docs(backlog): record that the 2026-08-16 ruling settles ASVS 2.4.1 (BACKLOG #1114) - #862
Conversation
…BACKLOG #1114) The #1114 re-score banner rested on two premises that no longer hold at a2eef0f, and the row now says so rather than carrying them forward. Measured at HEAD, with a control on every reading: - The pacing keys reach four of the nine externally-facing inbound factories. MLLP, Tcp, X12 and Http accept max_messages_per_second and message_burst and carry both into the connection spec; DICOM, File, Sftp, Ftp and DatabasePoll construct without the keys and then raise TypeError on each. Every row ran that no-key control leg first, so a rejection is a fact about the key and not about a bad signature. - By symbol, _MessagePacer and _pacing_settings appear only in mllp.py, tcp.py, x12.py and http_listener.py. Two positive controls fire against that zero: source_ip_allowlist returns 12 in dicom.py, the very file the pacer scan calls zero, and register_source returns 2 in every inbound transport module. - DEFAULT_MAX_MESSAGES_PER_SECOND is still None and nothing reads the key at startup, so a default install WOULD still take messages at an unbounded rate on first deployment. So the banner's "for non-MLLP inbounds there is no opt-in bound at all" is struck as falsified by the 2026-09-03 port, and its difficulty clause is marked spent: the raw-TCP limb shipped, and the ruling it priced was written on 2026-08-16, before the score was set. The numbers are left as the scoring pass recorded them, because re-scoring is that pass's act and not a builder's. The cell's verdict is settled by standing rule rather than by a build. Rule 3 takes it off fail; rule 4 denies pass because the control ships off and no gate refuses to start; section 1.1a pre-rejects the vacuity argument by name. Rule 5 then selects partial on two independent limbs, so finishing the port would not move it either. The row now tells a builder who reaches it not to build. Also re-points the dead docs/SECURITY.md:1582 citation by content, to the "Ingest plane" row under "Business-logic limits (ASVS 2.1.3)", and records one residual: that row's "both surfaces express them" clause overstates the TOML surface for X12. Left for its own diff. And narrows the Severity line's "MLLP has neither intake authentication nor rate limiting". Intake authentication holds in no configuration, but an opt-in pacer has existed on MLLP since 2026-08-11, so the flat claim contradicted this item's own body -- the same defect the 2026-08-13 amendment was raised to fix. The asymmetry the line exists to carry is unchanged and now sharper: no intake auth at all, no rate bound on the shipped default. No code changed. The ASVS scorecard is untouched; it lives in the vault clone. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Local verification against the committed tree ( pytest, its own summary line: Files:
One further control, run after the push, on the claim this row turns on. The row says the pacer reaches four intakes and no others. A symbol grep can be defeated by an The four uncovered inbound modules that import from Not run: the full suite. The diff is one Markdown row, and the box was carrying concurrent |
|
The Disclosure per the Manager playbook section 6. I am the seat that commissioned this diff, so the label records my read of work I asked for, not an independent one. The builder deliberately held off labelling because its brief's precondition was unmet -- the review-gate run was queued rather than What the label stands on. The pacing keys reach four of the nine externally-facing inbound factories -- MLLP, TCP, X12, HTTP -- and are rejected by DICOM, File, SFTP, FTP and DatabasePoll. Every probe row constructed the factory without the keys first as a control; three rows failed that control on the first attempt and reported themselves uninterpretable rather than as absent, and were re-run against the real signatures. A separate alias check confirmed the uncovered modules import only
pytest, quoting its own summary line: A correction the builder made in its own draft, which I want on the record because it cuts against the finding. It first wrote that nothing on this item's build list moves the cell. That is false -- the refuse-to-start gate is on that list and would move it. It corrected to "no further widening of the pacer's surface moves it" before committing. The distinction matters: this row records that a build exists which would change the verdict, and it is not being claimed as unreachable. It also re-pointed the dead |
What this changes
One row in
docs/BACKLOG.md(item #1114). No engine code, and no documentoutside that row. The ASVS scorecard lives in the vault clone and is untouched.
BACKLOG #1114 asks whether ASVS 2.4.1 can reach an honest pass. Its original
claim was falsified once already, on 2026-08-12. This pass found and confirmed a
second staleness, then recorded the answer the item's own hardened question
already had.
The second staleness, measured with a control on every reading
The pacing keys reach four of the nine externally-facing inbound factories.
MLLP,Tcp,X12andHttpacceptmax_messages_per_secondandmessage_burstand carry both into the connection spec'ssettings.DICOM,File,Sftp,FtpandDatabasePollconstruct normally WITHOUT the keys andthen raise
TypeErroron each, so the rejection is a fact about the key and notabout a bad signature. Every row ran that no-key control leg first; three rows
failed it on the first run, reported themselves uninterpretable rather than
absent, and were re-run against the real signatures.
By symbol,
_MessagePacerand_pacing_settingsappear intransports/mllp.py,tcp.py,x12.pyandhttp_listener.pyand in no other transport module. Twopositive controls fire against that zero:
source_ip_allowlistreturns 12 indicom.py, the very file the pacer scan calls zero, andregister_sourcereturns 2 in every inbound transport module.
So the re-score banner's clause "for non-MLLP inbounds there is no opt-in bound
at all, so no workaround exists there" is FALSE at HEAD. It is struck in place,
not deleted. Its difficulty clause is marked spent for two reasons: the raw-TCP
limb it priced was delivered on 2026-09-03, and the ruling it priced was written
on 2026-08-16, before the score was set.
The numbers are left as the scoring pass recorded them. Re-scoring is that
pass's act, not a builder's, and changing them here would desync the quadrant
census elsewhere in the file.
What did not change is the half that decides the cell.
DEFAULT_MAX_MESSAGES_PER_SECONDis stillNone, each of the four factoriesstill defaults both keys to
None, andmax_messages_per_secondappears nowherein
messagefoundry/outside those four transport modules andconfig/wiring.py-- run with the exclusion inverted as its own control, returning 4 and 11 in the
two files that do carry it. Nothing reads the key at startup and no gate refuses
to start without it. A default install WOULD still take messages at an unbounded
rate on first deployment, on every intake.
The 2026-08-16 ruling settles the cell on the shipped default
Walking
docs/ASVS-ASSESSMENT-METHOD.mdsection 1 in order: rule 3 takes thecell off
failbecause the control exists reachable by some configuration; rule4 denies
passbecause the control ships off and no gate refuses to start; andsection 1.1a records the owner ruling that rule 4 is strict, that an
off-by-default control can NEVER be graded
pass, and that the vacuity argumentis pre-rejected by name. Rule 5 then selects
partialon two independent limbsat once -- ships off, AND covers part of the surface.
That is why the 2026-09-03 port did not move the verdict and why finishing the
port would not move it either: widening the surface answers rule 5's third limb
while rule 4 goes on asking about the default.
transports/mllp.pyreached thesame conclusion first, in the comment above
DEFAULT_MAX_MESSAGES_PER_SECOND.The row now tells a builder not to build IN ORDER TO MOVE THIS CELL. Other
subjects on its proposed-work list stay buildable on their own merits, but none
of them changes the verdict, so none of them closes the item. The two changes
that could carry the cell to
passeach need an owner ruling first: flipping thedefault, which the 2026-08-11 ruling set OFF as a deliberate deviation; and the
refuse-to-start gate of rule 4's second limb, a new gate class.
That distinction is deliberate: an earlier draft of this row said "nothing on
this item's own build list moves it", which was false -- the refuse-to-start gate
IS on that list and would move it. Caught and corrected before commit.
Citation re-pointed by content
docs/SECURITY.md:1582now lands on account-lockout prose about an assertionleg, so that anchor is dead. The live sentence is the "Ingest plane" row of the
table under the "Business-logic limits (ASVS 2.1.3)" heading. The row cites it
that way rather than by line, because this anchor has now drifted twice.
One residual is recorded and deliberately left unedited: that same SECURITY.md
row concludes "the code-first and the TOML surface both express them" across all
four named factories, and for
X12the second half is false --_TRANSPORTSinconfig/connections_file.pycarries nox12key. The gap is already pinned withits own positive control in
tests/test_ingress_message_pacing.py. A securitysentence deserves a change a reviewer can see on its own.
One contradiction inside the row, narrowed
The Severity line said "MLLP has neither intake authentication nor rate
limiting". Intake authentication holds in no configuration, but an opt-in pacer
has existed on MLLP since 2026-08-11, so the flat claim contradicted this item's
own body -- the same defect the 2026-08-13 amendment was raised to fix. Narrowed
in place, struck rather than deleted. The asymmetry the line exists to carry is
unchanged and now sharper: no intake authentication at all, and no rate bound on
the shipped default, so there is still no actor to charge a budget against.
Checks run
ruff check .-- All checks passedruff format --check .-- 1241 files already formattedmypy messagefoundry(strict) -- Success: no issues found in 267 source filesscripts/docs/backlog_status_check.py-- OK, 664 backlog items, each declaringexactly one status
pytestover the ledger and doc-guard files that readdocs/BACKLOG.md(
test_backlog_status_check,test_backlog_citation_check,test_ledger_check,test_asvs_tally_lint,test_link_resolution,test_cp1252_console_safety,test_doc_guards_lane) -- see the comment below for the summary line of the runagainst the final text.
Not run: the full suite. The diff is one Markdown row and the box was under
heavy concurrent load -- seven test files took 7m26s. The legs above are the ones
that read this file.
/simplifyhad no target: no code changed.Please read the hosted legs after merge; a builder's process exits before they
report.
What I deliberately did not do
ruling behind it, and inverting it silently is the move this item most needs
nobody to make.
shipped configuration.
🤖 Generated with Claude Code