Zum Inhalt springen

atvoto Lexicons

Custom AT Protocol record schemas under ch.atvoto.*. Schema files: lexicons/.

Status: draft (POC). Every schema description starts with “Entwurf”. Breaking changes are still allowed while nobody outside atvoto depends on them; they get frozen before the prod launch (see Evolution).

XRPC methods of the AppView (ch.atvoto.argument.list, ch.atvoto.comment.get, ch.atvoto.peerreview.pending, …) are a separate family and are not published as lexicons yet.


NSID Written by Repo rkey
ch.atvoto.dossier.argument user (original) → writer (canonical copy) user / community TID / sha256(originUri)[:24]
ch.atvoto.dossier.comment user user TID (imports: any)
ch.atvoto.dossier.commentTranslation writer (translator) community {commentRkey}-{lang}
ch.atvoto.content.rating user user TID
ch.atvoto.peerreview.request user user TID
ch.atvoto.peerreview.invitation writer community {argumentRkey}-{didSuffix}
ch.atvoto.peerreview.response user (original) → writer (canonical copy) user / community TID / {argumentRkey}-{didSuffix}
ch.atvoto.peerreview.result writer (finaliser) community {argumentRkey}
ch.atvoto.taxonomy.snapshot registrar (taxonomy.publishSnapshot) community TID

“Community” = the per-dossier community account (dossier-{rkey}.id.<domain>).

Dossier (CMS content, no record; community account per dossier)
├── dossier.argument ──┬── dossier.comment ── dossier.commentTranslation
│ ├── content.rating
│ └── peerreview.invitation / peerreview.response / peerreview.result
└── taxonomy.snapshot (topic tree, references arguments by rkey)

Acceptance pattern (originals → canonical copies)

Abschnitt betitelt „Acceptance pattern (originals → canonical copies)“

User-authored arguments and review responses are written self-signed into the user’s own repo. The indexer stages them in app_acceptance_queue; the writer gates them (eligibility, quota, review authorization) and writes the canonical copy into the community repo with provenance fields:

  • dossier.argument: source.originUri / source.originCid (inside #sourceUser)
  • peerreview.response: top-level originUri / originCid

originCid pins the exact accepted version of the original. Only canonical copies are projected into the read model (app_arguments, app_peerreview_responses). Comments and ratings are projected straight from user repos (eligibility checked by the indexer).


Field Type Req Notes
title string ≤300 ✓
body string ≤10000 ✓
type PRO | CONTRA ✓
dossier string ≤64 ✓ dossier rkey
source union #sourceUser | #sourceOfficial | #sourceOrganization ✓ #sourceUser: authorDid (+ originUri/originCid on the canonical copy)
langs language[] ≤3 original languages
translations #translation[] ≤10 embedded translations (lang, title, body, source manual|ai, model)
createdAt datetime ✓
Field Type Req Notes
body string ≤5000 ✓
argument at-uri ✓ parent argument (canonical community record)
parent at-uri parent comment (threading)
title string ≤300 unstable, from the Demokratiefabrik import
langs language[] ≤3
createdAt datetime ✓

External Bluesky replies to cross-posted arguments are imported as comments with origin = 'extern' without a dossier.comment record.

Sidecar translation, because the store cannot write into user repos. One language per record.

Field Type Req Notes
subject {uri, cid?} ✓ translated comment (may be an external Bluesky post)
dossier string ≤64 denormalized dossier rkey
lang language ✓
body string ≤10000 ✓
source manual | ai ✓
model string ≤200 when source = ai
translatedAt datetime ✓
Field Type Req Notes
subject com.atproto.repo.strongRef ✓ rated record
preference integer 0–100 ✓ 0 = neutral, 100 = strong support
createdAt datetime ✓

Only createdAt. Its existence is the trigger: the writer runs the reviewer lottery (daily limit, anti-collusion, slots) and writes invitations.

Field Type Req Notes
argument at-uri ✓
invitee did ✓
invited boolean default true; false = lottery candidate not selected (dedup)
createdAt datetime ✓
Field Type Req Notes
argument at-uri ✓
reviewer did ✓ must match an invitation
vote APPROVE | REJECT ✓ the only binding signal
criteria #criterion[] ≥1 ✓ key, label, assessment ok|flagged
originUri / originCid at-uri / cid canonical copy only
createdAt datetime ✓

Outcome of a closed peer review, written once by the writer’s finaliser. Public and recountable against the invitations and responses in the same repo (VERFASSUNG Art. 29); clients learn about outcomes from the firehose.

Field Type Req Notes
argument at-uri ✓ argument in the same community repo
outcome approved | rejected ✓ tie = rejected
approvals / rejections integer ✓ invited responses only
quorum integer quorum that applied
createdAt datetime ✓ time of closure

Append-only snapshot of a dossier’s topic tree (source of truth for app_taxonomy_node/_membership): dossierRkey, version, contentHash, prev (strongRef to the predecessor), attribution, nodes[] (DFS pre-order; key, name, description, introduction, importance, parent, arguments[] with rkey/confidence/stance; stance is PRO/CONTRA like the argument type).


  • ch.atvoto.peerreview.note — procedural note of a reviewer on an argument (e.g. “duplicate of …”, wording, wrong PRO/CONTRA), visible only within the review process. Purpose: transparency / traceability of review decisions for authors and other reviewers. Removed because peer review is vote-only (no free text) and no code used it. Can be added later at any time (a new NSID is non-breaking); the old schema is in the git history (lexicons/ch/atvoto/peerreview/note.json).
  • ch.atvoto.review.* — poltr legacy duplicates of peerreview.*; removed.

Lexicon resolution: per NSID group (authority) a DNS TXT record _lexicon.<authority> → did=<publisher DID>; the schemas live as com.atproto.lexicon.schema records (rkey = NSID) in that account’s repo.

NSID group DNS TXT name Value
ch.atvoto.dossier.* _lexicon.dossier.atvoto.ch did=did:plc:kcwu3fqgy3wi7lamal6jtnn6
ch.atvoto.content.* _lexicon.content.atvoto.ch same
ch.atvoto.peerreview.* _lexicon.peerreview.atvoto.ch same
ch.atvoto.taxonomy.* _lexicon.taxonomy.atvoto.ch same

Publisher account: lexicon.atvoto.ch (custom-domain handle via TXT _atproto.lexicon.atvoto.ch; a store-owned account under the store domain). Credentials: secret pds-account-lexicon. The DNS authority is shared by test and prod: when the account moves (prod PDS) or the test PDS is reset, publish from the new account and update the four TXT values.

Terminal-Fenster
goat lex lint lexicons # style / best practice
goat lex check-dns lexicons # which TXT records are missing
scripts/publish_lexicons.sh atvoto-test # publish new schemas
scripts/publish_lexicons.sh atvoto-test --update # overwrite changed ones
goat lex breaking lexicons # breaking changes vs. published
goat lex resolve ch.atvoto.dossier.argument # check from outside

Note: the reference PDS does not resolve third-party lexicons. Writes with validate: true (goat’s default) fail with Unknown lexicon type even after publishing — use goat record create --no-validate; clients write without validate and the PDS stores the record unvalidated. Publishing serves discovery and client-side validation (goat lex validate).

A published schema is an ordinary record and can be overwritten. Convention after freezing: backwards-compatible changes only — add optional fields, add knownValues. Not allowed: removing/renaming fields, changing types, optional → required, tightening limits. A breaking change gets a new NSID (e.g. ch.atvoto.dossier.argumentV2). goat lex breaking checks this against the published version. During the POC (disposable test data) breaking changes remain possible.