Skip to content

feat(mllp)+fix(startup): expose the message-rate pacer (#1249); require public_origin for the 12.1.1 probe (#1026) - #392

Merged
wshallwshall merged 9 commits into
mainfrom
b2/1249-1026-owner-rulings
Aug 15, 2026
Merged

feat(mllp)+fix(startup): expose the message-rate pacer (#1249); require public_origin for the 12.1.1 probe (#1026)#392
wshallwshall merged 9 commits into
mainfrom
b2/1249-1026-owner-rulings

Conversation

@wshallwshall

Copy link
Copy Markdown
Collaborator

Two owner-ruled items, built by Builder 2. Opened and armed by the Lander at the author's explicit go.

f8b98061 -- expose the message-rate pacer on the MLLP() factory (BACKLOG #1249)

Exposes max_messages_per_second / message_burst on MLLP(). The connector had read both since
the pacer was built and nothing could populate them
-- the settings were live in the code and
unreachable from any config surface.

TOML comes free: connections_file.py does return factory(**settings), so the same change reaches
both the code-first and connections.toml paths. Off by default, and that default is tested.

SECURITY.md's ingest row moved in the same commit because the e92b7ecf guard reads reachability
from the signature and flipped on its own -- the doc change is the guard's output, not an
editorial choice made alongside it.

c162309b -- require public_origin where the ASVS 12.1.1 probe needs it (BACKLOG #1026)

Requires public_origin in the declared-terminator PHI enforce posture, which makes the false
comment at :2113-2114 true by construction
rather than by convention.

Negative control run: reverted, console-OFF fails and console-ON still passes -- so the test
discriminates the thing it claims to.

Verification

Author-side, before handing over:

  • ruff + ruff format + mypy --strict clean on every changed file
  • 223 tests pass across every affected file
  • the only failure was the inherited ratchet, from a base predating the #391 fix

Lander-side, independently:

The branch was not on origin when handed over -- both commits existed only as local refs
(refs/archive/b2-1249-expose-pacer, refs/archive/b2-1026-require-public-origin). Pushed for
durability before anything else.

The rebase was then simulated read-only rather than attempted, rc read before content:

git merge-tree --write-tree origin/main <branch>
rc=0, no conflicts, merged tree 53f9382b

branch as it stood : 54  OVER ceiling
merged tree        : 52  ok

The author independently reproduced that same tree hash 53f9382b from their own checkout.

Why this is armed rather than held

The author's local suite ran against the pre-rebase tree, and a pre-rebase run is not landing
evidence -- it is stale the moment the branch updates. At URGENT STOP neither of us should start a
fresh full suite. CI runs against the merged state, which is strictly better than any local run
either of us could produce, so arming is how the missing evidence gets generated rather than a way
of skipping it.

If CI goes red, it returns to the author -- not absorbed here.

…LOG #1249)

OWNER RULING 2026-08-14: expose the keys. The pacer was BUILT and CORRECT, and no documented
configuration could turn it on -- `mllp.py:1378` and `:1382` read `max_messages_per_second` and
`message_burst` from a settings dict nothing could populate. A ruled-off default and an unreachable
setting are different things, and only the first was intended.

Two keyword-only parameters on a factory that already had 26, plus the two keys in the settings
dict it returns. That is the whole change.

THE TOML SURFACE COMES FREE, AND I VERIFIED IT RATHER THAN ASSUMING IT.
`connections_file.py` resolves a transport to its factory and calls `return factory(**settings)` --
"the factory is the schema, there is no second source of truth". So `connections.toml` can now
express both keys with no second edit, and a test pins that so the claim is checkable instead of
resting on a docstring.

THE OFF DEFAULT IS PRESERVED AND TESTED. Exposing a knob must not turn it on: a rate on a clinical
interface is only safe at a number from a real feed profile. `DEFAULT_MAX_MESSAGES_PER_SECOND` is
still None, a default install still has no rate bound, and a test asserts that constant directly --
if it ever becomes non-None, this change would silently have paced everyone.

WHY THIS WAS INVISIBLE FOR SO LONG, and it is the useful part. The pacer HAD tests. Every one of
them built an MLLPSource from a raw settings dict, bypassing the factory -- so they proved the
control worked while the only surface that could configure it was broken. The new tests go THROUGH
the factory on purpose, and one of them is a positive control that MLLP() still rejects an unknown
keyword: without it, every reachability assertion here would pass even if the parameters did not
exist.

docs/SECURITY.md's ingest row is updated in the same commit, because the guard added in e92b7ec
reads reachability FROM THE SIGNATURE and requires the doc to agree with whatever it says. That
guard failed the moment this code changed -- which is exactly what it was built to do -- and it
named the correction it wanted. The row now states the shipped default rather than unreachability,
and keeps the parts that were always true: the pause-don't-drop behaviour, the raw-TCP intake still
having no pacer, and the resource bounds that do ship on.
… it (BACKLOG #1026)

OWNER RULING 2026-08-14: require it regardless of `serve_ui`.

THE DEFECT. The TLS-floor probe's gate has FOUR conditions; the comment above it named THREE and
asserted every other posture "never reaches here and is byte-identical". The undocumented fourth was
`public_origin` -- and the only thing that required `public_origin` was itself gated on `serve_ui`.
So with the console OFF, a PHI instance behind a declared terminator under `enforce` started with
the ASVS 12.1.1 control SILENTLY INERT, and nothing reported the skip. A reader of that comment
concluded the probe runs whenever a PHI instance sits behind a declared terminator under enforce.

THE SAME BLOCK ALREADY REFUSED THIS SHAPE TWICE, ONE LEVEL DOWN. It returns 2 when the probe's
MECHANISM is missing, because "a check that degrades to a no-op when its mechanism disappears
reports success forever afterwards", and it refuses on unreachable because "a gate that is trivially
defeated is not a gate". Leaving `public_origin` unset WAS trivially defeating this gate, and the
outcome WAS a check reporting success forever. The principle was stated twice and violated one level
up.

THE COMMENT IS NOW TRUE BY CONSTRUCTION, not by editing. The refusal guarantees `public_origin` for
exactly the posture the probe gate selects, so the fourth condition is no longer a hidden scope
narrowing -- it is a belt-and-braces and the type narrowing the call needs, and the comment says so.

SCOPE MATCHES THE PROBE'S SCOPE, INCLUDING LOOPBACK. The probe deliberately runs behind a declared
proxy on loopback ("a reachable front door that speaks TLS 1.0 is a fact, on loopback or not"), so
the precondition is required there too. A synthetic-data instance is untouched, and a test pins that
-- without it this would be a blanket refusal measuring something other than its own posture.

This REFUSES A POSTURE THAT STARTS TODAY. Per CLAUDE.md section 0 there are zero deployments, so it
breaks nothing and notifies nobody, and it will never be cheaper to add. That is why the cost is
acceptable -- not why the answer is (a). The reason for (a) is that it is the only end where the
control measures its own posture rather than measuring whether someone happened to configure an
unrelated console setting.

PROVED BY A NEGATIVE CONTROL, not by a green run: with the fix reverted, the console-OFF case FAILS
and the console-ON case still PASSES -- so the new test isolates exactly the defect, and the arm that
was already correct is shown to have been already correct.

Test fixtures pre-satisfy the new precondition the way they already pre-satisfy intra-service auth
and the KEX floor, so each case keeps testing its own subject. Two of them also stub the probe, for
the same reason `uvicorn.run` is stubbed: these are CONFIG-gate tests and the probe's network
behaviour is covered by tests/test_tls_floor_probe.py. NOTE FOR THE NEXT EDITOR: the authored key is
`[security].web_console_public_address`; `[api].public_origin` is the internal settings name and ADR
0118 retired the authored form, which caught these fixtures twice.
@wshallwshall
wshallwshall enabled auto-merge (squash) August 14, 2026 16:12
@wshallwshall
wshallwshall disabled auto-merge August 14, 2026 16:37
…g gate suites

Repairs the 13 failures my own c162309 introduced. Same class as the four I fixed in
test_api_tls.py and test_cli.py, in the two files I did not run: the #1026 start-time refusal blocks
postures those suites expect to START, so each was failing on a precondition rather than on its own
subject.

THE SCOPING ERROR IS THE POINT, and it is worth more than the fix. The refusal is FLEET-WIDE across
the startup ladder; my verification was FILE-LOCAL. "223 tests pass across every affected file" was
a TRUE statement over a WRONG POPULATION -- affected meant "files I edited", and the change affects
every suite that boots a declared-terminator PHI instance under enforce.

Two shared seams per file, so the repair is four edits for thirteen tests:
  - the TOML builder declares `[security].web_console_public_address`
  - the serve harness stubs `probe_tls_floor`, for the same reason it already stubs `uvicorn.run`:
    these are CONFIG-GATE tests, and the probe's network behaviour is tests/test_tls_floor_probe.py.
    Stubbing it to FAIL would assert the probe rather than the ladder.

In test_checks_gate_parity.py the constant follows the `_MEMORY_ENCRYPTION` precedent exactly,
including its placement rule -- a [security] key must precede _PROXY or TOML files it under [api].

ONE CONSEQUENCE FLAGGED RATHER THAN ABSORBED: the loopback-behind-a-declared-proxy topology in
OFF-LOOPBACK-DEPLOYMENT.md now needs a public address too. The 12.1.1 probe deliberately runs there
("a reachable front door that speaks TLS 1.0 is a fact, on loopback or not"), so the precondition
applies -- but that changes the published runbook's minimum config, which is a doc question and is
noted in the test rather than silently satisfied.

THE NEGATIVE CONTROL STILL DISCRIMINATES, re-verified after these edits because pre-satisfying a
precondition everywhere is exactly how you neuter your own proof: reverted to f8b9806 the
console-OFF case FAILS while console-ON and non-PHI still pass.

A first attempt at that check was INVALID and nearly cost the conclusion -- `git checkout --` restores
from HEAD, and HEAD is the #1026 commit, so it reverted TO the fix and everything passed. Removing a
committed change needs the parent, not the file.
@wshallwshall
wshallwshall enabled auto-merge (squash) August 14, 2026 19:35
THE PAIRED LEDGER COMMIT FOR THIS PR, supplied under the sanctioned interim (c):
a builder PR implementing a backlog item cannot make itself green, because the
required check `a PR that implements BACKLOG #N must update BACKLOG.md` reads the
PR's own three-dot diff, and ledger authoring is not the builder's lane.

WHY IT WAS THE PR BODY THAT TRIGGERED THE GATE, stated so nobody hunts a phantom:
the gate greps title and body for the literal token `BACKLOG #N`, and this PR's body
carries it because the Lander wrote it there. The claim is ACCURATE -- the PR does
implement both items -- so the honest satisfaction is to update the ledger, not to
reword the body until the gate stops looking. A gate you can silence by changing how
you describe the work is not a gate.

STATUS BANNERS ARE DELIBERATELY UNCHANGED, and this is the load-bearing choice.
`parse_items` before and after: 288 items, 208 open, #1249 and #1026 both still open.
Marking an item closed is a judgement about COMPLETENESS. Code landing is evidence
toward that judgement, never the judgement itself -- and the seat that supplied a
paired commit to unblock a gate is the worst-placed seat to make it. Left to the
ledger seats.

WHAT EACH AMENDMENT RECORDS:
  #1249  the pacer settings the connector has read since it was built are now
         reachable, from code-first wiring and from connections.toml alike
  #1026  public_origin is required where the probe needs it, making a comment that
         was true by convention true by construction; the negative control was
         re-run and still discriminates

Pure addition: 4 insertions, 0 deletions, one file.
@wshallwshall
wshallwshall merged commit 91a2406 into main Aug 15, 2026
35 of 36 checks passed
@wshallwshall
wshallwshall deleted the b2/1249-1026-owner-rulings branch August 15, 2026 06:00
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