State engine

Status: draft

Proposals by Claude – not binding until Daniel approves them.

State is never stored, always computed from the annotations plus the current source. The engine does it in three steps for every annotated file.

State engine pipeline: resolve the target, compare the fingerprint, compute the state source file+ annotation file 1 · resolvestructural → quote → position 2 · comparefingerprint now vs. then 3 · stateper element not found → orphaned changed → stale / alarm

1 · Resolve

Proposal: Selectors are tried in a fixed order and the first unique hit wins PROP_RESOLVE
status: draft
  1. Structural – the adapter’s element list has an element with exactly this selector.

  2. Text quote – the exact text occurs once in the file; if it occurs several times, prefix and suffix decide. Whitespace differences are ignored.

  3. Position – only if the text at that position still matches the fingerprint.

If the selector that hit is not the first one, the engine reports a relinked hint so deciwa can update the stored selectors (only on an explicit deciwa relink, never silently). Nothing hits → orphaned. Text quote and position follow the W3C Web Annotation Data Model.

2 · Compare

Proposal: The fingerprint covers the source text with whitespace normalised PROP_FINGERPRINT
status: draft
refines: PROP_RESOLVE

sha256 over the element’s source text after Unicode NFC, trimming and collapsing runs of whitespace into one space. Markup stays in: turning a word bold makes an approval stale.

Question: Should pure formatting changes make an approval stale? Q_FINGERPRINT_MARKUP
status: open
to: Daniel

With markup in the fingerprint, bold, a new link or a re-wrapped table makes an approved statement stale. Without it, only changes to the words do – but deciwa then has to strip markup per format. Proposal: keep markup in for 0.1 (simple, safe); revisit if it is too noisy in the knowledge base.

3 · State

Ratings and notes never change the state. For everything else the engine looks at the open and the latest annotations of an element and picks the first rule that applies:

#

Rule

State

1

target not found

orphaned

2

latest freeze is in force and the fingerprint changed

frozen, but changed

3

latest freeze is in force

frozen

4

an open delete job

changes requested

5

latest verdict is an open reject (not fixed yet)

rejected

6

latest verdict is approve and the fingerprint changed

stale

7

latest verdict is approve

approved

8

an open request

requested

9

none of these

unreviewed

Proposal: State rules in this order PROP_STATE_RULES
status: draft

An open request is shown as a badge on top of every other state, so approved with an open question is still visible as approved. A resolved quick action does not approve anything: after deciwa resolve the element falls back to its previous state, and the stale check shows that it was changed.

Question: How is a freeze lifted? Q_UNFREEZE
status: answered
to: Daniel

Options were: (a) a new verdict on the element ends the freeze; (b) an explicit deciwa unfreeze <id>; (c) only by deleting the freeze annotation. Answered by Daniel (2026-10-19): (a) – see A freeze ends with a new ve... (DEC_FREEZE_BY_VERDICT).