@opengsd/gsd-path 1.7.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/FULL.md +2 -2
  3. package/QUICK.md +1 -1
  4. package/README.md +9 -9
  5. package/WORKFLOW.md +2 -2
  6. package/package.json +1 -1
  7. package/scripts/dispatch_driver.py +5 -0
  8. package/scripts/isolation.py +20 -16
  9. package/skills/gsd-path/BUILD.md +3 -2
  10. package/skills/gsd-path/PLAN.md +3 -3
  11. package/skills/gsd-path/references/build-native.md +8 -4
  12. package/skills/gsd-path/references/planner.md +4 -3
  13. package/skills/gsd-path/references/reviewer-wave.md +10 -5
  14. package/skills/gsd-path/references/reviewer.md +13 -2
  15. package/skills/gsd-path/scripts/dispatch_driver.py +5 -0
  16. package/skills/gsd-path/scripts/isolation.py +20 -16
  17. package/skills/gsd-path/templates/plan.md +3 -2
  18. package/skills/gsd-path-build/SKILL.md +3 -2
  19. package/skills/gsd-path-build/references/build-native.md +8 -4
  20. package/skills/gsd-path-build/references/reviewer-wave.md +10 -5
  21. package/skills/gsd-path-build/references/reviewer.md +13 -2
  22. package/skills/gsd-path-build/scripts/dispatch_driver.py +5 -0
  23. package/skills/gsd-path-build/scripts/isolation.py +20 -16
  24. package/skills/gsd-path-decide/scripts/isolation.py +20 -16
  25. package/skills/gsd-path-define/scripts/isolation.py +20 -16
  26. package/skills/gsd-path-docs-audit/scripts/isolation.py +20 -16
  27. package/skills/gsd-path-inspect/scripts/isolation.py +20 -16
  28. package/skills/gsd-path-plan/SKILL.md +3 -3
  29. package/skills/gsd-path-plan/references/planner.md +4 -3
  30. package/skills/gsd-path-plan/scripts/isolation.py +20 -16
  31. package/skills/gsd-path-plan/templates/plan.md +3 -2
  32. package/skills/gsd-path-research/scripts/isolation.py +20 -16
  33. package/skills/gsd-path-roadmap/scripts/isolation.py +20 -16
  34. package/skills/gsd-path-ship/references/reviewer-wave.md +10 -5
  35. package/skills/gsd-path-ship/references/reviewer.md +13 -2
  36. package/skills/gsd-path-ship/scripts/isolation.py +20 -16
  37. package/skills/path/BUILD.md +3 -2
  38. package/skills/path/PLAN.md +3 -3
  39. package/skills/path/references/build-native.md +8 -4
  40. package/skills/path/references/planner.md +4 -3
  41. package/skills/path/references/reviewer-wave.md +10 -5
  42. package/skills/path/references/reviewer.md +13 -2
  43. package/skills/path/scripts/dispatch_driver.py +5 -0
  44. package/skills/path/scripts/isolation.py +20 -16
  45. package/skills/path/templates/plan.md +3 -2
package/CHANGELOG.md CHANGED
@@ -11,6 +11,15 @@ app and the daemon have their own file,
11
11
  [daemon/app/CHANGELOG.md](daemon/app/CHANGELOG.md). Release bookkeeping and
12
12
  test-only changes are not listed; the Git history has them.
13
13
 
14
+ ## [1.7.1] - 2026-10-31
15
+
16
+ ### Changed
17
+ - Focus reviews on agreed requirements and required proof, without searching for unrelated improvements.
18
+ - Require an explicit request for adversarial review, and limit repeat reviews to repaired failures and affected checks.
19
+
20
+ ### Fixed
21
+ - Resume a patch planner after its re-entry checkpoint without rejecting its task log.
22
+
14
23
  ## [1.7.0] - 2026-10-30
15
24
 
16
25
  ### Added
package/FULL.md CHANGED
@@ -293,8 +293,8 @@ from `files` unless it is that allowed Project-verify copy.
293
293
 
294
294
  Build reviews each completed wave against task criteria and the INTENT success
295
295
  criteria that wave owns. Each wave carries a review depth — `full`,
296
- `verify-only` for low-risk waves, or sparingly `deep`
297
- for irreversible or security-critical waves. The canonical
296
+ `verify-only` for low-risk waves, or `deep` only when INTENT.md records an
297
+ explicit user request for adversarial review. The canonical
298
298
  [build contract](skills/gsd-path-build/SKILL.md) defines each depth's writer
299
299
  and evidence rules. Review findings are keyed by their failed criterion and
300
300
  carried forward across cycles, so a criterion failing again after its fix task
package/QUICK.md CHANGED
@@ -14,7 +14,7 @@ One router skill drives a gated pipeline: inspect → define → research → de
14
14
  plan → build → ship. Every handoff lives in `.project/` so any session can resume from disk.
15
15
 
16
16
  **Hosts:** Codex, Claude Code, Grok, OpenCode, Antigravity, Cursor, and Kimi
17
- Code have a passing live milestone for release 1.7.0. Copilot CLI, Qwen, Zed,
17
+ Code have a passing live milestone for release 1.7.1. Copilot CLI, Qwen, Zed,
18
18
  Kiro, and Muse Code install, but have no live milestone for that release. See
19
19
  [host tiers](README.md).
20
20
 
package/README.md CHANGED
@@ -9,11 +9,11 @@ milestone loop. While a milestone builds, the next one can be planned in
9
9
  parallel under `.project/next/` (lookahead); a building milestone can also be
10
10
  abandoned on an explicit ruling, archiving its partial work for a re-slice.
11
11
 
12
- **Hosts with a passing full live milestone for release 1.7.0:** Codex, Claude
12
+ **Hosts with a passing full live milestone for release 1.7.1:** Codex, Claude
13
13
  Code, Grok, OpenCode, Antigravity CLI, Cursor, and Kimi Code.
14
14
 
15
15
  **Hosts with an installer and a dispatch contract, but no live milestone for
16
- release 1.7.0:** GitHub Copilot CLI (account quota exhausted), Qwen Code, Zed,
16
+ release 1.7.1:** GitHub Copilot CLI (account quota exhausted), Qwen Code, Zed,
17
17
  and Kiro (API credits), and Muse Code (no live release evidence recorded yet).
18
18
  These hosts are excluded from the release evaluation. Exclusion is not a pass.
19
19
 
@@ -24,16 +24,16 @@ The [host trust matrix](https://github.com/open-gsd/gsd-path/blob/main/docs/trus
24
24
  is the source of truth for live milestone proof and each host's guard tier.
25
25
 
26
26
  <!-- release-docs -->
27
- ## What's new in 1.7.0 — 2026-10-30
27
+ ## What's new in 1.7.1 — 2026-10-31
28
28
 
29
- **Latest npm release:** [@opengsd/gsd-path@1.7.0](https://www.npmjs.com/package/@opengsd/gsd-path/v/1.7.0) — [release notes](CHANGELOG.md#170---2026-10-30)
29
+ **Latest npm release:** [@opengsd/gsd-path@1.7.1](https://www.npmjs.com/package/@opengsd/gsd-path/v/1.7.1) — [release notes](CHANGELOG.md#171---2026-10-31)
30
30
 
31
31
  **Recent highlights**
32
- - translate every app screen through the message tables
33
- - add the app language setting with message tables
34
- - accept blessed successor runtimes on closed milestones
35
- - add a publish-only runtime store CLI
36
- - add evidence-manifest joining tasks to accepted evidence
32
+ - scope reviews to agreed acceptance criteria
33
+ - accept a resumed patch planner's re-entry checkpoint
34
+ - Point current-release docs at 1.7.1 evidence
35
+ - complete 1.7.1 release trust evidence
36
+ - record Cursor proof and pending 1.7.1 release checks
37
37
 
38
38
  <!-- /release-docs -->
39
39
 
package/WORKFLOW.md CHANGED
@@ -373,8 +373,8 @@ require a verdict per owned SC id. Acceptance criteria,
373
373
  owned SCs, and Verify are the contract; the coder owns
374
374
  implementation decisions inside the stated constraints. The planner reads
375
375
  `.project/LESSONS.md` when present and assigns each wave a `Review depth` —
376
- `full`, `verify-only` for low-risk waves, or sparingly `deep` for
377
- irreversible or security-critical waves; wave 1 and any wave touching
376
+ `full`, `verify-only` for low-risk waves, or `deep` only when INTENT.md
377
+ records an explicit user request for adversarial review; wave 1 and any wave touching
378
378
  authentication, payments, data migration, or concurrency stays `full` or
379
379
  `deep`. PLAN.md Config may name an optional `review_panel` (`off` by
380
380
  default, or `detected` / a named family list). In program flow CHARTER.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengsd/gsd-path",
3
- "version": "1.7.0",
3
+ "version": "1.7.1",
4
4
  "description": "Disk-backed AI agent pipeline. Docs: DOCS.md (start here), QUICK.md, FULL.md, UPDATE.md",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -1461,6 +1461,9 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1461
1461
  f"You are the reviewer for GSD Path wave {wave}, cycle {cycle}; logical task name "
1462
1462
  f"{state['task_id']}. Mode: wave" + (f"; lens: {lens}." if lens else "."),
1463
1463
  f"Read the reviewer role brief first and follow it exactly: {options.role_brief}",
1464
+ "Validate the agreed acceptance contract. "
1465
+ "Block only on a named unmet requirement or missing required evidence. "
1466
+ "Do not search for improvements or expand the agreed contract.",
1464
1467
  f"Template (use only this): {options.template}",
1465
1468
  f"AGENTS.md: {agents if agents.exists() else 'absent'}",
1466
1469
  f"Repository root, read-only: {primary}",
@@ -1478,6 +1481,8 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1478
1481
  f"landing commit {task['commit']}")
1479
1482
  if previous is not None:
1480
1483
  lines.append(f"Previous cycle review to re-check: {previous}")
1484
+ lines.append("Re-check repaired failures and affected passes only. "
1485
+ "Reuse settled evidence for unaffected criteria.")
1481
1486
  if options.repair_evidence:
1482
1487
  lines.append(f"Repair evidence receipt (re-review after a proven repair): {options.repair_evidence}")
1483
1488
  if final_scope:
@@ -5372,16 +5372,6 @@ def _committed_ship_active(repo: Path) -> bool:
5372
5372
  return fields.get("phase") == "ship" and fields.get("status") == "active"
5373
5373
 
5374
5374
 
5375
- # The STATE Log tail that sanctions a build checkpoint past a HEAD that is
5376
- # still ship/active: the blocked final review went through the patch plan
5377
- # (reopened, then approved) and build started again (#526).
5378
- _PATCH_REENTRY_LOG = (
5379
- ("plan", "patch plan reopened"),
5380
- ("plan", "patch plan approved"),
5381
- ("build", "build started"),
5382
- )
5383
-
5384
-
5385
5375
  def _patch_reentry_build_active(repo: Path) -> bool:
5386
5376
  """True when the worktree STATE is the sanctioned patch-re-entry build.
5387
5377
 
@@ -5389,8 +5379,12 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5389
5379
  (ship/active) on purpose: the patch plan runs uncommitted and the patch
5390
5380
  build's own checkpoint commits the artifacts (SHIP.md). This reads the
5391
5381
  worktree STATE the checkpoint is about to commit and accepts only the
5392
- documented sequence — a hand-flipped build/active during final review
5393
- carries no such Log tail and stays refused (#429, #526).
5382
+ documented shape: the Log ends with the build restart, the event before
5383
+ it closes the plan stay with the patch approval, and that stay opened
5384
+ with `patch plan reopened` — a resumed planner logs `patch planning
5385
+ blocked` and `planning resumed` inside the same stay (#531). A
5386
+ hand-flipped build/active during final review carries no such Log tail
5387
+ and stays refused (#429, #526).
5394
5388
  """
5395
5389
 
5396
5390
  state = repo / ".project" / "STATE.md"
@@ -5410,10 +5404,20 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5410
5404
  match = re.fullmatch(r"- \d{4}-\d{2}-\d{2} — (\S+) — (.+)", line)
5411
5405
  if match:
5412
5406
  events.append((match.group(1), match.group(2)))
5413
- # The sanctioned sequence appears in order, as the Log tail of this
5414
- # milestone's patch loop; the final event must be the build restart.
5415
- last = len(_PATCH_REENTRY_LOG)
5416
- return len(events) >= last and tuple(events[-last:]) == _PATCH_REENTRY_LOG
5407
+ # The final event must be the build restart, the event before it must
5408
+ # close the plan stay with the patch approval, and that stay must open
5409
+ # with the reopen; every plan event between them (a blocked, resumed
5410
+ # planner) stays inside the run (#531).
5411
+ if len(events) < 2 or events[-1] != ("build", "build started"):
5412
+ return False
5413
+ if events[-2] != ("plan", "patch plan approved"):
5414
+ return False
5415
+ stay = 0
5416
+ for phase, _event in reversed(events[:-1]):
5417
+ if phase != "plan":
5418
+ break
5419
+ stay += 1
5420
+ return events[-(stay + 1)] == ("plan", "patch plan reopened")
5417
5421
 
5418
5422
 
5419
5423
  def checkpoint(
@@ -133,8 +133,9 @@ that same brief into `.project/archive/`; build adds fix tasks and repairs
133
133
  briefs, it never replans. It also refuses a `build:` checkpoint while the
134
134
  committed STATE is `ship/active`: final-review outputs stay uncommitted until
135
135
  the ship commit. The one exception is the patch re-entry checkpoint: the
136
- worktree STATE is `build/active` and its Log ends with `patch plan reopened`,
137
- `patch plan approved`, `build started`.
136
+ worktree STATE is `build/active`, its Log ends with `patch plan approved`
137
+ then `build started`, and the plan stay holding that approval opened with
138
+ `patch plan reopened` (a blocked, resumed planner may log events inside it).
138
139
 
139
140
  ## Execute from runtime receipts
140
141
 
@@ -155,9 +155,9 @@ as stated in Lookahead mode.
155
155
  - Require a `Review depth` value (`full`, `deep`, or `verify-only`) on
156
156
  every wave. Wave 1 and any wave touching authentication, authorization,
157
157
  payments, data migration, or concurrency requires `full` or `deep`;
158
- this includes quick-lane single waves. The planner assigns `deep`
159
- sparingly to waves where a wrong merge is irreversible or
160
- security-critical.
158
+ this includes quick-lane single waves. Use `full` unless INTENT.md
159
+ records an explicit user request for adversarial review; risk alone
160
+ does not authorize `deep`.
161
161
  - When INTENT.md `Surfaces:` is not `none`, require a PLAN.md
162
162
  `## Surface contract` block per named surface with its Criteria, Entry,
163
163
  States, Walkthrough, and the task that delivers it. Those criteria must be
@@ -415,7 +415,10 @@ dispatch contract and perform steps 1–5 by hand.
415
415
  stages `.project/review/wave-N.cycleC.md` there; the
416
416
  orchestrator validates it, atomically copies it to the primary canonical
417
417
  path, and only then retires that sidecar with `retire`.
418
- - `deep`: spawn two independent reviewers in parallel, each with a fresh
418
+ - `deep`: require an explicit user request for adversarial review recorded
419
+ in INTENT.md. Risk alone does not authorize it; without the request,
420
+ return the plan to its owner for `full` review selection before dispatch.
421
+ Spawn two independent reviewers in parallel, each with a fresh
419
422
  isolated context and its own verify sidecar from `isolate-verify` at the
420
423
  recorded review base (`--name wave-<N>-cycle-<C>-contract` and
421
424
  `wave-<N>-cycle-<C>-adversarial`). Supply both every task path, its
@@ -427,9 +430,10 @@ dispatch contract and perform steps 1–5 by hand.
427
430
  check every acceptance criterion,
428
431
  owned INTENT success criterion, and interface contract. The adversarial
429
432
  lens — logical task name
430
- `review_wave_<wave>_cycle_<cycle>_adversarial` — tries to kill the work:
431
- security holes, unhandled edge cases, failure modes, data-loss and
432
- concurrency risks, and missing error handling. Each stages its own file
433
+ `review_wave_<wave>_cycle_<cycle>_adversarial` — exercises failure paths
434
+ required by the agreed contract. Every blocker needs a named unmet
435
+ requirement with checked evidence or missing required proof. Neither
436
+ lens searches for improvements or expands the contract. Each stages its own file
433
437
  in its own worktree — `.project/review/wave-N.cycleC.contract.md` and
434
438
  `.project/review/wave-N.cycleC.adversarial.md`; the orchestrator validates
435
439
  each, atomically copies both to their primary canonical paths, and only
@@ -33,9 +33,10 @@ the how.
33
33
  parallelism or isolates a risk.
34
34
  5. Assign each wave `Review depth: full`, `deep`, or `verify-only`. Wave 1
35
35
  and any wave touching authentication, authorization, payments, data
36
- migration, or concurrency requires `full` or `deep`. Assign `deep`
37
- sparingly, only to waves where a wrong merge is irreversible or
38
- security-critical; `verify-only` suits polish and low-risk feature waves
36
+ migration, or concurrency requires `full` or `deep`. Use `full` unless
37
+ the user explicitly requested adversarial review and that request is
38
+ recorded in INTENT.md; only then may you assign `deep`. Risk alone
39
+ does not authorize adversarial review; `verify-only` suits polish and low-risk feature waves
39
40
  whose Verify commands meaningfully cover the criteria.
40
41
 
41
42
  Every dependency must be in an earlier wave or in the same wave. Same-wave
@@ -80,8 +80,9 @@ or Verify commands that cannot fail unless either defeats a criterion. Set the
80
80
  wave verdict to `pass` only when every task passes and every owned INTENT
81
81
  success criterion for the wave passes.
82
82
 
83
- For cycle greater than 1, read the previous review, re-check every failure,
84
- and regression-check affected passes. State when the same criterion fails for
83
+ For cycle greater than 1, read the previous review, re-check repaired failures,
84
+ and regression-check affected passes only. Reuse settled evidence for unaffected
85
+ criteria; do not start a fresh search for improvements. State when the same criterion fails for
85
86
  a different reason. Use only the wave-review template.
86
87
 
87
88
  ### Review file format
@@ -153,6 +154,8 @@ runtime checks freshness and derives the final view from these records.
153
154
 
154
155
  ## Deep review lenses
155
156
 
157
+ Use `deep` only when the user explicitly requested adversarial review and that
158
+ request is recorded in INTENT.md. Risk alone does not authorize it.
156
159
  A `deep` wave spawns two independent reviewers in parallel, each with a fresh
157
160
  context and its own isolated workspace at the recorded review base (a verify
158
161
  sidecar in reconstructed mode, or the supplied combined checkout in immutable
@@ -166,9 +169,11 @@ mode). Every Wave mode rule above applies to both lenses.
166
169
  contract`.
167
170
  - **Adversarial** — logical task name
168
171
  `review_wave_<wave>_cycle_<cycle>_adversarial`; stages
169
- `.project/review/wave-N.cycleC.adversarial.md`. Try to kill the work:
170
- security holes, unhandled edge cases, failure modes, data-loss and
171
- concurrency risks, missing error handling. Record `Lens: adversarial`.
172
+ `.project/review/wave-N.cycleC.adversarial.md`. Exercise failure paths within
173
+ the agreed contract, including its required security, data-loss, concurrency,
174
+ and error-handling behavior. Every blocking finding still needs a named
175
+ requirement and checked failure or missing required proof. Do not invent
176
+ additional requirements. Record `Lens: adversarial`.
172
177
 
173
178
  The wave passes only when both lenses return `pass`; any `blocked` lens
174
179
  blocks the wave.
@@ -1,6 +1,7 @@
1
1
  # Reviewer role
2
2
 
3
- Verify written GSD Path expectations and block failures. Never fix code.
3
+ Validate that the agreed work functions. Block contract failures or missing
4
+ required evidence. Never search for improvements or fix code.
4
5
 
5
6
  ## Brief contract
6
7
 
@@ -36,7 +37,17 @@ Resolve sibling links against this role file's directory.
36
37
 
37
38
  - When `GSD_PATH_JEV=1`, wave and final reviewers follow the optional
38
39
  [Jev evidence screening procedure](jev-review.md) for uncovered criteria.
39
- - Review written expectations, not preferences or alternate designs.
40
+ - Use the written acceptance, interface, success, edge, prohibition, and
41
+ surface contracts as the complete review scope. Block only on a named
42
+ unmet requirement with checked evidence, or the specific missing evidence
43
+ needed to prove it. Passing tests alone do not prove a required walkthrough.
44
+ - Do not search for improvements, alternate designs, speculative hardening,
45
+ or unrelated edge cases. Do not turn these into findings or fix tasks.
46
+ A clean pass is a complete result; no finding quota applies.
47
+ - On re-review, check repaired failures and passes affected by the repair.
48
+ Reuse settled evidence for unaffected criteria; do not reopen them or
49
+ introduce new requirements. An observed regression against the unchanged
50
+ contract still blocks. Stop when every applicable claim is proven.
40
51
  - Treat an Interface contract violation as a failed criterion, citing the
41
52
  contract line and the offending diff hunk.
42
53
  - Require checked evidence for every verdict.
@@ -1461,6 +1461,9 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1461
1461
  f"You are the reviewer for GSD Path wave {wave}, cycle {cycle}; logical task name "
1462
1462
  f"{state['task_id']}. Mode: wave" + (f"; lens: {lens}." if lens else "."),
1463
1463
  f"Read the reviewer role brief first and follow it exactly: {options.role_brief}",
1464
+ "Validate the agreed acceptance contract. "
1465
+ "Block only on a named unmet requirement or missing required evidence. "
1466
+ "Do not search for improvements or expand the agreed contract.",
1464
1467
  f"Template (use only this): {options.template}",
1465
1468
  f"AGENTS.md: {agents if agents.exists() else 'absent'}",
1466
1469
  f"Repository root, read-only: {primary}",
@@ -1478,6 +1481,8 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1478
1481
  f"landing commit {task['commit']}")
1479
1482
  if previous is not None:
1480
1483
  lines.append(f"Previous cycle review to re-check: {previous}")
1484
+ lines.append("Re-check repaired failures and affected passes only. "
1485
+ "Reuse settled evidence for unaffected criteria.")
1481
1486
  if options.repair_evidence:
1482
1487
  lines.append(f"Repair evidence receipt (re-review after a proven repair): {options.repair_evidence}")
1483
1488
  if final_scope:
@@ -5372,16 +5372,6 @@ def _committed_ship_active(repo: Path) -> bool:
5372
5372
  return fields.get("phase") == "ship" and fields.get("status") == "active"
5373
5373
 
5374
5374
 
5375
- # The STATE Log tail that sanctions a build checkpoint past a HEAD that is
5376
- # still ship/active: the blocked final review went through the patch plan
5377
- # (reopened, then approved) and build started again (#526).
5378
- _PATCH_REENTRY_LOG = (
5379
- ("plan", "patch plan reopened"),
5380
- ("plan", "patch plan approved"),
5381
- ("build", "build started"),
5382
- )
5383
-
5384
-
5385
5375
  def _patch_reentry_build_active(repo: Path) -> bool:
5386
5376
  """True when the worktree STATE is the sanctioned patch-re-entry build.
5387
5377
 
@@ -5389,8 +5379,12 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5389
5379
  (ship/active) on purpose: the patch plan runs uncommitted and the patch
5390
5380
  build's own checkpoint commits the artifacts (SHIP.md). This reads the
5391
5381
  worktree STATE the checkpoint is about to commit and accepts only the
5392
- documented sequence — a hand-flipped build/active during final review
5393
- carries no such Log tail and stays refused (#429, #526).
5382
+ documented shape: the Log ends with the build restart, the event before
5383
+ it closes the plan stay with the patch approval, and that stay opened
5384
+ with `patch plan reopened` — a resumed planner logs `patch planning
5385
+ blocked` and `planning resumed` inside the same stay (#531). A
5386
+ hand-flipped build/active during final review carries no such Log tail
5387
+ and stays refused (#429, #526).
5394
5388
  """
5395
5389
 
5396
5390
  state = repo / ".project" / "STATE.md"
@@ -5410,10 +5404,20 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5410
5404
  match = re.fullmatch(r"- \d{4}-\d{2}-\d{2} — (\S+) — (.+)", line)
5411
5405
  if match:
5412
5406
  events.append((match.group(1), match.group(2)))
5413
- # The sanctioned sequence appears in order, as the Log tail of this
5414
- # milestone's patch loop; the final event must be the build restart.
5415
- last = len(_PATCH_REENTRY_LOG)
5416
- return len(events) >= last and tuple(events[-last:]) == _PATCH_REENTRY_LOG
5407
+ # The final event must be the build restart, the event before it must
5408
+ # close the plan stay with the patch approval, and that stay must open
5409
+ # with the reopen; every plan event between them (a blocked, resumed
5410
+ # planner) stays inside the run (#531).
5411
+ if len(events) < 2 or events[-1] != ("build", "build started"):
5412
+ return False
5413
+ if events[-2] != ("plan", "patch plan approved"):
5414
+ return False
5415
+ stay = 0
5416
+ for phase, _event in reversed(events[:-1]):
5417
+ if phase != "plan":
5418
+ break
5419
+ stay += 1
5420
+ return events[-(stay + 1)] == ("plan", "patch plan reopened")
5417
5421
 
5418
5422
 
5419
5423
  def checkpoint(
@@ -35,8 +35,9 @@ Project verify: `<command that installs dependencies, builds + tests the whole p
35
35
  Goal: <what this wave proves; if it fails, what changes>
36
36
  Review depth: full <!-- full | deep | verify-only. Wave 1 and auth/payments/
37
37
  data migration/concurrency waves must be full or
38
- deep. Assign deep sparingly: irreversible or
39
- security-critical merges. -->
38
+ deep. Use full unless the user explicitly requested
39
+ adversarial review, recorded in INTENT.md. Risk alone
40
+ does not authorize deep. -->
40
41
 
41
42
  <!-- No task table. Task id, title, deps, and files live only in each
42
43
  `tasks/T###-slug.md` frontmatter; `wave: N` there assigns it here. -->
@@ -133,8 +133,9 @@ that same brief into `.project/archive/`; build adds fix tasks and repairs
133
133
  briefs, it never replans. It also refuses a `build:` checkpoint while the
134
134
  committed STATE is `ship/active`: final-review outputs stay uncommitted until
135
135
  the ship commit. The one exception is the patch re-entry checkpoint: the
136
- worktree STATE is `build/active` and its Log ends with `patch plan reopened`,
137
- `patch plan approved`, `build started`.
136
+ worktree STATE is `build/active`, its Log ends with `patch plan approved`
137
+ then `build started`, and the plan stay holding that approval opened with
138
+ `patch plan reopened` (a blocked, resumed planner may log events inside it).
138
139
 
139
140
  ## Execute from runtime receipts
140
141
 
@@ -415,7 +415,10 @@ dispatch contract and perform steps 1–5 by hand.
415
415
  stages `.project/review/wave-N.cycleC.md` there; the
416
416
  orchestrator validates it, atomically copies it to the primary canonical
417
417
  path, and only then retires that sidecar with `retire`.
418
- - `deep`: spawn two independent reviewers in parallel, each with a fresh
418
+ - `deep`: require an explicit user request for adversarial review recorded
419
+ in INTENT.md. Risk alone does not authorize it; without the request,
420
+ return the plan to its owner for `full` review selection before dispatch.
421
+ Spawn two independent reviewers in parallel, each with a fresh
419
422
  isolated context and its own verify sidecar from `isolate-verify` at the
420
423
  recorded review base (`--name wave-<N>-cycle-<C>-contract` and
421
424
  `wave-<N>-cycle-<C>-adversarial`). Supply both every task path, its
@@ -427,9 +430,10 @@ dispatch contract and perform steps 1–5 by hand.
427
430
  check every acceptance criterion,
428
431
  owned INTENT success criterion, and interface contract. The adversarial
429
432
  lens — logical task name
430
- `review_wave_<wave>_cycle_<cycle>_adversarial` — tries to kill the work:
431
- security holes, unhandled edge cases, failure modes, data-loss and
432
- concurrency risks, and missing error handling. Each stages its own file
433
+ `review_wave_<wave>_cycle_<cycle>_adversarial` — exercises failure paths
434
+ required by the agreed contract. Every blocker needs a named unmet
435
+ requirement with checked evidence or missing required proof. Neither
436
+ lens searches for improvements or expands the contract. Each stages its own file
433
437
  in its own worktree — `.project/review/wave-N.cycleC.contract.md` and
434
438
  `.project/review/wave-N.cycleC.adversarial.md`; the orchestrator validates
435
439
  each, atomically copies both to their primary canonical paths, and only
@@ -80,8 +80,9 @@ or Verify commands that cannot fail unless either defeats a criterion. Set the
80
80
  wave verdict to `pass` only when every task passes and every owned INTENT
81
81
  success criterion for the wave passes.
82
82
 
83
- For cycle greater than 1, read the previous review, re-check every failure,
84
- and regression-check affected passes. State when the same criterion fails for
83
+ For cycle greater than 1, read the previous review, re-check repaired failures,
84
+ and regression-check affected passes only. Reuse settled evidence for unaffected
85
+ criteria; do not start a fresh search for improvements. State when the same criterion fails for
85
86
  a different reason. Use only the wave-review template.
86
87
 
87
88
  ### Review file format
@@ -153,6 +154,8 @@ runtime checks freshness and derives the final view from these records.
153
154
 
154
155
  ## Deep review lenses
155
156
 
157
+ Use `deep` only when the user explicitly requested adversarial review and that
158
+ request is recorded in INTENT.md. Risk alone does not authorize it.
156
159
  A `deep` wave spawns two independent reviewers in parallel, each with a fresh
157
160
  context and its own isolated workspace at the recorded review base (a verify
158
161
  sidecar in reconstructed mode, or the supplied combined checkout in immutable
@@ -166,9 +169,11 @@ mode). Every Wave mode rule above applies to both lenses.
166
169
  contract`.
167
170
  - **Adversarial** — logical task name
168
171
  `review_wave_<wave>_cycle_<cycle>_adversarial`; stages
169
- `.project/review/wave-N.cycleC.adversarial.md`. Try to kill the work:
170
- security holes, unhandled edge cases, failure modes, data-loss and
171
- concurrency risks, missing error handling. Record `Lens: adversarial`.
172
+ `.project/review/wave-N.cycleC.adversarial.md`. Exercise failure paths within
173
+ the agreed contract, including its required security, data-loss, concurrency,
174
+ and error-handling behavior. Every blocking finding still needs a named
175
+ requirement and checked failure or missing required proof. Do not invent
176
+ additional requirements. Record `Lens: adversarial`.
172
177
 
173
178
  The wave passes only when both lenses return `pass`; any `blocked` lens
174
179
  blocks the wave.
@@ -1,6 +1,7 @@
1
1
  # Reviewer role
2
2
 
3
- Verify written GSD Path expectations and block failures. Never fix code.
3
+ Validate that the agreed work functions. Block contract failures or missing
4
+ required evidence. Never search for improvements or fix code.
4
5
 
5
6
  ## Brief contract
6
7
 
@@ -36,7 +37,17 @@ Resolve sibling links against this role file's directory.
36
37
 
37
38
  - When `GSD_PATH_JEV=1`, wave and final reviewers follow the optional
38
39
  [Jev evidence screening procedure](jev-review.md) for uncovered criteria.
39
- - Review written expectations, not preferences or alternate designs.
40
+ - Use the written acceptance, interface, success, edge, prohibition, and
41
+ surface contracts as the complete review scope. Block only on a named
42
+ unmet requirement with checked evidence, or the specific missing evidence
43
+ needed to prove it. Passing tests alone do not prove a required walkthrough.
44
+ - Do not search for improvements, alternate designs, speculative hardening,
45
+ or unrelated edge cases. Do not turn these into findings or fix tasks.
46
+ A clean pass is a complete result; no finding quota applies.
47
+ - On re-review, check repaired failures and passes affected by the repair.
48
+ Reuse settled evidence for unaffected criteria; do not reopen them or
49
+ introduce new requirements. An observed regression against the unchanged
50
+ contract still blocks. Stop when every applicable claim is proven.
40
51
  - Treat an Interface contract violation as a failed criterion, citing the
41
52
  contract line and the offending diff hunk.
42
53
  - Require checked evidence for every verdict.
@@ -1461,6 +1461,9 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1461
1461
  f"You are the reviewer for GSD Path wave {wave}, cycle {cycle}; logical task name "
1462
1462
  f"{state['task_id']}. Mode: wave" + (f"; lens: {lens}." if lens else "."),
1463
1463
  f"Read the reviewer role brief first and follow it exactly: {options.role_brief}",
1464
+ "Validate the agreed acceptance contract. "
1465
+ "Block only on a named unmet requirement or missing required evidence. "
1466
+ "Do not search for improvements or expand the agreed contract.",
1464
1467
  f"Template (use only this): {options.template}",
1465
1468
  f"AGENTS.md: {agents if agents.exists() else 'absent'}",
1466
1469
  f"Repository root, read-only: {primary}",
@@ -1478,6 +1481,8 @@ def review_brief(state: Dict[str, object], options: argparse.Namespace, primary:
1478
1481
  f"landing commit {task['commit']}")
1479
1482
  if previous is not None:
1480
1483
  lines.append(f"Previous cycle review to re-check: {previous}")
1484
+ lines.append("Re-check repaired failures and affected passes only. "
1485
+ "Reuse settled evidence for unaffected criteria.")
1481
1486
  if options.repair_evidence:
1482
1487
  lines.append(f"Repair evidence receipt (re-review after a proven repair): {options.repair_evidence}")
1483
1488
  if final_scope:
@@ -5372,16 +5372,6 @@ def _committed_ship_active(repo: Path) -> bool:
5372
5372
  return fields.get("phase") == "ship" and fields.get("status") == "active"
5373
5373
 
5374
5374
 
5375
- # The STATE Log tail that sanctions a build checkpoint past a HEAD that is
5376
- # still ship/active: the blocked final review went through the patch plan
5377
- # (reopened, then approved) and build started again (#526).
5378
- _PATCH_REENTRY_LOG = (
5379
- ("plan", "patch plan reopened"),
5380
- ("plan", "patch plan approved"),
5381
- ("build", "build started"),
5382
- )
5383
-
5384
-
5385
5375
  def _patch_reentry_build_active(repo: Path) -> bool:
5386
5376
  """True when the worktree STATE is the sanctioned patch-re-entry build.
5387
5377
 
@@ -5389,8 +5379,12 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5389
5379
  (ship/active) on purpose: the patch plan runs uncommitted and the patch
5390
5380
  build's own checkpoint commits the artifacts (SHIP.md). This reads the
5391
5381
  worktree STATE the checkpoint is about to commit and accepts only the
5392
- documented sequence — a hand-flipped build/active during final review
5393
- carries no such Log tail and stays refused (#429, #526).
5382
+ documented shape: the Log ends with the build restart, the event before
5383
+ it closes the plan stay with the patch approval, and that stay opened
5384
+ with `patch plan reopened` — a resumed planner logs `patch planning
5385
+ blocked` and `planning resumed` inside the same stay (#531). A
5386
+ hand-flipped build/active during final review carries no such Log tail
5387
+ and stays refused (#429, #526).
5394
5388
  """
5395
5389
 
5396
5390
  state = repo / ".project" / "STATE.md"
@@ -5410,10 +5404,20 @@ def _patch_reentry_build_active(repo: Path) -> bool:
5410
5404
  match = re.fullmatch(r"- \d{4}-\d{2}-\d{2} — (\S+) — (.+)", line)
5411
5405
  if match:
5412
5406
  events.append((match.group(1), match.group(2)))
5413
- # The sanctioned sequence appears in order, as the Log tail of this
5414
- # milestone's patch loop; the final event must be the build restart.
5415
- last = len(_PATCH_REENTRY_LOG)
5416
- return len(events) >= last and tuple(events[-last:]) == _PATCH_REENTRY_LOG
5407
+ # The final event must be the build restart, the event before it must
5408
+ # close the plan stay with the patch approval, and that stay must open
5409
+ # with the reopen; every plan event between them (a blocked, resumed
5410
+ # planner) stays inside the run (#531).
5411
+ if len(events) < 2 or events[-1] != ("build", "build started"):
5412
+ return False
5413
+ if events[-2] != ("plan", "patch plan approved"):
5414
+ return False
5415
+ stay = 0
5416
+ for phase, _event in reversed(events[:-1]):
5417
+ if phase != "plan":
5418
+ break
5419
+ stay += 1
5420
+ return events[-(stay + 1)] == ("plan", "patch plan reopened")
5417
5421
 
5418
5422
 
5419
5423
  def checkpoint(