Skip to content

Open a 0003-era database with the CareerSignal that exists now - #40

Merged
Deep-Sixed merged 3 commits into
mainfrom
claude/gifted-pasteur-4xrelv
Sep 23, 2026
Merged

Deep-Sixed merged 3 commits into
mainfrom
claude/gifted-pasteur-4xrelv

Conversation

@Deep-Sixed

@Deep-Sixed Deep-Sixed commented Sep 20, 2026 •

Copy link
Copy Markdown
Owner

Item 2 of the career-ops queue: a semantic upgrade regression, not "the SQL executed."

Head: d5676b1
Base: main @ a50e83c
Three commits, two files.

commit what
ccf5c9a the regression itself — src/system/tests/test_historical_upgrade.py, +326
a107781 narrows two pytest.raises(Exception) to the exact exception and message
d5676b1 withholds the body on the one refuse-before-read call site that still sent it

No production code changes in any of the three.

Why

Every existing migration test starts from nothing — fresh database, apply all seven, assert the result. What none of them covers is a database that genuinely predates the later migrations being opened by current code.

It lives in src/system/tests/ rather than src/data/tests/ because the semantic assertions run the real outward workflow, and verify_tree.py allows data → recruiting only.

How the old database is built

monkeypatch.setattr(store, "migration_files", ...) narrows the list to <= 0003, then the real runner applies them. The old database therefore carries the same schema_migrations digests a real operator's would, and the later store.migrate() treats it as an ordinary upgrade rather than a special case.

No fixture .db is committed — a checked-in binary is one nobody reviews, and it would drift from the migrations it claims to predate.

What is asserted

old facts survive an opportunity recorded then is readable now
0004 backfills honestly the row says actor='migration', not an operator
0005 invents no authority an old approval authorizes no draft
0006 invents no target no addressing appears for one
0007 keeps one-attempt an old intent still bars a second

The three "invents nothing" claims are the point. 0005–0007 each added columns binding an approval to what the operator read, and each deliberately left old rows unmatched because the database has no record of what those approvals were for. A migration that backfilled a plausible value would authorize an outward write nobody approved — and every structural test in this repo would still pass.

Refusals are asserted on provider.calls == 0, following the repo's rule that a refusal and a rejection read alike to a person and only the call count says whether anything was contacted.

I wrote the defect this catches

The first version of the fixture pointed one opportunity's current_review at one of three reviews, leaving the other two stale. An authorization check reads its binding through current_review, so a stale review refuses before any 0005/0006/0007 column is consulted. All seven tests passed — and both outward tests were green about staleness while claiming to be about migrations.

It surfaced by testing the test: I fabricated a complete, correct binding for the old approval, as a dangerous migration would, and asked whether draft() then created one.

before the fix:  ValueError: Review is missing or stale     <- wrong refusal
after the fix:   draft() SUCCEEDED, provider.calls = 1, intent confirmed

The semantic test asserts calls == 0 and intent is None. Only after the fix does asserting that mean anything. The staleness precondition is now asserted in the vacuity test rather than left to hold by luck.

a107781 — the same vacuity class, one level up

Review was right that pytest.raises(Exception) proved a weaker property than this file's own claim. It passes for the intended refusal, but would also pass silently if an unrelated failure in _binding(), draft_material(), provider identity resolution or SQLite access threw first — provider.calls == 0 and intent is None would still hold, and the test would stay green while proving nothing. Both assertions now name the exception and match its message.

d5676b1 — the Windows failure, and a claim of mine that was wrong

Windows 3.12 failed on test_an_outward_command_refuses_an_unknown_query_parameter with WinError 10053. That is the unread-body reset race #39 was written to remove: _outward settles accepted() on the query before it reaches for _body(), so a declared body goes unread, and closing on unread bytes is a reset rather than a clean shutdown on Windows.

#39's docstring claimed it had removed "the last instance ... from this file". That claim was wrong when I wrote it. This call site arrived in #35 and I missed it — the sweep behind #39 was not a sweep. An AST pass over all 112 client call sites now says this was the only one remaining: every other send carrying a body either already declares transmit=False, or is an address that genuinely reads (malformed JSON, the charset 200, the provenance-in-order half of the ordering test), and the 39 calls through outward() / decide() never override provenance. The whole-file count in that docstring is replaced by the mechanism, which cannot rot the same way.

Withholding is the stronger fix than tolerating the race with unread() — and it strengthens the test:

Mutation Result
drop accepted() from _outward FAIL — TimeoutError
check the query after _body() FAIL — TimeoutError
the same reorder, body transmitted PASS ← what the old form allowed

The third row is the point. With the body sent, reading first and judging the query second still answers 400, so the old assertion held while the ordering the test is named for had been inverted. Withheld, the refusal can only arrive if the query was judged first — the test now proves its own title rather than a status code.

Mutation coverage — ccf5c9a

Mutation Result
0004 backfills actor='operator' FAIL
0007 defaults provider to 'controlled' FAIL
the fixture builds a current database FAIL — 7 errors
the three reviews share one opportunity again FAIL

The last two are vacuity guards. Note the honest limit: mutation 2 is caught by the structural assertion, not the semantic one — 0005's empty digests refuse independently, so the end-to-end test cannot attribute a refusal to any single column. The per-column claim is the structural test's job; the semantic test is the end-to-end backstop, and the fabricated-binding experiment above is what proves it is not vacuous.

Verification on d5676b1

1686 tests (1679 → 1686), Ruff check and format clean, verify_tree 100 publishable text files / 5 reviewed renders / 1 reviewed screenshot, verify_secrets PASS, verify_wheel PASS.

🤖 Generated with Claude Code

https://claude.ai/code/session_01B8kjhqYENShpeZ16QDnsyo


Generated by Claude Code

Deep-Sixed and others added 3 commits September 20, 2026 13:25
Seven migrations, and every test of them starts from nothing: create a
fresh database, apply all seven, assert the result. That proves the SQL
executes. It says nothing about the thing an operator depends on, which
is that a database holding months of their decisions still means what it
meant after the upgrade runs over it.

So this builds a genuine 0003-era database -- the real historical
migration resources, applied by the real runner with the file list
narrowed, carrying rows written the way that schema allowed -- and lets
the current code open it. No fixture .db is committed: a checked-in
binary is one nobody reviews, and it would drift from the migrations it
claims to predate.

What is asserted is semantic rather than structural:

  old facts survive           an opportunity recorded then reads now
  0004 backfills honestly     the row says a migration wrote it
  0005 invents no authority   an old approval authorizes no draft
  0006 invents no target      no addressing appears for one
  0007 keeps one-attempt      an old intent still bars a second

The three "invents nothing" claims are why this exists. 0005, 0006 and
0007 each added columns binding an approval to what the operator read,
and each deliberately left old rows unmatched, because the database has
no record of what those approvals were for. A migration that backfilled
a plausible value would authorize an outward write nobody approved --
and every structural test here would still pass.

Mutations, each alone:

  0004 backfills actor='operator'          FAIL
  0007 defaults provider to 'controlled'   FAIL
  the fixture builds a CURRENT database    FAIL (7 errors)
  the reviews share one opportunity again  FAIL

The third and fourth are vacuity guards, and the fourth is there because
I wrote the defect it catches. The first version of this fixture pointed
one opportunity's current_review at one of three reviews, so the other
two were stale -- and an authorization check reads its binding through
current_review, refusing a stale review before any 0005/0006/0007 column
is consulted. All seven tests passed. Both outward tests were green
about staleness while claiming to be about migrations.

It surfaced by testing the test: I fabricated a complete, correct
binding for the old approval, as a dangerous migration would, and asked
whether draft() then created one. It did not -- it raised "Review is
missing or stale", which is the wrong refusal and meant the test could
not have caught a fabricating migration at all.

With each review current for its own opportunity, the same experiment
creates a real draft: provider.calls = 1, intent confirmed. That is what
the semantic test asserts against, and only now does asserting it mean
anything.

The staleness precondition is now asserted in the vacuity test rather
than left to hold by luck.

Gates: 1679 -> 1686 tests, ruff clean, verify_tree 100/5/1,
verify_secrets and verify_wheel PASS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B8kjhqYENShpeZ16QDnsyo
Review is right, and the old assertions proved a weaker property than the
PR's own claim. `pytest.raises(Exception)` passes for the intended refusal
-- Repository.claim() raising ValueError("Approval predates draft
authorization binding...") or workflow.py raising ValueError("Requested
provider does not match the draft intent already reserved...") -- but it
would also pass, silently, if a future unrelated failure in _binding(),
draft_material(), provider identity resolution, or SQLite access threw
first. provider.calls == 0 and intent is None would still hold, and the
regression test would stay green while proving nothing about the
historical-upgrade contract it exists to guard -- the exact class of
defect this file was written to catch.

Both assertions now name the exact exception and match its message, so a
different failure earlier in draft() fails the test instead of passing it
for the wrong reason.

Gates: 1686 tests (both narrowed assertions still pass against the real
refusal), ruff clean, verify_tree 100/5/1, verify_secrets and verify_wheel
PASS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KR2F1vgfq8mygoDtcSaSyp
The Windows 3.12 cell failed on test_an_outward_command_refuses_an_unknown
_query_parameter with WinError 10053, which is the unread-body reset race
#39 was written to remove: `_outward` settles accepted() on the query
before it reaches for _body(), so a declared body goes unread, and closing
on unread bytes is a reset rather than a clean shutdown on Windows. Whether
the 400 or the reset reaches the client first is then a coin toss.

#39 fixed five call sites and claimed in its own docstring to have removed
"the last instance ... from this file". That claim was wrong when I wrote
it. This call site arrived in #35 and I missed it; the sweep behind #39 was
not a sweep. An AST pass over all 112 client call sites in the file now
says this was the only one left: every other send carrying a body either
declares transmit=False already or is an address that genuinely reads --
malformed JSON, the charset 200, and the provenance-in-order half of the
ordering test -- and the 39 calls through outward()/decide() never override
provenance, so they always reach the read.

The whole-file count in that docstring is replaced by the mechanism, which
cannot rot the same way: the file's rule is that an address refusing before
reading declares its body and sends none, written down on Client.send.

Withholding is the stronger fix rather than tolerating the race with
unread(), and it turns out to strengthen the test itself:

  drop accepted() from _outward       FAIL (TimeoutError)
  check the query AFTER _body()       FAIL (TimeoutError)
  the same reorder, body transmitted  PASS  <- what the old form allowed

The third line is the point. With the body sent, reading first and judging
the query second still answers 400, so the old assertion held while the
ordering it is named for had been inverted. Withheld, the refusal can only
arrive if the query was judged first, so the test now proves its own title
instead of a status code.

Gates on this commit: 1686 tests, ruff check and format clean, verify_tree
100 publishable text files / 5 reviewed renders / 1 reviewed screenshot,
verify_secrets and verify_wheel PASS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B8kjhqYENShpeZ16QDnsyo
@Deep-Sixed
Deep-Sixed marked this pull request as ready for review September 23, 2026 00:34
@Deep-Sixed
Deep-Sixed merged commit d0a40f9 into main Sep 23, 2026
24 checks passed
Deep-Sixed added a commit that referenced this pull request Sep 25, 2026
Brings in #40 (the 0003-era upgrade regression). Its change to
test_web_surface.py withholds the body on the one refuse-before-read call
site that still sent it; the new leading-empty-component test added here
already does the same, for the same reason.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012ViK1h7GSCZtShZqeknnVJ
Deep-Sixed added a commit that referenced this pull request Sep 26, 2026
Two findings from the review of #36-#40, both in the intake code #36 added.

A refusal decided on the envelope -- 413, 415, the namespace 400 -- is answered before
a byte of the body is read, which is right, and then the socket was closed on whatever
the client had sent, which is not. Closing on unread bytes is a reset, and a reset can
overtake the response; on Windows it discards a response the client has not read yet.
The page always sends the file it was given, so an operator choosing a 3 MB message
could see "Failed to fetch" instead of the ceiling that refused it.

The surface now settles every response the same way: write the answer, shut its own
send side, then read and discard whatever the client is still sending, bounded at
16 MiB and five seconds, and only then close. Nothing about what is decided, or when,
changes -- the answer is written before the drain begins and the drained bytes are
never parsed, stored or kept. The socket is reached as `self.request`, socketserver's
own name for it, because this package is mechanically forbidden the word `connection`
and that guard is right to be.

The suite could not see this. Every pre-read refusal was asserted with transmit=False,
which proves the surface decides before reading and cannot prove what a browser sees,
because a browser always sends the body. That was my choice in #39 and #40, and I did
not say what it left untested. These tests send it:

  unfixed surface, deterministic orderly-close test    FAIL 20/20 runs
  unfixed surface, over-ceiling full-body test         FAIL 10/10, then 1 pass in 3
  drain with no time bound                             FAIL (thread held)
  drain without shutting the send side first           FAIL (no early end-of-stream)

The small-body 415 and 400 full-body cases never fail on Linux; they are there for
Windows, where the reset destroys the response rather than trailing it.

`gmail-ingest --limit 0` reported "the mailbox could not be read". The service checked
label_ids before its try and let limit fall inside it, where every failure becomes
SourceUnreadable -- and only after the identity read had spent the credential. The
limit is now checked where label_ids is, against the reader's own rule, and the CLI
refuses a non-positive --limit before Gmail or the database is touched.

  service limit check removed    FAIL (4 cases)
  CLI limit check removed        FAIL

Finding #1 of the review, a malformed read token stopping serve, is not in this change:
whether that launch should refuse or start without Gmail is a decision still open.

Gates: 1686 -> 1696 tests, ruff check and format clean, verify_tree 100/5/1,
verify_secrets and verify_wheel PASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B8kjhqYENShpeZ16QDnsyo
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