Skip to content

Fix corpus reds: status readers, controlled reads, tier fixtures, retired tokens - #4598

Merged
Sinity merged 10 commits into
masterfrom
fix/corpus-reds-4
Sep 3, 2026
Merged

Fix corpus reds: status readers, controlled reads, tier fixtures, retired tokens#4598
Sinity merged 10 commits into
masterfrom
fix/corpus-reds-4

Conversation

@Sinity

@Sinity Sinity commented Sep 3, 2026

Copy link
Copy Markdown
Owner

Summary

Eight more red classes from the 2026-09-03 corpus run, stacked on #4591.
Four are product defects; four are fixtures pinned to shapes the runtime
has moved past.

Problem and solution, per class

Status readers raised instead of reporting tier skew

#4485's open-time tier check reached the readers whose subject is a
tier's version. The workload probe's payload carries user_version and
version_status fields; metrics is supposed to emit
schema_mismatch:index as a blocker series; the convergence-debt summary
has an error field for saying why the view is unavailable. All of them
raised instead:

SchemaSkewError: index schema skew: expected 85, found 1

Metrics, the workload probe (three sites), the embedding status payload,
the schema-inference gate's tier identity read and the debt summary now
open without the version assertion and report what they find. The context
preamble's scheduler receipt is best-effort by its own contract and
already swallowed sqlite errors; a tier this runtime cannot use joins them.

The relink route never derived attachment provenance

attachment_refs.direction is NOT NULL and only the main write route
derived it, so blob-reference closure failed the constraint on any record
parsed before attachments carried direction. The relink path uses the same
shared derivation, reading the owning turn from the index when the append
payload's own message map does not carry it.

One session cost total on two model rows

sessions.reported_cost_usd is one exact dollar total, written onto a
single session_model_usage row. A merge-append that switched models left
the superseded row holding the previous total, double-counting it in every
sum over the session.

A read that skipped the controlled reader

The delegation work-evidence materializer opened a read-only ArchiveStore
directly — the one thing the read-surface boundary forbids, because such a
read carries no admission, no execution budget and no cancellation.

Fixtures that open a tier before building it

A connection profile checks a tier's declared version at open time, so a
test cannot open a tier-named path and initialize it afterwards. The
assertion tests build the tier first through the production bootstrap; the
mmap-budget test builds every attached tier the same way, since the tier
filenames are its subject; the descriptor-binding test names its database
for what it is. The embedding-drain stubs declare the version they claim,
without which the daemon's probe passes them over and the drain silently
reports no work.

The resilience suite launched another checkout's daemon

which("polylogued") resolves from PATH, which in a worktree is the main
checkout. The tests launched a different tree's daemon against this tree's
archive, then waited out their budget with nothing ingested and reported a
timeout. The running interpreter's own script directory comes first now.
The installed-wheel smoke had the same shape: uv venv picked whatever
interpreter uv found, and the package refuses to start off free-threaded
CPython.

Rendered ages re-baselined instead of redacted

"relative_time": "70w ago" became "71w ago" on its own, because the
value is computed against the host clock over fixture timestamps that never
move. This file's own contract routes such a field to _redact, "not to
update the baseline".

Surfaces that read a retired token as removed

#4363 retired the Beads issue route, but the Origin token stays:
deleting it would narrow the durable source.db CHECKs that still admit
stored rows. Three surfaces each encoded a different guess. Origin has
twelve tokens, ten of them public badges — the generated-contract test
derives that split from PUBLIC_ORIGIN_TOKENS, the teaching table follows
the enum, and the namespace policy stays exhaustive over executable
origins, which the retired one is not. Separately, exclusive_keys and
scratch are retired descriptor keys, as test_dev_loop_service already
declares.

Verification

devtools test <file> -n 2, worktree venv resynced to the current lockfile:

file before after
tests/unit/storage/test_durable_change_train.py 3 failed 98 passed
tests/unit/daemon/test_metrics_endpoint.py 2 failed pass
tests/unit/maintenance/test_schema_inference_gate.py 1 failed pass
tests/unit/storage/test_connection_profile.py 1 failed pass
tests/unit/storage/test_archive_tiers_assertions.py 3 failed pass
tests/unit/daemon/test_embedding_readiness.py 1 failed pass
tests/unit/context/test_preamble.py::…non_git… 1 failed pass

devtools verify --quick green at this head.

Residual risk

validate_schema=False is now used at seven read sites. Each is a status
or identity projection whose caller models skew as data; none of them
writes.

A first attempt at this branch also relaxed the identity guard so an
ops.db predating the ledger would converge. That fixed three tests and
broke thirty in test_durable_change_train.py — bootstrap proceeded where
it used to refuse. The relaxation is dropped and those three ops-convergence
tests remain red; the reader change that types the absent ledger as None
is kept and was measured separately as harmless (98 passed with it alone).

🤖 Generated with Claude Code

https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Team

Run ID: a720fe8e-87d0-4b8a-88ab-160c9a346d52


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T10:16:45.755165Z d7ae654 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Base automatically changed from fix/corpus-reds-3 to master September 3, 2026 10:07
Sinity and others added 10 commits September 3, 2026 12:09
#4485's open-time tier check reached the readers whose subject is a tier's
version. Metrics, the workload probe, the embedding status payload and the
schema-inference gate all exist to describe what a tier holds -- the probe
payload's own fields are user_version and version_status -- and they raised
instead of reporting. Each now opens without the version assertion and
reports the skew as data, which is what their callers already model:
metrics emits schema_mismatch:index as a blocker series.

The context preamble's scheduler receipt is best effort by its own
contract and already swallows sqlite errors; a tier this runtime cannot
use joins them, so a disposable receipt never fails the preamble it
describes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
read_schema_identity queried the ledger table unconditionally, so a tier
written before that table existed raised OperationalError where its own
signature promises None. An absent ledger is an absent identity; the
bootstrap guard below already handles that case as skew.

schema_identity also entered the index DDL without the differential
classification the reindex census requires. It is a single row digesting
the tier's own DDL, so a full rebuild and an incremental convergence stamp
the same value: comparable, with nothing volatile.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
A connection profile checks a tier's declared version at open time, so a
test cannot open a tier-named path and initialize it afterwards. The
assertion tests create the tier first through the production bootstrap.
The mmap budget test builds every attached tier the same way, since the
tier filenames are its subject.

The descriptor-binding test names its database for what it is: a tier name
made the factory assert a tier the test never meant to build.

git finds a repository by walking upward, so the ceiling in the non-git
test sits above the directory under test rather than on it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
A rendered age is computed against the host clock over fixture timestamps
that never move, so "70w ago" became "71w ago" on its own. This file's
own contract routes such a field to _redact rather than to a new
baseline.

exclusive_keys and scratch are retired descriptor keys, as
test_dev_loop_service already declares. The bounded-operation test reads
the keys that carry that meaning now. The exclusive-key test goes with
them: mutual exclusion between applied GC and a verify run that consumes
the same cache is enforced by the artifact lease, which refuses to delete
a leased artifact and has its own test.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
…nature

Three more fixtures that the tier-guarded read profile passes over:

- The embedding backlog drain probes a candidate index before draining it,
  so a stub index that declares no version is silently skipped and the
  drain reports no work. The stubs declare the tier version they claim.
- The installed-wheel smoke built its venv from whatever interpreter uv
  discovered first, and the package refuses to start off free-threaded
  CPython. The venv is seeded from the running runtime; it is still fresh
  and separate, so the smoke still resolves the wheel's own scripts.
- A statement-tracing double refused the keyword its production
  counterpart now takes. It exists to trace statements, not to pin its
  caller's signature.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
…test

The resilience suite resolved polylogued and polylogue from PATH, which in
a worktree resolves the main checkout: the tests launched another tree's
daemon against this tree's archive and then waited out their budget with
nothing ingested, reporting a timeout. The running interpreter's own
script directory comes first now, with PATH kept as the last resort.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
#4363 retired the Beads issue route, but the Origin token stays: deleting
it would narrow the durable source.db CHECKs that still admit stored rows.
Three surfaces each encoded a different guess about that.

Origin has twelve tokens, ten of them public badges. The generated-contract
test derives that split from PUBLIC_ORIGIN_TOKENS instead of naming
unknown-export as the only exception. The teaching table follows the enum,
so its length does too, and it names beads-issue as reserved rather than
asserting it absent. The namespace policy is exhaustive over executable
origins, which the retired one is not.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
The delegation work-evidence materializer opened a read-only ArchiveStore
directly, which is the one thing the read-surface boundary forbids: a
read that skips the controlled reader carries no admission, no execution
budget, and no cancellation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
The summary's error field exists to say why the view could not be read,
and the open-time tier check pre-empted it: a malformed debt table on a
tier at another version reported the version instead of the malformation.
The projection reads the tier and reports what it finds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
… layout

A pointer target outside the archive root is the shape of a copied archive
and #4411 refuses it on purpose, so it cannot carry this contract. The
generation now lives inside the root, which is what promote() writes, and
the invariant the test exists for is unchanged: an active pointer moves the
index tier and leaves the durable tiers where they are.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
@Sinity
Sinity enabled auto-merge (squash) September 3, 2026 10:13
@Sinity
Sinity merged commit 853bc6e into master Sep 3, 2026
3 of 4 checks passed
@Sinity
Sinity deleted the fix/corpus-reds-4 branch September 3, 2026 10:19
Sinity added a commit that referenced this pull request Sep 3, 2026
fable-packet lives under `ops insights` (#4580 removed the root alias);
beads has no rendering policy (#4598); Claude Code tool results with an
exit code emit claude_tool_execution_result (#4502); the direct status
fallback reports "daemon idle" with the start hint; the integration
workload is a third default seeded artifact (#4532).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YGi8wLWGR2HYBh8p8fXFXz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant