docs(s33): document the wave snapshot's deliberate intra-wave semantics, pinned by test

Closes OQ1 (SC8). At k>1 every project in a wave reads the WAVE-START store,
so a verdict captured by project A does not reach project B's hypothesis
prompt inside the same wave — sequentially it would. Deliberate: the snapshot
is what removes the append race, and restoring intra-wave visibility would
restore the completion-order dependence the barrier exists to eliminate.
Learning flows ACROSS wave boundaries, not within them; concurrency trades
learning granularity for wall-clock.

The shipped fixture cannot show this (the fold is bundle_dir-gated and no
reference project sets bundle_dir), which is a property of the fixture and not
of the design — so it is pinned on the road-k + bundle-k+1 pair via the
existing load_reference_projects monkeypatch seam, no new production seam.
k=1 (two waves) carries the sentinel; k=2 (one wave) does not; store content
stays identical across k. Each half is the other's control.

Detach measured: remove _wave_snapshot -> RED on three tests including this one.

Also corrects two stale docstrings that outlived Session 1's finding: the
module header and the Step-2 test still named a sorted() in _merge_wave as the
detach point. There is no sorted() there, and a project_id sort would BREAK
the k=1-identity contract rather than protect it. A docstring naming a detach
point that does not exist is the green-but-dead defect this file exists to
prevent, so both now name the snapshot and mark the plan's claim as measured
wrong.

_wave_snapshot gains the honesty line about copying exactly two fields, with
the reason no field-count guard was added.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015vYbqW4MppACRvPhEMDpvF
This commit is contained in:
Kjell Tore Guttormsen 2026-07-31 17:40:05 +02:00
commit 16e1734264
2 changed files with 144 additions and 10 deletions

View file

@ -592,7 +592,14 @@ def _wave_snapshot(store: VerdictStore) -> VerdictStore:
``retriever`` is carried across deliberately: it is the S3.1 opt-in seam, and a snapshot that
dropped it would silently downgrade a caller-owned store's semantic retrieval to the
structural default mid-pass."""
structural default mid-pass.
**Honesty boundary: this copies exactly two fields because ``VerdictStore`` HAS exactly two.**
A third field added later would be silently dropped here the same defect class as the
``retriever`` omission this function was first written with, which the Step-2 contract test
caught. It is left as a documented hazard rather than a guard: an assertion on the field count
would go red on every benign addition to ``VerdictStore``, which trains people to edit the
guard rather than think about the snapshot a worse outcome than the line you are reading."""
return VerdictStore(verdicts=list(store.verdicts), retriever=store.retriever)
@ -702,7 +709,25 @@ async def run_portfolio(
the reason is that the ledger is STATIC during a pass (C3: no realization happens on the run
path, which ``test_concurrent_pass_does_not_write_on_the_run_path`` pins), so every check reads
the same accumulated sum regardless of when it runs. Wave-assembly placement buys the
never-started property, not determinism; determinism is the one-writer rule's."""
never-started property, not determinism; determinism is the one-writer rule's.
**The one semantic difference ``k > 1`` introduces, stated plainly (OQ1).** Every project in a
wave reads the WAVE-START store, so a verdict captured by project A does NOT reach project B's
hypothesis prompt when A and B share a wave sequentially it would. This is a deliberate trade,
not an oversight: the snapshot is what removes the append race, and restoring intra-wave
visibility would restore exactly the completion-order dependence the barrier exists to
eliminate (what B saw would depend on whether A happened to finish first). Learning therefore
flows ACROSS wave boundaries, not within them, and ``concurrency`` is the knob that trades
learning granularity for wall-clock at ``k=1`` nothing changes, and at ``k=len(portfolio)``
the pass learns nothing from itself.
On the SHIPPED reference fixture this difference is invisible in outcomes, because the Step-1
ExpeL fold is ``bundle_dir``-gated and no reference project sets ``bundle_dir`` the chain is
live for store CONTENT but inert for OUTCOMES. That is a property of the fixture, never a
property of the design, so it is pinned on a bundle-backed pair where the fold does fire
(``test_intra_wave_visibility_is_the_documented_semantic_difference``): same fixture, same
sentinel, only the wave boundary moves. Store content stays identical across ``k`` the
difference is confined to what each project READ, never to what the pass produced or persisted."""
if concurrency < 1:
raise ValueError(
f"concurrency must be >= 1, got {concurrency}: a non-positive wave size would run no "