I3915 — A combined top is composed by a typed command from members declared in a tracked train manifest
majordomus prs compose builds a combined top from a tracked train manifest under .ai/repo/integration/trains/ that lists its members (a branch head or a source patch, with its seat, its issue and its order constraints) and its base. It composes them in order on a scratch index, names each member that does not apply, and only then runs one derive and opens or updates the train pull request. Two machines composing the same manifest produce the same member list and the same tree before the derive; the derived output is the derive's, which ADR 0101 does not hold deterministic per tree.
BLOCKED wave 1 · p1 · implementation profile · runs alone
Part of landing-survives-any-session — Landing green work survives any session, any restart and any machine.
Blocked. This issue cannot start until I3910 is done. The status is derived from that, not declared.
Objective
majordomus prs compose builds a combined top from a tracked train manifest under .ai/repo/integration/trains/ that lists its members (a branch head or a source patch, with its seat, its issue and its order constraints) and its base. It composes them in order on a scratch index, names each member that does not apply, and only then runs one derive and opens or updates the train pull request. Two machines composing the same manifest produce the same member list and the same tree before the derive; the derived output is the derive's, which ADR 0101 does not hold deterministic per tree.
Why
Trains 3a, 3b and 4 were composed by shell scripts under ~/.cache/mj-e7 and ~/.cache/mj-a3; when the seats holding them died on 2026-10-22 the next seat had to reconstruct the order from a ledger, and each train needed two or three fix commits for reds the composition could have found.
Current state
train.rs reads stacked pull requests and refs/prep only; prs compose was planned in ADR 0167 and never landed; train member order lives in session caches.
Desired state
A seat composes a train with one command from its manifest; another seat on another machine composes the same pre-derive tree from the same manifest.
Scope
- apps/majordomus-cli/tests/integration_executor.rs
- apps/majordomus-cli/src/integration/train.rs
- apps/majordomus-cli/src/commands/prs.rs
- docs/INTEGRATION.md
- .ai/repo/project/issues/I3915.yaml
Dependencies
What waits on this
- I3976BLOCKED Every commit names the issue it serves, outside narrow machine-verifiable exemptions, with the earlier history as a baseline
- I3978BLOCKED Each train member is judged on its merged tree, and a fix member joins only with a test and its changed-code coverage
Acceptance criteria
- compose applies the manifest's members in order on a scratch index and names each member that does not apply
- Two compositions of one manifest give the same member list and the same pre-derive tree (case a_train_manifest_composes_one_tree)
- No member order is read from a session cache
Validation
- bin/majordomus plan validate
- env -u MAJORDOMUS_SHARE cargo test --manifest-path apps/majordomus-cli/Cargo.toml --lib -- integration::train
Evidence required
- trains_are_composed
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I3915.yaml. Read it back with majordomus plan show I3915.