PRD: os-sdlc:implement v2 — fresh agents every round, sharded parallel programmers, deterministic lint pre-pass #195

Closed
opened 2026-07-31 20:08:40 +00:00 by jared · 2 comments
Owner

PRD: os-sdlc:implement v2 — fresh agents every round, sharded parallel programmers, deterministic lint pre-pass

Source: fresh-context retro of session 229b7865 (llf-schema docs/retros/2026-07-31-os-sdlc-implement-run3-fresh-context-retro.md) plus trace metrics.

Problem Statement

As the operator of the os-sdlc pipeline, running one ticket end-to-end is far slower and more expensive than the work justifies. Evidence from the first real run (3 tickets, 163 minutes): a single programmer agent handed a 14-file ticket built a ~208k-token context in its first dispatch, then was resumed 4 more times, spending 20–40% of each resumed round re-reading files it had already read, and making arithmetic errors past ~179k context. Meanwhile a nearly fresh agent at 58.9k context fixed the same class of lint offense in 29 seconds. A real integration bug was caught only by an ad-hoc orchestrator check — the reviewer cannot run code and structurally cannot catch it. 31% of wall-clock time sat outside the pipeline, mostly batched merges (one approved ticket idled 95 minutes). The orchestrator hand-assembles the reviewer packet and retypes verdicts even though review-packet and record-verdict --from-agent-output subcommands already exist.

Solution

Restructure the implement pipeline around two principles: (1) no agent is ever resumed for test-writing, programming, or lint work — every round goes to a fresh agent with a distilled brief (the reviewer is exempt; its contexts stayed under 100k and resuming it works); (2) programming is sharded: one fresh programmer per test-file/collaborator cluster runs in parallel over disjoint file sets, shared entrypoint/registry files are reserved for a single fresh integration agent that wires and aligns everything, and the whole-suite green gate runs once after all shards land. Lint becomes deterministic-first: rubocop autocorrect runs before any LLM sees an offense, and residual offenses go to fresh mechanical (cheap-tier) agents. A named smoke/parity gate is added so integration bugs are caught by the pipeline, not by luck. Merges happen per-ticket at approval, never batched.

User Stories

  1. As the pipeline operator, I want every programmer round dispatched to a fresh agent, so that no round pays the token or drift cost of accumulated context.
  2. As the pipeline operator, I want the reviewer exempt from the fresh-agent rule, so that its cheap resumable context is not thrown away needlessly.
  3. As the orchestrator, I want a shard-plan step that maps test files/collaborator clusters to disjoint code-file sets, so that I can dispatch one programmer per shard in parallel.
  4. As the orchestrator, I want shared entrypoint/registry files (CLI dispatchers, seeders, registries) excluded from all shards, so that parallel programmers never edit the same file.
  5. As the orchestrator, I want a single integration/wiring agent that receives the ticket, all tests, and shard summaries after shards complete, so that shared-file edits and cross-shard alignment happen exactly once.
  6. As the pipeline operator, I want green-assert to run once, after all shards and wiring land, so that the whole-suite gate remains the single source of truth.
  7. As the pipeline operator, I want rubocop autocorrect to run deterministically before any lint dispatch, so that most offenses never consume LLM tokens at all.
  8. As the orchestrator, I want residual lint offenses dispatched per-file to fresh cheap-tier agents with only the offense list and file path, so that lint remediation never returns to the original programmer.
  9. As the pipeline operator, I want a named smoke/parity gate in the pipeline, so that integration bugs of the kind found ad-hoc in ticket #17 are caught by a formal step.
  10. As the orchestrator, I want to assemble the reviewer packet via the existing review-packet subcommand, so that I stop hand-assembling diffs and gate logs in main-loop context.
  11. As the orchestrator, I want to record verdicts via the existing record-verdict --from-agent-output, so that verdicts are never retyped by hand.
  12. As the pipeline operator, I want each ticket merged immediately at approval, so that approved work never idles behind a batch.
  13. As the pipeline operator, I want each fresh dispatch to carry a distilled brief (decided facts, changed files, next task) rather than a transcript, so that fresh agents start sharp and small.
  14. As the pipeline operator, I want an optional agent-budget check that reads a subagent transcript's token usage, so that any future policy regression toward oversized contexts is detected deterministically.
  15. As the orchestrator, I want shard dispatch prompts to include the shard's exact file list and test paths, so that round-1 read volume stays bounded by shard size.
  16. As the pipeline operator, I want shard results reported as summary + artifact paths only, so that the orchestrator context does not absorb shard file contents.
  17. As a developer auditing a run, I want the shard plan and per-shard outcomes recorded in the run's JSONL record, so that parallel runs remain traceable like sequential ones.

Implementation Decisions

  • Fresh-agent-every-round becomes the standing rule in the agent-design principles reference and is threaded through every SKILL.md retry/remediation step; SendMessage-resume is removed from the implement flow for test-writer, programmer, and lint roles. Reviewer is the sole exemption.
  • A new deterministic shard-plan step (gate-CLI subcommand) takes the ticket's test files and code paths and emits a shard map: shard → {test files, owned code files}; shared entrypoint/registry files are listed in a reserved set owned by no shard.
  • Shard detection of "shared" files: any file referenced by more than one shard's collaborator cluster, plus a configurable reserved list (CLI dispatcher, registries, seeders) in project.yaml.
  • The integration/wiring agent is a fresh programmer dispatched after all shards report; it alone edits reserved files and reconciles ticket/tests/code alignment.
  • Gate order becomes: red-assert → parallel shards → wiring → green-assert (once, whole suite) → autocorrect → residual-lint (fresh cheap agents) → lint gate → ac-lint → smoke/parity gate → reviewer → record-verdict (--from-agent-output) → verdict-assert → merge immediately.
  • The smoke/parity gate is deterministic where possible (script comparing new-path vs legacy-path output, as the ad-hoc #17 check did); its contract is the same exit-status-only rule as the other gates (per the existing ADR that makes exit status the sole verdict).
  • Autocorrect runs rubocop -a (safe corrections) as a gate-CLI pre-pass; unsafe/manual offenses are what reaches LLM agents.
  • Residual lint agents are cheap-tier, one per offending file, prompt = offense list + file path only; no ticket context needed.
  • The agent-budget subcommand reads a subagent transcript JSONL and reports peak context; it is a monitoring backstop, not a resume gate (there are no resumes).
  • Parallelism is bounded by disjoint file ownership; if the shard planner cannot produce disjoint shards, it falls back to a single-programmer dispatch (current behavior) rather than serializing shards.
  • No harness change to the deterministic red/green/lint/ac-lint gates themselves; they already run tests exactly once and remain the only verdict source.

Testing Decisions

  • Test at the existing highest seam: the gate CLI subprocess boundary (invoke subcommand, assert exit status and emitted JSON/JSONL), exactly as the existing red-assert/green-assert/lint gate tests do — prior art in the os-sdlc gate test suite.
  • Shard planner: given fixture ticket layouts (single test file; multiple independent files; overlapping collaborator clusters; reserved-file collisions), assert the emitted shard map, the reserved set, and the single-programmer fallback. External behavior only — the map JSON, not internal clustering steps.
  • Autocorrect pre-pass: fixture repo with known safe + unsafe offenses; assert safe ones are gone, unsafe ones appear in the residual report, exit codes correct.
  • Smoke/parity gate: fixture with a deliberate new-vs-legacy output divergence; assert nonzero exit and a useful diff artifact; passing fixture asserts zero exit.
  • agent-budget: fixture JSONL transcripts with known usage lines; assert reported peak and threshold exit codes.
  • SKILL.md flow changes (fresh-dispatch wording, gate order) are validated by the existing AiDD artifact linting, not by unit tests.

Out of Scope

  • Any change to the deterministic red/green-assert internals or the exit-status-only verdict rule.
  • AST/ctags/LSP/knowledge-graph navigation aids — the trace showed 55 Grep/Glob calls total; discovery is not the bottleneck.
  • Test-blast-radius selection — the suite runs in ~11 seconds; whole-suite gating stays.
  • SubagentStop-hook gating (the open hook-vs-inline-script question) — zero token difference; may be revisited separately.
  • Orchestrator context management beyond using the existing packet/verdict subcommands.
  • Changes to port-coverage or other os-sdlc skills.

Further Notes

  • Key evidence inverting an earlier assumption: programmer peak contexts were built almost entirely in round 1 (#17: 208,370 of 209,663 by end of round 1; #18: 179,719 of 194,486). Rotation alone would not have capped peaks — sharding round-1 read volume is the primary lever; fresh-every-round eliminates the resumed-round waste (20–40% re-reads) and drift.
  • Within-run control for fresh-vs-resumed: idle agent at 58.9k fixed a ClassLength offense in 29s while the resumed 199k programmer looped on the same class of task.
  • Real merge conflict observed (attorney_seeder.rb, tickets #21/#17) motivates the reserved-file set; lib/llf.rb/bin/llf were touched by two tickets and are canonical reserved-file examples.
  • Expected savings: #17's 59-minute single-programmer phase becomes ~4 parallel sub-60k dispatches; resumed-round waste (~1k–15k tokens/round re-reads plus full-context replay per resume) disappears entirely; batched-merge idle (95 min worst case) goes to zero.
# PRD: os-sdlc:implement v2 — fresh agents every round, sharded parallel programmers, deterministic lint pre-pass Source: fresh-context retro of session 229b7865 (llf-schema `docs/retros/2026-07-31-os-sdlc-implement-run3-fresh-context-retro.md`) plus trace metrics. ## Problem Statement As the operator of the os-sdlc pipeline, running one ticket end-to-end is far slower and more expensive than the work justifies. Evidence from the first real run (3 tickets, 163 minutes): a single programmer agent handed a 14-file ticket built a ~208k-token context in its *first* dispatch, then was resumed 4 more times, spending 20–40% of each resumed round re-reading files it had already read, and making arithmetic errors past ~179k context. Meanwhile a nearly fresh agent at 58.9k context fixed the same class of lint offense in 29 seconds. A real integration bug was caught only by an ad-hoc orchestrator check — the reviewer cannot run code and structurally cannot catch it. 31% of wall-clock time sat outside the pipeline, mostly batched merges (one approved ticket idled 95 minutes). The orchestrator hand-assembles the reviewer packet and retypes verdicts even though `review-packet` and `record-verdict --from-agent-output` subcommands already exist. ## Solution Restructure the implement pipeline around two principles: (1) **no agent is ever resumed** for test-writing, programming, or lint work — every round goes to a fresh agent with a distilled brief (the reviewer is exempt; its contexts stayed under 100k and resuming it works); (2) **programming is sharded**: one fresh programmer per test-file/collaborator cluster runs in parallel over disjoint file sets, shared entrypoint/registry files are reserved for a single fresh integration agent that wires and aligns everything, and the whole-suite green gate runs once after all shards land. Lint becomes deterministic-first: rubocop autocorrect runs before any LLM sees an offense, and residual offenses go to fresh mechanical (cheap-tier) agents. A named smoke/parity gate is added so integration bugs are caught by the pipeline, not by luck. Merges happen per-ticket at approval, never batched. ## User Stories 1. As the pipeline operator, I want every programmer round dispatched to a fresh agent, so that no round pays the token or drift cost of accumulated context. 2. As the pipeline operator, I want the reviewer exempt from the fresh-agent rule, so that its cheap resumable context is not thrown away needlessly. 3. As the orchestrator, I want a shard-plan step that maps test files/collaborator clusters to disjoint code-file sets, so that I can dispatch one programmer per shard in parallel. 4. As the orchestrator, I want shared entrypoint/registry files (CLI dispatchers, seeders, registries) excluded from all shards, so that parallel programmers never edit the same file. 5. As the orchestrator, I want a single integration/wiring agent that receives the ticket, all tests, and shard summaries after shards complete, so that shared-file edits and cross-shard alignment happen exactly once. 6. As the pipeline operator, I want green-assert to run once, after all shards and wiring land, so that the whole-suite gate remains the single source of truth. 7. As the pipeline operator, I want rubocop autocorrect to run deterministically before any lint dispatch, so that most offenses never consume LLM tokens at all. 8. As the orchestrator, I want residual lint offenses dispatched per-file to fresh cheap-tier agents with only the offense list and file path, so that lint remediation never returns to the original programmer. 9. As the pipeline operator, I want a named smoke/parity gate in the pipeline, so that integration bugs of the kind found ad-hoc in ticket #17 are caught by a formal step. 10. As the orchestrator, I want to assemble the reviewer packet via the existing `review-packet` subcommand, so that I stop hand-assembling diffs and gate logs in main-loop context. 11. As the orchestrator, I want to record verdicts via the existing `record-verdict --from-agent-output`, so that verdicts are never retyped by hand. 12. As the pipeline operator, I want each ticket merged immediately at approval, so that approved work never idles behind a batch. 13. As the pipeline operator, I want each fresh dispatch to carry a distilled brief (decided facts, changed files, next task) rather than a transcript, so that fresh agents start sharp and small. 14. As the pipeline operator, I want an optional agent-budget check that reads a subagent transcript's token usage, so that any future policy regression toward oversized contexts is detected deterministically. 15. As the orchestrator, I want shard dispatch prompts to include the shard's exact file list and test paths, so that round-1 read volume stays bounded by shard size. 16. As the pipeline operator, I want shard results reported as summary + artifact paths only, so that the orchestrator context does not absorb shard file contents. 17. As a developer auditing a run, I want the shard plan and per-shard outcomes recorded in the run's JSONL record, so that parallel runs remain traceable like sequential ones. ## Implementation Decisions - Fresh-agent-every-round becomes the standing rule in the agent-design principles reference and is threaded through every SKILL.md retry/remediation step; SendMessage-resume is removed from the implement flow for test-writer, programmer, and lint roles. Reviewer is the sole exemption. - A new deterministic shard-plan step (gate-CLI subcommand) takes the ticket's test files and code paths and emits a shard map: shard → {test files, owned code files}; shared entrypoint/registry files are listed in a reserved set owned by no shard. - Shard detection of "shared" files: any file referenced by more than one shard's collaborator cluster, plus a configurable reserved list (CLI dispatcher, registries, seeders) in project.yaml. - The integration/wiring agent is a fresh programmer dispatched after all shards report; it alone edits reserved files and reconciles ticket/tests/code alignment. - Gate order becomes: red-assert → parallel shards → wiring → green-assert (once, whole suite) → autocorrect → residual-lint (fresh cheap agents) → lint gate → ac-lint → smoke/parity gate → reviewer → record-verdict (`--from-agent-output`) → verdict-assert → merge immediately. - The smoke/parity gate is deterministic where possible (script comparing new-path vs legacy-path output, as the ad-hoc #17 check did); its contract is the same exit-status-only rule as the other gates (per the existing ADR that makes exit status the sole verdict). - Autocorrect runs `rubocop -a` (safe corrections) as a gate-CLI pre-pass; unsafe/manual offenses are what reaches LLM agents. - Residual lint agents are cheap-tier, one per offending file, prompt = offense list + file path only; no ticket context needed. - The agent-budget subcommand reads a subagent transcript JSONL and reports peak context; it is a monitoring backstop, not a resume gate (there are no resumes). - Parallelism is bounded by disjoint file ownership; if the shard planner cannot produce disjoint shards, it falls back to a single-programmer dispatch (current behavior) rather than serializing shards. - No harness change to the deterministic red/green/lint/ac-lint gates themselves; they already run tests exactly once and remain the only verdict source. ## Testing Decisions - Test at the existing highest seam: the gate CLI subprocess boundary (invoke subcommand, assert exit status and emitted JSON/JSONL), exactly as the existing red-assert/green-assert/lint gate tests do — prior art in the os-sdlc gate test suite. - Shard planner: given fixture ticket layouts (single test file; multiple independent files; overlapping collaborator clusters; reserved-file collisions), assert the emitted shard map, the reserved set, and the single-programmer fallback. External behavior only — the map JSON, not internal clustering steps. - Autocorrect pre-pass: fixture repo with known safe + unsafe offenses; assert safe ones are gone, unsafe ones appear in the residual report, exit codes correct. - Smoke/parity gate: fixture with a deliberate new-vs-legacy output divergence; assert nonzero exit and a useful diff artifact; passing fixture asserts zero exit. - agent-budget: fixture JSONL transcripts with known usage lines; assert reported peak and threshold exit codes. - SKILL.md flow changes (fresh-dispatch wording, gate order) are validated by the existing AiDD artifact linting, not by unit tests. ## Out of Scope - Any change to the deterministic red/green-assert internals or the exit-status-only verdict rule. - AST/ctags/LSP/knowledge-graph navigation aids — the trace showed 55 Grep/Glob calls total; discovery is not the bottleneck. - Test-blast-radius selection — the suite runs in ~11 seconds; whole-suite gating stays. - SubagentStop-hook gating (the open hook-vs-inline-script question) — zero token difference; may be revisited separately. - Orchestrator context management beyond using the existing packet/verdict subcommands. - Changes to port-coverage or other os-sdlc skills. ## Further Notes - Key evidence inverting an earlier assumption: programmer peak contexts were built almost entirely in round 1 (#17: 208,370 of 209,663 by end of round 1; #18: 179,719 of 194,486). Rotation alone would not have capped peaks — sharding round-1 read volume is the primary lever; fresh-every-round eliminates the resumed-round waste (20–40% re-reads) and drift. - Within-run control for fresh-vs-resumed: idle agent at 58.9k fixed a ClassLength offense in 29s while the resumed 199k programmer looped on the same class of task. - Real merge conflict observed (`attorney_seeder.rb`, tickets #21/#17) motivates the reserved-file set; `lib/llf.rb`/`bin/llf` were touched by two tickets and are canonical reserved-file examples. - Expected savings: #17's 59-minute single-programmer phase becomes ~4 parallel sub-60k dispatches; resumed-round waste (~1k–15k tokens/round re-reads plus full-context replay per resume) disappears entirely; batched-merge idle (95 min worst case) goes to zero.
Author
Owner

The smoke-parity gate was removed from the os-sdlc pipeline entirely (see commit d0cfc90). ac-lint pass now wires directly to workspace-housekeeping; #276 (smoke-parity follow-up) was closed as wontfix since the gate no longer exists.

The smoke-parity gate was removed from the os-sdlc pipeline entirely (see commit d0cfc90). ac-lint pass now wires directly to workspace-housekeeping; #276 (smoke-parity follow-up) was closed as wontfix since the gate no longer exists.
Author
Owner

Superseded by the actual build: ADR-0097 moved sequencing into the os-sdlc-runner Ruby stepper (implement/SKILL.md is now a thin dispatch loop). shard_plan.rb, review-packet/record-verdict wiring, and fresh-agent dispatch all exist in lib/os_sdlc/runner. Smoke-parity gate was removed entirely (2026-08-05 comment, commit d0cfc90). Remaining named gaps tracked separately in #197.

Superseded by the actual build: ADR-0097 moved sequencing into the os-sdlc-runner Ruby stepper (implement/SKILL.md is now a thin dispatch loop). shard_plan.rb, review-packet/record-verdict wiring, and fresh-agent dispatch all exist in lib/os_sdlc/runner. Smoke-parity gate was removed entirely (2026-08-05 comment, commit d0cfc90). Remaining named gaps tracked separately in #197.
jared closed this issue 2026-08-13 18:14:53 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jared/cc-os#195
No description provided.