BUG — `motir batch` records NO implementation provenance: there is no way to stamp source/harness/model without a session branch
markIntegrated is the only path that writes the implementation provenance triple — implementationSource / implementationHarness / implementationModel. And motir batch never calls it: batch opens ONE pull request per item off main, so there is no session branch, and its drain ends at transitionStatus(key, 'in_review').
So every card ever run by motir batch has a null triple. Not a wrong value — an absent one, for an entire command's output, silently.
The real gap: provenance is welded to integration
This is not a missing call site. markIntegrated(workItemId, sessionBranch, ctx, implementation?) takes the branch as a REQUIRED positional, and the v1 endpoint behind it (POST …/work-items/{key}/integration) requires sessionBranch in its body. Provenance rides along as an optional fourth argument to an operation whose subject is the branch.
There is no way to say "this was built by X on model Y" without also saying "and it is integrated on branch Z". For a per-item-PR run, the second half is false.
⚠️ The obvious fix is the dangerous one
Do NOT invent a session branch for batch items so markIntegrated can be called. A recorded sessionBranch is not bookkeeping — isOpenBlocker treats a blocker carrying one as NOT OPEN, so stamping a fake branch would make that item stop blocking its dependents without a merge, and motir done --session <branch> would then find it at close-out. A provenance fix that silently unblocks dependents and enrols items in a session they were never part of is far worse than a null column.
What to build
A way to record implementation provenance that does not assert integration. Shape is the implementer's, but it must satisfy: provenance recorded, sessionBranch untouched, and no new way to accidentally stamp a branch.
The service already has recordImplementationProvenance as a separate function — it is the composition above it, and the v1 surface, that assume a branch.
Scope BOUNDARY
Recording provenance on the per-item-PR path. It does NOT change markIntegrated's behaviour when a branch IS supplied. It does NOT change the cascade, the close-out, or isOpenBlocker. It does NOT fix WHAT the harness value is on the session path — that is MOTIR-2419, and the two should agree on the value once both land.
Acceptance criteria
- A card run by
motir batchcarriesimplementationSource, andimplementationHarness/implementationModelper whatever MOTIR-2419 settles about their sources. - Its
sessionBranchis still null afterwards, asserted — this is the assertion that catches the dangerous fix. - The item still blocks its dependents exactly as before, asserted: recording provenance must not touch readiness.
motir done --sessiondoes not find a batch-run item, asserted.- The session-lineage path is unchanged, asserted by
motir auto's existing suite passing untouched. - If a new endpoint or a widened body is needed, it is additive under ADR §8 with the contract MINOR moved and the client regenerated.
Context refs
lib/services/workItemsService.ts—markIntegrated,recordImplementationProvenance,isOpenBlocker.app/api/v1/work-items/[key]/integration/route.ts— the endpoint that requiressessionBranch.packages/cli/src/commands/batch.ts— the drain that ends attransitionStatus.- MOTIR-2419 — the sibling defect: what the harness value should BE on the path that does record it.
- Story: MOTIR-1855.