You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Filed for triage — proposes directions rather than one settled approach. Surfaced by a real AFK /orchestrate run (kntnt-code-skills 0.12.0) building Kntnt/Mimer#60–#70 at --level=L --merge. Broadened to cover a second facet (cross-reference dependencies) after the same run produced a second instance of the same root gap.
Summary
The dependency graph — and thus the wave assignment that decides what runs concurrently and in what order — is built only from explicit Blocked by#N edges. It is blind to implicit relationships that the issue text plainly reveals, and two such relationships each broke a real run:
Facet 1 — file/module overlap → should serialize. Two edge-independent issues that rewrite the same module land in the same wave and build concurrently; the second parks on a semantic rebase at integrate time.
Facet 2 — cross-reference → should order. An issue that names another in-scope issue's deliverable (a command, a symbol, a file it creates) has a real dependency on it, but with no Blocked by edge the planner can schedule the referrer first, leaving the reference dangling until the provider lands.
Both are the same root gap — the planner reasons only over explicit edges — with different corrective actions: overlap → avoid concurrency; cross-reference → hard ordering (exactly the Blocked by edge that was omitted). The deterministic orchestrate.py plan cannot see either (it never reads prose); the orchestrator's read pass (SKILL.md §Flow step 1, Profile and gather) can, since both signals are in plain text.
What happened (both from the same run)
Facet 1 — #60 × #63 (file overlap → park). The planner put #60–#64 in wave 1 with no Blocked by edges among them. #60 ("remove bootstrap") and #63 ("detached session-boundary pass + remove git bulk-capture") both heavily rewrote the same seam — transcript.py, curate.py, storeio.py, install.py. #63's own body said it "owns the full removal of the git bulk-capture path … across the seam … in one ticket, so no later ticket has to rewrite this seam across two files." Built concurrently off the same base; #60 integrated first; #63 — fully built, gates green, independently verified — could not fast-forward, its rebase hit real conflicts in all four files, and the engine parked it (correctly refusing to guess-merge). Net: 4/5 landed, #63 parked, remediated by a solo re-run against the advanced base.
Facet 2 — #68 → #69 (cross-reference → dangling).#68 emits a session-start warning naming mimer-manage disable-native-memory, a command #69 builds (its AC1). That is a real #68 → #69 dependency, but no edge existed (#68 blocked_by [64,65]; #69 blocked_by [63,64,65] — siblings). #68 ran first, so the command did not exist and the warning named a non-existent command. The docs-truthfulness gate caught it and #68's integration hotfix built #69's command itself (pulling #69's AC1/AC3 forward) — the safety net held, but at the cost of one issue's hotfix delivering another's scope plus a manual retarget of #69 onto its remaining AC. A #68 Blocked by #69 edge (or splitting the shallow disable-native-memory out of the deeper #69) would have ordered it correctly. Aggravating factor upstream: #69 bundles a shallow deliverable (needs only #64) with a deep one (needs #63/#64/#65), so #68 could not depend on just the shallow half.
Root cause
scripts/orchestrate.py plan builds dependency_edges/waves purely from Blocked by#N tokens; by design it never reads prose ("pure bookkeeping … never calls claude"), so it sees neither facet.
skills/orchestrate/SKILL.md states "issues in one wave are independent and may run concurrently" — true for the dependency graph, false once file overlap (Facet 1) or a cross-reference (Facet 2) is present, and nothing instructs the planner to look for either.
The engine's park-on-semantic-rebase (Facet 1) and the docs-truthfulness gate + hotfix (Facet 2) are correct backstops and must not change; the gap is upstream of them, in what gets scheduled and in what order.
Why it was foreseeable
The signals were in plain text and the orchestrator's read pass already reads every body/brief. Facet 1: #60 and #63 both describe rewriting the capture/transcript seam. Facet 2: #68 names the exact command #69's body promises to build. A deliberate cross-issue pass over the same-wave set would have flagged both — serialize #60/#63, order #69 before #68. So both are preventable as a planning-time heuristic, not as anything the graph can prove.
Proposed solutions (one or more; not mutually exclusive)
A — Planning-pass instruction (cheapest; LLM-side, no code). Add to SKILL.md §Flow (steps 1–2): beyond the Blocked by graph, read each in-scope issue for implicit relationships and act on them —
file/module overlap between same-wave issues → serialize the pair (soft-order / one-issue-per-slice), because concurrent same-module rewrites conflict at integrate time;
a reference to another in-scope issue's deliverable (a command, symbol, or file that issue creates) → treat it as a dependency and order the referrer after the provider (or flag the missing Blocked by edge), so no issue is built against a deliverable that has not landed.
Surface both decisions at the confirm gate.
B — Fix the misleading wording + chunking guidance. Qualify "issues in one wave are independent" to mean dependency-independence only, and in §Cost and chunking name both file overlap and cross-references as serialization/ordering reasons, recommending one-issue-per-slice for tightly-coupled refactors.
C — Optional structured input for a deterministic signal. Let an issue/brief declare lightweight hints orchestrate.py plan can read as soft edges without prose-reading: Touches: <area> (same-area issues in a wave → serialize) and/or Provides: / Needs: <capability> (a Needs matching another issue's Provides → an ordering edge). to-issues / triage populate them when cutting the slice — which is also the right upstream place to catch a missing Blocked by edge like #68 → #69.
D — Engine-side auto-remediation (Facet 1; strongest AFK guarantee). When an issue parks on an integrate-time semantic rebase, have the engine attempt one solo rebuild against the now-advanced base (the manual fix that worked here) before parking-and-reporting, bounded by the fix-round cap.
Recommendation: A + B are near-free and would have prevented both incidents; C is the robust deterministic complement for briefed pipelines (and its Provides/Needs half is really an upstream to-issues / triage improvement); D is the strongest Facet-1 guarantee but the most work.
Acceptance criteria (for triage — final set depends on the chosen direction)
SKILL.md §Flow instructs the planner to assess same-wave file/module overlap and serialize colliding pairs, surfaced at the confirm gate (Solution A, Facet 1).
SKILL.md §Flow instructs the planner to detect a reference to another in-scope issue's deliverable and order the referrer after the provider (or flag the missing Blocked by edge), surfaced at the confirm gate (Solution A, Facet 2).
The "issues in one wave are independent" wording is qualified to dependency-independence, and §Cost and chunking lists both facets as serialization/ordering reasons (Solution B).
(If C)orchestrate.py plan reads Touches: (serialize) and/or Provides:/Needs: (order) hints as soft edges, covered by tests/test_orchestrate.py.
(If D) the engine, on an integrate-time semantic-rebase park, attempts one solo rebuild against the advanced base before parking, bounded by the fix-round cap, with tests.
CHANGELOG.md updated; the repo's gates (scripts/audit.py, pytest) green.
Summary
The dependency graph — and thus the wave assignment that decides what runs concurrently and in what order — is built only from explicit
Blocked by#Nedges. It is blind to implicit relationships that the issue text plainly reveals, and two such relationships each broke a real run:Blocked byedge the planner can schedule the referrer first, leaving the reference dangling until the provider lands.Both are the same root gap — the planner reasons only over explicit edges — with different corrective actions: overlap → avoid concurrency; cross-reference → hard ordering (exactly the
Blocked byedge that was omitted). The deterministicorchestrate.py plancannot see either (it never reads prose); the orchestrator's read pass (SKILL.md §Flow step 1, Profile and gather) can, since both signals are in plain text.What happened (both from the same run)
Facet 1 — #60 × #63 (file overlap → park). The planner put #60–#64 in wave 1 with no
Blocked byedges among them. #60 ("remove bootstrap") and #63 ("detached session-boundary pass + remove git bulk-capture") both heavily rewrote the same seam —transcript.py,curate.py,storeio.py,install.py. #63's own body said it "owns the full removal of the git bulk-capture path … across the seam … in one ticket, so no later ticket has to rewrite this seam across two files." Built concurrently off the same base; #60 integrated first; #63 — fully built, gates green, independently verified — could not fast-forward, its rebase hit real conflicts in all four files, and the engine parked it (correctly refusing to guess-merge). Net: 4/5 landed, #63 parked, remediated by a solo re-run against the advanced base.Facet 2 — #68 → #69 (cross-reference → dangling). #68 emits a session-start warning naming
mimer-manage disable-native-memory, a command #69 builds (its AC1). That is a real#68 → #69dependency, but no edge existed (#68 blocked_by [64,65];#69 blocked_by [63,64,65]— siblings). #68 ran first, so the command did not exist and the warning named a non-existent command. The docs-truthfulness gate caught it and #68's integration hotfix built #69's command itself (pulling #69's AC1/AC3 forward) — the safety net held, but at the cost of one issue's hotfix delivering another's scope plus a manual retarget of #69 onto its remaining AC. A#68 Blocked by #69edge (or splitting the shallowdisable-native-memoryout of the deeper #69) would have ordered it correctly. Aggravating factor upstream: #69 bundles a shallow deliverable (needs only #64) with a deep one (needs #63/#64/#65), so #68 could not depend on just the shallow half.Root cause
scripts/orchestrate.py planbuildsdependency_edges/wavespurely fromBlocked by#Ntokens; by design it never reads prose ("pure bookkeeping … never calls claude"), so it sees neither facet.skills/orchestrate/SKILL.mdstates "issues in one wave are independent and may run concurrently" — true for the dependency graph, false once file overlap (Facet 1) or a cross-reference (Facet 2) is present, and nothing instructs the planner to look for either.Why it was foreseeable
The signals were in plain text and the orchestrator's read pass already reads every body/brief. Facet 1: #60 and #63 both describe rewriting the capture/transcript seam. Facet 2: #68 names the exact command #69's body promises to build. A deliberate cross-issue pass over the same-wave set would have flagged both — serialize #60/#63, order #69 before #68. So both are preventable as a planning-time heuristic, not as anything the graph can prove.
Proposed solutions (one or more; not mutually exclusive)
A — Planning-pass instruction (cheapest; LLM-side, no code). Add to SKILL.md §Flow (steps 1–2): beyond the
Blocked bygraph, read each in-scope issue for implicit relationships and act on them —Blocked byedge), so no issue is built against a deliverable that has not landed.Surface both decisions at the confirm gate.
B — Fix the misleading wording + chunking guidance. Qualify "issues in one wave are independent" to mean dependency-independence only, and in §Cost and chunking name both file overlap and cross-references as serialization/ordering reasons, recommending one-issue-per-slice for tightly-coupled refactors.
C — Optional structured input for a deterministic signal. Let an issue/brief declare lightweight hints
orchestrate.py plancan read as soft edges without prose-reading:Touches: <area>(same-area issues in a wave → serialize) and/orProvides:/Needs: <capability>(aNeedsmatching another issue'sProvides→ an ordering edge).to-issues/triagepopulate them when cutting the slice — which is also the right upstream place to catch a missingBlocked byedge like #68 → #69.D — Engine-side auto-remediation (Facet 1; strongest AFK guarantee). When an issue parks on an integrate-time semantic rebase, have the engine attempt one solo rebuild against the now-advanced base (the manual fix that worked here) before parking-and-reporting, bounded by the fix-round cap.
Recommendation: A + B are near-free and would have prevented both incidents; C is the robust deterministic complement for briefed pipelines (and its
Provides/Needshalf is really an upstreamto-issues/triageimprovement); D is the strongest Facet-1 guarantee but the most work.Acceptance criteria (for triage — final set depends on the chosen direction)
Blocked byedge), surfaced at the confirm gate (Solution A, Facet 2).orchestrate.py planreadsTouches:(serialize) and/orProvides:/Needs:(order) hints as soft edges, covered bytests/test_orchestrate.py.CHANGELOG.mdupdated; the repo's gates (scripts/audit.py,pytest) green.Blocked by
Environment
.claude-plugin/plugin.json): 0.12.0