docs(rfc#2843#23): SEO patch deleted (was never on main) + close #2838 #2844

Merged
devops-engineer merged 2 commits from fix/rfc-2843-23-delete-seo-patch into main 2026-06-14 10:59:28 +00:00
@@ -78,3 +78,126 @@ func listImports(t *testing.T, dir string) map[string]string {
}
return out
}
// SEO-patch grep-gate (RFC #2843 §4.4, PR #2844). The SEO
// patch (EnableSEOSkillPackage / SEOSkillPackageFiles /
// SEOSkillConfigBlock / seo_skill_package.go) was a
// per-template patch deleted by PR #2844. The generic asset
// channel (RFC #2843 #24) replaces it with template-agnostic
// template-repo fetches, so any reintroduction here is a
// layering violation (template content in core). This test
// makes the deletion STRUCTURAL — a future refactor that
// re-adds the patch (e.g. "let's just bring back
// EnableSEOSkillPackage for the new template") fails CI here
// before the SEO symbols leak into core, rather than after the
// next incident.
//
// Two layers of defense:
// 1. Symbol grep on every .go file in workspace-server/
// (catches a re-add to any package, not just provisioner).
// 2. File-path existence check (catches the embedded
// seo_skill_package/ directory reappearing).
//
// If this test fails: you re-introduced the per-template SEO
// patch that RFC #2843 §4.4 explicitly deletes. Use the generic
// template-repo asset channel (RFC #2843 #24) instead.
var seoPatchForbiddenSymbols = []string{
"EnableSEOSkillPackage",
"SEOSkillPackageFiles",
"SEOSkillConfigBlock",
"mergeSkillsBlockIntoConfigYAML",
}
var seoPatchForbiddenPathPrefixes = []string{
"workspace-server/internal/provisioner/seo_skill_package",
"workspace-server/internal/provisioner/seo_skill_package.go",
}
func TestNoSEOPatchSymbolsInCore(t *testing.T) {
t.Parallel()
// The test runs from internal/provisioner/ — the repo root
// is 4 levels up (workspace-server/internal/provisioner → root).
repoRoot, _ := filepath.Abs("../../..")
root := filepath.Join(repoRoot, "workspace-server")
// Layer 1: grep every .go file in workspace-server/ for the
// forbidden SEO-patch symbols. Catches re-adds to ANY package
// (provisioner, handlers, etc.) — the patch was per-template
// content in core, no package is a valid home.
var hits []string
// Resolve the current test file's absolute path so the
// self-exclude can match by exact path, not by basename
// (a basename match would skip EVERY architecture_test.go
// in the tree — workspace-server has them under
// internal/{models,db,provisioner,wsauth}/ — and create
// a blind spot where forbidden SEO symbols in a sibling
// architecture test would pass silently). Researcher
// RC #11684.
selfPath, _ := filepath.Abs("architecture_test.go")
err := filepath.Walk(root, func(path string, info os.FileInfo, walkErr error) error {
if walkErr != nil {
return walkErr
}
if info.IsDir() {
return nil
}
if !strings.HasSuffix(path, ".go") {
return nil
}
// Skip generated files and vendored code.
if strings.Contains(path, "/vendor/") {
return nil
}
// Skip THIS test file itself — it lists the forbidden
// symbols as documentation. Excluding self from the grep
// is necessary to avoid a self-match (the grep-gate would
// fail on the very file that defines it). Match by EXACT
// absolute path so sibling architecture_test.go files
// (workspace-server/internal/{models,db,wsauth}/) are
// still grep'd — they could legitimately contain the
// forbidden SEO symbols and must be caught.
if path == selfPath || strings.HasSuffix(path, "/"+filepath.Base(selfPath)) && path == selfPath {
return nil
}
b, readErr := os.ReadFile(path)
if readErr != nil {
return readErr
}
for _, sym := range seoPatchForbiddenSymbols {
if strings.Contains(string(b), sym) {
hits = append(hits, path+":"+sym)
}
}
return nil
})
if err != nil {
t.Fatalf("walk %s: %v", root, err)
}
if len(hits) > 0 {
t.Errorf(
"RFC #2843 §4.4 grep-gate: the SEO-specific patch symbols "+
"are forbidden in core (per-template content has no home "+
"here). Use the generic template-repo asset channel "+
"(RFC #2843 #24) instead. Hits: %v",
hits,
)
}
// Layer 2: forbidden file-path existence check. Catches
// the seo_skill_package/ directory reappearing with the
// embedded skill files (which the grep above would miss
// since the .md/.yaml files don't reference the symbols).
for _, forbidden := range seoPatchForbiddenPathPrefixes {
abs := filepath.Join(repoRoot, forbidden)
if _, statErr := os.Stat(abs); statErr == nil {
t.Errorf(
"RFC #2843 §4.4 grep-gate: forbidden file/dir re-appeared: %s "+
"(this is the per-template SEO patch that the generic "+
"asset channel replaces).",
abs,
)
}
}
}