spec: pin reviewed content with a second ref per review
commit
c176d17spec: pin reviewed content with a second ref per review
A data field cannot keep the reviewed commit alive; the pin ref can. Each re-review advances the pin fast-forward with a merge-shaped signed commit, retaining every reviewed round as its own audit trail.
spec: require the refs/meta/pins/reviews/<id> retention pin (model.review-pin) spec: exempt refs/meta/pins/* from the tree-is-the-entity shape Assisted-by: Claude:claude-fable-5
Reviews
No reviews of this commit yet — record a verdict below.
Start a review
docs/development-plan.adoc
@@ -223,7 +223,11 @@
`model.comment-thread`, `model.review`): the Comment struct's migration
(`meta-ref.migration` — old trees must stay readable), working-tree
capture and projection in `ents-anchor` (`anchor.working-tree`), the
- Review entity, and porcelain — `comment reply/resolve/reopen`,
+ Review entity plus its retention pin ref (`model.review-pin` —
+ `refs/meta/pins/reviews/<id>`, an empty-tree signed commit whose
+ parents include the reviewed commit; verify the gate's tip-signed and
+ fast-forward checks accept the merge-shaped pin advance), and
+ porcelain — `comment reply/resolve/reopen`,
`comment list --worktree` with a machine-readable form (`lens.parity`),
`issue` and `review` actions.
docs/spec/meta-ref.adoc
@@ -21,6 +21,9 @@
synchronization (fetching or pushing the ref moves exactly that entity),
authorization (refname-keyed rules gate who may advance it), and history
(its commit chain is the audit trail).
+Retention pins under `refs/meta/pins/*` (<<model.review-pin>>) are the
+sole exception: a pin's commits anchor other content's reachability and
+carry the empty tree, never an entity.
--
[role="requirement", id="meta-ref.granularity"]
docs/spec/model.adoc
@@ -162,13 +162,17 @@
.Review Is a Verdict Plus a Context
--
A Review entity MUST be a typed tree under its own ref in
-`refs/meta/reviews/*`, one ref per review (<<meta-ref.granularity>>),
+`refs/meta/reviews/<id>`, one ref per review (<<meta-ref.granularity>>),
written, gated, synced, and audited exactly like a comment.
-A Review MUST carry the reviewed commit's id as a plain data field —
-best-effort reachability, the same stance <<anchor.immutable>> takes for
-an anchor's commit — a verdict, and a body; `approve` and
-`request-changes` are conventions, not an enum, because custom verdicts
-are schema, not platform features (<<model.extensibility>>).
+Every review MUST occupy exactly two refs: the entity ref above, and a
+retention pin at `refs/meta/pins/reviews/<id>` anchoring the reviewed
+content itself (<<model.review-pin>>).
+A Review MUST carry the id of the most recently reviewed commit as a
+plain data field, a verdict, and a body; reading the field MUST NOT
+require the pin ref — the pin anchors, the entity describes.
+`approve` and `request-changes` are conventions, not an enum, because
+custom verdicts are schema, not platform features
+(<<model.extensibility>>).
A review's discussion MUST be Comment entities naming the review as
their context (<<model.comment-context>>), anchored into the reviewed
code where they concern specific lines (<<anchor.definition>>); the
@@ -177,6 +181,27 @@
(<<meta-ref.trailers>>).
--
+[role="requirement", id="model.review-pin"]
+.The Review Pin Anchors the Reviewed Content
+--
+A review's pin ref, `refs/meta/pins/reviews/<id>` — the entity's own
+canonical suffix prefixed the same way <<meta-ref.inbox>> prefixes one —
+MUST keep the reviewed content reachable: its tip is a signed commit
+authored by the reviewer 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.
+This is the commit-level counterpart of <<anchor.retention>>, which can
+embed blobs but has no reachability edge for commits — a gitlink is not
+one.
+Re-reviewing after the target moves MUST advance the pin fast-forward
+with a new signed commit whose parents are the previous pin tip and the
+newly reviewed commit, so every reviewed round stays retained and the
+pin's own history is the audit trail of exactly what was reviewed, when.
+A pin commit carries no entity: its tree MUST be the empty tree, the
+sole deliberate exception to <<meta-ref.namespace>>'s
+tree-is-the-entity shape.
+--
+
=== Effect
[role="requirement", id="model.effect-definition"]