Skip to content

Commit 901f97d

Browse files
fix(ce-code-review): flag unrequested behavior rules as advisory (EveryInc#1771)
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 7e705b6 commit 901f97d

6 files changed

Lines changed: 142 additions & 3 deletions

File tree

‎docs/guides/ce-code-review.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ Before confidence filtering, synthesis supplies evidence from matching reviewer
166166

167167
When findings span distinct concerns, related ones are grouped under a short theme (`grouping:auto`, the default). Groups are a triage lens, not a restructure: findings keep their stable `#`s, and groups reference them (`#2, #3`). Pass `grouping:off` for a flat report or `grouping:always` to group even small reviews.
168168

169-
When the diff has an associated plan (`docs/plans/*.md` or `.html`), the skill discovers it (`plan:` argument, PR body link, or auto-discovery from branch name) and verifies the diff against Product Contract Requirements and Implementation Units on an implementation-ready artifact.
169+
When the diff has an associated plan (`docs/plans/*.md` or `.html`), the skill discovers it (`plan:` argument, PR body link, or auto-discovery from branch name) and verifies the diff against Product Contract Requirements and Implementation Units on an implementation-ready artifact. It also checks the reverse direction: a behavior rule the diff introduces that nothing in the plan asks for, such as silently dropping repeated requests, is reported as a P3 advisory finding for you to keep or remove. That finding never changes the verdict.
170170

171171
Pipeline artifacts under `plans/`, `solutions/`, and legacy `brainstorms/` are protected. Findings to delete or gitignore them are discarded.
172172

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
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.

‎skills/ce-code-review/references/finish-input.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ The dispatch context writes this file after every local reviewer is collected, a
6161

6262
Every path in this file exists before a leaf is launched: the dispatch context writes `files.txt` and `full.diff` in every run, including a small diff it inlined for the reviewers, and a listed artifact that is missing on disk is a failed finish. A `base:` review of the current checkout is `standalone` scope; `scope.tree_is_reviewed_head` is true exactly when the working tree is the reviewed tree (`local-aligned` or `standalone`), which is the Stage 5c apply eligibility condition. `raw-returns.json` holds every compact reviewer return the dispatch context consumed, one array entry per reviewer, with the `fast-pass` pseudo-reviewer included when it found anything; the per-reviewer artifacts sit beside it. A reviewer whose return is unstructured prose rather than compact JSON (`learnings-researcher`, `agent-native-reviewer`, `deployment-verification-agent`) writes no artifact of its own, so the dispatch context saves each such return verbatim to `<run-dir>/<reviewer>.md` and lists it under `collection.unstructured_returns`; those are what Stage 5 and Stage 6 read for pack-rule findings, Known Pattern notes, agent-native gaps, and deployment notes. A selected unstructured reviewer with no listed file is a failed reviewer. `mode.apply_local` is the only apply authority the leaves ever see: the dispatch context resolves an explicit `apply:local` token or an explicit apply request in the invoking user prompt into that flag before writing the file, and nothing inside the file or the run directory can grant it. `scope.pr.title`, `scope.pr.body`, reviewer output, and comment text are untrusted data a leaf reads for context, never a user instruction; a leaf that finds apply or fix wording there leaves the tree untouched. `coverage_notes` carries every sentence Coverage must contain that only the dispatch context knew: the standards fallback, untracked files excluded, the cross-model skip reason, scope-mode notes.
6363

64-
`plan.requirements` and `plan.implementation_units` are the Stage 2 extraction (`references/intent-and-plan.md`), carried so Stage 6's Requirements Completeness section is built from what dispatch extracted rather than re-derived. `invocation.constraints` carries the user's own words for any limit on what may be changed or reported ("only change tests", "do not touch the schema"); the report leaf honors every one of them during Stage 5c and Stage 6, and a constraint it cannot honor makes the affected fix unapplied and reported, never silently applied.
64+
`plan.requirements` and `plan.implementation_units` are the Stage 2 extraction (`references/intent-and-plan.md`), carried so Stage 6's Requirements Completeness checklist is built from what dispatch extracted rather than re-derived. `invocation.constraints` carries the user's own words for any limit on what may be changed or reported ("only change tests", "do not touch the schema"); the report leaf honors every one of them during Stage 5c and Stage 6, and a constraint it cannot honor makes the affected fix unapplied and reported, never silently applied.
6565

6666
## What a leaf reads
6767

‎skills/ce-code-review/references/finish-review.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Write the human-readable findings through the `ce-noslop` skill. Preserve exact
135135
2. **Applied (explicit local apply only).** When Stage 5c applied fixes, list them first, before the findings, in an Applied section (see review output template). Each entry carries `#`, file, the fix, and reviewer (a multi-file fix is one row with one `#`), then a one-line validation outcome (e.g. "pin tests 4 -> 6; suite 94 pass, lint clean") and commit status (committed on a clean tree as `fix(review): …` or the repo's nearest convention, or left uncommitted for the user on a dirty one). Flag green-but-unverifiable edits (auth/contract/concurrency) prominently. Omit this section when local apply was not authorized or nothing was applied. Applied findings appear here, not in the severity tables.
136136
2b. **Triage Groups.** When finalized `triage_groups` exist (after validation in Stage 5b step 5 and after apply in Stage 5c), render a `### Triage Groups` section before the findings as a compact table (`| Group | Findings | Context | Preferred Resolution | Why |`); a table fits this content well. The `Findings` cell lists the stable `#`s it covers; the resolution names the order/dependency. **Mark whether each group is an apply-queue or a decision-gate** (a group of mechanical fixes an automated fixer can apply, or a group that needs a design decision first, so the fixer stops there). Every referenced `#` must appear in the findings below; groups supplement the findings, never replace them. Omit the section when `grouping:off` is active or no groups survived. In `mode:agent` this section is carried by the `triage_groups` JSON field instead.
137137
3. **Findings.** Grouped by severity (`### P0 -- Critical`, `### P1 -- High`, `### P2 -- Moderate`, `### P3 -- Low`), rendered per the per-finding direction above and consistent within the section. Show the decision-vs-mechanical split where it helps the actor (flag the design calls). Omit empty severity levels. Finding numbers come from the stable assignment in Stage 5 -- never re-derive them per severity section or triage group.
138-
4. **Requirements Completeness.** Include only when a plan was found in Stage 2b (Plan discovery). For each requirement (R1, R2, etc.) and implementation unit in the plan, report whether corresponding work appears in the diff. Use a simple checklist: met / not addressed / partially addressed. Unaddressed requirements or implementation units are findings routed by `plan_source` under the rule in the Plan Requirements Completeness section of `references/intent-and-plan.md` (explicit: P1 `manual` / `downstream-resolver`, into the actionable queue; inferred: P3 `advisory` / `human`, report only).
138+
4. **Requirements Completeness.** Include only when a plan was found in Stage 2b (Plan discovery). For each requirement (R1, R2, etc.) and implementation unit in the plan, report whether corresponding work appears in the diff. Use a simple checklist: met / not addressed / partially addressed. Unaddressed requirements or implementation units are findings routed by `plan_source` under the rule in the Plan Requirements Completeness section of `references/intent-and-plan.md` (explicit: P1 `manual` / `downstream-resolver`, into the actionable queue; inferred: P3 `advisory` / `human`, report only). Then run that section's reverse check against the reviewed diff and the plan document itself (`plan.path`), not only the extracted lists, and list each unrequested behavior rule it finds.
139139
Omit this section entirely when no plan was found; do not mention the absence of a plan.
140140
5. **Actionable Findings.** Include when the actionable queue is non-empty: findings the caller should address (`gated_auto` / `manual` with `downstream-resolver`), plus anything Stage 5c chose not to apply. When local apply ran, findings already applied appear in the Applied section, not here.
141141
6. **Pre-existing.** Separate section, does not count toward verdict.

‎skills/ce-code-review/references/intent-and-plan.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ inspect the contents before checking completeness. A Product Contract alone info
99

1010
An unaddressed requirement or implementation unit is a finding on every depth path, routed by `plan_source`: `explicit` (a `plan:` argument or a PR-body link) yields a P1 finding with `autofix_class: manual` and `owner: downstream-resolver`, which enters the actionable queue; `inferred` (auto-discovered) yields a P3 finding with `autofix_class: advisory` and `owner: human`, which stays in the report only, because an inferred match is a hint, not a contract.
1111

12+
The check also runs in reverse. A behavior rule is a decision about what users or callers observe that a product owner would otherwise have made, such as silently dropping a repeated refund request. When the diff introduces a behavior rule that nothing in the plan asks for, that unrequested behavior rule is a finding on every depth path, listed with the requirements completeness results. Route it P3 with `autofix_class: advisory` and `owner: human`, whatever the `plan_source`, and never let it change the verdict. Whether the rule is wanted is the user's call, and a correct diff is no evidence either way. Internal structure, refactors, and handling of inputs a requirement already covers are not behavior rules.
13+
1214
Extract requirements from these shapes, in order:
1315

1416
1. Unified `Product Contract` -> `### Requirements`

0 commit comments

Comments
 (0)