← back

STATUS · CURRENT IN KIND, AS OF 2026-08-05. Still the most detailed inventory of the codebase, and its method (report the code, record the gaps) is unchanged. But it was assembled from main @ 545a2ac and the repository has moved since. Known drift, so you can read it with the right discount:

it saystoday
engine toy-v0.3 / toy-v0.5toy-v0.8 (src/ah/core/engine.py's TOY_ENGINE_VERSION)
schemas/worldspec-v1.2.schema.jsonworldspec-v1.3.schema.json has landed alongside it
toy presets in the 5xx blocktoy presets 511–514; the shipped world is stagflation_1974 …603; stress worlds are …701/702/703
sleeve mappings v1.0v1.1 (map-2026.08.2) — PM rows re-estimated under AM-2026-08-12-001
the play surface is Play.tsx's panelsthe CIO dashboard is the play surface (cio-03); Book/PrivateMarkets retired
—the stress-scenario compiler (src/ah/gen/stress.py) did not exist
—play alphas are port-v4-ladder / port-v4-ladder-gen
hier-flow-v1 beats the benchmark on the sealed criterion (§5.9)retracted. The third campaign (2026-08-11, full 1953–2020) reversed it; bootstrap-v1 is generator of record by the challenger's failure, not by a sealed win

For what has been built and by what method as it stands today, read docs/current/METHOD.md first. Index: docs/current/README.md.


BUILD-SUMMARY.md — what actually exists

Assembled 2026-08-05 from the repository at main @ 545a2ac, by reading the code and running it. Where a design document and the code disagree, the code is reported and the disagreement is recorded in §5. Nothing planned is described as existing.

How to read this. §1 is the map. §2 is the inventory with evidence and invocation. §3 is the configuration, verbatim from the files that hold it. §4 is the test estate. §5 is the gap list, and §5 is the part worth your time — an orientation document whose gap section is short is a document that did not look.


1. System map

Dependency direction is downward only. port / gen / eval / artifacts depend on data, which depends on core; nothing points back up. The product surface (bundle, feed, serve, play, credibility, programme) sits on top of core + port and is the only layer the browser sees.

Terrarium/
├── src/ah/
│   ├── core/                  the numeric core — no pandas, no network, no clock
│   │   ├── worldspec.py       pydantic mirror of schemas/worldspec-v1.2.schema.json
│   │   ├── loader.py          jsonschema-first then pydantic (a property test pins agreement)
│   │   ├── validator.py       V1–V12 coherence rules; V10/V11/V12 block   → validate()
│   │   ├── numericworld.py    the narrative-free projection the engine consumes
│   │   ├── engine.py          the deterministic toy engine `toy-v0.3`     → run_path/run_ensemble
│   │   ├── institution.py     Step-0 toy institution (8 weights, no cash) → simulate_institution
│   │   ├── sleevestate.py     Step-3 sleeve/vehicle state contract
│   │   ├── institutionstate.py institution state for the twin
│   │   └── digest.py          canonical JSON + SHA-256 over float64 tensors
│   ├── store/                 SQLite; append-only where it matters
│   │   ├── db.py              schema + triggers (chronicle UPDATE/DELETE refused)
│   │   ├── worlds.py          save_world refuses edits to engine-consumed fields
│   │   ├── runrecords.py      RunRecords + verify_run (the anchor behind `ah replay`)
│   │   ├── chronicle.py       append-only event log per world
│   │   ├── sessions.py        play sessions: monotone pointer, final decisions
│   │   └── leaderboard.py     submit_score/scores over db.py:92's
│   │                          UNIQUE(world_id, seed, decision_alpha_version, participant)
│   ├── compiler/              scenario text → raw world document
│   │   ├── pipeline.py        validate → clamp → construct WorldSpec       → process()
│   │   ├── fixture_adapter.py the offline compiler (50 committed fixtures)
│   │   └── anthropic_adapter.py the live compiler, imported only under --live
│   ├── data/                  Step 1 — immutable Parquet vintages over DuckDB
│   │   ├── catalog.py         the vintage store; `current` advances only if QC passes
│   │   ├── connectors/        fred, bis, french, jst, shiller, treasury_hqm
│   │   ├── qc.py splice.py derive.py desmooth.py episode.py reports.py refresh.py
│   │   └── cli.py             → `ah data …`
│   ├── gen/                   Step 2 — the generator layer (research, NOT on the play path)
│   │   ├── registry.py        generator_id → factory                       → resolve()
│   │   ├── bootstrap.py       `bootstrap-v1`, the sealed benchmark
│   │   ├── climate/ regimes/  L1 (numpyro) and L2 (semi-Markov)
│   │   ├── blocks/            L3 — diffusion + flow (`hier-flow-v1`, torch)
│   │   ├── joinery/           L4 — waypoints, bridge, Denton reconciliation
│   │   └── systems.py         the five ablation systems A–E
│   ├── eval/                  the sealed judging code (hashed in pre-registration.lock)
│   │   ├── prereg.py g2.py g3seal.py g5seal.py     seals, locks, amendment log
│   │   ├── battery.py metrics/                     the Step-2 validation battery
│   │   ├── decision_metrics.py                     Step-5 sealed metric set
│   │   └── walkforward.py counterfactual.py episode2022.py negative_controls.py
│   ├── port/                  Step 3 — the translation layer and the real institution
│   │   ├── sleeves.py vehicles.py cohort.py        state objects
│   │   ├── cashflow_tier0.py cashflow_tier1.py     the commitment/call/distribution model
│   │   ├── portfolio.py                            cash account + coverage on both bases
│   │   ├── engine.py                               the quarterly waterfall  → PortfolioEngine
│   │   ├── twin.py                                 the DB-pension institutional twin
│   │   └── mapping.py smoothing.py heroes.py proxy.py
│   ├── artifacts/             Step 4 — the wire, the letters, the committee
│   │   ├── templates.py render.py                  Tier-1, pure functions of the tape
│   │   ├── author.py prompts.py gate.py            Tier-2 authoring + the G1–G9 gate
│   │   ├── bible.py validation.py committee.py     continuity, actor study, AI committee
│   │   ├── chronicle.py payloads.py                the G9 publication record (unused — §5.13)
│   │   └── live.py calendar.py windows.py decisions.py
│   ├── battery/               Step-0 stylized battery (thresholds still `todo` — §5)
│   ├── presets/               the four preset worlds
│   ├── splits.py              train/val/holdout + the FinalEvaluationToken guard (sealed)
│   ├── factors.py strategies.py  the factor manifest and the D4 strategy set (both sealed)
│   ├── experiment.py          local-first experiment tracking under experiments/
│   ├── play.py                the playable institution on the Step-3 twin → simulate_play
│   ├── bundle.py              the world bundle, contract `world-bundle-0.4` → build_bundle
│   ├── feed.py                the in-timeline tier-1 wire                  → build_tier1_feed
│   ├── serve.py               FastAPI session service — the scoring authority
│   ├── credibility.py         admin console: does this world's arithmetic look sane
│   ├── programme.py           the private-programme section of that console
│   ├── inspect.py             static figure page from a RunRecord alone
│   ├── tournament.py density.py                    Step-5 harnesses
│   └── cli.py exp_cli.py      → `ah`, `ah exp`
├── app/                       the React/TS player (vite 5173, proxies /sessions → 8787)
├── schemas/                   READ-ONLY vendored contract truth
├── mappings/                  frozen parameter artifacts (pacing, tier-0 spec, tier-1
│                              linkage, smoothing kernel, sleeve mappings)
├── fixtures/                  compiler, state, worlds, entity_screen, actor_validation,
│                              authoring_regression
├── tests/                     121 test modules + one shared helper
├── scripts/                   53 deterministic build/measure/train scripts
├── Instructions/              the authoritative plans, design notes and kickoffs
├── governance/                seals, amendment log, decision register, GenAI pack, evidence
├── docs/                      the realism register, data specs, and the superpowers plans
├── artifacts/                 committed research outputs (wp24…wp57, campaign2)
├── configs/ taxonomy/         search configs and the sleeve taxonomy
├── experiments/  (gitignored)  trained checkpoints and experiment records
└── data/         (gitignored)  the Parquet vintage store and data/ah.db

Entry points, exhaustively. The console script ah (pyproject.toml:35 → ah.cli:app); the ASGI app ah.serve:app (src/ah/serve.py:318); the module entry python -m ah.battery.report; the vite app in app/; and the 53 scripts in scripts/, each run with uv run python scripts/<name>.py.


2. Capability inventory

Status vocabulary: working — runs end to end and I ran it; partial — runs, but a named part of what the design asks for is absent; stub — present as an interface or placeholder without the substance behind it; absent — named somewhere but not built; unverified — I could not run it. Qualifiers after a status ("working, sealed"; "working locally, not reproducible from a clean clone") are free text, not vocabulary.

Flags are not exhaustive. The "how to invoke" column shows the shortest command that does the thing, not every option. Notably absent from it: ah data refresh --dry-run/--source/--vintage, the --data-root/--root overrides on the data and experiment commands, and ah credibility --seed. Run --help on any subcommand for the full set.

Coverage of this inventory, stated: core/, port/ and store/ are covered module by module. eval/, gen/, compiler/ and data/ are covered by capability, not by module — 28 of the 157 modules under src/ah/ have no row of their own, including sealed judged code (factors.py, strategies.py, eval/reference.py, eval/panel.py, eval/ablation.py, eval/sleevetails.py) and gen/base.py. See §5.15.

World generation

capabilitystatusevidencehow to invoke
Preset worlds (4)workingsrc/ah/presets/*.json; ran all four through build/validateah world build --preset stagflation
Scenario → world, offlineworkingsrc/ah/compiler/fixture_adapter.py; 50 fixtures in fixtures/compiler/; I built 00000000-0000-4000-8000-000000000000 from a fixture scenarioah world build --scenario "<text from fixtures/compiler/_manifest.json>"
Scenario → world, live LLMunverifiedsrc/ah/compiler/anthropic_adapter.py, imported lazily at src/ah/cli.py:117ah world build --scenario "…" --live (needs network + key; not run)
Toy engine toy-v0.3workingsrc/ah/core/engine.py:42, run_path at :261, run_ensemble at :415ah run [WORLD_ID] --paths N --seed S
L1 climate layerworking locally, not reproducible from a clean clonesrc/ah/gen/climate/; the fitted posterior is experiments/climate-l1-f7d4119c7101-s20260726/climate-posterior.npz, SHA-pinned at joinery/assemble.py:140,146. the L1 fit report is experiments/climate-l1-…/climate-fit-report.md, gitignored alongside the posterior; artifacts/wp27/ carries the downstream joinery/battery reportuv run python scripts/fit_climate.py
L2 regime layerworking locally, not reproducible from a clean clonesrc/ah/gen/regimes/; posterior at experiments/regimes-l2-1758709d4009-s20260727/, SHA-pinned at joinery/assemble.py:143,147uv run python scripts/fit_regimes.py
L3 block generatorsworking locally, not reproducible from a clean clonesrc/ah/gen/blocks/flow.py:583 registers hier-flow-v1; the factory hard-requires experiments/campaign2-flow-s0/checkpoint.pt against pinned SHA c6addb54… (flow.py:503,514,551). experiments/ is gitignoredregistry.resolve("hier-flow-v1") — I confirmed it resolves here and the checkpoint hash matches
L4 joineryworking (research)src/ah/gen/joinery/{waypoints,bridge,reconcile,assemble}.pyvia the systems in src/ah/gen/systems.py
Ablation systems A–Epartialsrc/ah/gen/systems.py:503,610; registry lists abl-a/b/c variants. abl-b-neural-rollout-diffusion and abl-c-neural-only-diffusion are constructible but untested by design (systems.py §"B and C run the FLOW arm only")uv run python scripts/run_ablation_grid.py
Neural generators on the play pathabsentah run calls run_ensemble (cli.py:195), which calls _require_toy (engine.py:151) and raises UnsupportedGeneratorError for anything but toy-v0— see §5.1

Compiler and coherence checks

capabilitystatusevidencehow to invoke
JSON-Schema validationworkingsrc/ah/core/loader.py; schema is schemas/worldspec-v1.2.schema.jsoninside process()
Pydantic mirror agreementworkingsrc/ah/core/worldspec.py; property test tests/test_worldspec.pypytest tests/test_worldspec.py
V1–V12 coherence rulesworkingsrc/ah/core/validator.py:70; bounds clamps :128, blocking V10/V11 :428, V12 :493ah world validate [WORLD_ID] — output: clamps=0 warnings=[] blocking=[]
Clamp-then-construct pipelineworkingsrc/ah/compiler/pipeline.py:28; rejection path cli.py:124ah world build
Validation stampingworkingstamp_validation at cli.py:129; flips status to validatedautomatic on build

Ensemble generation, replay, verification

capabilitystatusevidencehow to invoke
Ensemble with seed lineageworkingengine.py:427 — seeds are base_seed + 7919*kah run --paths 1000
Output digestworkingsrc/ah/core/digest.py; compute_outputs_digest at store/runrecords.py:31recorded on every RunRecord
Replay (bit-identical)workingcli.py:239; I ran it and got MATCH on sha256:73326f13…ah replay [RUN_ID]
Verify from lineageworkingstore/runrecords.py:83ah verify [RUN_ID] → True
Append-only chronicleworkingtrigger-level refusal, store/db.py:48; I read a 2-entry chronicle backah chronicle [WORLD_ID]
World immutabilityworkingstore/worlds.py:58 raises ImmutableWorldError on engine-consumed edits—

Cashflow engine and the portfolio engine

capabilitystatusevidencehow to invoke
Tier-0 cashflow (constant-G TA)workingsrc/ah/port/cashflow_tier0.py; frozen spec mappings/cashflow-tier0-v1.0.yamlrun_tier0(...)
Tier-1 cashflow (market-linked)workingsrc/ah/port/cashflow_tier1.py:90; linkage frozen in mappings/cashflow-tier1-v1.0.yaml; f_dist (:48) / f_call (:61) consume continuous states onlyrun_tier1(...)
"Tier 1 with linkage+fees off IS tier 0"workingasserted by test, tests/test_cashflow_tier1.pypytest tests/test_cashflow_tier1.py
Cohort recursionworkingsrc/ah/port/cohort.py; parameters in mappings/pacing-parameters-v1.0.yaml, drift-guarded by tests/test_pacing_artifact.py—
Call curve rc_curvepartial — placeholder[0.25,0.30,0.20,0.12,0.08,0.05] in fixtures/state/closed-end-cohort.example.json; ~29% of every commitment is never called (docs/engine-realism-register.md §ER-6, status open)— see §5.3
Quarterly waterfallworkingsrc/ah/port/engine.py:77 — receive, pay calls, spend off the trailing reported average, then forced salePortfolioEngine.run_quarter(...)
Forced sale, liquid pro-rataworkingport/engine.py:107-126, every event logged with cause and sleeves—
Forced secondary at haircutworkingport/engine.py:128-153 at secondary_haircut = 0.19—
Private-weight breach detectionworkingport/engine.py:155-170, both basesQuarterReport.breach_true/breach_reported
Vehicle mechanics (notice, gates, side pockets)workingsrc/ah/port/vehicles.py; tests/test_port_vehicles.py—
Hero funds (reconciliation invariant)workingsrc/ah/port/heroes.py; tests/test_port_proxy_heroes.py—

Decisions, twins, decision alpha

capabilitystatusevidencehow to invoke
Decision windowsworkingcore/institution.py:71 — month 12y-1, years 1–9. For a 40-quarter world: [11,23,35,47,59,71,83,95,107] (I read this back off a live session)GET /sessions/{sid} → decision_windows
Four actionsworkinghold / derisk / leanin / secondary (core/institution.py:52)POST /sessions/{sid}/decisions
Play institution (the scored one)workingsrc/ah/play.py:310 simulate_play — real cash account, a commitment ladder, calls that must be funded, forced salesvia the session service
Toy institution (Step 0)working, but still on live surfacescore/institution.py:98; used by bundle.summary, inspect.py, feed.py:175, tournament.py, density.py— see §5.2
Hold-course twin (product)workingplay.py:451 — the twin takes no action at any windowsimulate_play(paths, None)
Hold-course twin (toy)workingcore/institution.py:162hold_course_twin(...)
Institutional twin (DB pension)working, v1-simplesrc/ah/port/twin.py — parameterized benefit profile, flat discount, hedges, collateral. Full member-level projection explicitly deferredtests/test_port_twin.py
Drift twinstub — slot onlyserve.py:300 returns "drift_twin": None; the contract carries three series so its arrival is a data change (E7, Instructions/experience-deltas-register.md)—
Decision alpha, productworkingserve.py:256 alpha = active.final_value - twin.final_value, stamped PLAY_ALPHA_VERSION = "port-v1-cashflow" (play.py:80). I measured +3.3735 on a played decadeGET /sessions/{sid}/outcome
Decision alpha, researchworking, sealedeval/decision_metrics.py:55 (log points), DECISION_ALPHA_VERSION = "1.0" inside the G5 lockpytest tests/test_decision_metrics.py
Chain-link window attributionworkingplay.py:476, K+1 exact runs, no sampling. I verified the telescoping identity live: contributions summed to 3.3735227993676062, exactly the reported alphaGET /sessions/{sid}/outcome → window_contributions
Counterfactual "was it a good call"workingsrc/ah/eval/counterfactual.py; tests/test_recone.pyresearch only
Tournament (3 formats)workingsrc/ah/tournament.py — solo / cohort-cadence / simultaneous; score invariance across formats is a pinned testpytest tests/test_tournament.py
Decision-density studyworkingsrc/ah/density.py — but on the toy institutionpytest tests/test_density.py
Leaderboardworking (server), broken in the dev appserve.py:212 returns rows keyed on the required triple; curl against a live service returned {"world_id":"x","seed":1,"decision_alpha_version":"1.0","rows":[]}— see §5.4

The battery

capabilitystatusevidencehow to invoke
Step-0 stylized batterypartial — no ratified thresholdssrc/ah/battery/thresholds.yaml: every metric is status: todo, and the file says so ("Step 0 ships plumbing only… placeholders documenting intent, not ratified thresholds"). passed is not enforce_failures (battery/report.py:62), so with zero enforce entries it cannot failah battery [RUN_ID] / python -m ah.battery.report — not run here, per instruction
Step-2 validation batteryworking, sealedsrc/ah/eval/battery.py with suites in src/ah/eval/metrics/; MC error bars, reference bands, prereg thresholds. Hashed into pre-registration.lockrun_full_battery(...); results committed under artifacts/wp27*/, artifacts/wp29/
Negative controlsworkingsrc/ah/eval/negative_controls.py; tests/test_negative_controls.py—
Leakage guardworkingsrc/ah/splits.py; FinalEvaluationToken mintable only in eval/g2.py; import-graph test tests/test_leakage_guard.py. The holdout has been spent (WP5.6)pytest tests/test_leakage_guard.py
Pre-registration sealworkingpre-registration.lock (34 hashed files), pre-registration-g3.lock, pre-registration-g5.lock; tests/test_seal_guards.pypytest tests/test_seal_guards.py

Artifact generation

capabilitystatusevidencehow to invoke
Tier-1 templatesworkingsrc/ah/artifacts/templates.py — pure functions of the tape, no LLM/RNG/clockvia build_tier1_feed
Tier-1 wire in the bundleworkingsrc/ah/feed.py:159. My stagflation bundle carried 222 items across cb_statement, newspaper, quarterly_statement, release_page, wire_digestah bundle [RUN_ID]
Watermarkingworkingapplied in the renderer, src/ah/artifacts/render.py—
Tier-2 authoring pipelineworking, not shipped in bundlessrc/ah/artifacts/author.py (two retries then Tier-1 fallback, MAX_RETRIES = 2); the ≥95% first-pass bar is met — governance/evidence/AUTHORING-REGRESSION.md records 30/30, 100.0%, "ships: YES". No bundle contains a tier-2 letteruv run python scripts/run_authoring_regression.py (live model; not run here)
G1–G9 consistency gateworkingsrc/ah/artifacts/gate.py, GATE_IMPL_VERSION = "gate-impl/1.0.6"; blocking split frozen under AM-2026-08-02-002. G3's leak-checker prompt is v1.1, not built (stated in the module docstring); G6 is advisorypytest tests/test_authoring_regression.py
World bibleworkingsrc/ah/artifacts/bible.py, checks B1–B6pytest tests/test_bible.py
AI committeeworkingsrc/ah/artifacts/committee.py; benchmarked in governance/evidence/ACTOR-VALIDATION.mdpytest tests/test_committee.py
Live mode (sealed reveal)workingsrc/ah/artifacts/live.py; tape seal reused by the bundle (bundle.py:151)pytest tests/test_live_mode.py

The product surface

capabilitystatusevidencehow to invoke
World bundleworkingsrc/ah/bundle.py:56 BUNDLE_VERSION = "world-bundle-0.4"; 1 MB budget enforced at :190. I built one: 31,263 bytes, digest_verified: trueah bundle [RUN_ID] --out world.bundle.gz
Session serviceworkingsrc/ah/serve.py; 7 routes. I created a session, advanced, decided at all 9 windows, completed, and read the outcomeuv run uvicorn ah.serve:app --port 8787
Mark-to-market at the pointerworkingserve.py:119 — server-side, never client-side (W5). At month 12 I read value=98.0151, cash=0.3183, coverage_true=0.1782, private_weight_true=0.3436GET /sessions/{sid}
Authabsent by design (v0.1)serve.py:8-10 — "no auth — single-user, local"; joins at the M4 boundary—
React playerworkingapp/; 8 test files / 32 tests pass, tsc -b --noEmit cleancd app && npm run dev
Client-side seal re-verificationworkingapp/src/lib/bundle.ts, pinned against the committed app/fixtures/toy.bundle.gz by the TypeScript suite only — the Python suite builds its own bundles and never opens that file (§5.8)cd app && npm run test
Offline replay cacheworkingapp/src/lib/idb.ts (IndexedDB, W8)—
Static figure pageworkingsrc/ah/inspect.py; regenerates and re-verifies the digest on every render. I produced a 125,911-byte self-contained pageah inspect [RUN_ID] --out page.html
Credibility console (admin)workingsrc/ah/credibility.py:294; read-only. I ran it over two presets: "2 worlds, 2 flags"ah credibility --preset stagflation --preset goldilocks --out credibility.html
Private-programme console sectionworkingsrc/ah/programme.py:751; read-only enforced by import-graph test tests/test_programme_guard.pyincluded in ah credibility
ah audit (world register + wire audit)absent — plan onlydocs/superpowers/plans/2026-08-05-world-and-wire-audit.md (2,027 lines, 7 tasks) and its design note; ah --help lists no audit command—
Scenario build console (WP-B, added 2026-08-06 — postdates this document's survey)workingsrc/ah/buildconsole.py; dry-run five-stage compile ledger, keep-only writes (guard test test_only_keep_handler_writes_to_store); live path known to end in validator rejection until the compiler prompt rewrite (WP-A)uv run uvicorn ah.buildconsole:app --port 8798
Generator-input data console (added 2026-08-07 — postdates this document's survey)workingsrc/ah/dataconsole.py; read-only over the vintage store (guard test test_dataconsole_is_read_only); raw→factor lineage, proxy shading, de-smoothing overlay, split-shaded factor paneluv run uvicorn ah.dataconsole:app --port 8796

The data layer

capabilitystatusevidencehow to invoke
Requirements registerworkingrequirements.yaml — the single source of truth for required series—
Immutable vintage storeworkingsrc/ah/data/catalog.py; re-writing a (vintage, series) raises; current advances only on QC pass—
Connectorsworking (parse tested, fetch untested by design)src/ah/data/connectors/ — fred, bis, french, jst, shiller, treasury_hqmah data refresh --live (network; not run here)
Offline refreshworkingsrc/ah/data/refresh.pyah data refresh --fixtures <dir> --asof YYYY-MM-DD
Status reportworkingI ran it: current vintage 2026-08-02.4, six sources, QC 138 enforce-passedah data status
As-of resolutionworkingsrc/ah/data/catalog.py pointer historyah data asof YYYY-MM-DD
Episode packsworkingI ran the 2022 pack: 42 series, window 2022-01-01→2023-12-31ah data episode 2022
Manual intake validationworkingsrc/ah/data/intake.py + src/ah/data/schemas/ah data intake validate <file> --schema albourne_pm_returns
Manual intake apply (state-mutating)workingsrc/ah/data/cli.py — "Validate a drop AND apply it: write the vintage, run QC, advance on pass"; on QC failure the vintage is quarantined and the pointer stays putah data intake apply <file> --vintage 2026-08-01.1 (--vintage required; --schema optional, inferred)
Experiment trackingworkingsrc/ah/experiment.py; I listed 8 experiments with config hash, seed, git SHA, vintageah exp list / show / diff

3. The numbers as configured

Every value below is read from the file cited. UNSET means the code has no default and nothing in the repo supplies one.

Run shape

quantityvaluesource
Horizon (all 4 presets)40 quarters = 120 months, starting 2027-Q1src/ah/presets/*.json
Decision windows per run9 — months 11, 23, 35, 47, 59, 71, 83, 95, 107core/institution.py:71 (12y-1, years 1–9)
Ensemble size, presets1000 pathssrc/ah/presets/*.json engine_defaults.n_paths
Ensemble size, schema default10000 (min 100, max 100000)schemas/worldspec-v1.2.schema.json
Ensemble size, credibility console400 paths (--paths)cli.py:300
Seed lineagebase_seed + 7919*kengine.py:44,427
Preset base seedsstagflation 771204 · goldilocks 42 · deflation_bust 1848 · reflation_boom 2021src/ah/presets/*.json
Engine version stamptoy-v0.3engine.py:42
Validator version1.0.0validator.py:27
Battery versionbattery-0.1battery/report.py:34
Bundle contractworld-bundle-0.4, ≤1,000,000 bytes gzbundle.py:56,57
Product alpha versionport-v1-cashflowplay.py:80
Research alpha version1.0 (sealed)eval/decision_metrics.py:21

Sleeves

setmemberssource
Engine assets (order is contract)equity, bonds, hy, commodities, reits, pe, pc, reengine.py:74
Appraisal-smoothed ("reported")pe, pc, reengine.py:84
Liquid (play)equity, bonds, hy, commodities, reitsplay.py:82
Private (play)pe, pc, replay.py:83
Growth / defensive pairs(equity, pe) / (bonds, pc)play.py:125-126

Opening book — the scored institution

itemvaluesource
Targets, in points of 100equity 33 · bonds 12 · hy 5 · commodities 5 · reits 8 · pe 20 · pc 8 · re 7play.py:96-105
Opening cash2.0play.py:106
Opening private weight35 points — deliberately inside the policy bandplay.py §START_TARGETS note

The Step-0 toy institution uses a different opening mix — 45 points private (core/institution.py:39), outside the play policy band. Both are live; see §5.2.

Costs, bands, policy

itemvaluesource
Spending rate4.5%/yr, taken quarterlyport/engine.py:37
Spending basistrailing 12 quarters of REPORTED valueport/engine.py:38,98
Secondary haircut (play/port)0.19 (sells at 0.81 of NAV — the 2022-H2 public anchor)port/engine.py:39
Secondary discount (toy institution)0.18core/institution.py:56
Private-weight policy band(0.15, 0.40)port/engine.py:40
Derisk/lean-in shift10 points, liquid leg onlyplay.py:122
Voluntary secondary size8 points of the largest live PE cohortplay.py:123
Transaction costsUNSET — there is no cost term anywhere; LiquidSleeve.sell/buy move value at parport/sleeves.py:203,211
Management fee / carry on the play pathsupplied but never applied — every scored cohort is built from a document carrying mgmt_fee_rate 0.02, carry_rate 0.20, hurdle 0.08, European waterfall. They are never charged: cohort.step books CohortStep(..., 0.0, 0.0) for fees and carry, and the fee machinery lives in run_tier1, which the play path never callsfixture fixtures/state/closed-end-cohort.example.json; loaded at play.py:205-227,230-257; zeroed at port/cohort.py:203

Pacing

itemvaluesource
New vintage cadenceevery 4th quarter (annual)play.py:119
Annual commitment rate18% of each private sleeve's target NAV (≈6.3 points/yr against ≈35 private)play.py:118
Contractual life10 yearsmappings/pacing-parameters-v1.0.yaml
Distribution bow2.5mappings/pacing-parameters-v1.0.yaml
Terminal yield rate0.55mappings/pacing-parameters-v1.0.yaml
Call curve rc_curve[0.25, 0.30, 0.20, 0.12, 0.08, 0.05] of remaining unfunded, per year, last value repeatedmappings/pacing-parameters-v1.0.yaml; class "chosen", pending ALB-A
Tier-1 f_callclip(1 - c·drawdown, 0.5, 1.2) — near-flat by designcashflow_tier1.py:61-66
Tier-1 f_distclip(exp(-a·dd - b·ln(spread_ratio)), floor, ceiling)cashflow_tier1.py:48-58; coefficients in mappings/cashflow-tier1-v1.0.yaml
Spread reference400 bpsplay.py:109, engine.py:60

Declared plausibility bands (admin console — priors, not truth)

Asset bands, annualized % over ten years (credibility.py:66): equity −8…14 ret / 12…28 vol · bonds −2…9 / 3…12 · hy 0…11 / 6…18 · commodities −6…16 / 12…28 · reits −8…12 / 12…26 (and pe/pc/re below those lines in the same table).

Programme bands (programme.py:209), all seven: peak_unfunded_ratio 0.25–0.75 · call_rate_y1_3 0.15–0.45 · crossover_years 4–8 · dpi_age9 0.7–2.0 · linkage_bite 0.50–1.20 · linkage_shortfall 0.05–0.35 · forced_secondaries 0.0–1.0.

Battery thresholds

All status: todo — excess_kurtosis, skewness, hill_tail_index, acf_r_lag1, acf_abs_lag1, max_drawdown_median, corr_distance (src/ah/battery/thresholds.yaml). No metric is enforce; the Step-0 battery therefore cannot fail. The Step-2 battery's thresholds are real and live in pre-registration.yaml under the seal.


4. Test estate

Suites

suitewhat it ishow to run
Python, tests/121 test_*.py modules, 2,226 tests (plus joinery_common.py, a shared helper) covering core, store, data, gen, eval, port, artifacts, product surfaceuv run pytest
TypeScript, app/src/**8 test files, 32 tests (bundle loader + seal, session client, decision window, ranked setup, reckoning, fan chart, book, private markets)cd app && npm run test
Type checkingpyright basic mode over src + testsuv run pyright
Lint + formatruff 0.16.0 (pinned in uv.lock)uv run ruff check . / ruff format --check .

Structural invariants are tests, not conventions: narrative-blindness (tests/test_narrative_blindness.py scans the engine for narrative field access), no-network (pytest-socket, --disable-socket in addopts), leakage guard (tests/test_leakage_guard.py is an import-graph assertion), seal integrity (tests/test_seal_guards.py), the artifacts boundary (tests/test_artifacts_service.py::TestBoundary — core/gen/port never import artifacts), and the programme console's read-only guarantee (tests/test_programme_guard.py).

What CI runs

.github/workflows/ci.yml, on push to main and on every PR, in order:

  1. uv sync --frozen --dev
  2. uv run ruff check . and uv run ruff format --check .
  3. uv run pyright
  4. uv run pytest --cov=ah.core --cov-report=term-missing --cov-fail-under=90
  5. uv run python -m ah.battery.report
  6. uv run pytest tests/test_g0_end_to_end.py -v

Note the coverage gate covers ah.core only (pyproject.toml:69), not the rest of the tree. Two further workflows are scheduled, not gating: data-monthly.yml (a monthly public-source refresh that opens an issue on QC failure) and data-reminders.yml (quarterly manual-intake reminders).

Last-known status, measured here on 2026-08-05

checkresult
uv run pyright0 errors, 0 warnings, 0 informations — clean
uv run ruff check .All checks passed
uv run ruff format --check .FAILS — 2 files would be reformatted (both markdown plan docs; see §5.5)
cd app && npm run typecheckclean
cd app && npm run test8 files, 32 tests, all pass
uv run pytest2,226 tests across 121 modules — all passed (exit 0, ~20 minutes wall clock)
uv run pytest on the core rails only (engine, validator, worldspec, stores, digest, G0 end-to-end)80 passed in 3.29s
python -m ah.battery.reportnot run — battery execution is gated pending threshold ratification (§3)

5. Known gaps and discrepancies

Ordered by how much they would surprise someone who read the design documents and then read the code. Everything here was found in this pass; nothing is copied forward from a status table without re-checking.

5.1 The promoted generator cannot reach a player

Step 2's gate promoted hier-flow-v1 (G2-EVIDENCE.md; S2-DEFAULT-GENERATOR), and the WorldSpec enum carries it (core/worldspec.py:62). (That promotion was later reversed — see the standing caveat in §5.9. It is reported here as the position on 2026-08-05, not as a current result.) But every playable path runs the toy engine: ah run calls run_ensemble (cli.py:195), which calls _require_toy (engine.py:151) and raises UnsupportedGeneratorError for any other id. ah/gen/registry.py is never imported by ah/cli.py, ah/bundle.py, ah/serve.py, or ah/play.py. The generator layer is a research artifact; the product runs on toy-v0.3.

Two consequences worth stating separately:

5.2 Two institutions are live at once, and both reach the player

ah/play.py (cash account, calls, forced sales) is what scores. ah/core/institution.py (eight weights, no cash, nothing can be owed) is Step 0's toy. The toy is still wired into surfaces the player sees:

This is not theoretical. In the single bundle I built from the stagflation preset (run 03a76c08…, seed 771204, 200 paths):

summary.twin_final_value          = 166.502   (toy institution)
twin_ledger.nav_reported[-1]      =  76.712   (port institution — the one that scores)

The same file states the same institution's terminal value twice, 2.2× apart, and the wire the player reads is narrated off the higher one. The bundle docstring's own framing ("the HOLD-COURSE TWIN's cashflows") is accurate for twin_ledger; summary.twin_final_value is the leftover.

5.3 ER-6: about 29% of every commitment is never called

docs/engine-realism-register.md §ER-6, status open, dated 2026-08-05. The call curve is an ALB-A placeholder that was never fitted; measured at committed = 1.0, paid-in reaches 0.7075 over the contractual life against an allocator's 85–95% expectation. Downstream, peak_unfunded_ratio flags on all four presets (3.018 / 2.445 / 3.308 / 2.453 against a declared 0.25–0.75) and the J-curve crossover lands at ~8.5 years against a declared 4–8. On deflation_bust no year-1 vintage crosses over within the decade at all. The register is explicit that this is a prerequisite for the commitment lever (E1), not a parallel cleanup.

Two further register entries are open: ER-2 (the policy rate is a continuous drift with no meeting calendar and no 25bp quantisation) and ER-5 (the crisis is a rectangular block, giving equity an ACF of 0.364). ER-1 and ER-4 are closed in toy-v0.3; ER-3 is closed in the play surface (wire-play-surface) — a different layer, since ER-3 was the no-cashflow gap and was fixed in ah/port/, not in the return process.

5.4 The leaderboard is unreachable from the dev app

app/src/lib/session.ts:176 fetches /leaderboard/{worldId}. app/vite.config.ts:8 proxies only /sessions. Verified against the running dev stack:

GET http://127.0.0.1:8787/leaderboard/x?seed=1&alpha_version=1.0  → 200 application/json
GET http://localhost:5173/leaderboard/x?seed=1&alpha_version=1.0  → 200 text/html      (vite's SPA fallback)
GET http://localhost:5173/sessions/nope                            → 404 application/json (proxied correctly)

The client parses the SPA's HTML as JSON and throws; Leaderboard.tsx:31 catches it and renders the error string in place of the board. The server side is fine — the same request direct to 8787 returns a well-formed empty board. It is a one-line proxy entry.

5.5 ruff format --check . fails on main today

ruff 0.16 formats Python code blocks inside Markdown, and two committed plan documents contain unformatted blocks:

uv.lock pins ruff 0.16.0 and CI runs uv sync --frozen, so CI's lint step would take the same view. ruff check . and pyright are both clean; this is the formatter alone, and ruff format on those two files fixes it.

5.6 The battery CI step cannot fail

.github/workflows/ci.yml runs python -m ah.battery.report as a gate, but every threshold in src/ah/battery/thresholds.yaml is status: todo, and BatteryReport.passed is not enforce_failures (battery/report.py:58-64). With no enforce metric the step is green by construction. The file is candid about this ("placeholders documenting intent, not ratified thresholds") — the gap is that CI presents it as a gate.

The CI step is also mislabelled. It is titled "Validation battery (stagflation preset)", but main() runs _stagflation_ensemble() (battery/report.py:189-196), which loads schemas/example-long-stagflation.worldspec.json — a schema example, not src/ah/presets/stagflation.json — forces generator_id = "toy-v0", and runs 64 paths at base_seed=42, not the preset's 1000 at 771204.

Note the Step-2 battery (ah/eval/battery.py) does have real, sealed thresholds and all eight suites registered (_REFERENCE_DEPENDENT_SUITE_BUILDERS, battery.py:955); the two are different objects with similar names.

5.7 Tier-2 authoring passes its bar and still ships nothing

governance/evidence/AUTHORING-REGRESSION.md records the current run as 30/30, 100.0% first-pass, "ships: YES" against the frozen ≥95% bar, and governance/evidence/G4-EVIDENCE.md closes criterion 1 at 96.7%/100.0%. But every bundle still stamps:

meta.artifact_tier = "tier-1 templated wire (build-time, deterministic);
                      tier-2 letters await the frozen >=95% first-pass bar"

(bundle.py:139-142, and I read it back out of a freshly built bundle).

The string is stale, but the deeper point is that it describes the wrong rule. The ratified decision, PD-4 (Instructions/KICKOFF-PRODUCT-SU.md:78), is key-conditional, not bar-conditional: "tier-1 deterministic always; tier-2 letters when a key is present at build, recorded in the bundle either way." bundle.py has no such branch — it never imports ah.artifacts.author, so a key present at build time would change nothing. The stale string is the symptom; the missing PD-4 branch is the gap.

Also unbuilt: G3's leak-checker prompt over the draft, recorded as v1.1 in artifacts/gate.py's docstring, and G6 which warns "not evaluated" unless past artifacts are supplied.

5.8 Documentation that no longer matches the code

claimwherewhat the code says
bundle contract is world-bundle-0.3CLAUDE.md §Architecturebundle.py:56 — world-bundle-0.4
"ah/pacing.py is a display-only toy ledger"CLAUDE.md §Architecturethe module was deleted in 168cd22 ("retire ah/pacing.py"); only a stale .pyc remains. The pacing table lives in mappings/pacing-parameters-v1.0.yaml
docs/tier1-synthesis-and-decisions.md, named by Step 2's vendoring listCLAUDE.mdstill missing — confirmed absent
"CLI-echoed strings stay ASCII"CLAUDE.md §Environment gotchasdata/episode.py:107 emits an em-dash, echoed via typer.echo(pack.brief) at data/cli.py:154. It does not crash — exit 0 under PowerShell with the dash rendering correctly — but it renders as ? in Git Bash. (data/reports.py's em-dashes are not a deviation: they are in the module docstring and in the generated GAPS.md, which CLAUDE.md explicitly permits Unicode in)
"app/fixtures/toy.bundle.gz is a committed bundle both suites verify"CLAUDE.md §Regenerating fixtures, repeated in CHANGELOG.mdonly the TypeScript suite reads it (app/src/lib/bundle.test.ts:22). No file under tests/ mentions it; tests/test_bundle.py builds its own bundle. The two seal implementations are not pinned against a shared fixture — which is the property the sentence is claiming

5.9 Gate state, carried forward and re-checked

These are the project's own recorded positions, verified against the evidence files rather than restated from the status table:

5.10 Named-but-absent, and deferred-by-decision

5.11 A secondary sale relieves nothing — the obligation survives it

This is on the scored path, and it inverts the sign of the only liquidity lever the player has.

Both the voluntary sale (play.py:298-307) and the forced secondary (port/engine.py:136-140) reduce cohort.nav_true and cohort.nav_reported and credit cash. Neither touches unfunded or committed. Nothing else does: in port/cohort.py, unfunded moves only in step() (:200) and recall() (:233); report() (:207-211) writes the mark and returns. And calls are sized call = min(self.unfunded, call_rate * self.unfunded) (cohort.py:185) — a function of the unfunded balance, independent of NAV.

So you sell an LP interest at a 19% haircut, keep 100% of the future call obligation, and — since coverage is unfunded ÷ what you own — coverage gets strictly worse after the one action that exists to relieve liquidity stress. A cohort driven toward nav_true ≈ 0 by repeated forced secondaries keeps calling at full size. Not in docs/engine-realism-register.md (ER-1…ER-6 do not reach it).

5.12 Two writers to the leaderboard, and a version-label collision

The decision_alpha_version column is the mechanism that is supposed to keep incompatible scores off one board (db.py:92, UNIQUE(world_id, seed, decision_alpha_version, participant)). Three numeric definitions exist and two of them share a label:

writerlabelinstitutionmetric
serve.py:257port-v1-cashflowport (cash account)terminal value difference
tournament.py:2681.0 (from store/runrecords.py:27)toy (§5.2)terminal value difference
eval/decision_metrics.py:211.0 (sealed under G5)—log points, ln(player/twin)

tests/test_play.py:167 asserts only that PLAY_ALPHA_VERSION differs from the sealed constant; nothing pins runrecords.py's constant against it. The comment at runrecords.py:22-24 ("inert… Nothing reads them yet") is stale — tournament.py reads it and writes it to the board. Every bundle also stamps meta.decision_stamps.decision_alpha_version = "1.0".

5.13 Named-but-unwired, beyond §5.10

5.14 Pacing is open-loop, and one fixture governs all three private sleeves

Three separate simplifications, none of them registered:

ER-6 covers the shape of rc_curve. None of these three is in the register.

5.15 Smaller things that still change what a reader concludes


Evidence for every "working" claim in §2 is either a file:line in this repository or a command I ran on 2026-08-05; the commands and their real output are in docs/USER-MANUAL.md. Anything I could not verify is marked, and the full list of what I could not verify is in the closing note of that document.