queries: extract shared read layer to @atjam/lexicons/queries
Single source of truth for the network-read code that web/ and tests/
both need. Module-level configurable URLs (setConstellationUrl,
setPlcDirectoryUrl) called once at app startup; defaults work for
tests with zero config.
Created lexicons/src/queries/:
- at-uri.ts parseAtUri, buildAtUri
- did.ts resolveDid + plc-directory config
- pds.ts listRecords, getRecord (cross-DID, resolves PDS first)
- constellation.ts getBacklinks + normalization + url config
- fetchers.ts fetchRoundsForJam, fetchSignupsForRound,
fetchSubmissionsForRound, fetchHomeFeed, fetchMyJams,
fetchJam, fetchRound, fetchJamByUri
- index.ts barrel
Exported as `Queries` namespace from @atjam/lexicons root.
Web changes:
- root.tsx calls Queries.setConstellationUrl + setPlcDirectoryUrl once
from CONSTELLATION_URL + PLC_DIRECTORY_URL in ~/lib/config
- 6 import sites switched from ~/lib/{pds,fetchers,at-uri,etc} to
Queries.fnName via destructure
- Deleted web/app/lib/{at-uri,did,pds,constellation,fetchers}.ts
Tests changes:
- tests/src/reads.ts shrinks from ~170 lines to ~70: keeps only
listMyRecords (convenience for reset.ts) and waitForBacklinks
(polling wrapper, test-specific). Everything else delegates to
Queries.
- Scenarios + probe import Queries.listRecords / getRecord /
getBacklinks directly.
Behavior unchanged. All 9 unit tests + 11 integration tests pass.
No deploy needed — this is internal restructuring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
validator: invitation chain validation + lit-up stub scenarios
Adds Validate.validateSignup({signup, round}) to @atjam/lexicons — the
first reader implementation of bilateral correctness for hosted/network
joinMode rounds.
What it checks:
- Open mode: any signup is valid.
- Hosted: signup must reference an invitation written by the round's
organizer DID. Invitation's invitee field must match the signup's
creator DID. Invitation must reference the same round.
- Network: as hosted, but the inviter may also be any participant
with a valid signup of their own — walked recursively back to the
organizer (the chain root). Cycle detection via a visited set.
- networkGate=contributed: non-organizer inviters must also have at
least one at.atjam.submission to the round.
Read-only — never writes. Default fetchers go through Queries
(getRecord, listRecords); tests inject stubs for pure-logic coverage.
Test coverage added:
lexicons/src/validate.test.ts (17 unit tests, ~5ms)
open passthrough (3 cases), hosted (6 cases including all negative
paths), network (5 cases including 2-hop chain, forged chain, broken
parent chain, cycle), contributed gate (3 cases including organizer
bypass).
tests/scenarios/hosted-validation.test.ts (4 integration tests)
real records on real PDSes for each hosted case.
tests/scenarios/network-chain.test.ts (5 integration tests)
real records for the chain, forged invitation, contributed gate
both directions, and the mutual-invitation cycle.
Totals: 48 lexicons unit tests (+17), 25 integration tests (+9 lit-up
from todos). All previously-stubbed scenarios now run. Aggregate suite
under a minute.
No deploy — the web app doesn't yet call Validate.validateSignup when
rendering round detail. That's a separate wiring step; the validator is
ready when you want to call it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
queries: extract shared read layer to @atjam/lexicons/queries
Single source of truth for the network-read code that web/ and tests/
both need. Module-level configurable URLs (setConstellationUrl,
setPlcDirectoryUrl) called once at app startup; defaults work for
tests with zero config.
Created lexicons/src/queries/:
- at-uri.ts parseAtUri, buildAtUri
- did.ts resolveDid + plc-directory config
- pds.ts listRecords, getRecord (cross-DID, resolves PDS first)
- constellation.ts getBacklinks + normalization + url config
- fetchers.ts fetchRoundsForJam, fetchSignupsForRound,
fetchSubmissionsForRound, fetchHomeFeed, fetchMyJams,
fetchJam, fetchRound, fetchJamByUri
- index.ts barrel
Exported as `Queries` namespace from @atjam/lexicons root.
Web changes:
- root.tsx calls Queries.setConstellationUrl + setPlcDirectoryUrl once
from CONSTELLATION_URL + PLC_DIRECTORY_URL in ~/lib/config
- 6 import sites switched from ~/lib/{pds,fetchers,at-uri,etc} to
Queries.fnName via destructure
- Deleted web/app/lib/{at-uri,did,pds,constellation,fetchers}.ts
Tests changes:
- tests/src/reads.ts shrinks from ~170 lines to ~70: keeps only
listMyRecords (convenience for reset.ts) and waitForBacklinks
(polling wrapper, test-specific). Everything else delegates to
Queries.
- Scenarios + probe import Queries.listRecords / getRecord /
getBacklinks directly.
Behavior unchanged. All 9 unit tests + 11 integration tests pass.
No deploy needed — this is internal restructuring.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
validator: invitation chain validation + lit-up stub scenarios
Adds Validate.validateSignup({signup, round}) to @atjam/lexicons — the
first reader implementation of bilateral correctness for hosted/network
joinMode rounds.
What it checks:
- Open mode: any signup is valid.
- Hosted: signup must reference an invitation written by the round's
organizer DID. Invitation's invitee field must match the signup's
creator DID. Invitation must reference the same round.
- Network: as hosted, but the inviter may also be any participant
with a valid signup of their own — walked recursively back to the
organizer (the chain root). Cycle detection via a visited set.
- networkGate=contributed: non-organizer inviters must also have at
least one at.atjam.submission to the round.
Read-only — never writes. Default fetchers go through Queries
(getRecord, listRecords); tests inject stubs for pure-logic coverage.
Test coverage added:
lexicons/src/validate.test.ts (17 unit tests, ~5ms)
open passthrough (3 cases), hosted (6 cases including all negative
paths), network (5 cases including 2-hop chain, forged chain, broken
parent chain, cycle), contributed gate (3 cases including organizer
bypass).
tests/scenarios/hosted-validation.test.ts (4 integration tests)
real records on real PDSes for each hosted case.
tests/scenarios/network-chain.test.ts (5 integration tests)
real records for the chain, forged invitation, contributed gate
both directions, and the mutual-invitation cycle.
Totals: 48 lexicons unit tests (+17), 25 integration tests (+9 lit-up
from todos). All previously-stubbed scenarios now run. Aggregate suite
under a minute.
No deploy — the web app doesn't yet call Validate.validateSignup when
rendering round detail. That's a separate wiring step; the validator is
ready when you want to call it.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
tests: pure-function coverage + url resolver + reset invariant
Three additions filling the highest-value gaps in the test surface:
Lexicons (22 new pure-function tests, no network, ~5ms aggregate):
- round.test.ts extended with getJoinMode/getNetworkGate/
requiresInvitation/isRound. Notable: unknown-value forward-
compatibility cases that catch readers regressing to throw or
pass-through (would fail-open or fail-closed in subtle ways).
- New invitation.test.ts for isInvitation typeguard.
- New queries/at-uri.test.ts for parseAtUri / buildAtUri including the
round-trip equivalence (buildAtUri(parseAtUri(x)) === x).
Tests integration (3 new tests, ~3.7s):
- New reset-hermeticity.test.ts. Writes one record into every
at.atjam.* collection across multiple accounts, runs resetAll,
asserts 0 records remain. Locks in the invariant the rest of the
suite quietly depends on; catches reset.ts regressions before they
leak state into other scenarios.
Web (10 new tests, ~4ms — first vitest setup in this workspace):
- Added vitest devDep + test scripts + vitest.config.ts (tsconfig-paths
for ~/ resolution, node env, scoped to app/**/*.test.ts).
- New url-to-at-uri.test.ts covering all 5 branches of
resolveInputToAtUri: direct at:// passthrough, bsky URL with DID,
bsky URL with handle (via mocked resolveHandle), staging.bsky.app,
whtwnd entries, malformed paths in both, unknown hosts, non-URL
input. resolveHandle is mocked so no network.
Totals across workspaces: 31 lexicons unit tests, 14 integration tests
(+ 9 todo waiting on validator), 10 web unit tests. Aggregate runtime
under a minute. No deploy needed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>