As of 2026-08-18 23:40 IST, runner step 1 in progress. Skeleton written by the brains lane so the hands lane fills the sections as the CLI runs; every number below marked MEASURED comes from a run, everything else is a claim to replace. Source:
/Users/alcatraz627/Code/Versable/foundry-runner(working tree pastd076078; the import fix and the/manifest,/guidework are uncommitted pending the owner's word).
1. What it is#
The V1 runner: services-api/app extracted into the foundry_runner package
behind a payload port (step 0, dcdd0dd), the shared password replaced by a
keys verifier (d076078), then step 1: GET /manifest generated from what
the runner actually serves and validated against
../contracts/manifest.schema.json (0 errors), GET /guide rendered from the
manifest and nothing else, both answering 503 UNAVAILABLE with a gaps list
when the manifest would not conform. Python, FastAPI, runs locally with zero
env; V1 co-hosts the four capabilities on this one deployment under the
canon/14 exception (../adr/001 Consequences, ../patterns/00 V1
carve-out). Called by the console (versable-forge-v6) through
../contracts/module-surface.md routes only.
2. Shape of the runner#
Runner owns everything it serves; the payload owns capabilities. manifest.py
and guide.py are assembly only (no FastAPI import) so they test with no
third-party dependency; routes live in usage.py. surface.routes is
enumerated off the live router at request time (walking FastAPI's included
routers, which app.routes does not flatten), never hand-written. Config
gained RUNNER_MODULE (default unconfigured-module, deliberately implausible),
RUNNER_MODULE_VERSION, RUNNER_ENV, GIT_SHA, GIT_BRANCH, BUILT_AT,
RUNNER_PAGE_SIZE_DEFAULT, RUNNER_PAGE_SIZE_MAX, every one with a default.
3. Concern by concern#
Filled by inheritance from services-api at extraction (step 0 lifted
services-api/app wholesale), with the rows step 1 changed marked; every
inherited row is a claim to re-verify against foundry_runner/, not a read.
| # | Concern | Mechanism | Where | Vendor-specific? |
|---|---|---|---|---|
| 1 | Runner/payload seam | inherited from services-api at extraction (versable-runner.md row 1); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 2 | Caller identity | local verifier only, fixed context caller_id: local, env local, all scopes (canon/02); the shared password remains beside it outside local, a lapse; keys and remote not yet implemented | foundry_runner/identity.py, d076078 | no |
| 3 | Tenancy | inherited from services-api at extraction (versable-runner.md row 3); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 4 | Roles / RBAC | inherited from services-api at extraction (versable-runner.md row 4); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 5 | Submit surface | inherited from services-api at extraction (versable-runner.md row 5); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 6 | Job state ownership | inherited from services-api at extraction (versable-runner.md row 6); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 7 | Derived vs stored status | inherited from services-api at extraction (versable-runner.md row 7); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 8 | Dispatch / queue | inherited from services-api at extraction (versable-runner.md row 8); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 9 | Concurrency | inherited from services-api at extraction (versable-runner.md row 9); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 10 | Retry / backoff | inherited from services-api at extraction (versable-runner.md row 10); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 11 | Heartbeat | inherited from services-api at extraction (versable-runner.md row 11); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 12 | Cancel | inherited from services-api at extraction (versable-runner.md row 12); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 13 | Resume / checkpoint | inherited from services-api at extraction (versable-runner.md row 13); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 14 | Idempotency | inherited from services-api at extraction (versable-runner.md row 14); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 15 | Storage of inputs | inherited from services-api at extraction (versable-runner.md row 15); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 16 | Storage of outcomes | inherited from services-api at extraction (versable-runner.md row 16); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 17 | Results reporting | inherited from services-api at extraction (versable-runner.md row 17); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 18 | Logs per job and item | inherited from services-api at extraction (versable-runner.md row 18); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 19 | Tracing | inherited from services-api at extraction (versable-runner.md row 19); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 20 | Usage metering | inherited from services-api at extraction (versable-runner.md row 20); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 21 | Limits / quotas | inherited from services-api at extraction (versable-runner.md row 21); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 22 | Caching | inherited from services-api at extraction (versable-runner.md row 22); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 23 | Rate limiting outbound | inherited from services-api at extraction (versable-runner.md row 23); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 24 | Config | inherited from services-api at extraction (versable-runner.md row 24); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 25 | Secrets | inherited from services-api at extraction (versable-runner.md row 25); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 26 | Human in the loop | inherited from services-api at extraction (versable-runner.md row 26); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 27 | Completion signalling | inherited from services-api at extraction (versable-runner.md row 27); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 28 | Capability discovery | GET /manifest generated from the live router and validated against manifest.schema.json, ETag/If-None-Match, 503 with gaps when non-conforming; GET /guide rendered from the manifest only; /usage remains the hand-written quickstart | foundry_runner/manifest.py, guide.py, usage.py | no |
| 29 | Versioning | inherited from services-api at extraction (versable-runner.md row 29); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 30 | Health / readiness | inherited from services-api at extraction (versable-runner.md row 30); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 31 | Provisioning | inherited from services-api at extraction (versable-runner.md row 31); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 32 | Local dev | inherited from services-api at extraction (versable-runner.md row 32); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 33 | Output delivery | inherited from services-api at extraction (versable-runner.md row 33); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 34 | Data retention | inherited from services-api at extraction (versable-runner.md row 34); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 35 | Multiple versions | inherited from services-api at extraction (versable-runner.md row 35); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 36 | Conformance | inherited from services-api at extraction (versable-runner.md row 36); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 37 | Outputs and exports | inherited from services-api at extraction (versable-runner.md row 37); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
| 38 | Data ownership split | inherited from services-api at extraction (versable-runner.md row 38); re-verify against foundry_runner/ before trusting | (as versable-runner, pending re-read) | as versable-runner |
4. Runner vs payload#
The seam is the payload port (foundry_runner/payload.py); step 0 measured it
as one call plus two discovery reads. /usage is still payload-authored
through describe() and stays as a hand-written quickstart beside the
generated /guide (BACKLOG, retire when the console renders the guide).
5. Deliberate decisions#
/manifestreturns 503 with gaps rather than a non-conforming 200 (now contract,../contracts/module-surface.md).- Routes enumerated live, not listed, so the manifest cannot drift from the router.
- Assembly modules kept dependency-free for testability.
6. Lapses#
- Could not import between
dcdd0ddand the step-1 fix (stalefrom app importlines, two of them lazy inside functions): step 0's tests exercised only the seam, so a green suite shipped a runner that could not start. The[declared-ready]shape; recorded so the pattern is remembered. - One verifier of four; conforming in
env: localonly untilkeysorremotelands. - A1, fixed.
/healthreturned{"ok": true}whereconformance.mdA1 pins{status: "ok"}, inherited fromservices-apiby the extraction.foundry_runner/main.py. No sha: the fix is uncommitted, see below. - A6, fixed.
/build-inforeturned 404; the runner never served it. Added open, reading the same settings the manifest uses so the two cannot disagree.foundry_runner/usage.py. No sha, same reason. - Both fixes, and all of step 1, are uncommitted working-tree state as of
this run. The owner has not asked for a commit and the agent does not commit
unasked, so this doc cites files rather than shas. Every row above was
measured against that working tree, not against
d076078. client_job_idand the jobs-index adapter are not implemented; both are step-1 pieces still open, so C3 (repeatedclient_job_idis idempotent) cannot pass whatever the run says.
7. Conformance, MEASURED#
| run | rows attempted | pass | fail | n/r | advisory | by | how |
|---|---|---|---|---|---|---|---|
| 2026-08-18 | 40 | 12 | 0 | 27 | 1 | gcp-opus | foundry-conform http://127.0.0.1:6217 against the local runner, env: local, one synthetic payload declaring content.generate, --allow-writes OFF |
| 2026-08-19 15:55 IST | 40 | 12 | 2 | 25 | 1 | gcp-fable | foundry-conform http://127.0.0.1:5110 --table conformance.md against the pm2 service after the full step-1 surface landed (contract create, outcomes, jobs index, facets, re-run); the two FAILS are B1 and B2, /jobs and /stats answering 200 to an anonymous caller: the service is deliberately open (no app password, local verifier only), so these are honest fails by configuration where the earlier run read them as n/r on a 5xx; 17 rows still unattempted by the CLI (the same set); --allow-writes adds no rows yet because the mutating checks are not written, only gated |
17 further rows the CLI does not attempt at all: B4, B5, B6, B7, B8, C1, C2, C4, D1, D3, D4, D5, D6, D7, D8, D9, E4. They have no check written, so they are neither passes nor failures. The CLI names them on every run rather than omitting them, because a row absent from a report reads as a row that passed.
Zero failures is not a clean bill. It means every row this configuration
could reach passed. The rows most likely to fail are among the 43 that did not:
tenancy, per-caller credentials, callbacks, ceilings. --allow-writes was off,
so nothing that creates or mutates a job ran (C3, C5, C6, E1, E2, H3).
Three rows ran here for the first time in the estate: H4, H5 and H6, the
membership checks manifest.md § Validation assigns to conformance rather than
to the schema. They were n/r everywhere for one reason, that nothing served
/manifest, so there was no declaration to read back.
This measures a local process with no queue, no real storage and no credential.
It says nothing about a deployed foundry-runner, and there is not one yet.
Evidence: ../evidence/20260818-foundry-runner-conformance.md.
Section H (manifest against behaviour) reported beside the contract rows; group M (module-supplied evals) reported separately and never counted.
8. Unproven#
Everything in sections 3 and 6 not tagged with a file:line; the tally until the row above is filled.