diff --git a/check_templatesync.go b/check_templatesync.go new file mode 100644 index 0000000..32a73e8 --- /dev/null +++ b/check_templatesync.go @@ -0,0 +1,67 @@ +package main + +import ( + "bytes" + "os" + "path/filepath" +) + +// The bn chrome files authored in cms/backend/templates/bn and mechanically +// synced (make sync-templates) into the sibling core repo's templates/bn. +// Guest-side plugin templates compile core's copy into their wasm, so the two +// checkouts must stay byte-identical. validation.go is intentionally NOT in +// this set (cms's is a two-context-key bridge over the SDK tracker); neither +// is img.templ (cms-only, not referenced by the chrome). +// See cms docs/superpowers/specs/2026-07-07-bn-chrome-single-source-design.md. +var templateSyncSet = []string{ + "head.templ", + "toolbar.templ", + "engagement.templ", + "asset_hooks.go", +} + +func init() { + register(Check{ + Seq: 310, + ID: "31", + Title: "bn chrome templates in sync between cms and core", + Run: func(ctx *ScanContext, rep *Reporter) { + cmsDir := filepath.Join(ctx.repoRoot, "backend", "templates", "bn") + if _, err := os.Stat(cmsDir); err != nil { + rep.Skip("no backend/templates/bn in this repo — template-sync gate not applicable") + return + } + coreDir := filepath.Join(ctx.repoRoot, "..", "core", "templates", "bn") + if _, err := os.Stat(coreDir); err != nil { + rep.Skip("sibling core checkout not found — cannot verify template sync") + return + } + + var drifted []string + for _, name := range templateSyncSet { + cmsBytes, err := os.ReadFile(filepath.Join(cmsDir, name)) + if err != nil { + drifted = append(drifted, name+" (unreadable in cms: "+err.Error()+")") + continue + } + coreBytes, err := os.ReadFile(filepath.Join(coreDir, name)) + if err != nil { + drifted = append(drifted, name+" (missing in core)") + continue + } + if !bytes.Equal(cmsBytes, coreBytes) { + drifted = append(drifted, name) + } + } + + if len(drifted) > 0 { + rep.Fail("%d bn chrome file(s) drifted between cms and core", len(drifted)) + for _, name := range drifted { + rep.Findingf("templates/bn/%s differs — cms is the authoring source; run `make sync-templates` in cms, then commit + tag + push core", name) + } + } else { + rep.OK("bn chrome sync set byte-identical across cms and core (%d files)", len(templateSyncSet)) + } + }, + }) +}