feat(p17b): ONE commission, SEVERAL bases -- reachable from the command line

``run_mandate_across_bundles`` has existed since session 58, reachable from FIVE
test files and from NO command line (measured: ``grep -n across-bundle run.py``
= 0 hits). ``--across-bundle <dir>``, repeated once per base, is that door.

The engine takes a CALLBACK rather than an outbox directory. Its own docstring
has always said N runs need N ``run_id``s and that minting them there would
default a key this repo requires a caller to supply -- so ``outbox_for`` is that
contract KEPT, not relaxed, and the operator-chosen ``<run-id>-<bundle_id>``
rule lives in ``main()`` where the decision was made. The order's alternative (a
caller running ``run_project`` itself over ``route_by_bundle``'s sub-mandates)
would be a second copy of the loop's id reconciliation, shared store, per-base
project resolution, collision accounting and both budget teeth.

``resolve_bundle_routing`` is ONE resolution shared by the engine and the
dry-run arm: a free trip answering with a different project id, or tolerating a
duplicate id the paid dispatch refuses, would rehearse a different run.

``{run-id}-multibase.json`` is written from a ``finally`` and every row is built
from the resolution plus disk, so the pass a cap cut short still leaves the
record. ``completed`` is a required field for ``ExplorationTrace.completed``'s
reason. ``stop_reason`` is read BACK from each base's own coverage artefact.

Load-bearing MEASURED (17 arms), four mutations all red against the WHOLE suite,
green control 1761/5 (from 1744/5, superset, 0 removed), golden byte-unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-15 04:24:48 +02:00
commit 5e4c497a84
5 changed files with 994 additions and 37 deletions

View file

@ -2728,6 +2728,47 @@ Python ≥3.10. MAF (`agent-framework-core` 1.16.0, `-orchestrations` 1.1.1 —
runde betaler første approach, den andre er den taket kutter). **Ærlighets-grense, uttalt:**
`token_usage` er kjøringens ENE teller — den skiller ikke debatt fra generering, og en
per-fase-fordeling ville krevd en andre måler.
- **ÉN kommisjon, FLERE baser er nåbar fra CLI-en — og utboksens nøkkel er KALLERENS, aldri
motorens (P17b DEL 1, 15.09):** `run_mandate_across_bundles` har eksistert siden økt 58, nåbar
fra FEM testfiler og fra INGEN kommandolinje (MÅLT: `grep -n across-bundle run.py` = 0 treff).
`--across-bundle <dir>` (repeterbart; `--bundle-dir` forblir ÉN katalog og er NEKTET her) krever
`--mandate`, `--run-id` og `--outbox-dir`. **Motoren fikk en CALLBACK, ikke en `outbox_dir`:**
dens egen docstring har alltid sagt at N kjøringer trenger N `run_id`-er og at å mynte dem der
ville defaultet en nøkkel repoet krever at en kaller oppgir — så `outbox_for(bundle_id) ->
(dir, run_id)` er dét kravet OPPFYLT, ikke slakket, og myntingsregelen `<run-id>-<bundle_id>`
(OPERATØRVALGT 14.09) bor i `main()` der beslutningen ble tatt. Ordrens andre alternativ — en
kaller som kjører `run_project` selv over `route_by_bundle`s sub-mandater — ville vært en ANDRE
kopi av løkkas id-avstemming, delte store, per-base-prosjektoppslag, kollisjonsregnskap og
BEGGE budsjett-tenner: kø-(p) over fem regler som hver har ett hjem.
**`resolve_bundle_routing` er ÉN oppløsning, delt av motoren og dry-run-armen:** en gratis tur
som svarte med en annen `project_id`, eller tolererte en duplisert id den betalte kjøringen
nekter, ville vært en generalprøve på en annen kjøring. **Samlefila skrives fra en `finally`**
(`write_parse_failures`-presedensen) og hver rad bygges av RESOLUSJONEN + DISK — de konfigurerte
basene, kallerens egen myntingsregel, og hver bases egen `{run_id}-coverage.json` — så den
kjøringen som mest trenger regnskapet, den et tak kappet, etterlater det. `completed` er et
EGET påkrevd felt (`ExplorationTrace.completed`s grunn ordrett): «ingenting ble uoppnådd» og
«vi fikk aldri vite» må ikke være samme verdi. `stop_reason` LESES TILBAKE fra coverage-fila,
aldri utledet på nytt — P19 D2 la faktumet der, og en andre utledning her ville stått fritt til
å være uenig med den dommeren leser. **`BudgetExceeded` er i nekt-tuppelen** av
enkeltprosjekt-stiens MÅLTE grunn: den er en `RuntimeError`, og den FØRSTE tilnærmingen som
treffer taket re-raiser ved design — over flere baser er dét ikke et kanttilfelle (runde 3 målte
`stop_reason: rounds` i 5 av 5), så uten armen er en multi-base-kjørings vanligste utfall en
traceback. Tre partisjons-rader: `report_forbidden` og `--portfolio` NEKTER ved navn, mens
live-dry-run-raden er en WIRING — den driller HVER konfigurert base og printer hver bases egne
varsler, fordi en kjøring som sa dem én gang bare kunne snakket om én av N. Load-bearing MÅLT
(`tests/test_across_bundles_cli_loadbearing.py`, 17 armer), **fire mutasjoner alle røde mot HELE
suiten** + grønn kontroll **1761/5** (fra 1744/5, supersett, 0 fjernet) og golden
`demo-transcript.stdout` BYTE-UENDRET (`shasum -a 1` av INNHOLDET =
`ea8c534773acdbe41ae68f2c55724d69aaf8be4f`): (i) samlefila droppes (2 røde) · (ii) myntingen
kollapser til bart `<run-id>` (3) · (iii) `report_forbidden` slipper flagget stille (1) ·
(iv) `opened`/`requirements`-sinkene deles mellom basene (5, hvorav FIRE i tester eldre enn
dette arbeidet — uavhengige vitner på at sinkene er per kjøring). **Ærlighets-grenser, uttalt:**
en base som RAISER propagerer fortsatt (motorens egen dokumenterte grense — `collect-and-continue`
tilhører `run_portfolio`), så de etterfølgende basene kjøres ikke og samlefila sier `completed:
false`; `announce` sier fortsatt «the portfolio» når ingen `project_id` er gitt; den hostede
flaten er BEVISST urørt (feltet er i ingen av hostings tre sett); og `--proposal-review` trås
gjennom til ÉN terminal delt av alle basene (motorens egen begrunnelse — dispatchen er
sekvensiell).
- **STATE.md er local-only** (gitignored). Voyage session-state er efemert; STATE.md er kanonisk kontinuitet.
- Prosess: Voyage-plugin (`/trekbrief → /trekplan → /trekexecute → /trekreview`) per større fase.