# ADR 003: Versioned editor record contract

- HTML version: https://robbiepalmer.me/projects/agent-first-writing/adrs/003-versioned-editor-record-contract
- Project: Agent-first Writing Editor (https://robbiepalmer.me/projects/agent-first-writing.md)
- Status: Accepted
- Date: 2026-09-04
- Initiatives: Semi-autonomous Software Development (https://robbiepalmer.me/initiatives/semi-autonomous-software-development.md)

# Context

Vale, future classifiers, and contextual models need to report their results
through one review workflow. Free-form comments cannot reliably anchor a
passage, produce a diff, record a decision, or replay an evaluation against a
later editor version.

These producers do not all return the same kind of result. A rule may identify
a passage without knowing how to rewrite it. Another producer may supply a
safe local replacement. Passage rewrites can contain several edits that only
make sense together.

# Decision

Define version 1 records for findings, suggestions, proposals, and decisions.
They share a source reference containing the document ID, revision, and
SHA-256 hash of the exact UTF-8 source bytes.

A finding records:

* a stable finding ID;
* the producer ID, version, and rule or model provenance;
* a half-open UTF-8 byte span and its exact source text;
* a category and reason; and
* optional confidence.

Use a finding when the producer can locate a problem but cannot provide a safe
replacement. Findings never form proposals and never receive accepted,
rejected, or changed decisions.

A suggestion records the same source, span, producer, category, reason, and
optional confidence fields. It also contains a replacement and a stable
suggestion ID. A suggestion must represent an actionable edit, not a no-op or
a guessed deletion used to satisfy the schema.

Calculate finding and suggestion IDs from a canonical encoding of the schema
version, producer identity and version, source identity and revision, source
hash, span, and category. Include the replacement in suggestion identity. Keep
the reason, confidence, and detailed provenance outside both identities. Sort
records by start byte, end byte, producer ID, and record ID so independent runs
produce the same order.

Group dependent suggestions under one proposal so the interface can show their
combined replacement as a readable diff. Every proposal records a stable
proposal ID and an ordered list of member suggestion IDs. Use the suggestion
sort order for that list, and calculate the proposal ID from a canonical
encoding of the schema version and ordered member IDs. A suggestion shown on
its own forms a one-member proposal.

Record a decision for each reviewed proposal with an `accepted`, `rejected`,
or `changed` outcome. A changed decision stores the replacement the user chose.
Preserve the complete proposal, ordered member IDs, schema version, producer
versions, and source revision with the decision.

Before display or application, verify the source hash and confirm that the
recorded span contains the recorded source text. Treat a mismatch as a
stale-span conflict. Re-run the producer against the new revision, or create an
explicit migrated proposal that retains the old ID as provenance.

# Consequences

Detection-only rules and rewrite producers can share one source contract
without pretending they return equivalent evidence. Only actionable edits
enter the proposal and decision workflow. Later evaluations can separate a
detector's coverage from a rewrite's quality and recorded outcome.

Schema versioning adds migration work. Byte spans also require adapters at UI
boundaries that use another offset convention, but they keep the stored
contract unambiguous across producer languages.

# Implementation

The `writing-editor-domain` workspace package implements version 1. It
validates findings, suggestions, proposals, and decisions at runtime,
calculates their stable IDs, sorts proposal members, and rejects stale source
hashes or byte spans. Decisions embed the complete proposal so evaluation jobs
do not reconstruct the original suggestions from mutable producer output.

---

Markdown index of this site: https://robbiepalmer.me/llms.txt
