diff --git a/CHANGELOG.json b/CHANGELOG.json index d1fc670..aabbe5a 100644 --- a/CHANGELOG.json +++ b/CHANGELOG.json @@ -1,5 +1,47 @@ { "releases": [ + { + "version": "Unreleased", + "date": null, + "sections": { + "added": [ + { + "title": "`docs/multi-agent-handoff.md` — new `§Where inter-agent communication is recorded` section (routing table).", + "body": "Inserted between `§Field read/write ownership matrix` and `§Tool-permission matrix`. The field-ownership matrix declares **who may write each field**; the new routing table declares **which field carries each shape of inter-agent communication** — Implementer → Planner deltas (`implementation_notes[*]` with `type: planner_disagreement`), Reviewer → Implementer send-backs (`review_notes[*]` + phase reversion), Reviewer's reference-existence challenges (`review_notes[*]` + Implementer's reproduction in `implementation_notes[*]`), specialist audit findings (`parallel_groups[*].synthesis` for Reviewer parent), cluster-scoped returns (`implementation_clusters[*].status` + `cluster_id`-tagged `implementation_notes[*]`), supersede acts (new manifest with `supersedes`), escalations to humans (`escalations[*]`, `waivers[*]`), outbound briefings (`handoff_narrative` / `residual_risk` / `next_action`), long-running sub-agent mid-flight progress (D2 working-space path), supervision keep/discard/stop records (Tier-2 project memory), and sign-offs (`approvals[*]`). Cites only existing fields and rules; introduces no new artifact type, no new schema field, no new evidence enum. Closes the consolidation gap where a reader following a send-back, a discovery return, or an escalation had to reconstruct the routing per change. Includes an explicit `§What this table is not` callout: the table is not a license to introduce a free-form conversation log; every channel listed has a structured field, an owner, and a binding rule, and bundling them into a single flat artifact would erase the field decomposition the schema is built on." + }, + { + "title": "`docs/glossary.md` — new term `Agent loop` in `§Process terms`.", + "body": "The phrase \"agent loop\" appeared in four canonical files (`docs/runtime-hook-contract.md`, `docs/ci-cd-integration-hooks.md`, `docs/throughput-first-merge-philosophy.md`, `docs/diagrams.md`) as if defined, but no glossary entry pinned the term. The new entry defines it as the runtime cycle in which a tool-using agent reads context → emits action → observes result → repeats, names what binds on the loop normatively (phase progression, evidence emission, hook firing, role boundaries) versus what is bridge-layer (event-driven vs polling, single-threaded vs concurrent, sync vs async tool dispatch), enumerates termination triggers (stop conditions, iteration caps, Tree D escalation, runtime-imposed boundaries), and explicitly classifies the **loop-as-clock failure mode** (fire delegation → end turn → wait for tick → fire again, without canonical-role concurrent work) as the central pattern long-running-delegation D3 and `docs/anti-entropy-discipline.md` Rule \"Sweep agent runs 24/7\" reject from opposite directions. Pinning the definition in the glossary prevents the term from drifting independently across consumers and gives the four consuming files a single citation target rather than each implying its own definition." + }, + { + "title": "`skills/engineering-workflow/references/long-running-delegation.md` — new `§Mapping the runtime loop to phase boundaries` section.", + "body": "Added between `§Capability-category mapping` and `§Anti-patterns`. Maps the abstract D1 (checkpoint-bounded scope) / D2 (artifact-grounded progress) / D3 (canonical-role non-idle) disciplines onto a concrete agent loop without endorsing the failure modes the methodology rejects. Four sub-points: (a) where loop iterations meet phase boundaries (a phase advance is a single iteration; intra-phase iterations may fire Category B/C hooks but do not change `phase`); (b) where D2 writes happen on a loop tick (per useful-work iteration; canonical role's separate loop may tail the D2 path on its own iterations as part of its defined polling plan — two loops, one shared artifact path, never one loop polling the other agent); (c) termination triggers in priority order (stop conditions per `AGENTS.md §Stop conditions` → iteration caps per `application-driven-loop.md` and `fix-retest-loop.md` framed as **diagnostic budgets, not compute budgets** → Tree D escalation per `docs/decision-trees.md` → runtime-imposed boundaries); (d) explicit anti-pattern call-out classifying loop-as-clock as symmetric with `anti-entropy-discipline.md` \"Sweep agent runs 24/7\" and with `ai-operating-contract.md §11` fabrication-by-silence. Closes the dangling-term gap where multiple files used \"agent loop\" as a runtime primitive without normative content explaining how the methodology binds to it." + }, + { + "title": "`docs/runtime-hook-contract.md`, `docs/ci-cd-integration-hooks.md`, `docs/throughput-first-merge-philosophy.md`, `docs/diagrams.md` — back-pointers from each \"agent loop\" mention to the new glossary entry.", + "body": "One inline parenthetical link per file, on the first significant mention. `runtime-hook-contract.md:120` (prose-only refuse fallback, \"outside the agent loop\"); `ci-cd-integration-hooks.md:208` (runtime-vs-CI hook contrast, \"inside the agent loop\"); `throughput-first-merge-philosophy.md:14` (agent-velocity rationale, \"every block costs an agent loop iteration\"); `diagrams.md:227` (`See also` line on Stack Map diagram §6, where the `RUNTIME` node label uses the term). No substantive prose changed; only the dangling-term references resolved. Per `CLAUDE.md §5`, term changes propagate to all consumers in the same change." + }, + { + "title": "`skills/engineering-workflow/references/cluster-parallelism.md` — new `§Runtime isolation` section (Pattern C runtime enforcement layer).", + "body": "Existing §The core rule §1 declares file-disjoint scope at the schema level; the runtime mechanism that enforces the declaration was undefined, leaving three failure modes the schema cannot detect: races on files outside `scope_files` (lockfiles, build caches, `.git/index`), concurrent appends to shared manifest array fields, and merge-back ambiguity at fan-in. The new section names the discipline in three sub-sections: **Per-cluster exclusive write region** (each cluster's Implementer runs in an isolated working copy where only that cluster holds write capability; the methodology binds on the property — mutual write exclusion covering files outside `scope_files` as well as inside — not on the runtime mechanism, which is a bridge-layer choice per `docs/file-role-map.md`); **Manifest field collision rule** (each cluster's Implementer appends only entries tagged with its own `cluster_id` to shared array fields like `implementation_notes[]`; cross-cluster aggregation is the Planner's responsibility at §5 fan-in); **Merge-back ordering at fan-in** (three-rule priority: halt overrides → cluster_id-sorted assembly → cross-cluster gap-check first; determinism is the property so two Reviewers replaying the same fan-in produce byte-identical merged output). Includes a six-row failure-mode catalog enumerating concrete races (lockfile conflicts, build-cache poisoning, ambiguous notes attribution, git-commit collisions, shared `/tmp` contamination, parallel write-locks erasing the parallelism benefit). Closes the gap where `cluster-parallelism.md` had a declared invariant 1 (file-disjoint) but no operational discipline binding the declaration to runtime enforcement, leaving Pattern C's runtime safety implicit. Cross-cutting: §The core rule §1 explanation extended to point at the new section; §Why each invariant is needed gains a row distinguishing declared vs runtime-enforced disjointness; §Anti-patterns gains four rows (shared write region, untagged shared-array appends, premature merge before gap check, verification writes to shared OS path); §Relation to other documents updated to cite the new schema field." + }, + { + "title": null, + "body": "**`schemas/change-manifest.schema.yaml` (and generated `.json`) — new optional `implementation_clusters[*].isolation_root` field.** Declarative companion to the new §Runtime isolation section: a string field naming the cluster's exclusive write region (worktree path, container mount, scoped filesystem view). **Optional**, additive (existing manifests without the field validate unchanged); not part of the cluster's `required` list because not every runtime can produce a stable identifier (ephemeral container mounts, in-memory filesystems). When declared, gives the Reviewer a verifiable target (\"did this cluster's Implementer in fact write only within `isolation_root`?\"); when absent, the runtime-isolation property still binds but cannot be audited from the manifest alone. Field description cross-references `cluster-parallelism.md §Runtime isolation §Per-cluster exclusive write region` so a runtime bridge author landing in the schema can navigate to the binding rule. Backwards compatibility: existing 1.x manifests using `implementation_clusters` without `isolation_root` continue to validate; pre-1.30 manifests (without `implementation_clusters` at all) continue to validate." + } + ], + "changed": [ + { + "title": "`skills/engineering-workflow/references/cluster-parallelism.md §The core rule §1` — extended to name runtime-enforcement scope.", + "body": "Previously only declared \"no two clusters declare `scope_files` patterns that could resolve to the same file.\" Now adds: \"Declaration alone does not prevent races on files outside `scope_files` (lockfiles, build caches, `.git/index`) or on shared manifest array fields; runtime enforcement of the declaration lives in §Runtime isolation below.\" This is a normative scope expansion — invariant 1 now binds on both declaration and runtime enforcement, surfacing the operational gap the new section closes. The §Why each invariant is needed table also gains a row distinguishing the two enforcement layers." + }, + { + "title": "`skills/engineering-workflow/references/parallelization-patterns.md` §Phase applicability summary footnote — Pattern C disciplines list updated.", + "body": "The footnote naming Pattern C's disciplines previously listed \"file-disjoint clusters, discovery-halt-all-clusters, Reviewer cross-cluster gap check, `implementation_clusters` manifest field.\" Now also names \"runtime isolation per `cluster-parallelism.md §Runtime isolation`.\" This is a one-clause cross-reference addition — substantive Pattern C content remains in `cluster-parallelism.md` per `CLAUDE.md §5` (do not split SoT across multiple files)." + } + ] + } + }, { "version": "1.34.0", "date": "2026-04-29", diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e25391..fa01a21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,26 @@ Format inspired by Keep a Changelog; versioning policy in `VERSIONING.md`. ## [Unreleased] +### Added + +- **`docs/multi-agent-handoff.md` — new `§Where inter-agent communication is recorded` section (routing table).** Inserted between `§Field read/write ownership matrix` and `§Tool-permission matrix`. The field-ownership matrix declares **who may write each field**; the new routing table declares **which field carries each shape of inter-agent communication** — Implementer → Planner deltas (`implementation_notes[*]` with `type: planner_disagreement`), Reviewer → Implementer send-backs (`review_notes[*]` + phase reversion), Reviewer's reference-existence challenges (`review_notes[*]` + Implementer's reproduction in `implementation_notes[*]`), specialist audit findings (`parallel_groups[*].synthesis` for Reviewer parent), cluster-scoped returns (`implementation_clusters[*].status` + `cluster_id`-tagged `implementation_notes[*]`), supersede acts (new manifest with `supersedes`), escalations to humans (`escalations[*]`, `waivers[*]`), outbound briefings (`handoff_narrative` / `residual_risk` / `next_action`), long-running sub-agent mid-flight progress (D2 working-space path), supervision keep/discard/stop records (Tier-2 project memory), and sign-offs (`approvals[*]`). Cites only existing fields and rules; introduces no new artifact type, no new schema field, no new evidence enum. Closes the consolidation gap where a reader following a send-back, a discovery return, or an escalation had to reconstruct the routing per change. Includes an explicit `§What this table is not` callout: the table is not a license to introduce a free-form conversation log; every channel listed has a structured field, an owner, and a binding rule, and bundling them into a single flat artifact would erase the field decomposition the schema is built on. + +- **`docs/glossary.md` — new term `Agent loop` in `§Process terms`.** The phrase "agent loop" appeared in four canonical files (`docs/runtime-hook-contract.md`, `docs/ci-cd-integration-hooks.md`, `docs/throughput-first-merge-philosophy.md`, `docs/diagrams.md`) as if defined, but no glossary entry pinned the term. The new entry defines it as the runtime cycle in which a tool-using agent reads context → emits action → observes result → repeats, names what binds on the loop normatively (phase progression, evidence emission, hook firing, role boundaries) versus what is bridge-layer (event-driven vs polling, single-threaded vs concurrent, sync vs async tool dispatch), enumerates termination triggers (stop conditions, iteration caps, Tree D escalation, runtime-imposed boundaries), and explicitly classifies the **loop-as-clock failure mode** (fire delegation → end turn → wait for tick → fire again, without canonical-role concurrent work) as the central pattern long-running-delegation D3 and `docs/anti-entropy-discipline.md` Rule "Sweep agent runs 24/7" reject from opposite directions. Pinning the definition in the glossary prevents the term from drifting independently across consumers and gives the four consuming files a single citation target rather than each implying its own definition. + +- **`skills/engineering-workflow/references/long-running-delegation.md` — new `§Mapping the runtime loop to phase boundaries` section.** Added between `§Capability-category mapping` and `§Anti-patterns`. Maps the abstract D1 (checkpoint-bounded scope) / D2 (artifact-grounded progress) / D3 (canonical-role non-idle) disciplines onto a concrete agent loop without endorsing the failure modes the methodology rejects. Four sub-points: (a) where loop iterations meet phase boundaries (a phase advance is a single iteration; intra-phase iterations may fire Category B/C hooks but do not change `phase`); (b) where D2 writes happen on a loop tick (per useful-work iteration; canonical role's separate loop may tail the D2 path on its own iterations as part of its defined polling plan — two loops, one shared artifact path, never one loop polling the other agent); (c) termination triggers in priority order (stop conditions per `AGENTS.md §Stop conditions` → iteration caps per `application-driven-loop.md` and `fix-retest-loop.md` framed as **diagnostic budgets, not compute budgets** → Tree D escalation per `docs/decision-trees.md` → runtime-imposed boundaries); (d) explicit anti-pattern call-out classifying loop-as-clock as symmetric with `anti-entropy-discipline.md` "Sweep agent runs 24/7" and with `ai-operating-contract.md §11` fabrication-by-silence. Closes the dangling-term gap where multiple files used "agent loop" as a runtime primitive without normative content explaining how the methodology binds to it. + +- **`docs/runtime-hook-contract.md`, `docs/ci-cd-integration-hooks.md`, `docs/throughput-first-merge-philosophy.md`, `docs/diagrams.md` — back-pointers from each "agent loop" mention to the new glossary entry.** One inline parenthetical link per file, on the first significant mention. `runtime-hook-contract.md:120` (prose-only refuse fallback, "outside the agent loop"); `ci-cd-integration-hooks.md:208` (runtime-vs-CI hook contrast, "inside the agent loop"); `throughput-first-merge-philosophy.md:14` (agent-velocity rationale, "every block costs an agent loop iteration"); `diagrams.md:227` (`See also` line on Stack Map diagram §6, where the `RUNTIME` node label uses the term). No substantive prose changed; only the dangling-term references resolved. Per `CLAUDE.md §5`, term changes propagate to all consumers in the same change. + +- **`skills/engineering-workflow/references/cluster-parallelism.md` — new `§Runtime isolation` section (Pattern C runtime enforcement layer).** Existing §The core rule §1 declares file-disjoint scope at the schema level; the runtime mechanism that enforces the declaration was undefined, leaving three failure modes the schema cannot detect: races on files outside `scope_files` (lockfiles, build caches, `.git/index`), concurrent appends to shared manifest array fields, and merge-back ambiguity at fan-in. The new section names the discipline in three sub-sections: **Per-cluster exclusive write region** (each cluster's Implementer runs in an isolated working copy where only that cluster holds write capability; the methodology binds on the property — mutual write exclusion covering files outside `scope_files` as well as inside — not on the runtime mechanism, which is a bridge-layer choice per `docs/file-role-map.md`); **Manifest field collision rule** (each cluster's Implementer appends only entries tagged with its own `cluster_id` to shared array fields like `implementation_notes[]`; cross-cluster aggregation is the Planner's responsibility at §5 fan-in); **Merge-back ordering at fan-in** (three-rule priority: halt overrides → cluster_id-sorted assembly → cross-cluster gap-check first; determinism is the property so two Reviewers replaying the same fan-in produce byte-identical merged output). Includes a six-row failure-mode catalog enumerating concrete races (lockfile conflicts, build-cache poisoning, ambiguous notes attribution, git-commit collisions, shared `/tmp` contamination, parallel write-locks erasing the parallelism benefit). Closes the gap where `cluster-parallelism.md` had a declared invariant 1 (file-disjoint) but no operational discipline binding the declaration to runtime enforcement, leaving Pattern C's runtime safety implicit. Cross-cutting: §The core rule §1 explanation extended to point at the new section; §Why each invariant is needed gains a row distinguishing declared vs runtime-enforced disjointness; §Anti-patterns gains four rows (shared write region, untagged shared-array appends, premature merge before gap check, verification writes to shared OS path); §Relation to other documents updated to cite the new schema field. + +- **`schemas/change-manifest.schema.yaml` (and generated `.json`) — new optional `implementation_clusters[*].isolation_root` field.** Declarative companion to the new §Runtime isolation section: a string field naming the cluster's exclusive write region (worktree path, container mount, scoped filesystem view). **Optional**, additive (existing manifests without the field validate unchanged); not part of the cluster's `required` list because not every runtime can produce a stable identifier (ephemeral container mounts, in-memory filesystems). When declared, gives the Reviewer a verifiable target ("did this cluster's Implementer in fact write only within `isolation_root`?"); when absent, the runtime-isolation property still binds but cannot be audited from the manifest alone. Field description cross-references `cluster-parallelism.md §Runtime isolation §Per-cluster exclusive write region` so a runtime bridge author landing in the schema can navigate to the binding rule. Backwards compatibility: existing 1.x manifests using `implementation_clusters` without `isolation_root` continue to validate; pre-1.30 manifests (without `implementation_clusters` at all) continue to validate. + +### Changed + +- **`skills/engineering-workflow/references/cluster-parallelism.md §The core rule §1` — extended to name runtime-enforcement scope.** Previously only declared "no two clusters declare `scope_files` patterns that could resolve to the same file." Now adds: "Declaration alone does not prevent races on files outside `scope_files` (lockfiles, build caches, `.git/index`) or on shared manifest array fields; runtime enforcement of the declaration lives in §Runtime isolation below." This is a normative scope expansion — invariant 1 now binds on both declaration and runtime enforcement, surfacing the operational gap the new section closes. The §Why each invariant is needed table also gains a row distinguishing the two enforcement layers. + +- **`skills/engineering-workflow/references/parallelization-patterns.md` §Phase applicability summary footnote — Pattern C disciplines list updated.** The footnote naming Pattern C's disciplines previously listed "file-disjoint clusters, discovery-halt-all-clusters, Reviewer cross-cluster gap check, `implementation_clusters` manifest field." Now also names "runtime isolation per `cluster-parallelism.md §Runtime isolation`." This is a one-clause cross-reference addition — substantive Pattern C content remains in `cluster-parallelism.md` per `CLAUDE.md §5` (do not split SoT across multiple files). + ## [1.34.0] - 2026-04-29 Minor release adding a Claude Code bridge-layer Implementer variant (`agents/implementer-deep.md`, Opus + `xhigh` effort) plus a routing guide (`agents/README.md`) that lets the Planner escalate from the default Sonnet-tier Implementer to deeper reasoning on high-complexity tasks (`breaking_change.level` ≥ L3, Pattern C with non-trivial cross-cluster invariants, SoT patterns with high canonical-vs-consumer drift cost, Phase Re-entry from a prior `implementer` Discovery-loop). Also adds explicit `effort` declarations to the existing three canonical-role bridges (`planner.md`, `implementer.md`, `reviewer.md`). Closes the gap where the Planner had no formal way to route execution complexity to deeper reasoning while keeping the canonical methodology tool-agnostic — the variant lives entirely at the bridge layer per `CLAUDE.md` §Rule 2, the Change Manifest schema deliberately does not gain an `effort` field, and other runtimes (Codex / Cursor / Gemini / Windsurf) are unchanged. diff --git a/docs/ci-cd-integration-hooks.md b/docs/ci-cd-integration-hooks.md index ee0da14..795b396 100644 --- a/docs/ci-cd-integration-hooks.md +++ b/docs/ci-cd-integration-hooks.md @@ -205,4 +205,4 @@ Do not wire everything in at once. Suggested order: ## Relationship to runtime-layer hooks -This document defines **CI/CD-platform** hooks (fire on PR events, merge events). Its sibling, [`runtime-hook-contract.md`](./runtime-hook-contract.md), defines **agent-runtime** hooks (fire on tool use, response completion, commit). The two share the exit-code contract (`0 = pass`, `1 = fail`, `2 = warn`), so a rule implemented as a runtime hook can be lifted into a CI hook — and vice versa — with only the event-payload translation rewritten. Use the runtime contract when you want guardrails to fire *inside* the agent loop (pre-commit blocking, drift warnings on edit); use the CI contract when you want them to fire *after* the change leaves the agent (PR review, pre-merge). +This document defines **CI/CD-platform** hooks (fire on PR events, merge events). Its sibling, [`runtime-hook-contract.md`](./runtime-hook-contract.md), defines **agent-runtime** hooks (fire on tool use, response completion, commit). The two share the exit-code contract (`0 = pass`, `1 = fail`, `2 = warn`), so a rule implemented as a runtime hook can be lifted into a CI hook — and vice versa — with only the event-payload translation rewritten. Use the runtime contract when you want guardrails to fire *inside* the agent loop (see [`docs/glossary.md §Agent loop`](./glossary.md#agent-loop) for the runtime cycle these hooks fire on — pre-commit blocking, drift warnings on edit); use the CI contract when you want them to fire *after* the change leaves the agent (PR review, pre-merge). diff --git a/docs/diagrams.md b/docs/diagrams.md index 2a0cb94..413090c 100644 --- a/docs/diagrams.md +++ b/docs/diagrams.md @@ -224,7 +224,7 @@ graph TB The dashed arrows back into the execution and carrier layers show the **feedback direction**: when a guard fires, the fix happens inside the phase loop, not in the guard. Hooks do not edit manifests — they refuse to let incomplete ones proceed. -See also: [`AGENTS.md`](../AGENTS.md) §7 (multi-agent), [`docs/runtime-hook-contract.md`](./runtime-hook-contract.md) + [`docs/runtime-hooks-in-practice.md`](./runtime-hooks-in-practice.md) (runtime hooks — spec + how-to), [`docs/ci-cd-integration-hooks.md`](./ci-cd-integration-hooks.md), [`schemas/change-manifest.schema.yaml`](../schemas/change-manifest.schema.yaml) (canonical YAML) + [`schemas/change-manifest.schema.json`](../schemas/change-manifest.schema.json) (generated JSON mirror), [`reference-implementations/validator-{posix-shell,python,node}/`](../reference-implementations/) (three non-normative language references), [`examples/starter-repo/`](../examples/starter-repo/) for a working end-to-end instantiation. +See also: [`AGENTS.md`](../AGENTS.md) §7 (multi-agent), [`docs/glossary.md §Agent loop`](./glossary.md#agent-loop) (the runtime cycle the `RUNTIME` node fires inside), [`docs/runtime-hook-contract.md`](./runtime-hook-contract.md) + [`docs/runtime-hooks-in-practice.md`](./runtime-hooks-in-practice.md) (runtime hooks — spec + how-to), [`docs/ci-cd-integration-hooks.md`](./ci-cd-integration-hooks.md), [`schemas/change-manifest.schema.yaml`](../schemas/change-manifest.schema.yaml) (canonical YAML) + [`schemas/change-manifest.schema.json`](../schemas/change-manifest.schema.json) (generated JSON mirror), [`reference-implementations/validator-{posix-shell,python,node}/`](../reference-implementations/) (three non-normative language references), [`examples/starter-repo/`](../examples/starter-repo/) for a working end-to-end instantiation. --- diff --git a/docs/glossary.md b/docs/glossary.md index cc90262..7fde899 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -218,6 +218,16 @@ A single-file artifact recording **reusable knowledge that spans multiple change CCKNs have asymmetric timing: **query opportunistically** when a change's surfaces / libraries / external APIs overlap with topics catalogued in the CCKN directory (§When to query a CCKN; absent directory = no-op); **write during Phase 1** — at initial Investigate per §Ceremony scaling, or at re-entry after a Phase 4 Discovery loop per §Relation to Change Manifest §3. Phase 4 Discovery triggers re-entry; it does not itself write. Citing a stale CCKN (>12 months) without triggering the refresh obligation is the primary anti-pattern. +### Agent loop + +The runtime cycle in which a tool-using agent reads its input context, emits an action (text response, tool call, or sub-agent spawn), observes the result, and iterates until a termination condition fires. The loop is the **runtime substrate** on which every other methodology primitive operates — phase boundaries fire on specific iterations, hooks (`docs/runtime-hook-contract.md`) fire on specific tool-call events within the loop, sub-agent invocations are spawned and joined inside the canonical role's loop, and progress artifacts (long-running delegation D2 per `skills/engineering-workflow/references/long-running-delegation.md`) are written on iteration boundaries. + +The methodology binds on what the loop **does** (phase progression, evidence emission, hook firing, role boundaries) and not on the loop's runtime semantics (event-driven vs polling, single-threaded vs concurrent, synchronous vs asynchronous tool dispatch); specific runtime semantics are bridge-layer concerns per `docs/file-role-map.md §Where a new rule belongs`. Termination triggers are normative and apply across runtimes: stop conditions (`AGENTS.md §Stop conditions`), iteration caps (`skills/engineering-workflow/references/application-driven-loop.md` §iteration cap, `skills/engineering-workflow/phases/fix-retest-loop.md` §three-failure rule), Tree D escalation (`docs/decision-trees.md`), and runtime-imposed cache-window or session boundaries. + +A loop running solely as a polling clock — fire delegation, end turn, wait for next tick, fire again — without canonical-role concurrent work or a defined polling plan violates the canonical-role non-idle rule (long-running-delegation D3) and is the central failure mode `docs/anti-entropy-discipline.md §Rule "Sweep agent runs 24/7"` rejects. The agent loop is a cycle, not a scheduler; treating it as a clock collapses the methodology's evidence-and-progression discipline back into "narrate, hand off to the next tick, hope for convergence." + +Mapping the loop to phase boundaries, D2 progress writes, and termination triggers: `skills/engineering-workflow/references/long-running-delegation.md §Mapping the runtime loop to phase boundaries`. Capability requirements per runtime: same doc §Capability-category mapping. + ### Sub-agent invocation A single spawn-run-return cycle of a non-canonical sub-agent. One-shot: the invocation begins when the canonical role spawns it, ends when the sub-agent produces its structured return, and does not persist as a running process afterward. The canonical role must not treat a returned sub-agent as a long-lived process that needs cleanup or termination. diff --git a/docs/multi-agent-handoff.md b/docs/multi-agent-handoff.md index 9284213..f933c36 100644 --- a/docs/multi-agent-handoff.md +++ b/docs/multi-agent-handoff.md @@ -166,6 +166,36 @@ If there is disagreement: **open a new manifest + `supersedes`**, not overwrite --- +## Where inter-agent communication is recorded + +The field-ownership matrix above declares **who may write each field**. This routing table declares **which field carries each shape of inter-agent communication**, so a reader following a send-back, a discovery return, or an escalation can locate the binding artifact without reconstructing the routing per change. + +The table cites only existing fields and rules. No new artifact type, no new schema field, no new evidence enum is introduced — the channels exist; only the index was missing. + +| Communication shape | Sender → Receiver | Recorded in | Binding rule | +|---|---|---|---| +| Working brief at spawn time | Planner → Implementer | Task Prompt (six columns: goal / scope / input / expected output / acceptance criteria / boundaries) — non-manifest output, not persisted as canonical artifact | `§Task Prompt structure`; Pattern C cluster-scoped extension in `skills/engineering-workflow/references/cluster-parallelism.md §2` | +| Implementation delta from plan (annotation) | Implementer → Planner | `implementation_notes[*]` with `type: planner_disagreement` | `§Conflict resolution §Tier 1: annotate` | +| Implementation discovery return (escalation) | Implementer → Planner | `phase: implement → plan` reversion + `implementation_notes[*]` with `type: discovery` | `§Conflict resolution §Tier 2: escalate`; `docs/phase-gate-discipline.md §Rule 6 Phase Re-entry Protocol` | +| Substantive Phase 4 record + evidence | Implementer → Reviewer | manifest as state snapshot (specifically `implementation_notes[*]`, `evidence_plan.artifacts[*]`, `residual_risk` augment) | `§Pre-handoff self-check`; `docs/change-manifest-spec.md §State-snapshot discipline` | +| Review finding (send-back) | Reviewer → Implementer | `review_notes[*]` + `phase: review → implement` reversion | `§Anti-rationalization rules`; `docs/phase-gate-discipline.md §Rule 6` | +| Review finding (scope / plan defect) | Reviewer → Planner | `review_notes[*]` + `phase: review → plan` reversion | `§Conflict resolution §Tier 2: escalate` | +| Reviewer's reference-existence challenge | Reviewer → Implementer | `review_notes[*]` with the cited identifier; the Implementer's reproduction goes in `implementation_notes[*]` | `§Reference-existence sampling right` (line 134); `docs/ai-operating-contract.md §2a` | +| Specialist audit finding | Specialist → parent canonical role | `parallel_groups[*].synthesis` (Reviewer parent), `implementation_notes[*]` (Planner / Implementer parent), or a referenced CCKN | `§Composable specialist sub-agent roles §Output slot`; `skills/engineering-workflow/references/parallelization-patterns.md §Fan-in discipline` | +| Cluster-scoped completion / discovery return | Cluster Implementer → Planner | `implementation_clusters[*].status` transition + `implementation_notes[*]` tagged with `cluster_id` | `cluster-parallelism.md §Discovery-loop handling`; manifest field collision rule in `cluster-parallelism.md §Runtime isolation §Manifest field collision rule` | +| Re-do as fresh plan (entire premise wrong) | Reviewer → next-cycle Planner | New manifest with `supersedes: [prior_id]` + `supersede_reason` | `§Conflict resolution §Tier 3: supersede` | +| Escalation requiring human approval | Any AI role → human | `escalations[*]` (with `trigger`, `severity`); for waivers: `waivers[*]` with `approver_role: human` | `§Capability gating by risk level`; schema `escalations[*]`, `waivers[*]` | +| Outbound briefing to next operator (cross-session, cross-team) | Any role → next operator / future self | `handoff_narrative`, `residual_risk`, `next_action` | `docs/glossary.md §Handoff`; `skills/engineering-workflow/templates/handoff-prompt-template.md` | +| Long-running sub-agent mid-flight progress | sub-agent → its canonical role | session-scoped working-space path (D2 artifact, not a manifest field until promoted) | `skills/engineering-workflow/references/long-running-delegation.md §D2 Artifact-grounded progress` | +| Supervisory keep / discard / stop record | Canonical role → Reviewer (audit-time) | Tier-2 project-memory supervision log (referenced from `parallel_groups[*].supervision_log_ref` when declared) | `long-running-delegation.md §Supervision log` | +| Sign-off | Reviewer / human → next phase | `approvals[*]` (with `approver_identity`, `approver_role`, `signed_at`) | `§Reviewer §Additional required fields`; `§Capability gating by risk level` for `approver_role: human` requirements | + +**Reading the table.** Each row names a specific communication act, the field that records it, and the rule that binds the act. The table does not relax any existing rule — for example, the row "Cluster-scoped completion / discovery return" reuses the `cluster_id`-tagged append rule from `cluster-parallelism.md §Runtime isolation`, and the row "Escalation requiring human approval" reuses the `approver_role: human` requirement already specified in `§Capability gating by risk level`. The table consolidates the routing for navigability; the binding rule remains in the cited canonical source per `CLAUDE.md §5`. + +**What this table is not.** Not a free-form conversation log — every channel listed above is a **structured field with an owner** and a **binding rule that defines its lifecycle**. A request for an "agent dialog" log that bundles all of these into a single flat artifact would erase the field decomposition the schema is built on; resist that pressure. If a routing question is not answered by any row above, the answer is most likely a missing rule (open an issue) rather than a missing field. + +--- + ## Tool-permission matrix Field ownership (above) declares *which manifest fields* each role may write. This matrix declares *which capability categories* the host runtime must grant each role. It is the enforcement layer that makes role separation real rather than advisory — a Reviewer without write permission cannot "rubber-stamp then quietly patch," and a Planner without write permission cannot quietly drift into coding. diff --git a/docs/runtime-hook-contract.md b/docs/runtime-hook-contract.md index 82ad4f7..1bc1b3a 100644 --- a/docs/runtime-hook-contract.md +++ b/docs/runtime-hook-contract.md @@ -117,7 +117,7 @@ This list extends Category A (phase-gate). It enumerates classes of action that, **The two enforcement modes.** - **Mechanical block.** When the runtime supports `pre-tool-use` interception with stdin payload, a hook in `reference-implementations/hooks-/hooks/risky-*.sh` returns exit 1 and the action does not land. This is the strong form. -- **Prose-only refuse.** When the runtime cannot intercept a tool call (no hook surface, or the action is initiated outside the agent loop), the discipline degrades to a refusal in the agent's text output: the agent narrates that the action falls in the risky-action list, lists the row, and stops without taking the action. This is the weak form. It depends on the agent's compliance with [`AGENTS.md §Stop conditions`](../AGENTS.md), and is therefore enforceable only in the same way other prose-level rules are. +- **Prose-only refuse.** When the runtime cannot intercept a tool call (no hook surface, or the action is initiated outside the agent loop — see [`docs/glossary.md §Agent loop`](glossary.md#agent-loop)), the discipline degrades to a refusal in the agent's text output: the agent narrates that the action falls in the risky-action list, lists the row, and stops without taking the action. This is the weak form. It depends on the agent's compliance with [`AGENTS.md §Stop conditions`](../AGENTS.md), and is therefore enforceable only in the same way other prose-level rules are. **Anti-patterns.** diff --git a/docs/throughput-first-merge-philosophy.md b/docs/throughput-first-merge-philosophy.md index d1507b6..22aa24e 100644 --- a/docs/throughput-first-merge-philosophy.md +++ b/docs/throughput-first-merge-philosophy.md @@ -11,7 +11,7 @@ This document is the **single source of truth** for the merge-gate posture. Othe In a low-throughput environment (a small team of humans, a handful of PRs per week), the merge gate's bias toward strict blocking is rational — every block is reviewed by a human, every false positive is caught, the cost of a missed regression is high relative to the cost of a slow merge. In a high-throughput environment (an agent-driven team, dozens of PRs per day), that posture inverts: -- **Block-default produces queue collapse.** Every block costs an agent loop iteration; every iteration costs context budget and wall-clock; the agent's effective throughput drops below the rate at which it can address the blocks. The team's adoption silently degrades to "we wait for the gates to clear." +- **Block-default produces queue collapse.** Every block costs an agent loop iteration (see [`docs/glossary.md §Agent loop`](glossary.md#agent-loop) for the runtime cycle whose iteration cost this argument depends on); every iteration costs context budget and wall-clock; the agent's effective throughput drops below the rate at which it can address the blocks. The team's adoption silently degrades to "we wait for the gates to clear." - **Lint drift accumulates faster than humans can review.** When the gate fires on every taste-level finding, the noise drowns the signal — real findings are buried in routine ones, and the agent's next iteration ignores all of them equally. - **Long-lived PRs decay.** A PR open for three days against an agent-velocity branch base is rebasing on shifting code; the diff the Reviewer reviewed at hour 0 is not the diff that merges at hour 72. Throughput-first existence is required precisely so that PRs *can* close inside one work-cycle. diff --git a/schemas/change-manifest.schema.json b/schemas/change-manifest.schema.json index 36e9451..d6096fe 100644 --- a/schemas/change-manifest.schema.json +++ b/schemas/change-manifest.schema.json @@ -1580,6 +1580,10 @@ }, "description": "Glob patterns identifying the file set this cluster's\nImplementer may modify. The Task Prompt for the spawned\nImplementer names this boundary as a hard write boundary.\nCross-cluster pair-wise disjointness is required and\nvalidator-enforced.\n" }, + "isolation_root": { + "type": "string", + "description": "Optional path or namespace identifying this cluster's\nexclusive write region \u2014 the isolated working copy where\nonly this cluster's Implementer holds write capability.\nCommon forms: a per-cluster branch on a separate working\ntree, a per-cluster container mount, or an OS-level scoped\nfilesystem view. The methodology binds on the property\n(mutual write exclusion across clusters, covering files\noutside scope_files as well as inside) and not on the\nspecific runtime mechanism.\n\nOptional because not every runtime can produce a stable\nidentifier (ephemeral container mounts, in-memory\nfilesystems). When declared, it gives the Reviewer a\nverifiable target (\"did this cluster's Implementer in\nfact write only within isolation_root?\"). When absent,\nthe runtime isolation property still binds but cannot be\naudited from the manifest alone.\n\nSee cluster-parallelism.md \u00a7Runtime isolation\n\u00a7Per-cluster exclusive write region.\n" + }, "scope_surfaces": { "type": "array", "items": { diff --git a/schemas/change-manifest.schema.yaml b/schemas/change-manifest.schema.yaml index 0490c40..0604557 100644 --- a/schemas/change-manifest.schema.yaml +++ b/schemas/change-manifest.schema.yaml @@ -970,6 +970,29 @@ properties: Implementer names this boundary as a hard write boundary. Cross-cluster pair-wise disjointness is required and validator-enforced. + isolation_root: + type: string + description: | + Optional path or namespace identifying this cluster's + exclusive write region — the isolated working copy where + only this cluster's Implementer holds write capability. + Common forms: a per-cluster branch on a separate working + tree, a per-cluster container mount, or an OS-level scoped + filesystem view. The methodology binds on the property + (mutual write exclusion across clusters, covering files + outside scope_files as well as inside) and not on the + specific runtime mechanism. + + Optional because not every runtime can produce a stable + identifier (ephemeral container mounts, in-memory + filesystems). When declared, it gives the Reviewer a + verifiable target ("did this cluster's Implementer in + fact write only within isolation_root?"). When absent, + the runtime isolation property still binds but cannot be + audited from the manifest alone. + + See cluster-parallelism.md §Runtime isolation + §Per-cluster exclusive write region. scope_surfaces: type: array items: diff --git a/skills/engineering-workflow/references/cluster-parallelism.md b/skills/engineering-workflow/references/cluster-parallelism.md index 84a7496..8cd705f 100644 --- a/skills/engineering-workflow/references/cluster-parallelism.md +++ b/skills/engineering-workflow/references/cluster-parallelism.md @@ -23,7 +23,7 @@ Pattern C is the only parallel pattern where canonical role identities are spawn A Pattern C execution has **four invariants**: -1. **File-disjoint scope per cluster.** No two clusters declare `scope_files` patterns that could resolve to the same file. Cluster boundaries are *files*, not concerns — if two clusters "touch the same schema in different ways," that is not disjoint and must be serialized. +1. **File-disjoint scope per cluster.** No two clusters declare `scope_files` patterns that could resolve to the same file. Cluster boundaries are *files*, not concerns — if two clusters "touch the same schema in different ways," that is not disjoint and must be serialized. Declaration alone does not prevent races on files outside `scope_files` (lockfiles, build caches, `.git/index`) or on shared manifest array fields; runtime enforcement of the declaration lives in §Runtime isolation below. 2. **Single-batch spawn.** All Implementer invocations are initiated in one tool-call batch per the cache-window rule (`parallelization-patterns.md` §Cache-window rule, applied to canonical delegation). Serial spawn erases the parallelization benefit. 3. **Any cluster's Discovery halts all clusters.** If any Implementer hits the Discovery loop (plan gap, unfamiliar SoT, missing surface), the cluster flips to `status: blocked_discovery` and the Planner pauses all other clusters until Phase 2 is re-opened and the plan is corrected. 4. **Reviewer performs a cross-cluster cross-cutting gap check.** Cluster intersections are where issues hide: cluster A's API field matches cluster B's frontend call, but cluster C's analytics event still references the old field name. No single Implementer will catch that — only the Reviewer, looking at the union, will. @@ -132,11 +132,61 @@ Findings go into `review_notes` as usual. A finding whose root cause is "cluster --- +## Runtime isolation + +§The core rule §1 declares the contract (`scope_files` are pair-wise disjoint at the schema level). This section names the runtime mechanism that enforces it. Without runtime isolation, two clusters whose declared scopes are disjoint can still collide in three ways the schema cannot detect: shared lockfiles outside any cluster's declared scope, build caches written during verification, and concurrent appends to manifest array fields that the schema permits but does not partition. + +### Per-cluster exclusive write region + +Each cluster's Implementer runs in an **exclusive write region** — an isolated working copy of the repository where only that cluster's Implementer holds write capability. Two clusters never share a write region. + +The methodology binds on the **property** (mutual write exclusion across clusters, covering files outside `scope_files` as well as inside) and not on the runtime mechanism. Common implementations are a per-cluster branch on a separate working tree, a per-cluster container mount, or an OS-level scoped filesystem view; the specific choice belongs in a runtime bridge per `docs/file-role-map.md §Where a new rule belongs`. + +The exclusive write region must cover files **outside** any cluster's declared `scope_files` — `package-lock.json`, `.git/index`, build-cache directories, OS-level lock files, generated `dist/` artifacts. These files are typically not in any cluster's declared `scope_files` but are written by the Implementer's verification or shell calls regardless. A region that excludes only the declared `scope_files` is incomplete and re-introduces the very races the invariant exists to prevent. + +A cluster's Implementer that writes outside its exclusive write region is committing the cluster-boundary violation that anti-pattern row "Cluster Implementer writes to files outside `scope_files`" already names; runtime isolation is what makes that anti-pattern detectable in practice rather than only in principle. + +### Manifest field collision rule + +Two clusters never write directly to the same manifest field. The schema already supports this routing via `cluster_id` tags on cluster-scoped data; the runtime rule names the writer-side discipline that makes the routing usable: + +- Each cluster's Implementer appends only entries **tagged with its own `cluster_id`** to shared array fields (`implementation_notes[]`, evidence rows where `cluster_id` is present per §3 above). +- Untagged appends to shared arrays from a Pattern C cluster are a contract escape — they cannot be attributed at fan-in, and the Reviewer cannot determine which cluster authored them. +- Cross-cluster aggregation is the **Planner's** responsibility at §5 fan-in (`Planner records the fan-out in parallel_groups…`), not a cluster's. A cluster Implementer that writes top-level non-cluster fields is a cluster that has stopped being a cluster. + +### Merge-back ordering at fan-in + +When the Planner assembles cluster outputs at §5, ordering follows three rules in priority: + +1. **Halt overrides.** If any cluster is in `blocked_discovery` at fan-in time, the halt-all rule (§The core rule §3) takes precedence — partial cluster outputs are not merged into a working manifest until Phase 2 re-opens. +2. **Cluster_id-sorted assembly.** Where multiple clusters wrote to the same array field via the cluster_id tag, the Planner merges in `cluster_id` lexical order. Determinism is the property — alphabetical, stable, and runtime-independent. Two Reviewers replaying the same fan-in must produce byte-identical merged output. +3. **Cross-cluster gap-check first.** Before the Planner finalises the merged manifest fields, §The core rule §4 (Reviewer's cross-cluster cross-cutting gap check) is run as a first-pass at fan-in. A gap finding may cause the Planner to drop a cluster's contribution from the merge and return to Phase 2; merging first and discovering the gap afterwards loses the early-stop opportunity. + +### Failure-mode catalog + +Specific runtime races the exclusive write region prevents and the manifest collision rule guards against: + +| Failure | Without runtime isolation | With it | +|---|---|---| +| Two clusters install dependencies and write conflicting `package-lock.json` (or equivalent) | Last-writer-wins; build breaks for whichever cluster ran first | Each cluster's lockfile lives in its own write region; Planner merges at fan-in or treats lockfile divergence as a Phase 2 re-entry trigger | +| Two clusters compile and write the same build cache | Cache poisoning — Cluster A's cache hits in Cluster B's verification, masking real failures | Build caches scoped to the write region; verification artifacts are per-cluster | +| Two clusters append to `implementation_notes[]` simultaneously without `cluster_id` tag | Schema-valid but ambiguous attribution; Reviewer cannot tell which cluster wrote which note; supervision log loses meaning | Each entry carries `cluster_id`; Planner merges deterministically at fan-in per the ordering rule above | +| Cluster A's git commits collide with Cluster B's | Conflict resolution at merge-back is per-line, not per-cluster — merge produces an undescribed hybrid | Per-cluster branch; Planner merges branches in cluster_id order; conflicts surface as Phase 2 re-entry signals, not silent merges | +| Cluster's verification writes to a shared OS path (e.g. shared `/tmp` cache) | Cross-cluster contamination of test results; Cluster A's stale state breaks Cluster B's verification | Write region scoped to per-cluster filesystem view; verification side-effects bounded by the region | +| Two clusters issue parallel write-lock requests to a shared external resource (database, ports, file lock) | Implicit serialization at the resource layer; one cluster blocks until the other releases — the parallelism benefit is erased | The clusters were not independent (§When NOT to use Pattern C row "shared test infrastructure that updates per-cluster") and should have been serialized at plan time; runtime isolation surfaces this as a cluster that hangs rather than as silently degraded throughput | + +### Optional schema declaration + +A cluster MAY declare its `isolation_root` in the manifest — a path or namespace identifying the cluster's exclusive write region. The field is optional because not every runtime can produce a stable identifier (ephemeral container mounts, in-memory filesystems); when declared, it gives the Reviewer a verifiable target ("did this cluster's Implementer in fact write only within `isolation_root`?"). See `schemas/change-manifest.schema.yaml §implementation_clusters[*].isolation_root`. + +--- + ## Why each invariant is needed | Invariant | Specific failure prevented | |---|---| -| File-disjoint scope | Merge conflicts → implicit serialization + unclear ownership of the conflicted file | +| File-disjoint scope (declared) | Merge conflicts → implicit serialization + unclear ownership of the conflicted file | +| File-disjoint scope (runtime-enforced via §Runtime isolation) | Races on files outside `scope_files` (lockfiles, build caches, `.git/index`) and concurrent appends to shared manifest array fields — the failure modes the declaration alone cannot prevent | | Single-batch spawn | Cache-window cost hits per-spawn, erasing the parallelization benefit (same argument as Patterns A/B) | | Discovery-halt-all-clusters | Other clusters building on invalidated plan state → silently-wrong code with clean local verification | | Cross-cluster cross-cutting gap check | Issues visible only at the intersection of two clusters — the specific failure mode parallel implementation introduces, analogous to §Cross-cutting gap check in Patterns A/B | @@ -157,6 +207,10 @@ Findings go into `review_notes` as usual. A finding whose root cause is "cluster | Pattern C where the Implementer envelope would need to vary per cluster | Pattern C assumes homogeneous canonical-Implementer envelope; heterogeneous-envelope delegation is a different problem | | Implementer sub-agent identity shared between two clusters | Anti-collusion violated transitively; a cluster reviewing (even implicitly) its sibling's output is self-review | | Writing `implementation_clusters` into the manifest **after** spawning Implementers | The declaration is the contract between Planner and each Implementer; retroactive declaration breaks the Task Prompt honesty | +| Two clusters share an exclusive write region (worktree / container / scoped filesystem view) | Runtime isolation collapses; lockfile, build cache, and `.git/index` races re-emerge below the schema's visibility (§Runtime isolation) | +| Cluster appends entries to `implementation_notes[]` (or other shared arrays) without `cluster_id` tag | Manifest field collision rule violated; Reviewer cannot attribute the entry to a cluster at fan-in audit (§Runtime isolation §Manifest field collision rule) | +| Planner merges cluster outputs into the canonical manifest before running the cross-cluster gap check | Loses the early-stop opportunity that gap-check-first enables; a cluster contribution that should have been dropped lands in the merged manifest and a later send-back becomes more expensive (§Runtime isolation §Merge-back ordering) | +| Cluster's verification writes to a shared OS path (e.g. shared `/tmp` build cache) outside its exclusive write region | The exclusive-write-region property is broken in scope but compliant at the `scope_files` declaration; the most common silent runtime-isolation breakage (§Runtime isolation §Per-cluster exclusive write region) | --- @@ -170,7 +224,7 @@ Findings go into `review_notes` as usual. A finding whose root cause is "cluster | `reference-implementations/roles/role-composition-patterns.md` Pattern 7 | Non-normative companion — acknowledges that Pattern C exists alongside Patterns 1–6 but is canonical-role multi-delegation, not sub-agent composition | | `skills/engineering-workflow/references/parallelization-patterns.md` | Pattern C is listed in the phase-applicability table as Phase 4's parallel pattern. The two documents cover different mechanisms | | `docs/phase-gate-discipline.md` Rule 6 (phase re-entry) | Invoked when any cluster triggers Discovery-loop halt | -| `schemas/change-manifest.schema.yaml §implementation_clusters` + §parallel_groups | `implementation_clusters` is the substantive record of Pattern C; `parallel_groups` with `pattern: C_cluster_implementers` is the audit breadcrumb that points at it | +| `schemas/change-manifest.schema.yaml §implementation_clusters` + §parallel_groups | `implementation_clusters` is the substantive record of Pattern C; `parallel_groups` with `pattern: C_cluster_implementers` is the audit breadcrumb that points at it. The optional `implementation_clusters[*].isolation_root` field declares the cluster's exclusive write region per §Runtime isolation | | `agents/planner.md`, `agents/implementer.md` | Role files gain "Optional: Pattern C" sections naming the Planner's declare-and-spawn duties and the Implementer's cluster-scoped execution duty | | `skills/engineering-workflow/references/phase-overlap-zones.md` | Orthogonal: Pattern C is within-Phase-4 parallelism; overlap zones are between-phase prep. The two stack — e.g. Pattern C's Phase 4 runs in parallel while Phase 5 Reviewer's context pack is being pre-distilled in overlap | | `skills/engineering-workflow/references/long-running-delegation.md` | The Planner's monitoring of cluster statuses (§4 halt trigger and §5 completion detection) is a D3 non-idle instance — the Planner reads each cluster's session-scoped status artifact (D2) rather than polling by re-invocation. A cluster whose planned scope would exceed one cache window is a D1 decomposition problem, not a halt problem | diff --git a/skills/engineering-workflow/references/long-running-delegation.md b/skills/engineering-workflow/references/long-running-delegation.md index 7a1500c..211d100 100644 --- a/skills/engineering-workflow/references/long-running-delegation.md +++ b/skills/engineering-workflow/references/long-running-delegation.md @@ -187,6 +187,27 @@ The canonical role cannot run concurrent work during the sub-agent invocation --- +## Mapping the runtime loop to phase boundaries + +The methodology defines D1 / D2 / D3 abstractly — "checkpoint-bounded scope," "artifact-grounded progress," "canonical-role non-idle." Every implementation runs them on top of a concrete **agent loop** (per `docs/glossary.md §Agent loop`): the runtime cycle of read-context → emit-action → observe-result → repeat. This section names how the abstract disciplines land on a real loop without endorsing the failure modes the methodology rejects. + +**Where loop iterations meet phase boundaries.** A phase advance (`phase: investigate → plan`, etc.) is a single loop iteration in which the canonical role: reads the gate's exit-criteria evidence, runs the gate's check, and emits the manifest write that advances `phase`. Category A phase-gate hooks (`docs/runtime-hook-contract.md`) fire on that iteration's tool call. Loop iterations that do not cross a gate are **intra-phase** — they may fire Category B (evidence) or Category C (drift) hooks but do not change `phase`. The loop neither knows nor enforces phase boundaries; the canonical role does, and the loop dispatches the role's actions. + +**Where D2 writes happen on a loop tick.** Inside a long-running sub-agent, every loop iteration that completes a unit of useful work writes one structured progress entry to the D2 path (per §D2 above — append-only, structured, session-scoped). The canonical role's loop, separately, may tail the D2 path on its own iterations as part of its defined polling plan (per §D3). Two loops, one shared artifact path; **never one loop polling the other agent**. + +**Termination triggers — runtime-neutral.** A loop terminates when any one of the following fires, in priority order: + +1. **Stop conditions** per `AGENTS.md §Stop conditions` — SoT unclear, surfaces unenumerable, breaking change without migration path, rollback unknown, evidence cannot be produced. The canonical role's loop must stop and surface, not iterate further. +2. **Iteration caps** specific to certain loops — `skills/engineering-workflow/references/application-driven-loop.md` §five-iteration cap (BEFORE/trigger/AFTER/fix/re-validate); `skills/engineering-workflow/phases/fix-retest-loop.md` §three-failure rule (same-category test failures). These caps are **diagnostic budgets**, not compute budgets — five corrective iterations is the methodology's claim that further retries indicate a wrong diagnosis, not a missing fix. +3. **Tree D escalation** per `docs/decision-trees.md` — risky-action interception list, breaking-change L2+, rollback mode 3, auth/PII/secrets paths. Escalation is loop-terminating (the loop yields to a human). +4. **Runtime-imposed boundaries** — cache-window expiry (`parallelization-patterns.md §Cache-window rule`), session timeout, sub-agent return. These are runtime concerns; the methodology binds on what the canonical role does at the boundary (read D2, decide, advance the manifest), not on the boundary's exact wall-clock value. + +A runtime that exposes none of these triggers as enforceable mechanisms — i.e. a loop that runs until something external kills it — is unsuited for unattended Full-mode operation. The methodology is consumable on such a runtime only in human-supervised configurations where a human plays the role of the missing termination logic. + +**Anti-pattern: loop-as-clock.** A loop that fires a delegation, ends its turn without canonical-role concurrent work, waits for a runtime-imposed tick, and fires another delegation on the next tick is implementing the polling-clock pattern this discipline (D3) rejects. The polling-clock pattern is symmetric with `docs/anti-entropy-discipline.md` Rule "Sweep agent runs 24/7" — both treat the loop as a scheduler that compensates for absent canonical-role work, both incur continuous cost, and both produce the fabrication-by-silence failure mode `docs/ai-operating-contract.md §11` and §D3 here close from opposite directions. The loop is a cycle the canonical role drives with intent; it is not a clock that runs in the role's absence. + +--- + ## Anti-patterns | Anti-pattern | What breaks | diff --git a/skills/engineering-workflow/references/parallelization-patterns.md b/skills/engineering-workflow/references/parallelization-patterns.md index 4fc099f..d042ada 100644 --- a/skills/engineering-workflow/references/parallelization-patterns.md +++ b/skills/engineering-workflow/references/parallelization-patterns.md @@ -126,7 +126,7 @@ The field is optional — a Full-mode change that chose not to fan out validates | Phase 6 Sign-off | — (human-in-loop checkpoint) | — | — | | Phase 7 Deliver | — | — | — | -**Two parallelism mechanisms.** Patterns A and B spawn **non-canonical sub-agents** that return findings for the canonical role to synthesize into its own manifest fields. Pattern C spawns **canonical Implementer identities** that each write their own cluster's fields directly. The disciplines in this document (cache-window rule, context pack, fan-in synthesis, cross-cutting gap check, `parallel_groups` audit) apply to Patterns A and B; Pattern C has its own discipline in `cluster-parallelism.md` (file-disjoint clusters, discovery-halt-all-clusters, Reviewer cross-cluster gap check, `implementation_clusters` manifest field). Both mechanisms may appear on the same change — a Phase 1 Pattern A fan-out and a Phase 4 Pattern C delegation and a Phase 5 Pattern B fan-out, each recorded in its own field. +**Two parallelism mechanisms.** Patterns A and B spawn **non-canonical sub-agents** that return findings for the canonical role to synthesize into its own manifest fields. Pattern C spawns **canonical Implementer identities** that each write their own cluster's fields directly. The disciplines in this document (cache-window rule, context pack, fan-in synthesis, cross-cutting gap check, `parallel_groups` audit) apply to Patterns A and B; Pattern C has its own discipline in `cluster-parallelism.md` (file-disjoint clusters, discovery-halt-all-clusters, Reviewer cross-cluster gap check, runtime isolation per `cluster-parallelism.md §Runtime isolation`, `implementation_clusters` manifest field). Both mechanisms may appear on the same change — a Phase 1 Pattern A fan-out and a Phase 4 Pattern C delegation and a Phase 5 Pattern B fan-out, each recorded in its own field. For the canonical-role multi-delegation discipline that Pattern C introduces, see [`cluster-parallelism.md`](cluster-parallelism.md) and `role-composition-patterns.md` §Pattern 7.