From 2e7b174aa4cbfb78e171c6a8510c7a965244ac54 Mon Sep 17 00:00:00 2001 From: Oscar Villavicencio <9220505+odvcencio@users.noreply.github.com> Date: Mon, 24 Aug 2026 05:47:55 -0700 Subject: [PATCH 1/2] update: Update PHP issue #454 parity test with deep digests - Verify production and compact deep digests match pinned values - Ensure locked C deep digest differs from Go route digests - Assert all roots report HasError=true across every route - Update CHANGELOG and blocker documentation with new base hash - Add twenty-minute timeout and single-worker constraints to logs Buckley-Change-Hash: sha256:3c022ac3b4930f89138c75baade586a4b2c2e798bd9a7ad6388697e5d32b4474 Buckley-Change-Stats: files=3 insertions=91 deletions=14 binaries=0 --- CHANGELOG.md | 16 ++++-- cgo_harness/php_issue454_parity_test.go | 55 ++++++++++++++++++- docs/issue-454-compact-correctness-blocker.md | 34 +++++++++--- 3 files changed, 91 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9e133dd..7f6badef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1044,11 +1044,17 @@ for tags and release notes while still in `0.x`. `docs/root-normalization-retirement.md` for current artifact hashes and reopening conditions. -- Recorded the PHP issue #454 compact fallback guard at main commit - `af056b2d90e50a8917b9389bf42dfdf75872035`. The 140,287-byte edited witness - matched production and locked C. Compact recorded `routed=0` and - `fallback=1`. Two focused Docker runs passed with one CPU and 4 GiB. - Keep issue #454 open. Ship no parser change. See +- Hardened the PHP issue #454 compact fallback guard at base commit + `c25686c882affd7408e5ef4a7d65e92cc8391fab`. The 140,287-byte edited + witness produced the pinned production and compact Go deep digest + `4456730ce6919a623dd6db2e6ae7f11933aeb454c7e337b7da5c08a8d9ba267c`. + The locked-C `gts-deep-tree-v1` digest is + `1516308c38163089778464ad171875308c559af11af7c8c03ee17ae4eacd23c6`. + The digest covers byte and point spans, fields, extra and missing flags, + error flags, and root `HasError`. Both Go routes differ from locked C. + Compact recorded `routed=0` and `fallback=1`. Two one-CPU, 4 GiB Docker + runs passed with one test worker, a 20-minute timeout, `GOMAXPROCS=1`, and + `GOFLAGS=-p=1`. Keep issue #454 open. Ship no parser change. See `docs/issue-454-compact-correctness-blocker.md`. - Reject the issue #454 generic recovery candidate from PR #793. The candidate diff --git a/cgo_harness/php_issue454_parity_test.go b/cgo_harness/php_issue454_parity_test.go index 35a48b80..07a179bc 100644 --- a/cgo_harness/php_issue454_parity_test.go +++ b/cgo_harness/php_issue454_parity_test.go @@ -22,6 +22,13 @@ const issue454PHPGrammarCommit = "3f2465c217d0a966d41e584b42d75522f2a3149e" const issue454PHPGrammarBlobSHA256 = "15724627db479c27304b43fa3b5ef7d8d81f85e3b9ce6d8575a847b2dbaa5cd5" const issue454PHPCArtifactSHA256 = "1daea60ac1ee31227b8e1ed3cbd76b841435fe693e95af65cc61dad447d27891" +const ( + issue454PHPProductionDeepDigest = "4456730ce6919a623dd6db2e6ae7f11933aeb454c7e337b7da5c08a8d9ba267c" + issue454PHPCompactDeepDigest = "4456730ce6919a623dd6db2e6ae7f11933aeb454c7e337b7da5c08a8d9ba267c" + issue454PHPLockedCDeepDigest = "1516308c38163089778464ad171875308c559af11af7c8c03ee17ae4eacd23c6" + issue454PHPRootHasError = true +) + func TestParityIssue454PHPWholeTreeFallback(t *testing.T) { source := benchfixtures.Issue454PHPSource() site := bytes.Index(source, []byte("$x0")) @@ -80,6 +87,29 @@ func TestParityIssue454PHPWholeTreeFallback(t *testing.T) { t.Fatal("C reference parser returned nil tree") } defer cTree.Close() + productionInspection, err := benchfixtures.InspectGoTree(goTree.RootNode(), goLang) + if err != nil { + t.Fatal(err) + } + cDeepDigest, err := COracleDeepDigest(cTree) + if err != nil { + t.Fatal(err) + } + if productionInspection.SHA256 != issue454PHPProductionDeepDigest { + t.Fatalf("PHP issue #454 production gts-deep-tree-v1 digest=%s, want %s", productionInspection.SHA256, issue454PHPProductionDeepDigest) + } + if cDeepDigest != issue454PHPLockedCDeepDigest { + t.Fatalf("PHP issue #454 locked-C gts-deep-tree-v1 digest=%s, want %s", cDeepDigest, issue454PHPLockedCDeepDigest) + } + if got := goTree.RootNode().HasError(); got != issue454PHPRootHasError { + t.Fatalf("PHP issue #454 production root HasError=%t, want %t", got, issue454PHPRootHasError) + } + if got := cTree.RootNode().HasError(); got != issue454PHPRootHasError { + t.Fatalf("PHP issue #454 locked-C root HasError=%t, want %t", got, issue454PHPRootHasError) + } + if productionInspection.SHA256 == cDeepDigest { + t.Fatal("PHP issue #454 production deep digest unexpectedly matches locked C; review the NO-GO receipt before changing route policy") + } var errs []string compareNodes(goTree.RootNode(), goLang, cTree.RootNode(), "root", &errs) @@ -110,6 +140,23 @@ func TestParityIssue454PHPWholeTreeFallback(t *testing.T) { if len(compactErrs) > 0 { t.Fatalf("PHP issue #454 compact fallback differs from the pinned C oracle: %s", compactErrs[0]) } + compactInspection, err := benchfixtures.InspectGoTree(compactTree.RootNode(), goLang) + if err != nil { + t.Fatal(err) + } + if compactInspection.SHA256 != issue454PHPCompactDeepDigest { + t.Fatalf("PHP issue #454 compact gts-deep-tree-v1 digest=%s, want %s", compactInspection.SHA256, issue454PHPCompactDeepDigest) + } + if compactInspection.SHA256 != productionInspection.SHA256 { + t.Fatalf("PHP issue #454 compact and production deep digests differ: compact=%s production=%s", compactInspection.SHA256, productionInspection.SHA256) + } + if got := compactTree.RootNode().HasError(); got != issue454PHPRootHasError { + t.Fatalf("PHP issue #454 compact root HasError=%t, want %t", got, issue454PHPRootHasError) + } + if compactInspection.SHA256 == cDeepDigest { + t.Fatal("PHP issue #454 compact deep digest unexpectedly matches locked C; review the NO-GO receipt before changing route policy") + } + t.Logf("deep_digest format=%s production=%s compact=%s locked_c=%s production_root_has_error=%t compact_root_has_error=%t locked_c_root_has_error=%t exact_locked_c=false fields=type+named,field,byte+point,extra+missing+error+has_error,child_order", benchfixtures.DeepTreeDigestVersion, productionInspection.SHA256, compactInspection.SHA256, cDeepDigest, goTree.RootNode().HasError(), compactTree.RootNode().HasError(), cTree.RootNode().HasError()) t.Logf("PHP issue #454 compact route source_sha256=%x bytes=%d routed=%d fallback=%d reason=%q", sha256.Sum256(edited), len(edited), routedAfter-routedBefore, fallbackAfter-fallbackBefore, gotreesitter.AdmissionCandidateLastFallbackReason()) document, err := os.ReadFile("../docs/issue-454-compact-correctness-blocker.md") if err != nil { @@ -118,8 +165,14 @@ func TestParityIssue454PHPWholeTreeFallback(t *testing.T) { documentText := strings.Join(strings.Fields(string(document)), " ") for _, marker := range []string{ "## 2026-08-24 PHP compact fallback guard", - "Publication base: `af056b2d90e50a8917b9389bf42dfdf75872035e`.", + "Publication base: `c25686c882affd7408e5ef4a7d65e92cc8391fab`.", "The locked-C artifact SHA-256 is `1daea60ac1ee31227b8e1ed3cbd76b841435fe693e95af65cc61dad447d27891`.", + issue454PHPProductionDeepDigest, + issue454PHPCompactDeepDigest, + issue454PHPLockedCDeepDigest, + "The `gts-deep-tree-v1` stream covers type and named identity, incoming fields, byte and point spans, and child order. It also covers extra and missing flags, error flags, and the `HasError` flag.", + "The production and compact deep digests differ from the locked-C digest.", + "All three roots report `HasError=true`.", "The compact route recorded `routed=0` and `fallback=1`.", "This guard does not graduate PHP compact admission.", } { diff --git a/docs/issue-454-compact-correctness-blocker.md b/docs/issue-454-compact-correctness-blocker.md index 18cde0e0..e5d3bc6e 100644 --- a/docs/issue-454-compact-correctness-blocker.md +++ b/docs/issue-454-compact-correctness-blocker.md @@ -207,7 +207,7 @@ The 1 KiB known-divergence ratchet passes in ## 2026-08-24 PHP compact fallback guard -Publication base: `af056b2d90e50a8917b9389bf42dfdf75872035e`. +Publication base: `c25686c882affd7408e5ef4a7d65e92cc8391fab`. Status: **KEEP LIVE / NO-GO**. Keep issue #454 open. Ship no parser change. @@ -229,15 +229,33 @@ Its fallback reason was: compact route declined at recovery [mechanism=recovery-entered]: did not accept EOF: generic scheduler has no table action for the elected token ``` -The compact tree equals the production tree and the locked-C tree. -The guard passed twice with one CPU, 4 GiB, `GOMAXPROCS=1`, and `GOFLAGS=-p=1`. -Both runs had no out-of-memory kill and no wall timeout. +The `gts-deep-tree-v1` stream covers type and named identity, incoming fields, +byte and point spans, and child order. It also covers extra and missing flags, +error flags, and the `HasError` flag. + +The pinned deep digests are: + +| Route | Deep digest | Root `HasError` | +| --- | --- | --- | +| Production Go | `4456730ce6919a623dd6db2e6ae7f11933aeb454c7e337b7da5c08a8d9ba267c` | `true` | +| Compact fallback Go | `4456730ce6919a623dd6db2e6ae7f11933aeb454c7e337b7da5c08a8d9ba267c` | `true` | +| Locked C | `1516308c38163089778464ad171875308c559af11af7c8c03ee17ae4eacd23c6` | `true` | + +All three roots report `HasError=true`. + +The compact tree equals the production tree. The production and compact deep +digests differ from the locked-C digest. This full comparison keeps the PHP +route at **NO-GO**. + +The guard passed twice with one CPU, 4 GiB, one test worker, a 20-minute +timeout, `GOMAXPROCS=1`, and `GOFLAGS=-p=1`. Both runs had no out-of-memory +kill and no wall timeout. The final artifacts are: -- `/tmp/gotreesitter-compact-next2-artifacts/20260824T095540Z-issue454-php-compact-review-fix-1` -- `/tmp/gotreesitter-compact-next2-artifacts/20260824T095557Z-issue454-php-compact-review-fix-2` +- `/tmp/gotreesitter-php454-deep-guard-artifacts/20260824T110806Z-final-php454-2` +- `/tmp/gotreesitter-php454-deep-guard-artifacts/20260824T110900Z-final-php454-3` This guard does not graduate PHP compact admission. -Reopen the route only after a generic recovery proof removes the fallback and -retains exact locked-C parity on the PHP witness. +Reopen the route only after a generic recovery proof removes the fallback, +matches both Go route digests to locked C, and preserves all deep-digest fields. From 3006b0392684efcd875dcad3a0cc890b0bbeac0a Mon Sep 17 00:00:00 2001 From: Oscar Villavicencio <9220505+odvcencio@users.noreply.github.com> Date: Mon, 24 Aug 2026 05:49:44 -0700 Subject: [PATCH 2/2] update(docs): Update PHP deep guard artifact paths in documentation - Update the artifact paths in the PHP deep guard analysis document. - Replace the 'final' artifact paths with the 'refresh' runs. Buckley-Change-Hash: sha256:3166094b152b68a9059790b18d81e3144b562d0135f37a130f8c036a3f324242 Buckley-Change-Stats: files=1 insertions=2 deletions=2 binaries=0 --- docs/issue-454-compact-correctness-blocker.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/issue-454-compact-correctness-blocker.md b/docs/issue-454-compact-correctness-blocker.md index e5d3bc6e..81da7693 100644 --- a/docs/issue-454-compact-correctness-blocker.md +++ b/docs/issue-454-compact-correctness-blocker.md @@ -253,8 +253,8 @@ kill and no wall timeout. The final artifacts are: -- `/tmp/gotreesitter-php454-deep-guard-artifacts/20260824T110806Z-final-php454-2` -- `/tmp/gotreesitter-php454-deep-guard-artifacts/20260824T110900Z-final-php454-3` +- `/tmp/gotreesitter-php454-deep-guard-refresh-artifacts/20260824T124547Z-php454-refresh-1` +- `/tmp/gotreesitter-php454-deep-guard-refresh-artifacts/20260824T124620Z-php454-refresh-2` This guard does not graduate PHP compact admission. Reopen the route only after a generic recovery proof removes the fallback,