The capability vault checked an issuer's registration and then read it
again to store it, including its nested header rows. A stateful issuer
could show an allowed header set to the forbidden-header check and hand
`Authorization` to the copy, so the vault stored — and the executor sent —
a credential no rule had ever seen. The registration and everything nested
in it is now snapshotted once, and only that snapshot is validated,
frozen and stored.
The upload control plane had the same shape one level down: a `sessionId`
that answered `session_01` to the regex and `../../unsafe` to the result
snapshot reached a success receipt.
Two lifetimes were also unowned. A download source lease that resolved
after the caller's abort never reached the holder, so nothing closed it
and its fetch reader and capability lease outlived the terminal result; a
compensator sharing the holder's close-once latch now closes it exactly
once. And `dispose()` proved quiescence from the wrapper registry alone,
so a provider that ignored its attempt deadline let teardown report a
drained runtime and close the checkpoint store while the provider was
still running. Raw provider promises are now their own registry and the
drain must prove both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
TR-RR-05. The shared abortable-operation primitive now distinguishes VALUE,
REJECTED and TERMINAL, so a collaborator's own rejection is no longer forged
into a cancellation and race() always names the same first owner terminal()
reports. The caller signal and scheduler are captured once, so replacing a
method after construction cannot change how an in-flight operation is bounded.
A scheduler that cannot install the deadline is itself terminal: previously it
released the caller listener and left no owner, which made every later abort
invisible. Late values are compensated exactly once.
Both presigned subsystems, which each carried their own copy of these
mechanics, are now projections of that primitive — giving it real production
importers rather than a shared helper nobody used.
TR-RR-01. close() on an active download aborts the scope instead of only
dropping listeners, so a fetch or read already in flight actually stops. The
consumer's stream signal joins the operation's ownership before any I/O begins,
so an already-aborted consumer no longer causes one network request first.
TR-RR-02. The upload abort scope is created before the digest, and the digest
races the caller and the deadline like every other step. A non-settling hash can
no longer hold put() open, and the vault claim and the network call happen only
after the owner is re-checked.
TR-RR-03. A capability registration is a versioned exact union validated at
registration time: the protocol version, HTTPS only, exact own-data fields, a
2xx expected status, and no ambient credential or cookie header — a presigned
URL carries its own authorization, and a session header alongside it would send
the user's credentials to that origin.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BT-PRE-02: add the top-level PRESIGNED_TRANSFER_V1 protocol literal to the
capability request and response. A missing, V0 or V2 envelope is closed as
POLICY_REJECTED before the vault registers anything. The server negotiates by
request shape; fields are never dual-emitted into a strict decoder, and the
nested PRESIGNED_MULTIPART_V1 binding protocol is unchanged.
BT-PRE-03: aborting a controller does not settle a fetch that ignores its
signal, so both presigned scopes now race the task, cancel a late response body
and survive a throwing scheduler without leaking the external abort listener.
BT-PRE-04: the vault owns its registration invariants, re-checking method,
href/origin/path agreement, embedded credentials, byte bounds, digest shape and
expiry, so a second issuer cannot register a weaker capability of the same type.
BT-PRE-05: decode each path segment once and require it to round-trip through
the canonical uppercase percent encoder, closing %2f, %5c, %252e%252e, mixed-case
escapes and encoded NUL while still admitting valid opaque UTF-8 segments.
BT-UP-02: inject and snapshot the upload transport clock and scheduler, so
Retry-After delta-seconds and HTTP-date resolve against the same captured now
and a clock rollback clamps to zero instead of producing a negative delay.
BT-IMG-01: make the image resolve() lifetime signal required, replacing the
hidden PRIMARY_REQUIRED preset precondition with a type-level one, and add the
negative typecheck fixture and gate that prove it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>