Skip to content

backlog: amend #1212 (built, refuted, reverted) and #122 (visibility is not enforcement) - #323

Merged
wshallwshall merged 1 commit into
mainfrom
w3-amend-1212-122
Aug 11, 2026
Merged

backlog: amend #1212 (built, refuted, reverted) and #122 (visibility is not enforcement)#323
wshallwshall merged 1 commit into
mainfrom
w3-amend-1212-122

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Amends #1212 and #122. Ledger only. Both items stay OPEN; neither glyph is touched.

#1212 -- recorded as BUILT, REFUTED, REVERTED

Not as unbuilt. The obvious implementation is now known to be wrong -- it would have deleted PHI on
instances whose operator explicitly opted into keep-forever -- and the next person to pick this up
would otherwise rebuild the same defect.

It also retires a stale premise inside the item's own trap list: an earlier change already inverted
the production gate, so a production-PHI instance with an unset window no longer refuses -- it
auto-bounds and starts. The PHI documentation still described the old refusal, which is exactly how the
stale premise reached the original filing. A security document describing a refusal the engine no
longer performs is the misleading-a-live-engineer case, and that argues for raising the item's
priority rather than lowering it.

#122 -- the owner's ruling post-dates both the demand-gate and the score

The original 2/10 came from conflating visibility with enforcement. Console output, service
rotation, the TLS forwarder and metering all make the log visible; none makes processing stop when
it cannot be written.

Flagged for whoever builds it: a guard that logs a warning and continues does not satisfy this item.

Verification

Ledger re-derived with parse_items: live 248, open 183, archive 236 -- namespace 484 conserved. No
duplicates, no item declaring more than one status. #1212 and #122 both confirmed still OPEN.
Merges cleanly onto main.

…it in)

Both items STAY OPEN; neither status glyph is touched.

#1212 -- the record must not read as merely unbuilt, because the obvious
implementation is now known to be WRONG. It was built, refuted by another
session, verified by execution, and reverted at ed8a09d.

The defect is the inversion of the item's intent. serve's posture gate is
wrapped in 'if not settings.retention.allow_unbounded_phi:', so when the
AUDITED keep-forever opt-out is TRUE the auto-bound block is SKIPPED and
the field keeps its model default. Measured:
RetentionSettings(allow_unbounded_phi=True).messages_days -> 60. The
runner then purges PHI bodies after 60 days on exactly the instances
whose operator consciously chose to keep them forever.

And it was a no-op where aimed: the auto-bound keys on model_fields_set,
so an operator who says nothing still resolves to 30 and always did.

The amendment also retires a STALE PREMISE IN THE ITEM'S OWN TRAP 5. PR
#71 already inverted the prod gate -- a production PHI instance with an
unset window no longer refuses, it auto-bounds at 30 and starts, and
tests/test_cli.py:1619 flipped with it. So the 'less explicit by default'
trade was already made and was never this item's to weigh. PHI.md section
8 still described the old refusal, which is exactly how that stale
premise reached the filing: the doc-vs-code gap recorded under ASVS
14.2.4 ground (5), misleading a second engineer in practice.

Recorded for whoever picks it up: if the 60 is still wanted the value to
change is auto_bound_days in retention_classification.py, NOT the field
default -- and 30 -> 60 LOOSENS the shipped PHI bound rather than
tightening it. That module carries nine windows behind
MIN_PHI_RETENTION_WINDOWS = 9 with a two-way drift test against PHI.md
section 2, so the tuple and the doc must move together.

#122 -- the owner ruled it IN, and that ruling POST-DATES the DEMAND-GATE
and the 2/10 above: 'we never want to process stuff if the processing
cannot be logged.' That coupling IS the count-and-log invariant, so the
gate is discharged and the trigger is moot.

The 2/10 came from conflating VISIBILITY with ENFORCEMENT. stdout, NSSM
rotation, the TLS syslog forwarder and #50's disk metering make the log
visible; none makes processing STOP when it cannot be written. A guard
that logs a warning and continues does not satisfy this item -- that is
the specific thing to check at review.

Work exists on w3-log-write-failure (d26d66a, five commits, pushed and
anchored) and is UNVERIFIED -- the lane died mid-flight on a usage limit.
ADR 0162's number is confirmed sound (real alloc record, main's highest
is 0161), but the index row should be re-checked before landing. The
claim most worth executing is the partial halt: a halt that stops intake
while routed and outbound rows keep draining still violates the invariant.

Gates: 484 items each declaring exactly one status (248 live / 236
archived); ledger_check clean; citation check 272 in scope, same 4
pre-existing advisory warnings. Open 183 on main -- unchanged by this
commit; the 188 I quoted earlier was before the C train (PR #319) landed
its five closures.
@wshallwshall
wshallwshall merged commit 543d58d into main Aug 11, 2026
33 checks passed
@wshallwshall
wshallwshall deleted the w3-amend-1212-122 branch August 11, 2026 12:46
wshallwshall added a commit that referenced this pull request Aug 26, 2026
… clean half, split per owner ruling (#614)

* docs(testing): retire five dead SMTP-posture assertions in the alerting test plan (BACKLOG #1100)

Five cells in chapter 15 assert that the alert/security-notify STARTTLS hop is unauthenticated and
that docs/PHI.md and docs/BACKLOG.md contradict each other about it. BOTH PREMISES WERE ALREADY FALSE
WHEN THE PLAN WAS WRITTEN: #323 closed it on 2026-08-02.

I VERIFIED BOTH PRECONDITIONS AGAINST THE CODE BEFORE TOUCHING A WORD, because this chapter's only P0
"with a real security consequence" was one of the cells, and correcting it wrongly would have silently
closed a live security question:
  alert_sinks.py:385 states "The STARTTLS hop is VERIFIED (#323, layer 3)", and :430-431 pass it --
    `smtp.starttls(context=tls_context)`, commented "context= is REQUIRED (#323): starttls()'s own
    default verifies NOTHING".
  docs/PHI.md ROW 11 (:1015) states the verifying posture in full -- explicit context, chain +
    hostname + strict RFC 5280, TLS 1.2 floor, via tls_policy.build_smtp_tls_context() -- and records
    the pre-#323 state as history.
  tests/test_alert_smtp_tls.py exists, 21 tests.

THE TRAP THAT NEARLY CAUGHT ME IS IN THE FILE I WAS READING. alert_sinks.py:387-388 describes
`ssl._create_unverified_context`, `CERT_NONE`, `check_hostname=False` -- in the PAST TENSE, as the
defect #323 fixed. Read as current, it confirms the plan's claim exactly. The first pass of this work
stopped and reported the preconditions as UNMEASURED rather than guess which tense governed; the
answer came from :385 and :430-431, not from :387.

THE TESTS SURVIVE; ONLY THE PREMISE GOES. ALERT-08, 58 and 67 are still worth building -- pinning the
posture at send time and binding the docs to the code catch a FUTURE divergence, which is the only
thing they were ever able to catch. What changed is that ALERT-67 is now expected to PASS on arrival
rather than "fail today", and S4's manual matrix expects a self-signed and a hostname-mismatched cert
to be REJECTED. Running S4 against the old sentence would have recorded three passes as the expected
result and read a working control as a finding.

THE EXIT CRITERION WAS THE WORST OF THE FIVE: "the three contradicting documents agree with the code",
naming a contradiction that was already resolved. An exit criterion demanding that a resolved
contradiction be resolved CANNOT FAIL, so passing it says nothing while a reader believes a check ran.

AND OQ-3 WAS THE MOST EXPENSIVE: an OPEN P0 blocking four rows, describing a fix as a live exposure.
Its second half has a recorded answer too -- this path did NOT adopt the connector hop gradient; its
deviations are gated by a [security].allow_unverified_alert_smtp_tls acknowledgment switch at the
serve gate. It blocks nothing.

Each dead assertion is QUOTED inside its correction rather than deleted, so a reader can see what the
plan used to claim and why it was wrong -- the same reason #1215's marker paragraph records both of its
inversions. A grep for the old strings therefore still matches, inside the corrections.

SCOPE: this is the clearest cluster only -- five cells in 15-alerting-and-observability.md, whose
premise I verified. The item names NINE sites; the other four are NOT verified and the item stays open
for them. The cited docs/BACKLOG.md:5152 anchor has drifted and is flagged in place as re-derive-by-content.

Verified: 112 passed / 91 skipped across the test-plan, doc-drift, feature-map and phi-logging suites;
no-glyph cp1252 test run against the DIFF rather than the file, because the chapter carries
pre-existing glyphs that are not mine to sweep. My added lines introduce none.

* docs(testing): retire two stale gap rows in the pipeline and connector test plans (BACKLOG #1100)

Both rows were re-measured against the current tree, and both were making claims
the code and docs had already overtaken.

02-pipeline-reliability.md: the Postgres 2-engine crash-and-restart row said
tests/test_shard_recovery_postgres.py "runs nowhere". It runs -- in ci.yml's
postgres-store job -- but that job is gated on
schedule || workflow_dispatch || serverdb == 'true', so it does not run on a PR
that touches no server-DB path. "Runs nowhere" understates the coverage and
"runs in CI" would overstate it; only the gated form supports a decision about
PIPE-01, which is what the row exists to inform.

05-connections-and-transports.md: the "CONNECTIONS.md contradicts the code" row
is fully closed. SFTP-IN, REST-IN and SMTP-OUT are all marked shipped now; DB-IN
agrees with FEATURE-MAP's "Production" rather than contradicting it; SOAP-IN is
receive-only rather than planned; and all six connectors the row called
undocumented have settings headings. FHIR-IN still reads "planned" and that is
correct -- the facade is unshipped -- so the row's inference (the listener is
built, therefore FHIR-IN is built) does not follow: shipping the substrate does
not ship the facade.

Both rows are rewritten in place rather than deleted, so the re-measurement is
auditable and the tables keep their shape. All seven line citations in the
connector row had drifted off their subjects and had to be re-found by content
before any of them could be judged; that is the sixth recorded instance of the
anchor rule this sweep has produced.

* docs(testing): two P0 HA/DR rows say "runs nowhere" about suites that run (BACKLOG #1100)

Both rows asserted that live server-DB suites are invoked by no workflow.
Measured against ci.yml by parsing the YAML rather than grepping it:

Row 80: tests/test_cluster_failover_postgres.py runs at ci.yml:1570, in the
postgres-store job's step "Run the failover + engine-shard recovery suites on
real Postgres". The anchor the row cites as its evidence, ci.yml:614, has
drifted and now lands on a comment about arithmetic.

Row 81: all six DR suites exist and all six are invoked -- the Postgres trio by
postgres-store, the SQL Server trio by sqlserver-store, each in a step named for
exactly those suites.

BOTH STAY P0. The residual risk is real, but it is a GATING risk rather than an
absence: both jobs carry schedule || workflow_dispatch || serverdb == 'true', so
a PR that changes election or DR logic without touching a server-DB path still
ships unverified. "Detected today?" moves from "No" to "Partly -- on the gated
server-DB leg only, never on an ordinary PR", which is the form that supports a
decision. "No" understates the coverage and a bare "yes, it runs" would overstate
it.

Row 81's MEFOR_TEST_* env gating is a SECOND, INDEPENDENT condition and was not
re-measured here. The row now says so, so that correcting one half of its claim
does not read as clearing the whole row.

Found by transferring probe 6's shape rather than by a new search: the identical
"runs nowhere" phrasing about a sibling Postgres suite was already falsified in
02-pipeline-reliability.md, and the two test files turn out to sit on consecutive
lines of the same CI step. A defect class, once named, is worth re-running across
the corpus -- this is the third and fourth instance of it.

* docs(testing): the HTTP listener does authenticate -- correct a P1 row that says it cannot (BACKLOG #1100)

05-connections-and-transports.md row 98 claimed "Inbound HTTP listener has no
application-layer authentication", evidenced by "grep for auth/Authorization/
bearer/hmac in http_listener.py returns 0 hits". EVERY PART OF THAT EVIDENCE IS
NOW FALSE:

  the same grep measures 52 matching lines;
  Http() does not expose "caps + TLS/mTLS only";
  ADR 0023 no longer defers auth -- ADR 0154 (Accepted 2026-07-31) is titled its
  "deferred tail" and delivered it.

Built and measured: intake_auth: Literal["none","api_key","bearer",
"mtls_subject"], enforced by _authorize_head (http_listener.py:618) with a 401
plus WWW-Authenticate, credentials env()-only, rotation via intake_api_key_next,
health probes inside the gate by default, and failed-attempt rate limits at
10/min/peer and 60/min global. The row's "Covered?" cell is equally stale: there
is a dedicated tests/test_inbound_http_intake_auth.py plus four more files, 18
test functions naming the surface.

THE ROW STAYS P1 BECAUSE ITS CONCERN SURVIVES ITS EVIDENCE, IN A NARROWER FORM.
intake_auth defaults to "none" and _authorize_head returns early when unset, so a
site deploying the listener off-loopback without setting it would accept
unauthenticated POSTs. That is now an explicit, documented, tested opt-in rather
than an implicit omission -- a different decision, and the only one still open is
whether "none" is the right default for a PHI intake path.

Written in the conditional per CLAUDE.md section 0: there are no deployments, so
this is what a deploying site would hit, not something happening now.

Found by a reversed discriminator: rows asserting a grep returns ZERO hits go
stale precisely because code gets added. Four such claims exist in the plan; this
is the one that broke, and the other three (ADR coverage-plan hits in 05:95 and
09:122, and 0 occurrences of "validate" in 06:86) were re-measured and HOLD.

* docs(testing): the lagging-ADR-status count is four, not five (BACKLOG #1100)

05-connections-and-transports.md row 105 said five ADR status lines contradict
their code. Re-measured against the ADR files, both halves of each claim:

  0011  "Proposed"                     transports/timer.py, 341 lines      LAGS
  0015  "No code written yet"          transports/soap.py, 844 lines       LAGS
  0016  "No code written yet"          tests/test_x12_rte.py, 625 lines    LAGS
  0022  "Design-only (no code yet)"    test_ack_capture_runner.py, fhir.py LAGS
  0021  "No code yet"                  -> NOW READS "Built and shipped"    FIXED

ADR 0021's status has been corrected since the row was written and now reads
"Accepted (2026-06-19, owner go). Built and shipped (eventlog #16, Lane S)". It
is struck from the count rather than left inflating it.

The row keeps its point and its priority: four is still four, and a wrong ADR
status is still a governance defect. What changes is that a count carried forward
without re-measurement drifts upward relative to reality -- 0021 is itself the
evidence that these get fixed one at a time, so the count has to be re-derived
rather than quoted.

Found by generalising the discriminator that broke row 98 in the same file: that
row cited "ADR 0023 defers auth" when ADR 0154, titled ADR 0023's "deferred
tail", had closed it. A plan row citing an ADR's status is asserting something
about a FILE THAT MOVES INDEPENDENTLY of the plan, which makes it stale by
construction.

* docs(testing): mark the HA catalog-drift row verified-live and fix its one drifted anchor (BACKLOG #1100)

04-high-availability-and-dr.md row 97 was probed for staleness and turned out to
be CORRECT. Every claim re-measured:

  FEATURE-MAP omits ADR 0047/0048/0049/0056/0096   0 grep hits each   TRUE
  BACKLOG #100 ranked Tier cell still reads "P1"   BACKLOG.md:373     TRUE
  BACKLOG #101 ranked Tier cell reads DEMAND-GATE  BACKLOG.md:380     TRUE
  ADR 0096 is Accepted                                                TRUE
  code is in settings.py:2896-2910                 that range is now
                                                   ADR 0014 alert
                                                   rules              DRIFTED

Only the code anchor was wrong. The ADR 0096 surface is `promotable: bool = True`
at settings.py:3026, with its explanation from :3016, so the citation is corrected
to settings.py:3016-3026 and named rather than left as a bare line range.

The row is annotated as re-verified rather than rewritten, because a sweep that
only marks stale rows leaves the next reader unable to tell "checked and live"
from "not yet checked". Both are useful; only one of them was recorded until now.

NOTE FOR WHOEVER OWNS THE LEDGER: the two Tier cells are a real, still-open
defect -- two archived/shipped items carrying pre-shipping scores in the ranked
backlog. They live in docs/BACKLOG.md, which a Builder may not edit under the
owner ruling, so this commit records and locates the defect without touching it.

Found by probing plan rows that cite a BACKLOG item as open. 28 raw hits, of
which nearly all were co-occurrence rather than claims -- "#1"/"#2" were
"synthetic ADT #1", and one trigger was the word "pending" in unrelated prose.
One row carried real, checkable ledger claims, and it was right.

* docs(testing): verify the leaderless-cluster P0 row and re-anchor its drifted citation (BACKLOG #1100)

04-high-availability-and-dr.md row 82 was probed on the assumption that its
"18 members" count had drifted, since counts were the class that broke row 105.
IT HAD NOT. Measured via AST rather than a text window:

  _ALERT_EVENT_TYPES  frozenset, settings.py:2599, EXACTLY 18 members
  only leader-related member is leadership_acquired -- nothing fires on ABSENCE
  alerts.py:206-213 still lands on leadership_lost, "Emits no notification"

So the row is correct on every claim and the P0 gap it describes is real and
open: a cluster that loses leadership entirely pages nobody, because the alert
vocabulary has a member for ACQUIRING leadership and none for having none.

Only the settings anchor was stale (cited :2499-2526, declared at :2599). It is
now cited by NAME plus declaration line rather than as a range, because a range
drawn around a growing frozenset re-drifts the next time a member is added --
which is precisely how this one drifted.

The row is annotated as re-verified rather than left silent, matching the
practice adopted in c4d6030a: a sweep that marks only stale rows cannot tell the
next reader "checked, still true" from "not yet checked".

* docs(testing): close a P0 that describes a failure the engine refuses at startup (BACKLOG #1100)

04-high-availability-and-dr.md row 83 claimed engine shards and [cluster] "collide
on one lease", on the strength of two claims. The load-bearing one is false.

  "no validator relates serve --shard to [cluster].enabled"
      THERE IS ONE, IT FAILS CLOSED, AND IT IS TESTED.
      ADR 0073 makes them mutually exclusive; __main__.py:2649-2659 refuses the
      combination with exit 2 BEFORE the store or app is built; and
      test_shard_recovery_engine.py:321::test_serve_refuses_shard_with_cluster_enabled
      asserts rc == 2. Executed here: 1 passed.

  "_lease_key is not engine-shard-namespaced"
      STILL TRUE, and the anchor drifted (cited cluster.py:414, actual :484).
      But it is MOOT for this failure mode: N engine-shard processes can never
      come up against an enabled [cluster] to contend at all.

The stated blast radius -- "silent full stop for every engine shard but one,
looking healthy on /cluster/status" -- CANNOT OCCUR. A fail-closed startup
refusal is the opposite of silent, so the row is closed rather than narrowed.
That makes it the first row in this sweep whose concern did not survive its
evidence; the previous nine were all narrowings.

What remains is a design note, not a gap: the un-namespaced lease key matters
only if ADR 0073's mutual exclusion is ever lifted, so it is a CONSTRAINT TO
PRESERVE and is recorded as such.

Also noted in the row: this satisfies the HA-03 exit criterion at :399 by its
FIRST alternative (a config-load rejection, not an engine-shard-namespaced lease
key) -- though the assertion lives in test_shard_recovery_engine.py rather than
the tests/test_cluster_shard_interaction.py that the criterion names, so anyone
grepping for that filename would wrongly conclude the criterion is unmet.

* docs(testing): verify the cross-store divergence P0 and sharpen what is actually missing (BACKLOG #1100)

04-high-availability-and-dr.md row 84 was re-measured and is CORRECT on all
three claims -- the last unchecked P0 in this chapter's risk table:

  dr.py:296-301 disclaims a cross-store guarantee   TRUE, and the anchor lands
                                                    exactly on "the engine gives
                                                    no cross-store loss/duplicate
                                                    guarantee -- documented, not
                                                    an engine AC"
  harness/reconcile/ has capture/compare/normalize/report   TRUE, all four
  nothing binds it to the DR release path           TRUE -- 4 unit-test files
                                                    exercise harness.reconcile,
                                                    but no workflow and no
                                                    runbook step invokes it

The two "reconcile" hits under .github/workflows/ are an unrelated ingress probe
and an English verb, not a binding. Worth stating because a grep for the word
alone suggests coverage that does not exist.

AND THE GAP IS SHARPER THAN THE ROW SAID. AOAG-DEPLOYMENT.md:708 DOES instruct
the operator -- "reconcile before you discard; do not rubber-stamp the loss" --
and never names harness/reconcile/. The runbook asks for the activity and points
at no tool, which is worse than saying nothing: the operator is told to do it and
left to invent how, at the exact moment they are recovering from a failover.

That makes the remedy cheap and specific rather than open-ended: have :708 name
the tool. Recorded in the row so whoever picks up this P0 starts from a one-line
fix rather than from "bind the harness to the release path".

Note: correcting the AOAG runbook is not in this claim's scope, and the row now
carries the pointer instead.

* docs(testing): a P0 about unrun suites was wrong, and the real defect is its inverse (BACKLOG #1100)

02-pipeline-reliability.md row 145 claimed six MEFOR_TEST_*-gated pipeline suites
are "named in no workflow step", citing batch_handoff_statements and engine-shard
recovery, and asserting they are "in neither the steps nor the gate regex".

BOTH PARTS ARE FALSE FOR BOTH NAMED EXAMPLES:
  tests/test_adr0075_batch_sqlserver.py     ci.yml:1375, sqlserver-store step
  tests/test_shard_recovery_sqlserver.py    ci.yml:1371, same step
  adr0075 and shard_recovery are both in the gate alternation at ci.yml:993
The cited anchor :424-428 had drifted onto a comment about CI run timings; the
"MUST list every file" comment is at :983-988.

THE RESIDUAL GAP IS REAL AND SHARPER THAN THE ROW STATED. Of 54 MEFOR_TEST_-gated
suites, 19 are named in no workflow step, and every server-DB step invokes
EXPLICIT FILES rather than a directory -- so an unnamed suite runs nowhere on a
real backend. THREE OF THE 19 ARE MATCHED BY THE GATE REGEX:

  test_adr0157_fence_scope             8 tests
  test_sqlserver_sync_handoff_offline  6 tests
  test_adr0071_fusion_wiring

each named ZERO times anywhere in .github/ (positive control: shard_recovery_
sqlserver = 1). A change to any of them PULLS the expensive server-DB legs and
then never executes them -- the leg goes green having not run the suite the gate
fired for.

ci.yml:983-988 states only one direction of the invariant: the alternation must
list every file the steps run. THE INVERSE IS UNSTATED AND VIOLATED THREE TIMES:
every file the alternation lists should be run by some step. That asymmetry is
why this went unnoticed -- the stated half is checked by the comment's own
instruction, and nothing looks at the other half.

Stays P0. The original blast radius (duplicate PHI delivery across engine shards)
is in fact covered, since shard_recovery and adr0075 both run; what remains is
ADR 0157 fence scope with no real-Postgres execution, which is a correctness
mechanism against duplicate delivery in its own right.

* docs(testing): verify the poison-crash P0 and locate exactly where its ceiling is missing (BACKLOG #1100)

02-pipeline-reliability.md row 146 is CORRECT, and re-deriving it from the code
turns "no ceiling exists" into something a fixer can act on.

What is actually there:
  queue table carries an attempts column for EVERY stage    store.py:1319
  a max_attempts ceiling IS enforced                        :5756 mark_failed
                                                            :5816 mark_batch_failed
  reset_stale_inflight, 69 lines                            :5948 -- references
                                                            NEITHER attempts NOR
                                                            dead_letter

So the ceiling is real but sits ONLY on the caught-Python-exception path. A hard
abort -- C-extension segfault, OOM kill -- calls neither mark_failed nor
mark_batch_failed, and recovery runs reset_stale_inflight instead, which re-pends
the head without counting anything. The lane re-runs and the process dies again,
exactly as the row says.

THE FIX HAS A LOCATION: the increment must happen at CLAIM time or inside
reset_stale_inflight, NOT on the failure path -- because the failure path is
precisely what a hard abort skips. A ceiling added to mark_failed would pass
review and change nothing about this failure mode.

Also recorded: G6 is an OUTBOX-stage mechanism throughout (every reference reads
OutboxItem.attempts), which is why it does not cover the split ingress/routed
path. Worth stating because "there is a poison ceiling" is true and misleading
in the same breath.

Verified by reading the whole function via AST rather than a byte window -- the
same instrument that produced a wrong member count earlier tonight.

* docs(testing): narrow the leak-gate floor P0 to the one claim that survives (BACKLOG #1100)

16-security-phi-and-supply-chain.md row 201 said nothing asserts that the
MEFOR_MIN_DETECTORS floor matches the real list, that the spec parses, or that a
partially-mangled secret is caught. TWO OF THOSE THREE ARE NOW FALSE.

test_scan_tokens_source.py carries 56 tests. The spec IS parse-asserted
(test_min_spec_parsing_rejects_nonsense, test_unrecognised_require_value_refuses)
and a partially-mangled secret IS covered (test_present_but_unusable_token_source_
fails_closed, parametrized over `mangled`, whose docstring records that a mangled
secret once yielded ZERO detectors). Ran the cited tests: 7 passed.

Materially, the ESTATE half no longer depends on the token list at all. BACKLOG
#321's structural estate-identifier shape detector fires with NO token source
present, and the allowlist validator refuses an entry broad enough to disable it.

DEPENDENCY STATED IN THE ROW ITSELF: that detector is commit c3959449, which is on
this builder branch and NOT on main. If the plan edit lands without it, the cell
is wrong. A row whose truth depends on an unlanded sibling commit has to say so,
or it becomes a false claim the moment the two are separated -- and they are
separable, because I reported these items as individually landable.

THE SURVIVING CLAIM IS THE INTERESTING ONE AND IT STAYS P0. Every floor test uses
a SYNTHETIC floor (names=2 + estate=2 + site_prefixes=1), so nothing asserts the
real names=7,estate=13,site_prefixes=1. That cannot be fixed in pytest:
scan-tokens.local.txt is gitignored and the real list arrives only via
MEFOR_FORBIDDEN_TOKENS, so no checkout can hold it. Any real fix must compare the
floor against the list INSIDE THE GATE RUN. Recorded so the next attempt does not
start by writing a unit test that cannot see the data.

Anchor corrected: security.yml:403 -> :674 (commented at :655).

* docs(testing): close a security P0 whose guard already exists (BACKLOG #1100)

16-security-phi-and-supply-chain.md row 200 said the continue-on-error guard
pattern "was never extended to security.yml". IT WAS. tests/test_security_posture.py
is that guard -- 12 tests, all passing, last touched 72e67095 on 2026-08-10 under
BACKLOG #1079.

It covers BOTH vectors the row names:
  test_required_jobs_carry_no_continue_on_error
  test_required_jobs_declare_no_skippable_job_level_if
       -- "a job-level `if:` is the other way a required context silently never
          reports", allowlisted per job

_BLOCKING_SECURITY_JOBS is exactly the seven jobs this row lists, and each is
asserted present in .github/required-contexts.txt, so "blocking" is a checked
claim rather than a label. The module also runs the REVERSE direction (sbom and
trivy must KEEP continue-on-error, catching a silent promotion), and it is not
vacuous by construction: test_every_security_job_is_classified fails when a new
job arrives in security.yml unclassified.

THE REASON THIS ROW SURVIVED IS WORTH RECORDING, BECAUSE IT WILL RECUR. The
guard's own module docstring restates this row's claim VERBATIM -- "nothing
guarded it: the three tests in this repo that read a workflow's continue-on-error
cover quality-advisory.yml and freethread-smoke.yml" -- as THE HISTORY IT WAS
WRITTEN TO CLOSE. Anyone who greps for the claim finds it, in the very file that
refutes it, and comes away confirmed. A test that documents the defect it fixes
reads exactly like evidence the defect is open.

Second closure of this sweep, after row 83. Both were P0s asserting a gap that
the engine or its CI had already closed, and in both cases the refutation was one
file away from the row's own citation.

* docs(testing): re-verify the security-wave coverage P0 with a positive control (BACKLOG #1100)

16-security-phi-and-supply-chain.md row 199 is CORRECT and still open.
FEATURE-COVERAGE-PLAN.md returns zero hits for all 17 of ADR 0135 and 0138-0153,
and its status blocks still date to 2026-07-13.

Re-measured WITH A POSITIVE CONTROL, which is the part worth keeping: ADRs
0010/0023/0030/0066 DO resolve in that file. Without that, "zero hits" is
indistinguishable from a grep that matches nothing for a reason of its own -- the
exact failure that made an earlier probe in this sweep report 0 for eight ADRs it
had never actually tested.

Zero-hits claims now stand 3 verified-true (05:95, 09:122, this row) to 1 broken
(05:98, the HTTP listener auth row). Worth recording as a base rate: the class is
productive precisely BECAUSE it usually holds -- when one breaks, it breaks
loudly and in the direction of understated coverage.

The row is annotated rather than changed. It is also the row whose staleness would
be hardest to notice from inside the document, because the instrument it indicts
is the same one a reader reaches for to check it.

* docs(testing): the suspected Kerberos SPN defect is CONFIRMED, and worse than suspected (BACKLOG #1100)

10-auth-rbac-and-active-directory.md row 91 carried this as a SUSPECTED live
defect. It is confirmed, against pyspnego's own signature rather than by
inference:

    spnego.server(hostname: str = 'unspecified', service: str = 'host', ...)
      hostname: The principal part of the SPN. Required to build the SPN.
      service:  The service part of the SPN. Required to build the SPN.

The library BUILDS the SPN from the two fields. Both acceptor sites pass the whole
SPN into service= -- auth/ldap.py:315 and :375 -- and settings.py:1905 documents
kerberos_spn as "HTTP/host.example.com".

WORSE THAN THE ROW ASSUMED: hostname is never passed at EITHER site, so it takes
its default. The acceptor principal is HTTP/host.example.com/unspecified, not
.../<hostname>. The row inferred a hostname would be supplied from somewhere; none
is.

Scope stated honestly per CLAUDE.md section 0: kerberos_enabled defaults to False
and is marked experimental (settings.py:1904), so this WOULD bite the first site
that turns Kerberos SSO on. It is not affecting anything now, and the conditional
is the accurate tense -- but the row's blast radius (a working-looking feature
that always fails, every failure an audited generic reject) is correct for that
site.

Three anchors re-pointed: :300 -> :315, :360 -> :375, :1846 -> :1905.

Not fixing the code here: that is auth-surface engine work outside this claim, and
the row now carries the exact evidence -- both call sites, the signature, and the
missing hostname= -- so the fix does not need re-derivation.

* docs(testing): confirm the AD account-state P0 and re-point all four drifted anchors (BACKLOG #1100)

10-auth-rbac-and-active-directory.md row 93 is CORRECT on every claim. Only its
citations had rotted, and they had rotted in a way that reads as confirmation:

  cited auth/ldap.py:182-187 as the ACCOUNTDISABLE reject
        -> that range now lands on the ATTRIBUTE LIST, which is the other thing
           this same row cites. A reader checking the anchor sees plausible code
           and moves on.
  actual reject          auth/ldap.py:197-201   (uac & 0x2)
  actual attribute list  auth/ldap.py:185-192   (requests userAccountControl)
  _find_user             auth/ldap.py:174
  resolve_principal      auth/ldap.py:277
  _probe_principal       service.py:1244        (cited :1207), calls it at :1253

Verified by reading _find_user and resolve_principal whole via AST rather than by
grepping a window: neither contains accountExpires, lockoutTime or UF_LOCKOUT.

So an AD account that is EXPIRED or LOCKED but not explicitly DISABLED is accepted
by all three password-free paths -- Kerberos SSO, OIDC, and the ADR-0079
reconciler, which would probe it PRESENT every pass. Offboarding-by-expiry, the
common HR pattern, would not propagate. service.py:959 states the shared path in
as many words: "Roles come from resolve_principal -- the same password-free LDAP
lookup Kerberos uses".

Not fixing it: auth-surface engine work outside this claim. The row now carries
the exact reject site, the exact attribute list, and the three entry points, so
the fix does not need re-deriving.

* docs(testing): grade the ADR 0142 row only as far as this repository can see (BACKLOG #1100)

10-auth-rbac-and-active-directory.md row 92 makes three claims. Two are confirmed
from here; the third cannot be, and saying so is the point of this commit.

CONFIRMED
  the ADR status line still reads exactly "Proposed -- code COMPLETE, awaiting
  lab validation", and its inline note adds "flips to Accepted only when runbook
  cells L6a, L9 and L18 report"
  docs/testing/ holds 26 files, all plan documents, with no AD-lab run record

NOT CHECKABLE FROM THIS REPOSITORY
  whether L6a / L9 / L18 have since run. The runbook is
  docs/security/AD-FEDERATION-LAB-RUNBOOK.md, and docs/security/ DOES NOT EXIST
  in this checkout -- it is the private companion repo. My brief also assigns
  that half to the ASVS Tracker, so the constraint and the practical limit
  coincide.

The row now says UNKNOWN for that clause rather than leaving it reading as
CONFIRMED OPEN. The distinction matters here more than usual: L18 is described as
the proof of a control that a review once found to be a live privilege-escalation
route, so "we have not verified this" and "this is still broken" are very
different statements to leave in a security test plan. The ADR status is the
honest public proxy -- it has not flipped -- and the row now says that instead of
implying more.

This is the first row in the sweep whose evidence lives outside the repository. A
verification pass has to be able to say "I cannot see this from here" without
either guessing or going quiet.

* docs(testing): confirm the mock-seam P0, and correct the one clause a reader could refute it with (BACKLOG #1100)

10-auth-rbac-and-active-directory.md row 90 is substantively CORRECT. All six
acceptor sites are still pragma: no cover, annotated "needs real AD" and
"requires a domain-joined server + keytab":

  ldap3 LDAPException arms   :267  :289          (cited :252, :274)
  SPNEGO acceptor lines      :313 :321 :373 :378 (cited :298, :306, :358, :363)

Zero workflows mention ldap, and there is no OpenLDAP / Samba / 389ds service
container anywhere.

ONE CLAUSE IS FALSE AS WRITTEN: "no self-hosted runner ... exists in
.github/workflows/". One does -- selfhosted-win2025-sql.yml :: sqlserver-real,
"SQL Server 2025 suites (real hardware)". It mentions no ldap, kerberos, spnego,
ad_domain or directory, so the row's INTENT holds exactly; its literal claim does
not.

That is worth fixing in both directions. Defensively: as written, a reader can
refute a P0 by pointing at one file, and a row that can be dismissed on a
technicality does not survive the meeting it matters in. Constructively: A
SELF-HOSTED WINDOWS RUNNER WITH A LABEL SCHEME ALREADY EXISTS AND IS PROVEN, so
the remedy here is "point an existing pattern at a directory", not "stand up
runner infrastructure". The row previously implied the expensive half was
missing when it is already built.

This is the sixth row in the sweep that understated something -- coverage, its own
gap, or as here, how close the fix already is.

* docs(testing): confirm the PHI retention-gate bypass and re-point it at the moved gate (BACKLOG #1100)

03-store-and-data-lifecycle.md R3 is CONFIRMED. The gate has MOVED since the row
was written, which is why its anchor no longer showed the defect:

  cited  __main__.py:1968-1975 "builds unbounded_windows"
  actual config/retention_classification.py:186 defines it (20 lines)
         __main__.py:2240 is its ONLY caller: _unbounded_windows(settings)

Read whole via AST, unbounded_windows contains no registry / connection /
per_connection / overrides / inbound token. It sees global settings and nothing
else.

The override that defeats it is documented in the code that creates it,
wiring.py:3125-3126: "None = inherit the global [retention].messages_days window;
0 = keep this connection's bodies forever; >0 = days" -- and pipeline/retention.py:150
honours it at purge time.

BOTH HALVES ARE INDIVIDUALLY CORRECT AND JOINTLY PERMISSIVE. A deploying PHI
instance with a global 30-day window would pass the startup gate while every
inbound set to messages_days=0 retains bodies forever, with no warning, no audit
entry and no test. Written conditionally per CLAUDE.md section 0: there are no
deployments, so nothing retains PHI today; it is wrong in the shipped code.

This is the most consequential of the three code defects this sweep has confirmed,
because the control is LABELLED fail-closed and audited (ASVS 14.2.4) -- its
existence is exactly what a reviewer would rely on instead of checking. That is
the compensating-control-on-a-false-premise shape in its purest form.

Not fixed: store/config surface, outside this claim. The row names the fix -- hand
the gate the registry's resolved per-connection windows rather than settings alone.

* docs(testing): narrow the at-rest AAD row from "barely exercised" to what is actually missing (BACKLOG #1100)

03-store-and-data-lifecycle.md R2's core claim is CONFIRMED: no workflow sets
MEFOR_TEST_FORCE_AAD_BIND -- 0 occurrences across .github/workflows/, against a
positive control of 14 for MEFOR_TEST_SQLSERVER. aad_bind still defaults True
(settings.py:388) and make_cipher's library default is still write_v2=False
(crypto.py:812).

BUT "THE SHIPPED WRITER IS BARELY EXERCISED" NOW OVERSTATES IT, and the flag's own
docstring (tests/conftest.py:133-138) is the authority:

    "The flag is OFF by default and stays meaningful even though [store].aad_bind
     now DEFAULTS TRUE (ADR 0148 GIVEN 1). ... The settings default governs what
     open_store builds; this flag governs every cipher in the process, which is
     what makes the sweep exhaustive rather than merely representative."

The flag is a SWEEP AMPLIFIER, not a gate: unset, the suites still run and
open_store still builds the mfenc:v2 writer because the setting defaults True. So
the shipped writer IS exercised. What never runs is the process-wide forcing that
also catches ciphers constructed with an EXPLICIT write_v2=False.

The parenthetical was wrong too: EIGHT test files reference the flag, not
conftest.py alone.

STAYS P0. The residual risk is exactly as stated -- a half-threaded cell_aad on
purge re-encrypt, document strip write-back, attachment re-seal or restore
surfaces only under the forced sweep, and that sweep runs nowhere. Narrowing the
headline does not shrink the gap; it stops the row being refutable by anyone who
checks whether the writer runs at all.

* fix(testing): repair the R2 row I split into six columns in eb32618f (BACKLOG #1100)

eb32618f introduced a stray `|` in 03-store-and-data-lifecycle.md row 107, turning
a 5-column row into 6 and breaking the risk table's alignment from that row on.
Replaced the stray boundary with a full stop; header and both neighbouring rows
now agree at 5.

I RAN THE COLUMN CHECK AND COMMITTED ANYWAY. The check printed "row107: 6" against
a header of 5, in the same command that staged and committed. Running a
verification and GATING on it are different things, and batching them into one
command guaranteed the output arrived after the decision it was supposed to
inform.

That is the same instrument-vs-question failure this whole sweep keeps finding,
in its most avoidable form: the measurement was correct, present, and ignored.
Every other near-miss tonight needed a subtle reason -- a truncated window, a
pipe swallowing an exit code, a docstring quoting the claim it refutes. This one
needed only that I put the check and the commit in the same breath.

Splitting them from here: verify, read the result, then stage.

* fix(testing): restore the G4 row's missing column, and sweep all 172 tables (BACKLOG #1100)

After breaking a row in eb32618f I checked whether I had done it elsewhere. I had.

15-alerting-and-observability.md:138 -- my FIRST #1100 commit tonight, 1e926ec9 --
merged the Risk and Failure-mode cells into one, leaving a 4-column row under a
5-column header (Risk | Failure mode | Blast radius | Detected today? | Priority).
It has been misaligned for the whole session. Split at the natural boundary: the
verdict sentence stays in Risk, the send_plain_email evidence moves to Failure
mode.

THE POINT IS NOT THE TWO ROWS, IT IS THAT I ONLY EVER CHECKED THE ROW IN FRONT OF
ME. The per-edit column check I adopted mid-session cannot see damage done before
I adopted it, and never looked at the other 171 tables. A check scoped to the
thing you are currently touching is blind to your own history with the file.

Swept all 20 chapters: 172 tables checked, 0 misaligned rows remaining.

Process corrected as well as the rows: the integrity check now runs as its own
step and I read the result BEFORE staging. In eb32618f the check and the commit
were one command, so the output that would have stopped me arrived after the
decision it was meant to inform.

* docs(testing): confirm the per-connection purge coverage gap, and show it is the DOUBLE kind (BACKLOG #1100)

03-store-and-data-lifecycle.md R1 holds on every claim, measured with a positive
control:

  connection_cutoffs in test_postgres_store.py     0
  connection_cutoffs in test_sqlserver_store.py    0
  control: it appears in exactly 2 files repo-wide, so the zeros are real
  serverdb path-gate regex matches per_connection_retention   0 times
  regex is at ci.yml:993, not the cited :434

TWO ADDITIONS. The row named only test_per_connection_retention.py; the second
file carrying connection_cutoffs is test_embedded_document_pruning.py, and it is
in the same position. And BOTH are in the 19 MEFOR_TEST_-gated suites that
02-pipeline-reliability.md:145 was corrected to describe -- so the two rows are
looking at one CI defect from opposite ends.

THE SHAPES ARE NOT EQUIVALENT, AND THIS ONE IS WORSE. The three suites in that
other row are MATCHED BY THE GATE BUT RUN BY NO STEP: the expensive server-DB leg
fires and then does not test them, which is waste plus false assurance. These two
are MATCHED BY NOTHING AND NAMED BY NOTHING: editing the per-connection purge
predicate fires no server-DB leg at all, and no test that mentions
connection_cutoffs runs anywhere.

For a predicate that decides WHICH FEED'S PHI BODIES GET DELETED -- irreversible in
one direction, unbounded retention in the other -- "no signal at all" is the
weaker of two weak positions. Recorded in the row so the two CI findings can be
fixed as one change to the gate regex plus the step lists.

* docs(testing): confirm the API wire-contract P0, and flag two tokens that look like counter-evidence (BACKLOG #1100)

09-engine-api.md row 113 is CORRECT on its load-bearing half.
tests/test_webconsole_seam_snapshot.py is a digest over rendered-DTO FIELD NAMES
and contains no status_code, methods, __annotations__, type_ or optional
reference at all. Types, optionality, path, method and status code are unpinned,
exactly as the row says.

I LEFT THE COUNT ALONE ON PURPOSE. Re-counted by AST walk over all of api/: 117
BaseModel/RootModel classes (models.py 84, auth_models.py 32, phi_gate.py 1)
against the "~121" written here. That is inside the row's own tilde, and
re-pinning it to 117 would replace one figure that will drift with another. The
hedge is doing its job; round 4's lesson was that a HARD count rots, not that
every number must be restated.

RECORDED FOR THE NEXT CHECKER: two tokens in that test file look like
counter-evidence and are not. `annotation` is `from __future__ import
annotations` at :14, and `required` is the English word at :76. A grep for either
returns a hit in the file that would otherwise settle the question, and suggests
types are pinned when nothing of the sort is happening. I spent a step on exactly
that detour.

That is the same shape as 16-security row 200, where the guard's docstring quoted
the claim it refutes: THE FILE THAT ANSWERS THE QUESTION ALSO CONTAINS THE STRING
THAT ANSWERS IT WRONGLY.

My own first count was wrong too -- 89, from a base filter matching any name
containing "Model" rather than BaseModel/RootModel specifically. Re-measured
before reporting.

* docs(testing): confirm no API route runs on a server DB, with both populations measured (BACKLOG #1100)

09-engine-api.md row 114 is CORRECT, and measuring it properly makes it much
harder to wave away than "verified by cross-grep" did:

  tests setting MEFOR_TEST_SQLSERVER / MEFOR_TEST_POSTGRES   46
  tests constructing create_app                              63
  intersection                                                0

BOTH POPULATIONS ARE LARGE, which is the part that matters. A bare "zero hits"
cannot distinguish a real disjointness from an empty set, a typo'd token, or a
grep that never matched anything -- and this sweep has already produced one probe
that reported 0 for eight ADRs it had never tested. 46 and 63 with no overlap is
a structural fact about the test estate, not an absence of evidence.

The two halves do not meet: everything that exercises a route runs on SQLite, and
everything that runs on a real server backend addresses the store directly. So
every backend divergence the row lists -- list_messages + count_messages
composition, search truncation, record_audit against the ADR 0150 client column
on NVARCHAR(256), preset listing, dead-letter paging, audit filters -- would first
appear at a deploying site rather than in CI.

Chapter 09's P0 risk set is now complete (113 confirmed, 114 confirmed), making
six chapters: 02, 03, 04, 09, 10, 16.

* docs(testing): a control exists for the false-promote P0, and it compares the wrong two things (BACKLOG #1100)

08-publishing-and-promotion.md row 109 said "Nothing recomputes or compares a
fingerprint". THAT IS FALSE. ConfigProvenance (api/app.py:4570-4590) reads
engine.loaded_config_fingerprint, RECOMPUTES config_fingerprint_detail(target)
off the loop, COMPARES them, and returns a drift flag. ADR 0041 D1 additionally
writes a fingerprint-bearing config_reload audit row on every reload (:554-581).

BUT IT COMPARES LOADED-VS-DISK-NOW, AND THE RISK IS DISK-VS-THE-COMMIT-CI-WAS-
MEANT-TO-DELIVER. In the exact scenario this row describes -- CI/CD never
delivered the commit -- the disk still equals what was loaded, so drift is False
and provenance reports clean.

SO THE CONCERN SURVIVES ITS EVIDENCE ENTIRELY, AND IS NOW HARDER TO SEE THAN
BEFORE. A reviewer who greps for fingerprint handling finds a recompute, a
comparison and a drift flag, and reasonably concludes the risk is covered. The
control is real, well-built, and answers a different question.

That is the compensating-control-on-a-false-premise shape for the fourth time in
this sweep, and the most dangerous instance: the other three rested on evidence
that had rotted, while this one rests on a control that genuinely exists.

Still true, and re-anchored: ReloadResult (api/models.py:371, cited :351-360)
carries no fingerprint, so the promoting caller never receives one; and there is
no `messagefoundry fingerprint` CLI -- the subcommands are graph, serve, validate.

THE FIX IS SMALLER THAN THE ROW IMPLIED. The fingerprint is already computed on
every reload. It needs surfacing in ReloadResult and comparing against an EXPECTED
value, rather than building fingerprinting from nothing.

* docs(testing): confirm the fingerprint's environments/ blind spot against ADR 0041's SHALL (BACKLOG #1100)

08-publishing-and-promotion.md row 108 is CONFIRMED, measured on this checkout.

fingerprint.py:44 lists environments/*.toml in _FINGERPRINT_GLOBS, globbed at :59
as base.glob(pattern) where base is the directory passed in -- last_reload_dir /
config_dir, the CONFIG DIR. Repo-root environments/ holds 2 .toml files;
samples/config/environments/ does not exist. Every documented layout (ADR 0017,
ADR 0050) keeps environments/ as a SIBLING of --config, so the declared glob
resolves to nothing.

WHAT THOSE FILES HOLD IS WHY THIS MATTERS: acme_adt_host, acme_adt_port,
demo_oru_host, demo_oru_port, fhir_base_url, payer_rte_host, payer_rte_port --
14 keys each. Repointing a peer host changes WHERE PHI IS SENT and produces an
identical fingerprint, no drift flag, and an audit row indistinguishable from a
clean reload.

AND ADR 0041 STATES THE OPPOSITE AS A REQUIREMENT, NOT A DESCRIPTION:
  :100 "It spans connections.toml AND environments/ so a transport/env-value
       redirect cannot change [the graph without changing the fingerprint]"
  :153 "... or environments/*.toml -- THE SYSTEM SHALL produce a different
       fingerprint."

So this is not a doc gap. SHIPPED CODE DOES NOT MEET A SHALL ITS OWN ADR RECORDS,
and the attestation built to detect a redirect is blind to the file that performs
one. Conditional per section 0: no deployments, so nothing is mis-attested today.

ADR 0041:238 separately leaves "Fingerprint env-value scope" open -- that question
is about hashing RESOLVED values and does not cover this. This is the declared
scope failing to resolve at all, which is a different and simpler failure.

Not fixed: config surface, outside this claim. The fix is to anchor the
environments/ glob at the project root rather than the config dir.

* docs(testing): confirm the dual-control promote renders as success (BACKLOG #1100)

08-publishing-and-promotion.md row 110 is CONFIRMED on all four claims, and BOTH
ANCHORS STILL LAND -- rare in this sweep.

  engineClient.ts:94-96   if (status >= 200 && status < 300) {
                            resolve((text ? JSON.parse(text) : {}) as T)
  promote.ts:191-195      prints "promoted to <target> -- live graph:
                          ${result.inbound} inbound, ..." with NO status check
  41 IDE test files exist and NOT ONE drives promote.ts
                          (promote-target.test.ts tests promoteTarget.ts, a
                          different module)

STRONGER THAN THE ROW STATES: PendingApproval appears nowhere in ide/, and there
is no 202 handling anywhere in ide/src. This is not a missed branch -- the client
does not model the pending-approval response as a concept. So the fix is one
status check at the postJson call site, not new machinery.

WORTH RECORDING ABOUT THE ANCHORS. Nearly every Python row in this sweep had
drifted citations; both TypeScript anchors here are exact. ANCHOR DRIFT TRACKS
CHURN, and the IDE surface has moved far less than the engine. That is a useful
prior for whoever sweeps next: weight re-derivation toward the fastest-moving
code, and treat a stable surface's citations as more trustworthy -- but still not
as evidence.

* docs(testing): confirm the restart-publish attribution gap, re-pointing both drifted anchors (BACKLOG #1100)

08-publishing-and-promotion.md row 107 is CONFIRMED on substance. Both of its
anchors had drifted, one of them onto text that looks nothing like the claim:

  cited api/app.py:5455-5462 as the start-path load
        -> that range is now a function signature's KEYWORD PARAMETERS
           (priority_default, retention_settings, ...), ~270 lines away
  actual api/app.py:5725  loaded = load_config(config_dir)
         api/app.py:5730  engine.add_registry(loaded)

  cited engine.py:1488-1500 as "only reload sets loaded_config_fingerprint"
  actual engine.py:450   initialised None
         engine.py:1610 / :1615  BOTH inside reload() (def :1479)
        -- right method, wrong lines

VERIFIED FROM THE OTHER SIDE TOO, which is what makes it conclusive rather than
suggestive: Engine.start() (engine.py:875, 301 lines) mentions NONE of
loaded_config_fingerprint, config_fingerprint, add_registry or load_config. The
fingerprint-bearing config_reload audit row is written only from the reload path
(app.py:554-573, gate action registered :547).

So the primary CI/CD path -- copy files, restart the service -- leaves the engine
unattested, and GET /config/provenance answers loaded=false. Its own comment shows
the conflation: "no graph loaded yet, or fingerprint unavailable". Two very
different states, one indistinguishable answer.

PROCESS NOTE: my first edit dropped the cell boundary between Risk and Failure
mode (the old text had two pipes, my replacement had one) -- the same error I
committed twice earlier tonight. THE INTEGRITY GATE CAUGHT IT BEFORE STAGING this
time, because it now runs as its own step and I read it before deciding. Fixed
before the commit rather than after.

* docs(testing): confirm the split-config row, and record that three P0s are one gap (BACKLOG #1100)

08-publishing-and-promotion.md row 111 CONFIRMED. ClusterStatus (api/models.py:786,
cited :737-748) has exactly node_id, clustered, is_leader, role, config_version --
no fingerprint; ClusterNode (:800) adds none either. The convergence anchor lands
exactly, and the module states the assumption in its own words:
config_convergence.py:16-18, "The version token coordinates when nodes reload;
each node reloads its OWN config dir. Skewed config dirs would diverge."

THE FINDING WORTH MORE THAN THE ROW: 107, 109 AND 111 ARE ONE GAP SEEN THREE
TIMES. ADR 0041 D1 computes a content fingerprint on every reload, and it is
surfaced in NONE of the three places a consumer could compare it -- not on the
restart path (107 never sets it), not in ReloadResult (109), not in ClusterStatus
(111). THE VALUE IS ALREADY COMPUTED; THE GAP IS ENTIRELY IN EXPOSURE.

That matters because each row scopes as its own piece of work. Read separately
they suggest three investigations into attestation. Read together they are one
change -- surface the existing fingerprint on those responses and compare it
against an EXPECTED value at the promote site. ConfigProvenance already proves the
recompute-and-compare machinery works; it just compares the wrong two things.

Recorded in all three rows and as handoff 6h, so whichever is picked up first
finds the other two rather than solving a third of the problem well.

* docs(testing): correct a false claim I committed in f21d0e33 -- the CLI has 37 subcommands, not 3 (BACKLOG #1100)

While checking a different row I read FEATURE-COVERAGE-PLAN.md:1420, "all 28
argparse subcommands", against my own note in row 109 that the subcommands are
"graph, serve, validate". Both cannot be right.

MINE WAS WRONG. An AST walk over every add_parser call finds 38 calls, 37 distinct
(`import` appears twice): adr-analyze, ai-policy, alert, audit-anchor,
audit-verify, backup, cert, check, codeset, connection, corepoint, dryrun,
gen-key, generate, graph, hl7schema, hl7structures, impact, import, init,
inventory, lens, parse, protect-key, rekey-audit, restore-verify, rewrite,
rotate-key, schema, security, self-signed, serve, service, supervise,
support-bundle, validate, verify.

My original grep, `add_parser("[a-z-]*"`, matched only single-line call sites with
that exact shape -- 3 of 38.

THE CONCLUSION WAS UNAFFECTED: `fingerprint` is not among them either way, so row
109's substantive point stands. THE EVIDENCE WAS NOT, AND THAT IS PRECISELY THE
DEFECT THIS SWEEP EXISTS TO FIX. I have spent the night correcting rows whose
conclusions were right and whose supporting citations had rotted, and I committed
one of my own in the same form: a true claim propped on a false enumeration that
reads as thorough because it names specific things.

The row now cites the AST measurement and records what the earlier revision said
and why it was wrong, rather than quietly replacing it -- a silent fix would leave
the next reader unable to tell whether the number was ever checked.

Also noted: FCP:1420's "28" does not match 37 either. I am not correcting that
here; it is outside this row and this claim, and the discrepancy is now visible in
the commit record for whoever owns that plan.

* docs(testing): audit my own committed counts, and correct the second false one (BACKLOG #1100)

After finding that I had committed a false subcommand enumeration (8e0f281b), I
audited every count I asserted in this sweep by AST instead of grep.

CORRECT, confirmed: 56 tests in test_scan_tokens_source.py; 12 in
test_security_posture.py; 6 in test_webconsole_seam_snapshot.py. No nested tests
in any of them, so the ^def test_ pattern happened to be accurate.

WRONG: row 98's "18 test functions naming the surface". Measured across the five
cited files: 76 test functions total, of which 6 have "intake" in the name, and
the dedicated test_inbound_http_intake_auth.py alone holds 22. NOTHING IS 18. The
figure came from `grep -rh "def test_.*intake" tests/ | wc -l` -- a count over ALL
of tests/, which I then attributed to five specific files.

BOTH OF MY FALSE ENUMERATIONS TONIGHT HAVE THE SAME TWO CAUSES, and naming them is
worth more than either fix:
  1. COUNTING LINES AND CALLING THEM THINGS. grep counts matching lines; a
     multi-line call site, a class-nested def or a second match on one line all
     break the equivalence silently.
  2. CONFLATING SEARCH SCOPE WITH CITED SCOPE. I searched tests/ and reported the
     number as a property of five named files.
Neither produces an error. Both produce a specific, confident, wrong number that
reads as diligence BECAUSE it is specific.

The substance is unaffected and slightly strengthened -- 22 dedicated tests is a
better answer to "No test states the accepted control set" than 18 was. As with
the subcommand fix, the row records what the earlier revision said and why it was
wrong rather than silently replacing it.

A NOTE ON THE AUDIT ITSELF: it also flagged test_ech_record_premise as "claimed
10, found 8". That one is MY AUDIT being wrong -- 8 functions produce 10 cases via
parametrize, and I had only ever quoted pytest's case count in conversation, never
in a document. A self-audit needs the same instrument-vs-question discipline as
everything else, or it manufactures its own findings.

* docs(testing): confirm the composite-pipeline row, and name why it has stayed open (BACKLOG #1100)

08-publishing-and-promotion.md row 112 is CORRECT. All six FEATURE-COVERAGE-PLAN
citations LAND -- unusual in this sweep -- and every one is an EXPLICIT exclusion
rather than the word "IDE" merely appearing on the line:

  :946   "Excludes the VS Code IDE (owner's lane)"
  :1216  "OUT of scope: the VS Code IDE extension"
  :1379  "... and the VS Code IDE extension are out of scope"
  :1420  "Excludes the VS Code IDE extension (owner's parallel work)"
  :1471  "... the VS Code IDE Steps view ... are out of scope"
  :1521  "Excludes the VS Code IDE extension (owner's parallel work)"

I checked the clause and not just the token because this sweep has produced four
separate cases where a term appeared on the right line for the wrong reason.

THE ATTRIBUTION IS THE PART WORTH ADDING. Four of the six say "owner's lane" or
"owner's parallel work". These are DELIBERATE scoping decisions, not oversights.
So the composite pipeline -- author, check, non-prod, traffic, identical artifact
to prod, per-environment substitution, rollback -- is unowned BY CONSTRUCTION:
each half sits inside a scope that explicitly disclaims the other, and the seam
between them belongs to neither.

That reframes the remedy. The row reads as "someone should write the assembly
test"; the accurate version is "this requires crossing an ownership boundary that
six separate scope statements were written to establish". Nobody is going to close
it by accident, and no amount of test-writing inside either lane will reach it.

Chapter 08's P0 risk set is now complete (107, 108, 109, 110, 111, 112), making
seven chapters: 02, 03, 04, 08, 09, 10, 16.

* docs(testing): the security warning IS tested, and the real config gap is mis-SECTIONING (BACKLOG #1100)

07-config-wiring-and-cli.md row 80. One clause is false, and correcting it makes
the surviving gap sharper rather than smaller.

CONFIRMED: extra="ignore" holds via the _Section base (settings.py:173) and
ServiceSettings (:3811, cited :3623). The only extra="forbid" models are
EscalationTier and AlertRule -- nested rule objects, not sections. I checked that
specifically because two forbid declarations initially looked like they refuted
"each section"; they do not. test_settings.py:118 pins the silence as intended and
its anchor lands.

FALSE: "that warning itself is untested". tests/test_security_config.py covers it
with a positive AND a negative control -- test_unknown_security_key_warns_and_is_
ignored (:386) and test_known_security_keys_warn_about_nothing (:401), the latter
asserting "unrecognized key" is ABSENT for valid keys. Ran both: 2 passed. The
warning lives at :4060-4074; the cited :3880 is now _cluster_requires_server_db.

THE REAL GAP IS THE ONE THIS ROW'S OWN FIRST EXAMPLE FALLS INTO. The warning diffs
set(raw) - set(SecuritySettings.model_fields), so it catches an unknown KEY inside
a PRESENT [security] section. A misspelled SECTION HEADER -- the row's own
[secrity] -- is dropped by ServiceSettings' extra="ignore" and never reaches the
check. It warns nothing.

So MIS-SECTIONING IS THE UNCOVERED HALF, NOT MIS-KEYING, and the row had them the
other way round while listing both. Its stated consequence stands unchanged for the
mis-sectioned case: the operator believes a posture switch is set, the permissive
default applies, and there is zero signal.

That also explains why the existing coverage looks reassuring. Someone checking
"is the unknown-key path tested?" finds two tests and a negative control and stops
-- which is the correct answer to a question adjacent to the dangerous one.

* docs(testing): confirm the unreachable-settings-sections P0, exactly (BACKLOG #1100)

07-config-wiring-and-cli.md row 82 is CORRECT on every claim, measured by AST
rather than grep -- which matters here, because this row is a COUNT plus an
ENUMERATION, the class that produced both of my own false claims tonight.

  _SECTIONS (settings.py:109)            23 entries
  ServiceSettings annotated fields       28
  difference                              5, and EXACTLY the five named:
                                          sandbox, cert_monitor, secret_rotation,
                                          update_check, service

The .partition("_") mechanism is at :3971 --
  section, _, key = name[len(_ENV_PREFIX):].lower().partition("_")
so MEFOR_CERT_MONITOR_* parses as section "cert", key "monitor_*". The three
multi-word names are unreachable a SECOND way, independently of _SECTIONS.

MEFOR_SANDBOX appears in ZERO tests.

AND THE "NO TEST PINS _SECTIONS" CLAIM SURVIVES A TRAP THAT LOOKED LIKE COVERAGE.
Five test files match the token _SECTIONS. NONE imports settings._SECTIONS:
test_verify.py's hit is ALL_SECTIONS from verify.runner -- host, store, smoke,
manual, federation -- an unrelated constant that my grep matched as a substring.
A file count would have said "covered five times over".

So ADR 0087's Router/Handler isolation boundary can be set in an NSSM environment
block, read back as off, and say nothing. That is a security boundary an operator
would reasonably believe is on, and the two independent failure paths mean fixing
_SECTIONS alone would still leave the three multi-word sections unreachable.

* docs(testing): confirm the shipped gate runs in no CI leg, past a collision that says otherwise (BACKLOG #1100)

07-config-wiring-and-cli.md row 78 is CORRECT on all three claims.

  .git/hooks/pre-commit begins "File generated by pre-commit"
        -> .pre-commit-config.yaml owns it
  .mefor-hooks/pre-commit exists AND DIFFERS BYTE-FOR-BYTE from the installed
        hook, verified with cmp rather than inferred: generated, not installed
  no workflow invokes `messagefoundry check`: 0 files, against a positive control
        of 10 workflows invoking pytest

THE COLLISION IS WORTH RECORDING BECAUSE ANYONE RE-CHECKING WILL HIT IT. Grepping
for lines containing both "messagefoundry" and "check" returns SEVEN, which reads
as "the gate is invoked seven times". Every one is `ruff check ... messagefoundry`
-- ruff's subcommand sitting beside the package name -- plus one comment. The
engine's own gate CLI appears nowhere in .github/.

My own two measurements disagreed (0 files vs 7 lines) and that disagreement is
the only reason I looked. A single measurement either way would have been
confidently wrong in whichever direction I ran first.

So the shipped config-quality gate runs in no CI leg: a change can demote
build-check from required or break a sub-check while every unit slice still
passes, and an adopter's gate exits 0 on a config `serve` will refuse.

That is the fourth same-line-different-subject collision in this sweep, after the
guard docstring quoting its own history, ALL_SECTIONS matching _SECTIONS, and
`annotation` matching `from __future__ import annotations`.

* docs(testing): the check SCHEMA is pinned, the ROSTER is not -- sharpen row 79 (BACKLOG #1100)

07-config-wiring-and-cli.md row 79 says "No test enumerates run_checks' result
names or flags". CONFIRMED IN SUBSTANCE, but the wording understates existing
coverage in a way that matters to whoever fixes it.

WHAT IS PINNED, tightly: tests/test_checks.py:383-385 asserts
  set(report.keys()) == {"ok", "checks"}
  set(c.keys())      == {"name", "ok", "required", "skipped", "detail"}
plus individual flags -- validate["required"] is True at :39 and :50, dryrun at
:64. So a dropped or renamed FIELD fails immediately.

WHAT IS NOT: WHICH CHECKS EXIST. run_checks (checks.py:114, 103 lines) assembles
results by calling a series of _check_* functions plus tool runs, and nothing
asserts that set. Drop a check, or flip its required flag, and every assertion
above still passes.

So the row's consequence holds exactly as written -- build-check is the only gate
catching an ADR 0092 production-PHI cleartext hop pre-serve, and reference-backend
the only one catching a Reference() against SQL Server that raises post-ACK
forever. Either could vanish silently.

I DELIBERATELY DID NOT STATE A COUNT. Three structural extractions of the roster
returned 0 or partial results: names are not literals, not name= kwargs, and come
from self.name on a per-check object. I have miscounted three times tonight by
asserting a number from a partial extraction, and an unverified count is precisely
what this sweep keeps finding rotted in other people's rows. THE SCHEMA-VS-ROSTER
DISTINCTION IS THE FINDING AND IT NEEDS NO NUMBER.

That also names the fix shape: the missing test is an ENUMERATION (the set of
check names and their required flags), not another per-check assertion. The
existing tests are the wrong kind, not too few.

* docs(testing): the lens fixtures are unguarded, and the guard next door is why (BACKLOG #1100)

07-config-wiring-and-cli.md row 81 is CONFIRMED, and the reason it survived is
worth more than the confirmation.

  steps.test.ts sets FIXTURE_DIR to src/test/fixtures/lens -- 7 fixtures present
  the ide CI job has 7 steps, NONE mentioning Python
  fixtures/lens/ is referenced by TYPESCRIPT ONLY; nothing regenerates or diffs it

THE TRAP: tests/test_lens_schema.py::test_ide_fixture_in_sync (:101) DOES
regenerate-and-diff a fixture, with the exact regeneration command in its failure
text. IT GUARDS fixtures/lens-SCHEMA/op-schema.json -- A DIFFERENT DIRECTORY
HOLDING ONE FILE.

  fixtures/lens-schema/   1 file    guarded from Python
  fixtures/lens/          7 files   not guarded at all

A grep for "fixtures/lens" matches "fixtures/lens-schema" as a PREFIX and reports
the gap as covered. I hit exactly that and only caught it by discriminating the
two directories -- the fifth substring collision in this sweep, after ALL_SECTIONS
matching _SECTIONS, `ruff check ... messagefoundry` matching the gate CLI,
`annotation` matching a __future__ import, and a docstring quoting the claim it
refutes.

So a lens.py change to kind / params / literal_params / line_start / line_end
leaves both suites green against seven stale committed fixtures, and the row's
consequence stands: Steps view mis-renders, or `lens rewrite` splices an edit into
the wrong statement of a clinical transform.

AND IT IS THE SAME SHAPE AS ROW 79, ONE ROW EARLIER IN THIS CHAPTER: there the
result SCHEMA is pinned and the ROSTER is not; he…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant