| name | review-change |
| position | end |
| description | Review an open change thoroughly and against something outside the change itself: assess what work categories the diff contains, resolve each category's review treatment from the review-knowledge memory shelf, review each through its layers (objective linters, then design-grounding from committed sources for design-bearing categories), consolidate findings that each cite their basis, and stop at one decision gate resolved per gate-config — the reviewer owns the approve/reject verdict when the gate is on; when off the computed recommendation is recorded and posted as a clearly marked harness verdict. The gate (third step) of the end sequence in the ProductOS command model. Use when a PR is ready to be reviewed and a verdict is needed. |
| user-invocable | true |
review-change
Review an open change so the merge decision rests on something outside the change. Assess
the work categories the diff contains, resolve each category's treatment from the
review-knowledge memory shelf, review each through up to two layers (objective linters, then
design-grounding for design-bearing categories), consolidate findings that each cite a basis,
and stop at one decision gate resolved per gate-config: the reviewer owns the verdict when
the gate is on; when off, the computed recommendation becomes the decision, marked as a
harness verdict — either way it is posted to the PR.
Pipeline position: end (third step of the end sequence: commit-change →
propose-change → review-change → merge-change). The D2 pipeline-position rule injects this
sequence into any play declared position: end. Independent, invokable play; ordering is
enforced by pre-flight (an open PR must exist).
Compiled From
This play was compiled from the review-change ICE (reference/ice.md) by play-editor
(#443 redesign; #467 Batch C gate ruling; #484 scripted chain; #496 grounding fan-out). Intent defines constraints (C1–C11) and failure
conditions (F1–F12); the expectation defines success scenarios (S1–S6), a Done means
(D1–D3, baked to stop-condition.yaml), and one recovery entry per failure condition.
To modify this play, update reference/ice.md and recompile with play-editor.
Do NOT edit this file manually — it is a compiled artifact.
Role
You are the orchestrator. You own the workflow, the step order, and the one decision gate.
You delegate the agentic assessment and the design-grounding to change-reviewer and the
standards linter to quality-auditor — genuine judgment, via JSON contracts over files on
disk. The mechanical PR/host I/O (context bind, verdict post) runs in bundled scripts, not
an agent (C10, #484). You presume no work categories and no review
treatment: the categories are assessed every run, and each category's treatment is resolved
from the knowledge/review/ shelf. You run only the layers and steps that apply to the
categories present. You never invent the verdict — you compute a recommendation; the gate
resolution (C8) decides who owns the decision: the human when the gate is on, the
recommendation itself (recorded as a harness verdict) when it is off.
The guiding rule: the change under review is never its own standard.
Forbidden: presuming or hardcoding a category list or a review treatment; grounding a
design principle in the branch's own new content; running a full-repo scan (reads outside the
diff are allowed only to reconstruct committed grounding, and are read-only);
auto-deciding the verdict while the gate resolves on; recording an off-gate decision that
differs from the computed recommendation, or posting any decision that does not name its
decider (harness vs human); leaving a verdict silent or unposted; reporting a finding with
no cited basis.
Agent boundaries:
| Agent | Domain | Skill/script it invokes | Phases | Role type |
|---|
change-reviewer | (Assessment) assess work categories from the diff; (Review) design-ground one design-bearing category from committed sources — dispatched once per design-bearing category as a concurrent read-only fan-out (C11) | reads knowledge/review/ shelf; git show <base>:<path> | Assessment, Review | Domain |
quality-auditor | Run the standards linter (quality-check-scoped) against the diff for the standards-driven categories | quality-check-scoped | Review | Domain |
The mechanical PR/host I/O has no agent (C10): fetch_pr_context.py binds the PR context
(Step 1) and post_verdict.py posts the decision + commits the run artifacts (Step 6), both
via platform_adapter.py.
Domain agents: 2 (change-reviewer, quality-auditor) — change-reviewer is dispatched
once for assessment and then once per design-bearing category for grounding, in one
concurrent batch (C11, standards/rules/concurrent-fanout.md). The verdict recommendation
is a deterministic script; the verdict decision follows the gate resolution — the human's
when the gate is on, the recommendation recorded as a harness verdict when it is off (C8).
Pre-flight
| Check | Constraint | Action on Failure |
|---|
Resolve working base + config (.garura/core/config.yaml) | — | Hard halt |
| An open PR exists for the branch | — | Hard halt |
Platform CLI available (gh) | C8 | Hard halt |
Resolve standards set + review-knowledge shelf path via standards_order / ltm | C2 | Hard halt |
Fetch PR diff + changed_paths + base ref (the only files in scope) | C5 | Hard halt |
Resolve the deterministic pre-flight facts with the bundled resolver — config tokens,
branch, issue, evidence_record:
python3 scripts/preflight.py --play review-change \
--config .garura/core/config.yaml --branch "$(git branch --show-current)"
Right after the resolver, record the session identity stamp's start marker (#463 — soft-fail, never a halt):
python3 scripts/session_stamp.py --phase start \
--marker "{stm_base}{issue}/status/session-stamp-review-change.json" \
--cwd "$(pwd)" --branch "$(git branch --show-current)"
The open-PR check and gh availability are live host reads; the standards set, the
review-knowledge shelf path, and the PR diff/changed_paths/base ref are resolved by the
bundled fetch_pr_context.py (Step 1, via platform_adapter.py) — no agent (C10). Record
the resolved shelf path, the standards set, the PR's changed_paths, and the base ref;
everything downstream is bounded to those paths.
Task DAG
Create ALL tasks immediately after resolving the working base — before any domain work.
The play owns this DAG; agents must not edit its top-level tasks.
[T1] Bind PR Context blockedBy: []
[T2] Assess Categories blockedBy: [T1]
[T3] Review Per Category (layers) blockedBy: [T2]
[T4] Consolidate + Recommend Verdict blockedBy: [T3]
[T5] Decision Gate (config-resolved) blockedBy: [T4]
[T6] Post Decision to PR blockedBy: [T5]
[T7] Scenario Validation blockedBy: [T6]
[T8] Close blockedBy: [T7]
Mark each task in-progress before its step and completed right after its eval passes. No
runtime reordering. On resume, skip completed and reset in-progress to pending.
Workflow
Phase: Assessment
Step 1 — Bind PR Context · Owner: play (script) · Depends on: pre-flight
Run the bundled fetch_pr_context.py — it fetches the PR diff/changed-paths/base-ref (via
platform_adapter.py) and binds standards_order + the resolved knowledge/review/ shelf
path from config into context.yaml. No agent (C10). Standards resolution per finding is
owned downstream by quality-check-scoped; this step binds the diff, the changed paths, the
base ref, the standards_order, and the review-shelf path:
python3 scripts/fetch_pr_context.py --config .garura/core/config.yaml \
--out-context "<working>/context.yaml" --out-diff "<working>/pr.diff"
context.yaml records standards_order, the review_shelf path, changed_paths, and
base.
Step 2 — Assess Categories · Owner: change-reviewer · Depends on: Step 1
The agent reads the diff and derives the work categories actually present — judging each
changed file by its content, consulting the knowledge/review/ shelf to recognise seeded
categories but never limited to them. It writes categories.yaml: each present category, the
changed paths that evidence it, and the governing playbook id (or null + "playbook missing"
for a new category).
{
"task": "assess the work categories present in the diff; cite changed-path evidence and the governing playbook",
"inputs": { "context": "<working>/context.yaml", "diff": "<working>/pr.diff",
"review_shelf": "<resolved>/knowledge/review/" },
"outputs": { "categories": "<working>/categories.yaml" }
}
SE-1 (F1/C1): every category in categories.yaml cites the changed paths that put it
there, and the set was derived from the diff — no presumed/hardcoded category list was used
(an absent category is simply not listed).
Phase: Review
Step 3 — Review Per Category · Owner: play (dispatch) · Depends on: Step 2
For each category in categories.yaml, resolve its treatment from its knowledge/review/
playbook, then run only the layers that apply:
- Layer 1 — linters. For the standards-driven categories (code, config, tests, docs-prose)
the play dispatches
quality-auditor to run quality-check-scoped against the diff →
quality-findings.yaml. For harness/memory the play runs the bundled structural linters the
playbook names (lint_play.py, lint-components) and folds their output into findings. For
categories whose linter is a known gap (ADRs, config-map path-existence), the play performs
the playbook's objective checks and records the basis. Where a category has a runnable
check (a test suite, a language linter), the play executes it — it is not merely read.
- Layer 2 — design-grounding (concurrent read-only fan-out, C11). Take the design-bearing
categories from
categories.yaml (harness, memory, any new design-bearing category) and
dispatch one change-reviewer per design-bearing category in a single concurrent batch
(one message, N dispatches — concurrent read-only fan-out: each grounds only its own category
from committed sources, writes only its own design-findings-<category>.yaml, no grounding
agent depends on another; the safety conditions hold and the batch is joined before Step 4
reads any output — see standards/rules/concurrent-fanout.md). Each agent reconstructs its
category's principles from committed sources (base ref, docs/philosophy/**, docs/adr/**,
memory/standards/rules/**) and checks conformance; grounding reads are read-only and never
from diff-added content. The batch is bounded (the design-bearing set fixed by Step 2) and its
outputs are collected in a stable category order, so the result is identical to a serial run.
A single design-bearing category is a fan-out of width one.
A category whose categories.yaml entry is absent has its layers skipped — that is the expected
path, not a failure.
One grounding dispatch per design-bearing category <cat>, all sent as one concurrent batch:
{
"task": "design-ground ONLY the '<cat>' category from committed sources; emit conformance findings",
"inputs": { "context": "<working>/context.yaml", "categories": "<working>/categories.yaml",
"category": "<cat>", "diff": "<working>/pr.diff" },
"outputs": { "design_findings": "<working>/design-findings-<cat>.yaml" }
}
The standards linter (a single dispatch across all standards-driven categories):
{
"task": "run the standards linter against the diff for the standards-driven categories",
"inputs": { "context": "<working>/context.yaml", "categories": "<working>/categories.yaml" },
"outputs": { "quality_findings": "<working>/quality-findings.yaml" }
}
SE-2 (F2/C2): each reviewed category's treatment is sourced from its knowledge/review/
playbook (the record cites the playbook id) — no treatment is carried in the play body.
SE-3 (F3/C3): the layers executed equal the union of the applicable layers for the
categories present — no layer ran for an absent category, and no applicable layer was skipped.
SE-4 (F4/C4): every grounded principle across the design-findings-<category>.yaml set
cites a committed/external source; none cites a diff-added file (the branch is not its own standard).
SE-5 (F5/C5): every path read for review is within changed_paths, except grounding reads
which are read-only and committed — no full-repo scan ran.
SE-7 (F7/C7): for each in-scope category with a runnable check, the check was executed and
its result recorded; none was merely read.
SE-12 (F12/C11): design-grounding ran as a concurrent read-only fan-out — the count of
grounding dispatches equals the count of design-bearing categories in categories.yaml; each
wrote only its own design-findings-<category>.yaml (distinct paths, no overlap); the batch was
joined before Step 4 read any of them; and the collected result is order-stable (a serial re-run
would produce the same consolidated findings).
Phase: Decision
Step 4 — Consolidate + Recommend Verdict · Owner: play (script) · Depends on: Step 3
The play assembles its agents' outputs — quality-findings.yaml, the joined
design-findings-<category>.yaml set (read in stable category order after the fan-out barrier),
and any bundled-linter findings — into one findings.yaml grouped by category and severity — every
finding already classified P1–P4 (by quality-check-scoped for standards findings, by the
pr.md taxonomy for design findings) and carrying a cited basis. It then computes the
recommended verdict — a fixed rule, no agent:
python3 scripts/compute_verdict.py --findings <working>/findings.yaml --threshold <conf>
It emits recommended_verdict.yaml (recommendation + reason + cited blocking findings +
counts): reject if any P1 finding (or a runnable suite is red), otherwise approve.
This is an input to the human gate, not the decision.
SE-6 (F6/C6): every finding in findings.yaml carries a P1–P4 class and a cited basis
— a linter rule id or a grounded principle with its committed source.
Step 5 — Decision Gate (class: standard) · Owner: play · Depends on: Step 4
This checkpoint is a config switch per standards/rules/gate-config.md (C8, #466/#467):
resolve gates.plays.review-change → gates.classes.standard → gates.default
(absent ⇒ on). Per the #467 ruling gates.plays.review-change is off; flipping the
config back to on restores the human wait unchanged. review-pr.bypass remains a
SEPARATE, pre-existing config (whether a reject blocks the downstream merge), untouched
by this switch.
- On — the human decides. Present, in plain language: the categories assessed; for
each design-bearing category, the principles grounded and their committed sources; the
consolidated findings grouped by category and severity, each with its basis; and the
recommended verdict with its reason. Then output the summary and wait for the
reviewer's typed approve or reject (do NOT use AskUserQuestion; do NOT proceed on the
recommendation alone). Record the reviewer's decision verbatim to
decision.yaml
(decided_by: human).
- Off — the recommendation becomes the decision. Do not wait. Record
gate skipped by config (gates.plays.review-change) as a Checkpoint Decisions row in
the evidence. Write decision.yaml directly from recommended_verdict.yaml:
decided_by: harness, the recommendation verbatim, and the citing (blocking)
findings. A reject outcome stands exactly as a human reject would — fix the cited
findings and re-raise. The verdict is still never silent and never unposted (C9).
Step 6 — Post Decision to PR · Owner: play (script) · Depends on: Step 5
Assemble the decision comment (decision + the cited findings + routing) into a file — the
comment ALWAYS names its decider: a human decision is posted as the reviewer's verdict; an
off-gate decision leads with Harness verdict (gate off per gates.plays.review-change): <decision> so no reader mistakes it for a human review (C8, F10). Then run the bundled
post_verdict.py — it posts the comment (via platform_adapter.py), writes
review/posted.json {posted: true, comment_url}, and commits+pushes the review run
artifacts, so the PR updates with its own review record. No agent (C10):
python3 scripts/post_verdict.py --config .garura/core/config.yaml \
--pr-number "<pr number>" --comment-file "<working>/decision-comment.md" \
--issue <issue> --artifacts-dir "{stm_base}{issue}/review/" \
--out "<working>/posted.json"
Whether a reject hard-blocks the downstream merge is governed by config
(review-pr.bypass), unchanged from prior behavior. A verdict rendered AND posted counts as
done regardless of approve/reject (C9).
SE-8 (F8/C8): the recommended verdict was computed; when the gate resolved on, the
recorded decision equals the reviewer's typed input; a verdict comment authored by this
run exists on the PR after the step.
SE-9 (F9/C9): posted.json reads posted: true with a comment URL; the run artifacts
are on the remote branch; the stop-condition verdict reads held before the close may read
COMPLETED.
SE-10 (F10/C8): when the gate resolved off, decision.yaml reads decided_by: harness
and equals the computed recommendation verbatim with its citing findings, and the posted
comment identifies its decider (harness vs human).
SE-11 (F11/C10): the PR context bind (Step 1) and the verdict post + artifact
commit/push (Step 6) ran as the bundled fetch_pr_context.py / post_verdict.py (via
platform_adapter.py), not an agent dispatch — no repo-orchestrator was invoked for the
mechanical PR/host work.
Phase: Scenario Validation
Step 7 — Scenario Evals · Owner: play · Depends on: Step 6
- SCE-1 (S1 — mixed PR): the assessed category set reflects the diff's content; every
present category ran its applicable layers; no absent-category layer ran; posted.json
records the comment URL; the run artifacts are committed and pushed to the branch; the
stop-condition verdict reads held.
- SCE-2 (S2 — single-kind PR): only the applicable layers ran; design-grounding and test
execution were skipped — not failed — when their categories were absent; posted.json
records the comment URL; the run artifacts are committed and pushed to the branch; the
stop-condition verdict reads held.
- SCE-3 (S3 — external grounding): every grounding source recorded is committed/external;
none is a diff-added file.
- SCE-4 (S4 — blocking finding): with a P1 finding, the recommended verdict is reject
citing it; the decision followed the gate resolution (human's input when on; the harness
reject, marked as such, when off); the posted decision equals the recorded decision and
names its decider.
- SCE-5 (S5 — cited basis): every finding in the consolidated report names a linter rule
or a grounded principle as its basis.
- SCE-6 (S6 — multi-category grounding): when the diff holds more than one design-bearing
category, the number of grounding dispatches equals the number of design-bearing categories,
each wrote only its own
design-findings-<category>.yaml, the batch was joined before
consolidation read any of them, and the consolidated result is order-stable.
Phase: Evidence & Close
Step 8 — Close · Owner: play · Depends on: Step 7
Run the Standard Play Close. Evidence recording is play-only and config-gated per the D1
evidence rule (standards/rules/evidence-recording.md).
evidence_template=$(cat "${ltm_project_target}standards/templates/evidence-file.md")
delivery_template=$(cat "${ltm_project_target}standards/templates/delivery-report.md")
ts=$(date -u +%Y%m%d-%H%M%S)
evidence_dest="${evidence_base}${ts}.md"
mkdir -p "$(dirname "$evidence_dest")"
session_stamp=$(python3 scripts/session_stamp.py --phase close \
--marker "${stm_base}${issue}/status/session-stamp-review-change.json")
python3 scripts/check_stop_condition.py \
--manifest "<play-dir>/stop-condition.yaml" \
--base "${stm_base}${issue}/" \
--out "${stm_base}${issue}/status/stop-condition-review-change.yaml"
sc_exit=$?
Step C0 — bind the verdict. sc_exit == 0 (held) permits status: COMPLETED.
Anything else closes HALTED with exit_reason: stop_condition_unmet and the evidence's
Stop Condition section names every unmet clause. An unevaluable verdict is never a pass.
Step C1 — Write evidence file. Gated by the resolved evidence.record flag (global +
per-play evidence.plays.review-change; first match wins, absent ⇒ record). When false,
skip the write and record evidence skipped (record=false) in the report's pointer line.
Otherwise fill the evidence-file.md slots (play review-change, run_id
review-change-${ts}, issue, started_at/completed_at, status per C0, exit_reason; artifacts
produced: context.yaml, categories.yaml, quality-findings.yaml, design-findings.yaml,
findings.yaml, recommended_verdict.yaml, decision.yaml, posted.json (with the PR
comment URL), the stop-condition verdict; step/scenario eval results; the recorded decision
(with its decided_by) as the terminal status; checkpoint decisions (incl. any
gate skipped by config row);
commit reference = the run-artifacts commit SHA; the session identity stamp fields from
$session_stamp (#463): session_id, ledger_file, ledger_start_offset, ledger_end_offset (null
when unresolved — never blocks the close); and stop_condition per C0 with the Stop Condition
section filled) and write to $evidence_dest. Do NOT hand-author the body.
Step C2 — Render delivery report. Also render the Next line: resolve this play in standards/rules/pipeline-next.md and emit **Next:** /<command> — <why>. Or run /next to see all recommended actions. (only /next pointer, or omit, when the mapped command is null), per play-close.md. Fill the delivery-report.md slots and output the
report: ## review-change Delivered — #${issue} (lead with the human's decision), the Run
Summary table, the Pipeline Steps table from the task DAG, the Artifacts Produced table, Next
Steps (on approve: run merge-change; on reject: fix the cited findings and re-raise), and a
pointer to $evidence_dest. Always emitted; never gated.
Scenario Validation
| Scenario | Persona | Eval |
|---|
| S1 — mixed PR | reviewer | SCE-1 |
| S2 — single-kind PR | reviewer | SCE-2 |
| S3 — external grounding | reviewer | SCE-3 |
| S4 — blocking finding | reviewer | SCE-4 |
| S5 — cited basis | reviewer | SCE-5 |
| S6 — multi-category grounding | reviewer | SCE-6 |
Recovery
| For | Trigger | Direction | Handoff |
|---|
| F1 | categories presumed or hardcoded | re-run the category assessment from the diff and discard any presumed list | autonomous |
| F2 | treatment taken from the play body | re-resolve the category's treatment from the knowledge/review/ shelf | autonomous |
| F3 | a layer ran for an absent category, or an applicable layer was skipped | recompute applicability from the assessed categories — skip absent-category layers, run every applicable one | autonomous |
| F4 | grounding drawn from the branch's own new content | re-ground the design from committed/external sources only and re-check conformance | autonomous |
| F5 | the review expanded beyond the diff | re-scope to the diff; keep any outside reads read-only and grounding-only | autonomous |
| F6 | a finding has no cited basis | attach the finding's basis (linter rule or grounded principle) or drop the finding | autonomous |
| F7 | a runnable check was read but not executed | execute the check and fold its result into the findings | autonomous |
| F8 | the verdict was auto-decided while the gate was on, or the decision was not posted | hold at the human gate, record the reviewer's decision verbatim, and post it to the PR | human |
| F9 | the run is about to close COMPLETED with the Done means unmet (verdict never posted, posted.json or run artifacts missing) | post the verdict / fix the run state (write posted.json, commit+push the run artifacts), then re-evaluate the stop condition; the close stays HALTED until the verdict reads held | autonomous |
| F10 | with the gate off, decision.yaml differs from the computed recommendation, or the posted comment does not identify its decider | rewrite decision.yaml from recommended_verdict.yaml (decided_by: harness, recommendation verbatim, citing findings) and re-post the comment with the decider named | autonomous |
| F11 | a mechanical PR/host op (context bind, or verdict post + artifact commit/push) ran through an agent instead of its bundled script | route it through fetch_pr_context.py / post_verdict.py (via platform_adapter.py) and remove the agent dispatch | autonomous |
| F12 | design-grounding ran as a serial monolithic pass, or a grounding agent crossed category scope / wrote a shared output, or the batch wasn't joined before consolidation | re-dispatch grounding as a concurrent read-only fan-out — one read-only change-reviewer per design-bearing category, each scoped to its category and its own design-findings-<category>.yaml, joined before consolidation | autonomous |
Pause and Resume
Steps run top to bottom. On entry, resolve the PR from the branch, check the status
marker, skip completed steps, reset any in-progress step to pending, and continue. When the
gate resolves on, the decision gate (Step 5) is never auto-resolved on resume — if it has
not been answered, re-present and wait; when it resolves off, resume re-derives the
decision from the recommendation exactly as a first pass would. A re-run re-posts the
current decision rather than adding a conflicting second one.
Compilation Metadata
| Field | Value |
|---|
| fingerprint | sha256:b4adce1338cabd935698234cf8157be971f9e8c589d48e2f5865733c99167cdd (of reference/ice.md) |
| compiled_by | play-editor (#466 Batch A; #467 Batch C; #484 scripted chain; #496 grounding fan-out) |
| pipeline_position | end |
| workflow_structure | A (multi-agent; agentic assessment → concurrent read-only design-grounding fan-out (one agent per design-bearing category) → consolidation; config-resolved verdict gate; gated close) |
| stop_condition | stop-condition.yaml (D1–D3), gate live at Step C0 |
| domain_agents | 2 (change-reviewer — assessment ×1, grounding ×N design-bearing categories in a concurrent batch; quality-auditor) |
| utility_agents | 0 (#484 — mechanical PR/host I/O moved to bundled scripts) |
| skills_reused | quality-check-scoped, lint_play.py, lint-components |
| knowledge_consumed | knowledge/review/ (category playbooks); standards/rules/pr.md (severity taxonomy); standards/rules/concurrent-fanout.md (Layer-2 fan-out); standards_order set |
| scripts | 7 (preflight.py — pre-flight facts; compute_verdict.py — recommended verdict over classified findings; check_stop_condition.py — Done-means gate; session_stamp.py — #463 identity stamp; platform_adapter.py — code-host adapter; fetch_pr_context.py — bind PR context; post_verdict.py — post decision + commit artifacts) |
| step_evals | 12 (SE-1…SE-12) |
| scenario_evals | 6 (SCE-1…SCE-6) |
| recovery_entries | 12 (one per failure condition; F8 hands to the human gate, the rest autonomous) |
Recompile note (#496, grounding fan-out)
Intent change via reference/ice.md → recompile. Added C11 (design-grounding runs as a
concurrent read-only fan-out per standards/rules/concurrent-fanout.md: one read-only
change-reviewer per design-bearing category, dispatched as one batch after assessment fixes
the category set, joined before consolidation), F12, REC12, SE-12, and S6/SCE-6. Step 3 Layer 2
changed from a single monolithic grounding dispatch (design-findings.yaml) to a per-category
fan-out (design-findings-<category>.yaml, distinct output paths); Step 4 now joins and reads
that set in stable category order. The assess-first barrier (Step 2) and the consolidate-last
barrier (Step 4) are unchanged, so the outcome is identical to a serial run — concurrency changes
only wall-clock, and a single design-bearing category is a fan-out of width one. No new agent
(same change-reviewer, dispatched N times), no new script. domain_agents stays 2; step_evals
11 → 12; scenario_evals 5 → 6; recovery_entries 11 → 12. The fold of assessment into grounding
was considered and dropped (Occam: it saves only the ~30s assessment round-trip on single-category
PRs, cannot coexist with the fan-out, and would add a permanent branch — see #496). Fingerprint
recomputed over the edited ICE.
Recompile note (#484, scripted chain)
Intent change via reference/ice.md → recompile. Added C10 (mechanical PR/host I/O runs in
bundled scripts, never agent dispatch), F11, REC10, SE-11. Step 1 (bind PR context) and Step
6 (post verdict + commit/push artifacts) no longer dispatch repo-orchestrator; they run
fetch_pr_context.py and post_verdict.py via platform_adapter.py (canonical copies in
play-creator/references/, stamped here). The category assessment + design-grounding
(change-reviewer) and the standards linter (quality-auditor) STAY agent-run — genuine
judgment. Utility agents 1 → 0; scripts 4 → 7. Guarantees (categories assessed from the diff,
treatment from the shelf, grounding from committed sources, cited findings, human/harness
decision per gate, verdict posted) unchanged. Fingerprint recomputed over the edited ICE.
Direct-edit deviation note (#434, harness-led sweep)
Superseded by the #443 redesign below. The prior note recorded moving the verdict from an LLM
agent into compute_verdict.py; that script is retained, now as the recommendation engine
feeding the human gate.
Direct-edit deviation note (#443, review-change redesign)
Intent change (via reference/ice.md → play-editor, not a hand-edit): review-change moved from
a single-pass autonomous scripted gate to a thorough, category-aware, externally-grounded
review. The play now assesses work categories agentically (change-reviewer → categories.yaml),
resolves each category's treatment from the new knowledge/review/ memory shelf, reviews each
through up to two layers (objective linters; design-grounding from committed sources for
design-bearing categories), runs only the applicable layers, consolidates findings that each
cite a basis, and ends at one mandatory human gate that owns the approve/reject verdict.
compute_verdict.py is retained as the recommendation input (no longer the decision);
preflight.py is unchanged. New domain agent change-reviewer added (categorization +
design-grounding); quality-auditor reused for the standards linter. The fingerprint reflects
the rewritten reference/ice.md.
Direct-edit deviation note (#463, session identity stamp)
Non-intent change: the Standard Play Close gained the session identity stamp — scripts/session_stamp.py (canonical copy: play-creator/references/session_stamp.py) runs --phase start at pre-flight and --phase close in the close block; the evidence frontmatter carries session_id / ledger_file / ledger_start_offset / ledger_end_offset. Source of truth: standards/rules/play-close.md; play-creator emits the same lines so a rebuild converges. No constraint, failure, scenario, or eval changed; the fingerprint stands.
Recompile note (#467 Batch C, chain gates off)
Intent change via reference/ice.md → play-editor: the Step 5 gate constraint (C8) now
resolves per gate-config (per-play gates.plays.review-change off per the #467 ruling).
When off, the recommendation from compute_verdict.py BECOMES the recorded decision —
decision.yaml carries decided_by: harness, the recommendation verbatim, and the citing
findings; the comment posted to the PR is clearly marked as a harness verdict; a REJECT
stands exactly as a human reject would (fix the cited findings, re-raise;
review-pr.bypass untouched). The verdict is still never silent and never unposted (C9
unchanged). New F10 + REC10 + SE-10 guard the off path (decision ≡ recommendation; the
posted comment names its decider). Checkpoint machinery is kept: flipping the config back
to on restores the human wait unchanged. No new scripts. The fingerprint reflects the
updated ICE.