Skip to content

feat(stack): delegate blob/release + blob/reject from piri nodes to upload - #19

Draft
frrist wants to merge 1 commit into
mainfrom
frrist/fil-588-blob-remove-v2
Draft

feat(stack): delegate blob/release + blob/reject from piri nodes to upload#19
frrist wants to merge 1 commit into
mainfrom
frrist/fil-588-blob-remove-v2

Conversation

@frrist

@frrist frrist commented Jul 17, 2026

Copy link
Copy Markdown
Member

Mirrors piri's registration delegation list for the blob-removal chain, per the blob-removal RFC (fil-one/RFC#13): each piri node delegates /blob/release (the provider-rooted claim release the upload service forwards when translating a client /blob/remove) and /blob/reject (retires a parked, never-accepted blob — the node half of a client /blob/abort) to the upload service, alongside allocate/accept. Rebased onto main (post-Hilt); libforge pinned to the fil-forge/libforge#49 merge commit for the /blob/release binding.

Landing order

fil-forge/libforge#49 (merged) → fil-forge/piri#30 (piri serves /blob/release + /blob/reject) → this — the delegations name capabilities piri only serves on #30 (harmless to older piri, useless without it).

Same chain: fil-forge/sprue#33 (upload-service handlers), fil-forge/ingot#40 (S3 surface — repins its smelt dep to this once merged).

🤖 Generated with Claude Code

@frrist frrist self-assigned this Jul 17, 2026
frrist added a commit to fil-forge/ingot that referenced this pull request Jul 17, 2026
CI has no sibling smelt checkout; pin the pushed branch commit
(fil-forge/smelt#19, 2718317) instead. Bump to the merge commit when
that PR lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@frrist frrist changed the title feat(stack): delegate blob/remove + blob/reject from piri nodes to upload feat(stack): delegate blob/release + blob/reject from piri nodes to upload Jul 24, 2026
frrist added a commit to fil-forge/libforge that referenced this pull request Jul 27, 2026
Splits the provider leg out of `/blob/remove` into a new `/blob/release`
binding, per the blob-removal RFC
([fil-one/RFC#13](fil-one/RFC#13), merged):
`/blob/remove` and `/blob/abort` are now space-subject client verbs
whose arguments no longer carry the space (it is the invocation
subject), while `/blob/release` carries `{space, digest}` under the
provider subject, matching `/blob/allocate` and `/blob/accept`. Cause
references say `/blob/add` throughout — the `/space` command prefix died
with the UCAN 1.0 transition.

Defines the RFC's named errors where every service can share them:
`BlobAccepted` (reject refused because **the invoking space** accepted
the blob — the guard is space-scoped, not digest-scoped, so another
tenant's acceptance never strands a parked allocation) and
`MissingCause` (abort's cause is missing or doesn't resolve to a known
`/blob/add` task).

## Landing order

**This PR is the root of the removal chain** — fil-forge/piri#30,
fil-forge/sprue#33, fil-forge/smelt#19, and fil-forge/ingot#40 all pin
this branch's head (`3e5e6ba`) and re-pin to the merge commit once this
lands.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
frrist added a commit to fil-forge/sprue that referenced this pull request Jul 27, 2026
…(FIL-522) (#33)

Serves the upload-service half of blob removal, aligned with the
blob-removal RFC
([fil-one/RFC#13](fil-one/RFC#13)):

- `/blob/remove` (subject = the space, args `{digest}`) — releases a
space's claim on an accepted blob: recovers every provider holding it
(primary via the registration's receipt chain, plus non-failed
replicas), forwards a provider-rooted **`/blob/release`** `{space,
digest}` to each (best-effort), and deregisters last so the receipt
chain survives for a retry if every forward fails.
- `/blob/abort` (subject = the space, args `{digest, cause}`) — abandons
a parked (never-accepted) blob: the provider is recovered from the
cause's receipt chain and the abort is forwarded as `/blob/reject`. A
cause that doesn't resolve to a known `/blob/add` task fails with the
named error `MissingCause`; a node refusing because the space accepted
the blob has its `BlobAccepted` re-surfaced in the abort receipt, so
clients can distinguish "use `/blob/remove`" from a retryable fault. No
local state mutates, so aborts are safely retryable.
- `/upload/remove` (subject = the space, args `{root}`) — deletes the
upload's root→shards index entry only. Shard blobs are the client's
per-digest `/blob/remove` decision (content addressing shares shards
between uploads).

All handlers are idempotent (unknown/already-removed → success). Named
errors come from libforge, shared with piri.

## Landing order

fil-forge/libforge#49 (`/blob/release` binding + named errors; pinned at
its branch head, re-pin on merge) → fil-forge/piri#30 (piri serves
`/blob/release` + `/blob/reject`) → **this** — the forwards here invoke
piri capabilities that only exist on #30.

Same chain: fil-forge/smelt#19 (devnet delegations), fil-forge/ingot#40
(S3 surface). Validated end-to-end by ingot's delete-finality and
deferred-multipart itests against piri #30 + this branch.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
…pload

Mirrors piri's registration delegation list for the blob-removal chain
(fil-one/RFC#13): each node delegates /blob/release (the provider-rooted
claim release sprue forwards when translating a client /blob/remove) and
/blob/reject (retires a parked, never-accepted blob — the node half of a
client /blob/abort) to the upload service, alongside allocate/accept.
libforge pinned to the fil-forge/libforge#49 merge commit for the
bindings.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@frrist
frrist force-pushed the frrist/fil-588-blob-remove-v2 branch from 2718317 to 0a0154e Compare July 28, 2026 21:04
@frrist
frrist marked this pull request as ready for review July 28, 2026 21:04
@frrist
frrist marked this pull request as draft July 29, 2026 17:05
frrist added a commit to fil-forge/piri that referenced this pull request Jul 30, 2026
… task engine (#30)

Adds the removal half of the blob lifecycle and moves the aggregation
pipeline onto the harmony scheduler. Aligned with the blob-removal RFC
([fil-one/RFC#13](fil-one/RFC#13)).

**Protocol**: `/blob/release` — the claim-release inverse of
`/blob/allocate`, invoked by the upload service translating a client
`/blob/remove` — drops a space's claim on an accepted blob (claim +
acceptance + allocation deleted; bytes released once no space holds an
allocation or acceptance). `/blob/reject` retires a parked blob — the
"don't accept" exit of allocate→accept|reject. Its `BlobAccepted` guard
is **scoped to the invoking space** per the RFC: only that space's own
acceptance refuses the reject; another tenant's acceptance of the same
content-addressed bytes just drops this space's allocation and retains
the bytes (multi-tenant liveness). Both named errors come from libforge,
shared with sprue. The registration delegation grants `/blob/release` +
`/blob/reject` to the upload service. Physical deletion is always
deferred to a sweep that re-verifies claims before every destructive
step.

**Pipeline**: the commp/aggregator/manager jobqueues (and their separate
aggregator_db) are replaced by harmonytask tasks — `PDPCommP`,
`PDPAggregate`, `PDPAddRoots`, `PDPRemoveSweep` — with all state in
harmonydb (`pdp_blob_pipeline`, `pdp_root_submissions`). Stage
transitions are transactional with the tables the removal machinery
inspects, which closes the accepted-blob removal races by construction:
pre-commp rows cancel transactionally, the fold locks its candidates (a
row is either cancelled or folded, never both), staged pieces ride the
root lifecycle, and roots retire on-chain (`schedulePieceDeletions`)
only when every live sub-piece is pending removal.

**Validated**: full suite including a harmonydb-backed (Postgres
testcontainer) regression harness for the removal races — including the
cross-space reject case the RFC mandates; smelt e2e with the injected
binary — upload/retrieve plus the full proving loop through the new
pipeline, proof verified by the PDPVerifier contract.

**Landing order**: fil-forge/libforge#49 (the `/blob/release` binding +
shared named errors; pinned at its branch head, re-pin on merge) →
**this**. Downstream: fil-forge/sprue#33 (upload-service handlers,
forwards `/blob/release`) + fil-forge/smelt#19 (devnet delegations),
then fil-forge/ingot#40 (S3 surface).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: ash <alan138@gmail.com>
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