Repository navigation
Conversation
Adds the two things dependents have been getting from libforge/testutil that this package did not have: Must2, the two-value form of Must, and six fixed identities (Alice, Bob, Carol, Mallory, Service, WebService) for tests that need stable DIDs rather than fresh random ones. Every other symbol libforge/testutil exports is already a re-export of this package, so with these in place dependents can import ucantone/testutil directly. The identities are the same throwaway ed25519 keys libforge's fixtures use, so tests that hard-code their DIDs keep passing after switching import paths. WebService is Service under a did:web identity. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
Moves libforge's ucan package (Go package name ucanlib) into ucantone. It is the invoker-side counterpart to validator: validator walks a proof chain already attached to a token and checks it; ucanlib searches a delegation store and assembles one — DelegationMatcherFunc, ProofChain, ProofStore, and the container-backed ContainerProofStore — in the order an invocation's prf list expects. Both traverse the same Container type from opposite ends, so they belong in the same module. The directory is ucanlib rather than ucan (the package's own name, and ucan/ is taken here). Source is byte-identical to libforge's apart from a package doc comment and the import paths in the tests, which now use this module's testutil for the fixed identities they rely on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
github.com/fil-forge/forge/protocol carries what libforge published as the network's wire contract, taken from libforge main (81372e7) plus its feat/hilt-s3-client branch (928cf2a, libforge PR #52): commands/** (every command binding except ucan/attest, which belongs with attestation), blobindex, receipt, retrieval (was ucan/retrieval), and the two small helpers they depend on, bytemap and digestutil. Import paths change from github.com/fil-forge/libforge/<pkg> to github.com/fil-forge/forge/protocol/<pkg>; the code does not, with one exception: commands/s3/bucket/errors.go is hilt main's newer copy of the bucket error sentinels (it adds ErrBucketAlreadyOwned), not PR #52's. The module depends only on ucantone and third-party libraries — on none of the other in-repo modules — so anything can consume it. ucantone is pinned to the branch that took libforge's ucan package (fil-forge/ucantone#57); re-pin to main once that merges. Codecs are generated (cbor-gen + dag-json-gen): `make gen` regenerates, `make codegen-build gen-check` is the CI gate. Both pass here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
github.com/fil-forge/forge/protocol carries what libforge published as the network's wire contract, taken from libforge main (81372e7) plus its feat/hilt-s3-client branch (928cf2a, libforge PR #52): commands/** (every command binding except ucan/attest, which belongs with attestation), blobindex, receipt, retrieval (was ucan/retrieval), and the two small helpers they depend on, bytemap and digestutil. Import paths change from github.com/fil-forge/libforge/<pkg> to github.com/fil-forge/forge/protocol/<pkg>; the code does not, with one exception: commands/s3/bucket/errors.go is hilt main's newer copy of the bucket error sentinels (it adds ErrBucketAlreadyOwned), not PR #52's. The module depends only on ucantone and third-party libraries — on none of the other in-repo modules — so anything can consume it. ucantone is pinned to the branch that took libforge's ucan package (fil-forge/ucantone#57); re-pin to main once that merges. Codecs are generated (cbor-gen + dag-json-gen): `make gen` regenerates, `make codegen-build gen-check` is the CI gate. Both pass here. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
| Service = multikey.KeyIssuer(service) | ||
|
|
||
| // did:web:test.storacha.network | ||
| webServiceDID, _ = did.Parse("did:web:test.storacha.network") |
There was a problem hiding this comment.
Maybe we should use example.com
There was a problem hiding this comment.
[From Claude:]
Agreed, and done in 3456649 — did:web:example.com and https://example.com.
You were pointing at a convention this fixture broke rather than a preference: did:web:example.com already appears 21 times in this tree against these 2. The fixture carried test.storacha.network over from libforge, where it was both a real domain and the old branding.
Checked before changing it, because the PR body promises dependents' hard-coded DIDs keep passing: nothing compares the literal. testutil.WebService and testutil.TestURL are used in piri's ucanhandlers suites and in indexing-service's contentclaims and blobindexlookup tests, always as values. The exact string did:web:test.storacha.network appears nowhere outside this file in ucantone, forge, guppy or indexing-service. The *.test.storacha.network hits a grep does turn up are different hostnames doing a different job — guppy's forge-test preset and piri's register test point at real staging endpoints, not at this fixture. The ed25519 keys are untouched, so that promise only ever concerned them.
Two up.storacha.network references remain in did/did_test.go. They are pre-existing and outside this diff, and they exercise DID method parsing rather than standing in as a service identity, so I left them.
make ci passes — build, codegen-build, gen-check, test.
Generated by Claude Code
| // invocation's "prf" list expects. This is the search-and-assemble | ||
| // counterpart to package validator, which walks a proof chain already | ||
| // attached to a token and checks it; ucanlib builds one from scratch. | ||
| package ucanlib |
There was a problem hiding this comment.
Is there a better place for these or a better name for this package?
There was a problem hiding this comment.
[From Claude:]
Fair — ucanlib is a bad name, and it is a bad name for a bad reason: it is what the package was called in libforge, where the directory could not be ucan/ either. I carried the name across rather than choosing one. Not changing it unilaterally, since this is a naming decision for the module rather than a defect; a proposal and the tradeoff instead.
Proposal: a top-level proof/ package. It sits beside validator/ as the counterpart the doc comment already claims it is — validator walks a chain that is attached to a token, this assembles one from a store — and the names stop stuttering:
| now | proposed |
|---|---|
ucanlib.ProofChain |
proof.Chain |
ucanlib.ProofStore |
proof.Store |
ucanlib.ContainerProofStore |
proof.ContainerStore |
ucanlib.DelegationMatcherFunc |
proof.MatcherFunc |
The alternative placement is under the existing tree as ucan/proof/, next to ucan/delegation and ucan/invocation. I'd argue against it: everything under ucan/ is a token type or a piece of one, and this is a search over a store, which is a different kind of thing. validator/, execution/ and binding/ are all top-level for that reason.
The timing argument, which is the part worth acting on. Every consumer of these symbols is changing its import path anyway in this migration — libforge/ucan is being retired and dependents move to ucantone. So a rename costs them one extra token per line they are already editing. Once they have migrated, the same rename is a breaking change to a published module with the blast radius AGENTS.md describes. This is the cheapest this decision will ever be, so it is worth settling now rather than filing.
Happy to push the rename to this branch if you and @Peeja like proof/; equally happy to leave ucanlib if you'd rather not spend the churn, in which case I'd at least drop the Proof prefix from ProofChain/ProofStore — that stutter is there regardless of what the package is called.
Generated by Claude Code
There was a problem hiding this comment.
Let's do proof, I think that resolves the names nicely.
…the repo Review feedback from alanshaw. These fixtures came across from libforge with `did:web:test.storacha.network` and `https://test.storacha.network`, which is both a real domain and the old branding. This repository already uses the RFC 2606 reserved domain everywhere else: `did:web:example.com` appears 21 times in the tree against these 2, so the fixture was the outlier. Safe to change because nothing compares the literal. Every consumer goes through the symbol -- `testutil.WebService` and `testutil.TestURL` are used in piri's ucanhandlers suites and in indexing-service's contentclaims and blobindexlookup tests, always as values, never as a hard-coded string. The exact DID `did:web:test.storacha.network` appears nowhere outside this file in ucantone, forge, guppy or indexing-service. The `*.test.storacha.network` hits those greps do turn up are different hostnames serving a different purpose: guppy's `forge-test` network preset and piri's register test point at real staging endpoints, not at this fixture. The PR body's promise that dependents' hard-coded DIDs keep passing was therefore about the ed25519 keys, which are untouched; only the did:web identity and the URL move. Two `up.storacha.network` references remain in did/did_test.go. They are pre-existing, outside this PR's diff, and they test DID METHOD PARSING rather than standing in as a service identity, so they are left alone. make ci passes: build, codegen-build, gen-check and test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
[From Claude:]
Two additive commits that let libforge's
ucanandtestutilpackages be retired as part of consolidating libforge into the forge monorepo. Nothing existing changes; the full module builds, vets and tests clean standalone (GOWORK=off).ucanlib/— invoker-side proof chain assemblylibforge's
ucanpackage (Go package nameucanlib) moved here asucanlib/. It is the invoker-side counterpart tovalidator/:validatorwalks a proof chain already attached to a token and checks it;ucanlibsearches a delegation store and assembles one, in the order an invocation'sprflist expects —DelegationMatcherFunc,ProofChain,ProofStore, and the container-backedContainerProofStore. Both traverse the sameContainertype from opposite ends, which is why it belongs in this module rather than in a Forge-specific library.The directory is
ucanlib(the package's own name) becauseucan/is taken here. Source is byte-identical to libforge'sucan/proof_chain.goanducan/proof_store.goapart from a package doc comment; the tests differ only in import paths.Deliberately not included from libforge's
ucan/directory:ucan/retrieval(an HTTP transport binding used by Forge services, staying in the monorepo) anducan/zapucan(depends ongo.uber.org/zap, which this module's dependency policy excludes).testutil/—Must2and fixed identitiesEvery symbol
libforge/testutilexports is already a re-export of this package except two things dependents actually use:Must2(the two-value form ofMust) and six fixed identities —Alice,Bob,Carol,Mallory,Service,WebService— for tests that need stable DIDs. Both are added here (same throwaway ed25519 test keys as libforge's fixtures, so tests that hard-code the DIDs keep passing after switching imports). With these in place, dependents can importucantone/testutildirectly andlibforge/testutilcan be deleted rather than moved.Verification
AGENTS.mdgained a bullet for each addition. No other files touched.Part of the forge consolidation; the forge PRs that consume this pin
github.com/fil-forge/ucantone@v0.0.0-20260904190501-7fca40e13941(this branch's head) and should be re-pinned tomainonce this merges.🤖 Generated with Claude Code
https://claude.ai/code/session_01CGAGAib517Ae1kg8SCdcEt
Generated by Claude Code