|
| 1 | +--- |
| 2 | +title: Reverse Plan-Alignment Check in ce-code-review - Plan |
| 3 | +type: fix |
| 4 | +date: 2026-09-23 |
| 5 | +artifact_contract: ce-unified-plan/v1 |
| 6 | +artifact_readiness: implementation-ready |
| 7 | +product_contract_source: ce-plan-bootstrap |
| 8 | +execution: code |
| 9 | +--- |
| 10 | + |
| 11 | +# Reverse Plan-Alignment Check in ce-code-review - Plan |
| 12 | + |
| 13 | +## Goal Capsule |
| 14 | + |
| 15 | +- **Objective:** `ce-code-review` reports each behavior rule a diff introduces that nothing in the plan asks for, as an advisory finding for the user that never blocks. |
| 16 | +- **Authority:** the user's request, then the repo standard (`AGENTS.md`, `ce-skill-work`, `docs/solutions/skill-design/portable-agent-skill-authoring.md`), then this plan. |
| 17 | +- **Execution profile:** one inline pass; two reference files and one test file. |
| 18 | +- **Stop conditions:** stop and report if the condition cannot be stated without a list of cases, or if placing it outside `intent-and-plan.md` turns out to be required for a depth path to read it. |
| 19 | +- **Tail ownership:** the calling pipeline (`lfg`) owns review, commit, push, PR, and CI. |
| 20 | + |
| 21 | +## Product Contract |
| 22 | + |
| 23 | +### Summary |
| 24 | + |
| 25 | +Add the reverse direction to `ce-code-review`'s plan requirements check. Today it asks only whether each plan requirement landed in the diff. After this change it also reports behavior rules the diff adds that the plan never asked for, and leaves the keep-or-remove decision to the user. |
| 26 | + |
| 27 | +### Problem Frame |
| 28 | + |
| 29 | +arXiv 2609.12039 ("Reality Is the Final Verifier") names hallucinated requirements as a gap that widens with agent authorship: the agent invents a business rule, such as silently dropping duplicate refund requests, and implements it correctly. `ce-code-review` checks plan -> diff only, so an invented rule passes review as long as every planned requirement is also present. The `api-contract` persona's "undocumented behavior changes" covers interface semantics, not business rules the plan never mentioned. The skill's own outcome is a correct change "within the agreed scope", so the one-directional check is a missing half, not a new capability. |
| 30 | + |
| 31 | +### Requirements |
| 32 | + |
| 33 | +**Detection** |
| 34 | + |
| 35 | +- R1. When a plan is found, the review reports each behavior rule the diff introduces that nothing in the plan asks for, on every depth path. |
| 36 | +- R2. The check is one condition with at most one illustrative example and one exclusion, not a list of cases. |
| 37 | + |
| 38 | +**Routing and reporting** |
| 39 | + |
| 40 | +- R3. Each such finding is P3, `autofix_class: advisory`, `owner: human`, whatever the `plan_source`; it never enters the actionable queue and never changes the verdict. |
| 41 | +- R4. The requirements completeness results name the unrequested rules on every depth path: the report section on the full path, and `requirements_completeness` wherever the receipt carries it. |
| 42 | + |
| 43 | +### Scope Boundaries |
| 44 | + |
| 45 | +- No new reviewer persona and no new spine stage. |
| 46 | +- No reverse check when no plan is found (see KTD3). |
| 47 | +- No change to how `lfg` or other callers treat advisory findings. |
| 48 | + |
| 49 | +### Deferred to Follow-Up Work |
| 50 | + |
| 51 | +- `lfg`'s residual record (step 6, `skills/lfg/references/review-followup.md`) carries unapplied actionable findings and settled-decision conflicts, not human-owned advisory findings. In an `lfg` run, a reverse-check finding therefore reaches `review.json` but not the PR body. Carrying human-owned advisory findings into that record is an `lfg` change that covers every such finding, not only this one. |
| 52 | +- An eval catalog row pair in `tests/skill-eval-cell/catalog.ts` for the invented-rule case and its restraint twin, so the check can be run on Claude and Codex by someone with those CLIs. |
| 53 | +- Stage 2b in `intent-and-plan.md` restates the requirement-extraction order that the Plan Requirements Completeness section already owns; collapsing that duplicate is a separate cleanup. |
| 54 | + |
| 55 | +## Planning Contract |
| 56 | + |
| 57 | +### Key Technical Decisions |
| 58 | + |
| 59 | +- KTD1. **State the check beside the forward rule; run it where the forward check runs.** The condition, route, and listing rule go in `skills/ce-code-review/references/intent-and-plan.md`, section "Plan Requirements Completeness". The lite and focused paths read that section by name (`references/depth-paths.md`) and run the check in their own context. On the full path, the forward check runs in the report leaf at `finish-review.md` Stage 6 item 4, so the reverse check runs there too. Item 4 must tell the leaf to read the plan document at `plan.path`, because `finish-input.json` carries only the extracted requirement and unit lists, and a rule a KTD or unit asks for would otherwise read as unrequested. Running at Stage 6 also keeps these findings clear of Stage 5's soft-bucket demotion, which rejects claims with no defect consequence. |
| 60 | +- KTD2. **Advisory, owned by the user, never blocking.** (session-settled: user-approved — chosen over routing it like an unaddressed explicit-plan requirement into the actionable queue: whether an unrequested rule is wanted is a product decision, and a correct diff is no evidence either way.) P3 keeps it clear of the verdict rule, which caps only on open P0 and P1 findings. |
| 61 | +- KTD3. **Only the plan can vouch for a rule.** The Stage 2 intent summary may be inferred from commits and the diff, which the same author wrote, so it cannot show that a rule was requested. Without a plan there is nothing independent to compare against, so the reverse check does not run. A rule the plan asks for anywhere, including a KTD or a unit's approach, counts as requested. Rejected: letting only the Product Contract vouch, which would flag every how-level rule a plan already made visible. |
| 62 | +- KTD4. **One condition, one example, one exclusion.** A behavior rule is a decision about what users or callers observe that a product owner would otherwise have made. One subordinated example (silently dropping a repeated refund request) anchors literal hosts, per `docs/solutions/skill-design/subordinate-the-failing-shape-to-the-condition.md`. The exclusion (internal structure, refactors, handling of inputs a requirement already covers) comes last so nothing after it competes. Rejected: the source doc's six-verb list (kept, dropped, rejected, retried, expired, charged), which is a case catalog standing in for the condition. |
| 63 | +- KTD5. **Pin the locator phrase and the route, not the prose.** The test finds the reverse-check paragraph by the phrase `unrequested behavior rule` inside the owning section, bounded by `## Plan Requirements Completeness` and the next heading of any level (today `### Stage 2: Intent discovery`). It asserts that paragraph carries the route tokens `P3`, `autofix_class: advisory`, and `owner: human`, and that Stage 6 item 4 carries the same phrase. The forward paragraph already contains the route tokens, so the phrase is what makes the pin falsifiable. Other wording stays free, per `docs/solutions/skill-design/bound-contradiction-checks-to-named-guidance.md`. |
| 64 | + |
| 65 | +### Assumptions |
| 66 | + |
| 67 | +- P3 is the right severity. The forward check already uses P3 advisory for inferred-plan omissions, and the verdict rule ignores P2 and P3 either way. |
| 68 | + |
| 69 | +## Implementation Units |
| 70 | + |
| 71 | +### U1. State and render the reverse check |
| 72 | + |
| 73 | +- **Goal:** Add the reverse condition to the owning section and name it in the report line. |
| 74 | +- **Requirements:** R1, R2, R3, R4 |
| 75 | +- **Dependencies:** none |
| 76 | +- **Files:** |
| 77 | + - `skills/ce-code-review/references/intent-and-plan.md` |
| 78 | + - `skills/ce-code-review/references/finish-review.md` |
| 79 | +- **Approach:** |
| 80 | + 1. In "Plan Requirements Completeness", after the forward-routing paragraph, add one paragraph that states the condition, the one subordinated example, the route, the listing rule (R4), and the exclusion, per KTD2 and KTD4. |
| 81 | + 2. In `finish-review.md` Stage 6 item 4, add one sentence telling the report leaf to run that section's reverse check against the reviewed diff and the plan document at `plan.path`, and to list what it finds (KTD1). |
| 82 | + 3. Follow `ce-skill-work` edit mode: plain sentences, no shouting, nothing else in the section restated. |
| 83 | +- **Patterns to follow:** the forward rule's routing sentence in the same section; the report-line cross-reference already in item 4. |
| 84 | +- **Test scenarios:** covered by U2. |
| 85 | +- **Verification:** a reader of the section alone can tell what counts, what does not, how it routes, where it is listed, and that it never blocks. |
| 86 | + |
| 87 | +### U2. Pin the contract |
| 88 | + |
| 89 | +- **Goal:** A deletion or re-route of the reverse check fails `bun test`. |
| 90 | +- **Requirements:** R1, R3, R4 |
| 91 | +- **Dependencies:** U1 |
| 92 | +- **Files:** `tests/review-skill-contract.test.ts` |
| 93 | +- **Approach:** add one test case next to "keeps plan requirements completeness compatible with current and legacy unit formats", per KTD5. |
| 94 | +- **Test scenarios:** |
| 95 | + - The "Plan Requirements Completeness" section of `intent-and-plan.md`, ending at the next heading of any level, contains a paragraph with the phrase `unrequested behavior rule`, and that paragraph contains `P3`, `` `autofix_class: advisory` ``, and `` `owner: human` ``. |
| 96 | + - Removing the paragraph, or moving it into Stage 2, 2b, or 2c, fails the test. |
| 97 | + - `finish-review.md` Stage 6 item 4 contains the phrase `unrequested behavior rule`. |
| 98 | +- **Verification:** the new case passes on the edited tree and fails when the paragraph is removed. |
| 99 | + |
| 100 | +## Verification Contract |
| 101 | + |
| 102 | +| Gate | Command or method | Applies to | |
| 103 | +|---|---|---| |
| 104 | +| Contract pin | `bun test tests/review-skill-contract.test.ts` | U2 | |
| 105 | +| Full suite | `bun run test` | all | |
| 106 | +| Release metadata | `bun run release:validate` | all | |
| 107 | +| Behavioral eval | Fresh-agent read-only probe of the requirements check on a throwaway repo: an invented-rule diff (expect one advisory, human-owned finding) and a restraint diff with a helper refactor, covered input handling, and a new log message the plan never mentions (expect none). Pre-change and post-change skill arms. | U1 | |
| 108 | + |
| 109 | +The repo's eval driver (`bun run test:skill-eval-cell`) needs `claude` or `codex` on PATH. Neither exists in this environment, so the behavioral eval runs as a single-host eval with fresh Cursor subagents and is labeled that way in the PR. |
| 110 | + |
| 111 | +## Definition of Done |
| 112 | + |
| 113 | +- U1 and U2 are complete and the three command gates pass. |
| 114 | +- The behavioral eval ran, or its exact skip reason is recorded in the PR. |
| 115 | +- No abandoned-attempt text remains in the touched files. |
0 commit comments