Skip to content

design: specify dispatcher capture retirement and profile integration. #20

Description

@jm9e

Current owner packet — 2026-09-26

The detailed lifetime observations retained below remain the acceptance source. Current implementation ownership is bitruntime #13, not a new nightseam release. Runtime v0.2.0 already includes the public invocation lifecycle; this issue remains open for the observation-by-observation independent integration/disposition, not another primitive rename.

Wire is now addressless, full WireTree supplies structure, and the historical addressed vocabulary in the older record refers to AddressedWire at today's boundary. Naming alone does not discharge capture/body/control authority.

Remaining contract and signoff work

  • Map every original acceptance observation to exact released evidence or a concrete missing owner row; preserve the distinction between bitwire test-only and actual runtime/generated/physical/live/tunnel evidence.
  • Settle any remaining public authority/participation ambiguity through #55, with two independent integrations and an opaque wrapper. No private-context-only exception.
  • Require explicit body ownership/completion, both stale-control races, cancellation latching, bounded depth/fan-out, shutdown and separate live-value lifetime; do not replace these with retained-reply fixtures.
  • Integrations are owned by runtime #13, tunnels #11, live #12 and bitlink #1. Each missing row needs a linked release/evidence disposition before signoff.
  • Publish final current contract/migration notes with immutable native/profile identities and reciprocal owner links. Do not revise historical tags.

Carrier closing/publication guarantees are #54. Raw relay attachment lifetime is separately bitwire-svc #13; the relay does not acquire application invocation admission policy. Generic service design consumes only the applicable public capability/lifetime requirements.

The bounded runtime #1/bitsystem3 #7 milestone can complete with its stated existing-profile coverage; this issue does not silently widen that gate. Coordinator: #47. New code/conformance paths retain component-first two-letter language layout.

Historical issue record (preserved; current execution instructions are above)

Deixis service coordination — 2026-09-25

Related API redesign: #42; service coordinator: https://github.com/Bitspark/deixis-svc/issues/1. Wire A0 is the addressless conveyance primitive and Deixis supplies addressed A1. The API is open to change; the old primitive-preservation wording below is not a fixed premise against that operator direction.

The independently stated lifetime observations remain requirements wherever an endpoint/profile claims invocation-aware routing. Assign capture, cancellation, body completion and retirement to their actual owners in the new layering. They do not require the raw A0 relay to inspect application operations or execute application-level admission policy. Relay resource/attachment lifetime remains its own concern in https://github.com/Bitspark/bitwire-svc/issues/9.

Neither structural Deixis laws nor message relay acceptance alone prove invocation lifecycle conformance. Carry the applicable cases and exact evidence forward explicitly.


Bitwire disposition and executable baseline, 2026-09-22

PR28 is merged at 0f30b515694cb3005403229be0f4e4158baf41b9. ADR0004 resolves the two findings from PR26: callable return Wire access has its own profile-defined path space, and Nightseam's recorded pre-1.0 release-based compatibility disposition is accepted for the exact v0.6.0 baseline, without claiming arbitrary mixed-release compatibility.

The required conformance gate passed: six Bitwire composition observation groups in Go and TypeScript over local pairs and both WebSocket role directions; five independently specified lifecycle cases in each language; separate pinned upstream independent-endpoint, opaque-wrapper, serial, execution-budget and lifecycle tests, including Go races. The historical 0.1 baseline also remains green. All required PR checks passed before squash merge.

This issue remains open. The coverage and remaining-acceptance table keeps generated/live/context acceptance, execution-owner authority, shutdown and asynchronous control drain explicit. The original criteria below are not marked complete merely by this scoped baseline. A downstream domain attachment demonstration is a separate consumer obligation. Published Wire/Endpoint declarations remain unchanged.

Operator requirement: finish the long-term public lifecycle interface now

The operator explicitly requires the correct, conceptually sound long-term interface now. Do not declare this work complete with a private-context-only migration or defer the public integration as optional future work. The detailed requirements are recorded in ADR0003, landed in Bitwire PR21.

  • Preserve the small generic Wire/Endpoint boundary unless a concrete obstruction demonstrates a needed extension. The invocation, not the registration or callback, owns immutable captured routing state per traversal.
  • Deliver a public, explicit, profile-specific lifecycle API and state rules in Go and TypeScript. Construct invocation-aware dispatch with this facility or an equivalent public capability. Private storage is fine; private concrete-type recognition, endpoint unwrapping or an exported lookup that works only with a private native ledger is not sufficient.
  • Include public participation by execution owners/generated binders to report actual body completion. Dispatcher authority to capture/observe must not silently grant authority to finish another owner's work or forge admitted/verified context.
  • Distinguish queue admission, invocation admission, caller withdrawal, fixed outcome, body completion, admitted-control drain and retirement. Capture is race-safe and cancellation latched while nested captures are attached. Repeated traversal of the same dispatcher has distinct capture identity.
  • Prove both identity-reuse races. An already queued control retains its invocation generation; a newly arriving indistinguishable old control cannot be solved by a private generation counter. State the enforceable nonreuse/scope/identity/barrier rule at the actual carrier boundary. A fresh local Return alone is insufficient if physical controls still have the same peer/request ID. Avoid unbounded tombstones.
  • Bound admitted work AND total capture/control cost, including depth and shallow fan-out. Timeout does not release execution capacity while the body runs; RPC retirement does not release returned live values.
  • Before freezing the lifecycle API, exercise two independently implemented same-profile endpoint integrations plus an opaque forwarding wrapper, through only public facilities and without a shared private ledger. Same frame vocabulary alone is not lifecycle participation. Unsupported endpoints have explicit refusal, but refusing every non-native implementation is not evidence of composability.
  • Deliver the small compilable API/state packet and independent experiment before final migration signoff, then actual generated/local/physical/tunnel/live acceptance. Retained-reply fixtures and package publication do not close this concern.

Bitwire 0.2.0 is already public and immutable. That is not a design freeze at the expense of correctness. If evidence requires changing shared public declarations, coordinate a reviewed new version; do not keep a private exception merely to avoid a release, and do not rewrite the existing tag. Any changed physical identity semantics need an explicit compatibility/profile-version decision.

Question and current behavior

How does an invocation-aware dispatcher preserve the receiver captured by an admitted request through detach/rebind, then reclaim that capture within bounded memory, while preserving the exact return-capability identity?

This is a focused follow-up to #18 / #19 and Nightseam #439, filed at the operator's request. The released 0.2 contract from #19 already correctly states that callback return is not invocation completion and that terminal-state ownership belongs to explicit profile integration. This issue records the obstruction, the required integration boundary, and the evidence needed to discharge it. It does not claim a released Bitwire runtime defect or request a competing implementation.

Existing composition and obstruction

Wire supplies send-only access; Endpoint adds one owning receive attachment and closure. Shared sibling/nested receiving views can use one explicit dispatcher. Routing policy can move out of the primitive, but request lifetime cannot be inferred from routing alone:

  1. A dispatcher delivers request R to receiver A. A returns immediately and finishes asynchronously.
  2. A is detached and B is registered at the same path.
  3. A response goes directly through R's original Return.Wire, bypassing the dispatcher. A later cancellation must still reach A, with the original return identity.

From the bare dispatcher interface, an execution where A has already replied and one where A remains active are indistinguishable. Dropping the capture too soon can lose or redirect cancellation; retaining every capture indefinitely leaks memory or exhausts a fixed capacity after enough sequential successful calls. A fixed timeout, callback return, a TypeScript Promise when callbacks may return void, or a weak map does not establish the required terminal lifetime. Wrapping the return capability to intercept replies violates the preservation requirement.

Nightseam's existing implementation obtains this evidence from its runtime, not from the callback:

  • Local admission and captured registration: localWireCall retains the chosen registration; localReturn.Send observes the actual response. Retirement waits until completion and any already queued cancellation has drained. A receiver deadline may answer early while the executing body still occupies its budget.
  • Physical peer dispatch and reply waiter: requestReceiver captures the receiver in a closure; an admitted incoming callWire continues waiting after cancellation until the actual reply.
  • TypeScript registration: registerWire starts a void Promise.resolve() chain, so returning from its callback is explicitly earlier than handler completion.

Alternatives and recommendation

Retain the small 0.2 primitive and document the additional profile integration needed for invocation-aware routing. One shared dispatcher owns routing; the profile/runtime owns admission, captured invocation state, cancellation and terminal retirement. The runtime may store selected-route snapshots in private invocation state, but dispatchers and independent execution owners must participate through an explicit public lifecycle/capture capability. Private storage is an implementation choice, not an alternative to the public integration contract in ADR0003. This need not replace the original return object or add a peer/channel/queue per selected view.

The integration must define:

  • Which boundary captures the route and makes its state available to later cancellation, including nested dispatchers and forwarding.
  • The difference between caller withdrawal, an early deadline response, actual handler completion and final queued-control retirement.
  • Capacity, retirement, shutdown and same-return/request-ID reuse; late controls must not delete or address a newer capture.
  • Behavior for a custom return capability or third-party Endpoint that lacks the implementing runtime's private context. A silently weaker fallback must not claim full capture guarantees.
  • Which guarantees belong to Bitwire's generic composition experiment and which require actual profile/runtime acceptance. Retained replies alone do not prove cancellation routing or bounded reclamation.

No new primitive is prescribed by this issue. If the documented profile seam cannot satisfy these observations, record that concrete obstruction before changing the shared declarations. Implementations remain in their owning repositories.

Acceptance observations

  • Go and TypeScript: a void/early-returning receiver responds asynchronously; detach/rebind does not redirect its cancellation or change its return-capability identity.
  • More sequential successful requests than the configured in-flight capacity reclaim capture state; genuinely unfinished requests remain bounded.
  • A response racing an already queued cancellation and same-key reuse cannot deliver old controls to, or retire, the new invocation. Separately prove that a newly arriving old control cannot address a newer invocation: document enforceable identity scope/nonreuse or a real distinguisher/barrier at each carrier boundary, bounded enforcement, exhaustion and any profile-version change.
  • Receiver timeout may settle the caller early, but an ignoring application body retains its execution budget until completion.
  • Identity-deferred delivery, sibling and nested receiving views, mounts and two-connection forwarding preserve the same ownership and capture behavior.
  • Two independently implemented same-profile endpoint integrations and an opaque forwarding wrapper exercise the public lifecycle facility without shared private ledgers, private concrete-type recognition or endpoint unwrapping. Execution owners report authoritative body completion through the public contract. Unsupported participation is explicit.
  • Nested and repeated traversals preserve distinct captures, cancellation is latched during capture installation, and total retained capture/control cost (including shallow fan-out) is bounded. Shutdown does not prematurely release a still-running body's budget; invocation retirement does not release returned live values.
  • The final 0.2 contract/migration notes identify the profile integration requirement, and the handover links actual Nightseam acceptance separately from Bitwire's test-only composition evidence.

The normative limitation is already acknowledged in the released contract from #19. Keep that statement, settle the profile seam with the Nightseam owner, and close this concern only with the corresponding decision/evidence links or an explicit cross-repository disposition of the remaining implementation checks.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    designA decision about the shared contract or its boundary

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions