Repository navigation
Align Directory listing admission with current SDK - #85
randomblocker wants to merge 21 commits into
Conversation
Brings #92-#94 (bounded verification work, owner-keyed deals, malformed artifact containment) under #85's SDK-aligned listing admission. Conflicts, resolved semantically: - store.ts: keep both startup migrations (#85 listing_rejections coordinates; #94 scan_runs omission counters, rejected-retry classes, revocation_candidates table). - chain.ts: keep #94's boundedJson guard on storage reads and #85's extended readback fields (storageAddress, metadata, tx refs). - indexer.ts: #85's admission (verifyListingResult with rejection diagnostics, validity window, `revocation`, transactionReadiness) over #94's bounded, owner-first revocation candidate batch and progress. - reindexCore.ts: #94's design (candidates live in SQLite, not scan state) with the public `revocation` field name. Semantic fixes the clean auto-merge did not cover: - verifyListingResult fails closed instead of throwing, keeping #94's "no canonical form" containment for every caller. - verifyListingRevocation: the pinned SDK's stripSignature now rejects non-canonical JSON, so it moves inside #94's existing guard. - scan.ts: SDK f68fed1 renamed the MVP agreement predicate; use isLegacyMvpAgreementDocument (byte-identical to 44d8ff2's isAgreementDocument that #94 was written against). - #94 tests: legacy listing fixtures use the SDK legacy-MVP string signature, current fixtures carry a DPA-1 verificationMethod, the revocation field is `revocation`, and the depth sweep follows the pinned SDK's 64-level canonical bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verification method: admission already delegates to the pinned SDK's isListing (DACS-4 DPA-1) and isVerificationMethod (closed DACS-2 registry). Pin each failure mode with a test: missing, free-form string, unregistered kind, registered kind with missing or malformed parameters, attested phase on a non-attested deliverable, and an invalid method outside an attested phase. Every registered variant is admitted, and the indexer excludes failures with VERIFICATION_METHOD_INVALID diagnostics while admitting the conforming listing. Transaction readiness: the SDK grants it only through its ordered Listing reader (isVerifiedListingAdmission), which the Directory does not run. Catalog, seller and inspection projections now always publish the Directory's `unassessed` disposition instead of republishing a stored value. Anchor receipt: registration admits a listing only on a receipt that passes the SDK's CORE §5.1 isAnchorReceipt gate, is finalized and established, and binds the exact logical/native address, content hash, writer and transaction. Confirmation tests now also cover the finality-pending and metadata-mismatch paths. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The metadata-mismatch case also broke native/transaction metadata equality, so a mutant dropping the envelopeHash comparison survived. Add the case where both metadata copies agree but neither hashes the anchored listing envelope. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f68fed1 refused Listings that the current SDK and Standard admit: APR-1 pay-alternative pipelines and CORE CF-5 nesting deeper than 64 levels. Move the pin to the current SDK revision. - The modules the Directory loads from the SDK reach only Node builtins at 3904d70, so none of the SDK's six new runtime dependencies is needed by the Directory. - The SDK's ClaimReference parser now reaches the browser bundle and imports node:net and node:url for domain hostnames. Add WHATWG browser shims next to the existing node:crypto and node:util ones, with a parity test against Node. - The signature depth sweep returns to main's 126-level threshold (CF-5 depth 128) and keeps 61-64 as guards against the old bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CORE B.1 CF-3 makes ClaimReference parameters advisory: identity is the scheme and identifier. The SDK's isListing authorizes the signer that way, but the Directory's Demos resolver accepted only the parameter-free form. A Listing signed as did:demos:agent:<key>?channel=x therefore passed the SDK and failed here with LISTING_SIGNATURE_INVALID. claimRef.ts now reads exact CF-2 parameters and returns the parameter-free identity, as the SDK's parseDemosAgentClaimReference does. It mirrors that function instead of importing it because the SDK identity tree loads node:net and this module also runs in the browser; test/claim-ref.test.ts pins parity with the SDK on 35 inputs. Key resolution, signer authorization and seller matching all use the identity, so sellers stay keyed by the parameter-free claim, and registrations still require it. The SDK validation view keeps the parameters and only repairs the scheme token. Cross-version conformance cases, all refused at the previous pin: signed pay-alternative Listings (and SDK-refused incoherent ones), nesting through 128 levels, advisory parameters on each signed role (and non-canonical parameter forms refused). An indexer-level case covers all three and an expired Listing, which had no indexer test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Validate the resolved object directory and reject shared or redirected object stores before fetching. Scope Git path overrides to the selected checkout and exercise the documented workflow across standalone clones and rejected layouts. Co-Authored-By: Codex <noreply@openai.com>
The browser publisher stored the wallet's hex signature as the Listing's signature value. CORE §B.7 SIG-6 defines that value as unpadded base64url, so SDK readers decoded 96 bytes and refused every Listing published through /register, while the Directory's hex-first decoder admitted them. Store base64url (the identity presentation too) and decode a current Listing's signature strictly as SIG-6 Ed25519. Apply isListing to the exact received bytes instead of a scheme-lowercased copy, so an uppercase DID: token inside a signed artifact fails here as it does at the SDK reader's first step. Hex-signed versions now leave the catalog but still occupy their owner-held program names. The publisher steps past up to four such versions so sellers can republish. check:listing-upgrade now verifies signatures and identity presentations against the signer's key instead of comparing the artifact with itself. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An unreadable revocation marker made findValidListingRevocation return null, and the indexer then emitted a fresh `active` summary. SDK readers take that as established revocation absence, so a transient outage could turn a revoked Listing back into a verified one. A revocation this catalog already published now stays in force while its marker cannot be read. When the node cannot serve a verified marker that has no published binding, or a candidate anchored by the listing's owner, the listing is withheld for that pass. Candidates anyone else anchored, and candidates that are absent rather than unavailable, cannot withhold a listing. A new readAnchorOutcome separates node failures (network, 5xx, 429) from answers that hold no artifact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… docs The finalized AnchorReceipt gates only the /register browser flow: registrations do not carry it, POST /api/dacs/register accepts pointer sets from any client, and catalog admission rests on the indexer re-reading and re-authenticating every anchor. Say so in the README and the prepare-registration route comment instead of describing the receipt as a catalog registration requirement. Also document SIG-6 admission on exact bytes, independent verification in check:listing-upgrade, the node:net/node:url browser shims, revocation handling during marker outages and stepping past unauthenticated versions. The local workflow guide now rejects symlinked .git/shallow and FETCH_HEAD and states its Git 2.31 requirement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cX3po
left a comment
There was a problem hiding this comment.
Checked draft head 0b61ec4cc8f1bedbd965520f9f03595c89b41bc5, SDK pin 3904d704fb540e6e1d7dd502a0be29f20569c92d, offline on Node 22.23.3: 305 tests passed, none failed or skipped; typecheck passed.
Using our public arena practice seller's verification-summary title, a shortened description and 0.01 DEM price, I constructed a normative Listing with a disposable Ed25519 identity and the SDK's signComponentArtifact. This is a seller-shaped synthetic Listing, not an export from our standing seller or a claim that its arena practice protocol implements the kit's paid lifecycle.
The baseline was indexed as a catalog candidate with transaction readiness unassessed. The indexer excluded all five variants: a non-Demos claim scheme (LISTING_SIGNATURE_INVALID, cause not isolated), missing price (NORMATIVE_LISTING_INVALID), expired validity, a different signing key (LISTING_SIGNATURE_INVALID), and a description exceeding 256 KiB. Expiry passed signature validation; the indexer excluded it without a rejection diagnostic, and its exported validity predicate returned false. The oversized artifact was excluded without a diagnostic and failed the read-path byte bound. Those last two causes are inferred from the measured predicates, not emitted diagnostic codes. A string verification method was refused with VERIFICATION_METHOD_INVALID; structured {kind:"self-signed"} passed. If a seller emits a string method, this SDK pin refuses that Listing; this run did not test generated-kit runtime behavior.
One boundary to clarify: signed acceptedRails[0].parameters containing network:"mainnet", chainId:"ethereum" still entered the catalog as unassessed. These are extension parameters, not proof of actual wrong-chain execution; the malformed claim-scheme probe does not establish network refusal. Is network selection intentionally left entirely to the SDK reader/rail policy? I cannot confirm general wrong-chain rejection from this run.
The public testnet RPC root returned HTTP 502 at 18:36 UTC on October 14. Storage responses were mocked, with outbound networking disabled during tests; no anchor was published and no live seller, finality, runtime capability or payment flow was tested. This is a COMMENT on a draft.
— PATH-OS (cX3po)
…zation DEMOS-MAPPING A.2 gives an ordinary storage API not-found the SR-2 disposition indeterminate, and DACS-1 RB-6 makes transport failures and integrity mismatches indeterminate too. readAnchorOutcome now reports every read that yields no readable artifact (404, any non-2xx, a failed or malformed body, a response without an artifact object) as unavailable, so a known verified marker or an owner-anchored candidate withholds its listing instead of letting it be republished active. Adds RB-1/RB-4 vectors for markers whose signature object, algorithm, signer, value, listingId, listingVersion or content hash is wrong, a marker carrying a reason, and a prior binding that must stay with the listing it revoked. malformed-artifacts now clears queued candidates between tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The publisher used phase-handler names (pay-dem, pay-x402) as rail IDs, so readers resolving the DACS-4 9.4.2 registry rejected its Listings as unknown-rail. It now emits demos-native:DEM and x402:default with their registered handlers, accepts the registry grammar on input, and the catalog projection keeps uppercase registry IDs for the 6.3.6 rail filter. rail-registry.test checks the table against an independent copy of the pinned Standard's registry and resolves a /register-built Listing against it. build-listing adds vectors that refuse a transaction for an invalid listing signature and allocate versions per listingId. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- hash the identity presentation over the SDK's identityBundleHash - publish RevocationBindings with the exact presentedBy bytes - fall back to block one when a node answers block zero with an error, read a known transactionRef by hash, and normalise JSON-string signatures so receipts carry the SDK's signed-transaction proof hash - require the node's validator-signature shape and a 64-hex block hash; validator signatures and quorum are still not verified - use Node's IPv6 zone grammar in the browser isIP shim Tests use node2-shaped fixtures and pin the presentation-kind, injected key-resolver and identity-comparison branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
setup-sdk.sh accepts a packaged SDK build only when it carries the pinned commit marker the source build writes, checks the source checkout is a clean HEAD at SDK_REV, and on both paths requires the SDK to declare the pinned Standard revision. Public Standard links name that revision instead of main, and the README scopes the rail and finality claims. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Align Directory listing admission with current SDK
Head:
d0da471(branchwork, basemainatd1de29d)Summary
dacs-sdk3904d704fb540e6e1d7dd502a0be29f20569c92d, which declares DACS-Standardd45c0a292006b2fd2e40d2dbe0cd7ed518ad0f20(dacs.standardRevision), and use the SDK's normative Listing shape/signature and current publication/reader gates.scripts/setup-sdk.shnow refuses an SDK build that is not marked as built from that commit, or that declares another Standard revisionisListingaccepts it, including DACS-4 DPA-1: anattested-payloadpipeline needs a structuredverificationMethodfrom the closed DACS-2 registry (isVerificationMethod); failures are excluded with the publicVERIFICATION_METHOD_INVALIDdiagnostictransactionReadiness.disposition = unassessed. The SDK grants readiness only through its ordered Listing reader (isVerifiedListingAdmission), which the Directory does not run, so the catalog, seller and inspection projections always publish that disposition and never republish a stored onedemos-native:DEM,x402:default,ap2:stripe-paymentintents) with their registered phase handlers, resolved through this release's disclosed PA-1 in-code table (pa1-in-code). The pinned Standard publishes the v0.1 registry as a table, not as signed definitions, so this is not a canonically anchored result. Refuse attested-payload publication when the browser cannot prove the seller runtime's DPA-1 production capabilityAnchorReceiptin the SDK's portable Demos form before catalog registration. The receipt must pass the SDK's CORE §5.1isAnchorReceiptgate, befinalized/established, and bind the exact logical/native address, content hash, writer and transactionnot found, a failed body read, or a response without an artifact as indeterminate (DEMOS-MAPPING §A.2, DACS-1 RB-6): a known verified or owner-anchored revocation marker that cannot be read withholds its listing instead of letting it be republishedactiverevocation(CatalogListingSummary.revocation), carrying the exactpresentedBybytes RB-2 compares, migrating persistedrevocationBindingsummaries onceMerge with main (#92–#94)
mainnow carries bounded verification work, owner-keyed deals, separate retry classes and malformed-artifact containment. This branch keeps that design and applies the admission changes on top:revocationWhy
The live Directory accepted current-looking Listings whose
offering.deliverable.verificationMethodwas a string, while the current Standard and SDK require a registered structured variant. Those candidates could be discovered but were rejected by an independent SDK buyer before payment.mainstill checks only thatoffering.deliverableis an object.Catalog admission is also narrower than transaction admission: the Directory can authenticate Listing shape, identity, signatures, hash, owner, and revocation observations, but it does not possess every buyer/session policy or runtime capability. The public contract now says that explicitly rather than calling candidates transaction-ready.
The prior browser flow could build a pay-bearing Listing without SDK rail/payload publication gates and register it after read visibility alone. It also did not show the exact server artifact before its Listing signature.
Scope and limits
finalizedreceipt rests on the configured Demos node's report. The node endpoint and build are not pinned.acceptedRails[].parameters(for example anetworkorchainIdan artifact signs). Network and chain selection stay with the transacting SDK: under DACS-1 LRR-6 the orchestrator selects and pins one completePaymentRailRefat session start and applies RAV-R1..RAV-R5. Catalog discovery is never transaction permission (transactionReadiness: unassessed). The Directory's own publisher emits only registry rail IDs without parameters.Impact
After deployment and reindex, malformed current Listings are observed but excluded from the active catalog with stable seller-facing diagnostics. Existing valid candidates remain discoverable but are explicitly marked transaction-readiness-unassessed.
Catalog JSON consumers that read
revocationBindingmust readrevocation(the SDK's §6.3.6 name; the SDK catalog client rejects a revoked summary without it).Listings previously published through
/registernamedpay-dem/pay-x402as rail IDs, which registry-resolving readers reject; their sellers should publish a new version from/register. New browser-published storage-program and entitlement Listings use registry rail IDs, are signed exactly as previewed, and are registered only after finalized write evidence plus independent content verification. Attested-payload sellers must use their current SDK runtime so the exact production method can be proved before any payment-bearing publication.An existing deployment that uploads a prebuilt SDK (
railway up . --no-gitignore) must rebuild it once withnpm run setup(or the documented local workflow) sovendor/dacs-sdk/dist/.dacs-sdk-revisionexists.The three existing x402 Listings remain excluded until their sellers publish conforming newer versions. This PR does not loosen the SDK, publish those replacement artifacts, deploy/reindex Community, or make the Directory depend on a gateway.
Deployment acceptance
After the three sellers publish replacements and the deployment is reindexed:
NEXT_PUBLIC_DIRECTORY_URL=https://directory.example \ DACS_LISTING_UPGRADE_REPLACEMENTS='[...]' \ npm run check:listing-upgradeThe command is read-only: it never contacts a gateway and never writes, reindexes, purchases, or invokes an agent.
SDK packaging note
The current SDK top-level barrel statically re-exports optional rail and substrate adapters, so it is not browser-bundle-safe without unrelated peers. Community imports the required public names through isolated compatibility modules until the SDK publishes safe subpaths.
Validation
Run offline against the vendored SDK at
3904d70on Node 22.23.3:npm run typecheck: passestest/*.test.tsandtest/*.test.mjsfile. Run asnode --import tsx --test --test-concurrency=2in two batches, because the sandbox forbids the tsx CLI's IPC sockettransactionRef, and recovery records that keep it; RB-2 bindings checked by the SDK'scheckListingRevocation; injected key-resolver and identity-comparison boundaries; setup refusal of unmarked or mismatched SDK buildsnpm run buildandnpm run test:e2e: not re-run in this round🤖 Generated with Claude Code