diff --git a/CHANGELOG.md b/CHANGELOG.md index b8e8dfc577..2a3b359d6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,210 @@ +### OpenCode normalizer tree mode matches tested publication + +- Restore the OpenCode review normalizer's executable mode after its published + blob matched the tested source but its Git tree entry did not. Exact-tree + publication evidence now includes file mode as well as content identity. + +### OpenCode quoted coverage labels cannot replace measured evidence + +- Reject a `coverage:` occurrence immediately preceded by a Markdown backtick + when selecting the authoritative coverage section or locating its boundary. + A reviewer warning that quotes a false full-coverage claim can therefore no + longer replace an earlier fail-closed coverage result. +- A durable regression first reproduced the false approval on PR #2564's + reviewed head, then passed with the bounded label-admission repair alongside + the existing repeated-label, identifier-suffix, and full-summary cases. + Fresh exact-head hosted Checks and a qualifying independent approval remain + required before ordinary merge. + +### OpenCode duplicate JSON members cannot replace review identity + +- Reject repeated object member names at every JSON nesting depth before a + value can become review-control evidence. A later duplicate `head_sha`, + `run_id`, or `run_attempt` can no longer replace the earlier value through + Python's default last-wins decoder behavior. +- RED against draft PR #2564 head + `3ecb54b896fbf4c9b7fea1bf8749c28cc558c0cd` reproduced both a direct + duplicate-object admission and an exact-run identity rewrite. The bounded + repair uses the standard decoder's `object_pairs_hook`, preserves mixed + prose recovery and non-finite-number behavior, and fails closed without + rewriting the model artifact. +- Focused normalizer verification is 174/174 with 100% statement, branch, and + public-doc coverage for the target module. The warning-fatal repository + suite passes 5,375 tests, 10 optional skips, and 40 subtests. Fresh + exact-head hosted Checks and a qualifying independent approval remain + required before ordinary merge. + +### OpenCode tilde fence delimiter lines cannot carry approval evidence + +- Classify CommonMark tilde fence delimiters with the same line-local, + non-authoritative boundary as backtick fence delimiters. An exact-run control + in either an opening tilde-fence info string or a closing delimiter suffix can + no longer be promoted as top-level approval evidence; fenced-body controls + and later independent controls retain their existing contract. +- RED `11c9c5ca2dce8d7ef32b078d76d7cd31101557e2` reproduces both false + admissions against exact parent `420f631b3b8bc0bb3c8dae4d69134ce97d932e02`. + GREEN `02f2763ff08d05060c66c8d6531df1aa8e49d035` generalizes the existing + delimiter-run classifier. Independent review then found the same bypass in + valid blockquote and list-item containers. RED + `0c226a1587b089a1ab267e48ab00ec9b0b69214c` binds four nested opening and + closing forms; GREEN `3ddd31841b73c6d5ae8555f6c8a838cb2b5f4e55` + closes those same-line forms. A second independent pass found exponential + regex backtracking plus four-space and ordered-list continuation gaps. RED + `f2aada37f6aa904442105d653d1217b834d8a18f` binds those cases and the + no-prefix-copy invariant; GREEN `e5ef765fb523596fdcc683876d80bc1bc644e566` + replaces the grammar regex with a conservative fail-closed container-marker + allowlist and evaluates at most one fence candidate per line. A 100,000-marker + failing prefix completes in about 0.03 seconds. Focused normalizer + verification is 171/171; the warning-fatal repository suite is 5,372 passed, + 10 optional skips, and 40 subtests. Fresh exact-head hosted Checks and a + qualifying independent approval remain required before ordinary merge. + +### OpenCode fence delimiter lines cannot carry approval evidence + +- Ignore every character after a line-start Markdown fence delimiter until the + newline. A balanced exact-run control embedded in an opening fence info + string or appended to a closing fence line therefore remains prose instead + of acquiring top-level approval authority; controls on later independent + lines retain the existing contract. +- RED `807fba4b845cba193126c1484b52e803315865a7` records both false admissions. + GREEN `705ac4a0a76d8160cc229e2b5e5a0337b7dfb2c9` adds one line-local state bit + and preserves executable mode. Focused normalizer verification is 158/158; + the warning-fatal repository suite is 5,359 passed, 10 optional skips, and + 40 subtests. Fresh exact-head hosted Checks and a qualifying independent + approval remain required before ordinary merge. + +### OpenCode inline examples and hostile nesting fail closed + +- Treat top-level single-quoted and inline backtick spans as prose rather + than approval evidence. An example exact-run control can no longer be + promoted merely because its JSON is balanced, and a quoted `{` or `[` can no + longer hide the later independent control. Apostrophes inside words remain + ordinary prose; triple-or-longer Markdown fences remain transparent to the + existing embedded-JSON contract. +- Catch decoder `RecursionError` at both JSON admission points so excessively + nested model output returns no candidate instead of crashing the review + step. Integrated source commit + `10b32952bae391d794a5d1af36be71f80b32a252` adds single-quote, + backtick, contraction, Markdown-fence, delimiter, and 10,000-level nesting + cases. Independent review then found that a contraction inside a + single-quoted span and a longer backtick run could end the span early; the + integrated repair applies word-internal apostrophe handling symmetrically + and closes only on an exact complete backtick run. A second independent pass + found that fence classification copied each same-line prefix; RED measured + 800,863 copied characters across 400 spans. The same integrated repair + short-circuits by the constant three-character fence indent before slicing. + Focused normalizer + verification is 156/156; the warning-fatal repository suite is 5,357 passed, + 10 optional skips, and 40 subtests. Fresh exact-head hosted Checks, coverage + evidence, and a qualifying independent approval remain required before + ordinary merge. + +### OpenCode quoted prose and unfinished wrappers preserve control identity + +- Restore the mixed-output scanner's linear-time security contract after an + independent exact-head review found per-nested-opener prefix rescans. RED + `e9a080f59ff6d85101c78da8ac1d4eddcd53c7b7` records 129 reverse-prefix + searches for 64 adversarial openers; GREEN + `5f5c2dc9b3ad8e7476663ce4d3c32ee49a8de4a4` preclassifies exact + `Diagnostic:` opener positions in one pass and reduces the same probe to one + decoder-internal search. Exact-function scaling from 16k to 128k nested + openers remains linear while quoted-prose and invalid-wrapper cases stay + fail-closed. +- Ignore `{` and `[` while they occur inside prose quotation state; an + unfinished quote remains fail-closed rather than promoting a quoted + multi-line control. Keep unfinished invalid-token wrappers fail-closed unless + the nested value follows the exact newline-separated + `Diagnostic: [pending` or `Diagnostic: {pending` recovery frame. +- Replace the Strix runtime-quality self-test's stale `decoder.raw_decode` + implementation-string assertion with its executable normalizer CLI contract; + that contract now includes a quoted-brace transcript before a valid current-run + control. Exact successor head `618471110757c74bcf6b7ac3a5783989dd010213` + produced 11 focused RED failures across three test-first cycles plus the + expected Strix self-test failures; the repaired focused normalizer suite + passes 134/134 with 100% statement, + branch, and public-doc coverage for the target module. The complete + repository suite passes 5,335 tests with 10 optional skips and 40 subtests; + the complete Strix harness also passes. +- Concurrent RED commit + `4de4805502e0fa2cae1178919ec31eec9fcd7249` binds parser and CLI + regressions; concurrent GREEN `a16431475a223d213b7e827b274282feda92286c` + first separated top-level prose quotation framing. The integrated repair + preserves both commits while superseding their newline-reset behavior with + the fail-closed unfinished-quote contract. The normalizer remains executable + (`100755`). + +### OpenCode separatorless invalid wrappers remain fail-closed + +- Preserve balanced malformed wrapper identity even when an invalid first + token is followed directly by a nested object or array without a comma or + colon. RED commit `8b1bd4a43be7604d6aa7b9e524295fea7501334c` + proves `[unquoted_token {control}]` and `{unquoted_key {control}}` promoted + the nested exact-run control. GREEN commit + `5261145a73e7b5a0b53c224317002fe98961f16f` records balanced parent spans in + one linear scan, suppresses their nested candidates, and still recovers a + complete control after an unclosed prose delimiter. The production + normalizer remains executable (`100755`). Focused verification is 120/120; + the repository suite passed 5,321 tests plus both pip-dependent cases in a + pip-equipped locked environment, with 5 optional skips and 40 subtests. + +### OpenCode invalid-token wrappers remain fail-closed + +- Preserve the outer-container identity boundary when an invalid token reaches + a nested opener without a comma or colon. RED commit + `4752398da1aef77ab8172126e2d3668870f628aa` reproduces nested-control + promotion from separatorless array and object wrappers; GREEN commit + `f6d6e255ed479150dbbd48490f0a527ce06e0917` records matched container spans + before decoding, so balanced malformed parents suppress nested controls while + unclosed prose delimiters still permit a later independent control. + +- Treat a balanced object or array whose first token is invalid JSON as one + outer evidence container instead of skipping its opener and promoting a + nested exact-run control. RED commit + `b5a0507b8ee4ec70cc5fca751f34df98719f219b` binds `undefined`, arbitrary + unquoted array tokens, and unquoted object keys; GREEN commit + `443c29aa6f56735f7fcf0ee6a550b6bad5f7e2f8` preserves the proven prose + delimiter recovery while keeping balanced malformed wrappers fail-closed. + The production normalizer remains executable (`100755`). + +### OpenCode mixed-output framing preserves later controls + +- Ignore prose `{` or `[` delimiters whose next non-whitespace token cannot + start the corresponding JSON container. This preserves a later complete + exact-run control after diagnostics such as `Diagnostic: [pending` without + weakening the existing fail-closed rule for malformed outer objects or + arrays. RED commit `42099a359cdfb8126ea4e3d9118c60f6d98af1fa` + records the lost-control case; GREEN commit + `07baba20259c9061fbb647963f09745a9ca6931b` restores the framing boundary. + Fresh exact-head hosted Checks and a qualifying independent approval remain + required before ordinary merge. + +### OpenCode embedded JSON evidence is outermost and linear-time + +- Parse prose-wrapped JSON by scanning each outermost object or array once, + with string and escape awareness, instead of retrying `raw_decode` at every + nested `{`. A malformed outer container can no longer promote a nested + exact-run control object into top-level approval evidence, and adversarial + nested prefixes no longer cause quadratic decoding work. RED commit + `d05f67f6c5f164309d3cbf15f4858c5fa3d176cd` preserves the malformed-object + exploit; GREEN commit `86f52f320e8eb5ac56efdf9a3e2552b20bf409de` + replaces the retry loop, and `1a00c73a752b45d9d2a808d9bc96baae51ea8402` + extends the same invariant to malformed array nesting. Fresh exact-head + hosted Checks and a qualifying independent approval remain required before + ordinary merge. + +### OpenCode evidence labels require standalone identity boundaries + +- Reject a purported verification label when it is only the suffix of an + identifier-like token such as `uncoverage:`. The OpenCode normalizer now + applies the same boundary rule while selecting the last admissible label and + while finding the next label that terminates its section. RED commit + `af06cf9c87de4ac76db575d087a170746d6ab83d` proves that a forged suffix could + override an earlier fail-closed coverage statement; GREEN commit + `4d49b8307706ab8d4565cca8b0d9728bcdad2a35` preserves repeated labels, + Markdown decoration, and the distinct `docstring coverage:` label while + rejecting the identity-confused form. Fresh exact-head hosted Checks and a + qualifying independent approval remain required before ordinary merge. + ### Maturin download failures close every transport response - Refactor the bounded Maturin asset downloader so successful and rejected diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index f839e18b4e..396ca3cf9d 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,5 +1,82 @@ # Product and Technical Gap Baseline +## 2026-10-09 OpenCode normalizer tree-mode integrity + +**Status:** Proposed on `ContextualWisdomLab/.github#2564`; focused local +verification is GREEN, while executable hosted Checks and a qualifying +independent approval remain mandatory. + +**Gap / RCA.** The published normalizer blob was byte-identical to the +warnings-fatal tested source, but the remote Git tree recorded mode `100644` +while the verified tree and shebang contract required `100755`. The claimed +exact remote/tested tree identity was therefore false and direct execution was +removed. + +**Action / evidence.** A mode-only ordinary fast-forward restored `100755` +without changing blob `fedb097409eeedee1b3a640923d1d5d88f60a473`. +Source tree `89239520e294c41dacfd4cc4e0bed9a5166cfd2c` then matched the +verified local tree. The focused normalizer corpus is **175 passed** with +warnings fatal; Python compilation, executable-mode assertion, and diff +checks are GREEN. Future publication receipts bind Git mode and content. + +## 2026-10-09 OpenCode quoted coverage-label authority + +**Status:** Proposed on `ContextualWisdomLab/.github#2564`; focused local +verification is GREEN, while fresh exact-head hosted Checks and a qualifying +independent approval remain mandatory. + +**PRD / buyer-visible Gap.** A fail-closed review must not become an approval +because its explanatory prose quotes the claim that it rejected. The coverage +oracle selected the last text occurrence of `coverage:` and admitted one that +started immediately after a Markdown backtick. A warning such as “do not claim +`coverage: ... 100%`” could therefore replace genuine “not measured” evidence. + +**TRD / Context Map / action.** The central `.github` review-control bounded +context owns label authority; OpenCode remains an untrusted evidence producer. +RED adds the exact quoted-warning transcript. GREEN rejects backtick-prefixed +labels in backward authority selection and forward section-boundary scanning, +without changing legitimate repeated labels or the separate docstring label. +The focused quoted-warning, repeated-label, identifier-suffix, and full-summary +cases pass 4/4 with warnings fatal. Completion still requires fresh exact-head +hosted evidence, no actionable review thread, qualifying independent approval, +and ordinary protected integration. + +## 2026-10-07 OpenCode unambiguous JSON-member authority + +| PRD / TRD scope | Context Map / UML | ERD | Gap / executable evidence | Action | Status | +|---|---|---|---|---|---| +| The central `.github` review-control owner must derive exact-run authority from an unambiguous JSON object. Repeated member names at any depth are invalid evidence; the PRD goal and loop remain unchanged. | `OpenCode model output → duplicate-aware JSON decoder → exact-run identity validation → review receipt gate`. The decoder boundary rejects ambiguity before domain validation, so neither outer identity nor nested evidence can acquire last-wins semantics. | No persistence, schema, table, or migration change. | Draft `ContextualWisdomLab/.github#2564@3ecb54b896fbf4c9b7fea1bf8749c28cc558c0cd` used Python's default `json.loads`, which retains only the last repeated member. RED proves `{"value":1,"value":2}` was accepted as one object and a stale first `head_sha` could be replaced by a later current-head value, producing exit 0. | Decode through the standard library with an `object_pairs_hook` that rejects the first repeated name at every nesting depth. Apply the same boundary to pure-JSON and mixed-prose recovery, preserve the original artifact on rejection, and bind the diagnostic-label branch so recovery authority cannot follow extra prose. Require fresh exact-head hosted Checks and a qualifying independent approval before merge. | **Proposed / local GREEN:** focused normalizer 174/174; target module 100% statement, branch, and public-doc coverage; warning-fatal repository suite 5,375 passed, 10 skipped, 40 subtests. Exact-head hosted evidence remains required. | + +## 2026-10-03 OpenCode tilde-fence authority boundary + +| PRD / TRD scope | Context Map / UML | ERD | Gap / executable evidence | Action | Status | +|---|---|---|---|---|---| +| The central `.github` review-control owner must treat every supported Markdown fence delimiter line as prose framing, never approval evidence. The PRD goal and loop remain unchanged. | `OpenCode model output → mixed-output normalizer → exact-run control candidate → review receipt gate`. Backtick and tilde delimiter lines, including blockquote, list-item, and continuation indentation, share one non-authoritative boundary; fenced bodies and later independent lines retain their existing identity. | No persistence, schema, table, or migration change. | Draft successor `ContextualWisdomLab/.github#2564@420f631b3b8bc0bb3c8dae4d69134ce97d932e02` ignored backtick delimiter-line controls but did not recognize root tilde fences. RED `11c9c5ca2dce8d7ef32b078d76d7cd31101557e2` binds opening and closing false admissions; GREEN `02f2763ff08d05060c66c8d6531df1aa8e49d035` closes the root form. Independent review then reproduced the same bypass under blockquote and list-item prefixes. RED `0c226a1587b089a1ab267e48ab00ec9b0b69214c` binds four nested forms; GREEN `3ddd31841b73c6d5ae8555f6c8a838cb2b5f4e55` closes those same-line cases. A second pass found exponential regex backtracking and four-space/ordered-list continuation gaps. RED `f2aada37f6aa904442105d653d1217b834d8a18f` binds five failures and the no-prefix-copy invariant. | Retain backtick-only inline quotation semantics and the transparent fenced-body contract. Evaluate at most one fence candidate per line, and conservatively fail closed when its prefix contains only whitespace or Markdown container-marker characters. GREEN `e5ef765fb523596fdcc683876d80bc1bc644e566` removes regex backtracking and prefix copying; a 100,000-marker failing prefix completes in about 0.03 seconds. This intentionally over-approximates CommonMark containers rather than claiming a full Markdown parser. Require fresh exact-head hosted Checks, coverage, and an independent current-head review before merge. | **Proposed / local GREEN:** focused normalizer 171/171; warning-fatal repository suite 5,372 passed, 10 skipped, 40 subtests; exact-head hosted evidence remains required. | + +## 2026-10-03 OpenCode fence-delimiter authority boundary + +| PRD / TRD scope | Context Map / UML | ERD | Gap / executable evidence | Action | Status | +|---|---|---|---|---|---| +| The central `.github` review-control owner must admit only independent top-level exact-run JSON. Markdown fence delimiter lines are prose framing, not a channel for approval evidence. The PRD goal and loop remain unchanged. | `OpenCode model output → mixed-output normalizer → exact-run control candidate → review receipt gate`. Fence delimiter lines terminate before candidate discovery; later independent lines keep their existing identity. | No persistence, schema, table, or migration change. | Draft successor `ContextualWisdomLab/.github#2564@2974f7a806af50bcc64be627d37182683467b61e` recognized a line-start Markdown fence but continued scanning the remainder of that same line. Consequently a balanced control in either an opening fence info string or the suffix of a closing fence delimiter was promoted as top-level authority. RED `807fba4b845cba193126c1484b52e803315865a7` binds both attacks. | In `iter_json_objects`, retain a line-local fence-delimiter state through the newline and ignore all remaining delimiter-line characters. GREEN `705ac4a0a76d8160cc229e2b5e5a0337b7dfb2c9` implements the minimal state transition while preserving the existing transparent fenced-body contract. Require fresh exact-head hosted Checks, coverage, and an independent current-head review before merge. | **Proposed / local GREEN:** focused normalizer 158/158; warning-fatal repository suite 5,359 passed, 10 skipped, 40 subtests; compileall and diff checks pass. Exact-head hosted evidence remains required. | + +## 2026-10-03 OpenCode inline-quotation authority boundary + +| PRD / TRD scope | Context Map / UML | ERD | Gap / executable evidence | Action | Status | +|---|---|---|---|---|---| +| The central `.github` review-control owner must admit only independent exact-run JSON as OpenCode approval evidence and must fail closed without terminating the review step on hostile model output. The PRD goal and loop remain unchanged. | `OpenCode model output → mixed-output normalizer → exact-run control candidate → review receipt gate`. Quoted examples stay outside the control-candidate boundary; repository and product consumers continue to use the released central workflow contract. | No persistence, schema, table, or migration change. | On draft successor `ContextualWisdomLab/.github#2564` parent `d2f1f1530a0e37ac6d17c23fceac8a9a861dbbe1`, balanced controls inside `'…'`, `` `…` ``, or `` ``…`` `` were promoted as authoritative. The same spans containing `{` or `[` hid a later real control, while 10,000-level JSON nesting raised uncaught `RecursionError`. Integrated source repair `10b32952bae391d794a5d1af36be71f80b32a252` binds both false-positive/false-negative directions, Markdown-fence compatibility, contractions, and crash containment. Independent review then reproduced early termination by an apostrophe inside a quote, quote adjacency to a word, and mixed-length backtick runs; the integrated repair binds and corrects those composition cases. A second pass found quadratic same-line prefix copying during fence classification; RED measured 800,863 copied characters across 400 spans and the same source commit restores constant-width classification. | Track the top-level quotation delimiter; treat apostrophes as word-internal only when both neighbors are identifier-like; consume a complete backtick run and close inline spans only on the exact delimiter length; leave only line-start triple-or-longer Markdown fences transparent; check the maximum three-space fence indent before slicing; catch `RecursionError` at both decoder boundaries. Require fresh exact-head hosted Checks, coverage, and an independent current-head review before merge. | **Proposed / local GREEN:** focused normalizer 156/156; warning-fatal repository suite 5,357 passed, 10 skipped, 40 subtests. The current execution image lacks the locked `coverage` and `interrogate` modules, so no new local coverage percentage is claimed; hosted exact-head evidence remains required. | + +## 2026-10-03 OpenCode linear-time transcript framing contract + +| Gap | Exact evidence | Action | Status | +|---|---|---|---| +| The exact-head diagnostic compatibility repair called prefix-wide `str.rfind()` twice for each nested non-JSON opener. Untrusted model output could therefore drive the mixed-output scanner toward quadratic work before evidence normalization. | Independent exact-head review of #2564 `a62fe71a7573cf377da535d2dcb72e9f714b263d`; deterministic RED `e9a080f59ff6d85101c78da8ac1d4eddcd53c7b7` observes 129 reverse searches for 64 nested openers. | Preclassify exact line-local `Diagnostic:` opener positions in one linear pass, use O(1) membership during nesting, and retain the existing exact recovery grammar and fail-closed ambiguity rules. GREEN `5f5c2dc9b3ad8e7476663ce4d3c32ee49a8de4a4` observes one decoder-internal reverse search and scales from about 0.010 s at 16k openers to 0.080 s at 128k. | **Proposed / focused GREEN; exact-head hosted Checks and qualifying independent approval required.** | + +## 2026-10-03 OpenCode quoted-prose and unfinished-wrapper evidence boundary + +| Gap | Exact evidence | Action | Status | +|---|---|---|---| +| The single-pass mixed-output scanner treated a quoted prose `{` or `[` as an outer JSON container, so its closing prose quote could consume a later independent exact-run control. Conversely, an unfinished invalid-token wrapper was not retained as an evidence boundary, so its completed nested control could be promoted at EOF. The Strix runtime-quality self-test also required the deleted `decoder.raw_decode` implementation string instead of executing the active scanner contract. | Draft successor `ContextualWisdomLab/.github#2564`; review threads `PRRT_kwDOS_C14s6oi-5R` and `PRRT_kwDOS_C14s6oi-6j`; concurrent RED `4de4805502e0fa2cae1178919ec31eec9fcd7249` and GREEN `a16431475a223d213b7e827b274282feda92286c`; three additional test-first RED cycles produced 11 focused failures across quoted delimiters, unfinished quotes, same-line/newline invalid wrappers, and false diagnostic aliases, while the Strix harness failed both its stale implementation assertion and quoted-brace CLI case | In the central `.github` review-control owner, preserve the concurrent ancestry and CLI regression, track prose quotation state independently from JSON strings, and keep an unfinished quote fail-closed. Retain only the exact newline-separated `Diagnostic: [pending` / `Diagnostic: {pending` recovery grammar; every other unfinished invalid parent blocks nested values. Replace the stale implementation assertion with execution of the active scanner contract. | **Proposed / exact integrated tree GREEN: focused normalizer 134/134; target statement/branch/public-doc coverage 100%; repository suite 5,335 passed, 10 skipped, 40 subtests; filtered and complete Strix harness PASS; both actionable threads resolved. Fresh terminal hosted Checks and qualifying independent approval remain required.** | + ## 2026-10-03 Noema document-reader prerelease security-oracle closure | Gap | Exact evidence | Action | Status | @@ -3731,3 +3808,186 @@ verdict-shape acceptance, and qualifying independent approval. **Gap / failure scene.** The v2 handler names a run with `head/base/required-run/producer-source`, but its required-workflow fallback looked up only `head/base/required-run`. When authenticated status publication is unavailable, a completed clean handler job could not be found and a rerun ended false RED. Omitting the producer source would also allow a regenerated live merge revision to reuse predecessor evidence. **Action / evidence.** Correct the fallback lookup to include the live merge source and retain fail-closed base, head, required-run, workflow-path, job-name, GHAS-identity, and SARIF checks. The test-first repair reproduced two failures, then passed 96 focused workflow-contract tests; the new edge case rejects a stale merge-source title. Ruff E9/F/I on the changed dispatch-contract file and `git diff --check` pass. Fresh hosted Checks and a qualifying independent approval are still required on the unchanged executable delta before merge. + +## 2026-10-01 OpenCode evidence-label identity boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; fresh exact-head +hosted Checks and a qualifying independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode response normalization and approval-evidence admission. OpenCode +is the untrusted evidence producer; repository review workflows consume only +the normalizer's fail-closed verdict contract. + +**Gap / RCA.** The optimized last-label search used an unconstrained +`rfind("coverage:")`. A response could state that real coverage evidence was +not measured, then append `uncoverage: ... 100%`; the suffix beginning inside +`uncoverage:` was accepted as a newer `coverage:` label. The false label could +therefore replace the genuine fail-closed section and make +`mentions_full_coverage` return true. The same missing identity boundary also +affected forward searches for the next section label. + +**RED → GREEN / action.** RED +`af06cf9c87de4ac76db575d087a170746d6ab83d` adds the durable suffix-forgery +case. GREEN `4d49b8307706ab8d4565cca8b0d9728bcdad2a35` rejects label occurrences whose +preceding character is alphanumeric, underscore, or hyphen in both backward +selection and forward section termination. It retains decorated Markdown +labels, repeated legitimate labels, and the separate `docstring coverage:` +rule. Local direct behavior cases, Python compilation, and `git diff --check` +are GREEN; the local environment has no pytest installation, so no full-suite +claim is made. Completion still requires hosted exact-head tests, terminal +required Checks, no unresolved actionable thread, qualifying independent +approval, and ordinary protected integration. + +## 2026-10-01 OpenCode outermost JSON evidence boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable repair +and local focused verification are GREEN, while fresh exact-head hosted Checks +and a qualifying independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode response normalization and exact-run evidence admission. The +model response is untrusted input; downstream required-review workflows may +consume only top-level controls accepted by this owner contract. + +**Gap / RCA.** Exact-head Strix run +[36794394865](https://github.com/ContextualWisdomLab/.github/actions/runs/36794394865) +reported repeated JSON decoding in `iter_json_objects`. Direct reproduction +confirmed two effects from the same retry-at-every-`{` loop: a malformed outer +object could promote its valid nested exact-run control into top-level evidence, +and doubling an unclosed nested prefix increased processing time by roughly +four times. The first effect is an identity-boundary false admission; the +second permits model-controlled quadratic work. + +**RED → GREEN / action.** RED +`d05f67f6c5f164309d3cbf15f4858c5fa3d176cd` records the malformed-object +promotion. GREEN `86f52f320e8eb5ac56efdf9a3e2552b20bf409de` +tracks one outermost container at a time, handles quoted strings and escapes, +and decodes only a completed outermost span. Follow-up test commit +`1a00c73a752b45d9d2a808d9bc96baae51ea8402` binds the same rule to malformed +array nesting. The existing embedded-object cases and both new adversarial +cases pass; Python compilation and `git diff --check` are GREEN. A direct +3,200-level measurement completed in 0.001236 seconds, while the prior +1,600-level case required 0.065367 seconds. These are local diagnostic values, +not a hosted performance claim. Pytest is unavailable in the local runner, so +the complete suite remains an exact-head hosted acceptance requirement. + + +## 2026-10-01 OpenCode mixed-output JSON framing boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable +RED→GREEN complete, fresh exact-head hosted Checks and a qualifying independent +approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns mixed-output framing and exact-run evidence admission. OpenCode output is +untrusted: prose delimiters must not block a later complete top-level control, +while actual malformed outer containers must continue to suppress nested +controls. + +**Gap / RCA.** CodeRabbit review on prior exact head +`2ee8ddad072fe59bbe33c99994fa1e8c9cb5387c` showed that +`Diagnostic: [pending` was treated as an unclosed JSON array and hid a later +valid control. Direct reproduction showed the same regression for +`Diagnostic: {pending`. The outermost single-pass repair had dropped the +predecessor's candidate-start grammar gate. + +**RED → GREEN / action.** RED +`42099a359cdfb8126ea4e3d9118c60f6d98af1fa` binds both prose delimiters. +GREEN `07baba20259c9061fbb647963f09745a9ca6931b` admits an object start only +before `"` or `}`, and an array start only before a JSON value starter. +Existing malformed object/array nested-control cases remain fail-closed. +Direct focused cases 8/8, Python compilation, and `git diff --check` are GREEN; +pytest is unavailable locally, so the full hosted suite remains required. + + +## 2026-10-01 balanced invalid-token wrapper evidence boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable +RED→GREEN is published, while fresh exact-head hosted Checks and a qualifying +independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode mixed-output normalization and exact-run evidence admission. +OpenCode model output is untrusted. A nested control inside any balanced outer +container—including a syntactically invalid one—must never acquire top-level +identity. + +**Gap / RCA.** The candidate-start allowlist skipped balanced wrappers whose +first token was invalid JSON. Inputs such as `[undefined, {control}]`, +`[unquoted_token, {control}]`, and `{unquoted_key: {control}}` therefore +promoted the nested exact-run control. The earlier `NaN`/`Infinity` repair +covered Python JSON extensions but not the general invalid-token boundary. + +**RED → GREEN / action.** RED +`b5a0507b8ee4ec70cc5fca751f34df98719f219b` reproduces all three promotions. +GREEN `443c29aa6f56735f7fcf0ee6a550b6bad5f7e2f8` treats an invalid starter as a +malformed outer container when its token reaches a structural separator before +another opener; the proven unclosed prose-delimiter recovery remains intact. +Focused parser verification is 118/118 GREEN. Full repository verification +reached 5,318 passed, 7 skipped, and 40 subtests; its sole failure was the +published-commit ancestry test because the isolated `git archive` intentionally +has no `.git` directory. Warnings-fatal compilation and diff whitespace checks +are GREEN. Exact Git tree `dccb57a152c21600305c0eabac06cb29de2e0cf7` +preserves source mode `100755`. + +## 2026-10-03 separatorless invalid-wrapper evidence regression + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; local focused +RED→GREEN is complete. Fresh exact-head hosted Checks, no unresolved actionable +thread, and qualifying independent approval remain mandatory before ordinary +merge. + +**Context Map / owner.** The central `.github` review-control bounded context +owns OpenCode mixed-output framing and exact-run evidence identity. Model output +is untrusted; only controls that are top-level in the producer output may enter +the approval contract. + +**Gap / RCA.** Exact head +`24efc99bb0aad3f4c0d76b00b173b6d9a5be34ee` preserved comma/colon invalid-token +tests but lost the separatorless regression cases and their span-ownership +implementation during concurrent branch restoration. Consequently +`[undefined {control}]`, `[unquoted_token {control}]`, and +`{unquoted_key {control}}` promoted the nested control. The parser skipped the +invalid outer opener when its token reached another opener, even when the outer +container later closed. + +**RED → GREEN / action.** RED +`4752398da1aef77ab8172126e2d3668870f628aa` binds the three real-parser +failures. GREEN `f6d6e255ed479150dbbd48490f0a527ce06e0917` records matched parent/child +spans and decodes only spans without a matched or JSON-shaped enclosing parent. +Balanced malformed wrappers therefore retain outer ownership, while an +unclosed prose delimiter such as `Diagnostic: [pending` still cannot hide a +later independent control. Focused framing verification is 10/10 GREEN; +complete repository verification and fresh hosted exact-head evidence remain +required. + +## 2026-10-01 separatorless invalid-token wrapper evidence boundary + +**Status:** Proposed on `ContextualWisdomLab/.github#2543`; executable +RED→GREEN is published, while fresh exact-head hosted Checks and a qualifying +independent approval remain mandatory. + +**Context Map / owner.** The central `.github` review-control bounded context +owns mixed-output framing and exact-run evidence admission. Balanced malformed +wrappers remain evidence boundaries even when the malformed token and nested +container have no JSON separator; unclosed prose delimiters must still permit a +later complete top-level control. + +**Gap / RCA.** Exact-head CodeRabbit review of +`a5fddfa7c46ff68eea593a4dd71bc6196bc640ba` found that the invalid-token scan +stopped at a nested `{` or `[` and discarded the outer opener. Inputs +`[unquoted_token {control}]` and `{unquoted_key {control}}` therefore promoted +the nested exact-run control despite their balanced outer wrappers. + +**RED → GREEN / action.** RED +`8b1bd4a43be7604d6aa7b9e524295fea7501334c` binds both separatorless attacks. +GREEN `5261145a73e7b5a0b53c224317002fe98961f16f` records matched container spans, +their immediate parents, and JSON-like blocking depth in one linear scan. +Nested candidates are rejected when a balanced parent exists or a JSON-like +ancestor remains open; candidates after unmatched prose delimiters remain +recoverable. Focused normalizer verification is 120/120 GREEN. The repository +run passed 5,321 tests, skipped 5 optional cases, and passed 40 subtests; its +only two initial failures were direct `python -m pip` calls in a verification +venv without pip, and both passed in the pip-equipped locked venv (2/2). The +source mode remains `100755`. diff --git a/scripts/ci/opencode_review_normalize_output.py b/scripts/ci/opencode_review_normalize_output.py index 7ad4c2b431..fedb097409 100755 --- a/scripts/ci/opencode_review_normalize_output.py +++ b/scripts/ci/opencode_review_normalize_output.py @@ -953,23 +953,28 @@ def mentions_verification_posture(reason: str, summary: str) -> bool: def label_section(text: str, label: str) -> str: - """Return text after a verification label until the next known label.""" - # ⚡ Bolt: Fast path starts using native find, avoiding nested O(N) regex evaluation - starts: list[int] = [] - index = text.find(label) + """Return text after the last admissible label until the next known label.""" + index = text.rfind(label) while index != -1: - if label == "coverage:" and text[max(0, index - 10) : index] == "docstring ": - index = text.find(label, index + len(label)) + if ( + ( + index > 0 + and (text[index - 1].isalnum() or text[index - 1] in "_-`") + ) + or ( + label == "coverage:" + and text[max(0, index - 10) : index] == "docstring " + ) + ): + index = text.rfind(label, 0, index) continue - starts.append(index) - index = text.find(label, index + len(label)) + break - if not starts: + if index == -1: return "" - start = starts[-1] + len(label) + start = index + len(label) end = len(text) - # ⚡ Bolt: Dynamically shrink the search window to prevent O(N) redundant scanning overhead for candidate in APPROVAL_VERIFICATION_LABELS: if candidate == label: continue @@ -977,8 +982,14 @@ def label_section(text: str, label: str) -> str: idx = text.find(candidate, start, end) while idx != -1: if ( - candidate == "coverage:" - and text[max(0, idx - 10) : idx] == "docstring " + ( + idx > 0 + and (text[idx - 1].isalnum() or text[idx - 1] in "_-`") + ) + or ( + candidate == "coverage:" + and text[max(0, idx - 10) : idx] == "docstring " + ) ): idx = text.find(candidate, idx + len(candidate), end) continue @@ -1441,38 +1452,233 @@ def reject(reason: str) -> None: return normalized +class DuplicateJsonMemberError(ValueError): + """Signal that an object repeats a member name.""" + + +def load_json_without_duplicate_members(text: str) -> Any: + """Decode JSON while rejecting ambiguous object member authority.""" + + def reject_duplicate_members(pairs: list[tuple[str, Any]]) -> dict[str, Any]: + """Build one object only when every member name is unique.""" + value: dict[str, Any] = {} + for key, member in pairs: + if key in value: + raise DuplicateJsonMemberError(key) + value[key] = member + return value + + return json.loads(text, object_pairs_hook=reject_duplicate_members) + + def iter_json_objects(text: str) -> list[Any]: """Extract top-level JSON values without promoting nested control objects.""" - decoder = json.JSONDecoder() values: list[Any] = [] try: # Fast path for pure JSON payloads; preserve the single top-level value. - return [json.loads(text)] - except json.JSONDecodeError: + return [load_json_without_duplicate_members(text)] + except (DuplicateJsonMemberError, json.JSONDecodeError, RecursionError): # OpenCode exports may contain prose around the JSON control object. pass - index = 0 - while True: - index = text.find("{", index) - if index == -1: - break + def blocks_nested_container(index: int, character: str) -> bool: + """Return whether an unmatched opener still resembles JSON syntax.""" next_index = index + 1 while next_index < len(text) and text[next_index] in " \t\r\n": next_index += 1 - if next_index < len(text) and text[next_index] not in {'"', "}"}: - index += 1 + next_character = text[next_index] if next_index < len(text) else "" + return (character == "{" and next_character in {'"', "}"}) or ( + character == "[" + and ( + next_character in '\"{[-0123456789]' + or any( + text.startswith(literal, next_index) + for literal in ( + "true", + "false", + "null", + "NaN", + "Infinity", + ) + ) + ) + ) + + diagnostic_opener_indices: set[int] = set() + diagnostic_label = "Diagnostic:" + diagnostic_label_index = 0 + diagnostic_label_complete = False + diagnostic_prefix_invalid = False + for diagnostic_index, diagnostic_character in enumerate(text): + if diagnostic_character in "\r\n": + diagnostic_label_index = 0 + diagnostic_label_complete = False + diagnostic_prefix_invalid = False continue - try: - value, new_index = decoder.raw_decode(text, index) - values.append(value) - # ⚡ Bolt: Advance index to avoid O(N^2) redundant parsing of nested JSON blocks - index = new_index + if diagnostic_prefix_invalid: + continue + if not diagnostic_label_complete: + if diagnostic_label_index == 0 and diagnostic_character.isspace(): + continue + if ( + diagnostic_label_index < len(diagnostic_label) + and diagnostic_character == diagnostic_label[diagnostic_label_index] + ): + diagnostic_label_index += 1 + diagnostic_label_complete = diagnostic_label_index == len( + diagnostic_label + ) + continue + diagnostic_prefix_invalid = True + continue + if diagnostic_character.isspace(): + continue + if diagnostic_character in "{[": + diagnostic_opener_indices.add(diagnostic_index) + diagnostic_prefix_invalid = True + + def is_recoverable_prose_container(start_index: int, nested_index: int) -> bool: + """Return whether a known diagnostic frame precedes the nested value.""" + if start_index not in diagnostic_opener_indices: + return False + frame_body = text[start_index + 1 : nested_index] + return frame_body.strip() == "pending" and any( + newline in frame_body for newline in "\r\n" + ) + + def apostrophe_is_word_internal(index: int) -> bool: + """Return whether an apostrophe joins two identifier-like characters.""" + return ( + 0 < index < len(text) - 1 + and (text[index - 1].isalnum() or text[index - 1] == "_") + and (text[index + 1].isalnum() or text[index + 1] == "_") + ) + + def delimiter_run_length_at(index: int, delimiter: str) -> int: + """Return the complete delimiter run length beginning at ``index``.""" + run_length = 0 + while ( + index + run_length < len(text) + and text[index + run_length] == delimiter + ): + run_length += 1 + return run_length + + markdown_container_characters = frozenset(" \t>+-*.)0123456789") + + def is_markdown_fence_prefix(start_index: int, end_index: int) -> bool: + """Return whether a line prefix contains only Markdown containers.""" + return all( + text[index] in markdown_container_characters + for index in range(start_index, end_index) + ) + + matched_spans: list[tuple[int, int, int | None, bool]] = [] + container_stack: list[tuple[str, int, bool]] = [] + blocking_depth = 0 + in_string = False + escaped = False + prose_quote_delimiter: str | None = None + prose_quote_escaped = False + prose_quote_skip_until = 0 + line_start_index = 0 + markdown_fence_line = False + markdown_fence_candidate_consumed = False + for index, character in enumerate(text): + if character in "\r\n": + line_start_index = index + 1 + markdown_fence_line = False + markdown_fence_candidate_consumed = False + elif markdown_fence_line: + continue + if not container_stack: + if index < prose_quote_skip_until: + continue + if prose_quote_delimiter is not None: + if prose_quote_delimiter.startswith("`"): + if character == "`": + backtick_run_length = delimiter_run_length_at(index, "`") + prose_quote_skip_until = index + backtick_run_length + if backtick_run_length == len(prose_quote_delimiter): + prose_quote_delimiter = None + elif prose_quote_escaped: + prose_quote_escaped = False + elif character == "\\": + prose_quote_escaped = True + elif character == prose_quote_delimiter and not ( + character == "'" and apostrophe_is_word_internal(index) + ): + prose_quote_delimiter = None + continue + if character in {"`", "~"}: + delimiter_run_length = delimiter_run_length_at(index, character) + prose_quote_skip_until = index + delimiter_run_length + is_markdown_fence = ( + not markdown_fence_candidate_consumed + and delimiter_run_length >= 3 + and is_markdown_fence_prefix(line_start_index, index) + ) + markdown_fence_candidate_consumed = True + if is_markdown_fence: + markdown_fence_line = True + elif character == "`": + prose_quote_delimiter = "`" * delimiter_run_length + continue + if character in {'"', "'"} and not ( + character == "'" and apostrophe_is_word_internal(index) + ): + prose_quote_delimiter = character + continue + if character in "{[": + blocks_nested = blocks_nested_container(index, character) + container_stack.append( + ("}" if character == "{" else "]", index, blocks_nested) + ) + blocking_depth += int(blocks_nested) + continue + + if in_string: + if escaped: + escaped = False + elif character == "\\": + escaped = True + elif character == '"': + in_string = False + continue + + if character == '"': + in_string = True + elif character in "{[": + parent_closer, parent_start, parent_blocks_nested = container_stack[-1] + if not parent_blocks_nested and not is_recoverable_prose_container( + parent_start, index + ): + container_stack[-1] = (parent_closer, parent_start, True) + blocking_depth += 1 + blocks_nested = blocks_nested_container(index, character) + container_stack.append( + ("}" if character == "{" else "]", index, blocks_nested) + ) + blocking_depth += int(blocks_nested) + elif character in "}]" and character == container_stack[-1][0]: + _, start_index, blocks_nested = container_stack.pop() + blocking_depth -= int(blocks_nested) + parent_start = container_stack[-1][1] if container_stack else None + matched_spans.append( + (start_index, index + 1, parent_start, blocking_depth > 0) + ) + + matched_starts = {start for start, _, _, _ in matched_spans} + for start_index, end_index, parent_start, blocked in matched_spans: + if blocked or parent_start in matched_starts: continue - except json.JSONDecodeError: + try: + values.append( + load_json_without_duplicate_members(text[start_index:end_index]) + ) + except (DuplicateJsonMemberError, json.JSONDecodeError, RecursionError): pass - index += 1 return values diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index e53741bd51..993a02ef74 100755 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -878,7 +878,9 @@ assert_opencode_review_uses_codegraph_and_contextual_orchestrator() { assert_file_contains "$workflow_file" '"$HEAD_SHA" "$RUN_ID" "$RUN_ATTEMPT" "$output_file"; then' "opencode review model steps pass current-run identity to the normalizer" assert_file_contains "$workflow_file" "normalize_opencode_output" "opencode review model steps normalize model control output" assert_file_contains "$workflow_file" "opencode_review_normalize_output.py" "opencode review model steps normalize transcript-embedded JSON output" - assert_file_contains "$REPO_ROOT/scripts/ci/opencode_review_normalize_output.py" "decoder.raw_decode" "opencode review normalizer scans transcript text for JSON objects" + if ! PYTHONPATH="$REPO_ROOT" python3 -c 'import json; from scripts.ci import opencode_review_normalize_output as norm; control_data = {"head_sha": "head", "run_id": "run", "run_attempt": "attempt"}; model_output = '"'"'Review noted a literal "{" in the log.\n'"'"' + json.dumps(control_data); assert norm.iter_json_objects(model_output) == [control_data]'; then + record_failure "opencode review normalizer must recover a control after a quoted prose delimiter" + fi assert_file_contains "$REPO_ROOT/scripts/ci/opencode_review_normalize_output.py" "valid_control" "opencode review normalizer accepts only current-run control JSON" assert_file_contains "$workflow_file" "opencode run" "opencode review workflow runs the bounded OpenCode agent path" assert_file_contains "$workflow_file" 'opencode run "$(cat "$prompt_file")"' "opencode review passes the prompt as the positional message before file attachments" @@ -1675,7 +1677,7 @@ EOF seal_opencode_test_artifacts "$tmp_dir" "abc123" "42" "1" "$changed_files_file" cat >"$output_file" <<'EOF' -OpenCode transcript text before the review control block. +OpenCode transcript text quotes a literal "{" before the review control block. {"head_sha":"abc123","run_id":"42","run_attempt":"1","result":"APPROVE","reason":"No blockers found after structural exploration of .github/workflows/opencode-review.yml.","summary":"Approval sufficiency: affirmative evidence supported approval beyond absence of blockers. Reviewed .github/workflows/opencode-review.yml, scripts/ci/opencode_review_normalize_output.py, and scripts/ci/test_strix_quick_gate.sh. Verification posture: Linter/static: actionlint and bash syntax evidence passed. TDD/regression: scripts/ci/test_strix_quick_gate.sh self-test evidence passed. Coverage: Coverage execution evidence reported 100% test coverage. Docstring coverage: Coverage execution evidence reported 100% docstring coverage. DAG: CodeGraph behavior DAG rendered .github/workflows/opencode-review.yml to GitHub Actions review job and verification path. PoC/execution: scratch PoC executed bash scripts/ci/test_strix_quick_gate.sh and passed. DDD/domain: no product domain boundary changed. CDD/context: CodeGraph structural MCP evidence covered the workflow and script blast radius. Similar issues: checked related OpenCode gate cases. Claim/concept check: no unverified user concept accepted. Standards search: checked current GitHub Actions/OpenCode docs where applicable. Compatibility/convention: workflow naming and shell conventions match existing code. Breaking-change/backcompat: no deployed public contract changed. Performance: no runtime path affected. Developer experience: review automation remains clear to maintainers and contributors. User experience: no user-facing UI affected. Visual/DOM: non-web workflow and review-comment output was checked. Accessibility/i18n: human-readable workflow and review text was checked. Supply-chain/license: dependency and external-tool risk was checked. Packaging: package and workflow contracts were checked. Security/privacy: token and pull_request_target boundaries preserved.","findings":[]} EOF diff --git a/tests/test_opencode_review_normalize_output.py b/tests/test_opencode_review_normalize_output.py index a24c541743..9aacded66c 100644 --- a/tests/test_opencode_review_normalize_output.py +++ b/tests/test_opencode_review_normalize_output.py @@ -1367,6 +1367,42 @@ def test_material_changed_file_scope_rejects_false_documentation_typo_reason( assert check_structural_approval(path) == 4 +def test_label_section_uses_last_non_docstring_coverage_label() -> None: + """Ignore embedded docstring labels while selecting the last test label.""" + combined = ( + "coverage: stale evidence " + "docstring coverage: 100% documentation evidence " + "coverage: 100% current evidence " + "performance: measured" + ) + + assert norm.label_section(combined, "coverage:") == " 100% current evidence " + + +def test_coverage_label_rejects_identifier_suffix_override() -> None: + """Do not let an identifier suffix override failed coverage evidence.""" + combined = ( + "coverage: coverage execution evidence not measured\n" + "uncoverage: coverage execution evidence 100%\n" + "docstring coverage: coverage execution evidence 100%" + ) + + assert not norm.mentions_full_coverage(combined, "") + + +def test_coverage_label_rejects_inline_quoted_override() -> None: + """Do not treat a quoted reviewer warning as authoritative evidence.""" + combined = ( + "coverage: coverage execution evidence not measured.\n" + "Reviewer note: do not claim `coverage: coverage execution evidence " + "proves 100% test coverage`.\n" + "docstring coverage: coverage execution evidence proves 100% docstring " + "coverage." + ) + + assert not norm.mentions_full_coverage("", combined) + + def test_label_and_full_coverage_detection(tmp_path, monkeypatch): combined = FULL_SUMMARY.casefold() assert "100%" in norm.label_section(combined, "coverage:") @@ -1375,6 +1411,19 @@ def test_label_and_full_coverage_detection(tmp_path, monkeypatch): "performance: FAST docstring coverage: 100% something else coverage: 100%" ) assert norm.label_section(text_coverage, "performance:") == " FAST " + assert ( + norm.label_section( + "coverage: stale\ncoverage: current\nperformance: measured", "coverage:" + ) + == " current\n" + ) + assert ( + norm.label_section( + "coverage: direct\ndocstring coverage: docs\nperformance: measured", + "coverage:", + ) + == " direct\n" + ) assert norm.mentions_full_coverage("", FULL_SUMMARY) no_source_summary = FULL_SUMMARY.replace( "coverage execution evidence proves 100% test coverage", @@ -2482,6 +2531,492 @@ def test_iter_json_objects_extracts_raw_and_embedded_json(): assert norm.iter_json_objects("no json here") == [] +def test_iter_json_objects_rejects_duplicate_members_at_any_depth(): + """Duplicate JSON members cannot gain last-wins control authority.""" + assert norm.iter_json_objects('{"value": 1, "value": 2}') == [] + assert ( + norm.iter_json_objects( + 'prefix {"wrapper": {"control": true, "control": true}} suffix' + ) + == [] + ) + + +def test_main_rejects_duplicate_current_run_identity_without_rewriting( + tmp_path, capsys +): + """A later duplicate identity cannot replace an earlier stale identity.""" + output = tmp_path / "duplicate-identity-control.txt" + original = json.dumps(control()).replace( + '"head_sha": "head"', + '"head_sha": "stale", "head_sha": "head"', + 1, + ) + output.write_text(original, encoding="utf-8") + + assert norm.main(["normalizer", "head", "run", "attempt", str(output)]) == 4 + assert output.read_text(encoding="utf-8") == original + assert "no top-level current-run control JSON object" in capsys.readouterr().err + + +def test_iter_json_objects_skips_non_json_prose_delimiters(): + """Unclosed prose delimiters cannot hide a later complete control object.""" + control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + encoded_control = json.dumps(control) + + assert norm.iter_json_objects("Diagnostic: [pending\n" + encoded_control) == [ + control + ] + assert norm.iter_json_objects("Diagnostic: {pending\n" + encoded_control) == [ + control + ] + + +class PrefixScanCountingText(str): + """Count prefix-wide searches performed on an untrusted transcript.""" + + def __new__(cls, value): + """Create a string that records every rfind call.""" + + instance = super().__new__(cls, value) + instance.rfind_call_count = 0 + return instance + + def rfind(self, substring, start=None, end=None): + """Record one reverse search before delegating to str.""" + + self.rfind_call_count += 1 + if start is None: + return super().rfind(substring) + if end is None: + return super().rfind(substring, start) + return super().rfind(substring, start, end) + + +class SliceCountingText(str): + """Count characters copied by slices of an untrusted transcript.""" + + def __new__(cls, value): + """Create a string that records cumulative sliced width.""" + + instance = super().__new__(cls, value) + instance.sliced_character_count = 0 + return instance + + def __getitem__(self, key): + """Record copied slice width before returning the normal string value.""" + + result = super().__getitem__(key) + if isinstance(key, slice): + self.sliced_character_count += len(result) + return result + + +def test_iter_json_objects_does_not_rescan_prefix_per_nested_opener(): + """Nested untrusted delimiters retain the scanner's linear-time contract.""" + + nested_transcript = PrefixScanCountingText( + "prefix " + "{x" * 64 + '{"head_sha":"head"}' + ) + + assert norm.iter_json_objects(nested_transcript) == [] + assert nested_transcript.rfind_call_count <= 2 + + +def test_iter_json_objects_does_not_copy_line_prefix_per_backtick_span(): + """Backtick fence classification retains the scanner's linear contract.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + encoded_control = json.dumps(current_control) + transcript = SliceCountingText("prefix " + "`example` " * 400 + encoded_control) + + assert norm.iter_json_objects(transcript) == [current_control] + assert transcript.sliced_character_count <= len(encoded_control) + 3 + + +def test_iter_json_objects_does_not_copy_nested_container_prefix(): + """Nested fence classification cannot copy or backtrack over its prefix.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + encoded_control = json.dumps(current_control) + transcript = SliceCountingText( + "> " * 20 + "not-a-fence ~~~ " + encoded_control + ) + + assert norm.iter_json_objects(transcript) == [current_control] + assert transcript.sliced_character_count <= len(encoded_control) + 3 + + +def test_iter_json_objects_fails_closed_on_excessive_json_nesting(): + """Hostile nesting cannot crash the review-output normalizer.""" + deeply_nested_json = "[" * 10_000 + "0" + "]" * 10_000 + + assert norm.iter_json_objects(deeply_nested_json) == [] + + +@pytest.mark.parametrize("quoted_delimiter", ["{", "["]) +def test_iter_json_objects_skips_quoted_prose_delimiters(quoted_delimiter): + """Quoted prose punctuation cannot hide a later independent control.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = ( + f'Review noted a literal "{quoted_delimiter}" in the log.\n' + + json.dumps(current_control) + ) + + assert norm.iter_json_objects(text) == [current_control] + + +@pytest.mark.parametrize( + ("quote", "quoted_delimiter"), + [ + ("'", "{"), + ("'", "["), + ("`", "{"), + ("`", "["), + ("``", "{"), + ("``", "["), + ], +) +def test_iter_json_objects_skips_inline_delimiter_literals( + quote, quoted_delimiter +): + """Paired prose literals cannot hide a later independent control.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = ( + f"Review noted a literal {quote}{quoted_delimiter}{quote} in the log.\n" + + json.dumps(current_control) + ) + + assert norm.iter_json_objects(text) == [current_control] + + +@pytest.mark.parametrize("quote", ["'", "`", "``"]) +def test_iter_json_objects_does_not_promote_inline_control_examples(quote): + """Quoted examples cannot become authoritative approval controls.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = ( + f"Previous candidate was {quote}{json.dumps(example_control)}{quote}, " + "but reject it." + ) + + assert norm.iter_json_objects(text) == [] + + +def test_iter_json_objects_extracts_control_from_markdown_fence(): + """A fenced final JSON payload remains an eligible embedded control.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "```json\n" + json.dumps(current_control) + "\n```" + + assert norm.iter_json_objects(text) == [current_control] + + +@pytest.mark.parametrize( + "fence_line_transcript", + [ + "```json \n```", + "```json\nreview prose\n``` ", + "~~~json \n~~~", + "~~~json\nreview prose\n~~~ ", + "> ~~~json \n> ~~~", + "> ~~~json\n> review prose\n> ~~~ ", + "- ~~~json \n ~~~", + "> - ~~~json \n> ~~~", + "> ```json\n> review prose\n> ``` ", + "- ```json\n review prose\n ``` ", + "- review prose\n ~~~json \n ~~~", + "1. review prose\n ~~~json \n ~~~", + "- review prose\n ~~~json\n body\n ~~~ ", + "123456789. review prose\n ~~~json \n ~~~", + ], +) +def test_iter_json_objects_ignores_controls_on_markdown_fence_lines( + fence_line_transcript, +): + """A fence delimiter line cannot itself publish a control example.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = fence_line_transcript.replace("", json.dumps(example_control)) + + assert norm.iter_json_objects(text) == [] + + +@pytest.mark.parametrize( + ("quote", "mixed_run_text"), + [("`", "``` text `` "), ("``", "``` text ` ")], +) +def test_iter_json_objects_requires_exact_backtick_closing_run( + quote, mixed_run_text +): + """A longer backtick run cannot end a shorter quoted example.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = f"{quote}example {mixed_run_text}" + json.dumps(example_control) + quote + + assert norm.iter_json_objects(text) == [] + + +@pytest.mark.parametrize("quote", ["`", "``"]) +def test_iter_json_objects_recovers_after_exact_backtick_closing_run(quote): + """A mixed longer run cannot hide control after the exact closing run.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = f"{quote}example ``` text{quote}.\n" + json.dumps(current_control) + + assert norm.iter_json_objects(text) == [current_control] + + +def test_iter_json_objects_does_not_promote_inline_triple_backtick_example(): + """A same-line triple-backtick span is prose, not a Markdown fence.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "Previous ```" + json.dumps(example_control) + "``` was rejected." + + assert norm.iter_json_objects(text) == [] + + +def test_iter_json_objects_does_not_treat_contraction_as_prose_quote(): + """An apostrophe within a word cannot hide a later independent control.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "The review doesn't change the parser.\n" + json.dumps(current_control) + + assert norm.iter_json_objects(text) == [current_control] + + +def test_iter_json_objects_keeps_contraction_inside_single_quoted_example(): + """A contraction cannot end a quoted example and promote its control.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "'doesn't accept " + json.dumps(example_control) + "'" + + assert norm.iter_json_objects(text) == [] + + +def test_iter_json_objects_preserves_control_after_quoted_contraction(): + """A contraction cannot keep a completed quote open across real control.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "Review said 'it doesn't contain a control'.\n" + json.dumps( + current_control + ) + + assert norm.iter_json_objects(text) == [current_control] + + +def test_iter_json_objects_recognizes_quote_adjacent_to_word(): + """A quote beside prose still prevents promotion of its example control.""" + example_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "example'" + json.dumps(example_control) + "'" + + assert norm.iter_json_objects(text) == [] + + +def test_iter_json_objects_keeps_unclosed_prose_quote_fail_closed(): + """A next-line control inside an unfinished quote is not independent.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = 'Review noted an unfinished "{ delimiter.\n' + json.dumps( + current_control + ) + + assert norm.iter_json_objects(text) == [] + + +def test_iter_json_objects_honors_escaped_quotes_in_quoted_prose(): + """An escaped prose quote cannot end delimiter suppression early.""" + current_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = 'Review noted "an escaped \\" quote and { delimiter".\n' + json.dumps( + current_control + ) + + assert norm.iter_json_objects(text) == [current_control] + + +def test_main_normalizes_control_after_quoted_prose_delimiter(tmp_path): + """The CLI preserves a current-run control after a quoted prose brace.""" + output = tmp_path / "quoted-prose-control.txt" + output.write_text( + 'Review noted a literal "{" in the log.\n' + json.dumps(control()), + encoding="utf-8", + ) + + assert norm.main(["normalizer", "head", "run", "attempt", str(output)]) == 0 + assert "opencode-review-control-v1" in output.read_text(encoding="utf-8") + + +def test_iter_json_objects_does_not_promote_control_nested_in_malformed_outer(): + """A malformed outer container cannot promote nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + malformed_object = '{"outer":' * 2_000 + json.dumps(nested_control) + " trailing" + malformed_array = "[" * 2_000 + json.dumps(nested_control) + " trailing" + + assert norm.iter_json_objects(malformed_object) == [] + assert norm.iter_json_objects(malformed_array) == [] + + +@pytest.mark.parametrize("non_finite_value", ["NaN", "Infinity"]) +def test_iter_json_objects_does_not_promote_control_from_non_finite_array( + non_finite_value, +): + """Python JSON extensions cannot expose nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = f"review prose [{non_finite_value}, {json.dumps(nested_control)}]" + + values = norm.iter_json_objects(text) + + assert len(values) == 1 + assert isinstance(values[0], list) + assert values[0][1] == nested_control + + +@pytest.mark.parametrize( + "malformed_outer", + [ + "[undefined, ]", + "[unquoted_token, ]", + "{unquoted_key: }", + "[undefined ]", + "[unquoted_token ]", + "{unquoted_key }", + ], +) +def test_iter_json_objects_does_not_promote_control_from_invalid_outer_token( + malformed_outer, +): + """A balanced invalid outer token cannot expose nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "review prose " + malformed_outer.replace( + "", json.dumps(nested_control) + ) + + assert norm.iter_json_objects(text) == [] + + +@pytest.mark.parametrize( + "malformed_prefix", + [ + "[undefined, ", + "[unquoted_token ", + "[unquoted_token\n", + "{unquoted_key: ", + "{unquoted_key ", + "{unquoted_key\n", + ], +) +def test_iter_json_objects_does_not_promote_control_from_unclosed_invalid_outer( + malformed_prefix, +): + """An unfinished invalid wrapper cannot expose nested control evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + text = "review prose " + malformed_prefix + json.dumps(nested_control) + + assert norm.iter_json_objects(text) == [] + + +@pytest.mark.parametrize("malformed_prefix", ["Review: [pending\n", "Note: {pending\n"]) +def test_iter_json_objects_requires_diagnostic_label_for_prose_recovery( + malformed_prefix, +): + """An arbitrary pending label cannot manufacture top-level evidence.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + + assert norm.iter_json_objects(malformed_prefix + json.dumps(nested_control)) == [] + + +def test_iter_json_objects_requires_diagnostic_opener_immediately_after_label(): + """Extra diagnostic prose cannot authorize nested control recovery.""" + nested_control = { + "head_sha": "head", + "run_id": "run", + "run_attempt": "attempt", + } + + assert ( + norm.iter_json_objects( + "Diagnostic: ignored [pending\n" + json.dumps(nested_control) + ) + == [] + ) + + @pytest.mark.parametrize("approve_first", [True, False]) def test_main_rejects_conflicting_current_run_controls_without_rewriting( tmp_path, capsys, approve_first