verify/ledger.adoc
verify
the formal-stocktake verdict ledger
This is the deliverable of the formal-stocktake exercise.
Each row is one invariant claim extracted from docs/abstractions.adoc and docs/spec/*.adoc, paraphrased faithfully with key phrases quoted.
Every verdict stays OPEN until the paper exercise discharges the claim against a formal model.
The code is ground truth: crates/kernel/ents-gate-rules is the compiled Datalog rule set, and the encoded-in-ents-gate-rules? column classifies each claim against its seven denial rules (ff_violation, genesis_violation, second_root_violation, unsigned_violation, dangling_anchor_violation, dangling_context_violation, effect_admin_violation) and its two deliberately-marked gaps (abstraction 1’s granularity rule, abstraction 6’s monotone exactly-once effect dedup).
The harness is Rust-native, and the model column names which check discharges each claim: search is crates/verify/ents-verify/src/search.rs’s exhaustive bounded search calling gate() directly; stateright is crates/verify/ents-verify’s receive.rs/effects.rs/durability.rs protocol-over-time skeletons; proptest is crates/kernel/ents-gate-rules/tests/prop.rs’s cheap sampled floor; alloy-paper marks a claim demoted to verify/alloy/*.als as a paper-only design tool, no longer run in CI; and — means no model is assigned yet.
A row that turns FALSIFIED or DIVERGED lands a concrete counterexample as a test in crates/kernel/ents-gate-rules/tests/ledger.rs first, before anything else.
The ledger carries 163 rows; exactly one is non-OPEN — the refname-binding claim, marked DIVERGED.
| claim | source | model | encoded-in-ents-gate-rules? | verdict | assumption-or-counterexample |
|---|---|---|---|---|---|
A ref under |
abstractions.adoc, §1 Meta-ref, ~L14-19 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Granularity rule: one ref per independently-authored entity; entities different actors write concurrently must not share a ref; writes stay conflict-free. |
abstractions.adoc, §1 Meta-ref, ~L21-23 |
— |
gap-marked |
OPEN |
— |
Trees stay pure struct representations — no version marker entry. |
abstractions.adoc, §2 Typed tree, ~L39 |
alloy-paper |
gap-unmarked |
OPEN |
— |
"Refname binding needs no stored metadata at all: the refname is a total function of signed content, recomputed at verification." |
abstractions.adoc, §2 Typed tree, L42 (normative twin: meta-ref.identity-binding) |
search, proptest |
gap-unmarked |
DIVERGED |
Cross-ref replay: an admin-signed parentless comment commit (anchor+context resolving) replayed as creation of refs/meta/effects/x passes genesis, unsigned, effect_admin (ff vacuous). Missing rule: binding_violation. Pinned by crates/kernel/ents-gate-rules/tests/ledger.rs; Alloy witness verify/alloy/gate_rules.als check binding_refname_recomputed. |
Tip invariant: the tip of a meta-ref is always readable by the binary that owns the entity type; non-owning binary degrades to generic display, never an error (redaction is the sole qualification). |
abstractions.adoc, §2 Typed tree, ~L44-45 |
— |
gap-unmarked |
OPEN |
— |
Retention invariant: the tree storing an anchor embeds the anchored blob plus a context blob; anchored content is reachable from |
abstractions.adoc, §3 Anchor, ~L51-53 |
alloy-paper |
dangling_anchor_violation, dangling_context_violation |
OPEN |
— |
Gitlinks are not reachability edges and retain nothing; embedding is the only mechanism that works. |
abstractions.adoc, §3 Anchor, L53 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Redaction is the sole deliberate exception to retention. |
abstractions.adoc, §3 Anchor, L54 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Anchor data is never mutated. |
abstractions.adoc, §3 Anchor, L55 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Anchors project onto newer commits at read time via blame plus fuzzy matching; when the anchored commit is gc’d, projection degrades to context matching instead of breaking. |
abstractions.adoc, §3 Anchor, L55-56 |
— |
gap-unmarked |
OPEN |
— |
Every meta-ref mutation is an author-signed commit. |
abstractions.adoc, §4 Signed commit, L62 |
search, proptest |
unsigned_violation |
OPEN |
— |
The signature is a data artifact, not a transport artifact: it replicates with the repo and verifies offline in every clone, so verification evidence is itself repository state. |
abstractions.adoc, §4 Signed commit, L63 |
search |
gap-unmarked |
OPEN |
— |
Push certificates are demoted to transport concerns; they carry no meta-ref semantics. |
abstractions.adoc, §4 Signed commit, L64 |
search |
gap-unmarked |
OPEN |
— |
Refname binding is recomputed from the commit’s own signed content; a mismatch refuses (without this a signed commit could be replayed as the tip of a different meta-ref). |
abstractions.adoc, §4 Signed commit, L69 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Anti-replay: meta-refs advance fast-forward-only (new tip descends from old), enforced by atomic CAS; parent hash is the freshness binding, no nonce needed. |
abstractions.adoc, §4 Signed commit, L70 |
search |
ff_violation (FF part only; CAS mechanism itself not a Datalog rule) |
OPEN |
— |
Tip invariant: the tip of a meta-ref is signed by a member authorized for that refname; checkable after the fact by anyone with a clone. |
abstractions.adoc, §4 Signed commit, L72-73 |
search, proptest |
unsigned_violation (partial: enrolled-member only, not refname-specific authorization) |
OPEN |
— |
Adoption is always a merge, never rewrite: when author and placer differ, the authorized member merges the contributor’s commit onto the canonical ref, even trivially; the merge commit satisfies the tip invariant. |
abstractions.adoc, §4 Signed commit, L75-76,78 |
stateright |
gap-unmarked |
OPEN |
— |
Cherry-picking is forbidden as an adoption mechanism: it creates a new commit object and destroys the author’s signature. |
abstractions.adoc, §4 Signed commit, L77 |
stateright |
gap-unmarked |
OPEN |
— |
Same-actor divergence: two of a member’s own machines racing a single-writer ref is resolved by merging own heads, never erroring; typed trees merge schema-aware, not textually. |
abstractions.adoc, §4 Signed commit, L80-81 |
stateright |
gap-unmarked |
OPEN |
— |
Principled split: content signatures carry authorization only where mutations are author-signed single-writer appends (granularity-guaranteed); |
abstractions.adoc, §4 Signed commit, L83-84 |
search |
gap-unmarked |
OPEN |
— |
Gate’s four-part verification: tip signed by authorized member; refname recomputes from signed content; new tip descends from old tip; update commits via atomic CAS. |
abstractions.adoc, §5 Gate, L92-95 |
search |
ff_violation (descent part); rest gap-unmarked |
OPEN |
— |
Because members/refname rules live under |
abstractions.adoc, §5 Gate, L97 |
stateright |
gap-unmarked |
OPEN |
— |
Verification epoch: gate applies the tip invariant from an epoch recorded in |
abstractions.adoc, §5 Gate, L99-100 |
stateright |
gap-unmarked |
OPEN |
— |
Gate is a property of the store: hosted runs the gate at CAS time and aborts on failure (mandatory); local accepts any write and runs the gate as an annotating verdict (advisory). |
abstractions.adoc, §5 Gate, L104-106 |
stateright |
gap-unmarked |
OPEN |
— |
The moment a verdict predicts rejection, sync offers to route the commit to the inbox instead — not only after actual rejection. |
abstractions.adoc, §5 Gate, L108 |
stateright |
gap-unmarked |
OPEN |
— |
One function, three call sites: hosted CAS, local UI verdict, push pre-flight. |
abstractions.adoc, §5 Gate, L110 |
stateright |
gap-unmarked |
OPEN |
— |
A verdict is never a bare pass/fail: on failure it carries which rule failed and for which refname. |
abstractions.adoc, §5 Gate, L111 |
— |
gap-unmarked |
OPEN |
— |
Local web UI signs as the user with the user’s own member key; server-key signing is a hosted-only necessity, must not be imported locally. |
abstractions.adoc, §5 Gate, L114-115 |
— |
gap-unmarked |
OPEN |
— |
Results location is derived by convention; an effect cannot choose where its verdicts land. |
abstractions.adoc, §6 Effect, L132 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Trigger semantics: the trigger denotes a set of commits; the effect fires once per commit that enters the set. |
abstractions.adoc, §6 Effect, L134 |
stateright |
gap-marked |
OPEN |
— |
Meta-refs are outside `rev()’s domain by definition. |
abstractions.adoc, §6 Effect, L138 |
stateright |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, §6 Effect, L140-141 |
stateright |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, §6 Effect, L144 |
stateright |
gap-unmarked |
OPEN |
— |
Monotone, entry-only: a force-push can shrink a set, but a commit leaving the set retracts nothing — results are immutable history. |
abstractions.adoc, §6 Effect, L147 |
stateright |
gap-marked |
OPEN |
— |
No pipeline state: the work set is |
abstractions.adoc, §6 Effect, L150 |
stateright |
gap-marked |
OPEN |
— |
Dedup key |
abstractions.adoc, §6 Effect, L151 |
stateright |
gap-marked |
OPEN |
— |
Result taxonomy: a result is |
abstractions.adoc, §6 Effect, L153-154 |
stateright |
gap-unmarked |
OPEN |
— |
Infrastructure failure is not a result; only retry exhaustion writes a terminal |
abstractions.adoc, §6 Effect, L155 |
stateright |
gap-unmarked |
OPEN |
— |
Retry bounds are deployment configuration, never effect data. |
abstractions.adoc, §6 Effect, L156 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A transient outage can neither retry forever nor permanently discharge an obligation. |
abstractions.adoc, §6 Effect, L157 |
stateright |
gap-unmarked |
OPEN |
— |
Recursion is structure: downstream-of-effects is syntactically visible; because |
abstractions.adoc, §6 Effect, L159-160 |
stateright |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, §6 Effect, L165-166 |
stateright |
gap-unmarked |
OPEN |
— |
Pushes are never blocked; the durable enqueue is the entire synchronous cost. |
abstractions.adoc, §6 Effect, L167 |
stateright |
gap-unmarked |
OPEN |
— |
A worker dequeues, materializes toolchains, executes in a sandbox; host-direct requires explicit |
abstractions.adoc, §6 Effect, L168-169 |
— |
gap-unmarked |
OPEN |
— |
Results return only as signed commits pushed to one ref per tested commit ( |
abstractions.adoc, §6 Effect, L170 |
alloy-paper |
gap-marked |
OPEN |
— |
Identity discipline: the runner is a member, not an ambient authority; official results are official only because canonical refs are writable solely by designated worker keys. |
abstractions.adoc, §6 Effect, L172-173 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Any member may self-run any effect; results land in |
abstractions.adoc, §6 Effect, L174 |
alloy-paper |
gap-unmarked |
OPEN |
— |
No content predicates beyond |
abstractions.adoc, §6 Effect, L177 |
stateright |
gap-unmarked |
OPEN |
— |
Admin-only write rule on |
abstractions.adoc, §6 Effect, L181 |
search, proptest |
effect_admin_violation |
OPEN |
— |
Abstractions 4/5/6 close: all state changes, human or machine, flow through one verified, audited channel; the repository is the message bus. |
abstractions.adoc, "The loop", L188-189 |
stateright |
gap-unmarked |
OPEN |
— |
No code knows where it is running; an |
abstractions.adoc, "Composition", L196-197 |
— |
gap-unmarked |
OPEN |
— |
Crates that extend git carry the |
abstractions.adoc, "Composition", L209-210 |
— |
gap-unmarked |
OPEN |
— |
The unit the library exposes is |
abstractions.adoc, "Composition", L213 |
stateright |
gap-unmarked |
OPEN |
— |
Local and hosted do not share a push path; they share |
abstractions.adoc, "Composition", L215-216 |
stateright |
gap-unmarked |
OPEN |
— |
Dependencies point one way; a lower layer never depends on a higher one, checked mechanically. |
abstractions.adoc, "Layering", L238 |
— |
gap-unmarked |
OPEN |
— |
A package depends on kernel crates freely and on other packages never ( |
abstractions.adoc, "Layering", L247 |
— |
gap-unmarked |
OPEN |
— |
`ents-web’s generic rendering path must never match on which concrete entity type it was handed. |
abstractions.adoc, "Layering", L252-253 |
— |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, "Layering", L254 |
— |
gap-unmarked |
OPEN |
— |
A kernel crate must not depend on a package crate in any form (normal, dev, build, or feature-flagged). |
abstractions.adoc, "Layering", L256 |
— |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, "Layering", L257 |
— |
gap-unmarked |
OPEN |
— |
Every ref namespace is minted by one function in |
abstractions.adoc, "Layering", L259 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Fanout index: a stale or absent index degrades to scanning ref tips, never to wrong answers. |
abstractions.adoc, "Derived", L280 |
stateright |
gap-unmarked |
OPEN |
— |
Redacted bytes are withheld from the store and generated packs; the oid stays in history as evidence; signatures and the tip invariant are untouched because verification never reads withheld bytes. |
abstractions.adoc, "Derived", L282 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Redaction is enforced at ingest so content addressing cannot let anyone refill the hole exactly. |
abstractions.adoc, "Derived", L283 |
stateright |
gap-unmarked |
OPEN |
— |
Readers surface a redaction marker, never an error. |
abstractions.adoc, "Derived", L284 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Embeddable server: keeping authorization/effect-matching logic in the library, never smeared across subprocess boundaries. |
abstractions.adoc, "Derived", L289-290 |
— |
gap-unmarked |
OPEN |
— |
|
abstractions.adoc, "Command surface", L324 |
stateright |
gap-unmarked |
OPEN |
— |
Every mutation frontend shares the identical |
abstractions.adoc, "Command surface", L324 |
stateright |
gap-unmarked |
OPEN |
— |
Revocation is a state on the member entity, not deletion; a revoked key must be explicitly rejected. |
abstractions.adoc, "Command surface", L341 |
stateright |
gap-unmarked |
OPEN |
— |
Pushes to |
abstractions.adoc, "Deployment", L363 |
— |
gap-unmarked |
OPEN |
— |
Worktree update happens only after |
abstractions.adoc, "Deployment", L361 |
— |
gap-unmarked |
OPEN |
— |
Bootstrap gap: an empty member list admits every push so the first member can enroll. |
abstractions.adoc, "Deployment", L365 |
stateright |
gap-unmarked |
OPEN |
— |
An anchor MUST identify the exact content it was captured against (commit, path, blob oid, optional 1-based inclusive range); creation MUST validate path and range against the revision’s actual content. |
docs/spec/anchor.adoc, [#anchor.definition], ~L9-17 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Anchored text MUST be fully derivable from the blob and line range, derived at read time, never stored redundantly; the anchored commit’s id is recorded only as a plain data field, and MAY be gc’d. |
docs/spec/anchor.adoc, [#anchor.immutable], ~L19-28 |
alloy-paper |
gap-unmarked |
OPEN |
— |
The anchoring document MUST embed the anchored blob "referenced by the existing blob’s own object id rather than copied" plus a context blob "written fresh", as ordinary tree entries, keeping content reachable "for as long as the document’s ref exists". |
docs/spec/anchor.adoc, [#anchor.retention], ~L30-45 |
alloy-paper |
dangling_anchor_violation, dangling_context_violation |
OPEN |
— |
Projection MUST report one of exactly four outcomes (current/relocated/outdated/deleted), MUST follow renames, and MUST work between any two commits — forwards, backwards, or across unrelated history — while the anchor’s own commit exists. |
docs/spec/anchor.adoc, [#anchor.projection], ~L48-61 |
— |
gap-unmarked |
OPEN |
— |
After the anchored commit is gc’d, fuzzy fallback recovers the same four outcomes approximately; "an outdated or deleted projection MUST NOT lose the anchor". |
docs/spec/anchor.adoc, [#anchor.fuzzy-fallback], ~L63-74 |
— |
gap-unmarked |
OPEN |
— |
A working-tree anchor survives its content being "committed, amended, or discarded"; it records HEAD only as a "best-effort, never-load-bearing" field; projection MUST support the working tree as target. |
docs/spec/anchor.adoc, [#anchor.working-tree], ~L76-93 |
alloy-paper |
gap-unmarked |
OPEN |
— |
An effect definition MUST be rejected before storage when a toolchain name is not a valid ref-path segment or the trigger fails to parse (including |
docs/spec/effect.adoc, [#effect.validation], ~L41-50 |
search |
gap-unmarked |
OPEN |
— |
Host-direct execution MUST require an explicit |
docs/spec/effect.adoc, [#effect.execution], ~L54-68 |
— |
gap-unmarked |
OPEN |
— |
An effect’s stored data MUST NOT select its own executor, demand |
docs/spec/effect.adoc, [#effect.deployment-property], ~L70-78 |
— |
gap-unmarked |
OPEN |
— |
A member running |
docs/spec/effect.adoc, [#effect.local-run], ~L80-89 |
stateright |
gap-unmarked |
OPEN |
— |
Result write-back MUST be "an ordinary receive client, never a privileged write outside the gate". |
docs/spec/effect.adoc, [#effect.results-writeback], ~L93-106 |
stateright |
gap-unmarked |
OPEN |
— |
Only the sandbox MAY touch a toolchain’s extracted bytes; declared components MUST be resolved during effect execution, "never by any other code path". |
docs/spec/effect.adoc, [#effect.toolchains], ~L161-168 |
— |
gap-unmarked |
OPEN |
— |
A fanout index MUST be rebuilt only by an effect and written back only as a worker-signed commit, "never by any privileged out-of-band writer". |
docs/spec/effect.adoc, [#effect.fanout-index], ~L174-184 |
stateright |
gap-unmarked |
OPEN |
— |
Verification MUST depend only on the read half of the RefStore seam, never on write access or on any state outside |
docs/spec/gate.adoc, intro (also [#arch.refstore-read-cas-split]), ~L3-5 |
search |
gap-unmarked |
OPEN |
— |
Authorization is judged against the member entity in force at acceptance time — the member ref’s tip in the same snapshot the gate reads. |
docs/spec/gate.adoc, [#gate.tip-signed], ~L12-23 |
stateright |
unsigned_violation (partial: enrolled-membership only, not snapshot-scoped refname authorization) |
OPEN |
— |
A gate-owned hash-identified entity’s creation MUST strictly decode as its type, an unknown tree entry refusing; the gate-owned entity structs MUST stay pairwise disjoint under this decode. |
docs/spec/gate.adoc, [#gate.identity-binding], ~L36-40 |
alloy-paper |
gap-unmarked |
OPEN |
— |
When an object the binding needs is withheld by redaction, the binding MUST be vouched by the admin-signed redaction record, and a redacted object MUST NOT be re-admitted. |
docs/spec/gate.adoc, [#gate.identity-binding], ~L47-51 |
stateright |
gap-unmarked |
OPEN |
— |
Advancing a hash-identified entity’s ref is authorized only for the genesis signer or an admin; a review ref advances only under the signature of the member its refname names. |
docs/spec/gate.adoc, [#gate.owner-mutation], ~L54-67 |
search |
gap-unmarked |
OPEN |
— |
A pre-flight verdict "is a prediction that can only go stale; it MUST NOT diverge from the rules the hosted store will actually apply". |
docs/spec/gate.adoc, [#gate.call-sites], ~L188-196 |
stateright |
gap-unmarked |
OPEN |
— |
Transport-auth evidence MUST be threaded through uninterpreted — "never substituted for the tip invariant on a |
docs/spec/gate.adoc, [#gate.branch-acl-undefined], ~L267-284 |
stateright |
gap-unmarked |
OPEN |
— |
With no |
docs/spec/gate.adoc, [#gate.bootstrap], ~L288-296 |
stateright |
gap-unmarked |
OPEN |
— |
|
docs/spec/lens.adoc, [#lens.serve], ~L13-24 |
— |
gap-unmarked |
OPEN |
— |
Lens ranges are derived at request time via projection and "never cached across mutations of the comment’s ref"; non- |
docs/spec/lens.adoc, [#lens.lenses], ~L26-39 |
— |
gap-unmarked |
OPEN |
— |
Comment diagnostics "MUST NEVER use warning or error severity" and MUST be suppressible without affecting the lenses. |
docs/spec/lens.adoc, [#lens.diagnostics], ~L41-50 |
— |
gap-unmarked |
OPEN |
— |
Composing MUST require no client-specific extension; a richer input surface "MUST be sugar over the same create operation, never a second mechanism". |
docs/spec/lens.adoc, [#lens.compose], ~L61-75 |
— |
gap-unmarked |
OPEN |
— |
Editor-composed comments MUST anchor to the working tree’s content when it differs from HEAD — "exactly the bytes the author was reading". |
docs/spec/lens.adoc, [#lens.working-tree], ~L77-87 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Every lens operation MUST be the same library call the |
docs/spec/lens.adoc, [#lens.parity], ~L89-101 |
— |
gap-unmarked |
OPEN |
— |
All forge state MUST live under |
docs/spec/meta-ref.adoc, [#meta-ref.namespace], ~L15-27 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Inbox routing preserves the canonical ref’s entire path below |
docs/spec/meta-ref.adoc, [#meta-ref.inbox], ~L45-61 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A member is authorized only for its own |
docs/spec/meta-ref.adoc, [#meta-ref.inbox], ~L62-68 |
search |
gap-unmarked |
OPEN |
— |
An inbox ref MUST NOT be deleted on adoption or at any other time — it remains the contributor’s audit trail. |
docs/spec/meta-ref.adoc, [#meta-ref.inbox], ~L69-71 |
stateright |
gap-unmarked |
OPEN |
— |
|
docs/spec/meta-ref.adoc, [#meta-ref.inbox], ~L72-85 |
alloy-paper |
gap-unmarked |
OPEN |
— |
For a hash-identified entity, "every parentless commit reachable from the proposed tip MUST be that genesis" — the reachability form makes doppelgänger replay impossible and holds across divergence merges. |
docs/spec/meta-ref.adoc, [#meta-ref.identity-binding], ~L117-124 |
alloy-paper |
genesis_violation, second_root_violation |
OPEN |
— |
The parentless-roots walk MUST NOT be applied to pins: a pin’s ancestry deliberately reaches into code history. |
docs/spec/meta-ref.adoc, [#meta-ref.identity-binding], ~L132-135 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Who authored a state, and when, MUST come from the commit itself, never from duplicated tree fields: "each datum has exactly one signed home". |
docs/spec/meta-ref.adoc, [#meta-ref.identity-binding], ~L144-147 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Within a meta-ref’s history a commit parent means exactly one thing — the prior state of the same entity (pin retained-commit parents sole exception); a cross-entity relationship MUST be tree data, never a parent edge. |
docs/spec/meta-ref.adoc, [#meta-ref.identity-binding], ~L147-150 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A genesis commit is frozen by the identity derived from it, so hash-identified/composite-keyed structs MUST evolve additively only — "new fields optional, required fields never added, renamed, or removed". |
docs/spec/meta-ref.adoc, [#meta-ref.identity-binding], ~L149-153 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A struct change is a migration committed on top of the old tip; history keeps the old encoding, and a struct change "MUST NOT rewrite or delete a prior commit on the ref". |
docs/spec/meta-ref.adoc, [#meta-ref.migration], ~L172-180 |
alloy-paper |
gap-unmarked |
OPEN |
— |
The gate and |
docs/spec/model.adoc, [#model.extensibility], ~L8-22 |
search |
gap-unmarked |
OPEN |
— |
A facet shape MUST be compile-time-defined: runtime-readable, never runtime-constructible. |
docs/spec/model.adoc, [#model.extensibility], ~L13-15 |
— |
gap-unmarked |
OPEN |
— |
A member’s id binds to its key-carrying entity’s refname final segment; enrollment occurs as a signed commit — the member is forge state "with no user database separate from the repository". |
docs/spec/model.adoc, [#model.member-identity], ~L31-40 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Admission consults the member entity currently in force, so a revoked key’s new pushes are refused "from the moment the revocation lands, regardless of any committer timestamp the pushed commit claims". |
docs/spec/model.adoc, [#model.member-revocation], ~L47-50 |
stateright |
gap-unmarked |
OPEN |
— |
A ref accepted before the revocation landed remains valid: "acceptance is never re-judged". |
docs/spec/model.adoc, [#model.member-revocation], ~L51-52 |
stateright |
gap-unmarked |
OPEN |
— |
Unrevoking returns the key to authorizing new signatures "without altering the record of the period it was revoked". |
docs/spec/model.adoc, [#model.member-revocation], ~L60-61 |
stateright |
gap-unmarked |
OPEN |
— |
A self-attested member MUST NOT be authorized for canonical refs — writes limited to its own inbox and self-run namespaces — until an admin-registered member promotes it. |
docs/spec/model.adoc, [#model.member-provenance], ~L64-75 |
search |
gap-unmarked (effect_admin_violation covers only the effects namespace, not the provenance tier generally) |
OPEN |
— |
A machine actor is an ordinary Member entity, revocable like any human key; "a privileged write path for a machine actor MUST NOT exist outside this model". |
docs/spec/model.adoc, [#model.member-worker], ~L77-86 |
stateright |
gap-unmarked |
OPEN |
— |
A comment’s identity is the oid of its genesis commit and "MUST NEVER change afterward: edits advance the ref, they do not rename it". |
docs/spec/model.adoc, [#model.comment], ~L99-102 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A comment about nothing MUST be refused at creation by the writing tool, "though never by the gate, which stays content-agnostic". |
docs/spec/model.adoc, [#model.comment], ~L93-98 |
— |
gap-unmarked |
OPEN |
— |
A new comment’s state is |
docs/spec/model.adoc, [#model.comment-state], ~L109-121 |
— |
gap-unmarked |
OPEN |
— |
A state-changing mutation by an enrolled key MUST carry a |
docs/spec/model.adoc, [#model.comment-provenance], ~L123-129 |
— |
gap-unmarked |
OPEN |
— |
An entity’s thread MUST be an aggregation query over comment refs; a context entity MUST NOT store its comment list, so concurrent commenters "never race a shared ref". |
docs/spec/model.adoc, [#model.comment-context], ~L132-142 |
alloy-paper |
gap-marked (instance of abstraction 1’s granularity rule) |
OPEN |
— |
A reply’s parent MUST exist when the reply is created; aboutness is inherited from the thread root; no comment stores a list of its replies. |
docs/spec/model.adoc, [#model.comment-thread], ~L144-154 |
alloy-paper |
gap-unmarked |
OPEN |
— |
An issue’s identity is its genesis oid — no sequential counter exists — and machine-readable output (including |
docs/spec/model.adoc, [#model.issue], ~L158-177 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A review binds by composite key |
docs/spec/model.adoc, [#model.review], ~L181-198 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Every review MUST occupy exactly two refs: the entity ref and its retention pin. |
docs/spec/model.adoc, [#model.review], ~L191-193 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A review’s verdict MUST be a hard enum — |
docs/spec/model.adoc, [#model.review], ~L199-202 |
— |
gap-unmarked |
OPEN |
— |
A pin’s tip is a reviewer-signed commit whose parents include the reviewed commit, so that commit and its ancestry "survive force-push, branch deletion, and gc for as long as the review exists". |
docs/spec/model.adoc, [#model.review-pin], ~L213-224 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Re-reviewing MUST advance the pin fast-forward with parents = previous pin tip + newly reviewed commit, so every reviewed round stays retained and the pin’s history is the audit trail. |
docs/spec/model.adoc, [#model.review-pin], ~L225-229 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A result MUST carry the effect’s name and the judged commit’s full oid as tree fields from which the refname derives — "a result MUST mean something with the refname stripped away" (a signed |
docs/spec/model.adoc, [#model.result-identity], ~L260-270 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Result fields are not parent edges: a result ref’s parents stay prior states of the same result, and a result MUST NOT retain the judged commit’s ancestry the way a pin does. |
docs/spec/model.adoc, [#model.result-identity], ~L271-274 |
alloy-paper |
gap-unmarked |
OPEN |
— |
A toolchain is a hash-pinned ~1KB manifest carrying its own provenance, "a resource an effect declares as a dependency … never a trigger condition in its own right". |
docs/spec/model.adoc, [#model.toolchain], ~L279-289 |
— |
gap-unmarked |
OPEN |
— |
A Redaction entity carries the target oid, a reason, and the admin signature; it "MUST NOT carry the redacted content itself". |
docs/spec/model.adoc, [#model.redaction], ~L294-300 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Authentication state MUST live in the repository as ordinary forge state; "a session database or token table MUST NOT back it". |
docs/spec/model.adoc, [#model.account], ~L308-313 |
— |
gap-unmarked |
OPEN |
— |
The library MUST NOT define its own ObjectStore trait — gitoxide’s |
docs/spec/overview.adoc, [#arch.no-object-store-trait], ~L180-189 |
— |
gap-unmarked |
OPEN |
— |
The gate’s pure verify function MUST live in a crate separate from |
docs/spec/overview.adoc, [#arch.gate-receive-split], ~L191-199 |
— |
gap-unmarked |
OPEN |
— |
The query algebra MUST live apart from executor code; |
docs/spec/overview.adoc, [#arch.query-effect-split], ~L201-208 |
— |
gap-unmarked |
OPEN |
— |
A concrete store implementation is wired only inside a composition root, never a library crate, and is not promoted to a shared library crate until a second root consumes it. |
docs/spec/overview.adoc, [#arch.store-composition-root], ~L211-219 |
— |
gap-unmarked |
OPEN |
— |
A loose-ref RefStore MUST write refs through its own CAS discipline and MUST NOT shell out to |
docs/spec/overview.adoc, [#arch.loose-cas-discipline], ~L239-245 |
stateright |
gap-unmarked |
OPEN |
— |
A CommitQuery MUST parse per the fixed grammar; |
docs/spec/query.adoc, [#query.grammar] (+ [#query.set-ops]), ~L12-35 |
stateright |
gap-unmarked |
OPEN |
— |
Unsupported rev syntax ( |
docs/spec/query.adoc, [#query.rev], ~L39-58 |
stateright |
gap-unmarked |
OPEN |
— |
Membership in |
docs/spec/query.adoc, [#query.results], ~L61-79 |
stateright |
gap-unmarked |
OPEN |
— |
The fanout index "MUST NOT be addressable by any query atom at all". |
docs/spec/query.adoc, [#query.meta], ~L82-91 |
stateright |
gap-unmarked |
OPEN |
— |
|
docs/spec/query.adoc, [#query.workset], ~L159-173 |
stateright |
gap-marked (work-set/dedup materialization is the declared cross-transaction gap) |
OPEN |
— |
Replicating refs a trusted remote already admitted MAY apply directly (re-verification on fetch is opt-in audit); commits the replicating machinery authors itself — divergence and adoption merges — are origination, not replication. |
docs/spec/receive.adoc, [#receive.unit], ~L10-27 |
stateright |
gap-unmarked |
OPEN |
— |
Gate evaluation MUST be checkable against exactly the proposal shape, frontend-independent; meta-ref admission "MUST ignore [transport-auth evidence] entirely and MUST NOT consult it in place of the tip invariant". |
docs/spec/receive.adoc, [#receive.proposal-shape], ~L29-47 |
stateright |
gap-unmarked |
OPEN |
— |
An entity declared across multiple refs MUST write them in a single Proposal through one |
docs/spec/receive.adoc, [#receive.multi-ref-atomicity], ~L49-66 |
stateright |
gap-unmarked |
OPEN |
— |
A |
docs/spec/receive.adoc, [#receive.object-access], ~L93-105 |
stateright |
gap-unmarked |
OPEN |
— |
Pending obligations MUST be derivable from repository state alone; an EventSink MAY lose events on crash provided the root reconciles at startup before serving pushes; "a durable queue MUST be treated as a performance optimization, never a correctness requirement". |
docs/spec/receive.adoc, [#receive.reconstructible], ~L134-146 |
stateright |
gap-marked (cross-transaction queue/materialization state is the declared dedup gap) |
OPEN |
— |
A push to |
docs/spec/receive.adoc, [#receive.redaction-admin-only], ~L148-158 |
search |
gap-unmarked (effect_admin_violation covers only |
OPEN |
— |
The local root wires loose refs, the odb, Docker, null EventSink, and the advisory gate; |
docs/spec/roots.adoc, [#roots.local], ~L20-32 |
— |
gap-unmarked |
OPEN |
— |
The single-node hosted root’s hooks call the gate and reconcile around |
docs/spec/roots.adoc, [#roots.single-node-hosted], ~L34-52 |
stateright |
gap-unmarked |
OPEN |
— |
The worker MUST NOT share in-process state with |
docs/spec/roots.adoc, [#roots.hosted], ~L55-63 |
stateright |
gap-unmarked |
OPEN |
— |
Wiring the scale-out root (Postgres/Tigris/durable queue) MUST require zero modification to any library crate — the seam design’s honesty test, proven by an actual production migration. |
docs/spec/roots.adoc, [#roots.honesty-test], ~L66-75 |
— |
gap-unmarked |
OPEN |
— |
Configuration selects trait implementations only at the composition root and MUST NOT leak past it. |
docs/spec/roots.adoc, [#roots.config-isolation], ~L78-83 |
— |
gap-unmarked |
OPEN |
— |
|
docs/spec/roots.adoc, [#roots.web-agnostic], ~L96-103 |
— |
gap-unmarked |
OPEN |
— |
A hosted web session is held only in server memory; every state-changing request carries a per-session CSRF token verified before acting; a web edit is signed only on behalf of an authenticated session. |
docs/spec/roots.adoc, [#roots.web-session], ~L141-148 |
— |
gap-unmarked |
OPEN |
— |
Every repository-path segment MUST be validated before filesystem or subprocess use, rejecting escapes, nesting inside an existing repository, or namespace-directory collisions. |
docs/spec/roots.adoc, [#roots.path-validation], ~L151-158 |
— |
gap-unmarked |
OPEN |
— |
Fetch authorization MUST be refname-keyed, using the same authorization model as write authorization. |
docs/spec/roots.adoc, [#roots.fetch-auth], ~L160-167 |
search |
gap-unmarked |
OPEN |
— |
A clone plus |
docs/spec/sync.adoc, [#sync.forge-transfer], ~L9-16 |
alloy-paper |
gap-unmarked |
OPEN |
— |
Inbox adoption and self-run adoption MUST both go through the same merge machinery as divergence resolution, "not a separate adoption code path". |
docs/spec/sync.adoc, [#sync.adoption-machinery], ~L50-57 |
stateright |
gap-unmarked |
OPEN |
— |
"Nothing in the resulting ref-store state lets a pure verifier tell" a cherry-picked adoption from a hand-authored commit — attribution preservation binds the merge machinery, never the gate. |
docs/spec/sync.adoc, [#sync.adoption-no-cherry-pick] (also gate.adoc Adoption intro ~L218-224), ~L59-73 |
stateright |
gap-unmarked |
OPEN |
— |