Skip to content

Let stage numbering express independence, and add the join contract - #5

Open
dubedad wants to merge 1 commit into
RinDig:mainfrom
dubedad:concurrent-stages-and-joins
Open

Let stage numbering express independence, and add the join contract#5
dubedad wants to merge 1 commit into
RinDig:mainfrom
dubedad:concurrent-stages-and-joins

Conversation

@dubedad

@dubedad dubedad commented Jul 27, 2026

Copy link
Copy Markdown

The problem

Folder numbering is a total order. 01_, 02_, 03_ can only say "after." So a workspace with three genuinely independent steps — three scans that all read the same brief, none of which reads another's output — has to number them in sequence anyway, and the numbering lies. It asserts two dependencies that don't exist, and an agent walking the workspace cold will believe it.

core.md already says the structure is the documentation. A structure that misstates its own dependencies is a defect rather than a style choice, and today the method has no way to write down "these two are unordered."

The change

Four files, one convention, one new template.

Siblings sharing a number and differing by a letter are unordered. 02a_, 02b_, 02c_ are peers; the next integer runs after all of them. The letter is not a priority.

stages/
├─ 01_scope/          → output/brief.md
├─ 02a_market/        reads 01
├─ 02b_competitors/   reads 01
├─ 02c_regulatory/    reads 01
└─ 03_synthesis/      reads 02a + 02b + 02c

Status still comes from scanning output/ — it just reads as a checklist rather than a cursor. 02a ✓ 02b ✓ 02c ▢ says one branch is outstanding and synthesis is blocked, which is more informative than a single position on a line.

The stage after a fan is a join, and its contract does the waiting. It names every sibling output as an exact working input and states what it's waiting for. No new mechanism — the existing Inputs section already carries this; it just needed naming and a template (assets/templates/join-CONTEXT.md). The join flags contradictions between branches rather than silently resolving them, which puts the judgment call in front of a person before the expensive downstream work — the same move as any other stage boundary.

Two limits, stated with the convention

These matter more than the convention itself, and I'd rather they be in the doc than discovered later:

  • Fan width is bounded by human attention, not compute. The bottleneck in an ICM is the human gate, not model wall-clock. Parallelising three stages that each need twenty minutes of review saves seconds and creates a review pile. Two to four branches. If the work is wider and uniform — score twelve processes, audit thirty files — the repeating unit is a record, not a stage, and the record library already handles it with the index log as the join.
  • A fan is declared at design time, never inferred mid-run. A run that decides its own width can't name its inputs, only glob them, and the structure stops being readable before it executes. Build mode gains one interview question (does this step need the step before it, or just the original input?) so independence is established when the workspace is designed.

One thing to check carefully

This introduces a notation clash, and I've resolved it in a way you may disagree with.

core.md "Where ICM loses" used "3a vs 3b" to mean two mutually exclusive alternatives. Under this convention, letters mean concurrent peers — the opposite reading. That's exactly the "schema mandating names the files stopped using" anti-pattern the guardrails warn about, so leaving both would be worse than either.

I reworded that line to "two alternative stages at a gate" and made the distinction explicit: a fan runs every branch at a fixed width, so nothing is decided at run time, and it therefore doesn't fall under the mid-pipeline branching guardrail. Branching selects a path; that selection remains the hand-off point to framework code.

If you'd rather keep letters for alternatives, the fix is to pick a different marker for concurrency and I'll redo it.

Walk test

Adds one check, since a convention with no way to falsify it will drift:

Does any stage share a number with a sibling? Then confirm neither reads the other's output, and that the next stage names all of them in its inputs. A lettered stage reading a lettered sibling means the numbering is lying — renumber serially.

Files

  • SKILL.md — invariant 3 extended, one Build mode question, one walk test check, template list
  • references/core.md — new Parallel stages and the join section, naming convention, reworded branching guardrail
  • references/forms.md — one defining move added to Pipeline
  • assets/templates/join-CONTEXT.md — new

Docs only; nothing here changes an existing workspace. Happy to cut any part of it — the notation clash is the piece I'd most want your call on.

🤖 Generated with Claude Code

Folder numbering is a total order, so a pipeline can only say "after."
Independent steps therefore have to be numbered as though each depends on
the last, which asserts a dependency that does not exist. In a method
whose structure is its documentation, that is a defect rather than a
style choice.

Siblings that share a number and differ by a letter (02a_, 02b_) are
unordered with respect to each other; the next integer runs after all of
them. The stage after a fan is a join, and its contract does the waiting
by naming every sibling output as an exact working input. The existing
Inputs section already carries this, so no new mechanism is introduced.

Two limits are stated with the convention: fan width is bounded by human
attention rather than compute (two to four branches; wider and uniform
means the unit is a record, so use a record library), and a fan is
declared at design time, never inferred mid-run — a run that decides its
own width has to glob its inputs and stops being readable before it
executes.

Also reconciles a notation clash this introduces: "Where ICM loses" used
"3a vs 3b" for mutually exclusive alternatives, which would now read as
concurrent peers. Reworded, and the distinction made explicit — a fan
runs every branch at a fixed width, so nothing is decided at run time,
and it does not fall under the mid-pipeline branching guardrail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant