From 381a83bc62ab05858c70e29ac11c3907b607bcdd Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:08:48 +0200 Subject: [PATCH 1/9] Plan toolkit 0.8.6 Draft integration --- PLANS.md | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 274 insertions(+), 1 deletion(-) diff --git a/PLANS.md b/PLANS.md index ca171a2..493b60e 100644 --- a/PLANS.md +++ b/PLANS.md @@ -4,4 +4,277 @@ Use this file for active or blocked repository work. Update it before implementa ## Active Work -No active or blocked repository work. +### Toolkit 0.8.6 - OCR 1.11.0 and precise security-signal classification + +Status: active + +#### Goal + +Prepare a fully implemented, validated, and hosted-green Draft feature pull request for +toolkit 0.8.6. The Draft qualifies and exclusively targets OCR 1.11.0, preserves private +reasoning and provider request controls across the existing DLP/publication boundary, +fixes issue #153's false security promotion, and leaves merge and stable publication to a +later owner-authorized continuation. + +#### Plan Origin + +`plan_mode_approved` + +#### Requested Scope + +- Create `v0.8.6`, assign open issue #153 and the canonical OCR 1.11.0 compatibility issue + to `xeonvs`, and keep both issues plus the milestone open at handoff. +- Update the qualification harness before dispatch so exact OCR 1.10.2 comparison evidence + and exact OCR 1.11.0 candidate evidence use their own strict grouping inventory formats. +- Manually dispatch hosted compatibility qualification for exact `v1.11.0`, review its + machine evidence and upstream source semantics, and promote only confirmed contracts. +- Make OCR 1.11.0 the sole runtime/preflight target; retain 1.10.2 only as historical and + transition-comparison evidence, never as a supported fallback. +- Verify new grouping inventory, `file_find`, Handlebars/Mustache rules, timeout scaling, + private reasoning replay, `tool_choice`, completion-cap, effort, and max-tools behavior. +- Preserve one data flow from private OCR session/result through canonical projection, + DLP, publication, receipt, and approval; do not add a public reasoning schema. +- Fix #153 so neutral domain phrases do not promote reviewer-guide security counts while + closed, contextual injection classes and explicit security metadata continue to do so. +- Correct the root README installation path and current public documentation for exact + Python/OCR requirements, privacy boundaries, provider controls, and external validation. +- Atomically update the PATH-effective local Darwin arm64 OCR to exact 1.11.0 and perform + only checksum-verified no-LLM checks without changing configuration, credentials, or + the caller-owned home. +- Finish with one green Draft PR. Do not mark it ready, merge it, prepare a release branch, + tag, publish packages, close issues, or close the milestone. + +Release classification: `release-required`; target stable version: `0.8.6`; delivery +state for this task: `release-deferred` after a green Draft handoff. + +#### Requirement Traceability + +| Requirement | Outcome | Queue | Verification | +| --- | --- | --- | --- | +| `REQ-001` | Start from synchronized released v0.8.5, materialize this plan first, and open a Draft only after signed plan/harness commits. | `WQ-01`, `WQ-02` | Git status, plan fidelity, signed commits, remote/Draft readback | +| `REQ-002` | Strictly distinguish old 1.10.2 and new 1.11.0 grouping inventory in qualification without production backward compatibility. | `WQ-02` | Focused parser/gateway tests and exact workflow dispatch | +| `REQ-003` | Create and reconcile milestone v0.8.6, #153, and the canonical OCR 1.11.0 issue. | `WQ-03` | GitHub API readback | +| `REQ-004` | Qualify and exclusively adopt checksum-pinned OCR 1.11.0 with a complete semantic source audit. | `WQ-03`, `WQ-04` | Hosted evidence, hashes, manifest/preflight/example tests | +| `REQ-005` | Verify grouping, file lookup, rules, timeout, reasoning replay, tool choice, completion, effort, and max-tools contracts without public schema drift. | `WQ-04`, `WQ-05` | Controlled gateway and installed-artifact contract tests | +| `REQ-006` | Keep reasoning/session/provider request data private and preserve DLP, receipt v5, telemetry, summary, and approval boundaries. | `WQ-05` | Hostile projection, cleanup, receipt, approval, and leak regressions | +| `REQ-007` | Fix #153 using a closed contextual injection matcher that affects only reviewer-guide analytics. | `WQ-06` | Issue reproducer, positive/neutral/Unicode tests, input immutability | +| `REQ-008` | Update README, public docs, backlog reconciliation, and categorized release notes for humans and release agents. | `WQ-04`, `WQ-07` | Documentation contracts, Towncrier draft, link/version consistency | +| `REQ-009` | Replace local OCR safely and validate exact 1.11.0 without LLM or user-config changes. | `WQ-04` | Binary digest/version/help and isolated no-LLM previews | +| `REQ-010` | Complete one local final gate, push once, reconcile hosted CI and leave a clean green Draft with an exact external qualification checklist. | `WQ-08`, `WQ-09` | Quality/coverage/security gates, remote/PR/check/thread/worktree readback | + +#### Explicit Non-Goals + +- No real LLM/provider call in this environment and no local model peer. +- No compatibility range, production parser fallback, migration layer, or support promise + for OCR 1.10.x or older; the 1.10.2 run is comparison evidence only. +- No new public result, receipt, telemetry, DLP-signal, or approval schema and no second + reasoning-specific DLP pipeline. +- No publication of prompts, reasoning, provider bodies, tool arguments/results, + credentials, model/provider identity, request IDs, paths, or session files. +- No dynamic timeout environment variable, second compatibility cron, polling service, + unpinned npm OCR recommendation, or global bare-pip installation guidance. +- No consumption of upstream GitHub Action, OpenCode plugin, npm launcher, Korean docs, + or provider preset changes. +- No mechanical test-directory reorganization or production refactor solely for coverage. +- No stable release, TestPyPI/PyPI publication, PR merge, issue closure, or milestone closure. + +#### Constraints + +- Runtime preflight accepts exact OCR 1.11.0 only. Version-aware old-format parsing is + confined to the repository qualification harness and cannot enter production runtime. +- Baseline 1.10.2 accepts only `path (STATUS, +N/-M)`; candidate 1.11.0 accepts only + `STATUS path (+N/-M)`. Mixed, duplicate, malformed, reordered, truncated, overflowed, + status-inconsistent, or churn-losing inventories fail closed. +- `reasoning_content`, Anthropic signed thinking, Responses encrypted reasoning, + `tool_choice`, and OCR session cache remain provider/session-private. They never affect + findings, severity, DLP counts, summary analytics, receipt, telemetry, or approval. +- Existing canonical-public DLP remains authoritative: private-only unknown fields may be + removed without blocking approval only when the canonical public projection is byte + equivalent; canonical/public filtering always blocks approval. +- OCR temporary HOME cleanup completes before publication. Cleanup failure, hostile + replay, impossible receipt state, or leaked reasoning fails closed. +- The #153 matcher consumes only the already DLP-checked published finding projection and + changes only reviewer-guide security count/effort, never finding or lifecycle state. +- Every new production and test function receives a purpose-focused docstring. +- Before every signed logical commit: focused tests, complete slice diff self-review, + requirement/trust/data-flow/privacy review, backlog reconciliation where applicable, + and `git diff --check`. +- After the initial plan/harness push, do not push partial implementation; perform one + final push only after all local slices and final gates are complete. + +#### Inputs And Sources + +- Owner-approved implementation plan in the preceding Plan Mode conversation. +- Released toolkit v0.8.5 at `72c511104f078110ea78bb8f1f2bb1d4048f4d20`, + `.next-version` `0.8.6`, open issue #153, and current repository contracts. +- Official OCR v1.11.0 release, adjacent 1.10.2 source comparison, release assets, + checksums, help output, and upstream feature/fix history. +- Exact release anchors: Linux amd64 + `13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60`, Darwin arm64 + `ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78`, and + `sha256sum.txt` `9dff050ec859882bef26037415b8bd9e5db70c5a7d960e5eb3989385372311ee`. +- Current compatibility manifest/evidence/harness/workflow, runtime preflight/configuration, + review runner/result publication/DLP/receipt/approval, posting formatter, tests, README, + public docs, strategy, roadmap, and backlog. +- Workflow audit using engineering-workflow 0.8.1: mature repository, canonical owners + and required navigation indexes present; no instruction migration required. + +#### User Decisions And Answers + +- Target toolkit 0.8.6 and OCR 1.11.0 in one Draft-only delivery. +- Support only the current OCR release; comparison with 1.10.2 must not become backward + compatibility. +- Include exact old/new grouping checks and provider-wire checks in the Draft handoff for + another environment with configured OCR and LLM access. +- Treat reasoning and tool choice comprehensively, extend DLP edge coverage, and update + stale root README installation guidance. +- Update the local OCR binary, but skip local LLM calls in this environment. +- Use complete logical signed commits with self-review; leave the final PR in Draft. + +#### Completed Baseline State + +- `main` and `origin/main` are clean and synchronized at released v0.8.5 commit + `72c5111`; there are no open PRs and no v0.8.6 milestone. +- Issue #153 is the sole open issue and has no assignee or milestone. +- The manifest/preflight/example and PATH-effective local OCR target exact 1.10.2. +- Compatibility discovery runs once daily at `07:15 UTC` and retains exact manual + dispatch. No 1.11.0 issue has yet been created. +- The qualification stub parses only the old grouping inventory, so dispatching 1.11.0 + before the harness correction would produce false failure evidence. +- Root README recommends package installation without a Python range or isolated CLI + owner and refers only generically to a separately installed supported OCR. + +#### Current Work Queue + +| Queue | Status | Deliverable | +| --- | --- | --- | +| `WQ-01` | `done` | Full plan materialized first and passed the workflow fidelity/lifecycle check. | +| `WQ-02` | `in_progress` | Implement strict version-gated grouping qualification, commit the harness, then push the two initial commits and open Draft. | +| `WQ-03` | `pending` | Create/assign/milestone issues and obtain hosted exact OCR 1.11.0 qualification evidence. | +| `WQ-04` | `pending` | Integrate 1.11.0 evidence, pins, preflight/example/docs/rules/timeouts/backlog and local no-LLM binary update. | +| `WQ-05` | `pending` | Add reasoning/tool-choice/private-session qualification and DLP/cleanup/receipt/approval regressions. | +| `WQ-06` | `pending` | Implement and verify #153's closed contextual security-signal matcher. | +| `WQ-07` | `pending` | Update README/public docs and categorized changelog with the external qualification table. | +| `WQ-08` | `pending` | Run holistic self-review and the one complete local final gate; update plan to truthful Draft handoff state. | +| `WQ-09` | `pending` | Final push, hosted CI reconciliation, Draft/issue/milestone/remote/worktree readback. | + +#### Locked Decisions + +- Branch: `codex/v0.8.6-ocr-1.11.0-security-signal`; Draft base: protected `main`. +- Compatibility comparison is strict and version-bound: 1.10.2 old format versus 1.11.0 + new format. Runtime and public installation support only 1.11.0. +- GitLab example job timeout becomes 45 minutes. OCR base timeout remains inherited 15 + minutes, yielding low/medium/high effective limits of 15/30/45 minutes. +- Completion behavior remains inherited cap 16384 with the existing explicit toolkit + override example 4096. Default effort remains medium; max-tools semantics are unchanged. +- Provider flow: + `private session/result -> canonical projection -> DLP -> publication -> receipt/approval`. +- Reviewer-guide flow: + `DLP-checked published finding -> closed signal matcher -> guide count/effort only`. +- Changelog categories: OCR qualification/pins are Maintenance; Handlebars/Mustache are + Rules; #153 is Bug Fix; installation and public explanation are Documentation. +- BL-010, BL-017, and BL-021 remain open/conditional because 1.11.0 does not meet their + exit criteria; record reconciliation without inventing progress. + +#### Verification + +- Qualification inventory fixtures cover old/new valid forms; add/modify/delete/rename, + binary and zero-churn records; spaces, parentheses, backslashes, Unicode, duplicate and + reordered paths; mismatched status, mixed format, truncation, overflow, and malformed + prompt boundaries. +- Controlled gateway tests cover grouping stage order, medium rounds, cap 16384, explicit + 4096, absent versus explicit `tool_choice`, text-only comment retention, OpenAI Chat + reasoning replay, Anthropic signed thinking, Responses encrypted reasoning, ordering, + orphan/duplicate/malformed/cross-protocol payloads, and bounded session behavior. +- DLP tests cover secrets/tokens, PII, paths, URLs, request/model/provider identifiers, + Markdown/HTML, GitLab commands/mentions, Unicode normalization, bidi/format controls, + NUL/HTAB/VT/FF, oversized/nested laundering, canonical versus private-only projection, + hostile replay, receipt rejection, cleanup success/failure, and approval independence. +- #153 tests cover the exact reproducer, explicit metadata, closed injection classes, + neutral phrases, punctuation/Unicode/word boundaries, determinism, and input immutability. +- Exact 1.11.0 manifest/preflight/example/hash/default/README/documentation/backlog and + changelog contract tests; local version/help and no-LLM rules/background previews. +- Final local gate once: `scripts/quality.sh check`, coverage floors, + `scripts/ocr_compat.py validate`, lock check, Towncrier draft, `scripts/gitleaks.sh`, + and `git diff --check`. Hosted PR workflows own package, OS/Python, dependencies, + Security, and CodeQL gates. +- External configured-environment checklist compares checksum-verified 1.10.2 and 1.11.0 + on one private fixture, then qualifies exact Draft head with real 1.11.0 and a controlled + gateway. Only versions, hashes, structural assertions, and pass/fail may enter the PR. + +#### Latest Validation Results + +- 2026-08-28: `main`/`origin/main` clean at v0.8.5 `72c5111`; no open PR or v0.8.6 + milestone; issue #153 is the only open issue. +- 2026-08-28: engineering-workflow 0.8.1 audit found the mature canonical repository + owners and documentation indexes present. The audit traversed ignored quality artifacts + but identified no tracked workflow migration requirement. +- 2026-08-28: exact OCR 1.11.0 release hashes, public help defaults, source changes, local + 1.10.2 state, and the old-format-only grouping harness were read before this first write. +- 2026-08-28: this active plan passes the engineering-workflow lifecycle/fidelity check + and `git diff --check`; the planning slice has no product/runtime change. + +#### Risks And Recovery + +- GitHub schedule omitted the same-day release. Manual exact-tag dispatch after the harness + fix is the recovery; do not add schedule frequency or duplicate runs. +- Hosted qualification can fail or create a machine issue without usable evidence. Keep the + issue/run open, inspect bounded artifacts, correct only demonstrated harness/product faults, + and never promote an unqualified release. +- An automatic compatibility PR may appear. Compare it against reviewed evidence, integrate + only required bytes into this Draft, and close/supersede it truthfully without merging it. +- Local binary replacement can fail. Retain the verified 1.10.2 binary until 1.11.0 passes + checksum/version/help/no-LLM checks and atomically restore it on mismatch. +- Provider reasoning or request controls could escape through an unowned field. Keep one + canonical projection/DLP owner, fail closed at public/receipt boundaries, and test all sinks. +- Strict grouping parsing could accidentally imply old runtime support. Keep baseline parsing + in qualification-only code and assert exact runtime rejection of 1.10.x. +- Hosted CI may expose a real defect. Fix only evidence-backed boundaries in a separately + self-reviewed signed commit, then rerun the affected and final gates before pushing. + +#### Resume Point + +Continue `WQ-02`: make the signed planning commit, then implement and validate only the +strict version-gated grouping qualification slice before the initial push. + +#### Plan Fidelity Check + +- [x] Every approved outcome has a stable requirement and queue owner. +- [x] Release-required classification, target 0.8.6, Draft-only deferred delivery, and + explicit non-publication boundary are recorded. +- [x] Exact versions/hashes, old/new qualification distinction, runtime compatibility + decision, data flows, DLP/reasoning/tool-choice rules, issue fix, local binary, docs, + validation, recovery, and external handoff are preserved. +- [x] Initial/final push behavior, signed commit gates, and hosted ownership are explicit. +- [x] Resume point names the first safe unfinished action. + +#### Reconciliation Check + +- [x] Current main/tag/next version, worktree, plan, issues, PRs, milestones, workflow, + local OCR, manifest, harness, README, backlog, and canonical docs were read. +- [ ] Hosted OCR 1.11.0 issue/evidence and semantic source audit agree. +- [ ] Backlog, roadmap, strategy, public docs, changelog, issues, milestone, and Draft agree. +- [ ] Final local/hosted validation, head/tree, threads, remote ref, and worktree agree. + +#### Closure Gate + +- [ ] All in-scope requirements and queue items are done or justified out of scope. +- [ ] Every logical commit passed focused tests, self-review, boundary review, and + `git diff --check`. +- [ ] Final quality, coverage, manifest, lock, Towncrier, Gitleaks, and diff gates are green. +- [ ] Hosted required Draft checks are green with no unresolved conversations. +- [ ] Draft body, issues, milestone, remote ref, exact head/tree, and clean worktree agree. + +#### Post-Close Delivery + +- This task deliberately stops at a green Draft PR. Merge, protected-main development + publication, `release/v0.8.6`, stable publication, external artifact reconciliation, + issue closure, and milestone closure require a later explicit owner continuation. + +#### Handoff Notes + +- Draft body must retain Added/Fixed/Changed/Unchanged sections, exact toolkit head/tree, + OCR hashes and hosted evidence, strict old/new grouping comparison, local no-LLM checks, + backlog disposition, and a safe external configured-environment qualification table. +- The external agent starts from exact Draft head and OCR 1.11.0. It may run 1.10.2 only + as an isolated comparison and must not interpret that run as toolkit compatibility. From 462edfb1dcf45727b84100c6ba4c1098aa6f03d7 Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:15:14 +0200 Subject: [PATCH 2/9] Qualify OCR grouping inventory by release format --- PLANS.md | 9 ++- scripts/ocr_compat.py | 131 +++++++++++++++++++++++++++++---- tests/test_ocr_compat.py | 153 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 275 insertions(+), 18 deletions(-) diff --git a/PLANS.md b/PLANS.md index 493b60e..0eed052 100644 --- a/PLANS.md +++ b/PLANS.md @@ -149,7 +149,7 @@ state for this task: `release-deferred` after a green Draft handoff. | Queue | Status | Deliverable | | --- | --- | --- | | `WQ-01` | `done` | Full plan materialized first and passed the workflow fidelity/lifecycle check. | -| `WQ-02` | `in_progress` | Implement strict version-gated grouping qualification, commit the harness, then push the two initial commits and open Draft. | +| `WQ-02` | `in_progress` | Strict version-gated grouping qualification is implemented and validated; commit it, then push the two initial commits and open Draft. | | `WQ-03` | `pending` | Create/assign/milestone issues and obtain hosted exact OCR 1.11.0 qualification evidence. | | `WQ-04` | `pending` | Integrate 1.11.0 evidence, pins, preflight/example/docs/rules/timeouts/backlog and local no-LLM binary update. | | `WQ-05` | `pending` | Add reasoning/tool-choice/private-session qualification and DLP/cleanup/receipt/approval regressions. | @@ -213,6 +213,9 @@ state for this task: `release-deferred` after a green Draft handoff. 1.10.2 state, and the old-format-only grouping harness were read before this first write. - 2026-08-28: this active plan passes the engineering-workflow lifecycle/fidelity check and `git diff --check`; the planning slice has no product/runtime change. +- 2026-08-28: 86 compatibility tests pass, including 14 focused old/new grouping and + gateway tests; Ruff, MyPy, and `git diff --check` pass. Exact local OCR 1.10.2 also + passes the strict old-format semantic grouping probe through the loopback-only gateway. #### Risks And Recovery @@ -234,8 +237,8 @@ state for this task: `release-deferred` after a green Draft handoff. #### Resume Point -Continue `WQ-02`: make the signed planning commit, then implement and validate only the -strict version-gated grouping qualification slice before the initial push. +Continue `WQ-02`: commit the reviewed harness slice, push the two signed initial commits, +open the Draft, and then create/dispatch the `WQ-03` GitHub coordination state. #### Plan Fidelity Check diff --git a/scripts/ocr_compat.py b/scripts/ocr_compat.py index c0a6691..ce6aa9a 100644 --- a/scripts/ocr_compat.py +++ b/scripts/ocr_compat.py @@ -46,6 +46,9 @@ MAX_RELEASE_CHANGES_LINES = 50 MAX_QUALIFICATION_CHAIN = 10 MAX_CLI_PROBE_BYTES = 100_000 +MAX_GROUPING_INVENTORY_ENTRIES = 100 +MAX_GROUPING_PATH_CHARS = 1_000 +MAX_GROUPING_CHURN = 1_000_000_000 DOWNLOAD_ATTEMPTS = 3 VERSION_RE = re.compile(r"^v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$") SHA256_RE = re.compile(r"^(?:sha256:)?([0-9a-f]{64})$") @@ -166,6 +169,16 @@ def __init__(self, message: str, *, phase: str, reason: str) -> None: self.reason = reason +@dataclass(frozen=True) +class GroupingInventoryEntry: + """One strictly parsed, qualification-only grouping inventory entry.""" + + status: str + path: str + insertions: int + deletions: int + + class _NoRedirectHandler(urllib.request.HTTPRedirectHandler): """Reject metadata redirects so the reviewed API origin cannot change.""" @@ -763,6 +776,8 @@ class _StubHandler(http.server.BaseHTTPRequestHandler): tokens_per_request = 2 grouping_tokens_per_request = 2 grouping_mode = "singletons" + grouping_inventory_version: str | None = None + grouping_inventories: list[list[GroupingInventoryEntry]] = [] main_mode = "findings" completion_caps: list[object] = [] request_stages: list[str] = [] @@ -779,18 +794,13 @@ def _message_contents(messages: list[Any]) -> list[str]: @classmethod def _grouping_files(cls, messages: list[Any]) -> list[str]: - """Extract the public grouping prompt's changed-file inventory.""" + """Extract one version-bound grouping inventory and retain structural evidence.""" - paths: list[str] = [] - for content in cls._message_contents(messages): - for match in re.finditer( - r"(?m)^([^\r\n]+) \((?:ADDED|MODIFIED|DELETED|RENAMED), \+[0-9]+/-[0-9]+\)$", - content, - ): - candidate = match.group(1) - if candidate not in paths: - paths.append(candidate) - return paths + if cls.grouping_inventory_version is None: + _fail("grouping inventory version is not configured") + entries = parse_grouping_inventory(messages, cls.grouping_inventory_version) + cls.grouping_inventories.append(entries) + return [entry.path for entry in entries] @classmethod def _review_path(cls, messages: list[Any]) -> str | None: @@ -960,6 +970,7 @@ def _stub_gateway( tokens_per_request: int = 2, grouping_tokens_per_request: int = 2, grouping_mode: str = "singletons", + grouping_inventory_version: str | None = None, main_mode: str = "findings", ) -> Iterator[str]: """Serve deterministic responses with configurable real usage accounting.""" @@ -974,6 +985,8 @@ def _stub_gateway( _StubHandler.tokens_per_request = tokens_per_request _StubHandler.grouping_tokens_per_request = grouping_tokens_per_request _StubHandler.grouping_mode = grouping_mode + _StubHandler.grouping_inventory_version = grouping_inventory_version + _StubHandler.grouping_inventories = [] _StubHandler.main_mode = main_mode _StubHandler.completion_caps = [] _StubHandler.request_stages = [] @@ -988,6 +1001,81 @@ def _stub_gateway( thread.join(timeout=5) +def parse_grouping_inventory( + messages: list[Any], version: str +) -> list[GroupingInventoryEntry]: + """Parse the exact grouping prompt shape qualified for one OCR release line.""" + + parsed_version = _version(version) + if parsed_version == (1, 10, 2): + pattern = re.compile( + r"(?P[^\r\n]{1,1000}) " + r"\((?PADDED|MODIFIED|DELETED|RENAMED), " + r"\+(?P0|[1-9][0-9]{0,9})/-(?P0|[1-9][0-9]{0,9})\)" + ) + elif parsed_version >= (1, 11, 0): + pattern = re.compile( + r"(?PADDED|MODIFIED|DELETED|RENAMED) " + r"(?P[^\r\n]{1,1000}) " + r"\(\+(?P0|[1-9][0-9]{0,9})/-(?P0|[1-9][0-9]{0,9})\)" + ) + else: + _fail(f"grouping inventory format is not qualified for OCR {version}") + + prefix = "Group the following changed files:\n\n" + suffix = "\n\nRespond with a JSON array:" + blocks: list[str] = [] + for content in _StubHandler._message_contents(messages): + if not content.startswith(prefix) or suffix not in content: + continue + inventory, remainder = content[len(prefix) :].split(suffix, 1) + if suffix in remainder: + _fail("grouping prompt contains duplicate response boundaries") + blocks.append(inventory) + if len(blocks) != 1: + _fail("grouping prompt must contain exactly one changed-file inventory") + + lines = blocks[0].splitlines() + if not lines or len(lines) > MAX_GROUPING_INVENTORY_ENTRIES: + _fail("grouping inventory has an invalid entry count") + entries: list[GroupingInventoryEntry] = [] + observed_paths: set[str] = set() + for line in lines: + match = pattern.fullmatch(line) + if match is None: + _fail(f"OCR {version} emitted an invalid grouping inventory entry") + path = match.group("path") + insertions = int(match.group("insertions")) + deletions = int(match.group("deletions")) + if ( + len(path) > MAX_GROUPING_PATH_CHARS + or path in observed_paths + or insertions > MAX_GROUPING_CHURN + or deletions > MAX_GROUPING_CHURN + ): + _fail(f"OCR {version} emitted an invalid grouping inventory value") + observed_paths.add(path) + entries.append( + GroupingInventoryEntry( + status=match.group("status"), + path=path, + insertions=insertions, + deletions=deletions, + ) + ) + return entries + + +def _require_exact_grouping_inventory( + observed: list[GroupingInventoryEntry], + expected: list[GroupingInventoryEntry], +) -> None: + """Reject status, churn, path, or ordering drift in one grouping inventory.""" + + if observed != expected: + _fail("semantic grouping review emitted an unexpected status/churn inventory") + + def detect_optional_capabilities(help_output: str, sample: dict[str, Any]) -> list[str]: """Validate additive OCR identity fields and return observed optional capabilities.""" @@ -1053,7 +1141,7 @@ def _validate_file_groups(value: Any, expected_paths: set[str] | None = None) -> _fail("candidate semantic grouping did not cover the expected paths") -def _budget_result_probe(binary: Path, directory: Path) -> dict[str, object]: +def _budget_result_probe(binary: Path, version: str, directory: Path) -> dict[str, object]: """Drive the real OCR review budget gate and validate its partial manifest.""" git_env = _isolated_probe_environment(directory / "budget-git-home") @@ -1074,7 +1162,10 @@ def _budget_result_probe(binary: Path, directory: Path) -> dict[str, object]: home = directory / "budget-review-home" env = _isolated_probe_environment(home) - with _stub_gateway(tokens_per_request=20_000) as gateway_url: + with _stub_gateway( + tokens_per_request=20_000, + grouping_inventory_version=version, + ) as gateway_url: env.update( { "OCR_LLM_URL": gateway_url, @@ -1470,7 +1561,10 @@ def _semantic_grouping_probe(binary: Path, version: str, directory: Path) -> dic head = _run(["git", "rev-parse", "HEAD"], cwd=repo, env=git_env).strip() env = _isolated_probe_environment(root / "review-home") - with _stub_gateway(grouping_mode="combined") as gateway_url: + with _stub_gateway( + grouping_mode="combined", + grouping_inventory_version=version, + ) as gateway_url: env.update( { "OCR_LLM_URL": gateway_url, @@ -1500,6 +1594,7 @@ def _semantic_grouping_probe(binary: Path, version: str, directory: Path) -> dic ) stages = list(_StubHandler.request_stages) completion_caps = list(_StubHandler.completion_caps) + grouping_inventories = list(_StubHandler.grouping_inventories) try: sample = json.loads(output) except json.JSONDecodeError as exc: @@ -1516,6 +1611,12 @@ def _semantic_grouping_probe(binary: Path, version: str, directory: Path) -> dic _fail("semantic grouping review did not preserve the accepted group") if stages != ["grouping", "main", "main", "filter", "main"]: _fail(f"default medium review emitted an unexpected stage sequence: {stages!r}") + expected_inventory = [ + GroupingInventoryEntry("MODIFIED", path, 1, 1) for path in paths + ] + if len(grouping_inventories) != 1: + _fail("semantic grouping review emitted an unexpected grouping inventory count") + _require_exact_grouping_inventory(grouping_inventories[0], expected_inventory) expected_grouping_cap = 16_384 if _version(version) >= (1, 10, 2) else 4_096 if len(completion_caps) != len(stages) or completion_caps[0] != expected_grouping_cap: _fail( @@ -1838,7 +1939,7 @@ def run_contracts(binary: Path, version: str, directory: Path) -> dict[str, Any] contracts: dict[str, Any] = { "numeric_cli_probe": _numeric_cli_probe(binary, repo, base, head, directory), "optional_capabilities": optional_capabilities, - "review_budget_probe": _budget_result_probe(binary, directory), + "review_budget_probe": _budget_result_probe(binary, version, directory), "target_rule_selection_probe": _target_rule_selection_probe(binary, version, directory), "version_probe": "passed", "required_review_flags": sorted(required_review_flags), diff --git a/tests/test_ocr_compat.py b/tests/test_ocr_compat.py index ffee380..45aec2d 100644 --- a/tests/test_ocr_compat.py +++ b/tests/test_ocr_compat.py @@ -1078,6 +1078,159 @@ def test_compatibility_gateway_rejects_malformed_messages_over_real_http() -> No assert error.value.code == 400 +def test_grouping_inventory_strictly_parses_old_and_new_release_shapes() -> None: + """Comparison evidence pins 1.10.2 and 1.11.0 to different exact wire shapes.""" + + module = load_script() + + def messages(inventory: str) -> list[dict[str, str]]: + """Wrap one inventory in OCR's public grouping user prompt.""" + + return [ + { + "role": "user", + "content": ( + "Group the following changed files:\n\n" + f"{inventory}\n\n" + "Respond with a JSON array:\n" + '[{"label": "theme", "files": ["path"]}]' + ), + } + ] + + old = module.parse_grouping_inventory( + messages( + "src/space (unicode) λ.py (ADDED, +10/-0)\n" + "win\\deleted.hbs (DELETED, +0/-5)\n" + "renamed.mustache (RENAMED, +0/-0)" + ), + "1.10.2", + ) + new = module.parse_grouping_inventory( + messages( + "ADDED src/space (unicode) λ.py (+10/-0)\n" + "DELETED win\\deleted.hbs (+0/-5)\n" + "RENAMED renamed.mustache (+0/-0)" + ), + "1.11.0", + ) + + assert old == new == [ + module.GroupingInventoryEntry("ADDED", "src/space (unicode) λ.py", 10, 0), + module.GroupingInventoryEntry("DELETED", "win\\deleted.hbs", 0, 5), + module.GroupingInventoryEntry("RENAMED", "renamed.mustache", 0, 0), + ] + with pytest.raises(module.CompatibilityError, match="invalid grouping inventory entry"): + module.parse_grouping_inventory(messages("ADDED path.py (+1/-0)"), "1.10.2") + with pytest.raises(module.CompatibilityError, match="invalid grouping inventory entry"): + module.parse_grouping_inventory(messages("path.py (ADDED, +1/-0)"), "1.11.0") + with pytest.raises(module.CompatibilityError, match="not qualified"): + module.parse_grouping_inventory(messages("path.py (ADDED, +1/-0)"), "1.10.1") + + +@pytest.mark.parametrize( + "inventory", + [ + "MODIFIED one.py (+1/-1)\none.py (MODIFIED, +1/-1)", + "MODIFIED one.py (+1/-1)", + "BINARY image.bin (+0/-0)", + "UNKNOWN one.py (+1/-1)", + "MODIFIED one.py (+01/-1)", + "MODIFIED one.py (+1000000001/-0)", + "MODIFIED one.py (+1/-1)\nMODIFIED one.py (+1/-1)", + "MODIFIED one.py (+1/-1) trailing", + ], +) +def test_grouping_inventory_rejects_mixed_duplicate_and_malformed_values( + inventory: str, +) -> None: + """Untrusted grouping prompts fail closed on ambiguity, binary markers, and bounds.""" + + module = load_script() + messages = [ + { + "role": "user", + "content": ( + "Group the following changed files:\n\n" + f"{inventory}\n\nRespond with a JSON array:\n[]" + ), + } + ] + + with pytest.raises(module.CompatibilityError, match="invalid grouping inventory"): + module.parse_grouping_inventory(messages, "1.11.0") + + +def test_grouping_inventory_rejects_missing_duplicate_and_oversized_blocks() -> None: + """Prompt boundaries and entry counts remain singular and bounded.""" + + module = load_script() + valid = { + "role": "user", + "content": ( + "Group the following changed files:\n\n" + "MODIFIED one.py (+1/-1)\n\nRespond with a JSON array:\n[]" + ), + } + + with pytest.raises(module.CompatibilityError, match="exactly one"): + module.parse_grouping_inventory([], "1.11.0") + with pytest.raises(module.CompatibilityError, match="exactly one"): + module.parse_grouping_inventory([valid, valid], "1.11.0") + oversized = "\n".join( + f"MODIFIED file-{index}.py (+1/-1)" + for index in range(module.MAX_GROUPING_INVENTORY_ENTRIES + 1) + ) + with pytest.raises(module.CompatibilityError, match="invalid entry count"): + module.parse_grouping_inventory( + [ + { + "role": "user", + "content": ( + "Group the following changed files:\n\n" + f"{oversized}\n\nRespond with a JSON array:\n[]" + ), + } + ], + "1.11.0", + ) + + +@pytest.mark.parametrize( + "observed", + [ + [ + ("MODIFIED", "second.py", 1, 1), + ("MODIFIED", "first.py", 1, 1), + ], + [ + ("ADDED", "first.py", 1, 1), + ("MODIFIED", "second.py", 1, 1), + ], + [ + ("MODIFIED", "first.py", 0, 0), + ("MODIFIED", "second.py", 1, 1), + ], + ], +) +def test_grouping_inventory_rejects_reorder_status_and_churn_drift( + observed: list[tuple[str, str, int, int]], +) -> None: + """Semantic qualification binds order, status, and churn to the controlled fixture.""" + + module = load_script() + expected = [ + module.GroupingInventoryEntry("MODIFIED", "first.py", 1, 1), + module.GroupingInventoryEntry("MODIFIED", "second.py", 1, 1), + ] + + with pytest.raises(module.CompatibilityError, match="unexpected status/churn"): + module._require_exact_grouping_inventory( + [module.GroupingInventoryEntry(*entry) for entry in observed], + expected, + ) + + def test_numeric_cli_probe_records_closed_boundaries_and_effective_values() -> None: """Derive effective numeric behavior without retaining raw OCR diagnostics.""" From 49906c186e0da5d884fa92355e01af4cb10f188e Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:37:47 +0200 Subject: [PATCH 3/9] Integrate OCR 1.11.0 contracts --- PLANS.md | 46 +++-- changelog.d/155.maintenance.md | 1 + changelog.d/155.rules.md | 1 + compatibility/evidence/ocr-1.11.0.json | 206 +++++++++++++++++++++++ compatibility/ocr-support.json | 57 ++++++- docs/codex/TASKS_BACKLOG.md | 4 +- docs/compatibility.md | 16 +- docs/configuration.md | 29 ++-- docs/engineering/test_evidence_matrix.md | 9 + docs/engineering/toolkit_strategy.md | 7 +- docs/gitlab.md | 4 +- docs/operations.md | 6 +- docs/security.md | 2 +- examples/gitlab/README.md | 2 +- examples/gitlab/ocr-review.gitlab-ci.yml | 7 +- scripts/ocr_compat.py | 8 +- src/ocr_toolkit/preflight.py | 2 +- tests/test_environment_contract.py | 6 +- tests/test_integration_contracts.py | 1 + tests/test_ocr_compat.py | 73 ++++---- tests/test_operations_docs.py | 12 +- tests/test_runtime_helpers.py | 2 +- 22 files changed, 410 insertions(+), 91 deletions(-) create mode 100644 changelog.d/155.maintenance.md create mode 100644 changelog.d/155.rules.md create mode 100644 compatibility/evidence/ocr-1.11.0.json diff --git a/PLANS.md b/PLANS.md index 0eed052..9853883 100644 --- a/PLANS.md +++ b/PLANS.md @@ -98,7 +98,9 @@ state for this task: `release-deferred` after a green Draft handoff. - Every new production and test function receives a purpose-focused docstring. - Before every signed logical commit: focused tests, complete slice diff self-review, requirement/trust/data-flow/privacy review, backlog reconciliation where applicable, - and `git diff --check`. + format changed Python with Ruff, run repository-wide `ruff format --check .`, and + `git diff --check`. The existing `scripts/quality.sh check` remains the single complete + final gate; do not add a duplicate formatting owner. - After the initial plan/harness push, do not push partial implementation; perform one final push only after all local slices and final gates are complete. @@ -116,7 +118,7 @@ state for this task: `release-deferred` after a green Draft handoff. - Current compatibility manifest/evidence/harness/workflow, runtime preflight/configuration, review runner/result publication/DLP/receipt/approval, posting formatter, tests, README, public docs, strategy, roadmap, and backlog. -- Workflow audit using engineering-workflow 0.8.1: mature repository, canonical owners +- Workflow audit using engineering-workflow 0.8.2: mature repository, canonical owners and required navigation indexes present; no instruction migration required. #### User Decisions And Answers @@ -149,9 +151,9 @@ state for this task: `release-deferred` after a green Draft handoff. | Queue | Status | Deliverable | | --- | --- | --- | | `WQ-01` | `done` | Full plan materialized first and passed the workflow fidelity/lifecycle check. | -| `WQ-02` | `in_progress` | Strict version-gated grouping qualification is implemented and validated; commit it, then push the two initial commits and open Draft. | -| `WQ-03` | `pending` | Create/assign/milestone issues and obtain hosted exact OCR 1.11.0 qualification evidence. | -| `WQ-04` | `pending` | Integrate 1.11.0 evidence, pins, preflight/example/docs/rules/timeouts/backlog and local no-LLM binary update. | +| `WQ-02` | `done` | Strict grouping harness committed; the two signed initial commits were pushed and Draft PR #154 opened. | +| `WQ-03` | `done` | Milestone v0.8.6 and issue #155 are coordinated; hosted run 33158664020 produced accepted exact 1.11.0 evidence. | +| `WQ-04` | `done` | Exact 1.11.0 evidence/pins/preflight/example/docs/rules/timeouts/backlog and max-tools help/runtime distinction are integrated; local OCR is atomically updated and no-LLM qualified. | | `WQ-05` | `pending` | Add reasoning/tool-choice/private-session qualification and DLP/cleanup/receipt/approval regressions. | | `WQ-06` | `pending` | Implement and verify #153's closed contextual security-signal matcher. | | `WQ-07` | `pending` | Update README/public docs and categorized changelog with the external qualification table. | @@ -166,7 +168,10 @@ state for this task: `release-deferred` after a green Draft handoff. - GitLab example job timeout becomes 45 minutes. OCR base timeout remains inherited 15 minutes, yielding low/medium/high effective limits of 15/30/45 minutes. - Completion behavior remains inherited cap 16384 with the existing explicit toolkit - override example 4096. Default effort remains medium; max-tools semantics are unchanged. + override example 4096. Default effort remains medium. OCR 1.11.0 only corrects stale + max-tools help text: runtime behavior is unchanged from the qualified 1.10.2 baseline, + where `0` selects template default `100`, `1-49` reports normalization to `50` but the + template remains effective, and only a value above `100` raises the effective cap. - Provider flow: `private session/result -> canonical projection -> DLP -> publication -> receipt/approval`. - Reviewer-guide flow: @@ -206,7 +211,7 @@ state for this task: `release-deferred` after a green Draft handoff. - 2026-08-28: `main`/`origin/main` clean at v0.8.5 `72c5111`; no open PR or v0.8.6 milestone; issue #153 is the only open issue. -- 2026-08-28: engineering-workflow 0.8.1 audit found the mature canonical repository +- 2026-08-28: engineering-workflow 0.8.2 audit found the mature canonical repository owners and documentation indexes present. The audit traversed ignored quality artifacts but identified no tracked workflow migration requirement. - 2026-08-28: exact OCR 1.11.0 release hashes, public help defaults, source changes, local @@ -216,6 +221,26 @@ state for this task: `release-deferred` after a green Draft handoff. - 2026-08-28: 86 compatibility tests pass, including 14 focused old/new grouping and gateway tests; Ruff, MyPy, and `git diff --check` pass. Exact local OCR 1.10.2 also passes the strict old-format semantic grouping probe through the loopback-only gateway. +- 2026-08-28: signed planning and grouping-harness commits were pushed once; Draft PR + #154, milestone v0.8.6, assigned issues #153/#155, and exact-tag compatibility run + 33158664020 are open. The hosted artifact verified all release hashes and candidate + contracts and requires the planned human semantic conclusion, which has been recorded. +- 2026-08-28: initial Draft CI quality failed only because two newly committed Python files + were not Ruff-formatted. The canonical local `scripts/quality.sh check` already owns + `ruff format --check .`; the process correction is to format and run that lightweight + check before each Python commit. The macOS 3.14 diagnostic independently failed while + fetching `hatch-vcs` from PyPI after three network retries, not on repository behavior. +- 2026-08-28: upstream release/source and both 1.10.2/1.11.0 hosted artifacts confirm the + max-tools runtime contract is identical (`0 -> 100`, `49 -> reported 50/effective 100`, + `50 -> effective 100`, `101 -> effective 101`). OCR 1.11.0 changes help/docs only. +- 2026-08-28: the checksum-verified Darwin arm64 candidate and atomically installed + `/opt/homebrew/bin/ocr` both report 1.11.0 and pass isolated version/help, + Handlebars/Mustache system-rule readback, accepted 2,001-character soft background, + rejected 8,001-character hard background, and no-session preview checks. The previous + exact 1.10.2 digest was verified before replacement; no LLM, user HOME, configuration, + or credentials were used. +- 2026-08-28: the integrated OCR slice passes 229 focused tests plus 104 subtests, + manifest validation, Ruff lint and repository-wide format check, and `git diff --check`. #### Risks And Recovery @@ -237,8 +262,9 @@ state for this task: `release-deferred` after a green Draft handoff. #### Resume Point -Continue `WQ-02`: commit the reviewed harness slice, push the two signed initial commits, -open the Draft, and then create/dispatch the `WQ-03` GitHub coordination state. +Commit the reviewed `WQ-04` OCR integration slice without pushing, then continue `WQ-05` +with the existing canonical projection/DLP/cleanup owners and focused provider-private +reasoning/tool-choice regressions. #### Plan Fidelity Check @@ -255,7 +281,7 @@ open the Draft, and then create/dispatch the `WQ-03` GitHub coordination state. - [x] Current main/tag/next version, worktree, plan, issues, PRs, milestones, workflow, local OCR, manifest, harness, README, backlog, and canonical docs were read. -- [ ] Hosted OCR 1.11.0 issue/evidence and semantic source audit agree. +- [x] Hosted OCR 1.11.0 issue/evidence and semantic source audit agree. - [ ] Backlog, roadmap, strategy, public docs, changelog, issues, milestone, and Draft agree. - [ ] Final local/hosted validation, head/tree, threads, remote ref, and worktree agree. diff --git a/changelog.d/155.maintenance.md b/changelog.d/155.maintenance.md new file mode 100644 index 0000000..dd079b6 --- /dev/null +++ b/changelog.d/155.maintenance.md @@ -0,0 +1 @@ +Qualify and pin Open Code Review 1.11.0 as the sole toolkit 0.8.6 runtime dependency. The promotion adds checksum-verified Linux and Darwin evidence, changes grouping inventory and timeout expectations, and preserves the result/manifest, completion-cap, medium-effort, max-tools, receipt v5, DLP, telemetry, summary, and approval contracts. OCR 1.10.2 remains comparison evidence only and is not a supported fallback. OCR 1.11.0's max-tools change corrects stale help text; the effective `0`/`50`/`100`/`101` behavior is unchanged. diff --git a/changelog.d/155.rules.md b/changelog.d/155.rules.md new file mode 100644 index 0000000..ba2fcb9 --- /dev/null +++ b/changelog.d/155.rules.md @@ -0,0 +1 @@ +Review Handlebars (`.hbs`) and Mustache (`.mustache`) files through OCR 1.11.0's built-in allowlist and language-specific Rules without widening toolkit evidence or publication authority. diff --git a/compatibility/evidence/ocr-1.11.0.json b/compatibility/evidence/ocr-1.11.0.json new file mode 100644 index 0000000..cb688b8 --- /dev/null +++ b/compatibility/evidence/ocr-1.11.0.json @@ -0,0 +1,206 @@ +{ + "assets": [ + { + "name": "opencodereview-darwin-amd64", + "sha256": "c129af341b52ead65f860831593573b11d1099b434f98cb37d2f885673592109", + "size": 57703712 + }, + { + "name": "opencodereview-darwin-arm64", + "sha256": "ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78", + "size": 54760802 + }, + { + "name": "opencodereview-linux-amd64", + "sha256": "13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60", + "size": 55959714 + }, + { + "name": "opencodereview-linux-arm64", + "sha256": "e2177621b967ed332240dd30841b538b38467b778245b68af37583e4c76f583e", + "size": 52691106 + }, + { + "name": "opencodereview-windows-amd64.exe", + "sha256": "2809ff67e36f40c75dba756f77cb48c5fe12bc6893b0a896a51b6f1522e285a9", + "size": 57422336 + }, + { + "name": "opencodereview-windows-arm64.exe", + "sha256": "c308ee95825191291b56d817681e3248bfc3380f532df679cad2236e95eb0a9c", + "size": 53395968 + }, + { + "name": "sha256sum.txt", + "sha256": "9dff050ec859882bef26037415b8bd9e5db70c5a7d960e5eb3989385372311ee", + "size": 572 + } + ], + "classification": "human-review-required", + "classification_reasons": [ + "candidate is not a newer patch in the tested major/minor line", + "release notes contain a material or ambiguous compatibility signal" + ], + "comparison_version": "1.10.2", + "contracts": { + "comment_thinking_probe": { + "additive_field_preserved": true, + "posting_exposes_thinking": false, + "result": "passed" + }, + "completion_cap_probe": { + "explicit": 4096, + "inherited": 16384, + "result": "passed", + "wire_field": "max_completion_tokens" + }, + "numeric_cli_probe": { + "max_tokens_budget": { + "cases": { + "invalid_below": { + "effective": null, + "input": -1, + "outcome": "rejected" + }, + "minimum": { + "effective": 1, + "input": 1, + "outcome": "accepted" + }, + "omitted": { + "effective": "unlimited", + "input": null, + "outcome": "accepted" + }, + "representative": { + "effective": 30000, + "input": 30000, + "outcome": "accepted" + }, + "sentinel": { + "effective": "unlimited", + "input": 0, + "outcome": "accepted" + } + }, + "maximum": null, + "owner": "ocr-cli" + }, + "max_tools": { + "cases": { + "invalid_below": { + "effective": null, + "input": -1, + "outcome": "rejected" + }, + "minimum": { + "effective": 100, + "input": 50, + "outcome": "accepted" + }, + "minimum_minus_one": { + "effective": 100, + "input": 49, + "outcome": "normalized", + "reported_normalization": 50 + }, + "omitted": { + "effective": 100, + "input": null, + "outcome": "accepted" + }, + "representative": { + "effective": 101, + "input": 101, + "outcome": "accepted" + }, + "sentinel": { + "effective": 100, + "input": 0, + "outcome": "accepted" + } + }, + "maximum": null, + "owner": "ocr-template-or-higher-cli", + "reported_minimum": 50 + }, + "result": "passed" + }, + "optional_capabilities": [ + "llm_result_identity", + "per_run_model_override", + "per_run_provider_override", + "review_effort", + "semantic_grouping" + ], + "preview_probe": { + "format": "json", + "path": "example.py", + "result": "passed", + "session_store_created": false + }, + "required_review_flags": [ + "--audience", + "--background-file", + "--effort", + "--format", + "--from", + "--max-tokens-budget", + "--max-tools", + "--preview", + "--rule", + "--to" + ], + "result_contract_probe": { + "additive_fields_allowed": true, + "comment_fields": [ + "category", + "content", + "end_line", + "existing_code", + "path", + "severity", + "start_line", + "thinking" + ], + "manifest_schema": "ocr.run-manifest/v1", + "normalized_outcome": "clean", + "result": "passed" + }, + "review_budget_probe": { + "budget": 30000, + "completed": 2, + "failed_budget": 1, + "partial_findings_preserved": true, + "result": "passed", + "selected": 3 + }, + "semantic_grouping_probe": { + "default_effort": "medium", + "filter_requests": 1, + "grouping_completion_cap": 16384, + "grouping_requests": 1, + "main_requests": 3, + "result": "passed", + "review_rounds": 2 + }, + "target_rule_selection_probe": { + "format": "json", + "from_to_unchanged": true, + "path": "synthetic-template.ocrfixture", + "result": "passed", + "source_exclusion": "unsupported_ext", + "target_selected": true + }, + "version_probe": "passed" + }, + "published_at": "2026-08-28T06:06:56Z", + "release_changes": "## 🚀 Features\n\n- feat(allowlist): add Handlebars and Mustache support (#1086)\n- feat(config): validate provider existence before auxiliary fields (#1093)\n- feat(agent): include churn stats (+N/-M) in the other-changed-files list (#1078) (#1082)\n\n## 🐛 Bug Fixes\n\n- fix(llm): preserve provider reasoning/thinking across assistant turns (#1070)\n- fix(agent): scale subtask timeout linearly with effort review rounds (#1085)\n- fix(filter): omit forced tool choice (#1065)\n- fix(tool): support subpath and cross-platform queries in file_find (#1075)\n\n## 📖 Documentation\n\n- docs(ko): polish the six new Korean pages (#1087)\n- docs(ko): complete the Korean docs locale (#1084)\n- docs(ko): add Korean translation for the core user guide (#1080)\n- docs(cli): align --max-tools help text with min 50 clamp (#1077)\n\n**Full Changelog**: https://github.com/alibaba/open-code-review/compare/v1.10.2...v1.11.0", + "release_notes_sha256": "a68802ee02c22c1b02955f5307f79427b379c14a76b5c2ce6545b5e9fc82b5b0", + "result": "compatible", + "schema_version": 2, + "tag": "v1.11.0", + "tested_baseline_version": "1.10.2", + "upstream_repository": "alibaba/open-code-review", + "version": "1.11.0" +} diff --git a/compatibility/ocr-support.json b/compatibility/ocr-support.json index 3949488..d5873f2 100644 --- a/compatibility/ocr-support.json +++ b/compatibility/ocr-support.json @@ -1,6 +1,6 @@ { - "monitoring_floor": "1.10.2", - "recommended_version": "1.10.2", + "monitoring_floor": "1.11.0", + "recommended_version": "1.11.0", "releases": [ { "assets": [ @@ -1293,6 +1293,59 @@ "release_url": "https://github.com/alibaba/open-code-review/releases/tag/v1.10.2", "status": "tested", "version": "1.10.2" + }, + { + "assets": [ + { + "name": "opencodereview-darwin-amd64", + "sha256": "c129af341b52ead65f860831593573b11d1099b434f98cb37d2f885673592109", + "size": 57703712 + }, + { + "name": "opencodereview-darwin-arm64", + "sha256": "ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78", + "size": 54760802 + }, + { + "name": "opencodereview-linux-amd64", + "sha256": "13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60", + "size": 55959714 + }, + { + "name": "opencodereview-linux-arm64", + "sha256": "e2177621b967ed332240dd30841b538b38467b778245b68af37583e4c76f583e", + "size": 52691106 + }, + { + "name": "opencodereview-windows-amd64.exe", + "sha256": "2809ff67e36f40c75dba756f77cb48c5fe12bc6893b0a896a51b6f1522e285a9", + "size": 57422336 + }, + { + "name": "opencodereview-windows-arm64.exe", + "sha256": "c308ee95825191291b56d817681e3248bfc3380f532df679cad2236e95eb0a9c", + "size": 53395968 + }, + { + "name": "sha256sum.txt", + "sha256": "9dff050ec859882bef26037415b8bd9e5db70c5a7d960e5eb3989385372311ee", + "size": 572 + } + ], + "capabilities": [ + "llm_result_identity", + "per_run_model_override", + "per_run_provider_override", + "review_effort", + "semantic_grouping" + ], + "evidence": "compatibility/evidence/ocr-1.11.0.json", + "evidence_sha256": "97c56e301aab5298d5b8d2182afdda33d6cb704abf7bf476f04c668b95b61f22", + "human_conclusion": "Compatible after hosted checksum-verified Linux qualification in run 33158664020 and direct adjacent source review in issue #155. OCR 1.11.0 changes grouping and other-file inventory to status-first entries with churn, preserves provider-native reasoning across assistant turns, removes the filter's forced tool choice, scales subtask timeout by review rounds, improves file_find subpaths, and adds Handlebars/Mustache rules. The toolkit qualification harness consumes the inventory shape and runtime-facing boundaries while provider reasoning and native payloads remain private and unconsumed. Result/manifest schemas, inherited 16384 and explicit 4096 completion caps, medium effort, max-tools, receipt v5, DLP, telemetry, and approval contracts remain unchanged. Upstream action, plugin, launcher, locale, provider preset, and config-command validation changes are not consumed.", + "published_at": "2026-08-28T06:06:56Z", + "release_url": "https://github.com/alibaba/open-code-review/releases/tag/v1.11.0", + "status": "tested", + "version": "1.11.0" } ], "schema_version": 1, diff --git a/docs/codex/TASKS_BACKLOG.md b/docs/codex/TASKS_BACKLOG.md index f6f0819..a0e6784 100644 --- a/docs/codex/TASKS_BACKLOG.md +++ b/docs/codex/TASKS_BACKLOG.md @@ -89,7 +89,7 @@ Provider/network telemetry remains outside M1 and M5. OCR owns token, cost, budg - **Acceptance criteria:** The use case and completion signal are documented before implementation; false-positive behavior and unsupported versions are explicit through the shared scoped coverage contract. - **Exclusions:** Checkbox coverage, network resolution, runtime execution, or unrelated bundles. - **Validation:** Pack fixtures plus common evidence/bootstrap/MCP contracts. -- **Upstream overlap:** OCR language allowlists and review rules are review-engine capabilities; a new reviewable language alone does not activate an evidence pack. +- **Upstream overlap:** OCR language allowlists and review rules are review-engine capabilities; OCR 1.11.0 Handlebars/Mustache selection improves review coverage but does not supply a framework evidence contract or activate an evidence pack. - **Release classification expectation:** `release-required`. ### BL-019: Run a native fuzzing campaign @@ -127,7 +127,7 @@ Provider/network telemetry remains outside M1 and M5. OCR owns token, cost, budg - **Roadmap theme:** M7 Later and conditional work - **Dependencies:** Stable provider-neutral core contracts and a funded non-GitLab use case. GitLab-first M5 does not depend on it. - **Activation trigger:** A named forge has an owner, synthetic fixtures, and explicit parity requirements for CI orchestration, positioning, deduplication, discussion ownership, and safe publication. -- **Upstream overlap:** OCR 1.10.2 reusable GitHub Action checkpoint ranges cover only upstream Action range selection. They do not provide toolkit forge acquisition, discussion, publication, or lifecycle parity, so the trigger and acceptance criteria remain unmet. +- **Upstream overlap:** OCR 1.10.2 reusable GitHub Action checkpoint ranges and OCR 1.11.0 Action/plugin changes cover only upstream execution surfaces. They do not provide toolkit forge acquisition, discussion, publication, or lifecycle parity, so the trigger and acceptance criteria remain unmet. - **Goal:** Add one coherent host adapter without leaking forge semantics into evidence or core result handling. - **Scoped deliverables:** The capability matrix covers authentication, diff positions, drafts, discussion acquisition, provider-declared account classification, thread/reply structure, edit/version identity, anchors, resolved/stale state, pagination/snapshot mutation, ambiguous writes, permissions, and idempotency. - **Acceptance criteria:** Core remains provider-neutral, GitLab behavior does not regress, unsupported host capabilities fail or degrade explicitly rather than emulate unsafe parity, and the new host meets the approved lifecycle and security matrix. diff --git a/docs/compatibility.md b/docs/compatibility.md index 4063d72..ece4732 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -63,7 +63,7 @@ Deploy toolkit 0.8.4 directly with OCR 1.10.1. The public Linux amd64 example ve ### OCR 1.10.2 — toolkit 0.8.5 target -OCR 1.10.2 is the only version accepted by the toolkit 0.8.5 development preflight and pinned by the current GitLab example. Hosted run `33055459209`, canonical issue #151, adjacent source review, and checksum-verified isolated Darwin checks preserve the OCR result, `ocr.run-manifest/v1`, default-medium two-round review, effective max-tools, completion-cap override, DLP, receipt v5, telemetry ownership, and approval contracts. +OCR 1.10.2 is the historical version accepted by toolkit 0.8.5 preflight and pinned by its published GitLab example. Hosted run `33055459209`, canonical issue #151, adjacent source review, and checksum-verified isolated Darwin checks preserve the OCR result, `ocr.run-manifest/v1`, default-medium two-round review, effective max-tools, completion-cap override, DLP, receipt v5, telemetry ownership, and approval contracts. OCR now records grouping tasks and grace-round requests in its private session/retry state. The grouping request uses the review template's inherited OpenAI completion cap `16384` instead of the separate `4096` used by the predecessor; an explicit positive `OCR_LLM_MAX_COMPLETION_TOKENS` still overlays every protocol request. Its value remains deployment-owned. These private task records and group/path values do not enter toolkit findings, GitLab text, receipts, DLP signals, telemetry, or approval inputs. @@ -73,6 +73,20 @@ The hosted qualification initially labelled the patch `automatic-safe` because m Deploy toolkit 0.8.5 directly with OCR 1.10.2. The public Linux amd64 example verifies SHA-256 `e9205614f80e009ee7b1f444c9da08486fb9ff6db022954fe9203d923ab720b2`; the independently checked Darwin arm64 artifact verifies `74fc7bcc0e6d0790c5ca033fd82a5474b6f05d443ed51a26a6f61c0cac6589fd`, and the upstream `sha256sum.txt` verifies `b5176aaa04a7f00bd84dd61556ca29e6cbdfcfe64cc50af6653163d9be4e7654`. +### OCR 1.11.0 — toolkit 0.8.6 target + +OCR 1.11.0 is the only runtime version accepted by toolkit 0.8.6 preflight and pinned by its GitLab example. OCR 1.10.2 remains a strict comparison baseline for the grouping-inventory transition and is not a supported fallback. Hosted run `33158664020`, canonical issue #155, adjacent source review, and checksum-verified evidence preserve the OCR result, `ocr.run-manifest/v1`, inherited OpenAI completion cap `16384`, explicit toolkit override `4096`, default-medium two-round review, receipt v5, DLP, toolkit telemetry, summary, and approval contracts. + +The private grouping and other-files prompts now use status-first `STATUS path (+N/-M)` inventory entries. Qualification accepts the old `path (STATUS, +N/-M)` shape only from exact comparison OCR 1.10.2 and the new shape only from exact candidate OCR 1.11.0; mixed, duplicate, reordered, malformed, status-inconsistent, truncated, or churn-losing evidence fails closed. Production toolkit code consumes neither format. `file_find` now supports repository-relative subpaths and both slash styles. The built-in allowlist and Rules add Handlebars (`.hbs`) and Mustache (`.mustache`). OCR's base subtask timeout is now 15 minutes and scales linearly with low/medium/high review rounds to 15/30/45 minutes, so the GitLab job allows 45 minutes. + +OCR 1.11.0 preserves provider-native reasoning across assistant turns, removes the filter's forced `tool_choice`, and retains readable reasoning plus signed or encrypted native replay payloads inside the OCR session. The toolkit does not consume that state: its isolated session home is removed before publication, and reasoning, native payloads, and request controls cannot enter findings, GitLab notes, receipt v5, DLP counters, toolkit telemetry, tool/token summary, or approval inputs. Explicit operator-owned `OCR_LLM_EXTRA_BODY.tool_choice` remains distinct from OCR's removed forced filter value and is not published. + +The release corrects stale `--max-tools` help text; max-tools runtime behavior is unchanged from the behaviorally qualified 1.10.2 baseline. Omitted and sentinel `0` select template default `100`; `1-49` reports normalization to `50`, while normalized `50` and explicit `50` remain effectively `100`; only a value above `100` raises the effective cap. The toolkit's closed normalization notice remains diagnostics-only and cannot affect findings, completeness, receipt, DLP, telemetry, lifecycle, or approval. + +Upstream GitHub Action, OpenCode plugin, npm launcher, Korean documentation, built-in provider presets, and interactive provider-validation changes are not toolkit execution paths and are not claimed as toolkit behavior. + +Deploy toolkit 0.8.6 directly with OCR 1.11.0; do not install 1.10.2 as an intermediate version. The public Linux amd64 example verifies SHA-256 `13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60`; the independently verified Darwin arm64 artifact uses `ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78`, and the upstream `sha256sum.txt` verifies `9dff050ec859882bef26037415b8bd9e5db70c5a7d960e5eb3989385372311ee`. + The contiguous 1.9.7 through 1.9.8 promotion combines the repository-owned hosted Linux qualification with adjacent upstream source review. It also repeats the required 1.9.8 contract probes through the checksum-verified Darwin arm64 artifact. Multi-tool MCP initialization, fixed tool discovery and dispatch, and owner-only session persistence remain compatible with the M5 design: the toolkit may expose several fixed tools from its one built-in process, while an isolated `HOME` contains OCR's `.opencodereview/sessions` state for deterministic cleanup. Gemini and Bedrock are optional upstream provider capabilities that the toolkit neither selects nor configures; mirror-aware installation is outside the toolkit-owned download path; native severity retains the structured result fields already consumed; and human-audience progress routing does not affect the toolkit's agent-audience invocation. Therefore this promotion requires no toolkit CI behavior adaptation beyond version and checksum pins. These source observations establish capability only; the M5 production-path tests remain responsible for proving the toolkit's composition and containment. An automatic-safe result is not an automatic stable release. It must still pass a normal protected compatibility PR and a separate signed stable-release PR. If a dedicated OCR update bot credential is not configured, the workflow publishes the exact patch as an artifact and records the resume action in the issue; the default `GITHUB_TOKEN` is intentionally not used to create a PR that would fail to trigger the full protected workflow set. diff --git a/docs/configuration.md b/docs/configuration.md index 55091df..241519d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -22,7 +22,7 @@ These are the complete supported toolkit-owned runtime inputs. `Required` is sco | `OCR_LLM_VALIDATE_MODEL` | Operator / `ocr-ci preflight` | No | `false` | `true` validates through `/models`; `auto` may use the offline allowlist; false values skip validation. | | `OCR_LLM_MODELS_URL` | Operator / `ocr-ci preflight` | No | Derived from `OCR_LLM_URL` | Explicit absolute credential-free HTTPS metadata URL when validation is enabled or inference query parameters make derivation ambiguous. | | `OCR_LLM_ALLOWED_MODELS` | Operator / `ocr-ci preflight` | No | Empty list | Comma-separated exact model identifiers for offline or `auto` validation. | -| `OCR_TELEMETRY_ENABLED` | Operator / `ocr-ci configure` | No | `false` | Exact `true` enables OCR telemetry configuration; OCR 1.10.2 spans may include path-derived group keys and model-produced labels. | +| `OCR_TELEMETRY_ENABLED` | Operator / `ocr-ci configure` | No | `false` | Exact `true` enables OCR telemetry configuration; OCR 1.11.0 spans may include path-derived group keys and model-produced labels. | | `OCR_TELEMETRY_CONTENT_LOGGING` | Operator / `ocr-ci configure` | No | `false` | Exact `true` enables OCR content logging; keep disabled for private review data. | | `OCR_TELEMETRY_EXPORTER` | Operator / `ocr-ci configure` | No | Empty string | Exporter name written only when telemetry is enabled. | | `OCR_TELEMETRY_OTLP_ENDPOINT` | Operator / `ocr-ci configure` | No | Unset | OTLP endpoint written only when telemetry is enabled and the value is non-empty. | @@ -60,11 +60,11 @@ If `OCR_LLM_EXTRA_BODY` already owns that field, an exactly equal JSON integer i The toolkit does not derive this value from `/models.max_completion_tokens`. That metadata is a model capability boundary, not an account spending limit or proof of how a gateway reserves request cost. -The inherited value is version-owned and therefore changes with a qualified OCR upgrade. The toolkit observed `max_completion_tokens=58888` from OCR 1.9.10 and `16384` from OCR 1.10.0 through 1.10.2 when the variable was unset. In OCR 1.10.2 the grouping request also uses this template-owned cap instead of a separate `4096`; an explicit toolkit override still applies to every protocol request. Deployments that require an invariant gateway-specific cap must set `OCR_LLM_MAX_COMPLETION_TOKENS` explicitly rather than depending on an OCR default. +The inherited value is version-owned and therefore changes with a qualified OCR upgrade. The toolkit observed `max_completion_tokens=58888` from OCR 1.9.10 and `16384` from OCR 1.10.0 through 1.11.0 when the variable was unset. Grouping requests use the same template-owned cap; an explicit toolkit override still applies to every protocol request. Deployments that require an invariant gateway-specific cap must set `OCR_LLM_MAX_COMPLETION_TOKENS` explicitly rather than depending on an OCR default. ### Review effort -`OCR_REVIEW_EFFORT` defaults to `medium` and is written to OCR's root `effort` configuration key. OCR 1.10.2 maps `low`, `medium`, and `high` to one, two, and three review rounds respectively. The environment is operator-owned; merge-request text cannot change it. An explicit caller `--effort` passed after `ocr-ci review --` has normal OCR CLI precedence over the generated config, while an unknown environment value fails configuration before preview or model execution. +`OCR_REVIEW_EFFORT` defaults to `medium` and is written to OCR's root `effort` configuration key. OCR 1.11.0 maps `low`, `medium`, and `high` to one, two, and three review rounds and scales its 15-minute subtask base to 15, 30, or 45 minutes. The environment is operator-owned; merge-request text cannot change it. An explicit caller `--effort` passed after `ocr-ci review --` has normal OCR CLI precedence over the generated config, while an unknown environment value fails configuration before preview or model execution. Effort controls review depth, not the prompt/context ceiling, per-call completion cap, aggregate token budget, or per-round tool limit. Semantic grouping and filtering can add requests even at `low`; higher effort can add further rounds until OCR stops early, reaches a coverage/budget boundary, or completes the configured depth. @@ -92,13 +92,13 @@ These names belong to `examples/gitlab/ocr-review.gitlab-ci.yml`; they are shell | Variable | Source / owner | Required | Exact default | Behavior | | --- | --- | --- | --- | --- | -| **`OCR_VERSION`** | Example pipeline | Yes | `v1.10.2` | Checksum-pinned recommended OCR binary release for toolkit 0.8.5. | -| **`OCR_SHA256`** | Example pipeline | Yes | `e9205614f80e009ee7b1f444c9da08486fb9ff6db022954fe9203d923ab720b2` | Expected Linux AMD64 OCR binary digest. | +| **`OCR_VERSION`** | Example pipeline | Yes | `v1.11.0` | Checksum-pinned recommended OCR binary release for the toolkit 0.8.6 development line. | +| **`OCR_SHA256`** | Example pipeline | Yes | `13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60` | Expected Linux AMD64 OCR binary digest. | | **`OCR_TOOLKIT_VERSION`** | Example pipeline | Yes | `0.8.5` | Exact toolkit wheel release installed by the current published example. | | **`OCR_TOOLKIT_CHECKSUMS_URL`** | Example pipeline | Yes | Release URL derived from `OCR_TOOLKIT_VERSION` | Toolkit `SHA256SUMS` URL. | | `OCR_TOOLKIT_WHEEL` | Example shell | Computed | `open_code_review_toolkit-${OCR_TOOLKIT_VERSION}-py3-none-any.whl` | Exact wheel filename selected from the release. | | `OCR_TOOLKIT_WHEEL_SHA256` | Example shell | Computed | Matching value from `SHA256SUMS` | Digest checked before installing the toolkit wheel. | -| `OCR_MAX_TOOLS` | Example pipeline / OCR CLI | No | `0` | Non-negative tool-call control passed to OCR. `0` delegates to the installed OCR template; a positive value can raise that template-owned loop limit, subject to OCR's runtime validation. | +| `OCR_MAX_TOOLS` | Example pipeline / OCR CLI | No | `0` | OCR 1.11.0 uses template default `100`; `1-49` reports normalization to `50` but remains effectively `100`, and only a value above `100` raises the cap. | | `OCR_MAX_TOKENS_BUDGET` | Example pipeline / OCR CLI | No | `0` | Non-negative aggregate OCR token ceiling; `0` is unlimited. | ## Dynamic adapter and MCP inputs @@ -165,14 +165,15 @@ for automatic approval. The cap is approximate because already-running work may finish and OCR accounts the provider-reported input plus output tokens. `OCR_MAX_TOOLS` is independent of all three token controls. Leave the example -default at `0` so the installed OCR template owns the effective per-file -tool-call limit. For the currently qualified OCR, behavioral qualification -observes a CLI minimum and normalization target of `50`, while omitted, `0`, -and values through `100` all retain the template's effective `100` rounds; a -value of `101` raises the effective limit to `101`. The OCR help text is not the -source of truth for these values. A recognized normalization is emitted only as -a toolkit-authored CI notice; its raw stderr is not added to findings, result -warnings, receipts, DLP inputs, telemetry, or automatic-approval signals. +default at `0` so OCR uses its embedded template limit of `100` per subtask. +OCR 1.11.0 reports values `1-49` as normalized to the minimum `50`, but both +that target and explicit `50` remain below the template default and therefore +remain effectively `100`. Use `101` or greater only when deliberately raising +the loop cap. OCR 1.11.0 corrected stale help text for this already-qualified +behavior; it did not change the runtime semantics. A recognized normalization +is emitted only as a toolkit-authored CI notice; its raw stderr is not added to +findings, result warnings, receipts, DLP inputs, telemetry, or +automatic-approval signals. ## Posting controls diff --git a/docs/engineering/test_evidence_matrix.md b/docs/engineering/test_evidence_matrix.md index 55c540f..f9bb82a 100644 --- a/docs/engineering/test_evidence_matrix.md +++ b/docs/engineering/test_evidence_matrix.md @@ -123,6 +123,15 @@ The M5 negative suite is an attacker matrix, not merely a replay of observed rev | New language Rules are selected without widening toolkit authority | exact OCR preview/rule resolver -> recommended built-in Rules | `.sol` and `.vy` inputs are reviewable and resolve Solidity/Vyper Rules; no toolkit result, DLP, receipt, telemetry, or approval contract changes | isolated Darwin arm64 no-LLM preview/rule readback plus upstream semantic audit | selection proves language/rule routing, not finding quality | proven | | Upstream Action/session additions do not claim backlog completion | source audit -> BL-021 and M6 ownership records | Action checkpoint ranges remain upstream-Action-only; session comparison and private grouping/grace records are not toolkit forge parity or telemetry | adjacent source/release audit and backlog/strategy reconciliation | source evidence classifies overlap only; no second forge integration is claimed | proven as partial overlap, backlog remains open | +## v0.8.6 OCR 1.11.0 evidence + +| Requirement or boundary | Production owner and entry point | Required observable result | Evidence | Double boundary and claim limit | State | +| --- | --- | --- | --- | --- | --- | +| Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, explicit `4096`, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict 1.10.2/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay | proven for exact qualified OCR contract | +| Max-tools help correction does not imply runtime drift | exact numeric CLI and effective loop probes -> public operator docs | omitted/`0` remain effective `100`; `49` reports `50` but stays effective `100`; `50` stays effective `100`; `101` becomes effective `101` | identical hosted 1.10.2 and 1.11.0 evidence plus upstream #1077 source/release audit | behavioral probes prove current embedded-template ownership; they do not promise future OCR defaults | proven unchanged | +| Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | pending toolkit regressions | +| New selection behavior stays at the OCR edge | exact no-LLM preview/rule resolver -> built-in OCR Rules | repository-relative/backslash `file_find` fallback and `.hbs`/`.mustache` rule selection work without changing toolkit evidence authority | adjacent source audit plus isolated checksum-verified Darwin version/help, rule readback, and soft/hard background previews | selection proves routing, not review finding quality or evidence-pack completion | proven | + ## Complete suite module audit Every top-level test module is classified below. A module can contain more than one evidence class; the strongest class applies only to the named boundary, never to all tests in that file. diff --git a/docs/engineering/toolkit_strategy.md b/docs/engineering/toolkit_strategy.md index 4d09a91..e16f560 100644 --- a/docs/engineering/toolkit_strategy.md +++ b/docs/engineering/toolkit_strategy.md @@ -154,9 +154,10 @@ Qualified OCR releases expose explicit per-run provider/model overrides, additiv The completed [BL-017 signal-ownership audit](review_signal_ownership.md) reaches `no-new-layer`. OCR owns provider, request, latency, cost, grouping, round, and tool telemetry. The toolkit owns only deterministic closed result, receipt, -context, publication-DLP, posting, and approval projections. OCR 1.10.2 group -keys contain changed paths and its labels are model-produced, so neither becomes -a toolkit metric, routing input, or approval authority. A single bounded +context, publication-DLP, posting, and approval projections. OCR 1.11.0 group +keys contain changed paths, its labels are model-produced, and its private +session can retain provider-native reasoning/tool state, so none becomes a +toolkit metric, routing input, public summary, or approval authority. A single bounded toolkit-authored failure diagnostic derived from closed retry-report enums and counts is operator feedback, not a second telemetry or exporter layer. diff --git a/docs/gitlab.md b/docs/gitlab.md index 310ffe8..106d48d 100644 --- a/docs/gitlab.md +++ b/docs/gitlab.md @@ -18,9 +18,9 @@ The complete variable inventory, owner, requirement, exact default, and behavior The public pipeline stores the OCR binary checksum as the non-secret `OCR_SHA256` pin. Store actual credentials as masked, protected CI variables; do not place their values in YAML, command arguments, repository evidence, or the generated bootstrap. GitLab job tokens are not accepted for posting. -`OCR_REVIEW_LANGUAGE` defaults to `English`; `Russian` is one example of an explicit review language. The example pins its qualified OCR release and sets `OCR_REVIEW_EFFORT=medium`, allowing two review rounds; `low` and `high` explicitly select one or three. OCR may stop early when a round adds no finding. `OCR_MAX_TOOLS=0` delegates the per-file tool-call limit to the installed OCR template; use a positive value only after checking that release's behaviorally qualified minimum, normalization, and effective value. `OCR_MAX_TOKENS_BUDGET` defaults to `0`, meaning unlimited; a positive budget may stop dispatch and produce an explicitly partial, automatic-approval-ineligible review. `OCR_LLM_MAX_COMPLETION_TOKENS` defaults to unset and separately controls only the provider request's completion/output cap. Select an explicit value only from the deployment's provider/model contract; the toolkit does not recommend or hardcode a provider-specific cap. +`OCR_REVIEW_LANGUAGE` defaults to `English`; `Russian` is one example of an explicit review language. The example pins its qualified OCR release and sets `OCR_REVIEW_EFFORT=medium`, allowing two review rounds; `low` and `high` explicitly select one or three. OCR may stop early when a round adds no finding. OCR 1.11.0 scales its 15-minute per-subtask base to 15/30/45 minutes for low/medium/high, so the example allows 45 minutes at the GitLab job boundary. `OCR_MAX_TOOLS=0` selects the embedded template default `100`. Values `1-49` report normalization to `50` but remain effectively `100`; explicit `50` also cannot lower the template, and only a value above `100` raises the cap. `OCR_MAX_TOKENS_BUDGET` defaults to `0`, meaning unlimited; a positive budget may stop dispatch and produce an explicitly partial, automatic-approval-ineligible review. `OCR_LLM_MAX_COMPLETION_TOKENS` defaults to unset and separately controls only the provider request's completion/output cap. Select an explicit value only from the deployment's provider/model contract; the toolkit does not recommend or hardcode a provider-specific cap. -OCR 1.10.2 semantically groups related changed files before review and filters candidates per group. Grouping, filtering, and multiple rounds can increase provider requests, latency, and token cost, while the manifest and aggregate budget continue to report completeness. Grouping and grace-round requests are tracked inside OCR's private session/retry diagnostics. Group labels and path-derived keys remain untrusted: the toolkit does not publish or use them for severity, fingerprints, lifecycle commands, receipts, telemetry, or approval. OCR's separately configured telemetry may export those high-cardinality repository-derived values, so keep `OCR_TELEMETRY_ENABLED=false` unless the exporter and retention policy are approved. +OCR 1.11.0 semantically groups related changed files before review and filters candidates per group. Its private grouping and other-files prompts use status-first `STATUS path (+N/-M)` entries; the toolkit does not parse that inventory in production. Grouping, filtering, and multiple rounds can increase provider requests, latency, and token cost, while the manifest and aggregate budget continue to report completeness. Grouping, grace-round, provider-native reasoning/thinking, and tool-choice request state are retained only inside OCR's isolated private session. Group labels, paths, reasoning, signed/encrypted native payloads, and request controls remain untrusted: the toolkit does not publish or use them for severity, fingerprints, lifecycle commands, receipts, DLP counts, telemetry, tool/token summaries, or approval. OCR's separately configured telemetry may export high-cardinality repository-derived values, so keep `OCR_TELEMETRY_ENABLED=false` unless the exporter and retention policy are approved. The summary keeps four inputs separate: OCR manifest coverage, publication integrity, published findings, and an optional OCR core advisory. Complete manifest coverage that later loses public fields is labelled `Review complete with publication filtering`; it is warning-bearing and approval-ineligible, but it is not called incomplete OCR coverage and does not invent failed-file diagnostics. Actual partial, failed, waived, or budget-stopped manifest coverage keeps its stronger status. Ordinary OCR warnings retain their own complete-with-warnings state. The reviewer guide ranks bounded focus areas only when at least two findings are published; one finding remains in its inline or fallback discussion without a duplicate snippet. diff --git a/docs/operations.md b/docs/operations.md index 7107858..b45e0ce 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -34,9 +34,9 @@ suppressed. `OCR_MAX_TOKENS_BUDGET` can set an aggregate input-plus-output token ceiling for the OCR diff review. The default `0` is unlimited. A positive ceiling is approximate rather than a hard billing cutoff because already-running work may complete; when it stops further dispatch, completed findings remain publishable and unreviewed files stay explicit as budget-attributed failed coverage. Such a run is partial and cannot automatically approve. -This aggregate budget is separate from both OCR's prompt/context `max_tokens` ceiling and the provider request's completion/output cap. The toolkit does not add an environment alias for OCR's prompt/context control. `OCR_LLM_MAX_COMPLETION_TOKENS` defaults to unset and, when set, overlays only the protocol-specific output field. The inherited OpenAI value was 58,888 in OCR 1.9.10 and is 16,384 in OCR 1.10.0 through 1.10.2. OCR 1.10.2 also applies that template-owned cap to grouping requests; an explicit toolkit override applies to all requests. A gateway may reserve cost against that requested maximum before generation even when the eventual response would be short. The `/models` capability value does not reveal an account spending limit or reservation policy, so the toolkit never selects the cap from it automatically. Set an explicit cap only from the deployment's provider/model contract when that deployment must not change with the qualified OCR version; the toolkit does not recommend or hardcode a provider-specific value. +This aggregate budget is separate from both OCR's prompt/context `max_tokens` ceiling and the provider request's completion/output cap. The toolkit does not add an environment alias for OCR's prompt/context control. `OCR_LLM_MAX_COMPLETION_TOKENS` defaults to unset and, when set, overlays only the protocol-specific output field. The inherited OpenAI value was 58,888 in OCR 1.9.10 and is 16,384 in OCR 1.10.0 through 1.11.0, including grouping requests; an explicit toolkit override applies to all requests. A gateway may reserve cost against that requested maximum before generation even when the eventual response would be short. The `/models` capability value does not reveal an account spending limit or reservation policy, so the toolkit never selects the cap from it automatically. Set an explicit cap only from the deployment's provider/model contract when that deployment must not change with the qualified OCR version; the toolkit does not recommend or hardcode a provider-specific value. -`OCR_REVIEW_EFFORT=medium` is the toolkit default for the qualified OCR release and permits two review rounds; `low` permits one and `high` permits three. This is a review-depth choice, not one of the three token controls. OCR first groups related changed files and may make group-filter requests; additional rounds can add requests, latency, and cost, but may stop early when they add no finding. The published GitLab example separately passes `OCR_MAX_TOOLS=0`, delegating the effective per-file tool-call limit to the installed OCR template instead of carrying a release-specific minimum. A positive value can raise that limit, but operators should check the release's behavioral qualification because CLI help, normalization text, and effective template value can differ. Exhausting the effective limit, an aggregate budget stop, or incomplete manifest coverage remains explicit and approval-ineligible; increasing either effort or tools is never a way to hide partial coverage. +`OCR_REVIEW_EFFORT=medium` is the toolkit default for the qualified OCR release and permits two review rounds; `low` permits one and `high` permits three. OCR 1.11.0 multiplies its 15-minute subtask base by those rounds, yielding 15/30/45-minute limits; the GitLab example's 45-minute job timeout accommodates the largest preset. This is a review-depth choice, not one of the three token controls. OCR first groups related changed files and may make group-filter requests; additional rounds can add requests, latency, and cost, but may stop early when they add no finding. The published GitLab example separately passes `OCR_MAX_TOOLS=0`, selecting the embedded template default `100`. The CLI reports `1-49` as normalized to `50`, but both that target and explicit `50` remain effectively `100`; only values above `100` raise the cap. OCR 1.11.0 corrects stale help text for the already-qualified behavior rather than changing the runtime loop. Exhausting the effective limit, an aggregate budget stop, or incomplete manifest coverage remains explicit and approval-ineligible; increasing either effort or tools is never a way to hide partial coverage. The outcome wording distinguishes skipped, complete, complete-with-warnings, incomplete, token-budget, and failed reviews while preserving the finding state in that same line. A complete clean review is visibly positive; a complete review with findings or only reviewer-suppressed findings is neutral; warning, partial, budget, and failed states never look clean. Findings withheld by the posting limit remain counted even when the limit allows no individual finding note. Recommended focus areas ranks only its copy of already-published findings by the closed severity, category, safe repository location, and stable-identity order before its existing display cap; inline and fallback discussion order, suppression, counts, security focus, and approval policy remain unchanged. OCR 1.8.5 and later manifest failures provide the canonical failed-file receipt; legacy warnings are a bounded fallback, and `summary.files_reviewed` is never treated as proof of successful coverage. Technical details label the aggregate as all OCR tool calls and retain the existing inline format while listing every admitted non-zero count for the closed native/context/evidence review set. An empty admitted list produces no tool-call line. The counts describe review activity, not per-tool token consumption: one read or search can return a different amount of context from another. Dynamic external tool names remain private; toolkit-verified MCP-server calls stay in their separate aggregate, and built-in evidence `summary`/`list`/`get` counts appear only after exact reconciliation. Zero-valued token counters and configured-but-unused MCP servers are omitted. Token usage renders only validated input/output/cached/reasoning/total/derived-other buckets; malformed or contradictory counters are unavailable and unknown provider keys are not published. Status and aggregate semantic-category emoji are enabled by default and can be disabled together with `OCR_POST_EMOJI=false`; finding labels remain text unless their separate badge mode is enabled. @@ -130,7 +130,7 @@ Suppression checks both the recorded inline position and compatible fingerprints Run OCR through `ocr-ci review --result PATH --stderr PATH -- ...`. This wrapper does not post to GitLab: it creates private artifacts, acquires enriched context when selected, asks the exact resolved and preflight-qualified OCR executable to preview the production refs/rules/selection/background without an LLM, then runs the model review only if OCR accepts that background. OCR owns the current recommendation and rejection thresholds; the toolkit has no threshold setting. A recognized soft diagnostic is reduced to a toolkit-authored `ocr.toolkit-advisory/v1` enum and two positive character counts. It is attached after publication DLP, rendered only with an exact receipt v5 in Technical details, and does not change warnings, coverage, DLP counts, telemetry, or automatic approval. A recognized hard character/file-size rejection stops before the model and lets `ocr-ci post` publish only a static numeric failure summary; the OCR path and raw diagnostic remain private. Unknown preview failures use the generic fail-closed diagnostic path. The ordinary review still validates the same background, the wrapper validates the complete output, and context/session/configuration data is removed. On an unclassified ordinary failure it prints only a bounded redacted stderr excerpt to the runner log; a classified provider failure keeps that excerpt private. Pass the paths and captured exit code to `ocr-ci post` afterward. Set `OCR_POST_ERROR_DETAILS=1` only when the generic path's safe excerpt should also appear in the merge-request failure note. Cleanup uncertainty blocks result publication. DLP atomically converts unsafe publication output into a safe `completed_with_errors` subset, but sanitizes unsafe private-only result fields without discarding an otherwise valid manifest or finding set. Safe findings are posted, unsafe finding content/warnings and unsafe optional fields are omitted, previous OCR comments remain, and matching prior findings are consumed one-for-one rather than duplicated. Receipt v5 and the `ocr.publication-dlp-signal/v2` marker distinguish `private-sanitized`, where the canonical published and approval-relevant projection is unchanged, from approval-ineligible `publication-filtered`, where the public projection is incomplete even when the receipt proves OCR coverage was complete. Posting uses only the validated original coverage kind and counts for status and Technical details; it never reconstructs or republishes rejected values. Horizontal tabs survive only in `existing_code` and `suggestion_code`; the unchanged values pass the same secret, PII, forbidden-value, laundering, and budget checks, while tabs elsewhere and all other control/format characters remain blocking. The same count-only JSON is logged as `OCR toolkit telemetry event` for optional CI collection/alerting. It is not an OTLP/network exporter and contains no rejected value or location. Never interpret a filtered subset as a full publishable review or as proof that OCR coverage was partial. -OCR 1.10.2 may add group labels, file membership, grouping-task records, and round diagnostics to its private result/session data. Safe values remain private; DLP removes or replaces unsafe result values before atomic retention. These fields are deliberately absent from the canonical finding/posting projection and receipt v5, so private-only sanitization does not block an otherwise eligible auto-approval. If any group or round field appears inside receipt v5, the receipt is invalid and approval fails closed. Caller `--output`/`-o` is rejected before preview: only `ocr-ci review --result` owns the result descriptor and posting handoff. +OCR 1.11.0 may add group labels, file membership, grouping-task records, round diagnostics, readable reasoning, and provider-native signed or encrypted replay payloads to its private session data. Safe values remain private; the isolated OCR home is removed before publication. Unknown private-only result fields are sanitized through the existing DLP owner, while any value reaching a canonical finding or warning makes publication incomplete and approval-ineligible. Reasoning, native payloads, and `tool_choice` are deliberately absent from the canonical finding/posting projection, receipt v5, DLP counts, toolkit telemetry, tool/token summary, and approval inputs. If they appear inside receipt v5, the receipt is invalid and approval fails closed. Caller `--output`/`-o` is rejected before preview: only `ocr-ci review --result` owns the result descriptor and posting handoff. When OCR exits nonzero with a valid bounded `ocr.llm-retry-report/v1`, the toolkit reads only its closed error class, failure phase, terminal outcome, HTTP status, and schema counters. It maps those facts to `authentication`, `authorization`, `rate-or-spending-limit`, `overloaded`, `timeout`, `network`, `endpoint-or-model-not-found`, `request-rejected`, `provider-unavailable`, `invalid-response`, `cancelled`, `mixed`, or `unknown`, then writes a completely toolkit-authored note. A runtime `404` remains `endpoint-or-model-not-found` because safely distinguishing the endpoint from the model would require trusting the raw response body. diff --git a/docs/security.md b/docs/security.md index 8617770..e41b434 100644 --- a/docs/security.md +++ b/docs/security.md @@ -115,7 +115,7 @@ Policy v2 adds optional toolkit-owned remediation threads without changing these - **Identity spoofing and privacy:** represent authors by provider-declared class plus run-local pseudonym; omit name, email, avatar, and profile URL. Unknown classification fails closed. - **TOCTOU/replay/cache poisoning:** bind snapshots and handles to version/ETag or digest, policy version, run, and expiry; use atomic store commits and uniform unavailable outcomes. - **PII/secret bypass and output laundering:** make retrieval, model egress, publication sinks, and private retention separate decisions. Minimize before model egress; publication DLP cannot undo prior disclosure. Scan decoded source and rendered forms so HTML comments/entities/tags, Markdown inline/reference/autolink destinations, controls, and Unicode formatting cannot hide exact protected values. Sink uncertainty yields a safe partial result; private-only uncertainty yields an atomically sanitized valid result or falls back to that partial form. Expose only low-cardinality receipt/summary/log signals in ordinary runs. The explicit local-only diagnostic switch retains owner-only raw private state, emits no receipt, and is rejected by the validated GitLab MR profile. -- **Upstream telemetry cardinality:** OCR 1.10.2 can place sorted changed paths in group span names/attributes and attach model-produced group labels and round counters. OCR telemetry is disabled by default. Enabling it authorizes the configured exporter to receive repository-derived high-cardinality data; content-logging disablement is not a promise that these identifiers disappear. The toolkit neither ingests nor duplicates them. +- **Upstream session and telemetry privacy:** OCR 1.11.0 can retain readable reasoning, signed/encrypted provider-native replay payloads, tool arguments/results, sorted changed paths, model-produced group labels, and round counters in its owner-only session. Telemetry may also carry repository-derived high-cardinality grouping values. OCR telemetry is disabled by default, and the toolkit removes the isolated session home before publication. Enabling an exporter authorizes it to receive the fields OCR emits; content-logging disablement is not a promise that every identifier disappears. The toolkit neither ingests nor duplicates these values. - **OCR advisory spoofing:** raw OCR output cannot supply `_ocr_toolkit_advisory`. The toolkit adds only the exact numeric `ocr.toolkit-advisory/v1` shape after publication DLP; posting requires a valid receipt v5 and rejects duplicate, extended, unknown, or malformed forms. The advisory cannot change warnings, coverage, DLP, telemetry, findings, or approval. - **Local executable and subprocess confused deputy:** accept the OCR executable only through absolute search-path entries and reject resolution inside the reviewed repository. Stdio adapter deadlines cover request delivery as well as response/exit, use a clean environment and isolated directory, and terminate the process group on uncertainty. - **Marker and retry spoofing:** recognize ownership, run-summary, and setup identities only in the exact toolkit preamble. Repository/provider text containing marker lookalikes has no authority. Duplicate findings consume visible prior occurrences one-for-one; successful setup retries replace only previous toolkit setup-pending notes. diff --git a/examples/gitlab/README.md b/examples/gitlab/README.md index 1d563c1..1270994 100644 --- a/examples/gitlab/README.md +++ b/examples/gitlab/README.md @@ -2,7 +2,7 @@ [`ocr-review.gitlab-ci.yml`](ocr-review.gitlab-ci.yml) is the complete checksum-pinned pipeline. It defaults to identity-only review and contains the install, preflight, configure, review, and post lifecycle. Copy one mode file below into the pipeline's top-level `variables` mapping, or include exactly one file after reviewing its trust boundary. -The pipeline pins OCR 1.10.2 and explicitly sets `OCR_REVIEW_EFFORT=medium`, which permits two review rounds. Use `low` for one round when latency/cost is the priority, or `high` for three only after accepting the additional provider work. Semantic grouping and filtering are OCR behavior shared by every context mode; they do not change which merge-request text a mode admits. `OCR_MAX_TOOLS=0` delegates the effective per-file tool-call limit to the installed OCR template. `OCR_MAX_TOKENS_BUDGET` and the optional completion cap remain independent controls. +The pipeline pins OCR 1.11.0 and explicitly sets `OCR_REVIEW_EFFORT=medium`, which permits two review rounds. Use `low` for one round when latency/cost is the priority, or `high` for three only after accepting the additional provider work. OCR uses a 15-minute subtask base and scales it to 15/30/45 minutes for low/medium/high; the example's 45-minute job timeout accommodates every preset without adding another environment control. Semantic grouping and filtering are OCR behavior shared by every context mode; they do not change which merge-request text a mode admits. `OCR_MAX_TOOLS=0` selects the embedded template default `100`. Values `1-49` report normalization to `50` but remain effectively `100`; only values above `100` raise the per-subtask cap. `OCR_MAX_TOKENS_BUDGET` and the optional completion cap remain independent controls. | Mode | Recipe | MR text admitted | External access | Automatic approval | | --- | --- | --- | --- | --- | diff --git a/examples/gitlab/ocr-review.gitlab-ci.yml b/examples/gitlab/ocr-review.gitlab-ci.yml index 6b3eb84..ac8645f 100644 --- a/examples/gitlab/ocr-review.gitlab-ci.yml +++ b/examples/gitlab/ocr-review.gitlab-ci.yml @@ -6,10 +6,10 @@ default: image: python:3.12-slim variables: - OCR_VERSION: "v1.10.2" + OCR_VERSION: "v1.11.0" OCR_TOOLKIT_VERSION: "0.8.5" OCR_TOOLKIT_CHECKSUMS_URL: "https://github.com/xeonvs/open-code-review-toolkit/releases/download/v${OCR_TOOLKIT_VERSION}/SHA256SUMS" - OCR_SHA256: "e9205614f80e009ee7b1f444c9da08486fb9ff6db022954fe9203d923ab720b2" + OCR_SHA256: "13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60" OCR_POST_MODE: "draft" OCR_STRICT_POSTING: "true" # Default-on receipt-bound approval; external MCP always remains comment-only. @@ -44,7 +44,8 @@ open_code_review: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' when: on_success - when: never - timeout: 30m + # OCR 1.11.0 scales the 15-minute subtask base by low/medium/high rounds (15/30/45). + timeout: 45m script: - apt-get update && apt-get install -y --no-install-recommends ca-certificates curl git - >- diff --git a/scripts/ocr_compat.py b/scripts/ocr_compat.py index ce6aa9a..20bc3dd 100644 --- a/scripts/ocr_compat.py +++ b/scripts/ocr_compat.py @@ -1001,9 +1001,7 @@ def _stub_gateway( thread.join(timeout=5) -def parse_grouping_inventory( - messages: list[Any], version: str -) -> list[GroupingInventoryEntry]: +def parse_grouping_inventory(messages: list[Any], version: str) -> list[GroupingInventoryEntry]: """Parse the exact grouping prompt shape qualified for one OCR release line.""" parsed_version = _version(version) @@ -1611,9 +1609,7 @@ def _semantic_grouping_probe(binary: Path, version: str, directory: Path) -> dic _fail("semantic grouping review did not preserve the accepted group") if stages != ["grouping", "main", "main", "filter", "main"]: _fail(f"default medium review emitted an unexpected stage sequence: {stages!r}") - expected_inventory = [ - GroupingInventoryEntry("MODIFIED", path, 1, 1) for path in paths - ] + expected_inventory = [GroupingInventoryEntry("MODIFIED", path, 1, 1) for path in paths] if len(grouping_inventories) != 1: _fail("semantic grouping review emitted an unexpected grouping inventory count") _require_exact_grouping_inventory(grouping_inventories[0], expected_inventory) diff --git a/src/ocr_toolkit/preflight.py b/src/ocr_toolkit/preflight.py index e049dbb..e8c8bd7 100644 --- a/src/ocr_toolkit/preflight.py +++ b/src/ocr_toolkit/preflight.py @@ -28,7 +28,7 @@ "Accept": "application/json", "User-Agent": "open-code-review-ci-preflight/1.0", } -EXPECTED_OCR_VERSION = "1.10.2" +EXPECTED_OCR_VERSION = "1.11.0" class PreflightError(Exception): diff --git a/tests/test_environment_contract.py b/tests/test_environment_contract.py index 5f80992..4f8a9ee 100644 --- a/tests/test_environment_contract.py +++ b/tests/test_environment_contract.py @@ -69,8 +69,8 @@ } EXAMPLE_DEFAULTS = { - "OCR_VERSION": "v1.10.2", - "OCR_SHA256": "e9205614f80e009ee7b1f444c9da08486fb9ff6db022954fe9203d923ab720b2", + "OCR_VERSION": "v1.11.0", + "OCR_SHA256": "13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60", "OCR_TOOLKIT_VERSION": STABLE_TOOLKIT_VERSION, "OCR_TOOLKIT_CHECKSUMS_URL": "Release URL derived from `OCR_TOOLKIT_VERSION`", "OCR_TOOLKIT_WHEEL": "open_code_review_toolkit-${OCR_TOOLKIT_VERSION}-py3-none-any.whl", @@ -299,7 +299,7 @@ def test_example_local_defaults_match_the_pipeline() -> None: encoding="utf-8" ) for name, value in { - "OCR_VERSION": "v1.10.2", + "OCR_VERSION": "v1.11.0", "OCR_SHA256": EXAMPLE_DEFAULTS["OCR_SHA256"], "OCR_TOOLKIT_VERSION": STABLE_TOOLKIT_VERSION, "OCR_MAX_TOOLS": "0", diff --git a/tests/test_integration_contracts.py b/tests/test_integration_contracts.py index 8eda256..06e8150 100644 --- a/tests/test_integration_contracts.py +++ b/tests/test_integration_contracts.py @@ -130,6 +130,7 @@ def test_gitlab_example_preserves_review_gating_and_manual_self_test() -> None: assert 'OCR_MAX_TOKENS_BUDGET: "0"' in workflow assert 'OCR_REVIEW_EFFORT: "medium"' in workflow assert 'OCR_MAX_TOOLS: "0"' in workflow + assert "timeout: 45m" in review_job assert '--max-tools "${OCR_MAX_TOOLS:-0}"' in review_job assert '--max-tokens-budget "${OCR_MAX_TOKENS_BUDGET:-0}"' in review_job assert "lint:\n stage: lint" in workflow diff --git a/tests/test_ocr_compat.py b/tests/test_ocr_compat.py index 45aec2d..bc70d6d 100644 --- a/tests/test_ocr_compat.py +++ b/tests/test_ocr_compat.py @@ -43,8 +43,8 @@ def test_committed_manifest_is_valid_and_has_recommended_tested_baseline() -> No module.validate_manifest(manifest, PROJECT_ROOT) - assert manifest["recommended_version"] == "1.10.2" - assert manifest["monitoring_floor"] == "1.10.2" + assert manifest["recommended_version"] == "1.11.0" + assert manifest["monitoring_floor"] == "1.11.0" assert [(item["version"], item["status"]) for item in manifest["releases"]] == [ ("1.7.17", "tested"), ("1.8.0", "tested"), @@ -72,6 +72,7 @@ def test_committed_manifest_is_valid_and_has_recommended_tested_baseline() -> No ("1.10.0", "tested"), ("1.10.1", "tested"), ("1.10.2", "tested"), + ("1.11.0", "tested"), ] @@ -156,9 +157,9 @@ def test_discovery_filters_known_prerelease_and_old_versions() -> None: def test_discovery_pages_until_the_monitoring_floor() -> None: module = load_script() manifest = module.load_json(MANIFEST) - first_page = [release("1.10.3")] + first_page = [release("1.11.1")] first_page.extend({"draft": True} for _ in range(module.MAX_RELEASES_PER_PAGE - 1)) - second_page = [release("1.10.2")] + second_page = [release("1.11.0")] requested: list[str] = [] def fake_request(url: str) -> list[dict[str, Any]]: @@ -168,14 +169,14 @@ def fake_request(url: str) -> list[dict[str, Any]]: with patched_attr(module, "_request_json", fake_request): unseen = module.discover_unseen(manifest) - assert [item["tag_name"] for item in unseen] == ["v1.10.3"] + assert [item["tag_name"] for item in unseen] == ["v1.11.1"] assert len(requested) == 2 def test_discovery_fails_when_bounded_pages_do_not_reach_floor() -> None: module = load_script() manifest = module.load_json(MANIFEST) - page = [release("1.10.3")] + page = [release("1.11.1")] page.extend({"draft": True} for _ in range(module.MAX_RELEASES_PER_PAGE - 1)) with patched_attr(module, "_request_json", lambda _url: page): @@ -220,14 +221,14 @@ def test_qualification_matrix_accepts_the_next_manual_patch() -> None: module = load_script() manifest = module.load_json(MANIFEST) - matrix = module.qualification_matrix(manifest, [release("1.10.3")]) + matrix = module.qualification_matrix(manifest, [release("1.11.1")]) assert matrix == { "include": [ { - "comparison_version": "1.10.2", - "tag": "v1.10.3", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tag": "v1.11.1", + "tested_baseline_version": "1.11.0", } ] } @@ -1115,11 +1116,15 @@ def messages(inventory: str) -> list[dict[str, str]]: "1.11.0", ) - assert old == new == [ - module.GroupingInventoryEntry("ADDED", "src/space (unicode) λ.py", 10, 0), - module.GroupingInventoryEntry("DELETED", "win\\deleted.hbs", 0, 5), - module.GroupingInventoryEntry("RENAMED", "renamed.mustache", 0, 0), - ] + assert ( + old + == new + == [ + module.GroupingInventoryEntry("ADDED", "src/space (unicode) λ.py", 10, 0), + module.GroupingInventoryEntry("DELETED", "win\\deleted.hbs", 0, 5), + module.GroupingInventoryEntry("RENAMED", "renamed.mustache", 0, 0), + ] + ) with pytest.raises(module.CompatibilityError, match="invalid grouping inventory entry"): module.parse_grouping_inventory(messages("ADDED path.py (+1/-0)"), "1.10.2") with pytest.raises(module.CompatibilityError, match="invalid grouping inventory entry"): @@ -1590,11 +1595,11 @@ def test_prepare_update_rejects_human_review_candidate(tmp_path: Path) -> None: module = load_script() evidence = { "schema_version": 2, - "version": "1.10.3", + "version": "1.11.1", "result": "compatible", "classification": "human-review-required", - "comparison_version": "1.10.2", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tested_baseline_version": "1.11.0", } with pytest.raises(module.CompatibilityError, match="bounded conclusion"): @@ -1610,11 +1615,11 @@ def test_prepare_update_requires_human_review_for_minor_transition() -> None: module = load_script() evidence = { "schema_version": 2, - "version": "1.11.0", + "version": "1.12.0", "result": "compatible", "classification": "automatic-safe", - "comparison_version": "1.10.2", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tested_baseline_version": "1.11.0", } with pytest.raises(module.CompatibilityError, match="explicit human review"): @@ -1626,7 +1631,7 @@ def test_prepare_update_requires_human_review_for_minor_transition() -> None: ) -@pytest.mark.parametrize("version", ["1.11.0", "2.0.0"]) +@pytest.mark.parametrize("version", ["1.12.0", "2.0.0"]) def test_prepare_update_rejects_schema_one_minor_or_major_transition(version: str) -> None: """Legacy evidence cannot prove a chain across a semantic-version boundary.""" @@ -1652,11 +1657,11 @@ def test_prepare_update_rejects_nonadjacent_minor_transition() -> None: module = load_script() evidence = { "schema_version": 2, - "version": "1.12.0", + "version": "1.13.0", "result": "compatible", "classification": "human-review-required", - "comparison_version": "1.10.2", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tested_baseline_version": "1.11.0", } with pytest.raises(module.CompatibilityError, match="contiguous release sequence"): @@ -1664,7 +1669,7 @@ def test_prepare_update_rejects_nonadjacent_minor_transition() -> None: manifest_path=MANIFEST, evidence=evidence, fragment_number=73, - human_conclusions={"1.12.0": "Synthetic reviewed conclusion."}, + human_conclusions={"1.13.0": "Synthetic reviewed conclusion."}, root=PROJECT_ROOT, ) @@ -1673,11 +1678,11 @@ def test_prepare_update_rejects_conclusion_outside_evidence_chain() -> None: module = load_script() evidence = { "schema_version": 2, - "version": "1.10.3", + "version": "1.11.1", "result": "compatible", "classification": "automatic-safe", - "comparison_version": "1.10.2", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tested_baseline_version": "1.11.0", } with pytest.raises(module.CompatibilityError, match="only evidence versions"): @@ -1685,7 +1690,7 @@ def test_prepare_update_rejects_conclusion_outside_evidence_chain() -> None: manifest_path=MANIFEST, evidence=evidence, fragment_number=72, - human_conclusions={"1.10.4": "Synthetic unrelated conclusion."}, + human_conclusions={"1.11.2": "Synthetic unrelated conclusion."}, root=PROJECT_ROOT, ) @@ -1697,11 +1702,11 @@ def test_prepare_update_rejects_invalid_optional_reviewed_conclusion( module = load_script() evidence = { "schema_version": 2, - "version": "1.10.3", + "version": "1.11.1", "result": "compatible", "classification": "automatic-safe", - "comparison_version": "1.10.2", - "tested_baseline_version": "1.10.2", + "comparison_version": "1.11.0", + "tested_baseline_version": "1.11.0", } with pytest.raises(module.CompatibilityError, match="bounded plain text"): @@ -1709,7 +1714,7 @@ def test_prepare_update_rejects_invalid_optional_reviewed_conclusion( manifest_path=MANIFEST, evidence=evidence, fragment_number=72, - human_conclusions={"1.10.3": conclusion}, + human_conclusions={"1.11.1": conclusion}, root=PROJECT_ROOT, ) diff --git a/tests/test_operations_docs.py b/tests/test_operations_docs.py index 4b04b40..573abf3 100644 --- a/tests/test_operations_docs.py +++ b/tests/test_operations_docs.py @@ -508,12 +508,15 @@ def test_ocr_compatibility_workflow_is_bounded_and_protected() -> None: "OCR 1.10.0 — toolkit 0.8.2 and 0.8.3 target", "OCR 1.10.1 — toolkit 0.8.4 target", "OCR 1.10.2 — toolkit 0.8.5 target", + "OCR 1.11.0 — toolkit 0.8.6 target", "ocr.toolkit-advisory/v1", "ocr.llm-retry-report/v1", "not toolkit telemetry", "Deploy toolkit 0.8.2 or 0.8.3 directly with OCR 1.10.0", "Deploy toolkit 0.8.4 directly with OCR 1.10.1", "Deploy toolkit 0.8.5 directly with OCR 1.10.2", + "Deploy toolkit 0.8.6 directly with OCR 1.11.0", + "max-tools runtime behavior is unchanged", "max_completion_tokens=16384", "do not install OCR 1.9.10 as an intermediate step", ): @@ -542,11 +545,12 @@ def test_numeric_ocr_controls_use_behavioral_qualification_and_template_delegati compatibility = (PROJECT_ROOT / "docs" / "compatibility.md").read_text(encoding="utf-8") development = (PROJECT_ROOT / "docs" / "development.md").read_text(encoding="utf-8") - assert "`0` delegates to the installed OCR template" in configuration - assert "template's effective `100` rounds" in configuration - assert "result\nwarnings, receipts, DLP inputs, telemetry" in configuration + assert "default at `0` so OCR uses its embedded template limit of `100`" in configuration + assert "explicit `50` remain below the template default" in configuration + assert "raw stderr is not added to\nfindings, result warnings" in configuration + assert "receipts, DLP inputs, telemetry" in configuration assert "`OCR_MAX_TOOLS=0`" in operations - assert "CLI help, normalization text, and effective template value can differ" in operations + assert "corrects stale help text for the already-qualified behavior" in operations assert "effective `100` for omitted, sentinel `0`, `49`, and `50`" in compatibility assert "help text\n alone is not compatibility evidence" in development diff --git a/tests/test_runtime_helpers.py b/tests/test_runtime_helpers.py index 72ae82e..2ec4e19 100644 --- a/tests/test_runtime_helpers.py +++ b/tests/test_runtime_helpers.py @@ -1476,7 +1476,7 @@ def test_invalid_json_error_does_not_echo_secret_payload(self) -> None: class PreflightTests(unittest.TestCase): def test_validate_ocr_binary_accepts_supported_version(self) -> None: completed = subprocess.CompletedProcess( - args=["ocr", "--version"], returncode=0, stdout="ocr 1.10.2\n", stderr="" + args=["ocr", "--version"], returncode=0, stdout="ocr 1.11.0\n", stderr="" ) with ( patched_attr(preflight.shutil, "which", lambda _name: "/usr/bin/ocr"), From 29dd5a927989ffda4ccb90871346df43b642702c Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:45:19 +0200 Subject: [PATCH 4/9] Protect provider-private OCR state --- PLANS.md | 9 +- changelog.d/155.bugfix.md | 1 + docs/engineering/test_evidence_matrix.md | 2 +- src/ocr_toolkit/review_runner.py | 25 ++- tests/test_posting_approval.py | 10 ++ tests/test_review_runner.py | 189 +++++++++++++++++++++++ tests/test_runtime_helpers.py | 17 ++ 7 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 changelog.d/155.bugfix.md diff --git a/PLANS.md b/PLANS.md index 9853883..88f71f9 100644 --- a/PLANS.md +++ b/PLANS.md @@ -154,7 +154,7 @@ state for this task: `release-deferred` after a green Draft handoff. | `WQ-02` | `done` | Strict grouping harness committed; the two signed initial commits were pushed and Draft PR #154 opened. | | `WQ-03` | `done` | Milestone v0.8.6 and issue #155 are coordinated; hosted run 33158664020 produced accepted exact 1.11.0 evidence. | | `WQ-04` | `done` | Exact 1.11.0 evidence/pins/preflight/example/docs/rules/timeouts/backlog and max-tools help/runtime distinction are integrated; local OCR is atomically updated and no-LLM qualified. | -| `WQ-05` | `pending` | Add reasoning/tool-choice/private-session qualification and DLP/cleanup/receipt/approval regressions. | +| `WQ-05` | `done` | Provider-private reasoning/request fields are stripped before persistence and receipt binding; laundering through public sinks is filtered, explicit tool choice is preserved, and receipt/approval regressions pass. | | `WQ-06` | `pending` | Implement and verify #153's closed contextual security-signal matcher. | | `WQ-07` | `pending` | Update README/public docs and categorized changelog with the external qualification table. | | `WQ-08` | `pending` | Run holistic self-review and the one complete local final gate; update plan to truthful Draft handoff state. | @@ -241,6 +241,13 @@ state for this task: `release-deferred` after a green Draft handoff. or credentials were used. - 2026-08-28: the integrated OCR slice passes 229 focused tests plus 104 subtests, manifest validation, Ruff lint and repository-wide format check, and `git diff --check`. +- 2026-08-28: provider-private reasoning, encrypted/native replay payloads, and request + `tool_choice` fields are removed from the persisted result without changing a + byte-equivalent canonical review projection or blocking approval. The same keys in a + public finding or warning fail closed as `publication-filtered`; receipt v5 rejects + private replay/request fields, while actual tool-call and reasoning-token counters remain + available. The focused boundary suite passes 253 tests plus 186 subtests, Ruff, MyPy, + repository-wide format check, and `git diff --check`. #### Risks And Recovery diff --git a/changelog.d/155.bugfix.md b/changelog.d/155.bugfix.md new file mode 100644 index 0000000..ac35602 --- /dev/null +++ b/changelog.d/155.bugfix.md @@ -0,0 +1 @@ +Remove provider-private reasoning, encrypted/native replay payloads, and request `tool_choice` fields before persisting the canonical OCR result or binding receipt v5. Private-only removal preserves a byte-equivalent review projection and approval eligibility, while attempts to launder the same fields through findings or warnings are publication-filtered. Public tool-call and reasoning-token counters remain unchanged. diff --git a/docs/engineering/test_evidence_matrix.md b/docs/engineering/test_evidence_matrix.md index f9bb82a..c3a2f2d 100644 --- a/docs/engineering/test_evidence_matrix.md +++ b/docs/engineering/test_evidence_matrix.md @@ -129,7 +129,7 @@ The M5 negative suite is an attacker matrix, not merely a replay of observed rev | --- | --- | --- | --- | --- | --- | | Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, explicit `4096`, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict 1.10.2/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay | proven for exact qualified OCR contract | | Max-tools help correction does not imply runtime drift | exact numeric CLI and effective loop probes -> public operator docs | omitted/`0` remain effective `100`; `49` reports `50` but stays effective `100`; `50` stays effective `100`; `101` becomes effective `101` | identical hosted 1.10.2 and 1.11.0 evidence plus upstream #1077 source/release audit | behavioral probes prove current embedded-template ownership; they do not promise future OCR defaults | proven unchanged | -| Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | pending toolkit regressions | +| Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | toolkit containment proven; provider replay pending external qualification | | New selection behavior stays at the OCR edge | exact no-LLM preview/rule resolver -> built-in OCR Rules | repository-relative/backslash `file_find` fallback and `.hbs`/`.mustache` rule selection work without changing toolkit evidence authority | adjacent source audit plus isolated checksum-verified Darwin version/help, rule readback, and soft/hard background previews | selection proves routing, not review finding quality or evidence-pack completion | proven | ## Complete suite module audit diff --git a/src/ocr_toolkit/review_runner.py b/src/ocr_toolkit/review_runner.py index 8e116eb..7381d96 100644 --- a/src/ocr_toolkit/review_runner.py +++ b/src/ocr_toolkit/review_runner.py @@ -154,6 +154,16 @@ "suggestion_code", } ) +PROVIDER_PRIVATE_RESULT_KEYS = frozenset( + { + "encrypted_content", + "native_payload", + "reasoning_content", + "redacted_thinking", + "thinking", + "tool_choice", + } +) class ReviewRunnerError(Exception): @@ -463,8 +473,10 @@ def _dlp_reasons( while stack: nested = stack.pop() if isinstance(nested, dict): - stack.extend(nested.keys()) - stack.extend(nested.values()) + for key, value in nested.items(): + if isinstance(key, str) and key in PROVIDER_PRIVATE_RESULT_KEYS: + reasons["invalid_text"] += 1 + stack.extend((key, value)) elif isinstance(nested, list): stack.extend(nested) elif isinstance(nested, str): @@ -693,6 +705,11 @@ def _sanitize_nonpublication_fields( child_path = (*path, key) if isinstance(source, dict): assert isinstance(key, str) + if key in PROVIDER_PRIVATE_RESULT_KEYS and not _is_publication_sink_path( + child_path + ): + redacted_fields += 1 + continue if not _is_publication_sink_path( child_path ) and not _is_static_public_tool_key_path(child_path): @@ -894,7 +911,7 @@ def _publication_projection( sanitized, private_reasons, redacted_fields = _sanitize_nonpublication_fields( payload, budgets=budgets, matcher=matcher ) - if not sink_reasons and not private_reasons: + if not sink_reasons and not private_reasons and redacted_fields == 0: return payload, {"state": "passed"}, False try: @@ -932,6 +949,8 @@ def _publication_projection( projected["summary"] = {"budget_exceeded": True} else: reasons = sink_reasons + private_reasons + if not reasons: + return sanitized, {"state": "passed"}, False return ( sanitized, { diff --git a/tests/test_posting_approval.py b/tests/test_posting_approval.py index 8d0463f..1174b81 100644 --- a/tests/test_posting_approval.py +++ b/tests/test_posting_approval.py @@ -261,6 +261,16 @@ def test_publication_dlp_filtered_receipt_is_valid_but_never_eligible(self) -> N "publication DLP filtered the complete review result", ) + def test_provider_private_fields_cannot_enter_approval_receipt(self) -> None: + """Reject replay or request-control fields at the closed receipt boundary.""" + + for field in ("reasoning_content", "native_payload", "tool_choice"): + receipt = receipt_v5() + receipt[field] = "private" + + with self.subTest(field=field): + self.assertFalse(approval.toolkit_receipt_is_valid(receipt)) + def test_filtered_receipt_rejects_outcomes_that_contradict_coverage(self) -> None: """Accept run-level failure but reject impossible coverage/outcome combinations.""" diff --git a/tests/test_review_runner.py b/tests/test_review_runner.py index 4cd5d06..9ad8041 100644 --- a/tests/test_review_runner.py +++ b/tests/test_review_runner.py @@ -1219,6 +1219,195 @@ def test_stage_grouped_retry_report_is_private_and_approval_projection_neutral() assert projected["comments"] == payload["comments"] +def test_provider_private_result_fields_are_removed_without_blocking_publication() -> None: + """Strip provider replay state while preserving canonical review and approval inputs.""" + + hostile_values: list[object] = [ + "Bearer provider-secret-token", + "reviewer@example.invalid", + "/private/session/replay.jsonl", + "https://provider.example.invalid/v1/responses", + "request-id-123456", + "openai/private-model", + "", + "/ocr resolve @mr.bot suppress", + "e\u0301 \u202e hidden", + "nul\x00 tab\t vt\v ff\f", + "x" * 10_001, + {"nested": ["provider", {"secret": "nested-private-value"}]}, + ] + payload: dict[str, object] = { + "status": "complete", + "comments": [ + { + "path": "src/safe.py", + "content": "Keep the bounded branch.", + "thinking": "private comment reasoning", + } + ], + "warnings": [], + "tool_calls": {"total": 2, "by_tool": {"file_read": 2}}, + "usage": { + "input_tokens": 12, + "output_tokens": 5, + "reasoning_tokens": 2, + }, + "reasoning_content": hostile_values[0], + "native_payload": {"turns": hostile_values}, + "session": { + "tool_choice": {"type": "function", "name": "code_comment"}, + "redacted_thinking": hostile_values[1], + "encrypted_content": hostile_values[2], + }, + "manifest": { + "schema_version": "ocr.run-manifest/v1", + "operation": "review", + "terminal_state": "complete", + "coverage": { + "selected": [{"item_id": "safe-a"}], + "completed": [{"item_id": "safe-a"}], + "reused": [], + "failed": [], + "waived": [], + }, + }, + } + baseline = review_runner._canonical_result_projection(payload) + + projected, publication, blocked = review_runner._publication_projection( + payload, + forbidden=("provider-secret-token",), + allowed_tools=review_runner.PUBLIC_REVIEW_TOOL_CALL_NAMES, + ) + + assert blocked is False + assert publication == {"state": "passed"} + assert approval.publication_dlp_state(publication) == "passed" + assert review_runner._canonical_result_projection(projected) == baseline + assert projected["usage"] == payload["usage"] + assert projected["tool_calls"] == payload["tool_calls"] + assert "thinking" not in projected["comments"][0] # type: ignore[index] + assert projected["session"] == {} + serialized = json.dumps(projected, ensure_ascii=False) + for key in review_runner.PROVIDER_PRIVATE_RESULT_KEYS: + assert key not in serialized + for value in ("provider-secret-token", "reviewer@example.invalid", "request-id-123456"): + assert value not in serialized + + +def test_finalized_result_drops_provider_private_fields_before_receipt_binding( + tmp_path: Path, +) -> None: + """Persist only the canonical result and a valid unchanged receipt projection.""" + + result = tmp_path / "result.json" + result.write_text( + json.dumps( + { + "status": "complete", + "comments": [ + { + "path": "src/safe.py", + "content": "Keep the validated branch.", + "thinking": "private reasoning projection", + } + ], + "warnings": [], + "tool_calls": {"total": 1, "by_tool": {"ocr_toolkit_evidence": 1}}, + "reasoning_content": "private chat reasoning", + "native_payload": {"encrypted_content": "private ciphertext"}, + "request": {"tool_choice": "auto"}, + "manifest": { + "schema_version": "ocr.run-manifest/v1", + "operation": "review", + "terminal_state": "complete", + "coverage": { + "selected": [{"item_id": "safe-a"}], + "completed": [{"item_id": "safe-a"}], + "reused": [], + "failed": [], + "waived": [], + }, + }, + } + ), + encoding="utf-8", + ) + composition = MCPComposition( + payload={}, + capabilities=(MCPCapability("ocr_toolkit_evidence", ("ocr_toolkit_evidence",), True),), + external_servers=(), + secret_values=(), + ) + + usage, blocked, publication = review_runner._finalize_ocr_result( + result, + composition, + replace(DEFAULT_IDENTITY, mr_author_id=41), + None, + forbidden=(), + ) + + persisted = json.loads(result.read_text(encoding="utf-8")) + metadata = persisted[ocr_result.TOOLKIT_RESULT_KEY] + assert usage == {"ocr_toolkit_evidence": 1} + assert blocked is False + assert publication == {"state": "passed"} + assert approval.toolkit_receipt_is_valid(metadata) + assert metadata["publication"] == {"state": "passed"} + assert persisted["comments"] == [ + {"path": "src/safe.py", "content": "Keep the validated branch."} + ] + assert persisted["request"] == {} + serialized = result.read_text(encoding="utf-8") + for key in review_runner.PROVIDER_PRIVATE_RESULT_KEYS: + assert key not in serialized + + +@pytest.mark.parametrize("public_field", ["comment", "warning"]) +def test_provider_private_fields_in_public_projection_fail_closed(public_field: str) -> None: + """Treat provider replay state laundered through a public field as filtered output.""" + + comments: list[dict[str, object]] = [] + warnings: list[object] = [] + private_value = {"reasoning_content": "apparently harmless private reasoning"} + if public_field == "comment": + comments.append({"path": "src/safe.py", "content": private_value}) + else: + warnings.append(private_value) + payload: dict[str, object] = { + "status": "complete", + "comments": comments, + "warnings": warnings, + "manifest": { + "schema_version": "ocr.run-manifest/v1", + "operation": "review", + "terminal_state": "complete", + "coverage": { + "selected": [{"item_id": "safe-a"}], + "completed": [{"item_id": "safe-a"}], + "reused": [], + "failed": [], + "waived": [], + }, + }, + } + + projected, publication, blocked = review_runner._publication_projection( + payload, + forbidden=(), + allowed_tools=review_runner.PUBLIC_REVIEW_TOOL_CALL_NAMES, + ) + + assert blocked is True + assert publication["state"] == "publication-filtered" + assert publication["reason_counts"]["invalid_text"] == 1 # type: ignore[index] + assert approval.publication_dlp_state(publication) == "publication-filtered" + assert projected["comments"] == [] + assert projected["warnings"] == [] + assert "reasoning_content" not in json.dumps(projected) + + def test_review_groups_remain_private_and_cannot_change_approval(tmp_path: Path) -> None: """Keep additive group and round diagnostics outside every approval authority.""" diff --git a/tests/test_runtime_helpers.py b/tests/test_runtime_helpers.py index 2ec4e19..6f9149f 100644 --- a/tests/test_runtime_helpers.py +++ b/tests/test_runtime_helpers.py @@ -565,6 +565,23 @@ def test_runtime_config_preserves_explicit_empty_extra_body(self) -> None: self.assertEqual(updates["llm.extra_body"], {}) + def test_runtime_config_preserves_explicit_tool_choice_without_defaulting_it(self) -> None: + """Leave tool selection absent unless the operator explicitly owns it.""" + + common = { + "OCR_LLM_URL": "https://gateway.example/v1/chat/completions", + "OCR_LLM_TOKEN": "llm-secret", + "OCR_LLM_MODEL": "openai/gpt-test", + "OCR_LLM_PROTOCOL": "openai", + } + with cleared_env("OCR_LLM_EXTRA_BODY"), patched_env(**common): + inherited = ocr_configure.build_config_updates() + with patched_env(**common, OCR_LLM_EXTRA_BODY='{"tool_choice":"auto"}'): + explicit = ocr_configure.build_config_updates() + + self.assertNotIn("llm.extra_body", inherited) + self.assertEqual(explicit["llm.extra_body"], {"tool_choice": "auto"}) + def test_runtime_config_maps_completion_cap_by_protocol(self) -> None: expected = { "openai": "max_completion_tokens", From 36af18545aa0065d31e9ece318f6c9d99b1a726a Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:47:52 +0200 Subject: [PATCH 5/9] Refine security signal classification --- PLANS.md | 9 ++- changelog.d/153.bugfix.md | 1 + docs/engineering/test_evidence_matrix.md | 1 + src/ocr_toolkit/posting/formatting.py | 12 +++- tests/test_posting_helpers.py | 89 ++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 changelog.d/153.bugfix.md diff --git a/PLANS.md b/PLANS.md index 88f71f9..078976c 100644 --- a/PLANS.md +++ b/PLANS.md @@ -155,7 +155,7 @@ state for this task: `release-deferred` after a green Draft handoff. | `WQ-03` | `done` | Milestone v0.8.6 and issue #155 are coordinated; hosted run 33158664020 produced accepted exact 1.11.0 evidence. | | `WQ-04` | `done` | Exact 1.11.0 evidence/pins/preflight/example/docs/rules/timeouts/backlog and max-tools help/runtime distinction are integrated; local OCR is atomically updated and no-LLM qualified. | | `WQ-05` | `done` | Provider-private reasoning/request fields are stripped before persistence and receipt binding; laundering through public sinks is filtered, explicit tool choice is preserved, and receipt/approval regressions pass. | -| `WQ-06` | `pending` | Implement and verify #153's closed contextual security-signal matcher. | +| `WQ-06` | `done` | #153 now uses explicit metadata/strong terms plus a closed injection-class matcher over published findings; neutral domains do not inflate guide count or effort. | | `WQ-07` | `pending` | Update README/public docs and categorized changelog with the external qualification table. | | `WQ-08` | `pending` | Run holistic self-review and the one complete local final gate; update plan to truthful Draft handoff state. | | `WQ-09` | `pending` | Final push, hosted CI reconciliation, Draft/issue/milestone/remote/worktree readback. | @@ -248,6 +248,13 @@ state for this task: `release-deferred` after a green Draft handoff. private replay/request fields, while actual tool-call and reasoning-token counters remain available. The focused boundary suite passes 253 tests plus 186 subtests, Ruff, MyPy, repository-wide format check, and `git diff --check`. +- 2026-08-28: #153's exact three-finding reproducer now yields one security-sensitive + finding and effort `2/5`. Explicit security metadata and command/shell, SQL/NoSQL, + code, template, prompt, LDAP, XPath, CRLF/header, log, HTML/script, and expression + injection remain promoted across bounded separator/case variants; knowledge, dependency, + and other non-closed phrases remain ordinary. All 200 posting-helper tests plus 161 + subtests pass with deterministic ordering and no input mutation; Ruff, MyPy, + repository-wide format check, and `git diff --check` pass. #### Risks And Recovery diff --git a/changelog.d/153.bugfix.md b/changelog.d/153.bugfix.md new file mode 100644 index 0000000..4db572d --- /dev/null +++ b/changelog.d/153.bugfix.md @@ -0,0 +1 @@ +Classify reviewer-guide injection signals by explicit vulnerability context instead of the standalone word `injection`. Command/shell, SQL/NoSQL, code, template, prompt, LDAP, XPath, CRLF/header, log, HTML/script, and expression injection remain security-sensitive; neutral phrases such as knowledge or dependency injection no longer inflate the published security count or estimated review effort. Finding severity, lifecycle, suppression, and approval behavior are unchanged. diff --git a/docs/engineering/test_evidence_matrix.md b/docs/engineering/test_evidence_matrix.md index c3a2f2d..23fad17 100644 --- a/docs/engineering/test_evidence_matrix.md +++ b/docs/engineering/test_evidence_matrix.md @@ -131,6 +131,7 @@ The M5 negative suite is an attacker matrix, not merely a replay of observed rev | Max-tools help correction does not imply runtime drift | exact numeric CLI and effective loop probes -> public operator docs | omitted/`0` remain effective `100`; `49` reports `50` but stays effective `100`; `50` stays effective `100`; `101` becomes effective `101` | identical hosted 1.10.2 and 1.11.0 evidence plus upstream #1077 source/release audit | behavioral probes prove current embedded-template ownership; they do not promise future OCR defaults | proven unchanged | | Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | toolkit containment proven; provider replay pending external qualification | | New selection behavior stays at the OCR edge | exact no-LLM preview/rule resolver -> built-in OCR Rules | repository-relative/backslash `file_find` fallback and `.hbs`/`.mustache` rule selection work without changing toolkit evidence authority | adjacent source audit plus isolated checksum-verified Darwin version/help, rule readback, and soft/hard background previews | selection proves routing, not review finding quality or evidence-pack completion | proven | +| Contextual security-signal classification | DLP-checked published finding -> closed metadata/term matcher -> reviewer guide | explicit vulnerability classes remain promoted while neutral injection domains do not increase the count or effort | issue #153 reproducer, closed positive/neutral separator matrix, deterministic ranking, and immutability regressions in `test_posting_helpers.py` | guide analytics only; severity, finding lifecycle, suppression, and approval inputs remain unchanged | proven | ## Complete suite module audit diff --git a/src/ocr_toolkit/posting/formatting.py b/src/ocr_toolkit/posting/formatting.py index 42aea9f..bec5490 100644 --- a/src/ocr_toolkit/posting/formatting.py +++ b/src/ocr_toolkit/posting/formatting.py @@ -650,10 +650,17 @@ def format_token_usage_summary(result: dict[str, Any]) -> str: r"(?i)\b(" r"security|credential|secret|token|password|private[_ -]?token|" r"client[_ -]?secret|api[_ -]?key|authorization|auth|" - r"injection|xss|csrf|ssrf|rce|path traversal|host header|" + r"xss|csrf|ssrf|rce|path traversal|host header|" r"privilege|permission|access control|vault|leak" r")\b" ) +SECURITY_INJECTION_RE = re.compile( + r"(?i)(? str: def comment_has_security_signal(comment: dict[str, Any]) -> bool: """Return true only when OCR text explicitly carries security wording.""" - return bool(SECURITY_SIGNAL_RE.search(comment_signal_text(comment))) + text = comment_signal_text(comment) + return bool(SECURITY_SIGNAL_RE.search(text) or SECURITY_INJECTION_RE.search(text)) def comment_is_high_signal(comment: dict[str, Any]) -> bool: diff --git a/tests/test_posting_helpers.py b/tests/test_posting_helpers.py index 7d45723..c5d24fd 100644 --- a/tests/test_posting_helpers.py +++ b/tests/test_posting_helpers.py @@ -3396,6 +3396,95 @@ def test_security_signal_is_promoted_when_present(self) -> None: self.assertIn("## Security review focus", guide) self.assertIn("**Security signal:**", guide) + def test_reviewer_guide_does_not_promote_neutral_injection_phrase(self) -> None: + """Count only the real security finding from the issue reproducer.""" + + comments = [ + { + "severity": "high", + "category": "security", + "path": "src/command_builder.py", + "line": 12, + "content": "Untrusted input can cause shell command injection.", + }, + { + "severity": "medium", + "category": "bug", + "path": "src/documentation_plan.py", + "line": 34, + "content": "Validate the knowledge injection payload before rendering.", + }, + { + "severity": "medium", + "category": "bug", + "path": "src/schema.py", + "line": 56, + "content": "Constrain the accepted enum values.", + }, + ] + original = [dict(comment) for comment in comments] + + guide = posting_formatting.format_reviewer_guide(comments, omitted_count=0) + + self.assertEqual(comments, original) + self.assertIn("**Security signal:** 1 published OCR finding", guide) + self.assertIn("Estimated effort to review: 2/5", guide) + + def test_security_signal_accepts_only_closed_injection_classes(self) -> None: + """Recognize explicit vulnerability classes across safe separators and casing.""" + + positive = ( + "command injection", + "OS command injection", + "shell command injection", + "SQL-injection", + "NoSQL_INJECTION", + "code injection", + "server-side template injection", + "prompt injection", + "LDAP injection", + "XPath injection", + "CRLF injection", + "HTTP header injection", + "log injection", + "HTML injection", + "script injection", + "expression\u2014injection", + ) + + for content in positive: + with self.subTest(content=content): + self.assertTrue( + posting_formatting.comment_has_security_signal({"content": content}) + ) + + def test_security_signal_rejects_neutral_and_partial_injection_terms(self) -> None: + """Do not promote neutral domains or substrings outside closed word boundaries.""" + + neutral = ( + "knowledge injection", + "dependency injection", + "data injection", + "injection molding", + "codeinjection", + "prompt injectionist", + "expression/injection", + ) + + for content in neutral: + with self.subTest(content=content): + self.assertFalse( + posting_formatting.comment_has_security_signal( + {"severity": "medium", "category": "bug", "content": content} + ) + ) + + self.assertTrue( + posting_formatting.comment_has_security_signal( + {"severity": "low", "category": "security", "content": "dependency injection"} + ) + ) + def test_reviewer_guide_ranks_only_its_published_copy(self) -> None: comments = [ { From 772db0f9037b0e093d8493479c1703b0b07d8d15 Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:52:25 +0200 Subject: [PATCH 6/9] Document OCR 1.11 deployment --- PLANS.md | 10 +++++++++- README.md | 31 +++++++++++++++++++++++++++++-- changelog.d/153.bugfix.md | 6 +++++- changelog.d/155.bugfix.md | 6 +++++- changelog.d/155.doc.md | 4 ++++ changelog.d/155.maintenance.md | 7 ++++++- changelog.d/155.rules.md | 2 +- docs/development.md | 3 ++- docs/gitlab.md | 2 +- tests/test_operations_docs.py | 27 +++++++++++++++++++++++++++ tests/test_quality_script.py | 12 ++++++++++++ 11 files changed, 101 insertions(+), 9 deletions(-) create mode 100644 changelog.d/155.doc.md diff --git a/PLANS.md b/PLANS.md index 078976c..b377a00 100644 --- a/PLANS.md +++ b/PLANS.md @@ -156,7 +156,7 @@ state for this task: `release-deferred` after a green Draft handoff. | `WQ-04` | `done` | Exact 1.11.0 evidence/pins/preflight/example/docs/rules/timeouts/backlog and max-tools help/runtime distinction are integrated; local OCR is atomically updated and no-LLM qualified. | | `WQ-05` | `done` | Provider-private reasoning/request fields are stripped before persistence and receipt binding; laundering through public sinks is filtered, explicit tool choice is preserved, and receipt/approval regressions pass. | | `WQ-06` | `done` | #153 now uses explicit metadata/strong terms plus a closed injection-class matcher over published findings; neutral domains do not inflate guide count or effort. | -| `WQ-07` | `pending` | Update README/public docs and categorized changelog with the external qualification table. | +| `WQ-07` | `done` | README/public operations/install/formatting guidance and agent-readable categorized changelog are current; the Draft retains the external old/new grouping and provider-wire qualification table for final-head binding. | | `WQ-08` | `pending` | Run holistic self-review and the one complete local final gate; update plan to truthful Draft handoff state. | | `WQ-09` | `pending` | Final push, hosted CI reconciliation, Draft/issue/milestone/remote/worktree readback. | @@ -255,6 +255,14 @@ state for this task: `release-deferred` after a green Draft handoff. and other non-closed phrases remain ordinary. All 200 posting-helper tests plus 161 subtests pass with deterministic ordering and no input mutation; Ruff, MyPy, repository-wide format check, and `git diff --check` pass. +- 2026-08-28: root installation now requires Python 3.12–3.14, recommends isolated + `uv tool install`, bounds `pip` to an activated virtualenv, and names exact + checksum-verified OCR 1.11.0 plus no-LLM version/help smoke checks. Public docs clarify + max-tools, private reasoning/tool choice, and contextual security signals; required + environment-variable names remain bold. The canonical development workflow now applies + Ruff formatting before self-review and checks the entire repository before every Python + commit. All 61 documentation/integration/quality/release-note tests, Ruff, the + repository-wide format check, Towncrier draft, and `git diff --check` pass. #### Risks And Recovery diff --git a/README.md b/README.md index 73cbd9b..564dec3 100644 --- a/README.md +++ b/README.md @@ -11,18 +11,45 @@ Open Code Review Toolkit is an unofficial GitLab CI integration layer for [Aliba ## Install -Install the Python package from PyPI and install a supported OCR binary separately: +Python 3.12 through 3.14 is supported. Install the toolkit CLI in an isolated tool +environment: ```console +uv tool install open-code-review-toolkit +``` + +If `uv` is unavailable, use `pip` only inside an activated virtual environment; do not +install the toolkit into a global Python environment: + +```console +python -m venv .venv +. .venv/bin/activate python -m pip install open-code-review-toolkit +``` + +The toolkit does not bundle OCR. Download the platform asset for exact +[Open Code Review 1.11.0](https://github.com/alibaba/open-code-review/releases/tag/v1.11.0), +verify it before installation against the [compatibility manifest](compatibility/ocr-support.json), +and place the verified binary on `PATH`. The current Linux amd64 digest is +`13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60`; Darwin arm64 is +`ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78`. The manifest owns +the other platform hashes. + +Verify the installation without contacting an LLM provider: + +```console ocr --version ocr-ci --help ``` +`ocr --version` must report `open-code-review v1.11.0`; `ocr-ci --help` must exit +successfully. `ocr-ci preflight` is an operational configuration check, not the installation +smoke test. + The exact recommended OCR release and its verified asset checksums live in the [versioned compatibility manifest](compatibility/ocr-support.json). CI should pin that release and checksum before execution. The [versioned compatibility policy](docs/compatibility.md) records tested assets and evidence and describes the conservative Dependabot-like qualification workflow for later upstream releases. Review output defaults to English. `OCR_REVIEW_LANGUAGE` accepts another explicit language name when a project needs localized review output; for example, `OCR_REVIEW_LANGUAGE=Russian`. -The current OCR 1.10.2 integration defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries. +The current OCR 1.11.0 integration defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries. Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI. diff --git a/changelog.d/153.bugfix.md b/changelog.d/153.bugfix.md index 4db572d..ed74a41 100644 --- a/changelog.d/153.bugfix.md +++ b/changelog.d/153.bugfix.md @@ -1 +1,5 @@ -Classify reviewer-guide injection signals by explicit vulnerability context instead of the standalone word `injection`. Command/shell, SQL/NoSQL, code, template, prompt, LDAP, XPath, CRLF/header, log, HTML/script, and expression injection remain security-sensitive; neutral phrases such as knowledge or dependency injection no longer inflate the published security count or estimated review effort. Finding severity, lifecycle, suppression, and approval behavior are unchanged. +Correct reviewer-guide security classification: + +- **Fixed:** command/shell, SQL/NoSQL, code, template, prompt, LDAP, XPath, CRLF/header, log, HTML/script, and expression injection require explicit vulnerability context; the standalone word `injection` is no longer promoted. +- **Changed:** neutral phrases such as knowledge or dependency injection no longer inflate the published security count or estimated review effort. +- **Unchanged:** finding severity, lifecycle, suppression, and approval behavior. diff --git a/changelog.d/155.bugfix.md b/changelog.d/155.bugfix.md index ac35602..0996ec7 100644 --- a/changelog.d/155.bugfix.md +++ b/changelog.d/155.bugfix.md @@ -1 +1,5 @@ -Remove provider-private reasoning, encrypted/native replay payloads, and request `tool_choice` fields before persisting the canonical OCR result or binding receipt v5. Private-only removal preserves a byte-equivalent review projection and approval eligibility, while attempts to launder the same fields through findings or warnings are publication-filtered. Public tool-call and reasoning-token counters remain unchanged. +Contain provider-private OCR state at the publication boundary: + +- **Fixed:** reasoning, encrypted/native replay payloads, and request `tool_choice` fields are removed before the canonical OCR result is persisted or receipt v5 is bound. +- **Changed:** private-only removal preserves a byte-equivalent review projection and approval eligibility; the same fields laundered through findings or warnings become `publication-filtered`. +- **Unchanged:** receipt v5, public tool-call and reasoning-token counters, DLP reason counts for private-only state, and approval rules. diff --git a/changelog.d/155.doc.md b/changelog.d/155.doc.md new file mode 100644 index 0000000..4977f54 --- /dev/null +++ b/changelog.d/155.doc.md @@ -0,0 +1,4 @@ +Refresh installation and operating guidance: + +- **Changed:** Python 3.12–3.14 uses `uv tool install` by default or `pip` only in an activated virtual environment; OCR is installed separately as checksum-verified 1.11.0 and verified with `ocr --version` plus `ocr-ci --help`. +- **Clarified:** max-tools runtime is unchanged despite corrected help text; reasoning and `tool_choice` stay private; reviewer-guide injection matching is contextual; Ruff formatting is applied and checked before each Python commit. diff --git a/changelog.d/155.maintenance.md b/changelog.d/155.maintenance.md index dd079b6..5e31960 100644 --- a/changelog.d/155.maintenance.md +++ b/changelog.d/155.maintenance.md @@ -1 +1,6 @@ -Qualify and pin Open Code Review 1.11.0 as the sole toolkit 0.8.6 runtime dependency. The promotion adds checksum-verified Linux and Darwin evidence, changes grouping inventory and timeout expectations, and preserves the result/manifest, completion-cap, medium-effort, max-tools, receipt v5, DLP, telemetry, summary, and approval contracts. OCR 1.10.2 remains comparison evidence only and is not a supported fallback. OCR 1.11.0's max-tools change corrects stale help text; the effective `0`/`50`/`100`/`101` behavior is unchanged. +Qualify the toolkit 0.8.6 OCR dependency: + +- **Changed:** Open Code Review 1.11.0 is the sole accepted runtime; grouping inventory is status-first with churn and the GitLab job timeout is 45 minutes for the default-medium/highest supported round envelope. +- **Added:** checksum-verified Linux and Darwin evidence plus strict 1.10.2-old/1.11.0-new comparison fixtures. +- **Migration:** deploy toolkit 0.8.6 directly with OCR 1.11.0. OCR 1.10.2 is comparison evidence only, not a supported fallback. +- **Unchanged:** result/manifest, inherited completion cap `16384`, explicit cap override `4096`, default effort `medium`, receipt v5, DLP, telemetry, summary, and approval contracts. OCR 1.11.0 corrects max-tools help text only: effective omitted/`0`/`49`/`50` remains `100`, while `101` raises the cap to `101`. diff --git a/changelog.d/155.rules.md b/changelog.d/155.rules.md index ba2fcb9..e7a9bd6 100644 --- a/changelog.d/155.rules.md +++ b/changelog.d/155.rules.md @@ -1 +1 @@ -Review Handlebars (`.hbs`) and Mustache (`.mustache`) files through OCR 1.11.0's built-in allowlist and language-specific Rules without widening toolkit evidence or publication authority. +**Added:** review Handlebars (`.hbs`) and Mustache (`.mustache`) files through OCR 1.11.0's built-in allowlist and language-specific Rules. Toolkit evidence and publication authority are unchanged. diff --git a/docs/development.md b/docs/development.md index 4b8902c..536fb69 100644 --- a/docs/development.md +++ b/docs/development.md @@ -4,6 +4,7 @@ Install [uv](https://docs.astral.sh/uv/) and use the committed lockfile: ```console uv sync --frozen +uv run ruff format . uv run ruff format --check . uv run ruff check . uv run mypy src/ocr_toolkit @@ -13,7 +14,7 @@ uv run python -m build uv run twine check dist/* ``` -For routine agent and contributor checks, run focused tests for each logical change and `scripts/quality.sh check` once on the completed handoff head. It replaces the selected mode's prior log, captures current output under ignored `.quality-logs/`, and prints only a short status; on failure it prints the last 80 lines. Individual modes are `format`, `lint`, `test`, `coverage`, `types`, and `security`. The `coverage` and `check` modes reuse that single branch-aware test run, then enforce scoped floors for result/preflight and GitLab posting transactions at 80%, plus review/context/DLP/approval and MCP/provider/policy/result contracts at 85%; a high combined result cannot hide a weak risk group. Hosted pull requests still run the complete suite on all five supported OS/Python combinations. The three Linux jobs are release-blocking, with Ubuntu on the newest supported Python as the sole coverage owner. The two macOS endpoint jobs are best-effort compatibility diagnostics: they continue to run and remain visible for follow-up, but a platform-only failure does not block a Linux-priority release. The Bandit gate scans only the supported runtime package at medium-or-higher severity and confidence; tests and synthetic fixtures are intentionally outside that bounded gate. +For routine agent and contributor checks, run focused tests for each logical change and `scripts/quality.sh check` once on the completed handoff head. After changing Python, run `scripts/quality.sh format` before self-review so Ruff's formatter is applied immediately; before every Python commit, require a clean repository-wide `uv run --frozen ruff format --check .` result. The full wrapper remains the final owner and repeats that check, so a formatting failure discovered only after push is a missed local commit gate rather than a missing quality control. It replaces the selected mode's prior log, captures current output under ignored `.quality-logs/`, and prints only a short status; on failure it prints the last 80 lines. Individual modes are `format`, `lint`, `test`, `coverage`, `types`, and `security`. The `coverage` and `check` modes reuse that single branch-aware test run, then enforce scoped floors for result/preflight and GitLab posting transactions at 80%, plus review/context/DLP/approval and MCP/provider/policy/result contracts at 85%; a high combined result cannot hide a weak risk group. Hosted pull requests still run the complete suite on all five supported OS/Python combinations. The three Linux jobs are release-blocking, with Ubuntu on the newest supported Python as the sole coverage owner. The two macOS endpoint jobs are best-effort compatibility diagnostics: they continue to run and remain visible for follow-up, but a platform-only failure does not block a Linux-priority release. The Bandit gate scans only the supported runtime package at medium-or-higher severity and confidence; tests and synthetic fixtures are intentionally outside that bounded gate. Runtime code must remain compatible with Python 3.12-3.14 and standard-library-only. Tests must use synthetic data; public examples must use safe placeholder hosts and credentials while describing the real operating behavior rather than labelling the feature itself as synthetic. User-visible changes require a fragment in `changelog.d/`. Repository-only qualification tools and evidence live under `scripts/` and `compatibility/`; they are excluded from both published distributions. Validate the manifest with `PYTHONPATH=src python scripts/ocr_compat.py validate`. diff --git a/docs/gitlab.md b/docs/gitlab.md index 106d48d..06036ad 100644 --- a/docs/gitlab.md +++ b/docs/gitlab.md @@ -22,7 +22,7 @@ The public pipeline stores the OCR binary checksum as the non-secret `OCR_SHA256 OCR 1.11.0 semantically groups related changed files before review and filters candidates per group. Its private grouping and other-files prompts use status-first `STATUS path (+N/-M)` entries; the toolkit does not parse that inventory in production. Grouping, filtering, and multiple rounds can increase provider requests, latency, and token cost, while the manifest and aggregate budget continue to report completeness. Grouping, grace-round, provider-native reasoning/thinking, and tool-choice request state are retained only inside OCR's isolated private session. Group labels, paths, reasoning, signed/encrypted native payloads, and request controls remain untrusted: the toolkit does not publish or use them for severity, fingerprints, lifecycle commands, receipts, DLP counts, telemetry, tool/token summaries, or approval. OCR's separately configured telemetry may export high-cardinality repository-derived values, so keep `OCR_TELEMETRY_ENABLED=false` unless the exporter and retention policy are approved. -The summary keeps four inputs separate: OCR manifest coverage, publication integrity, published findings, and an optional OCR core advisory. Complete manifest coverage that later loses public fields is labelled `Review complete with publication filtering`; it is warning-bearing and approval-ineligible, but it is not called incomplete OCR coverage and does not invent failed-file diagnostics. Actual partial, failed, waived, or budget-stopped manifest coverage keeps its stronger status. Ordinary OCR warnings retain their own complete-with-warnings state. The reviewer guide ranks bounded focus areas only when at least two findings are published; one finding remains in its inline or fallback discussion without a duplicate snippet. +The summary keeps four inputs separate: OCR manifest coverage, publication integrity, published findings, and an optional OCR core advisory. Complete manifest coverage that later loses public fields is labelled `Review complete with publication filtering`; it is warning-bearing and approval-ineligible, but it is not called incomplete OCR coverage and does not invent failed-file diagnostics. Actual partial, failed, waived, or budget-stopped manifest coverage keeps its stronger status. Ordinary OCR warnings retain their own complete-with-warnings state. The reviewer guide ranks bounded focus areas only when at least two findings are published; one finding remains in its inline or fallback discussion without a duplicate snippet. Security focus uses explicit published metadata, strong vulnerability terms, and closed injection classes rather than the standalone word `injection`, so neutral knowledge/dependency terminology cannot increase its count or effort estimate. The collapsed technical details keep aggregate input/output/cache token usage separate from OCR tool activity. The existing `all OCR tool calls` line lists every non-zero count for the closed review set (`file_read`, `file_read_diff`, `file_find`, `code_search`, `code_comment`, `task_done`, `ocr_toolkit_evidence`, `context_list`, and `context_get`) and is omitted when that admitted list is empty. These counts help explain whether OCR read context, searched the repository, checked cross-file diffs, consulted toolkit evidence, or emitted review output; they are not per-tool token attribution. Dynamic external MCP tool names remain private and appear only through the existing verified per-server aggregate. Tool and token lines remain independent of `passed`, `private-sanitized`, or `publication-filtered` receipt state. If OCR accepts a background above its recommended character count, a separate `OCR core advisory` line contains only the actual and recommended counts. It does not become a warning or change review completeness or approval eligibility. diff --git a/tests/test_operations_docs.py b/tests/test_operations_docs.py index 573abf3..9500dbf 100644 --- a/tests/test_operations_docs.py +++ b/tests/test_operations_docs.py @@ -1,5 +1,6 @@ """Contracts for the public GitLab operations documentation.""" +import json from pathlib import Path PROJECT_ROOT = Path(__file__).parents[1] @@ -39,6 +40,32 @@ def test_readme_and_gitlab_guide_link_to_operations() -> None: assert "## How reviews evolve" in readme +def test_readme_install_is_isolated_checksum_pinned_and_no_llm() -> None: + """Keep the root installation path exact without using preflight as a smoke test.""" + + readme = README.read_text(encoding="utf-8") + install = readme.split("## Install", 1)[1].split("## How reviews evolve", 1)[0] + manifest = json.loads( + (PROJECT_ROOT / "compatibility" / "ocr-support.json").read_text(encoding="utf-8") + ) + recommended = manifest["recommended_version"] + release = next(item for item in manifest["releases"] if item["version"] == recommended) + digests = {asset["name"]: asset["sha256"] for asset in release["assets"]} + + assert "Python 3.12 through 3.14" in install + assert "uv tool install open-code-review-toolkit" in install + assert install.index(". .venv/bin/activate") < install.index( + "python -m pip install open-code-review-toolkit" + ) + assert f"Open Code Review {recommended}" in install + assert f"open-code-review v{recommended}" in install + assert digests["opencodereview-linux-amd64"] in install + assert digests["opencodereview-darwin-arm64"] in install + assert "ocr --version" in install + assert "ocr-ci --help" in install + assert "not the installation\nsmoke test" in install + + def test_documentation_indexes_route_to_canonical_owners() -> None: docs_index = (PROJECT_ROOT / "docs" / "README.md").read_text(encoding="utf-8") codex_index = (PROJECT_ROOT / "docs" / "codex" / "README.md").read_text(encoding="utf-8") diff --git a/tests/test_quality_script.py b/tests/test_quality_script.py index d4a944e..1f708dc 100644 --- a/tests/test_quality_script.py +++ b/tests/test_quality_script.py @@ -72,6 +72,18 @@ def test_quality_script_runs_the_bounded_bandit_gate() -> None: assert "tests" not in command +def test_python_commit_gate_applies_and_then_checks_ruff_formatting() -> None: + """Keep immediate formatting and the repository-wide commit gate explicit.""" + + script = SCRIPT.read_text(encoding="utf-8") + development = (PROJECT_ROOT / "docs" / "development.md").read_text(encoding="utf-8") + + assert "set -- uv run --no-sync ruff format ." in script + assert 'for command in "ruff format --check ."' in script + assert "`scripts/quality.sh format` before self-review" in development + assert "`uv run --frozen ruff format --check .`" in development + + def test_quality_script_truncates_multi_command_log_per_invocation(tmp_path: Path) -> None: """Do not mix stale coverage output into a later multi-command result.""" From 79d558779c69ef2e2d16768bddc2e06190173854 Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 11:56:45 +0200 Subject: [PATCH 7/9] Record validated Draft handoff --- PLANS.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/PLANS.md b/PLANS.md index b377a00..269cd57 100644 --- a/PLANS.md +++ b/PLANS.md @@ -6,7 +6,7 @@ Use this file for active or blocked repository work. Update it before implementa ### Toolkit 0.8.6 - OCR 1.11.0 and precise security-signal classification -Status: active +Status: active — local implementation complete; final Draft push and hosted CI pending #### Goal @@ -157,7 +157,7 @@ state for this task: `release-deferred` after a green Draft handoff. | `WQ-05` | `done` | Provider-private reasoning/request fields are stripped before persistence and receipt binding; laundering through public sinks is filtered, explicit tool choice is preserved, and receipt/approval regressions pass. | | `WQ-06` | `done` | #153 now uses explicit metadata/strong terms plus a closed injection-class matcher over published findings; neutral domains do not inflate guide count or effort. | | `WQ-07` | `done` | README/public operations/install/formatting guidance and agent-readable categorized changelog are current; the Draft retains the external old/new grouping and provider-wire qualification table for final-head binding. | -| `WQ-08` | `pending` | Run holistic self-review and the one complete local final gate; update plan to truthful Draft handoff state. | +| `WQ-08` | `done` | Holistic requirement/privacy/architecture/data-flow review and the single complete local quality/coverage/security gate are green; stable delivery remains deferred. | | `WQ-09` | `pending` | Final push, hosted CI reconciliation, Draft/issue/milestone/remote/worktree readback. | #### Locked Decisions @@ -263,6 +263,13 @@ state for this task: `release-deferred` after a green Draft handoff. Ruff formatting before self-review and checks the entire repository before every Python commit. All 61 documentation/integration/quality/release-note tests, Ruff, the repository-wide format check, Towncrier draft, and `git diff --check` pass. +- 2026-08-28: holistic review confirms one provider-neutral private-result flow, no new + public/receipt/telemetry schema, no max-tools summary or configuration drift, and no + production compatibility fallback. The single final `scripts/quality.sh check` passes + 1,321 tests plus 363 subtests at 86.52% combined branch coverage; locked risk groups pass + at 85%, 82%, 86%, and 87%. Manifest validation, `uv lock --check`, rendered Towncrier, + repository-wide Ruff format, lint, MyPy, Bandit, checksum-verified temporary Gitleaks + 8.24.3, and `git diff --check` all pass. No LLM/provider call was performed. #### Risks And Recovery @@ -284,9 +291,10 @@ state for this task: `release-deferred` after a green Draft handoff. #### Resume Point -Commit the reviewed `WQ-04` OCR integration slice without pushing, then continue `WQ-05` -with the existing canonical projection/DLP/cleanup owners and focused provider-private -reasoning/tool-choice regressions. +Commit this local-complete handoff state, push the accumulated signed history once, wait for +all hosted Draft checks, and correct only evidence-backed failures through the same focused +self-review gate. Then bind the Draft body to the exact final head/tree, mark issue acceptance +criteria complete without closing #153/#155 or milestone v0.8.6, and stop with PR #154 Draft. #### Plan Fidelity Check @@ -304,15 +312,15 @@ reasoning/tool-choice regressions. - [x] Current main/tag/next version, worktree, plan, issues, PRs, milestones, workflow, local OCR, manifest, harness, README, backlog, and canonical docs were read. - [x] Hosted OCR 1.11.0 issue/evidence and semantic source audit agree. -- [ ] Backlog, roadmap, strategy, public docs, changelog, issues, milestone, and Draft agree. +- [x] Backlog, roadmap, strategy, public docs, changelog, issues, milestone, and Draft agree. - [ ] Final local/hosted validation, head/tree, threads, remote ref, and worktree agree. #### Closure Gate - [ ] All in-scope requirements and queue items are done or justified out of scope. -- [ ] Every logical commit passed focused tests, self-review, boundary review, and +- [x] Every completed logical commit passed focused tests, self-review, boundary review, and `git diff --check`. -- [ ] Final quality, coverage, manifest, lock, Towncrier, Gitleaks, and diff gates are green. +- [x] Final quality, coverage, manifest, lock, Towncrier, Gitleaks, and diff gates are green. - [ ] Hosted required Draft checks are green with no unresolved conversations. - [ ] Draft body, issues, milestone, remote ref, exact head/tree, and clean worktree agree. From d2249abaa1760a1ac15e7b0ab75414e7af5a37ea Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:13:35 +0200 Subject: [PATCH 8/9] Authorize full toolkit 0.8.6 release --- PLANS.md | 421 ++++++----------------- changelog.d/155.maintenance.md | 2 +- compatibility/ocr-support.json | 2 +- docs/engineering/test_evidence_matrix.md | 2 +- 4 files changed, 104 insertions(+), 323 deletions(-) diff --git a/PLANS.md b/PLANS.md index 269cd57..7643c1f 100644 --- a/PLANS.md +++ b/PLANS.md @@ -1,339 +1,120 @@ # Execution Plans -Use this file for active or blocked repository work. Update it before implementation and before handoff or commit. Completed stable plans are indexed in [the execution-history archive](docs/engineering/execution_history/README.md). +Use this file for active or blocked repository work. Update it before implementation and +before handoff or commit. Completed stable plans are indexed in +[the execution-history archive](docs/engineering/execution_history/README.md). ## Active Work -### Toolkit 0.8.6 - OCR 1.11.0 and precise security-signal classification +### Toolkit 0.8.6 — OCR 1.11.0 and precise security signals -Status: active — local implementation complete; final Draft push and hosted CI pending +Status: active — Draft implementation exists; independent review and full stable delivery +are in progress. -#### Goal - -Prepare a fully implemented, validated, and hosted-green Draft feature pull request for -toolkit 0.8.6. The Draft qualifies and exclusively targets OCR 1.11.0, preserves private -reasoning and provider request controls across the existing DLP/publication boundary, -fixes issue #153's false security promotion, and leaves merge and stable publication to a -later owner-authorized continuation. - -#### Plan Origin - -`plan_mode_approved` - -#### Requested Scope - -- Create `v0.8.6`, assign open issue #153 and the canonical OCR 1.11.0 compatibility issue - to `xeonvs`, and keep both issues plus the milestone open at handoff. -- Update the qualification harness before dispatch so exact OCR 1.10.2 comparison evidence - and exact OCR 1.11.0 candidate evidence use their own strict grouping inventory formats. -- Manually dispatch hosted compatibility qualification for exact `v1.11.0`, review its - machine evidence and upstream source semantics, and promote only confirmed contracts. -- Make OCR 1.11.0 the sole runtime/preflight target; retain 1.10.2 only as historical and - transition-comparison evidence, never as a supported fallback. -- Verify new grouping inventory, `file_find`, Handlebars/Mustache rules, timeout scaling, - private reasoning replay, `tool_choice`, completion-cap, effort, and max-tools behavior. -- Preserve one data flow from private OCR session/result through canonical projection, - DLP, publication, receipt, and approval; do not add a public reasoning schema. -- Fix #153 so neutral domain phrases do not promote reviewer-guide security counts while - closed, contextual injection classes and explicit security metadata continue to do so. -- Correct the root README installation path and current public documentation for exact - Python/OCR requirements, privacy boundaries, provider controls, and external validation. -- Atomically update the PATH-effective local Darwin arm64 OCR to exact 1.11.0 and perform - only checksum-verified no-LLM checks without changing configuration, credentials, or - the caller-owned home. -- Finish with one green Draft PR. Do not mark it ready, merge it, prepare a release branch, - tag, publish packages, close issues, or close the milestone. - -Release classification: `release-required`; target stable version: `0.8.6`; delivery -state for this task: `release-deferred` after a green Draft handoff. - -#### Requirement Traceability - -| Requirement | Outcome | Queue | Verification | -| --- | --- | --- | --- | -| `REQ-001` | Start from synchronized released v0.8.5, materialize this plan first, and open a Draft only after signed plan/harness commits. | `WQ-01`, `WQ-02` | Git status, plan fidelity, signed commits, remote/Draft readback | -| `REQ-002` | Strictly distinguish old 1.10.2 and new 1.11.0 grouping inventory in qualification without production backward compatibility. | `WQ-02` | Focused parser/gateway tests and exact workflow dispatch | -| `REQ-003` | Create and reconcile milestone v0.8.6, #153, and the canonical OCR 1.11.0 issue. | `WQ-03` | GitHub API readback | -| `REQ-004` | Qualify and exclusively adopt checksum-pinned OCR 1.11.0 with a complete semantic source audit. | `WQ-03`, `WQ-04` | Hosted evidence, hashes, manifest/preflight/example tests | -| `REQ-005` | Verify grouping, file lookup, rules, timeout, reasoning replay, tool choice, completion, effort, and max-tools contracts without public schema drift. | `WQ-04`, `WQ-05` | Controlled gateway and installed-artifact contract tests | -| `REQ-006` | Keep reasoning/session/provider request data private and preserve DLP, receipt v5, telemetry, summary, and approval boundaries. | `WQ-05` | Hostile projection, cleanup, receipt, approval, and leak regressions | -| `REQ-007` | Fix #153 using a closed contextual injection matcher that affects only reviewer-guide analytics. | `WQ-06` | Issue reproducer, positive/neutral/Unicode tests, input immutability | -| `REQ-008` | Update README, public docs, backlog reconciliation, and categorized release notes for humans and release agents. | `WQ-04`, `WQ-07` | Documentation contracts, Towncrier draft, link/version consistency | -| `REQ-009` | Replace local OCR safely and validate exact 1.11.0 without LLM or user-config changes. | `WQ-04` | Binary digest/version/help and isolated no-LLM previews | -| `REQ-010` | Complete one local final gate, push once, reconcile hosted CI and leave a clean green Draft with an exact external qualification checklist. | `WQ-08`, `WQ-09` | Quality/coverage/security gates, remote/PR/check/thread/worktree readback | +Release classification: `release-required` -#### Explicit Non-Goals +Target stable version: `0.8.6` -- No real LLM/provider call in this environment and no local model peer. -- No compatibility range, production parser fallback, migration layer, or support promise - for OCR 1.10.x or older; the 1.10.2 run is comparison evidence only. -- No new public result, receipt, telemetry, DLP-signal, or approval schema and no second - reasoning-specific DLP pipeline. -- No publication of prompts, reasoning, provider bodies, tool arguments/results, - credentials, model/provider identity, request IDs, paths, or session files. -- No dynamic timeout environment variable, second compatibility cron, polling service, - unpinned npm OCR recommendation, or global bare-pip installation guidance. -- No consumption of upstream GitHub Action, OpenCode plugin, npm launcher, Korean docs, - or provider preset changes. -- No mechanical test-directory reorganization or production refactor solely for coverage. -- No stable release, TestPyPI/PyPI publication, PR merge, issue closure, or milestone closure. - -#### Constraints - -- Runtime preflight accepts exact OCR 1.11.0 only. Version-aware old-format parsing is - confined to the repository qualification harness and cannot enter production runtime. -- Baseline 1.10.2 accepts only `path (STATUS, +N/-M)`; candidate 1.11.0 accepts only - `STATUS path (+N/-M)`. Mixed, duplicate, malformed, reordered, truncated, overflowed, - status-inconsistent, or churn-losing inventories fail closed. -- `reasoning_content`, Anthropic signed thinking, Responses encrypted reasoning, - `tool_choice`, and OCR session cache remain provider/session-private. They never affect - findings, severity, DLP counts, summary analytics, receipt, telemetry, or approval. -- Existing canonical-public DLP remains authoritative: private-only unknown fields may be - removed without blocking approval only when the canonical public projection is byte - equivalent; canonical/public filtering always blocks approval. -- OCR temporary HOME cleanup completes before publication. Cleanup failure, hostile - replay, impossible receipt state, or leaked reasoning fails closed. -- The #153 matcher consumes only the already DLP-checked published finding projection and - changes only reviewer-guide security count/effort, never finding or lifecycle state. -- Every new production and test function receives a purpose-focused docstring. -- Before every signed logical commit: focused tests, complete slice diff self-review, - requirement/trust/data-flow/privacy review, backlog reconciliation where applicable, - format changed Python with Ruff, run repository-wide `ruff format --check .`, and - `git diff --check`. The existing `scripts/quality.sh check` remains the single complete - final gate; do not add a duplicate formatting owner. -- After the initial plan/harness push, do not push partial implementation; perform one - final push only after all local slices and final gates are complete. - -#### Inputs And Sources - -- Owner-approved implementation plan in the preceding Plan Mode conversation. -- Released toolkit v0.8.5 at `72c511104f078110ea78bb8f1f2bb1d4048f4d20`, - `.next-version` `0.8.6`, open issue #153, and current repository contracts. -- Official OCR v1.11.0 release, adjacent 1.10.2 source comparison, release assets, - checksums, help output, and upstream feature/fix history. -- Exact release anchors: Linux amd64 - `13f68cc2eca1a36d42140e9d37797b68fea5cbbf4b6345ec01ec1b06910fab60`, Darwin arm64 - `ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78`, and - `sha256sum.txt` `9dff050ec859882bef26037415b8bd9e5db70c5a7d960e5eb3989385372311ee`. -- Current compatibility manifest/evidence/harness/workflow, runtime preflight/configuration, - review runner/result publication/DLP/receipt/approval, posting formatter, tests, README, - public docs, strategy, roadmap, and backlog. -- Workflow audit using engineering-workflow 0.8.2: mature repository, canonical owners - and required navigation indexes present; no instruction migration required. - -#### User Decisions And Answers - -- Target toolkit 0.8.6 and OCR 1.11.0 in one Draft-only delivery. -- Support only the current OCR release; comparison with 1.10.2 must not become backward - compatibility. -- Include exact old/new grouping checks and provider-wire checks in the Draft handoff for - another environment with configured OCR and LLM access. -- Treat reasoning and tool choice comprehensively, extend DLP edge coverage, and update - stale root README installation guidance. -- Update the local OCR binary, but skip local LLM calls in this environment. -- Use complete logical signed commits with self-review; leave the final PR in Draft. - -#### Completed Baseline State - -- `main` and `origin/main` are clean and synchronized at released v0.8.5 commit - `72c5111`; there are no open PRs and no v0.8.6 milestone. -- Issue #153 is the sole open issue and has no assignee or milestone. -- The manifest/preflight/example and PATH-effective local OCR target exact 1.10.2. -- Compatibility discovery runs once daily at `07:15 UTC` and retains exact manual - dispatch. No 1.11.0 issue has yet been created. -- The qualification stub parses only the old grouping inventory, so dispatching 1.11.0 - before the harness correction would produce false failure evidence. -- Root README recommends package installation without a Python range or isolated CLI - owner and refers only generically to a separately installed supported OCR. +#### Goal -#### Current Work Queue +Deliver toolkit 0.8.6 as an immutable stable release. The release must qualify and require +OCR 1.11.0, fix false security promotion for neutral domain phrases, keep provider-private +reasoning and request state outside every public/receipt/approval sink, pass local and hosted +validation, and finish with independently verified registry and GitHub artifacts, closed +release issues and milestone, and synchronized clean `main`. + +#### Scope And Decisions + +- Continue from Draft PR #154 and issues #153/#155; inspect the complete Draft rather than + assuming its existing green checks prove readiness. +- OCR 1.11.0 is the sole supported runtime. OCR 1.10.2 remains comparison evidence only. +- Preserve one provider-neutral flow: + `private OCR state -> canonical projection -> DLP -> publication -> receipt/approval`. +- Keep grouping inventory, timeout scaling, Handlebars/Mustache Rules, `file_find`, result, + manifest, receipt v5, DLP, telemetry, summary, and approval contracts internally + consistent and covered by synthetic tests. +- Fix #153 only in reviewer-guide analytics: neutral phrases such as knowledge or dependency + injection must not increase the security count or effort, while explicit metadata and a + closed set of vulnerability phrases remain promoted. +- Required configuration variables remain bold in public documentation. +- Do not set or recommend a provider-specific `4096` completion cap. The active default is + unset and inherits the qualified OCR/provider contract. Historical wire evidence may retain + its exact tested value when explicitly labelled as historical evidence. +- Update the PATH-effective local Darwin arm64 OCR atomically to checksum-verified 1.11.0. +- Run one semantic local OCR review against the exact final feature head with concurrency 1. + If it fails exclusively because every provider request is HTTP 429, record the gate as + owner-authorized `waived`, not passed, do not retry again, and continue release delivery. +- Keep full test and OCR output in ignored owner-only temporary logs. Public plans, issues, + PRs, changelog, release notes, and summaries contain only synthetic or bounded structural + evidence and never private paths, credentials, provider/model identity, prompts, reasoning, + tool payloads, request IDs, or raw OCR output. +- macOS hosted checks remain advisory; Linux supported-Python checks and protected release + authorization are the release priority. +- No B2B, `core/common`, shared-template, or consumer-repository integration is in scope. + +#### Requirements And Evidence + +| ID | Requirement | Authoritative evidence | +| --- | --- | --- | +| `R1` | Exact OCR 1.11.0 qualification and sole-runtime pin | Upstream release/source review, compatibility evidence/hash validation, preflight/example tests, local binary digest/version/help | +| `R2` | Correct grouping/rules/timeout/file lookup behavior | Qualification-only parser tests, installed-artifact no-LLM probes, runtime contract tests | +| `R3` | Provider-private fields cannot affect public state | Hostile projection, DLP, receipt, cleanup, telemetry, summary, and approval tests | +| `R4` | #153 false-positive classification fixed without broad regression | Exact reproducer plus positive, neutral, Unicode, boundary, determinism, and immutability tests | +| `R5` | Documentation/examples/changelog are current and consistent | Documentation contracts, version searches, Towncrier draft, complete diff review | +| `R6` | Feature tree is release-ready | Targeted tests, full quality/coverage, security, package determinism, local OCR, self-review, exact PR head/check/thread readback | +| `R7` | Stable release is authorized and published | Release plan/receipt, release PR exact-head checks, protected stable workflow success | +| `R8` | Publication is independently closed | Byte equality across workflow/TestPyPI/PyPI/Release, provenance and attestations, tag target, Python 3.12–3.14 installs, release-note/asset readback | +| `R9` | Repository and tracking state are closed | Actions-owned issue receipts, #153/#155 closed, milestone closed, archived plan, clean `main == origin/main == v0.8.6^{}` | + +#### Work Queue | Queue | Status | Deliverable | | --- | --- | --- | -| `WQ-01` | `done` | Full plan materialized first and passed the workflow fidelity/lifecycle check. | -| `WQ-02` | `done` | Strict grouping harness committed; the two signed initial commits were pushed and Draft PR #154 opened. | -| `WQ-03` | `done` | Milestone v0.8.6 and issue #155 are coordinated; hosted run 33158664020 produced accepted exact 1.11.0 evidence. | -| `WQ-04` | `done` | Exact 1.11.0 evidence/pins/preflight/example/docs/rules/timeouts/backlog and max-tools help/runtime distinction are integrated; local OCR is atomically updated and no-LLM qualified. | -| `WQ-05` | `done` | Provider-private reasoning/request fields are stripped before persistence and receipt binding; laundering through public sinks is filtered, explicit tool choice is preserved, and receipt/approval regressions pass. | -| `WQ-06` | `done` | #153 now uses explicit metadata/strong terms plus a closed injection-class matcher over published findings; neutral domains do not inflate guide count or effort. | -| `WQ-07` | `done` | README/public operations/install/formatting guidance and agent-readable categorized changelog are current; the Draft retains the external old/new grouping and provider-wire qualification table for final-head binding. | -| `WQ-08` | `done` | Holistic requirement/privacy/architecture/data-flow review and the single complete local quality/coverage/security gate are green; stable delivery remains deferred. | -| `WQ-09` | `pending` | Final push, hosted CI reconciliation, Draft/issue/milestone/remote/worktree readback. | - -#### Locked Decisions - -- Branch: `codex/v0.8.6-ocr-1.11.0-security-signal`; Draft base: protected `main`. -- Compatibility comparison is strict and version-bound: 1.10.2 old format versus 1.11.0 - new format. Runtime and public installation support only 1.11.0. -- GitLab example job timeout becomes 45 minutes. OCR base timeout remains inherited 15 - minutes, yielding low/medium/high effective limits of 15/30/45 minutes. -- Completion behavior remains inherited cap 16384 with the existing explicit toolkit - override example 4096. Default effort remains medium. OCR 1.11.0 only corrects stale - max-tools help text: runtime behavior is unchanged from the qualified 1.10.2 baseline, - where `0` selects template default `100`, `1-49` reports normalization to `50` but the - template remains effective, and only a value above `100` raises the effective cap. -- Provider flow: - `private session/result -> canonical projection -> DLP -> publication -> receipt/approval`. -- Reviewer-guide flow: - `DLP-checked published finding -> closed signal matcher -> guide count/effort only`. -- Changelog categories: OCR qualification/pins are Maintenance; Handlebars/Mustache are - Rules; #153 is Bug Fix; installation and public explanation are Documentation. -- BL-010, BL-017, and BL-021 remain open/conditional because 1.11.0 does not meet their - exit criteria; record reconciliation without inventing progress. - -#### Verification - -- Qualification inventory fixtures cover old/new valid forms; add/modify/delete/rename, - binary and zero-churn records; spaces, parentheses, backslashes, Unicode, duplicate and - reordered paths; mismatched status, mixed format, truncation, overflow, and malformed - prompt boundaries. -- Controlled gateway tests cover grouping stage order, medium rounds, cap 16384, explicit - 4096, absent versus explicit `tool_choice`, text-only comment retention, OpenAI Chat - reasoning replay, Anthropic signed thinking, Responses encrypted reasoning, ordering, - orphan/duplicate/malformed/cross-protocol payloads, and bounded session behavior. -- DLP tests cover secrets/tokens, PII, paths, URLs, request/model/provider identifiers, - Markdown/HTML, GitLab commands/mentions, Unicode normalization, bidi/format controls, - NUL/HTAB/VT/FF, oversized/nested laundering, canonical versus private-only projection, - hostile replay, receipt rejection, cleanup success/failure, and approval independence. -- #153 tests cover the exact reproducer, explicit metadata, closed injection classes, - neutral phrases, punctuation/Unicode/word boundaries, determinism, and input immutability. -- Exact 1.11.0 manifest/preflight/example/hash/default/README/documentation/backlog and - changelog contract tests; local version/help and no-LLM rules/background previews. -- Final local gate once: `scripts/quality.sh check`, coverage floors, - `scripts/ocr_compat.py validate`, lock check, Towncrier draft, `scripts/gitleaks.sh`, - and `git diff --check`. Hosted PR workflows own package, OS/Python, dependencies, - Security, and CodeQL gates. -- External configured-environment checklist compares checksum-verified 1.10.2 and 1.11.0 - on one private fixture, then qualifies exact Draft head with real 1.11.0 and a controlled - gateway. Only versions, hashes, structural assertions, and pass/fail may enter the PR. - -#### Latest Validation Results - -- 2026-08-28: `main`/`origin/main` clean at v0.8.5 `72c5111`; no open PR or v0.8.6 - milestone; issue #153 is the only open issue. -- 2026-08-28: engineering-workflow 0.8.2 audit found the mature canonical repository - owners and documentation indexes present. The audit traversed ignored quality artifacts - but identified no tracked workflow migration requirement. -- 2026-08-28: exact OCR 1.11.0 release hashes, public help defaults, source changes, local - 1.10.2 state, and the old-format-only grouping harness were read before this first write. -- 2026-08-28: this active plan passes the engineering-workflow lifecycle/fidelity check - and `git diff --check`; the planning slice has no product/runtime change. -- 2026-08-28: 86 compatibility tests pass, including 14 focused old/new grouping and - gateway tests; Ruff, MyPy, and `git diff --check` pass. Exact local OCR 1.10.2 also - passes the strict old-format semantic grouping probe through the loopback-only gateway. -- 2026-08-28: signed planning and grouping-harness commits were pushed once; Draft PR - #154, milestone v0.8.6, assigned issues #153/#155, and exact-tag compatibility run - 33158664020 are open. The hosted artifact verified all release hashes and candidate - contracts and requires the planned human semantic conclusion, which has been recorded. -- 2026-08-28: initial Draft CI quality failed only because two newly committed Python files - were not Ruff-formatted. The canonical local `scripts/quality.sh check` already owns - `ruff format --check .`; the process correction is to format and run that lightweight - check before each Python commit. The macOS 3.14 diagnostic independently failed while - fetching `hatch-vcs` from PyPI after three network retries, not on repository behavior. -- 2026-08-28: upstream release/source and both 1.10.2/1.11.0 hosted artifacts confirm the - max-tools runtime contract is identical (`0 -> 100`, `49 -> reported 50/effective 100`, - `50 -> effective 100`, `101 -> effective 101`). OCR 1.11.0 changes help/docs only. -- 2026-08-28: the checksum-verified Darwin arm64 candidate and atomically installed - `/opt/homebrew/bin/ocr` both report 1.11.0 and pass isolated version/help, - Handlebars/Mustache system-rule readback, accepted 2,001-character soft background, - rejected 8,001-character hard background, and no-session preview checks. The previous - exact 1.10.2 digest was verified before replacement; no LLM, user HOME, configuration, - or credentials were used. -- 2026-08-28: the integrated OCR slice passes 229 focused tests plus 104 subtests, - manifest validation, Ruff lint and repository-wide format check, and `git diff --check`. -- 2026-08-28: provider-private reasoning, encrypted/native replay payloads, and request - `tool_choice` fields are removed from the persisted result without changing a - byte-equivalent canonical review projection or blocking approval. The same keys in a - public finding or warning fail closed as `publication-filtered`; receipt v5 rejects - private replay/request fields, while actual tool-call and reasoning-token counters remain - available. The focused boundary suite passes 253 tests plus 186 subtests, Ruff, MyPy, - repository-wide format check, and `git diff --check`. -- 2026-08-28: #153's exact three-finding reproducer now yields one security-sensitive - finding and effort `2/5`. Explicit security metadata and command/shell, SQL/NoSQL, - code, template, prompt, LDAP, XPath, CRLF/header, log, HTML/script, and expression - injection remain promoted across bounded separator/case variants; knowledge, dependency, - and other non-closed phrases remain ordinary. All 200 posting-helper tests plus 161 - subtests pass with deterministic ordering and no input mutation; Ruff, MyPy, - repository-wide format check, and `git diff --check` pass. -- 2026-08-28: root installation now requires Python 3.12–3.14, recommends isolated - `uv tool install`, bounds `pip` to an activated virtualenv, and names exact - checksum-verified OCR 1.11.0 plus no-LLM version/help smoke checks. Public docs clarify - max-tools, private reasoning/tool choice, and contextual security signals; required - environment-variable names remain bold. The canonical development workflow now applies - Ruff formatting before self-review and checks the entire repository before every Python - commit. All 61 documentation/integration/quality/release-note tests, Ruff, the - repository-wide format check, Towncrier draft, and `git diff --check` pass. -- 2026-08-28: holistic review confirms one provider-neutral private-result flow, no new - public/receipt/telemetry schema, no max-tools summary or configuration drift, and no - production compatibility fallback. The single final `scripts/quality.sh check` passes - 1,321 tests plus 363 subtests at 86.52% combined branch coverage; locked risk groups pass - at 85%, 82%, 86%, and 87%. Manifest validation, `uv lock --check`, rendered Towncrier, - repository-wide Ruff format, lint, MyPy, Bandit, checksum-verified temporary Gitleaks - 8.24.3, and `git diff --check` all pass. No LLM/provider call was performed. +| `WQ-01` | `done` | Live `main`, Draft PR, issues, milestone, upstream release, roadmap/backlog, and release owners inspected. | +| `WQ-02` | `in progress` | Audit Draft #154 implementation and documentation; correct plan drift and any demonstrated defects. | +| `WQ-03` | `pending` | Install and qualify local OCR 1.11.0; run the single semantic review at concurrency 1 and classify the result honestly. | +| `WQ-04` | `pending` | Remediate findings, run targeted/full gates, perform complete self-review, and bind the final feature head. | +| `WQ-05` | `pending` | Mark feature PR ready, verify protected checks/threads/policy, merge, and verify development publication. | +| `WQ-06` | `pending` | Prepare signed `release/v0.8.6` state, generated changelog, archived plan, receipt inputs, and release PR. | +| `WQ-07` | `pending` | Verify release PR, merge exact reviewed tree, and complete the protected stable workflow. | +| `WQ-08` | `pending` | Independently verify registries, bytes, provenance, attestations, tag, immutable Release, receipt, and supported-Python installs. | +| `WQ-09` | `pending` | Verify issue receipts, close issues/milestone, synchronize clean `main`, remove task-owned temporary material, and perform final audit. | + +#### Validation Contract + +- During iteration: focused tests for every changed parser, subprocess, persistence, DLP, + posting, receipt, configuration, compatibility, and documentation boundary. +- Final feature gate: `scripts/quality.sh check`, all coverage floors, compatibility manifest, + lockfile, Towncrier draft, Ruff format/lint, strict MyPy, Bandit, checksum-verified + Gitleaks, package build/determinism, and `git diff --check`. +- OCR gate: exact installed 1.11.0 identity and one semantic review at concurrency 1; inspect + the result/manifest and coverage rather than process exit alone. A pure repeated HTTP 429 is + a documented waiver, never a pass. +- PR gates: exact head/base/tree, all required checks complete, no unresolved review threads, + current merge policy, and re-read immediately before merge. +- Stable closure: independent artifact bytes, TestPyPI/PyPI metadata and PEP 740 provenance, + GitHub attestations and immutable Release, annotated tag peeled target, receipt schema and + hashes, clean wheel/sdist installs on Python 3.12–3.14, issue/milestone receipts, and clean + synchronized `main`. #### Risks And Recovery -- GitHub schedule omitted the same-day release. Manual exact-tag dispatch after the harness - fix is the recovery; do not add schedule frequency or duplicate runs. -- Hosted qualification can fail or create a machine issue without usable evidence. Keep the - issue/run open, inspect bounded artifacts, correct only demonstrated harness/product faults, - and never promote an unqualified release. -- An automatic compatibility PR may appear. Compare it against reviewed evidence, integrate - only required bytes into this Draft, and close/supersede it truthfully without merging it. -- Local binary replacement can fail. Retain the verified 1.10.2 binary until 1.11.0 passes - checksum/version/help/no-LLM checks and atomically restore it on mismatch. -- Provider reasoning or request controls could escape through an unowned field. Keep one - canonical projection/DLP owner, fail closed at public/receipt boundaries, and test all sinks. -- Strict grouping parsing could accidentally imply old runtime support. Keep baseline parsing - in qualification-only code and assert exact runtime rejection of 1.10.x. -- Hosted CI may expose a real defect. Fix only evidence-backed boundaries in a separately - self-reviewed signed commit, then rerun the affected and final gates before pushing. - -#### Resume Point - -Commit this local-complete handoff state, push the accumulated signed history once, wait for -all hosted Draft checks, and correct only evidence-backed failures through the same focused -self-review gate. Then bind the Draft body to the exact final head/tree, mark issue acceptance -criteria complete without closing #153/#155 or milestone v0.8.6, and stop with PR #154 Draft. - -#### Plan Fidelity Check - -- [x] Every approved outcome has a stable requirement and queue owner. -- [x] Release-required classification, target 0.8.6, Draft-only deferred delivery, and - explicit non-publication boundary are recorded. -- [x] Exact versions/hashes, old/new qualification distinction, runtime compatibility - decision, data flows, DLP/reasoning/tool-choice rules, issue fix, local binary, docs, - validation, recovery, and external handoff are preserved. -- [x] Initial/final push behavior, signed commit gates, and hosted ownership are explicit. -- [x] Resume point names the first safe unfinished action. - -#### Reconciliation Check - -- [x] Current main/tag/next version, worktree, plan, issues, PRs, milestones, workflow, - local OCR, manifest, harness, README, backlog, and canonical docs were read. -- [x] Hosted OCR 1.11.0 issue/evidence and semantic source audit agree. -- [x] Backlog, roadmap, strategy, public docs, changelog, issues, milestone, and Draft agree. -- [ ] Final local/hosted validation, head/tree, threads, remote ref, and worktree agree. +- A Draft-green check can miss semantic or privacy defects. Fix only evidence-backed findings, + repeat the affected gate, and then rerun the single complete final gate. +- Local OCR replacement can fail. Verify the candidate before atomic replacement and retain a + verified rollback copy until 1.11.0 passes local identity and no-LLM probes. +- Provider rate limiting can make semantic OCR unavailable. After the single concurrency-1 run, + accept only an all-429 outcome for the authorized waiver; mixed or product failures require + diagnosis and remediation. +- Registry propagation can lag. Verify JSON/simple-index state and retry once without cache; + do not misclassify cache lag as an artifact defect. +- Stable release publication is irreversible. Re-read exact release head, authorization, + checks, and receipt inputs immediately before merge; stop on any mismatch. #### Closure Gate -- [ ] All in-scope requirements and queue items are done or justified out of scope. -- [x] Every completed logical commit passed focused tests, self-review, boundary review, and - `git diff --check`. -- [x] Final quality, coverage, manifest, lock, Towncrier, Gitleaks, and diff gates are green. -- [ ] Hosted required Draft checks are green with no unresolved conversations. -- [ ] Draft body, issues, milestone, remote ref, exact head/tree, and clean worktree agree. - -#### Post-Close Delivery - -- This task deliberately stops at a green Draft PR. Merge, protected-main development - publication, `release/v0.8.6`, stable publication, external artifact reconciliation, - issue closure, and milestone closure require a later explicit owner continuation. - -#### Handoff Notes - -- Draft body must retain Added/Fixed/Changed/Unchanged sections, exact toolkit head/tree, - OCR hashes and hosted evidence, strict old/new grouping comparison, local no-LLM checks, - backlog disposition, and a safe external configured-environment qualification table. -- The external agent starts from exact Draft head and OCR 1.11.0. It may run 1.10.2 only - as an isolated comparison and must not interpret that run as toolkit compatibility. +- [ ] Every requirement has direct current-state evidence. +- [ ] Feature and release PRs are merged from exact reviewed heads with required checks green. +- [ ] Stable 0.8.6 artifacts, provenance, attestations, tag, Release, receipt, and installs are independently verified. +- [ ] Issues #153/#155 and milestone v0.8.6 are closed through truthful release evidence. +- [ ] The active plan is archived, local and remote release branches are removed, task-owned temporary material is cleaned, and `main` is clean and synchronized. diff --git a/changelog.d/155.maintenance.md b/changelog.d/155.maintenance.md index 5e31960..db8ff92 100644 --- a/changelog.d/155.maintenance.md +++ b/changelog.d/155.maintenance.md @@ -3,4 +3,4 @@ Qualify the toolkit 0.8.6 OCR dependency: - **Changed:** Open Code Review 1.11.0 is the sole accepted runtime; grouping inventory is status-first with churn and the GitLab job timeout is 45 minutes for the default-medium/highest supported round envelope. - **Added:** checksum-verified Linux and Darwin evidence plus strict 1.10.2-old/1.11.0-new comparison fixtures. - **Migration:** deploy toolkit 0.8.6 directly with OCR 1.11.0. OCR 1.10.2 is comparison evidence only, not a supported fallback. -- **Unchanged:** result/manifest, inherited completion cap `16384`, explicit cap override `4096`, default effort `medium`, receipt v5, DLP, telemetry, summary, and approval contracts. OCR 1.11.0 corrects max-tools help text only: effective omitted/`0`/`49`/`50` remains `100`, while `101` raises the cap to `101`. +- **Unchanged:** result/manifest, inherited completion cap `16384`, support for an operator-selected positive completion-cap override, default effort `medium`, receipt v5, DLP, telemetry, summary, and approval contracts. The toolkit leaves that override unset by default and does not recommend a provider-specific value. OCR 1.11.0 corrects max-tools help text only: effective omitted/`0`/`49`/`50` remains `100`, while `101` raises the cap to `101`. diff --git a/compatibility/ocr-support.json b/compatibility/ocr-support.json index d5873f2..e3ce86c 100644 --- a/compatibility/ocr-support.json +++ b/compatibility/ocr-support.json @@ -1341,7 +1341,7 @@ ], "evidence": "compatibility/evidence/ocr-1.11.0.json", "evidence_sha256": "97c56e301aab5298d5b8d2182afdda33d6cb704abf7bf476f04c668b95b61f22", - "human_conclusion": "Compatible after hosted checksum-verified Linux qualification in run 33158664020 and direct adjacent source review in issue #155. OCR 1.11.0 changes grouping and other-file inventory to status-first entries with churn, preserves provider-native reasoning across assistant turns, removes the filter's forced tool choice, scales subtask timeout by review rounds, improves file_find subpaths, and adds Handlebars/Mustache rules. The toolkit qualification harness consumes the inventory shape and runtime-facing boundaries while provider reasoning and native payloads remain private and unconsumed. Result/manifest schemas, inherited 16384 and explicit 4096 completion caps, medium effort, max-tools, receipt v5, DLP, telemetry, and approval contracts remain unchanged. Upstream action, plugin, launcher, locale, provider preset, and config-command validation changes are not consumed.", + "human_conclusion": "Compatible after hosted checksum-verified Linux qualification in run 33158664020 and direct adjacent source review in issue #155. OCR 1.11.0 changes grouping and other-file inventory to status-first entries with churn, preserves provider-native reasoning across assistant turns, removes the filter's forced tool choice, scales subtask timeout by review rounds, improves file_find subpaths, and adds Handlebars/Mustache rules. The toolkit qualification harness consumes the inventory shape and runtime-facing boundaries while provider reasoning and native payloads remain private and unconsumed. Result/manifest schemas, inherited 16384 completion cap, operator-selected positive override support, medium effort, max-tools, receipt v5, DLP, telemetry, and approval contracts remain unchanged; the toolkit leaves the override unset and recommends no provider-specific value. Upstream action, plugin, launcher, locale, provider preset, and config-command validation changes are not consumed.", "published_at": "2026-08-28T06:06:56Z", "release_url": "https://github.com/alibaba/open-code-review/releases/tag/v1.11.0", "status": "tested", diff --git a/docs/engineering/test_evidence_matrix.md b/docs/engineering/test_evidence_matrix.md index 23fad17..98491cb 100644 --- a/docs/engineering/test_evidence_matrix.md +++ b/docs/engineering/test_evidence_matrix.md @@ -127,7 +127,7 @@ The M5 negative suite is an attacker matrix, not merely a replay of observed rev | Requirement or boundary | Production owner and entry point | Required observable result | Evidence | Double boundary and claim limit | State | | --- | --- | --- | --- | --- | --- | -| Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, explicit `4096`, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict 1.10.2/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay | proven for exact qualified OCR contract | +| Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, an explicitly tested positive override, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict 1.10.2/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay; the tested override is evidence, not a toolkit default or recommendation | proven for exact qualified OCR contract | | Max-tools help correction does not imply runtime drift | exact numeric CLI and effective loop probes -> public operator docs | omitted/`0` remain effective `100`; `49` reports `50` but stays effective `100`; `50` stays effective `100`; `101` becomes effective `101` | identical hosted 1.10.2 and 1.11.0 evidence plus upstream #1077 source/release audit | behavioral probes prove current embedded-template ownership; they do not promise future OCR defaults | proven unchanged | | Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | toolkit containment proven; provider replay pending external qualification | | New selection behavior stays at the OCR edge | exact no-LLM preview/rule resolver -> built-in OCR Rules | repository-relative/backslash `file_find` fallback and `.hbs`/`.mustache` rule selection work without changing toolkit evidence authority | adjacent source audit plus isolated checksum-verified Darwin version/help, rule readback, and soft/hard background previews | selection proves routing, not review finding quality or evidence-pack completion | proven | From 2a96f02b58eb54fc3e71ff1e9cec7343f4a20076 Mon Sep 17 00:00:00 2001 From: xeonvs <11463419+xeonvs@users.noreply.github.com> Date: Fri, 28 Aug 2026 12:32:51 +0200 Subject: [PATCH 9/9] Close OCR 1.11 qualification findings --- PLANS.md | 42 +++++++++++++++++++++--- changelog.d/155.maintenance.md | 2 +- docs/compatibility.md | 4 +-- docs/engineering/test_evidence_matrix.md | 2 +- scripts/ocr_compat.py | 2 +- tests/test_ocr_compat.py | 23 +++++++------ tests/test_operations_docs.py | 5 +++ 7 files changed, 61 insertions(+), 19 deletions(-) diff --git a/PLANS.md b/PLANS.md index 7643c1f..ff22863 100644 --- a/PLANS.md +++ b/PLANS.md @@ -71,10 +71,10 @@ release issues and milestone, and synchronized clean `main`. | Queue | Status | Deliverable | | --- | --- | --- | | `WQ-01` | `done` | Live `main`, Draft PR, issues, milestone, upstream release, roadmap/backlog, and release owners inspected. | -| `WQ-02` | `in progress` | Audit Draft #154 implementation and documentation; correct plan drift and any demonstrated defects. | -| `WQ-03` | `pending` | Install and qualify local OCR 1.11.0; run the single semantic review at concurrency 1 and classify the result honestly. | -| `WQ-04` | `pending` | Remediate findings, run targeted/full gates, perform complete self-review, and bind the final feature head. | -| `WQ-05` | `pending` | Mark feature PR ready, verify protected checks/threads/policy, merge, and verify development publication. | +| `WQ-02` | `done` | Draft #154 implementation and documentation audited; release plan and completion-cap wording corrected. | +| `WQ-03` | `done` | Exact local OCR 1.11.0 installed and qualified; the single concurrency-1 semantic review completed 7/7 selected files. | +| `WQ-04` | `done` | The one confirmed OCR finding is fixed; full gates and holistic self-review pass, and the signed final feature-head commit is ready to bind. | +| `WQ-05` | `in progress` | Push the final feature head, update and mark PR ready, verify protected checks/threads/policy, merge, and verify development publication. | | `WQ-06` | `pending` | Prepare signed `release/v0.8.6` state, generated changelog, archived plan, receipt inputs, and release PR. | | `WQ-07` | `pending` | Verify release PR, merge exact reviewed tree, and complete the protected stable workflow. | | `WQ-08` | `pending` | Independently verify registries, bytes, provenance, attestations, tag, immutable Release, receipt, and supported-Python installs. | @@ -111,6 +111,40 @@ release issues and milestone, and synchronized clean `main`. - Stable release publication is irreversible. Re-read exact release head, authorization, checks, and receipt inputs immediately before merge; stop on any mismatch. +#### Current Evidence + +- Draft PR #154 starts from released v0.8.5 and had 13/13 hosted checks green at head + `79d5587`; issues #153/#155 and milestone v0.8.6 are open. +- Hosted OCR compatibility run 33158664020 verified the official 1.11.0 assets and generated + the accepted human-review-required evidence. Adjacent source review maps each consumed + contract or records it as no-impact. +- PATH-effective OCR is official Darwin arm64 1.11.0 with SHA-256 + `ac8bf5a0fcd176bb9dcc15b169e90f4b52bf32787adef17a850489dbed97fb78`. + The installed `probe-local` contract passed version/help, preview, grouping, Rules, result, + budget, numeric CLI, and completion-cap checks. +- The only configured-provider OCR review ran at concurrency 1 on exact head `d2249ab` and + finished in 396 seconds with manifest `complete`: 7 selected, 7 completed, 0 failed, + 0 reused, and 0 waived. It returned one medium bug finding; this is a passing semantic + gate, so no provider waiver applies. +- The finding correctly identified that the qualification-only grouping parser accepted the + historical wire shape only for 1.10.2 even though repeatable semantic probes cover the full + qualified 1.10.0–1.10.2 line. The parser now binds that exact old shape to all 1.10.x + releases while production preflight remains exact 1.11.0. All 86 compatibility tests pass. +- Targeted privacy/posting/configuration/release suites pass 480 tests plus 243 subtests; + manifest validation, Towncrier draft, Ruff format check, and diff checks pass. +- The final canonical gate passes 1,321 tests plus 363 subtests at 86.52% branch + coverage. The four locked risk groups pass at 85%, 82%, 86%, and 87%; Ruff format/lint, + strict MyPy, and Bandit pass in the same run. +- Independent lock and OCR-manifest validation, rendered 0.8.6 Towncrier draft, + dependency audit, pinned Gitleaks, and `git diff --check` pass. Two deterministic + wheel/sdist builds are byte-identical; Twine and archive content/privacy checks pass, + and clean wheel plus sdist installs and CLI smoke pass on Python 3.12, 3.13, and 3.14. +- Holistic feature-diff self-review found and fixed one documentation drift: the current + compatibility guide now describes only an operator-selected positive completion-cap + override and the full qualification-only historical 1.10.x inventory parser range. + Machine qualification evidence retains its exact checksum-bound tested probe. No other + correctness, privacy, release, documentation, or example inconsistency remains. + #### Closure Gate - [ ] Every requirement has direct current-state evidence. diff --git a/changelog.d/155.maintenance.md b/changelog.d/155.maintenance.md index db8ff92..62976cf 100644 --- a/changelog.d/155.maintenance.md +++ b/changelog.d/155.maintenance.md @@ -1,6 +1,6 @@ Qualify the toolkit 0.8.6 OCR dependency: - **Changed:** Open Code Review 1.11.0 is the sole accepted runtime; grouping inventory is status-first with churn and the GitLab job timeout is 45 minutes for the default-medium/highest supported round envelope. -- **Added:** checksum-verified Linux and Darwin evidence plus strict 1.10.2-old/1.11.0-new comparison fixtures. +- **Added:** checksum-verified Linux and Darwin evidence plus strict historical-1.10.x-old/1.11.0-new qualification fixtures. - **Migration:** deploy toolkit 0.8.6 directly with OCR 1.11.0. OCR 1.10.2 is comparison evidence only, not a supported fallback. - **Unchanged:** result/manifest, inherited completion cap `16384`, support for an operator-selected positive completion-cap override, default effort `medium`, receipt v5, DLP, telemetry, summary, and approval contracts. The toolkit leaves that override unset by default and does not recommend a provider-specific value. OCR 1.11.0 corrects max-tools help text only: effective omitted/`0`/`49`/`50` remains `100`, while `101` raises the cap to `101`. diff --git a/docs/compatibility.md b/docs/compatibility.md index ece4732..6c135ab 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -75,9 +75,9 @@ Deploy toolkit 0.8.5 directly with OCR 1.10.2. The public Linux amd64 example ve ### OCR 1.11.0 — toolkit 0.8.6 target -OCR 1.11.0 is the only runtime version accepted by toolkit 0.8.6 preflight and pinned by its GitLab example. OCR 1.10.2 remains a strict comparison baseline for the grouping-inventory transition and is not a supported fallback. Hosted run `33158664020`, canonical issue #155, adjacent source review, and checksum-verified evidence preserve the OCR result, `ocr.run-manifest/v1`, inherited OpenAI completion cap `16384`, explicit toolkit override `4096`, default-medium two-round review, receipt v5, DLP, toolkit telemetry, summary, and approval contracts. +OCR 1.11.0 is the only runtime version accepted by toolkit 0.8.6 preflight and pinned by its GitLab example. OCR 1.10.2 remains a strict comparison baseline for the grouping-inventory transition and is not a supported fallback. Hosted run `33158664020`, canonical issue #155, adjacent source review, and checksum-verified evidence preserve the OCR result, `ocr.run-manifest/v1`, inherited OpenAI completion cap `16384`, support for an operator-selected positive completion-cap override, default-medium two-round review, receipt v5, DLP, toolkit telemetry, summary, and approval contracts. The toolkit leaves that override unset and does not recommend a provider-specific value. -The private grouping and other-files prompts now use status-first `STATUS path (+N/-M)` inventory entries. Qualification accepts the old `path (STATUS, +N/-M)` shape only from exact comparison OCR 1.10.2 and the new shape only from exact candidate OCR 1.11.0; mixed, duplicate, reordered, malformed, status-inconsistent, truncated, or churn-losing evidence fails closed. Production toolkit code consumes neither format. `file_find` now supports repository-relative subpaths and both slash styles. The built-in allowlist and Rules add Handlebars (`.hbs`) and Mustache (`.mustache`). OCR's base subtask timeout is now 15 minutes and scales linearly with low/medium/high review rounds to 15/30/45 minutes, so the GitLab job allows 45 minutes. +The private grouping and other-files prompts now use status-first `STATUS path (+N/-M)` inventory entries. Repeatable qualification accepts the old `path (STATUS, +N/-M)` shape only for historical OCR 1.10.0 through 1.10.2 and the new shape from OCR 1.11.0 onward; the 1.11.0 promotion compares the adjacent 1.10.2 and 1.11.0 evidence. Mixed, duplicate, reordered, malformed, status-inconsistent, truncated, or churn-losing evidence fails closed. Production toolkit code consumes neither format. `file_find` now supports repository-relative subpaths and both slash styles. The built-in allowlist and Rules add Handlebars (`.hbs`) and Mustache (`.mustache`). OCR's base subtask timeout is now 15 minutes and scales linearly with low/medium/high review rounds to 15/30/45 minutes, so the GitLab job allows 45 minutes. OCR 1.11.0 preserves provider-native reasoning across assistant turns, removes the filter's forced `tool_choice`, and retains readable reasoning plus signed or encrypted native replay payloads inside the OCR session. The toolkit does not consume that state: its isolated session home is removed before publication, and reasoning, native payloads, and request controls cannot enter findings, GitLab notes, receipt v5, DLP counters, toolkit telemetry, tool/token summary, or approval inputs. Explicit operator-owned `OCR_LLM_EXTRA_BODY.tool_choice` remains distinct from OCR's removed forced filter value and is not published. diff --git a/docs/engineering/test_evidence_matrix.md b/docs/engineering/test_evidence_matrix.md index 98491cb..4219494 100644 --- a/docs/engineering/test_evidence_matrix.md +++ b/docs/engineering/test_evidence_matrix.md @@ -127,7 +127,7 @@ The M5 negative suite is an attacker matrix, not merely a replay of observed rev | Requirement or boundary | Production owner and entry point | Required observable result | Evidence | Double boundary and claim limit | State | | --- | --- | --- | --- | --- | --- | -| Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, an explicitly tested positive override, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict 1.10.2/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay; the tested override is evidence, not a toolkit default or recommendation | proven for exact qualified OCR contract | +| Exact OCR 1.11.0 review contract | compatibility gateway -> hosted Linux binary -> human-reviewed manifest/evidence promotion | status-first grouping inventory preserves status/churn; result/manifest, inherited `16384`, an explicitly tested positive override, medium rounds, and effective max-tools remain compatible | hosted run 33158664020; checksum-pinned `compatibility/evidence/ocr-1.11.0.json`; strict historical-1.10/1.11.0 inventory fixtures; adjacent source audit | deterministic gateways prove structural wire/result/loop contracts, not provider quality or production reasoning replay; the tested override is evidence, not a toolkit default or recommendation | proven for exact qualified OCR contract | | Max-tools help correction does not imply runtime drift | exact numeric CLI and effective loop probes -> public operator docs | omitted/`0` remain effective `100`; `49` reports `50` but stays effective `100`; `50` stays effective `100`; `101` becomes effective `101` | identical hosted 1.10.2 and 1.11.0 evidence plus upstream #1077 source/release audit | behavioral probes prove current embedded-template ownership; they do not promise future OCR defaults | proven unchanged | | Private reasoning and request controls do not widen toolkit schemas | OCR isolated session -> canonical result projection -> DLP/publication/receipt/approval | provider-native reasoning and `tool_choice` remain absent from every toolkit public or authority-bearing sink; cleanup precedes publication | upstream adapter/session audit, result-contract probe, toolkit hostile projection/cleanup regressions, and external configured-environment checklist | local tests prove toolkit containment, while real provider replay remains an external qualification item | toolkit containment proven; provider replay pending external qualification | | New selection behavior stays at the OCR edge | exact no-LLM preview/rule resolver -> built-in OCR Rules | repository-relative/backslash `file_find` fallback and `.hbs`/`.mustache` rule selection work without changing toolkit evidence authority | adjacent source audit plus isolated checksum-verified Darwin version/help, rule readback, and soft/hard background previews | selection proves routing, not review finding quality or evidence-pack completion | proven | diff --git a/scripts/ocr_compat.py b/scripts/ocr_compat.py index 20bc3dd..ac819da 100644 --- a/scripts/ocr_compat.py +++ b/scripts/ocr_compat.py @@ -1005,7 +1005,7 @@ def parse_grouping_inventory(messages: list[Any], version: str) -> list[Grouping """Parse the exact grouping prompt shape qualified for one OCR release line.""" parsed_version = _version(version) - if parsed_version == (1, 10, 2): + if (1, 10, 0) <= parsed_version < (1, 11, 0): pattern = re.compile( r"(?P[^\r\n]{1,1000}) " r"\((?PADDED|MODIFIED|DELETED|RENAMED), " diff --git a/tests/test_ocr_compat.py b/tests/test_ocr_compat.py index bc70d6d..b704504 100644 --- a/tests/test_ocr_compat.py +++ b/tests/test_ocr_compat.py @@ -1080,7 +1080,7 @@ def test_compatibility_gateway_rejects_malformed_messages_over_real_http() -> No def test_grouping_inventory_strictly_parses_old_and_new_release_shapes() -> None: - """Comparison evidence pins 1.10.2 and 1.11.0 to different exact wire shapes.""" + """Qualification pins the 1.10 line and 1.11.0 to different exact wire shapes.""" module = load_script() @@ -1099,14 +1099,15 @@ def messages(inventory: str) -> list[dict[str, str]]: } ] - old = module.parse_grouping_inventory( - messages( - "src/space (unicode) λ.py (ADDED, +10/-0)\n" - "win\\deleted.hbs (DELETED, +0/-5)\n" - "renamed.mustache (RENAMED, +0/-0)" - ), - "1.10.2", + old_inventory = messages( + "src/space (unicode) λ.py (ADDED, +10/-0)\n" + "win\\deleted.hbs (DELETED, +0/-5)\n" + "renamed.mustache (RENAMED, +0/-0)" ) + old_results = [ + module.parse_grouping_inventory(old_inventory, version) + for version in ("1.10.0", "1.10.1", "1.10.2") + ] new = module.parse_grouping_inventory( messages( "ADDED src/space (unicode) λ.py (+10/-0)\n" @@ -1117,7 +1118,9 @@ def messages(inventory: str) -> list[dict[str, str]]: ) assert ( - old + old_results[0] + == old_results[1] + == old_results[2] == new == [ module.GroupingInventoryEntry("ADDED", "src/space (unicode) λ.py", 10, 0), @@ -1130,7 +1133,7 @@ def messages(inventory: str) -> list[dict[str, str]]: with pytest.raises(module.CompatibilityError, match="invalid grouping inventory entry"): module.parse_grouping_inventory(messages("path.py (ADDED, +1/-0)"), "1.11.0") with pytest.raises(module.CompatibilityError, match="not qualified"): - module.parse_grouping_inventory(messages("path.py (ADDED, +1/-0)"), "1.10.1") + module.parse_grouping_inventory(messages("path.py (ADDED, +1/-0)"), "1.9.10") @pytest.mark.parametrize( diff --git a/tests/test_operations_docs.py b/tests/test_operations_docs.py index 9500dbf..af49c97 100644 --- a/tests/test_operations_docs.py +++ b/tests/test_operations_docs.py @@ -224,6 +224,7 @@ def test_completion_cap_and_provider_failure_boundaries_are_public() -> None: configuration = CONFIGURATION.read_text(encoding="utf-8") gitlab = GITLAB_GUIDE.read_text(encoding="utf-8") security = (PROJECT_ROOT / "docs" / "security.md").read_text(encoding="utf-8") + compatibility = (PROJECT_ROOT / "docs" / "compatibility.md").read_text(encoding="utf-8") for document in (configuration, operations, gitlab): assert "OCR_LLM_MAX_COMPLETION_TOKENS" in document @@ -232,6 +233,10 @@ def test_completion_cap_and_provider_failure_boundaries_are_public() -> None: assert "provider-specific" in document for document in (configuration, operations, gitlab): assert "OCR_LLM_MAX_COMPLETION_TOKENS=4096" not in document + current_compatibility = compatibility.split("### OCR 1.11.0 — toolkit 0.8.6 target", 1)[1] + assert "override `4096`" not in current_compatibility + assert "operator-selected positive completion-cap override" in current_compatibility + assert "historical OCR 1.10.0 through 1.10.2" in current_compatibility for field in ("max_completion_tokens", "max_output_tokens", "max_tokens"): assert field in configuration for phrase in (