Skip to content

mcp: the MCP-FIX stack (plane-mcp findings 1-18, 24) - #703

Open
MattJackson wants to merge 69 commits into
predevfrom
lane-task-draft-673-mcpfix-stack
Open

MattJackson wants to merge 69 commits into
predevfrom
lane-task-draft-673-mcpfix-stack

Conversation

@MattJackson

Copy link
Copy Markdown
Collaborator

The one PR that lands the MCP-FIX stack (busbar-plane-mcp audit findings 1-18 and 24). It contains, by merge in landing order: #634 passthrough, #639 destjudge, #638 deadplane, #640 sessions-v2, #645 stdio-v2, #660 tasks, and its own bounds work, merged with current predev. #615 (sampling), #616 (ask) and #637 (line) have already merged into predev, so their share of the diff is gone from this PR.

Covered by this PR (the stack's layers, which carry no work of their own): #634, #638, #639, #640, #645, #660. Supersedes #673, #660, #645, #640, #639, #638, #634.

What it closes

group findings PR (detail, RED plant, original proof)
passthrough 2, 3: a tool result, a task result and an upstream error reach the caller as the upstream sent them; the outputSchema replacement and the markup strip on results are deleted; BUSBAR-7065 retired #634 (RED 6bc5958, 381e4c3; cli-d431829e)
destjudge 4 [security]: argument URLs are judged by the kernel's dest.judge; plane-local host rules deleted #639 (RED f8af9d2; cli-74b2870f)
deadplane 12: the unserved Plane/SessionPlane impl and the cross-plane sampling route are deleted; the xtask refusal-collapse scan drops its mcp row #638 (RED 87a59c0; cli-7463c40a)
line (merged) 16, 17: the line carrier refuses subscribe/setLevel (-32601) and bounds its live asks #637, in predev (RED 8f6c4e4; cli-7c7be1aa)
sessions 1, 18: the session revisions and the 2024-11-05 event stream, both directions; the session byte account never underflows #640 (RED 7150aa7; cli-17ae3789)
stdio 5 [security], 13, 14: relaying calls are serialised per stdio child in arrival order so each ask reaches only its caller, an ask raised with no call open is refused; a lease reads whole frames; Frames reads each byte once #645 (RED 11b3ca7; cli-56d97d32)
tasks 6, 24: the task store is host records; leftover live handles are settled; an owed settle is made again #660 (RED 7c81fbb; cli-e1d0037d)
bounds (this branch) 7, 8, 9, 15 and the unit table: an upstream answer under REPLY_MAX, the uri dedupe, the refused unit dropped, a per-owner listen quota; a full unit table refuses (429) and evicts nothing RED 67e0b43, 64a2244; cli-2f87e482
ask (merged) 10, 11: the final ask round needs its answer; a failed host clock refuses sealed state #616, in predev (RED 6643353, b7fc13f)
sampling (merged) the resolved-completion seam and the ask satisfier are deleted; an upstream's ask is relayed #615, in predev (RED 6d297d1)

Known limits (rulings)

  • Sessions: busbar does not act as a 2024-11-05 SSE client upstream and holds no upstream resource subscription. An upstream that offers only 2024-11-05 gets the upstream-failure answer naming that revision.
  • Stdio: an ask raised by a finished call after the next call opened is attributed to that next call (the wire's limit); a serial child holding a relayed ask blocks the member's next relaying call until the retry or the ask TTL (300 s); a waiting call is answered busy past its timeout:.
  • Line carrier: subscribe and setLevel stay -32601 in every revision the carrier speaks; subscribe for the old revisions is served on the HTTP sessions.

Cross-group resolutions made in the merges

  • deadplane x predev P-item refusal-reason collapse: one refusal classification; every surface a class-to-wire table #535: refusal_words lived only in the deleted unserved impl; tool_plane.rs and its test stay deleted.
  • deadplane x stdio: tests/alloc_gate.rs keeps the counting allocator and the finding-14 plant; the decode pin drove the deleted impl.
  • sessions x line: the carrier's initialize negotiation is re-applied on line's -32601 carrier, declaring neither subscribe nor logging; the subscription uri bound moves to door_sessions.rs.
  • tasks x stdio: Step::Wait stays for stdio's waiting call; the run's call takes destjudge's (services, ticket); the door test's records_composed takes both the wall clock and the dest judge.
  • bounds x sessions: REPLY_MAX is checked at the gather, before the client ladder; with keep() gone, the line carrier's revision table admits a new carrier session only while it has room (a full one is answered in the stateless revision), and the session stream table is bounded by the unit table's admission.
  • ask x tasks: the relayed task leg opens the retry's state and keeps ask's rule that an unreadable clock opens nothing.
  • sampling x passthrough/deadplane: call.rs's settle doc says both an ask and a result are relayed; purity.rs keeps both source scans.
  • Hop reds named on mcp tasks: the task store is host records; leftover live handles are settled; an owed settle is made again until it lands (plane-mcp findings 6, 24) #660 (run 37720341630), fixed here: mcp_stdio_serve now expects the negotiated session revision; the kind-isolation-ship selftest plants its short-circuit step in busbar-plane-a2a, because the mcp plane is now door-only.

The predev merge

  • destjudge x SECURITY: mcp tool-argument guard refuses every address the destination guard refuses; 6to4/Teredo judged by their IPv4 (C3 H5) #656 (argguard.rs): the branch's design stands. Every host an argument names is asked of dest.judge; SsrfPolicy and the plane-local host rules stay deleted; no verdict fails closed. SECURITY: mcp tool-argument guard refuses every address the destination guard refuses; 6to4/Teredo judged by their IPv4 (C3 H5) #656's extra ranges (benchmarking, IETF-protocol, this-network, broadcast, multicast, documentation) stay closed because dest.judge is the same destination guard. SECURITY: mcp tool-argument guard refuses every address the destination guard refuses; 6to4/Teredo judged by their IPv4 (C3 H5) #656's argguard cells (an_address_the_connector_guard_refuses_is_refused_in_an_argument_too, the_internal_range_table_is_pinned, a_transition_address_embedding_a_private_v4_is_refused) already drive the branch's dest.judge test double and are kept unchanged, every range case included.
  • deadplane x d3435dc (tests/conformance.rs): predev's only change there renamed the empty-envelope pin on the deleted McpPlane::decode_response. The two mcp P-item pins the DONE oracle counts (scripts/verify-1.6.0-done.sh: 11 refusal-collapse pins, 1 empty-reply pin) are ported onto the served door rather than dropped:
    • p_item_empty_reply_only_a_real_result_settles_complete (src/tests/call.rs): an envelope with neither result nor error settles as the upstream's failure (isError, upstream_failed, audited rejected), never as a delivered result.
    • p_item_refusal_reason_collapse_the_door_answers_every_reason_at_the_kernels_status_never_internal (tests/conformance.rs): every reason a plane is handed is answered at the kernel's status in the one refusal family (-32000), never as the internal error. It replaces the pin on the deleted refusal_words.
  • predev's stream_ceiling_secs: 0 and the snapshot's listed field in door.rs merged cleanly. Predev's DoorSeal/seal_relayed clock work merged into tool_door.rs and door_tasks.rs without conflicts.
  • Post-merge sweep: nothing in the tree references SsrfPolicy, tool_plane.rs, the mcp refusal_words, the resolved-completion seam or the ask satisfier. BUSBAR-7065 shows up only as a retired entry in docs/diagnostics-mcp.*. The xtask refusal-collapse scan and the kind-isolation rows name no deleted mcp file.

Proof

Latchkey cli-af296ba4-4bea-4bc7-8d9b-22c41bf0b838 ran on the combined tree before the predev merge. RED on 6d297d1: 3 of 3 failed. GREEN-EXIT=0: fmt, clippy -D warnings (kernel, llm, plane-mcp), tests for busbar-kernel, busbar-llm and busbar-plane-mcp, a busbar build, plane_host_universal_purity and plane_node. Each group's own RED and GREEN job is listed in the table. Nothing was built or run locally after the predev merge; this PR's hop is the gate.

1.5.5 had no MCP plane. An unconfigured node's GET /mcp is still the 1.5.5 404.

…pls the unserved Plane traits (finding 12; spec Law 11, never-constructed). Source scan: the honest plant for a pure deletion; fails while NestedPlane, SAMPLING_OP, impl Plane/SessionPlane for McpPlane exist
… struck cross-plane sampling route (finding 12)

The crate serves only plane_door::door; nothing constructed McpPlane as a Plane. Removes src/tool_plane.rs
(impl Plane / SessionPlane for McpPlane, the sampling row to DestinationFacts::NestedPlane, the roots row, the
second meter that disagreed with the served door's) and tool_meta::SAMPLING_OP. Law 11 (spec 420-421, 2123-2129):
no call is routed to another plane on the content's say-so; spec 1930: a capability that is never constructed
does not ship. Server and the McpPlane field were read only by that impl and go with it; McpPlane stays as the
PlaneMeta/Plugin carrier the door reads (tool_door.rs PLANE/CLAIMS). The served door's meter is untouched.

Tests driving the dead impl retire under the coordinator's finding-12 order (F25, spec 1181); surviving
assertions move to plane-free tables (conformance, declarations_agree).
…indings 2, 3)

Plants three tests in busbar-plane-mcp src/tests/call.rs, driving the pure settle the door
serves every tools/call answer through (call::settle_call):

- a_result_reaches_its_caller_as_the_upstream_sent_it: a result carrying `Vec<String>` and
  `<b>x</b>` in content text, structuredContent and _meta must reach the caller unchanged, its
  bytes the upstream's own. Fails today: the built-in markup strip serves `Vec` and `x`
  (finding 2, call.rs:1382).
- structured_output_breaking_the_published_schema_is_relayed_unchanged: a structuredContent
  that fails the tool's published outputSchema must be relayed unchanged, dispatched, audited
  applied. Fails today: busbar answers its own isError "The structured result was NOT served"
  (finding 3, call.rs:1355-1378). Replaces structured_output_breaking_the_published_schema_is_a_tool_failure,
  which asserted the replacement.
- the_task_path_names_no_rewrite_of_the_result: a source plant over door_tasks.rs (the task
  continuation is reached only through a live door). Fails today: door_tasks.rs:755 runs the
  strip over every completed task result.

Spec (docs/design/BUSBAR-1.6.0.md): Law 11, lines 2123-2133 ("A plane reads content ONLY to
translate dialects and to meter usage", 2126; "Code that answers, executes or branches on what a
request or response asks for is a defect: it is deleted", 2131-2132); product hard rules
3369-3373 ("every client header and body field passes through unchanged, except what busbar
governs").
…ip and the outputSchema replacement are deleted (findings 2, 3)

Finding 2 [HIGH] (markup stripper on tool results):
- call.rs completed(): the result no longer passes through sanitize::normalise_json. The
  caller's answer carries the upstream's own `result` bytes (serde_json RawValue over the far
  end's answer) under the caller's id, instead of a re-serialised parsed Value; the one
  addition is the dialect's `resultType: complete` on a result object that carries none. A
  `resultType` the upstream sent is no longer overwritten.
- door_tasks.rs continuation_answered(): a completed task stores the upstream's result as it
  came (End::Completed(value)).
- sanitize.rs: normalise_json deleted (no caller left). normalise / normalise_opt stay: they
  serve busbar's own section text (catalogue descriptions, prompts/get, resources/read) and
  busbar's words on a failed leg.
- busbar-plane-mcp Cargo.toml: serde_json names `raw_value` itself.

Finding 3 [HIGH] (structuredContent schema failure replaced by busbar's error):
- call.rs completed(): the outputschema::check branch and its "The structured result was NOT
  served" answer are deleted; the upstream's result is relayed unchanged, dispatched, audited
  applied.
- outputschema.rs and src/tests/outputschema_tests.rs deleted: the check has no caller ("a
  capability that is never constructed does not ship", THE DESIGN 1930).

Tests retired: src/tests/outputschema_tests.rs (16 tests of the deleted check);
sanitize_tests.rs every_wrapper_normalises_through_the_same_function loses its normalise_json
half (renamed the_optional_wrapper_normalises_through_the_same_function, normalise_opt half
kept). call.rs a_result_is_normalised_stamped_and_dispatched is renamed
a_result_is_stamped_and_dispatched and now pins the relayed bytes and the empty-result stamp.

Prose: call.rs module doc, sanitize.rs module doc, tools_config.rs output_schema doc,
tests/sanitize_complexity.rs doc, docs/mcp.md (output_schema row, catalogue and
markup-normalisation paragraphs) no longer claim results are stripped or validated.

Spec (docs/design/BUSBAR-1.6.0.md): Law 11, 2123-2133 (2126 "A plane reads content ONLY to
translate dialects and to meter usage"; 2131-2132 "Code that answers, executes or branches on
what a request or response asks for is a defect: it is deleted, never added"); product hard
rules 3369-3373 ("every client header and body field passes through unchanged, except what
busbar governs"); 1930.
…8, 9, 15)

Plants that fail on the unfixed tree: a unit the kernel refuses stays held (9);
a piece the plane refuses leaves its unit held (9); an upstream answer is
gathered with no reply ceiling (7, source-shape plant: the gather site needs a
kernel-admitted call this harness has no host to make); a request over the
64-uri ceiling is refused only after the whole array is read (8); one caller's
subscriptions are not refused at a per-owner quota (15).
Spec: BUSBAR-1.6.0.md 379-390 (mcp bullet, per-owner session and byte quotas),
199-201 (nothing evicts live work; an eviction is not a refusal).
… and the per-owner subscription quota (findings 7, 8, 9, 15)

7: an upstream answer is gathered only up to the SDK's REPLY_MAX; past it the call fails as a bad upstream answer does (upstream_failed).
8: resourceSubscriptions are deduplicated through a set and read no further than the first uri past MAX_SUBSCRIBED_URIS.
9: a unit the kernel refuses (refusal slot) or whose piece the plane refuses is dropped from the unit map.
15: subscriptions/listen holds at most 64 streams per caller; the 65th is refused 429 subscription_quota in the caller's own answer, never evicting another caller's stream (keep() no longer used for listens).
Spec: BUSBAR-1.6.0.md 379-390 (per-owner session and byte quotas), 199-201 (a refusal is a fact the caller can act on and an eviction is not).
…finding 4)

Two served-door tests in the root rig (crates/busbar/src/root/tests/door_steps.rs):
- a_host_the_deployment_refuses_is_refused_in_the_arguments: the rig's deployment blocks
  `blocked.example` (security.blocked_metadata_hosts); a call whose arguments name it must be
  refused 403 / -32000 / tool_argument_refused before it is sent. The plane's own predicate admits
  it, so this fails on the unfixed tree: the plane never asks the host.
- every_internal_address_the_guard_refuses_is_refused_in_the_arguments: the nine addresses the
  connector's guard refuses as internal (198.18.0.1, 192.0.0.8, 0.1.2.3, [::ffff:198.18.0.1],
  [::1%25lo], [fe80::1%25eth0], 224.0.0.1, 255.255.255.255, [ff02::1]) are refused in arguments
  by that same judgement.

The rig's kernel services now carry the deployment's one destination judge (the connector's
guard), as root::serve::kernel_services composes it in production, so the test host's dest.judge
is the kernel's real judgement, not a stub.

Spec (docs/design/BUSBAR-1.6.0.md): 5140 (B.3 item 11: argument-embedded URL judging is
dest.judge), 1579 (the dest.judge row), 614-621 (one guard, every scattered check deleted).
…anged (finding 2)

Plants an_upstream_error_message_reaches_its_caller_unchanged in busbar-plane-mcp
src/tests/call.rs: an upstream error whose message carries `Vec<String>` and `<b>x</b>` must
reach the caller byte-identical inside busbar's failure words. Fails today:
call.rs upstream_failure_result runs the markup strip over the whole text, serving `Vec` and
`x`. The envelope shape (isError result) is unchanged by this plant.

Spec (docs/design/BUSBAR-1.6.0.md): Law 11, 2126 and 2131-2132; product hard rules 3369-3373.
…d (finding 2)

call.rs upstream_failure_result no longer runs sanitize::normalise over its text. The text is
busbar's fixed wording ("The MCP server `<server>` did not complete this tool call: ...")
around the reason, and on an upstream error the reason carries the upstream's own JSON-RPC
error message, which the strip rewrote (`Vec<String>` -> `Vec`). The envelope (an isError
result) is unchanged. sanitize.rs and tests/sanitize_complexity.rs docs no longer name the
failure text as a strip site.

Spec (docs/design/BUSBAR-1.6.0.md): Law 11, 2126 and 2131-2132; product hard rules 3369-3373.
The structured-output check it reported is deleted (34df85d), so nothing emits the code.
Retired the way the catalogue retires a code (busbar-kernel diagnostics 8013): the number and
slug are kept, `retired: true`, the title marked RETIRED, the summary says what was removed and
why, the action is "Nothing emits this code." The plane's declares.json carries the same
title/summary/action (src/tests/diagnostics_tests.rs the_declares_file_states_the_catalog holds
it to the constant). docs/diagnostics-mcp.{md,json} edited by hand in the kernel renderer's exact
form (render_markdown_for appends " *(retired)*" to the heading; render_json_for writes
"retired": true): no committed-page test exists for the mcp page.

Spec (docs/design/BUSBAR-1.6.0.md): Law 11, 2131-2132; 1930.
…lane-mcp finding 15 class)

On the unfixed tree the 4097th arrival is accepted and unit 1 is evicted.
Spec: BUSBAR-1.6.0.md 199-201 (admission bounds live work; nothing evicts it; an eviction is not a refusal the caller can act on).
… evicting the oldest live unit; keep() removed

Spec: BUSBAR-1.6.0.md 199-201 (admission bounds live work; nothing evicts it). Per-owner bound not added: the arrival carries no caller reference.
… rules are deleted (finding 4)

plane-mcp finding 4 [HIGH]: the argument SSRF guard decided in the plane (argguard::judge_host
over busbar_contract::net::host_is_cloud_metadata / is_alternate_ipv4_encoding /
host_is_private_or_loopback under the registration's allow_private) and never asked the host.

- argguard.rs: judge_host now asks the host's ONE destination judge for every host the walk
  finds (an IPv6 literal bracketed, as dest.judge reads host[:port]) and renders its DEST_*
  verdict; a host that gives no verdict refuses the value (fail closed). SsrfPolicy and the local
  host rules are deleted; the walk, the scheme allowlist and the host reader stay.
- call.rs: the guard leaves admit_trusted (and its allow_private parameter) for
  judge_arguments, run on the admitted call, so the door's ask seal and the judge never hold the
  unit's handle counter at once. The refusal bytes are unchanged: 403, JSON-RPC -32000,
  data.reason tool_argument_refused, the same call-log line.
- tool_door.rs: dest_verdict asks dest.judge (Services::dest_judge_as) under the deployment's
  default egress class, DEST_REFUSE_PRIVATE unless the registration granted allow_private, name
  only (never DEST_RESOLVE, so it never pends), each on a fresh handle of the unit's ticket.
- door_tasks.rs: the task path's re-judgement of the arguments asks the same judge.
- tests: argguard_tests judge through a stand-in host over the contract's address predicates;
  call tests prove the host's verdict alone decides, each host is asked once for the called tool,
  and a host with no verdict refuses.

Spec (docs/design/BUSBAR-1.6.0.md): 5140 (Appendix C B.3 item 11: argument-embedded URL judging
is dest.judge, called where it is called today), 5111 (the B.2 row: dest.judge may pend: no),
1579 (the dest.judge row: judged against the egress rules, allow-list, class, metadata hosts),
614-621 (every outbound check in ONE place; every scattered check deleted in its favour),
4945 (class 0 of dest.judge is the deployment's security section).
…r node, leftover live handles settled, a refused settle made again

Finding 6 [HIGH] (plane-mcp audit): live task state lives only in the
instance's memory, a task not held in this process answers "unknown", and
live work handles an earlier process left (or a settle that did not land)
are never settled, so they pile up until work.open refuses every
task-creating call.

Three plants in the task_continuation rig (crates/busbar door_steps.rs),
each failing by assertion on the unfixed tree:

- a_live_task_created_on_one_node_is_answered_by_another: two nodes over
  one set of host rows; tasks/get on the second node for a live task the
  first created answers -32602 unknown instead of the first node's answer
  (BUSBAR-1.6.0.md line 389, "the task store is host records").
- the_live_handles_a_gone_process_left_are_settled_and_a_new_task_is_admitted:
  a process fills its host's bound of live work and ends; past the runs'
  lease the next process's task call is refused 503 at the bound instead
  of settling the leftover handles and being admitted (lines 199-202,
  "Admission bounds live work; nothing evicts it").
- a_settle_the_store_refuses_is_made_again_until_it_lands: the store
  refuses two settle writes; the handle stays live for ever instead of
  being settled by a following create.

The rig gains what the plants stand on: typed rows two rigs share
(Ledger::Rows, with the host's bound of live work), a wall clock the test
moves (the kernel's work book and the door's clock.now alike), and a store that refuses the next N settle writes.
…settled; an owed settle is made again until it lands

Finding 6 [HIGH] (plane-mcp audit), with finding 24 [LOW] in the same code.
BUSBAR-1.6.0.md line 389 (the mcp bullet: "the task store is host
records"), lines 199-202 ("Admission bounds live work; nothing evicts
it"), line 379 (the baseline is current predev behaviour: the tasks/*
answers on one node are unchanged).

Live task state is host records (door_tasks.rs, tool_tasks.rs):
- Every unit that moves a live task writes its live state - status, last
  update, inputRequests in order, answers, the upstream ask it is parked on
  (RelayPark), the round of its own asks - to the plane's task records in
  chunks (`{id}~/nnnn`, tool_tasks::live_parts), riding the write it makes
  anyway: the continuation's call (the far request), its park, the
  tasks/update ack.
- tasks/get, tasks/update and tasks/cancel resolve a task from the host's
  rows on every node and across a restart: work.find, then the live state
  (live handle) or the row and result chunks (settled handle). A live
  handle no longer answers "unknown" because this process holds nothing
  of it. What the instance holds is a cache of those rows plus its own
  halves (the run taken here, the unit running it, a settle owed).
- A task parked on its own ask round no longer waits in-process: the
  continuation ends with the handle live (as the relayed ask already did)
  and the tasks/update that answers the round, on whichever node, nests the
  resume (`resume: <round>`, its one-time claim `task-run:<id>/<round>`).
  Step::Wait, which only that wait used, is deleted.

Leftover live handles are settled (§1):
- Each live task is indexed under a digest of its caller with its run's
  lease (tool_tasks::Lease: taken at create, renewed with each call that
  goes out by the server's timeout plus RUN_LEASE_MS; 0 while parked on
  the caller). A task-creating call reads its caller's index and, before
  work.open, settles `cancelled` every live task no unit here runs whose
  lease lapsed or that nothing moved past the abandonment ceiling. From a
  submit, never a read or a timer.

Settles are no longer fire-and-forget:
- A settle that does not land (the create's sweep, a continuation the host
  would not nest, a failed retry nest, a cancel) leaves its task held
  unsettled; the next create's sweep settles it again until it lands. A
  landed settle strikes the task's live chunks and index row.

Finding 24: Task::deliver on a terminal task is a no-op (acknowledged,
nothing changed).

Judgment calls: work.find is scoped to the caller's principal, so a create
settles the leftover handles of its own caller only. A run's lease is the
only liveness the plane can read across processes; a run held past its
lease by another node is settled `cancelled` and that run's own settle is
then refused, as when tasks/cancel wins.

Unit tests (src/tests/tasks.rs): the live state reads back into the same
tasks/get answer; a shorter state over a longer one; the lease and the
abandonment rule; an update to a terminal task changes nothing.
…e, so the loader accepts it as a refused arrival

Spec: BUSBAR-1.6.0.md 199-201.
…d-frame lease skips the frame's rest; Frames reads a message once

Three plants, each failing on the unfixed tree by assertion (all compile against it):

- finding 5 [HIGH, SECURITY] (src/tests/tool_program.rs each_callers_ask_reaches_only_that_caller):
  two callers A and B on one stdio child, the child asks each for a sampling. The stand-in door
  keeps the child's line of relayed calls (`open`, arrival order). First-reader-wins
  (`peer.claim`) hands A's ask to B's exchange, which reads it first. Asserted: A's ask reaches
  only A, B's only B, neither is refused; an ask raised with no call in the line is refused once
  (`ask_unattributed`). Law 11 (spec 2125-2132): an ask is relayed down the session it belongs
  to, as-is.
- finding 13 [MEDIUM] (busbar-core-connector program_tests a_lease_opened_mid_frame_reads_from_the_next_frame):
  a lease opened while the program is part way through one frame reads that frame's rest as its
  first bytes. The test framer gains a `piece` knob so one frame arrives in several pieces, as the
  stdio line framer cuts a line its sink cannot hold.
- finding 14 [MEDIUM] (tests/alloc_gate.rs a_childs_message_read_in_small_pieces_is_parsed_once):
  a 2000-item message pushed in 64-byte pieces; Frames::push re-parses everything held per piece,
  so the allocation count is quadratic. Asserted: under 20 per item. The no-blocking rule (spec
  1276-1283): bounded work on the worker.
… tests stay deleted (finding 12); predev's refusal_words class table lived only in that unserved impl, so the xtask refusal-collapse scan drops its mcp row
…gotiator, through the door

tests/sessions.rs drives the MCP door over its own ABI under stand-in host services and a
stand-in connector (two upstreams: one that requires a session, one stateless) and asserts
THE DESIGN section 2 mcp bullet (docs/design/BUSBAR-1.6.0.md lines 379-390), finding 1 of the
plane-mcp audit:

- a 2025-06-18 initialize answers its revision and an Mcp-Session-Id of 128 bits; a request in
  that session is served and lowered (no stateless-only members);
- a session presented by another owner is 404 on POST and DELETE; the owner's DELETE ends it;
- a GET naming no revision opens the 2024-11-05 stream with its endpoint event, a message POSTed
  to the address is 202 and answered on the stream; a GET naming a revision, a plain GET and a
  DELETE with no session are 405;
- an upstream that refuses the stateless revision and requires initialize is reached by
  negotiation (and re-initialised when it forgets the session); a stateless upstream sees the
  stateless request exactly as the dialect builder writes it, with no handshake;
- subscribe stays for the old revisions (line 380): a 2025-06-18 session's resources/subscribe
  hears the announcing upstream's notifications/resources/updated on its GET stream.

Fails on the unfixed tree by assertion: every non-POST claim is refused 405 and initialize is
refused -32602.

src/tests/session_tests.rs plants finding 18: a push whose trim frees more than its own cost
underflows `cost - freed` (tool_sessions.rs push), a panic under overflow checks.
…oth directions; the session table's byte account never underflows

Finding 1 (plane-mcp, HIGH). THE DESIGN section 2, the mcp bullet (docs/design/BUSBAR-1.6.0.md
lines 379-390), wired on the served path through a new door child, src/door_sessions.rs:

- Inbound on the endpoint's three claims: a POST carrying the stateless marker, or naming neither
  a session nor initialize, is the stateless path untouched (adapt::classify_post); initialize
  opens a session in the revision negotiation picks (revision::negotiate; no revision config), its
  id 128 bits from the host's random.fill, bound to its owner {principal, credential} = the
  kernel's caller reference (derived from the key id) or "<ungoverned>"; any other owner, unknown,
  ended or expired id is 404 on every path (POST, GET, DELETE, the 2024-11-05 message address);
  a dispatched session method is raised (adapt::raise, with the header and parameter mirror) into
  the one dispatch and lowered after it (adapt::lower_result); an MCP-Protocol-Version that
  disagrees with the session is 400; DELETE ends the owner's session.
- GET: with a session, that session's event stream (resumed after Last-Event-ID from the table);
  with none and no MCP-Protocol-Version, the 2024-11-05 stream whose first event names the message
  address (adapt::endpoint_event), its answers delivered on the stream and its POSTs answered 202
  (revision::sessionless_get); a GET naming a revision, a GET accepting no event stream and a
  DELETE naming no session are 405 (lines 387-390). The streams are held as K6 sessions on the
  door's existing drive/tick machinery (door_listen).
- Sessions are this process's; per-owner session and byte quotas are tool_sessions::Bounds; the
  ungoverned chain's single owner isolates nothing, and the instance's first 2024-11-05 stream
  says so once as the declared diagnostic mcp-legacy-stream-ungoverned (lines 385-387).
- Subscribe stays for the old revisions (line 380, lane-lead ruling): a session's
  resources/subscribe, resources/unsubscribe and logging/setLevel are answered from its own state
  under a per-owner subscription cap; an upstream's notifications/resources/updated (on the event
  stream it answers a relayed call with, or from a stdio child) reaches every watching session's
  GET stream after the subscriber's entitlement is re-asked; its notifications/message reaches the
  caller's session past that session's level floor. initialize declares resources.subscribe and
  logging on every session revision.
- Outbound (client::negotiate on the served path): the walk's first hop is the stateless request
  byte for byte as before (the predev fence), or, to an upstream busbar holds a session with, that
  request lowered into it; a refusal moves the client ladder over the door's own connector
  (initialize, notifications/initialized, the lowered request), and a session the upstream forgot
  (404) is re-initialised once. Verify-on-call's tools/list negotiates the same way. An upstream
  that answered the stateless revision is remembered (tool_sessions::UpstreamTable) and never
  renegotiated; 401/403/407/429 are not revision signals. The ladder's last rung (the 2024-11-05
  event stream as a client) is not carried: an upstream that refuses both the stateless request and
  initialize fails the call with an upstream-failure answer naming the revision.
- The line carrier's initialize negotiates too (line.rs): a session revision a client asks for is
  answered in it and the carrier session's following lines are raised and lowered.
- The prose that claimed ONE revision is rewritten (codec.rs PROTOCOL_VERSION, checks.rs
  SUPPORTED_PROTOCOL_VERSIONS, which stays the stateless dispatch's data.supported so the stateless
  path's bytes do not move, door.rs 405 words, docs/mcp.md).

Finding 18 (LOW): tool_sessions push releases freed - cost when a trim frees more than the pushed
event cost, instead of underflowing cost - freed.

An unconfigured node claims no /mcp route, so its GET /mcp stays the 1.5.5 404.
…initialize negotiation (Era::Opened, the raised line) re-applied on L's carrier, which refuses logging/setLevel and resources/(un)subscribe with -32601 and declares neither in any revision it speaks; the subscription uri bound moves to door_sessions.rs, where the session revisions keep subscribe
…a lease reads whole frames; Frames reads each byte once

Finding 5 [HIGH, SECURITY]: a request over stdio names no call it serves (no related-request id on
the wire; the progress token is never echoed; the child numbers its own ids), so the door makes
attribution unambiguous by SERIALISING (lane-lead ruling): calls to a member whose grants let its
asks be relayed reach its child one at a time, in arrival order (door_program `Relaying` line,
`in_line`); a call behind waits (Step::Wait, woken when the call ahead leaves, or at its own
`timeout:` deadline, then answered as an upstream failure, never sent: `take_turn`). A call whose
asks went to its caller holds its place until its retry takes it up or the ask's state TTL lapses
(`ProgramRelay::hold`). The ask is the call's first in line (`first_in_line`, `Peer::owner`,
decided once by the first exchange to read it); an ask raised with no call in line is refused
once (`-32001` `ask_unattributed`). Law 11, spec 2125-2132.

Finding 13: busbar-core-connector program.rs: a lease opened mid-frame skips that frame's rest.
Finding 14: tool_program.rs Frames scans only new bytes and parses a value once, when whole
(spec 1276, 1283).
@MattJackson MattJackson added fixing and removed fixing labels Oct 10, 2026
…, re-pin the scan floors this stack moved, keep the law0 row unarmed

- door_steps.rs: the Clocked wrapper's work_settle takes and forwards `unit: Option<u64>`
  (HostServices::work_settle has six parameters since 82a9904); fixes E0050/E0061 in
  build:check, build:clippy, build:workspace-compile and every test row that compiles busbar.
- population::FLOOR 941 -> 940 and tracing::SCAN_FLOOR 971 -> 970: this stack deletes
  busbar-plane-mcp's tool_plane.rs and outputschema.rs and adds door_sessions.rs, a reviewed
  net removal of one non-test file; the blocking-ffi, response-header, settings-leak and tracing
  scan-floor rows and their selftest plants read the floor against the measured count.
- kind-isolation law0: restore predev's busbar x transport ceiling (208) and keep the word
  "stdio" in mcp_stdio_serve.rs's rewritten comment. Lowering the ceiling re-arms the whole
  law0 row, which is red on predev for cells this branch does not touch (busbar x
  instance:secret 37/35, plane 824/822, vendor 90/89, plugin-loader x transport 190/186,
  kernel x plane slack), so it can only arm red; leaving it at predev's ceiling with slack
  would raise the figure. The cell stays at predev's measure and predev's ceiling.

Not proved on a Latchkey runner: the run budget (RUN_CAP) is spent; the PR's CI is the proof.
Reasoned from run 38095165215 (law0 figure 11 at the candidate, 12 at the base re-measured
under the candidate's ledger, so the base under its own ledger is 11).
…s predev's floor_plant wording at this stack's measured 970 (check not run on a runner: RUN_CAP spent)
@MattJackson MattJackson added fixing and removed fixing labels Oct 11, 2026
…is stack's measured 940

The one conflict, xtask/src/gates/population.rs, is resolved keeping both sides: predev's
one_file_short plant wording, and #703's floor of 940. Predev's 94 new commits add no non-test
.rs under crates/ (only crates/busbar/tests/oidc_needs_operator_infrastructure.rs), so the merged
population is the stack's 940 (tool_plane.rs and outputschema.rs deleted, door_sessions.rs added);
predev's 941 would leave the floor row red on this tree. Ruling: BUSBAR-1.6.0.md:2092, a census
floor pins at today's measured value.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant