Home / Projects / Orchestrata Ultimate / Decisions / ADR index / ADR-0096
ADR-0096: ADR body-drift dispositions — the graph sync treats wiki pointer entries as pointers, the three-way check compares bodies, ADR-0073's graph body is re-baselined once to its docs body, and the post-acceptance edits of ADR-0004 and ADR-0019 are ratified as their accepted text
| field | value |
|---|---|
| Status | Accepted — Accepted (ruling, Mohamed, 2026-10-13, verbatim: "fix the sync and the check, re-baseline 0073, ratify 0004 and 0019") |
| Date | 2026-10-13 |
| Register | factory (docs/adr, 4-digit ids) |
| Source | docs/adr/0096-adr-body-drift-dispositions-sync-skips-wiki-pointers-check-compares-bodies-0073-rebaselined-0004-and-0019-ratified.md — permalink at 639cc9f62 (unchanged on master since that commit) |
| Wiki register entry | ADR-0096 (wiki status: Accepted) |
The record
Status: Accepted (ruling, Mohamed, 2026-10-13, verbatim: "fix the sync and the check, re-baseline 0073, ratify 0004 and 0019") · Date: 2026-10-13 · Applies ADR-0046 (three homes), ADR-0047 (two registers), ADR-0085 (every ruling recoverable and logged) · Evidence: scratchpad/adr-body-drift-audit-2026-10-13.md (auditor, 36 ids, graph read live)
Context
The 2026-10-13 run of scripts/sync_architecture_to_graph.py --adrs refused
36 BODY_DRIFT writes against Accepted ArchitectureDecision nodes while
scripts/check_adr_graph_sync.py reported "120 ids examined, no drift".
The audit measured:
- 35 of 36 are a two-writer artefact, not an edit. The graph holds the
full
docs/adr/body and itsbody_shaequals the HEAD docs hash for all 35. The wiki entry for each id is a one-paragraph pointer ending "Full record: docs/adr/…", added once in wiki commit13e0902(2026-08-29) and never edited. The sync's wiki pass (parse_adrs, which folds all prose intodecision) hashes the pointer, gets a different value, and the immutability guard (architecture_writer._adr_body_sha, hashing context, decision, alternatives, consequences) correctly refuses it. Only the wiki pass ran that day. - ADR-0073 is the one stale graph body. The graph captured the wiki
summary at wiki rev
db6ca40while the ADR was Proposed and never took the full docs body; context, alternatives and consequences are empty in the graph.parse_adr_filealso reads its bareStatus:line as empty. - ADR-0004 and ADR-0019 were edited in docs after acceptance but before
the graph first captured them, so the graph already holds the edited
text: 0004 gained the binding "one factory per Neo4j database" rule in its
Decision (
8add37289, 2026-07-24); 0019 gained a "Mechanism change" section replacing Neo4j bookmarks with a watermark token (0b9ebc64a, 2026-07-26), stating the decision itself unchanged. - The check script compares titles and presence only
(
check_adr_graph_sync.py:277-454), neverbody_sha; that is why it is green while the sync is red. - Status flips do not trip the hash (ADR-0013…0025, 0028…0033 flipped in
5fe5a7916with identical hashes). Provenance appends do, becauseparse_adr_filefolds## Provenanceinto consequences.
Decision (Mohamed's ruling, restated as the executable rule)
- Fix the sync. The wiki pass recognises a pointer entry (an entry whose
body is one paragraph ending in
Full record: docs/adr/<file>) and does not hash or write a body for it; factory-register ids are written fromdocs/adr/only.parse_adr_filereads a bareStatus:line. The immutability guard is unchanged. - Fix the check.
check_adr_graph_sync.pycomparesbody_shabetween the docs body and the graph for every factory id, treating wiki pointers as pointers, and reports body drift as a violation. A green check now means titles, presence and bodies agree. - Re-baseline ADR-0073 once. After rule 1 lands, the graph node for ADR-0073 is rewritten from its docs body (full context, decision, alternatives, consequences, status Accepted) through an explicit, logged, single-id re-baseline path that names this ADR as its authority; the path is not a general override and refuses any id this ADR does not name.
- Ratify ADR-0004 and ADR-0019 as they stand. Their current docs text, including the post-acceptance additions named in Context, is the accepted text; the graph already holds it; no superseding ADR is written. Future in-place edits of Accepted bodies remain forbidden; this ratification is retrospective and closed.
- Hash policy unchanged. Provenance stays inside the hashed body for now (Mohamed did not rule on excluding it); the sync's parser fix in rule 1 is scoped to pointers and the status line.
Alternatives rejected
- Re-baseline all 36. Would overwrite 35 correct graph bodies with wiki pointers; the audit showed no edit behind them.
- Supersede 0004 and 0019. The edits predate the graph's capture and the graph already holds them; a superseding ADR would record no change.
- Leave the check as is. It has been green through a real stale body (0073); a check that cannot see bodies cannot guard immutability.
Consequences
- Builder brief:
plans/briefs/2026-10-13-adr-sync-pointers-check-bodies-rebaseline-0073.md(DESIGN_WAIVER: ADR-0096). Files:scripts/sync_architecture_to_graph.py,scripts/check_adr_graph_sync.py,src/orchestrata_ultimate/knowledge_graph/architecture_writer.py, tests beside them; real graph, no doubles. - After the fix, a sync run reports 0
BODY_DRIFTfor the 35 and the check reports body agreement for 120 ids including 0073. - The scratch AST snapshot
plans/ast-ultimate.jsonthe auditor's queries regenerated is left to its owning session.
Provenance
Mohamed, 2026-10-13, verbatim in Status, after the coordinator presented the
audit's four decisions. Audit by a read-only auditor agent the same day;
scratch data (graph_adrs.json, analysis.json, wiki_cmp.json,
wiki_hist.json) beside the report. Recorded by the coordinating session;
the code change is delegated under the brief above.
Related ADRs
Rulings cited
None.
Specs cited
None (or no spec page exists for the ones named).