-- Objections « redit » / « contredit », typo fixes validated, and the messages -- of trustinWallet (2026-10-31, lot F, ADR 0010). Additive only: nothing is -- dropped, nothing is rewritten that an older image needs. -- -- The contradiction signals of before become objections « contredit », in the -- same table: an older image (rollback) still reads them as signals, and every -- lifting still writes `lifted_at` / `lifted_by` as before. ALTER TABLE signals ADD COLUMN kind TEXT NOT NULL DEFAULT 'contredit'; -- redit | contredit ALTER TABLE signals ADD COLUMN held_id TEXT; -- the version held back (not votable): the latest arrival, never one in force ALTER TABLE signals ADD COLUMN phase TEXT NOT NULL DEFAULT 'author'; -- author | objector | lifted ALTER TABLE signals ADD COLUMN cycle INTEGER NOT NULL DEFAULT 1; -- a reiteration opens the next ALTER TABLE signals ADD COLUMN due_at TEXT; -- phase objector: lifted by itself at this time ALTER TABLE signals ADD COLUMN answered_at TEXT; -- the last answer of the author ALTER TABLE signals ADD COLUMN answer TEXT; -- revision | other | proposal ALTER TABLE signals ADD COLUMN answer_id TEXT; -- the version revised, or the proposal linked ALTER TABLE signals ADD COLUMN lift TEXT; -- objector | admin | deadline | withdrawn | revision -- The signals of before that were lifted stay lifted: by their author, by an -- administrator, or because the text changed (the rule of before). UPDATE signals SET phase = 'lifted', lift = CASE WHEN lifted_by = 'revision' THEN 'revision' WHEN lifted_by = author_id THEN 'objector' ELSE 'admin' END WHERE lifted_at IS NOT NULL; -- A standing one whose other side left (withdrawn, or never submitted) ends: a -- withdrawal ends the objection, which the rule of before did not do. UPDATE signals SET phase = 'lifted', lift = 'withdrawn', lifted_by = 'withdrawn', lifted_at = strftime('%Y-%m-%dT%H:%M:%SZ', 'now') WHERE lifted_at IS NULL AND EXISTS ( SELECT 1 FROM proposals p WHERE p.id IN (signals.proposal_id, signals.target_proposal_id) AND p.status NOT IN ('open', 'in_force')); -- The standing ones wait for the author of the version they now hold back: the -- latest arrival of the two (submitted last; the same instant: written last), -- unless it is in force — then the other. Both in force: none is held. UPDATE signals SET held_id = ( SELECT CASE WHEN a.status = 'in_force' AND b.status = 'in_force' THEN NULL WHEN (IFNULL(a.submitted_at, a.created_at), a.rowid, a.id) > (IFNULL(b.submitted_at, b.created_at), b.rowid, b.id) THEN CASE WHEN a.status = 'in_force' THEN b.id ELSE a.id END ELSE CASE WHEN b.status = 'in_force' THEN a.id ELSE b.id END END FROM proposals a, proposals b WHERE a.id = signals.proposal_id AND b.id = signals.target_proposal_id) WHERE lifted_at IS NULL; CREATE INDEX signals_proposal ON signals(proposal_id); CREATE INDEX signals_target ON signals(target_proposal_id); CREATE INDEX signals_due ON signals(phase, due_at); -- One person, one standing objection on a pair, whichever way it was written -- (relecture of cd7e683: sent four times at once, four stood). CREATE UNIQUE INDEX signals_one_standing ON signals(author_id, min(proposal_id, target_proposal_id), max(proposal_id, target_proposal_id)) WHERE lifted_at IS NULL; -- A proposal written to answer an objection (« modifier l'article visé »). ALTER TABLE proposals ADD COLUMN objection_id TEXT; -- A typo fix written by someone other than the one who answers for the version: -- it waits for them (or for the deadline), then applies — or not. CREATE TABLE typos ( id TEXT PRIMARY KEY, proposal_id TEXT NOT NULL REFERENCES proposals(id), doc_id TEXT NOT NULL REFERENCES documents(id), writer_id TEXT NOT NULL REFERENCES identities(id), -- who wrote the fix answerer_id TEXT, -- the author of the version, who answers; NULL = administrators (no author) revision INTEGER NOT NULL, -- the revision it was written over base_title TEXT NOT NULL, -- the text it was written over base_body TEXT NOT NULL, title TEXT NOT NULL, -- the fix body TEXT NOT NULL, status TEXT NOT NULL, -- pending | applied | refused | stale created_at TEXT NOT NULL, due_at TEXT NOT NULL, -- applied by itself then, if nobody answered settled_at TEXT, settled_by TEXT -- identity id, 'deadline', or 'changed' (stale) ); CREATE INDEX typos_proposal ON typos(proposal_id, status); CREATE INDEX typos_due ON typos(status, due_at); -- The revision a validated fix wrote, or the one that took it back (kind 'revert'), -- and who let it in: the identity that validated it, or 'deadline'. ALTER TABLE revisions ADD COLUMN typo_id TEXT; ALTER TABLE revisions ADD COLUMN answered_by TEXT; -- The messages of trustinWallet: one person, one box. The text is told by the -- interface from the subject (in the language of the reader); the gestures -- follow the subject's state, so a message dealt with offers none. CREATE TABLE messages ( id TEXT PRIMARY KEY, recipient_id TEXT NOT NULL REFERENCES identities(id), doc_id TEXT NOT NULL REFERENCES documents(id), topic TEXT NOT NULL, -- objection | typo subject_id TEXT NOT NULL, -- signals.id | typos.id kind TEXT NOT NULL, -- objection_raised | objection_reiterated | objection_answered | typo_pending cycle INTEGER NOT NULL DEFAULT 1, created_at TEXT NOT NULL, due_at TEXT, read_at TEXT, done_at TEXT, outcome TEXT -- answered | lifted | reiterated | deadline | admin | withdrawn | applied | refused | stale ); CREATE INDEX messages_box ON messages(recipient_id, created_at); CREATE INDEX messages_subject ON messages(topic, subject_id);