11.5.24 Decision, then implement — the v1 ready row says READY but not "ready relative to WHAT": the inherited session branch
A ready item can be ready in two materially different ways, and the v1 row cannot tell them apart:
- ready from
main— every dependency is merged, so the work starts from the trunk; - ready on an inherited LINEAGE — the dependencies are integrated onto a session branch that has not merged, so starting the work means building on unmerged code.
The server computes this (getReadiness().inheritedSessionBranch) and the MCP dispatch payload publishes it as sessionBranch. lib/api/v1/ready/schema.ts deliberately leaves it off the v1 row, grouped with runCommand / contextRefs / targetRepo as things that "encode assumptions about a local checkout a third-party integration does not share".
That grouping is what this card re-examines. runCommand is an invocation string and targetRepo names a checkout — both are genuinely local. The inherited lineage is neither: it is a qualifier on the readiness the row is already asserting, and any consumer that acts on "ready" wants it. An agent loop that takes a lineage item without knowing it will open a pull request against a base that does not exist yet.
The consumer that forced the question
motir batch opens ONE pull request per item, off main. Its snapshot refuses lineage items for that reason (classifySnapshotItem → integrated_dep), and the refusal is printed in the plan a human reads BEFORE the run. MOTIR-2398 moves the snapshot onto the v1 ready collection, where the field does not exist.
The two routes around it were considered and rejected:
- Read the dispatch prompt per candidate — N requests to build a snapshot, and it moves a classification the plan prints into the drain that happens after the plan is printed.
- Drop the refusal —
motir batchwould take lineage items and open pull requests against unmerged bases.
The decision to record
Follow Amendment 10 Q1's precedent, which reversed this exact kind of omission for assignee.name: an embedded, minimal, read-only field that every integration needs is a FIELD, not an accidental resource, and "one CLI wants it" was the wrong reading — every agent loop wants it.
Name it for what it MEANS to a reader of the row, not for the CLI's use of it. sessionBranch on the dispatch payload reads as "the branch to work on"; on a ready row the fact is "this item's dependencies are integrated somewhere that is not main yet". Pick a name that survives being read by someone who has never used the CLI.
What to build
- An ADR amendment in
docs/decisions/public-api-conventions.mdrecording the reversal, its reasoning, and the rule it generalises to: a collection row that asserts a DERIVED state must carry what qualifies that state, or the assertion is not actionable. - The field on
readyItemSchema+ its presenter, sourced from the same readiness the row'sblockedBycomes from. - The contract MINOR bump (a new field on a shipped response is additive, §8), and the regenerated
packages/cli/src/apiartifact. lib/api/v1/ready/schema.ts's "deliberately NOT on the row" list updated — the entry moves out with a ⚠️ note saying it used to be there and why it moved, matching how Amendment 10 Q1's reversal is recorded.
Scope BOUNDARY
The ready row, its amendment, the version bump and the regenerated client. It does NOT change the CLI's behaviour — MOTIR-2398 consumes this. It does NOT add runCommand, contextRefs or targetRepo to the row; those stay off, and the amendment must say why this one is different rather than reopening all four. It does NOT touch the MCP dispatch payload.
Acceptance criteria
- The amendment is numbered against
mainand every in-flight branch (the amendment-number race check), and states the general rule, not just this field. - The field is on the emitted document, the served row, and the regenerated client types; the drift guard passes.
- The contract version's MINOR moves, and the freshness guard is green.
- A route test asserts the field is non-null for an item whose dependencies are integrated on a branch and null for one ready from
main— the distinction is the whole point, so both sides are asserted. lib/api/v1/ready/schema.ts's omission list no longer claims this field is absent.
Context refs
lib/api/v1/ready/schema.ts— the row, the omission list, and Amendment 10 Q1's reversal note as the template.- ADR
docs/decisions/public-api-conventions.md— Amendment 10 Q1 (the precedent) and Q2 (which named the dispatch prompt as the replacement fortargetRepo; this card does not disturb that). packages/cli/src/batchPlan.ts—classifySnapshotItem, the consumer whose refusal depends on this.- MOTIR-2398 — blocked on this.
- Story: MOTIR-1855.