backlog: amend #1212 (built, refuted, reverted) and #122 (visibility is not enforcement) - #323
Merged
Merged
Conversation
…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
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…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Amends
#1212and#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. Noduplicates, no item declaring more than one status.
#1212and#122both confirmed still OPEN.Merges cleanly onto
main.