A reading of our own work is answered where it is read, and never stored as a visitor's comment
Accepted
Context
Two things arrived at the foot of the same post on 2026-09-16, and the project had a place for neither.
A third party gave «Un freno no es un rumbo» (verifiable-course) to two models and shared both conversations. One answer was praise. The other carried three objections worth more than the praise: the three cases come from the author's own ecosystem and do not compare the approach against tests, observability or policy-as-code; declaring purpose, territory and provenance builds a second formal reality that can drift from the first; and the judgement the post keeps at the end of every rung is not removed, only bounded.
adr-080 could JUDGE those readings — custody in refs/, claim-level verdicts in sources/ — and could not ANSWER them. The judgement record had no field for what of ours was being read, no field for a reply, and the routing sent every 'Challenge inward with the rule that it never returns outward as an announcement of intent. Publishing a reply meant writing it by hand into the post, where the quote leaves the record and adr-080's own rule — a claim not in the record is not published — breaks the first time the prose is edited.
At the same foot sat the site's comment form. Measured the same day: rustelo_server stores the message with a publish-consent proof (timestamp and IP), the site's migrations add the columns, and the development store holds seventy messages, four with consent, every one in status `new`. Nothing moves a message out of `new`, nothing reads a published one, no route serves them and no template renders them. The form's checkbox promises a public comment the system cannot produce.
The obvious unification — insert the model readings into the comment store and finish the comment feature once — was the first idea on the table, and it is what this decision refuses.
Decision
ONE SURFACE, TWO STORES, AND THE BOUNDARY BETWEEN THEM IS PROVENANCE.
1 · THE READING OF OUR WORK IS A SOURCE WITH A SUBJECT (Base, additive)
`Source.subject` names the published artefact of this project the signal is a reading of — a post id, an ADR, a narrative. Empty is the ordinary case: a reading of the terrain. It names what was read about, never where anything will appear; the verdict vocabulary is untouched and still names relations only (adr-080 `verdict-names-a-relation-never-an-artefact`).
A claim may carry `response`, keyed by language, and `quote_i18n`, translations of the quote that never replace the literal. `SignalKind` gains `'Conversation`: one prompter, one respondent, an answer that depends on what was asked — so the capture holds the prompt with the answer.
`make_source` refuses, at export: · a response with no quote — an answer to our own paraphrase is a reply to nobody; · a response with no subject — the project answers readings of its work, it does not comment on other people's; · a 'Challenge carrying a response with no `consequences.backlog` — the answer names the address of the gap instead of promising to close it. This is how a 'Challenge may appear outward without becoming the announcement of intent adr-080 forbids; · (amendment) a `response_refs` entry that is not `<kind>:<id>` over the closed kinds, or refs carried by no response. An answer POINTS at what makes it true — a proof, a consumer project, a backlog item — and the projection resolves every ref or fails its check.
2 · CURATED READINGS ARE VERSIONED JUDGEMENT; VISITOR COMMENTS ARE RUNTIME DATA
A reading of our work — by a model, or by a person we quote — lives in sources/ with custody in refs/, and reaches the post by PROJECTION: a generator writes a delimited block into the post's sources from the judgement record, and a check mode fails when the block and the record differ. It is never inserted into the comment store: that would fabricate a consenting visitor, and would turn a digest-backed, locator-anchored judgement into a row nobody versions.
A visitor comment lives in the site's database. Consent is NECESSARY and not SUFFICIENT for publication: a message becomes public only by an explicit moderation act, from the CLI, which refuses a message without consent; the author's reply is stored with the comment it answers. A visitor comment becomes a judgement only by being assessed as a signal, like anything else read.
3 · ONE PRESENTATION: PERSPECTIVES
Both render at the foot of the post in one block, each entry labelled by origin — a curated reading names the respondent, the date, the prompt and the link to the shared original; a visitor comment names its author and date. Two feet competing for the reader would hide the thing the block exists for: voices side by side, each answered.
4 · WHAT A READING OF OUR WORK BECOMES (Project routing — applied on acceptance)
signal-routing-howto gains the row for a source with a subject: a projection into that subject's perspectives block, gated: · at least one projected claim is a 'Challenge — an objection, answered with its address. A reading whose claims are all 'Convergent or 'Adjacent is recorded and not projected: praise from a model is a testimonial, and a wall of them is the reach reach-vs-qualification refuses; · every projected claim carries a response in every language the subject is published in; · attribution names the respondent as the capture declares it — a model name the share does not state is not supplied from memory.
Constraints
- Hard A claim's response requires the quote it answers and a source subject; make_source refuses either absence at export.
- Hard A 'Challenge claim carrying a response requires a non-empty consequences.backlog.
- Hard Nothing in the positioning tree, the reflection modules or the ontology defaults writes to or names the site's comment table.
- Hard Every response_refs entry is <kind>:<id> over adr|bl|node|proof|domain|project|qa|source|post, and refs require a response.
- Hard Every response_refs entry of a projected claim resolves to an existing artefact of its kind.
- Soft The perspectives block in a post equals what the projection generator derives from the source records naming that post as subject.
- Hard A visitor message reaches public status only through the moderation CLI, which refuses a message whose publish_consent is false.
Alternatives considered
- Insert model readings into the site's comment store and finish comments once — rejected: It fabricates a visitor who gave consent, drops the digest and the locator, and moves a versioned judgement into runtime data no one reviews in a diff.
- Write a section into the post by hand — rejected: The quote and the answer leave the judgement record; the first prose edit breaks adr-080's rule that a claim not in the record is not published, and nothing detects it.
- Two blocks at the foot: readings and comments — rejected: Two surfaces compete for the same reader and split the one comparison the block exists to offer — voices side by side, each answered.
- A new verdict for a reading of our own work — rejected: The seven verdicts already name relations to the subject, and they fit the case — the objections are 'Challenge and 'Convergent. What is new is WHOSE subject, which is a field of the source, not a relation.
- Publish a comment on consent alone — rejected: Consent proves the visitor allowed it, not that it should be shown; the store holds unreviewed messages with consent beside spam without it.
Anti-patterns
- Model praise published as endorsement — Readings whose claims only agree with the post are shown at its foot, borrowing a model's fluency as evidence that the post is right.
- An objection answered with an intention — A public reply to a gap says it will be addressed, and reads to everyone downstream as addressed.
- Publishing a comment because its author allowed it — The consent checkbox is treated as the decision to publish, skipping review.