lexicons #
Vendored copies of every lexicon schema atgc reads or writes, from two
authorities with two different ways of publishing a schema — ../lexicons.json
is the one manifest covering both, under a sources map keyed by which
convention applies.
sh.tangled.* and com.atproto.repo.strongRef #
lexicons/sh/tangled/repo/pull.json is sh.tangled.repo.pull, and so on —
path mirrors NSID. com.atproto.repo.strongRef (needed by feed.comment's
subject/replyTo) lives alongside them.
Tangled's lexicons are not published as com.atproto.lexicon.schema
records — models.rs's own header comment names the real source of truth:
tangled.org/tangled.org/core/tree/master/lexicons, a git repo. So the
tangled entry in ../lexicons.json's sources pins provenance the way
that source actually offers it: the commit these files were fetched at, not
an at://-uri.
Refresh with ../scripts/vendor-tangled-lexicons.sh, which re-clones the
lexicons directory at its current tip, rewrites both the JSON here and the
generated Rust in ../vendor/tangled-lexicon/, and updates the pinned
commit.
Scoped to exactly the twelve lexicons the tangled source covers — not
Tangled's full surface (CI, knot management, and every XRPC endpoint atgc
never calls). Widen scripts/vendor-tangled-lexicons.sh's codegen input if
a future command needs another one typed, as sh.tangled.label.op and its
definition were widened for atgc report bug --agent.
sh.tangled.label.definition is vendored without a reader or a writer for a
narrower reason than the paragraph below: atgc writes the op and carries
one definition's at-uri as a constant, and the definition is what says what
that operand may contain — a null-typed label takes the literal "null"
and nothing else. The schema beside the op is what makes that checkable.
sh.tangled.repo.issue.comment is the other one here with neither a reader
nor a writer, and it is vendored on purpose. An issue comment is written as
sh.tangled.feed.comment — Tangled unified issue, pull and string comments
into that collection, and the appview's ingester handles this one as deletes
only. That claim is worth being able to check rather than take on trust, and
the two schemas side by side are the check: this one names its subject as a
bare at-uri and has no room for a CID, which is the shape from before the
unification. The pull twin, sh.tangled.repo.pull.comment, is not
vendored — it predates this reasoning, and adding it now would be a lexicon
bump inside an unrelated change.
app.userinput.* #
lexicons/app/userinput/discussion.json is app.userinput.discussion, and
so on for the rest — fetched from the lexicon authority
did:plc:uyixj57k6nmxrdj7pjs2ss5s (userinput.app's own PDS) rather than
hand-read from its minified web client.
This authority does publish com.atproto.lexicon.schema records, so the
userinput entry in ../lexicons.json's sources names the authority DID,
and each NSID under lexicons carries its own at://-uri and CID — a copy
here is provably what the authority published, not a guess.
Refresh with ../scripts/vendor-userinput-lexicons.sh, which re-resolves
every NSID and rewrites both the JSON here and the generated Rust in
../vendor/userinput-lexicon/.
Only discussion and upvote are turned into Rust today
(vendor/userinput-lexicon/), because those are the two records atgc report writes — a discussion for the report itself, an upvote for the
self-upvote the web client also gives its own posts. discussion's limits
(title, body, tag count) are worth enforcing before a write; upvote has
none to enforce, but is typed anyway so a vote is built the same way a
report is, not as one hand-rolled struct and one generated one. The other 14
are vendored for the same reason headquarters vendors blue.lance.camo: so
the shape a client assumes is checked against what the authority actually
publishes, not carried only in a comment. See TODO.md for what would need
generating next (#image for attachments) if report grows to use it.
Neither generated type's space/subject field is a typed
com.atproto.repo.strongRef — that ref is deliberately left out of this
crate's codegen input, unlike the tangled-lexicon crate's. See
scripts/vendor-userinput-lexicons.sh's comment on why: the generated
strongRef type marks cid required, true for a vote's subject but not
always for a discussion's space, and jacquard-codegen resolves a ref the
same way for every field that names it. Both fields stay the untyped
Data<S> a ref resolves to unvendored, built by hand from
crate::userinput::StrongRef at the point of use.
Both #
A normal cargo build reads neither the network nor either vendor script —
everything both need is already committed. Each script only touches its own
source entry and its own NSIDs under lexicons in ../lexicons.json, so
running one never disturbs the other's pins.