diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e4120932..faf82744a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -192,6 +192,16 @@ for tags and release notes while still in `0.x`. ### Fixed +- Record the `dispatch.templ` blocker receipt at base + `7498a678c52029a82f312e9637ecb66b15defa0b`. Keep the arm live. The + authenticated A0 manifest covers three Templ files, three checks, three + runs, 1138 visited nodes, and 76 rewrites. The medium template route + rewrites 53 nodes and still differs from locked C. The small template route + rewrites 23 nodes and matches after normalization. A malformed component + import still differs in its root error flag. The full real-corpus census is + unavailable. No registry or production change is included. See + `docs/root-normalization-retirement.md`. + - Record the issue #454 compact-parser correctness blocker. A 1 KiB fresh Go tree differs from locked C at `/translation_unit/function_definition[0]/compound_statement[2]/ERROR[2]/number_literal[0]`. diff --git a/cgo_harness/templ_next_live_probe_test.go b/cgo_harness/templ_next_live_probe_test.go new file mode 100644 index 000000000..41d55eeb4 --- /dev/null +++ b/cgo_harness/templ_next_live_probe_test.go @@ -0,0 +1,388 @@ +//go:build cgo && treesitter_c_parity + +package cgoharness + +import ( + "bytes" + "crypto/sha256" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + gotreesitter "github.com/odvcencio/gotreesitter" + "github.com/odvcencio/gotreesitter/grammars" + "github.com/odvcencio/gotreesitter/internal/benchfixtures" + sitter "github.com/tree-sitter/go-tree-sitter" +) + +type templNextWitness struct { + name string + source []byte +} + +// TestTemplNextLiveArmLockedCRoutes records Templ on raw, production, compact, +// forest, and incremental routes. It keeps rewrite and recovery evidence visible. +func TestTemplNextLiveArmLockedCRoutes(t *testing.T) { + t.Setenv("GTS_DISPATCHER_CENSUS", "1") + t.Setenv("GOT_PARSE_PHASE_TIMING", "1") + goLanguage := grammars.TemplLanguage() + cLanguage, err := COracleLanguage("templ") + if err != nil { + t.Fatal(err) + } + + witnesses := []templNextWitness{ + {name: "a0-medium-main", source: templNextReadA0(t, "medium__main.templ")}, + {name: "a0-medium-template", source: templNextReadA0(t, "medium__template.templ")}, + {name: "a0-small-template", source: templNextReadA0(t, "small__template.templ")}, + {name: "positive-no-op-control", source: []byte("templ T() {
ok
}\n")}, + {name: "qualified-component-import", source: []byte("package main\n\ntempl T() {\n\t@templ.JSONScript(\"scriptData\", scriptData)\n}\n")}, + {name: "malformed-dangling-attribute-quote", source: []byte("templ Broken() {\n\t\n}\n")}, + {name: "malformed-component-import", source: []byte("package main\n\ntempl Broken() {\n\t@counts(global,\n}\n")}, + } + + for _, witness := range witnesses { + witness := witness + t.Run(witness.name, func(t *testing.T) { + cParser := sitter.NewParser() + t.Cleanup(cParser.Close) + if err := cParser.SetLanguage(cLanguage); err != nil { + t.Fatal(err) + } + cTree := cParser.Parse(witness.source, nil) + if cTree == nil || cTree.RootNode() == nil { + t.Fatal("locked C parser returned no tree") + } + t.Cleanup(cTree.Close) + cDigest, err := COracleDeepDigest(cTree) + if err != nil { + t.Fatal(err) + } + if want := templNextExpectedCDigest(witness.name); want != "" && cDigest != want { + t.Fatalf("%s locked-C digest=%s, want %s", witness.name, cDigest, want) + } + + raw := templNextParseRoute(t, goLanguage, witness.source, "raw", func(p *gotreesitter.Parser, source []byte) (*gotreesitter.Tree, error) { + p.SetAdmissionCandidateRoute(false) + return p.ParseNoResultCompatibilityBenchmarkOnly(source) + }) + production := templNextParseRoute(t, goLanguage, witness.source, "production", func(p *gotreesitter.Parser, source []byte) (*gotreesitter.Tree, error) { + p.SetAdmissionCandidateRoute(false) + return p.Parse(source) + }) + + routedBefore, fallbackBefore := gotreesitter.AdmissionCandidateCounters() + compactParser := gotreesitter.NewParser(goLanguage) + compactParser.SetAdmissionCandidateRoute(true) + compact, err := compactParser.Parse(witness.source) + if err != nil { + t.Fatalf("compact parse: %v", err) + } + t.Cleanup(compact.Release) + routedAfter, fallbackAfter := gotreesitter.AdmissionCandidateCounters() + compactRoute := "accepted" + if fallbackAfter > fallbackBefore { + compactRoute = "fallback:" + gotreesitter.AdmissionCandidateLastFallbackReason() + } + + forestParser := gotreesitter.NewParser(goLanguage) + forest, forestOK := forestParser.ParseForestExperimental(witness.source) + forestRoute := "declined" + forestDetail := "" + if forestOK && forest != nil { + forestRoute = "accepted" + t.Cleanup(forest.Release) + } else { + offset, symbol, reason, _ := forestParser.ForestDeclineInfo() + forestDetail = fmt.Sprintf("offset=%d symbol=%d reason=%q", offset, symbol, reason) + } + + incremental, profile := templNextIncrementalRoute(t, goLanguage, witness.source) + + templNextLogRoute(t, "raw", raw, goLanguage, cTree, cDigest, "") + templNextAssertKnownRoute(t, witness.name, "raw", raw, goLanguage, cTree) + templNextLogRoute(t, "production", production, goLanguage, cTree, cDigest, "") + templNextAssertKnownRoute(t, witness.name, "production", production, goLanguage, cTree) + templNextLogRoute(t, "compact", compact, goLanguage, cTree, cDigest, compactRoute) + templNextAssertKnownRoute(t, witness.name, "compact", compact, goLanguage, cTree) + if forest != nil { + templNextLogRoute(t, "forest", forest, goLanguage, cTree, cDigest, forestRoute) + templNextAssertKnownRoute(t, witness.name, "forest", forest, goLanguage, cTree) + } else { + t.Logf("route=forest witness=%s result=declined %s", witness.name, forestDetail) + } + templNextLogRoute(t, "incremental", incremental, goLanguage, cTree, cDigest, fmt.Sprintf("reuse=%t unsupported=%t reason=%q reused_subtrees=%d reused_bytes=%d", profile.OldTreeReuseRoute, profile.ReuseUnsupported, profile.ReuseUnsupportedReason, profile.ReusedSubtrees, profile.ReusedBytes)) + templNextAssertKnownRoute(t, witness.name, "incremental", incremental, goLanguage, cTree) + if profile.ReuseUnsupportedReason != "external_scanner_unsupported" || profile.OldTreeReuseRoute || !profile.ReuseUnsupported { + t.Fatalf("incremental route profile = reuse=%t unsupported=%t reason=%q", profile.OldTreeReuseRoute, profile.ReuseUnsupported, profile.ReuseUnsupportedReason) + } + templNextAssertForestRoute(t, witness.name, forestParser, forestOK) + t.Logf("witness=%s bytes=%d source_sha256=%x c_digest=%s compact=%s counters=%d/%d->%d/%d forest=%s %s incremental_reuse=%t incremental_unsupported=%t incremental_reason=%q", witness.name, len(witness.source), sha256.Sum256(witness.source), cDigest, compactRoute, routedBefore, fallbackBefore, routedAfter, fallbackAfter, forestRoute, forestDetail, profile.OldTreeReuseRoute, profile.ReuseUnsupported, profile.ReuseUnsupportedReason) + templNextAssertCompactRoute(t, witness.name, compactRoute, routedAfter-routedBefore, fallbackAfter-fallbackBefore) + }) + } +} + +func templNextReadA0(t *testing.T, name string) []byte { + t.Helper() + source, err := os.ReadFile(filepath.Join("..", "testdata", "dispatcher_census_a0", "templ", name)) + if err != nil { + t.Fatal(err) + } + return source +} + +func templNextParseRoute(t *testing.T, language *gotreesitter.Language, source []byte, route string, parse func(*gotreesitter.Parser, []byte) (*gotreesitter.Tree, error)) *gotreesitter.Tree { + t.Helper() + parser := gotreesitter.NewParser(language) + tree, err := parse(parser, source) + if err != nil { + t.Fatalf("%s parse: %v", route, err) + } + if tree == nil || tree.RootNode() == nil { + t.Fatalf("%s returned no tree", route) + } + t.Cleanup(tree.Release) + return tree +} + +func templNextIncrementalRoute(t *testing.T, language *gotreesitter.Language, source []byte) (*gotreesitter.Tree, gotreesitter.IncrementalParseProfile) { + t.Helper() + if !bytes.HasSuffix(source, []byte{'\n'}) { + t.Fatalf("incremental witness does not end with newline") + } + base := bytes.TrimSuffix(source, []byte{'\n'}) + parser := gotreesitter.NewParser(language) + oldTree, err := parser.Parse(base) + if err != nil { + t.Fatalf("incremental base parse: %v", err) + } + t.Cleanup(oldTree.Release) + point := templNextPointAtByte(base) + oldTree.Edit(gotreesitter.InputEdit{ + StartByte: uint32(len(base)), + OldEndByte: uint32(len(base)), + NewEndByte: uint32(len(source)), + StartPoint: point, + OldEndPoint: point, + NewEndPoint: templNextPointAtByte(source), + }) + tree, profile, err := parser.ParseIncrementalProfiled(source, oldTree) + if err != nil { + t.Fatalf("incremental parse: %v", err) + } + if tree == nil || tree.RootNode() == nil { + t.Fatal("incremental returned no tree") + } + t.Cleanup(tree.Release) + return tree, profile +} + +func templNextPointAtByte(source []byte) gotreesitter.Point { + var point gotreesitter.Point + for _, b := range source { + if b == '\n' { + point.Row++ + point.Column = 0 + continue + } + point.Column++ + } + return point +} + +func templNextLogRoute(t *testing.T, route string, tree *gotreesitter.Tree, language *gotreesitter.Language, cTree *sitter.Tree, cDigest, detail string) { + t.Helper() + root := tree.RootNode() + inspection, err := benchfixtures.InspectGoTree(root, language) + if err != nil { + t.Fatalf("%s inspect Go tree: %v", route, err) + } + diff := FirstDivergenceDumpV1(root, language, cTree.RootNode()) + checked, run, visited, rewritten := templNextDispatchStats(tree) + if detail != "" { + detail = " " + detail + } + t.Logf("route=%s error=%t digest=%s c_digest=%s divergence=%+v dispatch_checked=%d dispatch_run=%d dispatch_visited=%d dispatch_rewritten=%d%s", route, root.HasError(), inspection.SHA256, cDigest, diff, checked, run, visited, rewritten, detail) +} + +func templNextDispatchStats(tree *gotreesitter.Tree) (checked, run, visited, rewritten uint64) { + runtime := tree.ParseRuntime() + if runtime.NormalizationPasses == nil { + return 0, 0, 0, 0 + } + for _, pass := range *runtime.NormalizationPasses { + if pass.Name != "dispatch.templ" { + continue + } + checked += pass.Checked + run += pass.Run + visited += pass.NodesVisited + rewritten += pass.NodesRewritten + } + return checked, run, visited, rewritten +} + +type templNextExpectedRoute struct { + digest string + error bool + rewrite uint64 + diff *DumpV1Divergence +} + +func templNextExpectedDiff(path, category, goValue, cValue string) *DumpV1Divergence { + return &DumpV1Divergence{Path: path, Category: category, GoValue: goValue, CValue: cValue} +} + +func templNextExpectedCDigest(witness string) string { + switch witness { + case "a0-medium-main": + return "efab90f3a4a75a4deba8c94d67c741dd842a7c8c6708bed3f59e37e0a994a11f" + case "a0-medium-template": + return "7de9788750436a485bee98ec6200da09d5062700368333fe380562d71f171891" + case "a0-small-template": + return "cb81fe10587416eae568216d16d2f7258bda32d00136030d8a4fcd2198e12594" + case "positive-no-op-control": + return "ac11fb7f49572a2132e31c3a46328e17a103c4ae73fd75745427a188c5987e11" + case "qualified-component-import": + return "631955c93c466e736f59aa22039f2558b7685d3b4641b71b874cac52b5e70a23" + case "malformed-dangling-attribute-quote": + return "3e6eb2d96ca843d122d8f1e952fcd465feee7f67d289c8de118c08436f1b4491" + case "malformed-component-import": + return "922cf68ffcfd8e890f27d0cb8fb995b5a5fdfb10c3853bc661bd8c722bbd34cb" + default: + return "" + } +} + +func templNextExpectedRouteFor(witness, route string) (templNextExpectedRoute, bool) { + shapeRaw := func(digest, path, goValue, cValue string) templNextExpectedRoute { + return templNextExpectedRoute{digest: digest, diff: templNextExpectedDiff(path, "shape", goValue, cValue)} + } + shapeNormalized := func(digest string) templNextExpectedRoute { + return shapeRaw(digest, "/source_file/component_declaration[26]/component_block[3]", "children=12", "children=11") + } + errorRoot := templNextExpectedDiff("/source_file", "error", "true", "false") + malformedRoot := templNextExpectedDiff("/source_file", "error", "false", "true") + switch witness { + case "a0-medium-main": + return templNextExpectedRoute{digest: "895657a1c4978896653cf968b2dedddf7badd40f464d558e97dd95a9d9675595", error: true, diff: errorRoot}, true + case "a0-medium-template": + if route == "raw" { + return shapeRaw("33a54940b5da62255e5a03056b2ed7935994773b53a746b9a7e706b60a1a8dcb", "/source_file/component_declaration[26]/component_block[3]", "children=20", "children=11"), true + } + want := shapeNormalized("2499953c81a152ca9db474f121b1a8a9de0c888c6f00a25125301c157bcb0b0e") + want.rewrite = 53 + return want, true + case "a0-small-template": + if route == "raw" { + return shapeRaw("80e67baee0a78d252f4621c42b4eab3e1334bc919bdcba000d17034d04f954f3", "/source_file/component_declaration[3]/component_block[3]/element[2]/element[1]", "children=4", "children=3"), true + } + return templNextExpectedRoute{digest: "cb81fe10587416eae568216d16d2f7258bda32d00136030d8a4fcd2198e12594", rewrite: 23}, true + case "positive-no-op-control": + return templNextExpectedRoute{digest: "ac11fb7f49572a2132e31c3a46328e17a103c4ae73fd75745427a188c5987e11"}, true + case "qualified-component-import": + if route == "raw" { + return shapeRaw("ed7d7f4155a6bdc6153038f7637dd2a14878abfcb26d27bbfc4a30529a4e0da7", "/source_file/component_declaration[1]/component_block[3]", "children=4", "children=3"), true + } + want := templNextExpectedRoute{digest: "631955c93c466e736f59aa22039f2558b7685d3b4641b71b874cac52b5e70a23"} + if route == "production" || route == "forest" || route == "incremental" { + want.rewrite = 15 + } + return want, true + case "malformed-dangling-attribute-quote": + return templNextExpectedRoute{digest: "3e6eb2d96ca843d122d8f1e952fcd465feee7f67d289c8de118c08436f1b4491", error: true}, true + case "malformed-component-import": + return templNextExpectedRoute{digest: "8954432deb8e607319a63b17b665508434a8d87fac8c6fe9923ad1bbe062760f", diff: malformedRoot}, true + default: + return templNextExpectedRoute{}, false + } +} + +func templNextAssertKnownRoute(t *testing.T, witness, route string, tree *gotreesitter.Tree, language *gotreesitter.Language, cTree *sitter.Tree) { + t.Helper() + want, ok := templNextExpectedRouteFor(witness, route) + if !ok { + return + } + root := tree.RootNode() + if root == nil { + t.Fatalf("%s/%s returned no root", witness, route) + } + if root.HasError() != want.error { + t.Fatalf("%s/%s error_root=%t, want %t", witness, route, root.HasError(), want.error) + } + inspection, err := benchfixtures.InspectGoTree(root, language) + if err != nil { + t.Fatalf("%s/%s inspect: %v", witness, route, err) + } + if inspection.SHA256 != want.digest { + t.Fatalf("%s/%s digest=%s, want %s", witness, route, inspection.SHA256, want.digest) + } + diff := FirstDivergenceDumpV1(root, language, cTree.RootNode()) + if want.diff == nil { + if diff != nil { + t.Fatalf("%s/%s divergence=%+v, want exact locked-C parity", witness, route, diff) + } + } else if diff == nil || *diff != *want.diff { + t.Fatalf("%s/%s divergence=%+v, want %+v", witness, route, diff, want.diff) + } + _, _, _, rewritten := templNextDispatchStats(tree) + if rewritten != want.rewrite { + t.Fatalf("%s/%s dispatch.templ rewrites=%d, want %d", witness, route, rewritten, want.rewrite) + } +} + +func templNextAssertCompactRoute(t *testing.T, witness, route string, routedDelta, fallbackDelta uint64) { + t.Helper() + if routedDelta+fallbackDelta != 1 { + t.Fatalf("%s compact counters routed_delta=%d fallback_delta=%d", witness, routedDelta, fallbackDelta) + } + wantFallback := witness == "a0-medium-main" || witness == "a0-medium-template" || witness == "a0-small-template" || witness == "malformed-dangling-attribute-quote" + if wantFallback && (route == "accepted" || routedDelta != 0 || fallbackDelta != 1) { + t.Fatalf("%s compact route=%q counters=%d/%d, want fallback", witness, route, routedDelta, fallbackDelta) + } + if !wantFallback && (route != "accepted" || routedDelta != 1 || fallbackDelta != 0) { + t.Fatalf("%s compact route=%q counters=%d/%d, want accepted", witness, route, routedDelta, fallbackDelta) + } +} + +func templNextAssertForestRoute(t *testing.T, witness string, parser *gotreesitter.Parser, accepted bool) { + t.Helper() + wantDeclined := witness == "a0-medium-main" || witness == "malformed-dangling-attribute-quote" + if wantDeclined != !accepted { + t.Fatalf("%s forest accepted=%t, want %t", witness, accepted, !wantDeclined) + } + if wantDeclined { + offset, symbol, reason, _ := parser.ForestDeclineInfo() + if witness == "a0-medium-main" && (offset != 1025 || symbol != 74 || reason != "dead_end") { + t.Fatalf("%s forest decline=%d/%d/%q, want 1025/74/dead_end", witness, offset, symbol, reason) + } + if witness == "malformed-dangling-attribute-quote" && (offset != 47 || symbol != 24 || reason != "dead_end") { + t.Fatalf("%s forest decline=%d/%d/%q, want 47/24/dead_end", witness, offset, symbol, reason) + } + } +} + +// TestTemplNextLiveArmReceiptDocument guards the final blocker receipt markers. +func TestTemplNextLiveArmReceiptDocument(t *testing.T) { + raw, err := os.ReadFile("../docs/root-normalization-retirement.md") + if err != nil { + t.Fatal(err) + } + document := strings.ReplaceAll(strings.Join(strings.Fields(string(raw)), " "), "`", "") + for _, marker := range []string{ + "Status: NO-GO. KEEP LIVE: dispatch.templ.", + "The authenticated Templ A0 receipt records three files, three checks, three runs, 1138 visited nodes, 76 rewritten nodes, one error root, and zero parse errors.", + "The medium template witness rewrites 53 nodes on production, compact, forest, and incremental routes.", + "The full real-corpus census is unavailable because cgo_harness/corpus_real is absent.", + "Do not change the registry or production state.", + } { + marker = strings.Join(strings.Fields(marker), " ") + if !strings.Contains(document, marker) { + t.Fatalf("Templ blocker receipt lacks marker %q", marker) + } + } +} diff --git a/docs/root-normalization-retirement.md b/docs/root-normalization-retirement.md index f23bbb266..758cb70e2 100644 --- a/docs/root-normalization-retirement.md +++ b/docs/root-normalization-retirement.md @@ -609,6 +609,140 @@ The focused Docker artifacts are: - `/tmp/ada-next-live-rebased-artifacts/20260822T232118Z-ada-census-registry`; - `/tmp/ada-next-live-rebased-artifacts/20260822T232128Z-ada-real-census`. +## 2026-08-24 Templ blocker receipt + +Status: `NO-GO`. `KEEP LIVE`: `dispatch.templ`. + +Base commit: `7498a678c52029a82f312e9637ecb66b15defa0b`. +This isolated receipt changes no production or registry file. + +Select Templ after the Authzed review and all earlier retired or blocked arms. +The registry ranks Templ next by its remaining A0 rewrite count. + +The registry has 88 entries. It has 78 dispatcher arms, three dispatcher +subpasses, one dispatcher predicate, three generic passes, and three fixpoints. +The live registry has 31 dispatcher arms, 33 dispatcher languages, one +predicate, 32 live entries, and 56 retired entries. It has 35 live language +labels, or 34 after case folding. + +The registry records `dispatch.templ` in `parser_result_templ.go`. Its owner is +`scheduler_action_semantics`. Its witnesses are in +`cgo_harness/parity_cgo_test.go`. + +The A0 (initial dispatcher census) manifest has 14 languages, 42 files, and +14 receipts. It records 44 checks, 44 runs, 313572 visited nodes, 3267 +rewritten nodes, 20 error roots, and zero parse errors. + +The authenticated Templ A0 receipt records three files, three checks, three +runs, 1138 visited nodes, 76 rewritten nodes, one error root, and zero parse +errors. The source files come from `a-h/templ` commit +`f8e3a1b4efb329e94e4831e3ad494bbc2086b756`. + +| A0 witness | Bytes | Source SHA-256 | +| --- | ---: | --- | +| `medium__main.templ` | 2161 | `4415618a310cc880cb67fcd902bb7e9f82e91b9d0f461349e0cfb5cd0b1fa007` | +| `medium__template.templ` | 2999 | `e4a5934ad709206e1c5ca82ab9bc86cd20467df61484357096e6378b5dbb7791` | +| `small__template.templ` | 257 | `bdc8798d13311d9f459108d3fad77f291dde4156fe68295671706684b8dd3eb3` | + +The tracked census has seven fixtures across six languages. It has no Templ +fixture. The full real-corpus census is unavailable because +`cgo_harness/corpus_real` is absent. The real-corpus test records a controlled +skip for this condition. + +The locked-C route receipt covers raw, production, compact, forest, and +incremental routes. The raw route suppresses result compatibility. It is a +diagnostic route and cannot support retirement by itself. + +| Witness | Raw Go digest | Normalized route digest | Locked C digest | +| --- | --- | --- | --- | +| `medium__main.templ` | `895657a1c4978896653cf968b2dedddf7badd40f464d558e97dd95a9d9675595` | `895657a1c4978896653cf968b2dedddf7badd40f464d558e97dd95a9d9675595` | `efab90f3a4a75a4deba8c94d67c741dd842a7c8c6708bed3f59e37e0a994a11f` | +| `medium__template.templ` | `33a54940b5da62255e5a03056b2ed7935994773b53a746b9a7e706b60a1a8dcb` | `2499953c81a152ca9db474f121b1a8a9de0c888c6f00a25125301c157bcb0b0e` | `7de9788750436a485bee98ec6200da09d5062700368333fe380562d71f171891` | +| `small__template.templ` | `80e67baee0a78d252f4621c42b4eab3e1334bc919bdcba000d17034d04f954f3` | `cb81fe10587416eae568216d16d2f7258bda32d00136030d8a4fcd2198e12594` | `cb81fe10587416eae568216d16d2f7258bda32d00136030d8a4fcd2198e12594` | + +The main witness differs at `/source_file`. Go marks the root as an error, +but C does not. Production, compact, and incremental routes report zero +`dispatch.templ` rewrites. The compact route falls back because the scheduler +did not accept EOF. The forest route declines at offset 1025, symbol 74, with +reason `dead_end`. Incremental parsing falls back for +`external_scanner_unsupported`. + +The medium template witness rewrites 53 nodes on production, compact, forest, +and incremental routes. The normalized routes still differ at +`/source_file/component_declaration[26]/component_block[3]`: Go has 12 +children, while C has 11. The raw route has 20 children at that path. Compact +parsing falls back for a converged-path reduction split. Forest parsing +accepts the source. Incremental parsing falls back for +`external_scanner_unsupported`. + +The small template witness rewrites 23 nodes on production, compact, forest, +and incremental routes. The normalized routes match locked C exactly. The raw +route differs at +`/source_file/component_declaration[3]/component_block[3]/element[2]/element[1]`: +Go has four children, while C has three. Compact parsing falls back for a +converged-path reduction split. Forest parsing accepts the source. Incremental +parsing falls back for `external_scanner_unsupported`. + +The focused positive control is `positive-no-op-control`. Its source SHA-256 is +`e0eb659e93f9306b1cc8cb6e9ec5fd9f86760d5d9de5f28122d0706bedc16ea4`. Every +route matches locked C digest +`ac11fb7f49572a2132e31c3a46328e17a103c4ae73fd75745427a188c5987e11`. Every +route records zero `dispatch.templ` rewrites. + +The qualified import witness has source SHA-256 +`8ff9410ceb223050d5ce5588700b3f8526115e12e130416533528bdcb22d1e9d`. +The raw route differs at `/source_file/component_declaration[1]/component_block[3]`: +Go has four children, while C has three. Production, forest, and incremental +routes rewrite 15 nodes and match locked C digest +`631955c93c466e736f59aa22039f2558b7685d3b4641b71b874cac52b5e70a23`. +Compact parsing accepts the source and records zero rewrites. + +The malformed dangling-quote witness has source SHA-256 +`8d823a16cc2d63f2ce220abfe07c792e7e2281855ac3b0a16e4de68c4450cb17`. +All raw, production, compact, and incremental routes match locked C digest +`3e6eb2d96ca843d122d8f1e952fcd465feee7f67d289c8de118c08436f1b4491` and +record zero rewrites. The root has an error. Compact parsing falls back because +the scheduler did not accept EOF. Forest parsing declines at offset 47, symbol +24, with reason `dead_end`. Incremental parsing falls back for +`external_scanner_unsupported`. + +The malformed component-import witness has source SHA-256 +`319a3cf489c8984bbe8c71d2be8bda4e28c073a6df43d75addeaea8c555b8e5f`. +Every Go route has digest +`8954432deb8e607319a63b17b665508434a8d87fac8c6fe9923ad1bbe062760f`. +Locked C has digest +`922cf68ffcfd8e890f27d0cb8fb995b5a5fdfb10c3853bc661bd8c722bbd34cb`. +The first difference is `/source_file`: Go has `error=false`, while C has +`error=true`. Every route records zero rewrites. Compact and forest parsing +accept the source. Incremental parsing falls back for +`external_scanner_unsupported`. + +The live positive controls include +`TestNormalizeTemplCompatibilityMergesComponentImportArgs`, +`TestNormalizeTemplCompatibilityBuildsSimpleStringArgument`, +`TestNormalizeTemplCompatibilityMergesQualifiedComponentImport`, and +`TestNormalizeTemplCompatibilityAddsDanglingAttributeQuoteError`. + +Do not retire `dispatch.templ`. The A0 receipt records 76 rewrites. The medium +template route retains a shape mismatch after 53 rewrites. The malformed +component-import route retains an error-flag mismatch. The authenticated +real-corpus census is unavailable. + +Keep `dispatch.templ` live until `scheduler_action_semantics` emits native +trees for every registered witness. Require exact raw, production, compact, +forest, incremental, and locked-C receipts. Require zero `dispatch.templ` +rewrites on every covered route. Require the authenticated Templ corpus before +retirement. Do not change the registry or production state. + +The focused Docker artifacts are: + +- `/tmp/templ-next-artifacts/20260823T011320Z-templ-registry-final` — registry receipt; +- `/tmp/templ-next-artifacts/20260823T011328Z-templ-a0-final` — A0 manifest receipt; +- `/tmp/templ-next-artifacts/20260823T011334Z-templ-tracked-final` — tracked census receipt; +- `/tmp/templ-next-artifacts/20260823T011340Z-templ-real-final` — unavailable corpus receipt; +- `/tmp/templ-next-artifacts/20260823T011354Z-templ-routes-final` — route and locked-C receipt; +- `/tmp/templ-next-artifacts/20260823T011346Z-templ-unit-final` — unit and scanner receipt; +- `/tmp/templ-next-artifacts/20260823T011507Z-templ-document-final2` — document guard receipt. + ## Ordered program ### R0 — inventory and containment