Repository navigation
C-04: hide completion and fault rates on testnet (no-rate restriction) - #96
Draft
randomblocker wants to merge 30 commits into
Draft
randomblocker wants to merge 30 commits into
randomblocker wants to merge 30 commits into
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The production-origin check accepted https://localhost, loopback and unspecified IP literals, so a mistyped NEXT_PUBLIC_DIRECTORY_URL could pass the deploy gate and poison canonical URLs, the sitemap and llms.txt. - Reject localhost, *.localhost, *.local, and loopback, unspecified, private, CGNAT and link-local IPv4/IPv6 literals (including IPv4-mapped IPv6). - Require the raw variable to be exactly the origin (optionally with one trailing slash), because directoryBaseUrl() uses it verbatim; values like " https://x ", "https://x?" or "https://X" no longer pass. - Assert the specific error for each rejection, add the password-only credential case, and move CI's directory URL off .local. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-config The deploy-config check rejected loopback, private, CGNAT and link-local literals but still passed other addresses that cannot be a deployment's public origin, such as https://192.0.2.1, https://224.0.0.1, https://[2001:db8::1], https://[fec0::1] or https://[64:ff9b::7f00:1]. It also passed single-label and private-use names (https://directory, https://directory.railway.internal) and names with empty labels (https://localhost..). - IPv4 literals: also reject the remaining RFC 6890 special-use ranges that are not globally reachable (192.0.0.0/24, 192.0.2.0/24, 192.88.99.0/24, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24), plus multicast, reserved and broadcast (224.0.0.0/4, 240.0.0.0/4). - IPv6 literals: accept only global unicast (2000::/3) outside the IETF-protocol (2001::/23, including Teredo), documentation (2001:db8::/32, 3fff::/20) and 6to4 (2002::/16) blocks. IPv4-mapped addresses still follow the IPv4 rules; NAT64, IPv4-compatible and site-local forms are now rejected. - Host names: require at least two non-empty labels (one trailing dot is still allowed) and also reject .internal, .home.arpa and .localdomain. - Tests pin both edges of every blocked range, so each range can neither shrink nor grow, and cover the special-use, transition-form and name cases. The README states the full contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/codex-local-workflow.md arrived from main (#88) after this branch retired the gateway demo, so it still named that demo's variables and told contributors to run NEXT_PUBLIC_DIRECTORY_URL=https://directory.ci.local \ NEXT_PUBLIC_BUTLER_ORIGIN=https://agents.ci.local \ npm run check:deploy-config check:deploy-config now rejects .local hosts, so that command exits 1. - Pass only NEXT_PUBLIC_DIRECTORY_URL=https://directory.ci.example, the value CI sets, to check:deploy-config and build, and say why a local origin must not be substituted. - Drop `unset RUN_LIVE_PAID_E2E LIVE_BUTLER_ORIGIN` and the "live/paid browser tests" wording; that suite no longer exists. - Add a test that reads the CI workflow and the guide: CI's origin must pass the check, every NEXT_PUBLIC_* value the guide passes must equal CI's, and the guide must not name the retired variables. CI does not build docs, so this is what keeps the guide runnable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
https://directory.example:0 passed as the production origin, but no browser can connect to port 0, so every canonical URL, sitemap entry and discovery document built from it would be unusable. URL parsing also turns :00 into :0, so the check reads the parsed port. The README now lists port 0 among the rejected forms, and it names the 6to4 relay range (192.88.99.0/24), which the check already blocked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The landing-page rewrite kept only the "Browse the directory" link's href, so no browser test loaded /discover any more, although the e2e README says the suite covers discovery. Restore main's check that /discover renders its heading. The e2e README also lost the `npx playwright install chromium` step when the live-suite instructions were removed; add it back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ries - Reject IANA special-use names and their subdomains (test, invalid, onion, alt, everything under arpa) besides localhost/local/internal/localdomain. RFC 6761 documentation names are rejected unless the check runs with --allow-documentation-names; only CI's placeholder step passes it, and railway.json keeps the strict check. - Reject all IPv4-mapped IPv6 literals (outside global unicast), every Fetch Standard bad port, and a trailing-dot host name. - Document the fail-closed deviations (192.0.0.0/24 and 2001::/23 anycast exceptions, NAT64, 6to4 relay) and pin the upstream tables in test/fixtures/origin-policy-sources.json, which the tests check the denylists against. - Compare real paths in the CLI guard so a symlinked invocation still runs. - Test the CLI itself: exit 1 with the [deployment config] message on a missing, insecure or non-public origin; exit 0 and the success line on a valid one; the symlink path; and that importing the module is silent. - Pin Node 22.23.3 in .nvmrc and use it in CI, pin checkout/setup-node by commit SHA, run on ubuntu-24.04, and correct the stale private-SDK comment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI installs Node from .nvmrc, but package.json engines still allowed any Node 22, and the README asked for a manual RAILPACK_NODE_VERSION service variable. Railpack applies engines.node first and then lets mise's idiomatic version files (.nvmrc) override it (railpack ec5d727, core/providers/node/node.go:419-494), so name the exact .nvmrc release in engines (and the lockfile's root entry): every source Railpack reads now gives 22.23.3, whatever their order. test/node-runtime.test.mjs fails if engines, the lockfile or CI drift from .nvmrc, or if another version file appears. The README and the local guide now describe the pin, and the guide selects the .nvmrc release instead of any Node 22. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…g matching The spawned check inherited the whole test environment, so a runtime warning it enabled reached the asserted stderr: with NODE_USE_ENV_PROXY=1 behind a proxy, Node prints an UNDICI-EHPA warning at startup and four CLI tests failed. Run the children with NODE_NO_WARNINGS=1, and add a test that injects an inherited warning (and checks that it does fire without the guard) while the exact exit status and output assertions stay. Also pin that only the exact --allow-documentation-names flag relaxes the check: a misspelt flag or any other argument leaves it strict. And check that the local guide runs the flagged origin check, since CI's placeholder origin fails the strict one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…gistry notes - The SDK repository is public, so DACS_SDK_GITHUB_TOKEN is optional and only authenticates the clone. The README table and deployment notes and the setup-sdk.sh comment still called it the private SDK's token. - The rejected exceptions inside 2001::/23 are not all anycast; list them (protocol anycast, AMT, AS112, ORCHIDv2, DRIP) next to the PCP and TURN anycast exceptions inside 192.0.0.0/24. - Add the SRv6 SID block 5f00::/16 (RFC 9602) to the fixture's IPv6 rows. CPython v3.15.0's copy lacks it; it lies outside 2000::/3, so the check already rejected it. The fixture and README now say the snapshot is the pinned copies plus the registry rows they lack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nvmrc release Railway doesn't pin which Railpack release builds the service, so the engines-then-mise precedence the README relies on could change without notice. Check the outcome instead: scripts/check-node-runtime.mjs exits non-zero unless the running Node is the .nvmrc release, and the Railway build command, start-railway.sh and CI all run it first. The version-file guard now covers every mise config file and glob that Railpack v0.41.0 hands to mise (mise/, .mise/, .config/mise*, mise.*.toml, conf.d), not just five names. The README cites the v0.41.0 tag instead of an untagged main commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The origin-policy fixture claimed a complete registry snapshot, but it lacked the IPv6 Dummy Prefix (100:0:0:1::/64), eap.arpa, eap-noob.arpa and the individual reverse-mapping zones. It also accepted the globally reachable AS112, AMT and Direct Delegation AS112 blocks, even though the README says special-purpose blocks are rejected. - Reject 192.31.196.0/24, 192.52.193.0/24, 192.175.48.0/24 and 2620:4f:8000::/48 with the other protocol-only blocks. - Pin both IP registries in full through Wireshark's IANA-generated tables. A new test requires every registry row to be rejected at both edges and traced to a fixture row. - Record each pinned copy as a raw URL at a fixed revision, with its sha256 and line ranges. scripts/verify-origin-sources.mjs (npm run verify:origin-sources, needs network) re-fetches them, checks the hashes and compares the re-extracted rows with the fixture. - Add hard-coded vectors for invalid, onion, alt and eap-noob.arpa. - Add a test for the CLI guard's realpath failure branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- test/directory-separation.test.ts fails if a gateway route, component, script, package script, Railway/CI/Playwright setting or sitemap entry comes back. It also checks that the sitemap's static routes are exactly the Directory's own pages. - Move the landing page's summary strip into homeCatalogSummary. Unit tests now cover the indexing, indexed-empty and populated states, the verified-only deal count, the 59/60-minute boundary and the clamp for a catalog timestamp in the future. - The home e2e test now asserts /discover's URL and title. The landing page shares /discover's heading, so the old check could not fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The local workflow guide still said the SDK clone might need GitHub authentication; the repository is public. playwright-report-live/ is no longer produced now that the live suite is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The names snapshot traced each name only through Unbound's and Knot Resolver's lists, and eap.arpa appears in neither, so nothing pinned it. Pin IANA's Special-Use Domain Names registry XML itself, byte for byte from a mirror of rsync.iana.org::assignments at a fixed commit, and make verify:origin-sources require the fixture's special-use and documentation names to equal the registry's names in both directions. eap.arpa now cites RFC 9965, which also deprecates eap-noob.arpa. verifyOriginSources takes an injected fetcher, and a new offline test checks it against small in-memory copies with real sha256s: the matching fixture verifies, and flipped or dropped registry rows, a missing CPython row, missing or extra names, a dropped port, a wrong sha256, changed bytes and HTTP 404 are each reported. The parser test now has IPv4 and IPv6 Wireshark rows whose forwardable and global flags differ, so reading the wrong column fails. The Wireshark copy holds every unexpired row and records an N/A Globally Reachable as false; say so, and note that the two terminated blocks IANA still lists are rejected anyway. Document running the verifier with --use-env-proxy behind a proxy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's Node always matches .nvmrc, so the CLI's exit 1 branch and the start script's errexit never ran: a check that exited 0 on the wrong release, or a start script without set -e, still passed. Run copies of check-node-runtime.mjs and start-railway.sh in a temp app whose .nvmrc pins 0.0.0, and assert exit 1, the [deployment config] message, and that start:railway stops before the data directory, the indexer and the server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The summary helper was tested, but app/page.tsx could bind a stat to the wrong field or label and every test would still pass. Render the page against pending, indexed-empty and populated catalogs saved in an isolated data directory, with the clock fixed, and assert the four value/label pairs; the populated values all differ. Also pin the page's link targets and its canonical URL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y-demo Separate the gateway demo from the Community Directory
Publish unavailable metrics for new and cached catalogs, refuse rate and score queries, and label observed history while keeping individual evidence inspection. Co-Authored-By: Codex <noreply@openai.com>
Check populated history, aborted outcomes, cached numeric metrics and refused queries through APIs and rendered pages. Add an isolated Playwright lane for browser validation. Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Codex <noreply@openai.com>
DACS-4 SB-2 (pinned Standard d45c0a29) groups the whole presented evidence set by settlement id before counting. A group claimed by two or more (jobId, phaseIndex) tuples counts only through settlement-side binding authority, and MUST NOT pick a winner by observedAt. The Directory verifies no such authority, so it now excludes every member of a collision group instead of crediting the earliest producer timestamp. Repeats of one tuple stay idempotent, and hash spelling variants (0x prefix, upper case) group as one settlement. The collision test now expects the group to be void. A new test loads three sb2-collision-authority-v0.8 vectors (source commit, path and sha256 recorded) and checks that a backdated or tied claimant never counts in either input order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TP-1 is now defined in-tree (dacs-directory/docs/TP-1.md). The file declares the null-rate and refused-filter behaviour, and the phaseIndex source used for settlement grouping, as open nonconforming deviations in the Standard's ImplementationDeviation shape. The README and INDEX link to it, and the code no longer cites an unpinned decision id. Contract and version signals: - The ListingSummary reputationHint schema requires every field the pinned SDK catalog reader requires (categoryScope, bundleCount, windowStart, windowEnd, computedAt). Counts and times are bounded to non-negative safe integers. - The manifest reports dacsDirectoryVersion "2" and restrictions ["TP-1"], and the OpenAPI document is 2.0.0, because two DACS-1 §6.3.6 parameters were removed. - The unversioned schema URL is no longer served as immutable. Projection: - A cached hint that the SDK reader would reject (missing count, non-prefix scope, reversed or non-integer window) falls back to the synthesized hint. - Rate, rating and score keys are dropped at seller, deal and listing level as well. - Writers (index-now, reindex, the fixture seed script) read the stored catalog through loadStoredCatalog, so a read-modify-write no longer persists null rating values. - /verify shows a recorded outcome as a neutral observation. The tests check the exact bundleRefs and currency totals through loadCatalog and the seller API, every refused metric key, the exact-category count, the emitted hint against the schema and the SDK reader, the manifest and OpenAPI literals, and the empty store. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The indexer now projects each success-evidence TxRef to its DACS-4 SB-1
settlement-tx-id on both the current and the legacy path: demos and the
legacy { rail: "demos", txHash } give demos:{txHash}, evm-event and
x402-event give evm:{chainId}:{txHash}:{logIndex}, and solana-instruction
gives solana:{cluster}:{signature}:{instructionIndex}. A deal citing a
reference that cannot be projected without ledger data is not countable.
SB-2 grouping moves to settlementUniqueness.countableDeals, which seller
reputation, indexed listing hints and the read projection all use. It
groups the complete admissible set before the window, and keys claimants
by deal identity so two records for one tuple also collide. A served hint's
bundleCount is recomputed from the retained records, so a cached count can
no longer include a voided collision.
A cached hint's categoryScope must also be a canonical string (trimmed,
NFC, no C0 controls or DEL), as the pinned SDK reader requires; the
published schema states that with a pattern.
docs/TP-1.md describes the projection and declares the missing SB-1
ledger-event check as an open nonconforming deviation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #85 at
25f4c58, with C-01 integrated from main. Head:de70e1c.Directory users see “Completion verification unavailable” and labelled observations. New and cached projections publish null metrics with a reason and TP-1 metadata, remove unknown cached rates, ratings and scores at seller, deal and listing level, and supply listing hints with observed category counts and snapshot windows in the shape the pinned SDK catalog reader accepts. Completion/rating filters, including bracketed keys, and sorting/ranking requests return 400. Evidence inspection, counts and currency totals remain available with their limitations stated. Full metrics return under a later reputation contract.
TP-1 is defined in-tree in
reference-implementations/dacs-directory/docs/TP-1.md, measured against DACS Standardd45c0a29. It declares the Directory's opennonconformingdeviations in the Standard'sImplementationDeviationshape. The manifest reportsdacsDirectoryVersion: "2"andrestrictions: ["TP-1"], the OpenAPI document is2.0.0, and the ListingSummary schema is served with a short, revalidated cache lifetime.Observed counts follow DACS-4 SB-1/SB-2 settlement uniqueness:
paymentTxRefsentry is projected to its SB-1settlement-tx-id(demos:{txHash}, including the legacy{ rail: "demos", txHash }ref;evm:{chainId}:{txHash}:{logIndex}forevm-eventandx402-event;solana:{cluster}:{signature}:{instructionIndex}). A deal citing a ref that can't be projected without ledger data isn't counted.(jobId, phaseIndex)is void, because the Directory verifies no settlement-side binding authority. Seller reputation, indexed listing hints and served hints share this rule, and a served hint's count is recomputed from retained records.phaseIndexrecovery aren't implemented. Both are declared as open deviations indocs/TP-1.md.This combined head also includes two build changes beyond the W restriction:
next/font/localusing two exact, integrity-pinned runtime packages. The earlier font failure came from a network guard; it did not show that CI required this switch. The owner decides whether to retain it.identityBundleHashimports through the SDK verification seam from its pure implementation. This resolves a client-build import error introduced by Align Directory listing admission with current SDK #85. A build failure on Align Directory listing admission with current SDK #85 alone is inferred from the recorded import trace; that head was not built independently. The owner decides whether to port the import change into Align Directory listing admission with current SDK #85 before merging it.Because main is merged here, the diff against #85 also contains main's #84/C-01 removal until #85 is updated from main. C-01 is included in this head and remains a merge prerequisite.
Validation at
de70e1c: the 36 unit/component files that reach the changed modules pass 309/309 (node --import tsx --test --test-concurrency=2), and typecheck reports 0 errors. The previous head passed all 47 files (351 tests) andnext build. Six retained browser cases were not run; no lint command is configured. Open for the owner: sign-off on deferring the SB-1phaseIndexderivation and the ledger-event check.🤖 Generated with Claude Code