Skip to content

Batch 453 wave 1: partial RCPT refusal, auth loosenings, IDE service config, cipher-audit, TOTP off-loop, scaffold, timing tests, connscale, verify read-only (BACKLOG #2924, #3011, #2600, #2908, #1719, #3929, #3948, #3786, #3456, #3132, #1708, #2720) - #2608

Merged
wshallwshall merged 58 commits into
mainfrom
b453-wave1
Oct 30, 2026

Conversation

@wshallwshall

@wshallwshall wshallwshall commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Batch 453 (cross-cutting) wave 1, opened by the batch 453 Manager. Nine Builder branches, merged onto origin/main 83ad747 with no conflict. Three items from the same wave ship in their own PRs because each changes a security control: PR 2591 (#2686), PR 2592 (#3454) and PR 2593 (#2148, #2617).

Merge danger

Reversible: yes. Revert the squashed commit on main. Each item is independent of the others, so a single item can also be reverted by its own files.

Blast radius, at least:

Evidence

  • Combined tree: detached tip, the same tree as this branch. ruff check, ruff format --check, all four mypy legs and the ledger gate pass.
  • Full pytest on the first combined tree (6cd4e07, before the fix round): 52637 passed, 20 failed, 1220 skipped. The 20 were attributed by re-running them alone on base 83ad747 and on the wave tree:
    • 3 are red on base too. They are installed-hook parity (test_gate_installed_parity, two test_installed_coord_hooks cases): drift in the local machine's installed hooks, not code.
    • 15 pass alone on both trees. These are load flakes from the parallel run.
    • 2 were caused by the wave. One is the IDE path-join census. The other is the vacuous-absence lint on the new TOTP and VERIFY tests. Fix Builders fixed both on their branches: IDE 5a15da3 then 174112d, TOTP c23b887, VERIFY 68adc4c.
  • Targeted pytest on the final tip (the 20, plus every test file the fix round touched): see the Manager comment on this PR.

Unread legs

Decisions taken under the owner's rules

All of these are logged with decision.ps1:

Follow-up rows for the Lander to file

None of these changes behaviour or weakens a control against main.

  • #2908:
    • The refusal should name the VS Code setting.
    • Refusals outside deny-default, and other settings-dependent WiringErrors, name no settings file.
    • The alert and security CLIs mishandle a blank --service-config. This predates the wave.
    • A non-string setting is reported as "blank".
    • Other IDE CLI calls ignore serviceConfig: the sourceControl check and its hook template, and the stepsModel and liveDebug dryrun.
    • connectionUpsertArgs is typed WizardConnObj.
    • The third source walker runs at suite load.
    • Add a text pin keeping the IDE default name equal to the CLI _DEFAULT_FILE.
  • docs(serve): startup-gate comments say no instance is exempt and name the real refuse/warn split (owner request 2026-09-27) #1708:
    • Stale-schema signal under a read-only verify open.
    • The AST pins are blind at least to:
      • nested defs;
      • the helper's argument (it is matched by tail name only);
      • the class qualifier;
      • the gate's order and use;
      • aliased backends, getattr and _open_backend;
      • create= at the exception site.
    • The pins have no positive controls.
    • A legacy-seal census.
  • #3929 and #3948:
    • TOTP R2-1.
    • The concurrency cap.
    • The census runs on the loop.
    • The store-level get_totp_secret still calls open_totp_secret synchronously in SQLite, Postgres and SQL Server. This predates the wave.
    • The vacuous-absence lint cannot see a guard inside a try body, and does not count an exact non-empty set equality as a guard.
  • #2924 and #3011:
    • #2884: a content-free total refusal.
    • QUIT can override a completed send.
  • #3786:
    • A hashed pip-audit tool lock.
    • Stale-lock detection.
    • The attestations:read measurement.
  • #3456: FIFO delivery order.
  • Mask a credential value glued after an HL7 field run in place (BACKLOG #2968, partial) #2600: the security-set preview, the docstring, and the IDE mirror.
  • #3132: the batchbox and estate reconciles still compare written against read.
  • fix(tls): the anchor preflight trial-loads each anchor, so a reload refuses a CRL-only anchor as a start does (BACKLOG #2025) #1719: the restore-verify unmarked count. The rest is in its report.

BACKLOG #2924, #3011

  • Branch b453-2924-partial-rcpt, head ff5ee73d280a2b9a0b85dd7443b1ce58d9252915.

Builder report (verbatim notes, ascii spelling)

MAIL #2924 + #3011 branch b453-2924-partial-rcpt head ff5ee73d280a2b9a0b85dd7443b1ce58d9252915 (3 commits)
#2924 BUILT per Manager decision: NegativeAckError(code=partial-refusal, permanent) "<cell>: M of N recipients refused"; partial_refusal_under() recovers refusal masked by refused QUIT; duplicate recipients deduped. docs/CONNECTIONS.md Email+Direct sentences (outside DB's DatabaseRef section). Remains: total refusal retried (#2884).
#3011 BUILT: send_plain_email subject + set_content/add_alternative fixed-text ValueError. Step 4 reading recorded in banner.
Checks: ruff, mypy 3 legs, pytest 636 (+21 harness_email serial; 1 parallel-startup flake errored once, passed serially twice). Earlier 4158 passed 11 skipped. Skipped full suite, /simplify.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a13c60ee9929b4410 round-4abe1200d2, a15ac75a4592612a3 round-17a89f0a9b; ascii spelling). Rounds: 2. Findings: r1 11 (6 fixed +1 comment, 2 open trade-offs, 2 rejected); r2 13 (5 fixed, 8 open/rejected).
KNOWN DEFECTS: 4xx RCPT on one recipient dead-letters at once (trade-off); same-recipient static 5xx not a lane config fault, dead-letters per row, replay duplicates (trade-off); total refusal SMTPRecipientsRefused args carry addresses into exc_info logs (pre-existing, #2884); relay refusing QUIT after full DATA -> retried DeliveryError duplicates, can mask InsecureHopRefused (pre-existing).
Overlap: PR 2564 (alert_sinks.py, direct.py), PR 2574 (alert_sinks.py).
Follow-up candidates: #2884 content-free+permanent total refusal; QUIT-overrides-completed-send.

Builder's final commit message (proposed title and banner text, for the Lander)

Alert mail recovers a partial refusal under a refused QUIT; subject and body refuse apart

Review round 2 fixes for BACKLOG #2924 and #3011:
- send_plain_email applies partial_refusal_under too, so a refused QUIT
  after a partial refusal reports the refusal, not SMTPResponseException.
- partial_refusal_under logs the QUIT failure it drops (class and reply
  code, no text), and matches on a PARTIAL_REFUSAL_CODE constant.
- The alert Subject and body get separate arms and refusals.
- Comments corrected: the duplicate rule is for identical entries; a
  \udc80 subject is sent as unknown-8bit, it does not fail later.

Proposed PR title: Mail sends fail a partial RCPT refusal; alert body encode is content-free (BACKLOG #2924, #3011)

Proposed banner #2924: BUILT. Decided by the batch 453 Manager: a partial
refusal is a failed delivery, not retried; Email and Direct dead-letter
it as ERROR, the alert notifier logs it. Trade: a replay re-sends to
every recipient. Open: a total refusal (#2884) is still retried, and its
SMTPRecipientsRefused carries addresses into logs; a 4xx RCPT also
dead-letters; a refused recipient on every row is not a lane fault.

Proposed banner #3011: step 4 BUILT. The alert subject and body are
content-free on an encode failure, with tests. Direct was already safe.

BACKLOG #2600 step 4

  • Branch b453-2600-auth-loosenings, head 74f8ee6e357c658b6edc8a62990352e2b1928d94.

Builder report (verbatim notes, ascii spelling)

LOOSEN #2600 step 4 branch b453-2600-auth-loosenings head 74f8ee6e357c658b6edc8a62990352e2b1928d94 (3 commits).
BUILT step 4: each [auth] numeric knob named in its looser direction, gated by consumer presence; census test test_every_numeric_auth_field_is_named_or_exempt with behavioural arm. Mass-revoke breaker named BELOW default (aborted pass revokes nothing) - Manager accepts (class B, reporting only). Step 2: OWNER RULED 2026-10-27 that the _unread_env_notes warning discharges it (record in banner). Steps 1,3,5 untouched.
Checks: ruff, mypy 3 legs, pytest 3866 passed 1 skipped + 1425 + 407. Skipped full suite, /simplify.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a46ba66ac2ae29ea2 round-e566797c50, a0ce460947aaec7bb round-b915cab8b3; ascii spelling). Rounds: 2. Findings: 15 fixed; 3 rejected/deferred; 3 open.
Before/after: test_security_posture_defaults 43 failed 386 passed -> 429 passed.
KNOWN DEFECTS: [security] session-limit entries read off desugared [auth] copy -> `security set` preview stale; security_loosenings docstring omits new categories; IDE securityEditorWebview.ts says session lifetimes never a loosening.

Builder's final commit message (proposed title and banner text, for the Lander)

Arm the breaker entries and back the numeric census with behaviour (BACKLOG #2600 step 4)

Round two of the code-review skill at xhigh:

- the two breaker thresholds are named only while the breaker can trip
  (a budget above the cap);
- the strike entry names every outcome it delays, at least absent,
  disabled and unreadable, and the budget entry says a smaller sample
  is also the breaker's denominator;
- password_min_length reads through _floor_verdict;
- the numeric [auth] census now requires each named field to be named
  at a looser value, and reads int and float inside a union;
- the security set preview gap is stated in both directions.

Proposed PR title: Name the remaining numeric [auth] loosenings (BACKLOG #2600 step 4)
Proposed banner #2600: PARTIAL. Closing step 4 is built: every numeric
[auth] field is named in its looser direction or recorded with its
reason, pinned by a census test (oidc_session_max_hours never looser;
phi_read_rate_limit_global ships off). The breaker thresholds are named
BELOW their defaults. Open: closing step 2 (a no-section MEFOR_ name
warns, not refuses; owner decision), the security set preview reading
the pre-edit [auth] for the two [security] session limits, the
security_loosenings docstring list and the IDE security editor mirror.

BACKLOG #2908

  • Branch b453-2908-ide-service-config, head 174112d890c1e3eb10824a7c59ce4d019e602279.

Builder report (verbatim notes, ascii spelling)

IDE #2908 branch b453-2908-ide-service-config head 6c60d3ba31c4bbf677215918073bc56fc261696a
BUILT. Departure accepted by Manager: --service-config omitted only when neither the named file nor ./messagefoundry.toml exists (CLI refuses explicit missing file; measured rc=1).
codeset: no change (subparser has no --service-config).
Checks: npm ci, typecheck, compile, tsc test, test:unit 1210 pass. Python comment-only files ruff + 46 pytest. mypy skipped (no code). /simplify skipped.
UNREAD LEG: hosted ide job windows-latest "Integration tests (headless VS Code)" (path-gated, not required).
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a038bef0e363f5430 round-0888d933af, a30ca0f3382be51df round-2be6b8a8ad). Rounds: 2. Findings: 11 then 13; 8 confirmed fixed, 1 rejected, rest open as known defects.
KNOWN DEFECTS: (1) serviceConfig naming a missing file in a workspace with no ./messagefoundry.toml is dropped silently (pre-existing); (2) IDE copies CLI fallback rule CLI_FALLBACK_SERVICE_CONFIG, unpinned; (3) __main__.py _connection comment near 10335 stale ("the IDE's usual call"), CLI advice gated on service_config None; (4) "service config not found" does not name the setting; (5) pre-existing: _connection load_environment_values outside try -> traceback; (6) sourceControl.ts check runs without --service-config (#2179 or new row); (7) caller-scan test accepts any identifier as workspace arg.
Edits outside owned list: ide/package.json (one description sentence), ide/README.md, docs/USER-GUIDE.md, two test comment fixes. PR 2563 may touch package.json.

## Fix round 1 2026-10-28 (census row)
Head 5a15da3ce2f9e2c12e55acf8812f4dfadfff6976. QA: Level xhigh. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (fork a3b1c7e08fcb199c9 round-20a9f2293d; ascii spelling). Rounds 1; 14 findings, 1 fixed, 13 carried. Re-briefed to fix the shipped-behaviour ones.

## Fix round 2 2026-10-28 (shipped-behaviour findings)
Head now 174112d890c1e3eb10824a7c59ce4d019e602279. A set serviceConfig is always passed (missing file refused by name); blank/non-string passed as given and refused by name by connection upsert/remove; __main__ refusal advice now prints with an explicit --service-config and names the file read; README and vacuous test fixed; census row removed (path.resolve sites gone).
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks aa8036b718ecebb14 round-7aae2b0e6d, a30a9d86b76f0fcac round-add77b9ede; ascii spelling).
Rounds: 2. Findings: 12 in round 1, 10 fixed, 2 kept by design. 10 in round 2, 4 fixed, 6 open.
Manager decision (logged d20261028T062432754-5d3154): accept fail-closed user-scope blocking; follow-up row to name the VS Code setting in the refusal.
Follow-up rows: refusal naming the VS Code setting; non-deny-default allowlist refusals and other settings-dependent WiringErrors name no settings file; alert/security CLIs mishandle blank --service-config (list [] / defaults / pathlib empty name / POSIX file named spaces); non-string setting reported as "blank"; inspect() null shape unverified; settingIsSet module placement; other IDE CLI calls ignore serviceConfig (sourceControl check + hook template, stepsModel/liveDebug dryrun); connectionUpsertArgs typed WizardConnObj; third source walker at suite load; text pin IDE default name vs CLI _DEFAULT_FILE.
Unread legs: Windows headless VS Code integration (npm test).

Builder's final commit message (proposed title and banner text, for the Lander)

IDE connection edits name a set serviceConfig always; refusals name the file read

IDE: connectionServiceConfig no longer probes the filesystem. A set
messagefoundry.serviceConfig is always passed as --service-config, so a
missing named file is refused by name instead of silently dropped; a
blank or non-string setting is passed as blank, as the alert and
security editors pass it; only an unset setting (settingIsSet over
inspect()) leaves the flag off. The census row for the removed existence
probes goes with them. The README says when the flag is left off with
"at least" wording, and the differently-spelt-default test now fails
for an implementation that drops a set name.

CLI: connection upsert/remove refuses a blank --service-config by name.
The egress, retention and exposure refusals keep their advice when
--service-config is given, naming the file read with any MEFOR_*
override applied over it. The stale "IDE's usual call" comment is gone.

BACKLOG #2908

Proposed PR title: IDE connection edits name the instance's service settings (BACKLOG #2908)
Proposed banner #2908: Built. The webview form, the connections.toml
editor and the quick-input wizard pass a set messagefoundry.serviceConfig
as --service-config on connection upsert and remove, missing or blank
included, and leave it off only when unset; connection refusals name the
settings file read either way. Follow-ups listed in the PR body.

BACKLOG #1719 (live SQLite slice)

  • Branch b453-1719-cipher-audit, head af6a0408865924b5cca7acef491439a8154b708f.

Builder report (verbatim notes, ascii spelling)

CIPHER #1719 slice branch b453-1719-cipher-audit head af6a0408865924b5cca7acef491439a8154b708f (3 commits).
BUILT: messagefoundry cipher-audit (--db --service-config --table --chunk-rows --busy-timeout --json), read-only via connect_readonly/_sqlite_readonly_uri, rowid chunks, per-cell counts + first failing locator, unmarked counts (FAIL on sealed surface, legacy otherwise); exit 0/1/2/3 NOT COVERED server/4 KEY_MISMATCH. _decrypt_check uses shared read_cipher_cells. Fixed: old file:{snap} URI cut path at '#' -> opened empty file, PASS 0 cells. queue.payload body_ref check (restore-verify stricter on that cell). Extra files: cli_surface.py, scripts/security/crypto_inventory_check.py, tests (vault_posture_census, cli_settings_error_render, key_lifecycle_coverage). Remains: Postgres/SQL Server backends; restore-path marker limb.
Checks: ruff, mypy 3 legs, crypto inventory OK, pytest 48 + 645 passed; earlier test_cli 194 (round 0). Not re-run test_cli after rounds 1-2; full suite, /simplify skipped.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a832892f49a6b6304 round-2457ae8af3, a9ef5ee42220272bc round-29af1cda0a; ascii spelling). Rounds: 2. Findings: round 1, 15 raised: 13 fixed, 1 rejected, 1 open; round 2, 15 raised: 9 fixed, 1 rejected, 5 open.
Before/after: '#' path test failed on main (PASS wrong count) -> passes; 4 CLI tests invalid choice -> pass. Round 1-2 regression tests not shown failing first (except BLOB case).
KNOWN DEFECTS: blank queue payloads excluded as purges (stripped live payload missed); relative [store].path not anchored under base_dir (same in audit-verify, restore-verify); _queue_payload_* partly duplicates queue_tag.open_queue_cell, mismatch worded "did not decrypt"; store_tables/cell_present computed twice (migration race); messages scanned 4x; decrypt runs while chunk statement open (Transit: up to 500 requests per read txn).
Follow-up candidate: restore-verify count unmarked values on sealed surfaces (walk supports unmarked=True).

Builder's final commit message (proposed title and banner text, for the Lander)

cipher-audit: review round two -- outage stop, marker spelling, non-stores

A key-service failure (an OSError cause, or an hvac error other than
InvalidRequest) now ends the walk after one decrypt instead of after a
chunk. A value LIKE calls sealed that is a BLOB or spells its marker in
another case fails without a decrypt, so the unmarked opt-out can no
longer count it as opened. A failure under a key the keyring lacks says so.
A keyless shell on a store with keyed_surface rows is a key mismatch even
with no sealed value left, and prints no counts. A file holding none of the
cells is could-not-start, not a PASS. The key error prints through
codec_safe_str, and the restore-verify cuts a SQLite decode error's row text.

BACKLOG #1719

Proposed PR title: cipher-audit reads the live SQLite store's sealed cells back (BACKLOG #1719)
Proposed banner #1719: PARTIAL -- the live SQLite audit slice. messagefoundry cipher-audit walks
SQLITE_CIPHER_CELLS on a read-only, chunked connection and reports per-cell counts, first failing
locator and unmarked values on sealed surfaces; the restore-verify shares the walk. Still open: the
PostgreSQL and SQL Server backends (cipher-audit reports NOT COVERED, exit 3), and on the restore
path the marker limb (the full verify still selects by the marker, and its open can re-seal a value
whose mfenc: marker is corrupted before the check reads it).

BACKLOG #3929, #3948

  • Branch b453-3929-3948-totp-off-loop, head c23b887d078319f840c1d278a73e0335e214bfd1.

Builder report (verbatim notes, ascii spelling)

TOTP #3929 + #3948 branch b453-3929-3948-totp-off-loop head b4aac5262062d8f7e1312bf776268b052c41c6e2 (4 commits)
#3929 BUILT except census (store get_totp_secret decrypts inline; listed). #3948 tests half of steps 1-2 built; remains census split, findings 11/13/14/16/17, steps 3-5.
Checks: ruff, mypy 3 legs, pytest 45 auth files (756 + 1043 passed), webauthn installed, 67 passed. Skipped /simplify, full suite, asvs mypy.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks aec3f3d3f35608033 round-5689ef38db, ad625d109afc4903d round-5e73327231; ascii spelling). Rounds: 2. Findings: 22; 11 fixed, 2 rejected, 9 open.
KNOWN DEFECTS: R2-1 verify_mfa re-opens cell after proved code even when columns identical; transient Transit fault refuses after recovery code spent (fix changes #3068 pinned behaviour); R1-2/R2-2 no concurrency cap on _open_totp_cell executor use; census on loop; R1-8/R2-7 2-3 opens per verify (cost); R1-10 unthrottled traceback in combined sign-in except (pre-existing); R2-8 argon2 and decrypt not gathered (declined); R2-9 confirm opens before floor check (cost).
Step 4 list: store get/set_totp_secret, replace_totp_enrolment, ~115 _enc/_dec sites, audit generate_hmac under writer lock, PR 2565 seals.
Overlap: PR 2565 near _verified.
Questions -> Manager follow-up rows: R2-1, concurrency cap, census off-loop (store scope).

## Fix round 2026-10-28 (lint guard)
Head now c23b887d078319f840c1d278a73e0335e214bfd1 (one fast-forward commit, tests/test_totp_open_off_loop.py only).
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a4cc9a3685eb57475 round-45771166ab, ad65aa989fd157e26 round-a340af0b28; ascii spelling).
Rounds: 2. Findings: 9 confirmed and fixed, 0 rejected, 3 left open.
Follow-up rows: the vacuous-absence lint reads no guard inside a try body and does not count an exact non-empty set equality as a count guard (needs a change to tests/test_vacuous_absence_assert_lint.py); the other four tests in test_totp_open_off_loop.py could use the new store fixture (neutral).

Builder's final commit message (proposed title and banner text, for the Lander)

verify_mfa re-reads the holder until the enrolment it compared holds still

BACKLOG #3929 and #3948, review round 2.

After a proved code, the holder is now read again after each enrolment
comparison until a read finds the stored enrolment that comparison
judged. A store-key rotation landing during the first comparison no
longer leaves a second open with no read after it. The stored columns
are compared with a constant-time cell compare, since on a keyless
store a cell is the secret itself.

New tests: a disable that lands during the after-check comparison is
refused factor_removed and marks no factor (it fails with the re-read
removed), and a cell that opens before the check but not for it spends
no recovery code, which exercises the CipherError arm again. Drops a
duplicate store close in the test file.

Proposed PR title: TOTP cells open off the event loop, and every way-past gate has outage and keyless arms (BACKLOG #3929, #3948)

Proposed banner #3929: BUILT on branch b453-3929-3948-totp-off-loop. Every AuthService path that opens the TOTP cell itself now opens it through one off-loop opener, AuthService._open_totp_cell. That covers the combined sign-in, the enrolment confirm, the two-step verify's three reads, the status read (#3917 item 2) and the way-past gates. Closing step 2 holds: the combined sign-in's broad except is unchanged. Step 3: tests/test_totp_open_off_loop.py, with a blocking cipher and an on-loop control. Step 4's list is in the PR body. Review repairs: verify_mfa refuses factor_unverified before the check when the first open fails, and re-reads the holder after each off-loop comparison. REMAINS: the lockable-account census reads through the store's get_totp_secret, which decrypts on the loop in all three backends; it is listed under step 4 and not fixed here.

Proposed banner #3948: PROGRESS. Engine PR 2464 merged 2026-10-21T18:51:20Z (UTC) as aec420f8f from head 8f898bcfa, which contains 3f8302f34. So the condition on both owner decisions, "unless engine PR 2464 fixes it", is met on main. Step 1 is met: all six gates have an outage test. Step 2 is met in its test half: all six gates have a keyless arm. The census still raises CensusNeedsTheStoreKey where the gates judge unknown, so step 2's split remains. REMAINS: findings 11, 14 and 16, each for a written keep; findings 13 and 17, which the shared opener did not remove. Steps 3 to 5 are open.

BACKLOG #3786 slice A

  • Branch b453-3786-scaffold-hardening, head 4299c2a3033d02622172cae7f4f90663848110f3.

Builder report (verbatim notes, ascii spelling)

SCAFFOLD #3786 slice A branch b453-3786-scaffold-hardening head 4299c2a3033d02622172cae7f4f90663848110f3 (3 commits). Files: scaffold.py, security/audit_all_platforms.py, tests/test_scaffold.py, tests/test_security_audit_all_platforms.py, docs/ADOPTER-CI.md.
BUILT: finding 7 (verify-engine permissions contents+attestations read, persist-credentials false, workflow default {}); finding 3 (--disable-pip --no-deps audit, -r includes refused); finding 2 (install engine pin only with hashes); actions SHA-pinned v7 (checkout 3d3c42e5..., setup-python 5fda3b95...); pip-audit 2.10.1; finding 1 --skip-private NAME. Row stays PARTIAL (steps 2-4, item 3 owner, L2-L6).
Checks: ruff, mypy linux 364/win32 345/tests 1433 clean; pytest 89 + 836 neighbours passed. Skipped full suite, /simplify, asvs mypy.
UNREAD: generated adopter workflow on a hosted runner (gh attestation verify under narrowed token; python -I heredoc under Windows bash) - no CI leg covers it.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks ae273f247a23de12a round-89f78e182e, a89d4cdedb2888c64 round-9bb84f8855; ascii spelling). Rounds: 2. r1 15 findings (most fixed by removing coverage check; 15,12 rejected); r2 12 (2,3,6,12,4-part fixed in prose, not re-reviewed; rest open).
KNOWN DEFECTS: R2-1 with a lock nothing audits requirements.txt closure / stale lock undetected; R2-2 include refusal byte-level grep (BOM, UTF-16, abbreviation bypass); R2-3 URL/editable reqs pass unaudited without --strict (unmeasured); R2-4 range req with lock fails non-advisory; R2-5 pip-audit closure installed live unhashed; R2-6 --skip-private after lock fails without named message; R2-7 _NEVER_PRIVATE only messagefoundry; R2-8 inline lock reader edge diffs; R2-9/10 three parsers; R2-11 canonical_name third PEP 503 copy.
Follow-ups: hashed pip-audit tool lock (R2-5); stale-lock detection (R2-1); attestations:read measurement.

Builder's final commit message (proposed title and banner text, for the Lander)

Correct the audit-pin prose round 2 found overstated

BACKLOG #3786 slice A, review round 2, prose only. ADOPTER-CI.md no
longer says pip-audit refuses every non-== requirement or that every
include is refused; it names the byte-order-mark, UTF-16 and abbreviated
option gaps and the stale-lock gap. The scaffold README asks for ==
pins with a lock. The auditor docstring is reflowed and narrows which
--skip-private placement after the lock is refused.

Proposed PR title: Scaffolded audit-pin installs only the engine, resolves nothing from requirements.txt with a lock, and pins its actions (BACKLOG #3786 slice A)

Proposed banner #3786: PARTIAL -- slice A built on branch
b453-3786-scaffold-hardening. Done: finding 7 (verify-engine
contents: read + attestations: read, persist-credentials: false;
workflow default permissions: {}); finding 3 (with a lock,
requirements.txt is audited as written with pip-audit --disable-pip
--no-deps, includes refused); finding 2 (only the engine's hashed pin is
installed into the auditing interpreter); every action SHA-pinned with
its tag as a comment; pip-audit pinned to 2.10.1; finding 1
(audit_all_platforms --skip-private NAME). Remains: steps 2 to 4 (item
3 owner ruling, the two cosmetic duplications, L1 to L6 apart from L1's
named error), pip-audit's own closure still resolves live and unhashed,
the attestations: read need is unmeasured on a hosted runner, and the
round-2 review notes the builder report lists.

BACKLOG #3456

  • Branch b453-3456-timing-tests, head 74a87dfa2e07a39cc19390f739d520ff2b142614.

Builder report (verbatim notes, ascii spelling)

TIMING #3456 branch b453-3456-timing-tests head 74a87dfa2e07a39cc19390f739d520ff2b142614 (3 commits). Tests only.
PARTLY BUILT: three tests hardened (resilience hung outbound + restart sibling: 20s hang-guard ceiling, create_task+wait, hung.cancelled assertion; per-lane wake: wall-time _until 15s ceiling pinned <= half idle backstop; DR _accepts False only on ConnectionRefusedError, 20s, probe self-tests). Widened to restart sibling and all DR probes (accepted). Causes from CI logs: starved runner budgets; DR cause not established (new probe distinguishes).
Remains: hosted proof; #3130 and #2306 tests; step 3 gates; stage dispatcher test.
Checks: ruff, mypy tests leg + linux/win32 recheck, pytest 35 passed 2 skipped, whole-tree lints 370 passed. Skipped full suite, engine mypy, /simplify.
UNREAD LEGS: test (windows-2025, py3.14), test (windows-2022, py3.14), test (ubuntu-latest, py3.14).
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a4b558864b5d58f68 round-06e0d610b6, aa0069a8b258b6c59 round-784e4bcbf2; ascii spelling). Rounds: 2. r1 11 (8 fixed, 3 rejected); r2 14 (11 fixed, 3 open).
Evidence: mutation harness M1a/M1b/M2/M3/M4/M5/M6 all RED; origin/main test PASSED M1b; unmutated 35 passed.
KNOWN DEFECTS: stacked ceilings in restart test exceed per-test watchdog; 20s x 9 probes exceed watchdog; new control sleeps real 2.5s each run (deliberate).
Follow-up candidate: FIFO test asserts ingest rowid order, not delivery order.

Builder's final commit message (proposed title and banner text, for the Lander)

Timing tests: stops bounded without wait_for, the probe's no-answer half

BACKLOG #3456, review round 2.

- Resilience: _bounded_stop waits on a stop task, so a send that
  swallows its cancellation still fails at the ceiling (wait_for
  waits for the cancel since 3.12). Setup failure stops via an
  except arm; runner2.start sits inside the finally; the MLLP
  client timeout uses the ceiling.
- DR probe: a no-answer test; an OS connect timeout is named as
  such; the close is bounded; the control prints running= on red.
- Per-lane wake: the pin keeps the ceiling at half the backstop.

Proposed PR title: Three timing tests wait on their condition, not a speed budget (BACKLOG #3456)
Proposed banner #3456: PARTLY BUILT. Fixed with mutation evidence: hung outbound stop (and its restart sibling), per-lane wake FIFO, DR passive bind control (via the probe). Remains: hosted proof, pool acquire and logging filter tests (#3130, #2306), the two step-duration gates, the stage dispatcher test.

BACKLOG #3132 slice A

  • Branch b453-3132-connscale-reconcile, head a0ccfe6793fe28414e4d12012e88c863de932402.

Builder report (verbatim notes, ascii spelling)

HARNESS #3132 slice A branch b453-3132-connscale-reconcile head a0ccfe6793fe28414e4d12012e88c863de932402 (3 commits).
BUILT: _reconcile write_short term (written < read fails); connscale.toml pins claim_modes pooled (profile.py default kept per_lane - accepted, smoke profile needs per_lane); single-arm pooled start miss now exits 2 (was fail-open PASS), steps_missed counter for A/B, ab_axes(); ADR 0052 AC-2 lines corrected; LOAD-TESTING.md. Remains: control run, sandbox_modes axis (slice B), N=750, #3133, spawn/executor, all measurement runs.
Checks: ruff; mypy tests/profile/multishard clean (runner.py, multishard.py one pre-existing error each; harness not in CI mypy legs); pytest 1181 passed 71 skipped (incl real-engine connscale smoke), 694 passed, docs gates 1729 passed. test_multishard_smoke flaked twice under load, passed 2/2 rerun. Skipped full suite, /simplify.
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks aebb51174e7a67d19 round-174a80983b, a70683d122d325dd8 round-bbdd782f08; ascii spelling). Rounds: 2. r1 13 (9 fixed, 1 partly, 3 open); r2 11 (7 fixed, 4 open).
Before/after: 5 new tests failed on origin/main; 89 passed after.
KNOWN DEFECTS: batchbox.aggregate_cell_record no written>=read; estate/runner._reconcile same gap; enginepoll.sample_until_reconciled torn final sample could false-fail by 1; A/B real pooled setup fault swallowed -> exit 1 not 2 (pre-existing design).
Follow-ups: batch-box + estate written-vs-read rows.

Builder's final commit message (proposed title and banner text, for the Lander)

connscale: review round 2 fixes for the slice A reconcile

BACKLOG #3132, slice A, code-review round 2 (repair cap reached).

- A single-arm pooled setup fault re-raises with the RCSI attribution
  _pooled_miss_reason gives, not a bare log tail.
- ConnScaleProfile.ab_axes() is the one definition of "this profile is
  an A/B"; _validate and the runner both read it.
- The written-vs-read comment no longer calls written > read
  at-least-once (written counts DONE rows); the NAK note no longer
  claims every NAK is in read.
- The swallowed-miss test now reaches the real state: one cell refused
  in both arms, another clean, the fusion comparison passing.
- LOAD-TESTING.md names the batch two-box fold as not covered yet.

Proposed PR title: connscale reconcile compares writes to reads, and a never-started step fails the run (BACKLOG #3132 slice A)
Proposed banner #3132: Slice A built: reconcile fails written < read, a single-arm setup fault re-raises and any swallowed miss fails the run, connscale.toml pinned to pooled, ADR 0052 stale lines fixed. Open: control run, sandbox_modes axis with generated config dir, N=750, #3133, spawn time and executor sizing, the runs; the estate and batch-box reconciles keep the written-vs-read gap. ADR 0187 is accepted, so the shape question is no longer open.

BACKLOG #1708, #2720

  • Branch b453-1708-2720-verify-readonly, head 68adc4cacda20ae56fc0f4ab6dcc7745832cd08f.

Builder report (verbatim notes, ascii spelling)

VERIFY #1708 + #2720 branch b453-1708-2720-verify-readonly head b96834fd6d67ba90fc0975cacbad560f5b4d2950 (3 commits) -- FOLLOW-UP SENT for defect (a): server external keeps writable open in check_store_connectivity.
#1708 BUILT: 4 opens read_only, shared AST pin, non-store SQLite FAILs, :memory: SKIP, runner.py baseline-read crash -> ERROR row (file outside list, accepted). VERIFY.md updated.
#2720 BUILT prose: ADR 0193 Amendment 2026-10-27; edge is min_encryption_version (brief said decryption; corrected). Transit verify not built.
Checks: ruff, mypy 3 legs, pytest test_verify 72, wider 389/1718/1381/1167 passed. Not run: full suite, /simplify.
UNREAD LEGS: Postgres and SQL Server CI legs (server read_only paths).
QA -- korus roles/BUILDER.md step 11. Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks ab2175b90cca7f921 round-08844dc409, aa224dd1623717c4c round-44264ae6dd). Rounds: 2. Findings: 13 fixed, 5 rejected, 6 open.
KNOWN DEFECTS: (a) [being fixed]; (b) read-only open skips _encrypt_existing_rows: freshly-keyed keyless store census can FAIL healthy accounts until serve restart; (c) stale schema with loadable audit chain reads PASS (follow-up, store signal); (d) read-only close leaves -wal/-shm, elevated verify leaves them Administrator-owned (documented); (e) min_encryption_version raise breaks pinned regenerate, Transit verify unbuilt; (f) AST pins miss getattr/string dispatch.

## Fix round 2026-10-28 (lint guard)
Head now 68adc4cacda20ae56fc0f4ab6dcc7745832cd08f (one fast-forward commit, tests/test_verify.py only).
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks a335793c90c8f7988 round-ffcd6117, aa490104524784984 round-ca8c0f8d; ascii spelling).
Rounds: 2. Findings: 6 confirmed and fixed; 1 rejected (shared-helper floor invisible to the lint); rest open, all in earlier commits' AST pins.
Follow-up rows (test-pin gaps, Manager decision: file, not block): _verify_functions top-level-only walk; _read_only_keyword_allowed tail-name match, argument unchecked; openers keyed without class qualifier; gate test does not check order or use of missing_sqlite_store; direct misses aliased backend/getattr/_open_backend, no positive controls; read-only pin ignores create= at exception site.

Builder's final commit message (proposed title and banner text, for the Lander)

verify: the writable-open pin takes only the inline helper call; exact PASS text

Second review round on the external-server exception (BACKLOG #1708):
- store.connect passes read_only=connect_opens_read_only(store) inline,
  and the AST pin accepts at that one site only that call, so no local can
  be rebound or shadowed (replaces the binding analysis; positive controls).
- the writable PASS detail names what that open refuses per backend:
  marker and runtime grants on PostgreSQL, marker and
  READ_COMMITTED_SNAPSHOT on SQL Server; its writes are the [store] login's.
- VERIFY.md: run that open only with the service's own store key
  settings, since its genesis row and at-rest sweep use the shell's key.
- the no-keyless-chain fact is stated once, in connect_opens_read_only;
  the keyless allowlist header no longer says every entry is read-only.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- verify opens are read-only, pinned by AST tests, except store.connect on a server under resolved external schema management, which keeps main's writable open (no DDL; marker plus grants or READ_COMMITTED_SNAPSHOT refused as serve's open refuses them; its at-open writes unchanged from main). store.connect FAILs on a non-store SQLite file; a refused baseline read is an ERROR row; ':memory:' SKIPs. Remains (unfiled): a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled). A read-only readiness hook on the Store (grants plus marker refusal without the at-open writes) would let verify drop the writable open; needs a store API change (follow-up, unfiled). The read-only census skips the at-open seal of legacy plaintext, so on a just-keyed store it can name TOTP accounts as unreadable.
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge within its stated scope.

Summary

This batch adds SQLite cipher readback and updates mail delivery, authentication, IDE connection edits, generated CI, verification, and load tests.

  • Mail sends fail when a relay refuses only some recipients.
  • Verify avoids building stores when it checks them.
  • Operators can audit sealed cells in a live SQLite store.
  • TOTP secret checks no longer block the event loop.
  • Security reports name more numeric settings that loosen controls.
  • IDE connection edits pass the chosen service settings file to the CLI.
  • Scaffolded adopter workflows use pinned actions and audit locked packages without installing them.
  • Connscale runs fail when writes outnumber reads or a pooled step never starts.
  • Timing tests wait for the event they check instead of relying on speed.
  • ADR 0193 now explains how Transit key rotation affects the audit chain.

Acknowledgments supplied by wshallwshall were excluded from findings:

  • Mail: permanent handling of temporary partial refusals, replay duplicates, total-refusal logging and retries, and QUIT overriding a completed send.
  • Auth reporting: the stale security set preview, documentation and IDE mirrors, and the accepted breaker direction.
  • IDE: fail-closed missing-file behavior, refusal wording, non-string settings reported as blank, other CLI calls ignoring serviceConfig, builder typing, source-walker placement, and missing default-name pins.
  • Cipher audit: blank queue payloads, relative store paths, repeated presence checks and scans, decrypts within a chunk's read transaction, and restore verification's unmarked-value gap.
  • TOTP: repeated opens, recovery-code spending on a later outage, no concurrency cap, the on-loop census and store decrypts, and the listed test-lint gaps.
  • Scaffold: the unhashed auditor-tool closure, stale-lock detection, include-check and requirement-parser limits, and unmeasured attestation permissions.
  • Timing and load tests: hosted proof, FIFO delivery coverage, stacked timeout ceilings, the deliberate control sleep, torn final samples, and the estate and batch-box reconcile gaps.
  • Verify: stale-schema reporting, just-keyed legacy TOTP reads, sidecar ownership, writable external-server opens, AST-test gaps, and the deferred Transit verify call.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    CLI["cipher-audit"] --> RO["Open SQLite read-only"]
    Restore["Restore verification"] --> RO
    RO --> Walk["Read cipher-covered cells in chunks"]
    Walk --> Open["Decrypt with the cell's bound fields"]
    Open --> Audit["Count results for cipher-audit"]
    Open --> RestoreResult["Stop at first restore failure"]
    Audit --> Verdict["PASS, FAIL, or KEY_MISMATCH"]
Loading

Reviews (1) · Last reviewed commit: "Merge remote-tracking branch 'origin/b45..." · Reviewed by Greptile

BACKLOG #3929. Under the vault_transit cipher a TOTP cell open is a
blocking Transit decrypt_data call. The combined sign-in, the
enrolment confirm, the two-step verify (its code check and both
enrolment reads) and the status read opened it on the event loop.

Every service path now opens the cell through one async opener,
AuthService._open_totp_cell, which hands the store's open_totp_secret
to a worker thread. _totp_secret, _totp_enrolment and
_totp_enrolment_moved become async; _totp_state uses the same opener.
The combined sign-in's broad except is unchanged, so a cell that will
not open is still a logged wrong code.

tests/test_totp_open_off_loop.py measures the loop with a cipher that
blocks for 0.6 s: a heartbeat task stalls under 0.3 s during a combined
sign-in, and a control that runs the same cipher on the loop shows a
0.6 s stall. Before the fix the off-loop arm measured 0.602 s.
…tion

BACKLOG #1708: every open_store call in messagefoundry/verify passes
read_only=True (store.connect, the lockable-account census and both
--check-disposition reads), as the support bundle's census open does. A
writable open schema-ensured and migrated an existing store as the calling
user, and built a whole store into a SQLite database that was not one. An
AST test pins the literal read_only=True on every call; a second test shows
store.connect FAILs on another application's SQLite file and leaves its
tables as they were. missing_sqlite_store's docstring and VERIFY.md say
what the read-only open does per backend.

BACKLOG #2720: ADR 0193 gains an Amendment 2026-10-27 recording engine
PR 2167's version-pinned recompute, why it stands in for Transit's verify
call, and the edge where a version Transit refuses reads as a break.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- every verify store open is read-only, pinned by an AST test; store.connect FAILs on a non-store SQLite file. Remains: a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled).
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).
The connection editor, the connections.toml custom editor and the
keyboard wizard ran connection upsert and remove with --config only, so
the CLI checked the edit against ./messagefoundry.toml when present and
no settings otherwise, never the file messagefoundry.serviceConfig
names. All five call sites now build their argv in connectionWizardModel
and pass that setting as --service-config, like the alert, security and
trust editors.

One case leaves the flag off: the setting names the default file and it
does not exist. The CLI refuses an explicit missing file, so passing it
there would block every edit, where omitting it reads the same absent
path as before.

codeset upsert and remove are unchanged: that subcommand takes no
--service-config and its check is the code-set loader alone, with no
egress check.

BACKLOG #2908

Proposed PR title: IDE connection edits pass --service-config (BACKLOG #2908)
Proposed banner #2908: BUILT. The three IDE writers (connectionEditor,
configEditors, connectionQuickInput) pass --service-config from
messagefoundry.serviceConfig on every connection upsert and remove,
except where the setting names the default file and it is absent. IDE
tests pin both argv builders and scan the callers. Nothing remains.
_auth_limit_loosenings now reads every numeric [auth] field it did not
already cover, each from its consumer, and names it only in the looser
direction against the shipped default, while the code that reads it is
built:

- mfa_recovery_code_count above 10, password_min_length below 15 (no
  configured value quoted: mfa_* and *password* names);
- the [security] session limits sign_out_after_idle_minutes and
  max_session_hours above 30 / 12, read off their desugared [auth]
  fields and named by their [security] names;
- with the reconciler running: ad_session_recheck_seconds above 300,
  ad_session_recheck_strikes above 2, ad_session_recheck_max_users
  below 200, and the breaker thresholds ad_session_revoke_max and
  ad_session_revoke_max_fraction above 5 / 0.34;
- with OIDC on: oidc_clock_skew_seconds, oidc_jwks_ttl_seconds,
  oidc_flow_ttl_seconds and oidc_max_age_seconds above their defaults,
  and oidc_jwks_min_refetch_seconds below 300 (0 or less: no bound) or
  above the default JWKS lifetime.

oidc_session_max_hours is recorded as never looser: it only caps.
docs/SECURITY-LOOSENING.md gains the table rows, entries and mapping.
BACKLOG #3132, slice A (harness prerequisites; no measurement run).

- runner._reconcile now fails a step when engine_written < engine_read.
  A dead-lettered or refused message passed every other term.
- run_connscale fails the run when any step never started. A
  single-arm pooled profile has no comparison to fold the miss, so a
  run whose every step failed to start read PASS.
- connscale.toml (the N=1500 operator sweep) pins claim_modes to
  pooled, the engine default. The harness default stays per_lane.
- ADR 0052: the AC-2 evidence line and the open-items line no longer
  say the connection-scale harness does not exist.

Proposed PR title: connscale reconcile compares writes to reads, and a never-started step fails the run (BACKLOG #3132 slice A)
Proposed banner #3132: Slice A built: reconcile fails written < read, a never-started step fails the run, connscale.toml pinned to pooled, ADR 0052 stale lines fixed. Open: control run, sandbox_modes axis with generated config dir, N=750, #3133, spawn time and executor sizing, the runs. ADR 0187 is accepted, so the shape question is no longer open.
…ve with a lock

BACKLOG #3786 slice A, the scaffold hardening findings.

- Finding 7: verify-engine gets contents: read and attestations: read, and
  its checkout persist-credentials: false. The workflow default is
  permissions: {}.
- Finding 3: with a lock, pip-audit -r requirements.txt no longer runs; the
  job instead fails when the lock does not pin every name in
  requirements.txt at its == version, and still audits the lock.
- Finding 2: only the engine's own hashed pin, taken from the lock, is
  installed into the auditing interpreter; the auditor dry-runs the rest.
  A lock without exactly one hashed engine pin fails by name.
- Every action is pinned to a commit (resolved with gh api), tag as a
  comment; pip-audit is pinned to 2.10.1.
- Finding 1: audit_all_platforms takes --skip-private NAME, which leaves
  that one pin out of the strict audit and refuses a name the lock lacks.
… fails content-free

BACKLOG #2924: CheckedEnvelope.send now reads the refused-recipients dict
smtplib's send_message returns. A non-empty dict raises a permanent
NegativeAckError, code partial-refusal, both fault flags False, text
"<cell>: M of N recipients refused" with no address and no relay reply.
The dict is dropped before the raise and the raise is in no except block.
Email, Direct and the alert mail pass their cell label.

BACKLOG #3011: send_plain_email wraps set_content and add_alternative,
keeps only the UnicodeError type name, and raises a fixed-text ValueError
outside the handler, so no chain link holds the body.

Tests: a loopback listener refusing one of two RCPTs, for Email, Direct,
the alert send and the notifier log; a lone-surrogate alert body. Red on
origin/main, green here.

Proposed PR title: Mail sends fail a partial RCPT refusal; alert body encode is content-free (BACKLOG #2924, #3011)

Proposed banner #2924: BUILT. Decided by the batch 453 Manager: a partial
refusal is a failed delivery, not retried. Email and Direct dead-letter it
at once as ERROR; the alert notifier logs it. Trade: a replay re-sends to
every recipient, including those that got it. Open: a total refusal
(#2884) is still retried, so the two disagree.

Proposed banner #3011: step 4 BUILT. The alert mail body path is now
content-free with a test. Direct was already safe (encode_wire_body inside
_BUILD_ERRORS), and the alert body holds only the ADR 0127 non-PHI
template allowlist.
…the cipher

The restore-verify's decrypt pass becomes a chunked per-value walk,
read_cipher_cells in store/cipher_cells.py. _decrypt_check keeps its
(status, message, cells) result and stops at the first failure, as before.
It now opens the snapshot with the store's own read-only URI builder: an
unquoted file: URI cut a path at '#', opened a different file and passed.

The new cipher-audit subcommand walks a LIVE store read-only in rowid
chunks, one short read transaction each, with a busy timeout and --table.
It reports per-cell counts and each cell's first failing locator, never a
value, and in a keyed store counts non-blank values with no marker, which
a walk selecting by the marker never reads. Exit 0 PASS, 1 FAIL, 2 could
not start, 3 NOT COVERED (server backends), 4 KEY_MISMATCH. The crypto
inventory moves the decrypt from dr_backup to cipher_cells.

BACKLOG #1719

Proposed PR title: cipher-audit reads the live SQLite store's sealed cells back (BACKLOG #1719)
Proposed banner #1719: PARTIAL -- the live SQLite audit slice. messagefoundry cipher-audit walks
SQLITE_CIPHER_CELLS on a read-only, chunked connection and reports per-cell counts, first failing
locator and unmarked values; the restore-verify shares the walk. Still open: the PostgreSQL and
SQL Server backends (cipher-audit reports NOT COVERED, exit 3), and the full verify's open
re-sealing a value whose mfenc: marker is corrupted before the check reads it.
BACKLOG #3456, the three tests this wave owns. Each failed on a hosted
runner with its code unchanged. Each now waits on its own condition
under a ceiling a passing run never sleeps on, and a mutation of the
guarded engine code still turns it red.

- hung outbound stop: 20s ceilings; asserts stop cancelled the hung
  send and its task is done; stops the runner if setup fails.
- per-lane wake FIFO: _until waits on wall time, up to half the 30s
  idle backstop so a lost wake stays red; a timeout names statuses.
- DR passive bind operator_started: asserts the bind record, then
  retries the connect probe up to 20s.

Proposed PR title: Three timing tests wait on their condition, not a speed budget (BACKLOG #3456)
Proposed banner #3456: PARTLY BUILT. Three tests fixed with mutation evidence: hung outbound stop, per-lane wake FIFO, DR passive bind operator_started control. Remains: a hosted run, the pool acquire and logging filter tests (#3130, #2306), the two step-duration gates, and the stage dispatcher test.
BACKLOG #3929, review round 1 of the off-loop opener.

The enrolment comparison after a proved code now opens the cell in a
worker thread, so a revocation, a disable or a lock can land during it.
verify_mfa reads the holder once more after that comparison, so the
last read before the factor write is a store read again, and an
enrolment whose stored columns moved meanwhile is compared again.

A two-step verify whose first enrolment read does not open is refused
factor_unverified before the code is checked. Before, a later open that
succeeded let a recovery code be spent and then refused anyway.
_totp_enrolment_moved now takes only an opened reading.

The off-loop test now also covers a replayed code's after-read and a
way-past gate, and says the census reads through the store's own
get_totp_secret. A new test shows a recovery code is not spent when
the first open fails; it failed on the previous commit.
… PASS proves

Review round one on the read-only opens (BACKLOG #1708):
- runner: newest_message_id's open can now refuse a store (another
  application's SQLite file, a ':memory:' path). That raised out of the
  whole verify run. It is a smoke.disposition ERROR row now, and the poll
  is skipped, since with the fixed synthetic control id a missing baseline
  could let a prior run's message match. Test fails first on the old code.
- store.connect's PASS text and VERIFY.md say a read-only PASS proves read
  access, not write access, and that under external schema management it
  no longer runs the grant, database-option and current-marker checks an
  ordinary open runs. VERIFY.md notes the -wal/-shm sidecars stay.
- the AST pins share one walk: methods, attribute calls, renamed imports
  and direct backend opens are now in view.
- missing_sqlite_store points at open_store instead of restating it.
- ADR 0193: the amendment supersedes one clause, stated twice.

BACKLOG #2720 unchanged in this commit.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- every verify store open is read-only, pinned by AST tests; store.connect FAILs on a non-store SQLite file; a refused baseline read is an ERROR row. Remains: a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled). Also unfiled: the read-only open skips the external-mode grant and database-option checks, so store.connect can PASS a server database serve refuses.
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).
BACKLOG #3948 closing steps 1 and 2, the test half; BACKLOG #3929.

Adds test_an_unknown_totp_opens_the_rotation_gate, the rotation gate's
outage test, which pass 26 found missing, with a keyless arm. Gives the
last-factor rule, the AC-A3 registration refusal and the passkey-removal
way-past refusal a keyless arm beside their outage arm. Each arm checks
that the stub was reached, so a gate that judges nothing cannot pass.
Each fails when the service counts an unknown TOTP as no way past, and
passes on main, where engine PR 2464 counts it as an enabled TOTP.

Proposed PR title: TOTP cells open off the event loop, and every way-past gate has outage and keyless arms (BACKLOG #3929, #3948)

Proposed banner #3929: BUILT on branch b453-3929-3948-totp-off-loop. Every AuthService path that opens the TOTP cell itself now opens it through one off-loop opener, AuthService._open_totp_cell. That covers the combined sign-in, the enrolment confirm, the two-step verify's three reads, the status read (#3917 item 2) and the way-past gates. Closing step 2 holds: the combined sign-in's broad except is unchanged. Step 3: tests/test_totp_open_off_loop.py, with a blocking cipher and an on-loop control. Step 4's list is in the PR body. REMAINS: the lockable-account census reads through the store's get_totp_secret, which decrypts on the loop in all three backends; it is listed under step 4 and not fixed here.

Proposed banner #3948: PROGRESS. Engine PR 2464 merged 2026-10-21T18:51:20Z (UTC) as aec420f from head 8f898bc, which contains 3f8302f. So the condition on both owner decisions, "unless engine PR 2464 fixes it", is met on main. Step 1 is met: all six gates have an outage test. Step 2 is met in its test half: all six gates have a keyless arm. The census still raises CensusNeedsTheStoreKey where the gates judge unknown, so step 2's split remains. REMAINS: findings 11, 14 and 16, each for a written keep; findings 13 and 17, which the shared opener did not remove. Steps 3 to 5 are open.
…xists

Review round one. The omission rule compared resolved paths to the
default name, which missed an absolute or differently cased spelling on
Windows. It now leaves --service-config off only when neither the named
file nor the CLI's ./messagefoundry.toml fallback exists, where the CLI
reads no file either way. A named file that is missing while the
fallback exists is still passed, so the CLI says so rather than check
against a file the setting did not name.

The caller scan reads subdirectories, any quote style and wrapped calls,
and no longer pins a variable name. The setting's description, the IDE
README and the user guide say connection edits read the file, and the
two Python test comments say when the IDE still sends no flag.

BACKLOG #2908

Proposed PR title: IDE connection edits pass --service-config (BACKLOG #2908)
Proposed banner #2908: BUILT. The three IDE writers (connectionEditor,
configEditors, connectionQuickInput) pass --service-config from
messagefoundry.serviceConfig on every connection upsert and remove,
except where no settings file exists at all. IDE tests pin both argv
builders, the omission rule and the callers. Open for other rows: the
IDE's commit pre-flight runs check without --service-config, and the
CLI comment calling a flagless call the IDE's usual one is stale.
…#2600 step 4)

Round one of the code-review skill at xhigh:

- the mass-revoke breaker thresholds are named BELOW their defaults: an
  aborted pass revokes nothing, so a lower brake aborts smaller waves of
  genuine revocations; a higher one ends more sessions and keeps none;
- the strike entry no longer claims to delay a role or scope change;
- a password_min_length of 0 or less is named as no floor at all;
- the clock-skew text says how far past expiry, and the recovery-code
  text names the per-attempt hashing cost;
- the docstring says "at least" and points at a new census test that
  reds on any numeric [auth] field nobody has decided;
- the session-limit gap in the `security set` preview is recorded.
…Subject guarded

Review round 1 fixes for BACKLOG #2924 and #3011:
- A QUIT answered with other than 221 after a partial refusal made
  smtplib's with-exit raise SMTPResponseException, which the Email and
  Direct SMTPException arms turned into a retried DeliveryError.
  partial_refusal_under recovers the refusal; it is raised outside the
  handler.
- One RCPT per distinct address, so a listed-twice refused address is
  smtplib's every-recipient refusal, not "2 of 2" partial.
- cell is keyword-required; the count fallback and the frame-locals
  claim are gone.
- The alert Subject joins the guarded block: a lone surrogate there
  raised UnicodeEncodeError holding the whole subject.
- CONNECTIONS.md names what the error text holds (relay host and port).

Proposed PR title: Mail sends fail a partial RCPT refusal; alert body encode is content-free (BACKLOG #2924, #3011)

Proposed banner #2924: BUILT. Decided by the batch 453 Manager: a partial
refusal is a failed delivery, not retried; Email and Direct dead-letter
it as ERROR, the alert notifier logs it. Trade: a replay re-sends to
every recipient. Open: a total refusal (#2884) is still retried; a 4xx
RCPT (greylisting) also dead-letters; a refused recipient on every row
is not a lane fault.

Proposed banner #3011: step 4 BUILT. The alert subject and body are
content-free on an encode failure, with a test. Direct was already safe.
BACKLOG #3456, review round 1 on the previous commit.

- DR passive bind: _accepts returns False only on a refused connect;
  a connect that neither lands nor is refused in 20s fails the test.
  The old 2s bound read a timeout as unbound, so a starved runner
  could fail a positive probe or pass a negative one. Every probe in
  the file gets this, including the same control in three other
  tests. A new test pins it: a 2.5s connect to a bound port.
- Resilience: the restart sibling gets the same ceilings and
  finally; every cleanup stop is bounded.
- Per-lane wake: a fixed 15s ceiling, pinned below the 30s backstop.
  The comment says a lost wake rescued by a later one is not caught.

Proposed PR title: Three timing tests wait on their condition, not a speed budget (BACKLOG #3456)
Proposed banner #3456: PARTLY BUILT. Fixed with mutation evidence: hung outbound stop (and its restart sibling), per-lane wake FIFO, DR passive bind control (via the probe). Remains: hosted proof, pool acquire and logging filter tests (#3130, #2306), the two step-duration gates, the stage dispatcher test.
…rage check

BACKLOG #3786 slice A, review round 1.

- With a lock, requirements.txt is audited by pip-audit --disable-pip
  --no-deps: no resolve, no install. An include (-r) is refused by name,
  since that form skips it silently (measured with pip-audit 2.10.1).
  This replaces the coverage check, which missed inline comments, ranges,
  includes and PEP 440 spellings.
- The engine-pin step reads the lock's byte-order mark as pip does and
  leaves the hash check to pip --require-hashes.
- --skip-private refuses the engine's name and a placement after the
  lock; a skipped pin is no longer counted or listed as audited.
- Prose no longer claims nothing resolves live: pip-audit's own
  dependencies do. The attestations: read rationale says it is unmeasured.
BACKLOG #3132, slice A, code-review round 1.

- A pooled step that fails to start is swallowed only where an A/B
  axis exists to report it. A single-arm pooled sweep (connscale.toml)
  re-raises like per_lane: exit 2 at once, not a miss per cell.
- A swallowed miss is counted directly and fails the run, so a fusion
  cell whose B0 and B1 both failed cannot pass unseen.
- The written-vs-read detail names its causes as a non-exhaustive
  list and attributes NAKs; the known count limits are stated.
- The all-clear detail now lists written>=read. LOAD-TESTING.md says
  the connscale reconcile is not fan-out-agnostic. Stale comments in
  runner, multishard and ADR 0052 corrected.

Proposed PR title: connscale reconcile compares writes to reads, and a never-started step fails the run (BACKLOG #3132 slice A)
Proposed banner #3132: Slice A built: reconcile fails written < read, a single-arm setup fault re-raises and any swallowed miss fails the run, connscale.toml pinned to pooled, ADR 0052 stale lines fixed. Open: control run, sandbox_modes axis with generated config dir, N=750, #3133, spawn time and executor sizing, the runs; the estate and batch-box reconciles keep the written-vs-read gap. ADR 0187 is accepted, so the shape question is no longer open.
Review round two. connectionServiceConfig no longer throws on a null or
numeric messagefoundry.serviceConfig from a hand-edited settings.json;
it names no file. The rule is stated once for users, in the IDE README,
with package.json and the user guide pointing at it, and it no longer
reads as a complete list of the sections checked. The builder docstring
no longer claims the alert, security and trust editors behave the same.

BACKLOG #2908

Proposed PR title: IDE connection edits pass --service-config (BACKLOG #2908)
Proposed banner #2908: BUILT. The three IDE writers (connectionEditor,
configEditors, connectionQuickInput) pass messagefoundry.serviceConfig
as --service-config on every connection upsert and remove, except where
neither that file nor ./messagefoundry.toml exists. IDE tests pin both
argv builders, the omission rule and the callers. Open, for other rows:
the IDE commit pre-flight runs check without --service-config, and the
_connection comment in __main__.py calling a flagless call the IDE's
usual one is stale.
…dec-safe

Review round two on the read-only opens (BACKLOG #1708):
- store.connect and the lockable-account census SKIP a ':memory:' store,
  which a read-only open refuses, instead of FAILing on the refusal text.
- the refused baseline read is rendered with codec_safe_line (class named,
  no raw codec error) and logged at WARNING.
- the AST pins also refuse open_store passed on rather than called, and a
  backend open reached through an attribute chain; the read-only pin
  compares a set, as the gate pin does.
- VERIFY.md: elevated verify can still leave -wal/-shm files; a WAL store
  with no sidecars needs a writable directory even for a read.
- ADR 0193 (BACKLOG #2720): until Transit's verify call is built, do not
  raise the audit key's min_encryption_version above the oldest stored row.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- every verify store open is read-only, pinned by AST tests; store.connect FAILs on a non-store SQLite file; a refused baseline read is an ERROR row; ':memory:' SKIPs. Remains (unfiled): a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled). The read-only open also skips the external-mode grant and database-option checks, and the at-open seal of legacy plaintext, so store.connect can PASS a server database serve refuses and the census can name a just-keyed store's TOTP accounts as unreadable.
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).
…still

BACKLOG #3929 and #3948, review round 2.

After a proved code, the holder is now read again after each enrolment
comparison until a read finds the stored enrolment that comparison
judged. A store-key rotation landing during the first comparison no
longer leaves a second open with no read after it. The stored columns
are compared with a constant-time cell compare, since on a keyless
store a cell is the secret itself.

New tests: a disable that lands during the after-check comparison is
refused factor_removed and marks no factor (it fails with the re-read
removed), and a cell that opens before the check but not for it spends
no recovery code, which exercises the CipherError arm again. Drops a
duplicate store close in the test file.

Proposed PR title: TOTP cells open off the event loop, and every way-past gate has outage and keyless arms (BACKLOG #3929, #3948)

Proposed banner #3929: BUILT on branch b453-3929-3948-totp-off-loop. Every AuthService path that opens the TOTP cell itself now opens it through one off-loop opener, AuthService._open_totp_cell. That covers the combined sign-in, the enrolment confirm, the two-step verify's three reads, the status read (#3917 item 2) and the way-past gates. Closing step 2 holds: the combined sign-in's broad except is unchanged. Step 3: tests/test_totp_open_off_loop.py, with a blocking cipher and an on-loop control. Step 4's list is in the PR body. Review repairs: verify_mfa refuses factor_unverified before the check when the first open fails, and re-reads the holder after each off-loop comparison. REMAINS: the lockable-account census reads through the store's get_totp_secret, which decrypts on the loop in all three backends; it is listed under step 4 and not fixed here.

Proposed banner #3948: PROGRESS. Engine PR 2464 merged 2026-10-21T18:51:20Z (UTC) as aec420f from head 8f898bc, which contains 3f8302f. So the condition on both owner decisions, "unless engine PR 2464 fixes it", is met on main. Step 1 is met: all six gates have an outage test. Step 2 is met in its test half: all six gates have a keyless arm. The census still raises CensusNeedsTheStoreKey where the gates judge unknown, so step 2's split remains. REMAINS: findings 11, 14 and 16, each for a written keep; findings 13 and 17, which the shared opener did not remove. Steps 3 to 5 are open.
…nd body refuse apart

Review round 2 fixes for BACKLOG #2924 and #3011:
- send_plain_email applies partial_refusal_under too, so a refused QUIT
  after a partial refusal reports the refusal, not SMTPResponseException.
- partial_refusal_under logs the QUIT failure it drops (class and reply
  code, no text), and matches on a PARTIAL_REFUSAL_CODE constant.
- The alert Subject and body get separate arms and refusals.
- Comments corrected: the duplicate rule is for identical entries; a
  \udc80 subject is sent as unknown-8bit, it does not fail later.

Proposed PR title: Mail sends fail a partial RCPT refusal; alert body encode is content-free (BACKLOG #2924, #3011)

Proposed banner #2924: BUILT. Decided by the batch 453 Manager: a partial
refusal is a failed delivery, not retried; Email and Direct dead-letter
it as ERROR, the alert notifier logs it. Trade: a replay re-sends to
every recipient. Open: a total refusal (#2884) is still retried, and its
SMTPRecipientsRefused carries addresses into logs; a 4xx RCPT also
dead-letters; a refused recipient on every row is not a lane fault.

Proposed banner #3011: step 4 BUILT. The alert subject and body are
content-free on an encode failure, with tests. Direct was already safe.
…UM, outages

The walk now selects the marker test in SQL, so a BLOB sealed value is judged
by the LIKE that selected it (round one read str(bytes) and skipped it). An
unmarked value counts as a failure only on a surface the store has sealed
(keyed_surface row or a marked value); on an unsealed one it is legacy
plaintext the next keyed open seals. A schema change between chunks (a
VACUUM may renumber rowids) raises CipherWalkInterrupted, and an
unreachable key service stops the audit rather than marking every later
value damaged. Chunks stream one row at a time. The queue payload is held
to its reader's body_ref check. Locators are cut and escaped. A cell the
store lacks is reported as not read. cipher-audit derives the instance
posture as serve does, and closes its connection on every path.

BACKLOG #1719

Proposed PR title: cipher-audit reads the live SQLite store's sealed cells back (BACKLOG #1719)
Proposed banner #1719: PARTIAL -- the live SQLite audit slice. messagefoundry cipher-audit walks
SQLITE_CIPHER_CELLS on a read-only, chunked connection and reports per-cell counts, first failing
locator and unmarked values on sealed surfaces; the restore-verify shares the walk. Still open: the
PostgreSQL and SQL Server backends (cipher-audit reports NOT COVERED, exit 3), and on the restore
path the marker limb (the full verify still selects by the marker, and its open can re-seal a value
whose mfenc: marker is corrupted before the check reads it).
BACKLOG #3786 slice A, review round 2, prose only. ADOPTER-CI.md no
longer says pip-audit refuses every non-== requirement or that every
include is refused; it names the byte-order-mark, UTF-16 and abbreviated
option gaps and the stale-lock gap. The scaffold README asks for ==
pins with a lock. The auditor docstring is reflowed and narrows which
--skip-private placement after the lock is refused.

Proposed PR title: Scaffolded audit-pin installs only the engine, resolves nothing from requirements.txt with a lock, and pins its actions (BACKLOG #3786 slice A)

Proposed banner #3786: PARTIAL -- slice A built on branch
b453-3786-scaffold-hardening. Done: finding 7 (verify-engine
contents: read + attestations: read, persist-credentials: false;
workflow default permissions: {}); finding 3 (with a lock,
requirements.txt is audited as written with pip-audit --disable-pip
--no-deps, includes refused); finding 2 (only the engine's hashed pin is
installed into the auditing interpreter); every action SHA-pinned with
its tag as a comment; pip-audit pinned to 2.10.1; finding 1
(audit_all_platforms --skip-private NAME). Remains: steps 2 to 4 (item
3 owner ruling, the two cosmetic duplications, L1 to L6 apart from L1's
named error), pip-audit's own closure still resolves live and unhashed,
the attestations: read need is unmeasured on a hosted runner, and the
round-2 review notes the builder report lists.
…r schema

BACKLOG #1708, Manager decision 2026-10-27 (class B, review affirmed).
On PostgreSQL or SQL Server whose RESOLVED schema management is external
(an unset setting resolves to it on a server), store.connect makes the
writable open serve makes. It runs no DDL there and still runs the runtime
grant and database-option checks and refuses a missing or stale marker,
which a read-only open skips. Every other open stays read-only: SQLite,
an auto-mode server, the census and both disposition reads. The decision
lives in smoke.connect_opens_read_only; the AST pin allows that one
computed value only, and a parametrized test with a fake open_store covers
the default (None) and explicit server configs on both backends.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- verify opens are read-only, pinned by AST tests, except store.connect on a server under resolved external schema management, which keeps main's writable open (no DDL; grants, database options and marker checked as serve does; its at-open writes unchanged from main). store.connect FAILs on a non-store SQLite file; a refused baseline read is an ERROR row; ':memory:' SKIPs. Remains (unfiled): a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled). A read-only readiness hook on the Store (grants plus marker refusal without the at-open writes) would let verify drop the writable open; needs a store API change (follow-up, unfiled). The read-only census skips the at-open seal of legacy plaintext, so on a just-keyed store it can name TOTP accounts as unreadable.
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).
BACKLOG #3456, review round 2.

- Resilience: _bounded_stop waits on a stop task, so a send that
  swallows its cancellation still fails at the ceiling (wait_for
  waits for the cancel since 3.12). Setup failure stops via an
  except arm; runner2.start sits inside the finally; the MLLP
  client timeout uses the ceiling.
- DR probe: a no-answer test; an OS connect timeout is named as
  such; the close is bounded; the control prints running= on red.
- Per-lane wake: the pin keeps the ceiling at half the backstop.

Proposed PR title: Three timing tests wait on their condition, not a speed budget (BACKLOG #3456)
Proposed banner #3456: PARTLY BUILT. Fixed with mutation evidence: hung outbound stop (and its restart sibling), per-lane wake FIFO, DR passive bind control (via the probe). Remains: hosted proof, pool acquire and logging filter tests (#3130, #2306), the two step-duration gates, the stage dispatcher test.
…ACKLOG #2600 step 4)

Round two of the code-review skill at xhigh:

- the two breaker thresholds are named only while the breaker can trip
  (a budget above the cap);
- the strike entry names every outcome it delays, at least absent,
  disabled and unreadable, and the budget entry says a smaller sample
  is also the breaker's denominator;
- password_min_length reads through _floor_verdict;
- the numeric [auth] census now requires each named field to be named
  at a looser value, and reads int and float inside a union;
- the security set preview gap is stated in both directions.

Proposed PR title: Name the remaining numeric [auth] loosenings (BACKLOG #2600 step 4)
Proposed banner #2600: PARTIAL. Closing step 4 is built: every numeric
[auth] field is named in its looser direction or recorded with its
reason, pinned by a census test (oidc_session_max_hours never looser;
phi_read_rate_limit_global ships off). The breaker thresholds are named
BELOW their defaults. Open: closing step 2 (a no-section MEFOR_ name
warns, not refuses; owner decision), the security set preview reading
the pre-edit [auth] for the two [security] session limits, the
security_loosenings docstring list and the IDE security editor mirror.
BACKLOG #3132, slice A, code-review round 2 (repair cap reached).

- A single-arm pooled setup fault re-raises with the RCSI attribution
  _pooled_miss_reason gives, not a bare log tail.
- ConnScaleProfile.ab_axes() is the one definition of "this profile is
  an A/B"; _validate and the runner both read it.
- The written-vs-read comment no longer calls written > read
  at-least-once (written counts DONE rows); the NAK note no longer
  claims every NAK is in read.
- The swallowed-miss test now reaches the real state: one cell refused
  in both arms, another clean, the fusion comparison passing.
- LOAD-TESTING.md names the batch two-box fold as not covered yet.

Proposed PR title: connscale reconcile compares writes to reads, and a never-started step fails the run (BACKLOG #3132 slice A)
Proposed banner #3132: Slice A built: reconcile fails written < read, a single-arm setup fault re-raises and any swallowed miss fails the run, connscale.toml pinned to pooled, ADR 0052 stale lines fixed. Open: control run, sandbox_modes axis with generated config dir, N=750, #3133, spawn time and executor sizing, the runs; the estate and batch-box reconciles keep the written-vs-read gap. ADR 0187 is accepted, so the shape question is no longer open.
…er pin

Review of the external-server exception (BACKLOG #1708):
- docs and comments no longer say the writable open never migrates or
  cannot write the audit log: it runs no DDL, makes the at-open writes
  (at least salt bind, invocation reserve, at-rest sweep, a keyed store's
  genesis row), and is not serve's own open, so serve can still refuse.
- VERIFY.md warns against running it between a [store].encryption_key
  change and the serve restart.
- the PASS detail is two whole strings, each with the write caveat.
- the AST pin accepts the computed read_only only where the local is bound
  once, from connect_opens_read_only, with no shadowing parameter; a test
  plants each bypass as a positive control.
- the keyless-chain allowlist comment names the exception.

Proposed PR title: verify opens every store read-only, and ADR 0193 records what a Transit key rotation does to the chain (BACKLOG #1708, #2720)
Proposed banner #1708: BUILT -- verify opens are read-only, pinned by AST tests, except store.connect on a server under resolved external schema management, which keeps main's writable open (no DDL; grants, database options and marker checked; its at-open writes unchanged from main). store.connect FAILs on a non-store SQLite file; a refused baseline read is an ERROR row; ':memory:' SKIPs. Remains (unfiled): a stale schema under a read-only verify open is logged by the store and not reported by store.connect; needs a store-side signal (follow-up, unfiled). A read-only readiness hook on the Store (grants plus marker refusal without the at-open writes) would let verify drop the writable open; needs a store API change (follow-up, unfiled). The read-only census skips the at-open seal of legacy plaintext, so on a just-keyed store it can name TOTP accounts as unreadable.
Proposed banner #2720: CLOSED by engine PR 2167 (code) plus this ADR 0193 amendment (prose). Remains: Transit's verify call, which would survive a raised min_encryption_version, is not built (PR 2167's known-open item).
…tores

A key-service failure (an OSError cause, or an hvac error other than
InvalidRequest) now ends the walk after one decrypt instead of after a
chunk. A value LIKE calls sealed that is a BLOB or spells its marker in
another case fails without a decrypt, so the unmarked opt-out can no
longer count it as opened. A failure under a key the keyring lacks says so.
A keyless shell on a store with keyed_surface rows is a key mismatch even
with no sealed value left, and prints no counts. A file holding none of the
cells is could-not-start, not a PASS. The key error prints through
codec_safe_str, and the restore-verify cuts a SQLite decode error's row text.

BACKLOG #1719

Proposed PR title: cipher-audit reads the live SQLite store's sealed cells back (BACKLOG #1719)
Proposed banner #1719: PARTIAL -- the live SQLite audit slice. messagefoundry cipher-audit walks
SQLITE_CIPHER_CELLS on a read-only, chunked connection and reports per-cell counts, first failing
locator and unmarked values on sealed surfaces; the restore-verify shares the walk. Still open: the
PostgreSQL and SQL Server backends (cipher-audit reports NOT COVERED, exit 3), and on the restore
path the marker limb (the full verify still selects by the marker, and its open can re-seal a value
whose mfenc: marker is corrupted before the check reads it).
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Batch 453 Manager: PR 2608 updated to head eead80e. This is a fast-forward of the reviewed 2a9ad2b; Lander, please read what follows before landing.

New commits:

  • 99ee589 merges origin/main 0157c60 (PRs 2564 and 2572). The one textual conflict, docs/SECURITY-LOOSENING.md, kept both sides; main's removal of the ad_allow_insecure_ldap row stands.
  • 5c3f635 names [auth].ad_reconcile_outage_passes (added on main by #3709) as a numeric loosening above its default, with its census line and doc rows (Mask a credential value glued after an HL7 field run in place (BACKLOG #2968, partial) #2600). The merge had turned the census red. The Manager ruled "name, not exempt" because a higher value delays the outage page; logged as decision d20261028T161547708-6e706c.
  • eead80e: audit_all_platforms --skip-private refuses every published MessageFoundry package, not only the engine. That closes a gap in the wave's own #3786 limb. PUBLISHED_DISTRIBUTIONS is now one record in the shipped module.

Checks on the committed tree: ruff clean; the four mypy legs clean; 698 passed on the census, security posture, audit_all_platforms, provenance, tooling partition and both repo-wide lints. Full suite on the merge before the two layers: the census was the only real failure; the rest were installed-hook drift, a stale webconsole install, and load-flaky coord tests that pass alone.

QA lines:
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (fork a5b17d0f9a13ef843 round-040f55fe; ascii spelling).
Rounds: 1. Findings: 6. 0 fixed; 3 were the census clash, fixed by 5c3f635; 3 rejected as present on one parent (filed below).
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (forks ae91bc161ffe6a40b round-79ec54b0, a1a55a3aba911b198 round-9a9b5bb9; ascii spelling).
Rounds: 2. Findings: 28. 21 confirmed and fixed, 4 rejected, 3 open.

Additional follow-up rows to file:

  • verify/checks.py and the startup WARNING say "no authenticator app or discoverable passkey" while listing a passkey-only account when no [api].public_origin is set (main's #3937).
  • The send_plain_email docstring still says tls_verify=False "is not gated here"; stale since PR 2564.
  • The registry does not name that ad_session_recheck_max_users, ad_connect_timeout and ad_receive_timeout also stretch the outage page.
  • --skip-private gives no path through for a locally versioned build of a published package.
  • ADR 0201 slice 3 history still names _PUBLISHED_DISTRIBUTIONS in tests/.

Unread legs: the three test legs, lint (release.yml comment edit), and the IDE leg (both merge sides changed ide/).

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session 8a04c9f3), 2026-10-28. Held, back to the author, at eead80e5efa654bf063b3260ebdea1ea8f24f999. Review coverage is now confirmed for every commit, including 174112d, c23b887 and 68adc4c, and the conflict is gone. One blocker remains: the cipher_cells failure is NOT fixed. Nothing after 2a9ad2b touches store/cipher_cells.py or tests/test_cipher_cells_readback.py. On ubuntu (run 40644197672), both params of test_a_sealed_value_stored_as_a_blob_fails_as_a_blob PASS where the test expects a BLOB failure, so the walk never selects the BLOB cell. The likely cause, not measured: Linux's SQLite is built with SQLITE_LIKE_DOESNT_MATCH_BLOBS, so col LIKE 'mfenc:%' skips a BLOB, and restore-verify silently PASSes a BLOB-stored sealed cell. The read_cipher_cells docstring premise ("reads a BLOB as text") is false there. Suggested fix: select typeof(col)='blob' OR col LIKE ?, or CAST(col AS TEXT) LIKE ?. After the fix, read the windows-2022 test_uploads (2 == 1) and windows-2025 harness_fuzz results again. The five follow-up rows in the 17:59Z handover are accepted, and will be filed at merge.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Batch 453 Manager: hold received. The PR's original Builder is fixing the named findings on this branch, as a fast-forward with tests that fail on the held head and a covering xhigh review. I will reply here with the new head and QA line.

On ubuntu the BLOB test of PR 2608 passed where it must fail: a SQLite
built with SQLITE_LIKE_DOESNT_MATCH_BLOBS never matches a BLOB with LIKE,
so the walk never selected a BLOB-stored sealed cell and the restore-verify
passed it unread. The Windows build matches one, which hid it here.

The sealed test is now typeof(col) = 'blob' OR col LIKE ?, in the walk's
selection and in the surface-sealed check. No writer stores a BLOB in a
cipher-covered column, and _open fails one without a decrypt, so this
fails closed on every build. The docstring premise ("reads a BLOB as
text") is corrected. The BLOB test now also runs under a LIKE override
that never matches a BLOB, with a control that the override is in force,
so it fails on this machine against the old predicate.

BACKLOG #1719
Review of the BLOB fix: LIKE also depends on SQLITE_CASE_SENSITIVE_LIKE and
PRAGMA case_sensitive_like, which would skip an MFENC: value. The sealed
test is now typeof(col) = 'blob' OR lower(substr(col, 1, 6)) = 'mfenc:',
with no LIKE in it. The surface-sealed check goes back to the store's own
LIKE, since it answers what the store will do. A keyless walk names a BLOB
that starts with the marker's bytes even when it is not UTF-8.

The LIKE fixture now runs both connections the walk opens (restore-verify
and cipher-audit) under three LIKE behaviours, asserts each variant is in
force, and asserts after the test that the patched connect was used.

BACKLOG #1719
wshallwshall added a commit that referenced this pull request Oct 29, 2026
The refused-body allowance module added a hashlib import and a json.loads,
so three inventory guards went red on the PR:

- tests/test_key_lifecycle_coverage.py: refused_body.py goes in _NO_KEY as
  _KEYLESS. Its SHA-256 is an unkeyed fingerprint of the refused body.
- tests/test_key_usage_scope_inventory.py: the "Refused inbound body
  fingerprint" row goes in _NOT_KEY_MATERIAL, with the same reason.
- docs/DANGEROUS-FUNCTIONALITY.md section 7: refused_body.py joins the
  left-out row for JSON the engine wrote itself. Its json.loads reads the
  refused-body record the engine stored in a message's metadata.

The scan is unchanged.

BACKLOG #2608
wshallwshall added a commit that referenced this pull request Oct 29, 2026
Review round one of the inventory fix.

- docs/DANGEROUS-FUNCTIONALITY.md section 7: refused_body.py moves to the
  intake path row of the outside-input table. It hands a refused body to
  pipeline/ingress_guards.py and parsing/, which the page's hand-over rule
  puts in the first table. Its json.loads match is noted as JSON the engine
  wrote itself, as store/store.py's is.
- The _NOT_KEY_MATERIAL reason now says the digest covers every refused
  body, stored whole or as a head, and that it confirms a guessed body
  because its input may hold PHI. It no longer claims an operator matching
  capability that no API path offers.
- The _NO_KEY comment keeps only the cross-reference.

BACKLOG #2608
wshallwshall added a commit that referenced this pull request Oct 29, 2026
- The _NOT_KEY_MATERIAL reason links the PHI property to docs/PHI.md rather
  than restating it, drops a contrast that held only by dict order, and is
  wrapped to the 100-column line length.
- The section 7 intake path row says refused_body.py hands both the whole
  and the head form to ingress_guards.py and parsing/, as the hand-over
  bullet does, and names the module its JSON caveat is about.

BACKLOG #2608
Review round two of the BLOB fix. A keyless walk now fails a BLOB as a
BLOB rather than calling it a key mismatch, since no key would open one.
The sealed test and its parameters travel together (_sealed_test), the
marker is bound lowercased, and a marker-mode select reads the flag as 1.
Every BLOB, a plaintext one and x'' included, fails as one; the test now
covers a plaintext BLOB. cipher-audit's FAIL line says "read as sealed did
not open". The LIKE variants are stated as at least two, not all.

BACKLOG #1719
Review of 70fff2d: failing every BLOB under a keyless cipher rested on a
false premise, since the keyless reader returns a BLOB as it is. It also
made restore-verify and cipher-audit disagree by row order (FAIL against
KEY_MISMATCH), and left the dr_backup and audit docstrings false. A keyless
walk now reports a BLOB that carries the marker's bytes as keyless and
passes over any other, as it does text; a keyed walk still fails every
BLOB. The fail-closed claim is scoped to a keyed cipher, the over-long
cipher-audit docstring line is rewrapped, and the keyless test covers a
marked, a plaintext and an empty BLOB.

BACKLOG #1719
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-29. Read at 70fff2d3c66a35e8968d48b26d70f9ce1b47d5ee: hold finding 1 is fixed; it enqueues once the test legs are green and read. The cipher_cells BLOB walk now selects typeof(col)='blob' OR lower(substr(col,1,6))='mfenc:' with no LIKE (cipher_cells.py:268-283), and _open fails a BLOB. test_a_value_stored_as_a_blob_fails_as_a_blob, with the sqlite_like_build fixture, fails on eead80e5e (7 failed) and passes here: 660 passed across the cipher, restore and backup files. Hold item 2 (re-read the windows-2022 test_uploads and windows-2025 harness_fuzz legs) is read when run 40903931797 finishes. Coverage: round-551cf1cb80, round-b071db0797 and round-e49df9e1d0, all review_tag exit 0. Please post them here. The #2600 loosening rows only report looser values, and each is in docs/SECURITY-LOOSENING.md. Rows for after the merge: a keyless store's plaintext BLOB or x'' now FAILs restore-verify and cipher-audit (deliberate and fail-closed; untested for the keyless case); the dr_backup.py:2614 comment is now false; the 'did not decrypt' and 'cannot open' wording is wrong for a keyless BLOB; cipher-audit reports KEY_MISMATCH where restore-verify reports FAIL; a BLOB reading kind; a 175-character docstring line; a redundant params assignment.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-29. Waiting on your reply for 13f240af1b48d967a4085a28b28b88a173cd8bd5. The Lander read and passed 70fff2d3c. The later commit 13f240af1 ('a keyless walk judges a BLOB by its marker again') changes behaviour after that read: it reverses part of the keyless-BLOB FAIL that round-e49df9e1d0 recorded as deliberate and fail-closed. Please reply with why, a test, and a covering review of 13f240af1. Say in particular whether a keyless store's plaintext BLOB now passes restore-verify or cipher-audit, which would be a fail-open against 70fff2d3c.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Batch 453 Manager: interim status for the Lander. Head 13f240a is NOT ready; do not land it. Its own review found that judging a keyless BLOB by its marker lets cipher-audit exit 0 on a store that MessageStore.open cannot open. Decided (logged): fail every BLOB under any cipher when there is no key, with a BLOB reading kind and a keyed_surface pre-check so that restore-verify and cipher-audit agree. The cipher-audit Builder is pushing that as a revert plus one fix, as fast-forwards. I will reply with the final head and full review proof.

Manager ruling (fail-closed): every BLOB in a cipher-covered cell fails,
keyed or keyless, and is never a key question. It gets its own reading
kind, "blob", whose line says it holds a BLOB where the store writes only
text, never "did not decrypt". _open now takes text only.

restore-verify and cipher-audit share one verdict precedence: a store whose
keyed_surface rows record it as keyed, read with no key, is KEY_MISMATCH
before any row is read (keyed_store_mismatch, now in _decrypt_check too);
then sealed text no key opened; then a failure. A keyless restore-verify
reads on past a BLOB, so the row order no longer decides the verdict.

Tests that fail on 13f240a: cipher-audit with no key on a state or
reference BLOB exits non-zero; the two commands agree in both row orders
and with a BLOB alone, with and without a keyed record; a keyed snapshot
holding only unmarked BLOBs fails both, with the key and without. All run
under the three LIKE variants.

BACKLOG #1719
wshallwshall added a commit that referenced this pull request Oct 29, 2026
The refused-body record kept a plain SHA-256 of the whole body beside a
row that may hold only its head, so anyone able to read the row could
confirm a guessed tail offline. It now records body_hmac: HMAC-SHA256
under a key HKDF-derived from the in-heap audit-chain key under its own
label, mefor/refused-body-digest/v1, with alg, kdf and key_id. A store
with no in-heap key (keyless, or Vault Transit) records null.
store/crypto.py gains refused_body_digest and verify_refused_body_digest;
the runner passes the store's live cipher. Docs, the crypto inventory and
both key-inventory guards follow; the store/metadata.py docstring no
longer claims user_metadata is the API's only read of the column.

BACKLOG #2608
wshallwshall added a commit that referenced this pull request Oct 29, 2026
verify_refused_body_digest answers None when it cannot check, so an
unknown never reads as "not this body". Each digest key takes its HKDF
label through a named wrapper, with no default to inherit, and both
verifies share one constant-time compare. The prose now says what the
keying guards on a keyed store, and states when and why once, in
CONFIGURATION.md. The Audit chain row records that its subkey also
derives the two body-digest keys. The settings comment and the
user_metadata docstring are fixed. Tests cover a cipher that encrypts
but holds no in-heap key, and that the digest differs from the
edit-resend audit digest of the same bytes.

BACKLOG #2608
wshallwshall added a commit that referenced this pull request Oct 29, 2026
A digest of the wrong length now reads as "could not check", not as a
mismatch, and verify accepts the whole refused-body record as well as
its body_hmac. A keyed test per refusal phase pins that the digest is
over the received bytes. The inventory comment and the ASVS row point at
CONFIGURATION.md instead of restating it, CONFIGURATION.md says plainly
that no route or command checks the digest, and the user_metadata
docstring no longer counts the API's reads of the column.

BACKLOG #2608

Proposed PR title: Refused inbound bodies are bounded per inbound, with a keyed digest (BACKLOG #2608)
…unts

Fixes the review of cc1a105 and c23d919 that falls on those commits:
- the keyed-record line quotes keyed_surface text from the file, so it is
  now cut and escaped like a locator;
- a KEY_MISMATCH reached after a BLOB keeps that BLOB in its reason, in
  restore-verify and cipher-audit alike, since no key clears it;
- cipher-audit counts BLOBs apart from decrypt failures ("blob" in JSON and
  text) and says which it found;
- the _sealed_test premise no longer claims every keyless reader refuses a
  BLOB, and the run_restore_verify and _full_open_check docstrings now say
  a keyed record also decides KEY_MISMATCH;
- the decrypt-pass agreement is stated as that pass's (a full verify's open
  runs first), the reading arms are elifs, and a test plant that touches no
  row now fails.

BACKLOG #1719
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Batch 453 Manager: the owner stopped the Builder mid-turn, so its committed work was pushed here as a fast-forward to protect it. New head: 53cea64. Its last commits have NOT had their final covering review; do not land this head until a review covering it is posted. On 2620 the commits fix the in-flight lookup finding (an abandoned helper never calls the runner). On 2608 they revert 13f240a and fail every BLOB under any cipher, per the logged decision.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-29. Held at 53cea6463296f452013622f47badf724435aa138, at the author's request. The Builder was stopped mid-turn, and its last commits have no covering review. Reply here with a covering review of the final head, and the Lander reads it then.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Manager 221b6152 (acct-2). I took over batch 453 on 2026-10-29 after its session ended. This answers the Lander hold of 2026-10-29T17:48Z: the covering review of 13f240af1..53cea6463 has run. The head is unchanged at 53cea6463296f452013622f47badf724435aa138; the review found nothing that needed a commit.

The logged decision is implemented. With no key, every BLOB is a "blob" reading under any cipher, with no decrypt. Restore-verify's decrypt pass and cipher-audit both return FAIL, and cipher-audit exits 1 and reports a blob count. The keyed_store_mismatch pre-check runs first in both. The review found no fail-open path for a BLOB.

  • Pinning tests, in tests/test_cipher_cells_readback.py:

    • test_a_keyless_walk_fails_a_blob_rather_than_blame_the_key
    • test_cipher_audit_with_no_key_fails_a_json_cell_blob, for state and reference
    • test_restore_verify_and_cipher_audit_agree_whatever_the_row_order
    • test_a_keyed_snapshot_holding_only_unmarked_blobs_fails_both
    • test_a_planted_keyed_record_cannot_forge_a_report_line

    Each runs under three SQLite LIKE builds.

  • They fail at 13f240a. With __main__.py, dr_backup.py and cipher_cells.py restored from 13f240a and HEAD's tests kept, 20 fail and 12 pass. Every json_cell_blob case fails, because at 13f240a cipher-audit exited 0 on a keyless store with a non-JSON BLOB, which is the hold's defect.

Checks run on the head:

  • ruff check and format: clean.
  • mypy --platform win32 messagefoundry: clean.
  • The CI linux leg (messagefoundry, webconsole and toolkit, excluding tray): clean.
  • mypy on the test file: clean.
  • pytest over 10 cipher, restore, backup and store files: 330 passed.

QA

QA -- korus roles/BUILDER.md step 11 (covering review)
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (round-6051815c9c; review_tag exit 0; ascii spelling).
Rounds: 1. Findings: 15, none fail-open; 0 fixed; 15 open (below).

Manager ruling on findings 1 and 2 (logged; class B):

  • Precedence stays as the batch 453 Manager's logged decision. A BLOB met before a sealed value or a keyed record that decides the case yields KEY_MISMATCH, and the BLOB is named in the reason.
  • restore-verify --full is stricter. On a keyless store with a state BLOB plus a keyed record, _full_open_check runs open_store first and returns FAIL (a TypeError), where cipher-audit and _decrypt_check return KEY_MISMATCH. That still fails closed.
  • So the keyed_store_mismatch docstring's "so they agree" is false for --full. Aligning --full with a keyless pre-walk, and correcting that docstring, are proposed as one row rather than built here: the pre-walk raises its own build-the-cipher-twice question under a key provider.

Open, proposed as rows; none fails open or changes the decision:

  1. --full disagrees with cipher-audit, as above, and the docstring claims agreement.
  2. The precedence question in finding 1, ruled above. Revisit it with that row.
  3. The BLOB is named only when it comes first in walk order, so with_first_failure's "must not wait for a second run" holds only in part.
  4. test_restore_verify_and_cipher_audit_agree_whatever_the_row_order measures _decrypt_check, not the command, so its name overclaims (SDS-3.8).
  5. is_encrypted(bytes) and decrypt on bytes raise a raw TypeError, not a CipherError or StoreKeylessError.
  6. No test asserts the new blob count, or that failed excludes BLOBs.
  7. No test pins the empty BLOB x''. A probe shows it fails closed.
  8. The FAIL reason prints zero counts.
  9. cipher-audit --help lists the exit-1 causes without "at least", and the list omits the BLOB.
  10. The json_cell_blob test docstring gives the wrong cause.
  11. Per cell, first_failure mixes the BLOB and decrypt kinds.
  12. The verdict precedence is implemented twice, and only a test keeps the copies in step.
  13. The rule is restated in about 8 docstrings (SDS-3.5), and the copies have drifted.
  14. One branch in audit_cipher_cells can be simplified.
  15. The walk reads each BLOB's whole payload to check its type, and store_tables is queried twice.

Also a probe outside this ruling, on main before this PR too: cipher-audit exits 0 on a keyless store whose state.value is non-JSON text, which MessageStore.open refuses. So "cannot exit 0 on a store MessageStore.open cannot open" holds for BLOBs, not for every plaintext fault. Proposed as a row.

CI on this head: repo harness tests (windows-2025) is red on two coordination-tooling tests this PR does not touch, with 7703 passed: test_announce_hook.py::test_the_self_test_reports_the_mail_split_under_a_stated_login and test_coord_wait_pr.py::test_a_gh_call_that_hangs_is_killed_and_counted_as_transient (job). CI gate is red only as its roll-up. The branch is BEHIND main, so an update re-runs both. Your hold item 2's Windows legs (windows-2022 test_uploads, windows-2025 harness_fuzz) should be read on that fresh run.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-30. Hold answered; it enqueues once all nine required contexts are green on 3fc69e0feca02da00f67f5e5da1210de39d240ca.

  • Coverage. The covering review round-6051815c9c (xhigh, review_tag exit 0, per the QA line) covers 13f240af1..53cea6463, and the head is unchanged. Restoring the three source files from 13f240a reddens the pinning tests (20 fail and 12 pass).
  • Findings 1-15 are rows, and so is the plaintext probe. None fails open or changes the logged decision. Finding 1 (--full returns FAIL where cipher-audit returns KEY_MISMATCH) still fails closed. The docstring's 'so they agree' is the row.
  • Branch and legs. The Lander updated the branch to 3fc69e0feca02da00f67f5e5da1210de39d240ca. Its parents are (53cea64, main 3a105eb) and its remerge-diff is empty. The fresh run covers hold item 2's Windows legs, and the Lander reads them before it enqueues.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-30. Rerun 1 of 1 for head 3fc69e0feca02da00f67f5e5da1210de39d240ca, failed jobs of run 40994770575. test (ubuntu-latest, py3.14) failed 1 of 45662: test_log_redaction_secret_domain::test_the_value_walk_grows_linearly_in_line_length. That is a timing control whose own message says the quadratic control 'grew only 21.0x, so this box ... cannot show' the effect, and the PR does not touch messagefoundry/support/redact.py. A second red on this leg at this head is a finding.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session d1c562bf), 2026-10-30. Enqueuing at 3fc69e0feca02da00f67f5e5da1210de39d240ca. After the rerun, all nine required contexts are green on this head, including both Windows legs from hold item 2. The head adds only a clean merge of main to the covered 53cea6463296f452013622f47badf724435aa138.

@wshallwshall
wshallwshall added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 713e687 Oct 30, 2026
87 of 89 checks passed
@wshallwshall
wshallwshall deleted the b453-wave1 branch October 30, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-red A required check went red. Attribute it before retrying. qa Builder QA record posted; not a merge gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant