Orchestrata Ultimate Decisions

RATIFIED 2026-07-19: the Architecture Ontology (31 node types / 44 relationships) — all eight rulings decided (MR !4): ADR guard+gate immutability; unified project-qualified Component; Rule→Constraint fold; phase-2 Memgraph semantic twin; ArchitectureDecision distinct from Decision; lazy CloudService + curated seed; OpenSpec owns the Change key; converged writer both-phased with a full architecture sync at session start (amended 2026-07-19, backgrounded + ADR-guard enforced). Phase 1 implemented & merged 2026-07-19 (MR !6, merge 340f3429): schema extension, unified Component, converged ArchitectureWriter, both-layer ADR guard, reference seed, and the SessionStart full-sync hook — 236/236 phase tests observed, live graph conforms. Phase 2 implemented & deployed 2026-07-19: the ADRs below are live ArchitectureDecision KG nodes (20 at the 2026-07-19 deploy; later ADRs sync via the SessionStart full-sync hook) (all Accepted, ruling-1 immutability guard active — an Accepted ADR's body on this page must NOT be edited in place; record a new ADR and supersede), and their prose is semantically retrievable from the Memgraph twin (ArchitectureChunk, 20 ADR + 11 design-doc chunks). The SessionStart hook keeps both graphs in step.

ADR categories at a glance (24 ADRs below, grouped by concern)

Diagram projects-orchestrata-ultimate-decisions-1

ADR-001: Memgraph as Semantic Graph Backend

ADR-002: Repository Pattern Over Direct Bolt

ADR-003: Single HA Controller Container (Interim)

ADR-004: ASYNC Replication Default

ADR-005: Monkeypatch Fully Forbidden Suite-Wide

ADR-006: Governance Wired into PipelineRunner (P0.1)

ADR-007: Prolog Atom Escaping (P0.2)

ADR-008: get_neighbors With depth < 1 Returns Empty

ADR-009: Fail-Closed Governance by Default (P0.3)

Date: 2026-07-08 · Status: Accepted

All governance error paths (may_complete, requires_human_consent, constitutional check, prolog_client queries) fail CLOSED when ORCHESTRATA_GOVERNANCE_STRICT is unset or true (read at call time via governance/_strict.py). Set the flag to false for legacy permissive behavior in dev/test.

ADR-010: All Persistence Through Core Factories (D12 P1)

Date: 2026-07-08 · Status: Accepted, enforced

Every Neo4j/Redis client construction routes through core.neo4j_factory / core.redis_factory (22 call sites migrated). Enforced by a blocking architecture_checker AST rule — direct GraphDatabase.driver/redis.Redis calls outside the factories fail CI.

ADR-011: NO_AUTH Sentinel for Unauthenticated Bolt

Date: 2026-07-08 · Status: Accepted

core.neo4j_factory.NO_AUTH means "explicitly no auth" (Memgraph nodes); auth=None means "unset — fall back to NEO4J_USERNAME/NEO4J_PASSWORD env".

ADR-012: core.protocols Is the Canonical Interface Home (P2)

Date: 2026-07-08 · Status: Accepted

All interface imports use core.protocols; core.interfaces survives only as a thin re-export shim for legacy test paths. Forward references are TYPE_CHECKING-only imports from canonical modules (no = Any sentinels). Companion P2 refactors: gateway start() decomposed into _init_* steps, LLM provider registration is a data-driven PROVIDER_CONFIGS table with double-checked-locked manager init, deprecated CXP packet shims live in cxp/compat.py.

ADR-013: Hybrid RRF Retrieval + TESTS Edges in the Semantic Graph

Date: 2026-07-08 · Status: Accepted, live

Semantic search fuses vector (0.6) and keyword (0.4) rankings via RRF (k=60) with the vector candidate pool always preserved into the reranker; module-name and log(prominence) boosts apply. Canonical chunk label is CodestralChunk. The enrichment layer now includes TestCase/TestModule entities with 13k TESTS edges, completing spec→requirement→code→test navigation. Cheap retrieval CLI: scripts/semantic_search.py. QA benchmark: 82% avg coverage, 0/100 low-quality (plans/semantic_graph_qa_results_latest.md; older snapshots archived).

ADR-014: review_edit Is a Deterministic Fail-Closed Floor

Date: 2026-07-08 · Status: Accepted

Cheetahclaws /edit reviews are answered by U:Cd/U:Qa/U:Ar deterministic checks (fragment-tolerant AST: syntax, mass-deletion, bare-except, test-weakening via real assert-statement counting, relative imports, direct driver construction) — a cheap fail-closed floor, NOT a correctness review. LLM-backed review remains a possible later upgrade.

ADR-015: No Docker Deployment Work — Incus Is the Runtime

Date: 2026-07-08 · Status: Accepted (standing ruling)

The remediation checklist's P3.3 "fix Docker deployment" is intentionally not implemented: containers run on Incus; docker-compose.yml is kept only as a topology reference.

ADR-016: The Agent Runtime Kernel Is REQUIRED Infrastructure

Date: 2026-07-10 · Status: Accepted (non-negotiable rule)

ADR-017: Free-Threaded janus-swi Is the Deployed Prolog Path (Fixed at the C Level)

Date: 2026-07-10 · Status: Accepted, live

ADR-018: pytest-xdist Is Banned With a Single Source of Truth

Date: 2026-07-10 · Status: Accepted, enforced

ADR-019: D13 — Raw Memgraph Coordinator Probe Lives in the Allowlisted HA Seam

Date: 2026-07-10 · Status: Accepted

ADR-020: The Memgraph Adapter Retries Transient Storage-Access Contention

ADR-021: Org-Mode Is Rejected as a Project Format

ADR-022: Five Prolog Anti-Goals Are Settled Negatives

ADR-023: The 2026-07-21 Corrected Decision Set Is Ratified

ADR-024: One Factory Per Neo4j Database (Deployment Contract)

Session-253 canonical-key enforcement (no new decision — canon applied)

The recurring kg_schema conformance failures were traced to live code re-creating retired drift on every suite run, and fixed per the already-ratified canon (commit 17ca5a9a): audit event nodes and orchestrator Fact nodes now carry the canonical id key; the retired component_name (bare-name) and redundant project_id constraints no longer ship in schema.py / sync.py DDL. All four Neo4j instances brought to conformance via migrate_neo4j_canonical.py. Standing rule reaffirmed: rulings are binding — gap #4 (enums reconcile-vs-retire) was closed per the recorded W3 ruling rather than re-surfaced as open.

ADR-025: KG Zero-Orphan Invariant Enforced; D1(b) Executed; Session CLI Refuses Auto-Detected Roots Under Pytest

Date: 2026-07-30 · Status: Accepted

Ratified during the fix-all-defects goal (session 256), closing the hub-link plan's open decisions:

ADR-0039: Ruleset design — one commit per design version (F12)

Date: 2026-08-28 · Status: Accepted

Every version of plans/ruleset-runtime-design.md (folds and amends) is snapshotted and committed before the next adversarial round; the header version label is the audit key. Full record: docs/adr/0039-ruleset-design-commit-per-version.md.

ADR-0040: Ruleset traceability contract + one-word approval UX (F13)

Date: 2026-08-29 · Status: Accepted

The trace is part of the plan (SPEC-115/REQ-115 map fixed in advance), totality both directions via @traces, verification automatic through five named gates; ratification is one harness-mediated approval in Mohamed's session — zero manual cryptography, durable no. Full record: docs/adr/0040-ruleset-traceability-contract-and-approval-ux.md.

ADR-0041: Ruleset engine — per-surface immutable versions, named compositions (F1)

Date: 2026-08-29 · Status: Proposed

Rules live in immutable per-surface RulesetVersions; a named Composition pins each surface to one version; every activation/rollback/denial targets a name. Stable ×7 snapshots, zero findings rounds 13–15, recommended 7 consecutive rounds. Awaiting Mohamed. Full record: docs/adr/0041-ruleset-per-surface-versions-named-compositions.md.

ADR-0042: Wiring-gate supersession by the ruleset engine's §5 (F4)

Date: 2026-08-29 · Status: Proposed

For the ruleset subsystem, §5's structural reachability (a rule unreachable from an active composition is dead by construction) supersedes the standalone wiring gate. Awaiting Mohamed. Full record: docs/adr/0042-ruleset-wiring-gate-supersession.md.

ADR-0043: Rollback window N + process-cap arithmetic (F8-cap)

Date: 2026-08-29 · Status: Proposed

Rollback window = last N ratified generations per name; CAP >= 2×max_pins + rollback headroom, checked at ratification. Split from F8's deny-all half. Awaiting Mohamed. Full record: docs/adr/0043-ruleset-rollback-window-and-cap-arithmetic.md.

ADR-0044: Registry entries self-admit via the ratify chain (r12-decision-1)

Date: 2026-08-29 · Status: Proposed

The remedy channel for a compromised projector must not route through the projector: ratify-signed, chain-ordered registry entries need no AdmissionRecord. Fallback stated. Awaiting Mohamed. Full record: docs/adr/0044-ruleset-registry-entries-self-admit.md.

ADR-0045: Per-lineage bearer token for submitter continuity (r12-decision-2, refined)

Date: 2026-08-29 · Status: Proposed

Queue-minted 256-bit bearer token, salted-hashed in the minting record; join-only (mint is never refused); re-mint supersedes = revocation; dies with the lineage. Fallback priced. Awaiting Mohamed. Full record: docs/adr/0045-ruleset-lineage-bearer-token.md.

ADR-0046: Every ADR lives in three synchronized homes — docs, wiki, graph

Date: 2026-08-29 · Status: Accepted

Mohamed's ruling: "ADR must be in graph, wiki and docs." docs/adr is the file of record, this page is the human register, ArchitectureDecision nodes are the graph home; check_adr_graph_sync.py is the standing three-way drift gate. Full record: docs/adr/0046-adr-three-synchronized-homes.md.

ADR-0047: Two ADR registers, string-significant ids — namespace, renumber nothing

Date: 2026-08-29 · Status: Accepted

Mohamed's ruling (option 1) on the id collision ADR-0046 exposed: ids match as zero-padded strings — ADR-0001 (factory register, docs/adr) and ADR-001 (project register, this page) are different ids. register becomes a graph-node property; the gate matches (register, padded id); nothing renumbers, every citation stays valid; the three-homes rule completes by mirroring both series. Full record: docs/adr/0047-adr-two-registers-string-significant-ids.md.

ADR-0048: A ratified ADR is sufficient design authority for bounded implementation

Date: 2026-08-29 · Status: Proposed

RUL-022's DESIGN_WAIVER, generalized: work whose entire scope executes an Accepted ADR cites DESIGN_WAIVER: <ADR id> instead of a contract file that would restate the ADR; scope beyond the ADR loses the waiver. Exercised once (ADR-0047 implementation). Awaiting Mohamed. Full record: docs/adr/0048-ratified-adr-is-design-authority.md.

ADR-0049: Adversarial-review evidence is repo-committed and enriches wiki + graph

Date: 2026-08-29 · Status: Proposed

Review evidence gets the decisions treatment: every round's lens reports + verifier files committed to plans/reviews// (rounds 1-16 backfilled: 39 files, commit 3e6eb9c5); a per-design review-index page on this wiki; semantic-twin ingestion as ArchitectureChunks beside the ADRs. Awaiting Mohamed. Full record: docs/adr/0049-review-evidence-three-homes.md.

ADR-0050: Amend F13(D) — target semantics, not current-CLI claims; correct the payload

Date: 2026-08-29 · Status: Proposed

R16-4 (HIGH): F13(D)'s ratified ratification-interface clause describes today's CLI doing things it does not do, and enumerates a signed payload missing seven fields. Proposed in-place amendment by its ratifier: D's steps are the SPEC-115 TARGET (the existing verbs are the UX pattern only), the payload becomes the full C-6 signed pointer payload, a rollback verb joins the set. Sole criterion-1 blocker on four §11 items. Awaiting Mohamed. Full record: docs/adr/0050-amend-f13d-target-semantics.md.

ADR-0001: Enforcement boundary is committed worktree state, not tool interception

Date: 2026-07-23 · Status: Accepted

The enforcement boundary is the committed worktree state. Full record: docs/adr/0001-enforcement-boundary-committed-worktree-state.md.

ADR-0002: Factory gates fail closed; interactive sessions stay fail-open

Date: 2026-07-23 · Status: Accepted

Two explicit modes. Full record: docs/adr/0002-factory-gates-fail-closed.md.

ADR-0003: Neo4j is the fact system of record; Memgraph deferred

Date: 2026-07-23 · Status: Accepted

Neo4j is the system of record for facts, now. Full record: docs/adr/0003-storage-neo4j-system-of-record.md.

ADR-0004: Facts are keyed by (worktree, commit); merge is fact promotion

Date: 2026-07-23 · Status: Accepted

All AST/trace facts are keyed by (worktree, commit). Full record: docs/adr/0004-facts-keyed-by-worktree-commit.md.

ADR-0005: Prolog is a stateless reasoning view; the graph is the sole fact store

Date: 2026-07-23 · Status: Accepted

The knowledge graph is the single system of record for facts. Full record: docs/adr/0005-prolog-is-a-stateless-reasoning-view.md.

ADR-0006: Projection is rule-driven, with a completeness meta-check

Date: 2026-07-23 · Status: Accepted

The projection is generated from the rules, not chosen by hand. Full record: docs/adr/0006-rule-driven-projection-with-completeness-check.md.

ADR-0007: Traces are structurally validated, never model-declared

Date: 2026-07-23 · Status: Accepted

A trace is valid only if both hold, checked structurally: 1. Full record: docs/adr/0007-traces-are-structurally-validated.md.

ADR-0008: The determinism boundary — gates check structure and transcription, not intent

Date: 2026-07-23 · Status: Accepted

State the boundary explicitly in the spec, and design to it: - Deterministic: existence, public signatures, cross-component dependency edges, complexity thresholds, test structure, coverage, trace validity (ADR-0007)... Full record: docs/adr/0008-determinism-boundary-structure-not-intent.md.

ADR-0009: Asymmetric amendment — tightening needs quorum, loosening needs the human

Date: 2026-07-23 · Status: Accepted

Amendments are asymmetric: - Tightening (the amended rulebase accepts strictly less) — quorum = 2 suffices. Full record: docs/adr/0009-asymmetric-amendment-tighten-quorum-loosen-human.md.

ADR-0010: Constitutional invariants require stratified negation

Date: 2026-07-23 · Status: Accepted

Constitutional invariants MUST NOT depend, via negation-as-failure, on any extension_point/1 predicate — i.e. Full record: docs/adr/0010-constitutional-invariants-require-stratified-negation.md.

ADR-0011: Detect incompleteness rather than prove completeness

Date: 2026-07-23 · Status: Accepted

Replace the completeness proof with a battery of incompleteness detectors, run at design time rather than discovered mid-build. Full record: docs/adr/0011-detect-incompleteness-not-prove-completeness.md.

ADR-0012: Semantic anchors are requirement-derived, not code-derived

Date: 2026-07-23 · Status: Accepted

The ratified artefact carries requirement-derived semantic anchors — constraints on behaviour that do not derive from the implementation, and so cannot be co-authored by the code: - Concrete input→output examples per... Full record: docs/adr/0012-semantic-anchors-are-requirement-derived.md.

ADR-0013: Anchors are constitution-tier and human-only; anchor edits are loosening

Date: 2026-07-24 · Status: Accepted

ADR-0014: Adjudications are promoted into the Project KB (detector memory)

Date: 2026-07-24 · Status: Accepted

Adjudicated assumptions and ratified anchors are promoted into the Project KB as reusable pinning artefacts, and the detectors consult them. Full record: docs/adr/0014-adjudications-promoted-into-project-kb.md.

ADR-0015: DoR is necessary-not-sufficient, with a human floor and forced-choice axes

Date: 2026-07-24 · Status: Accepted

ADR-0016: Anchor classes are ranked; differential oracles are mandatory for amendments

Date: 2026-07-24 · Status: Accepted

ADR-0017: Governed writers are (binary, config)-attested pure functions, re-executed trusted-side

Date: 2026-07-24 · Status: Accepted

ADR-0018: Three-uid execution model (agent / sandboxed executor / trusted gate)

Date: 2026-07-24 · Status: Accepted

Three distinct uids, none of which may impersonate another: 1. Full record: docs/adr/0018-three-uid-execution-model.md.

ADR-0019: Gate reads require causal consistency — snapshot + watermark, not replicas

Date: 2026-07-24 · Status: Accepted

ADR-0020: Amendment direction — syntactic sufficient condition, else the human

Date: 2026-07-24 · Status: Accepted

Direction is decided fail-closed, by a three-step cascade: 1. Full record: docs/adr/0020-amendment-direction-syntactic-then-human.md.

ADR-0021: Edge accounting over the transitive closure; boundary changes are loosening

Date: 2026-07-24 · Status: Accepted

ADR-0022: Interpretation mutation must be adversarially separated; promote the model-free detector

Date: 2026-07-24 · Status: Accepted

ADR-0023: The fast path requires anchors satisfied and unchanged

Date: 2026-07-24 · Status: Accepted

A change qualifies for the fast path only if, in addition to the structural within-contract proof: - the anchors of every touched acceptance criterion remain satisfied, and - those anchors remain unchanged. Full record: docs/adr/0023-fast-path-requires-anchors-unchanged.md.

ADR-0024: The assumption-matching arbiter and its independence guarantee

Date: 2026-07-24 · Status: Accepted

A three-stage cascade, with the model used only where its high recall is an asset: 1. Full record: docs/adr/0024-assumption-matching-arbiter.md.

ADR-0025: The governance rulebase bans dynamic predicate construction

Date: 2026-07-24 · Status: Accepted

In the governance rulebase (constitution, patterns, project rules — not application code): - Ban call/N on unbound goals and any dynamic goal construction. Full record: docs/adr/0025-ban-dynamic-predicate-construction.md.

ADR-0026: A governance predicate may not return a truncated answer set

Date: 2026-07-24 · Status: Accepted

No governance predicate may return a truncated answer set. Full record: docs/adr/0026-no-truncated-answers-in-governance-predicates.md.

ADR-0027: Retain Prolog as the reasoning engine

Date: 2026-07-24 · Status: Accepted

Retain SWI-Prolog. Full record: docs/adr/0027-retain-prolog-as-the-reasoning-engine.md.

ADR-0028: Completeness axes are delivered as a construction procedure, not a checklist

Date: 2026-07-24 · Status: Accepted

The completeness axes are retained in full, and are delivered as a construction procedure. Full record: docs/adr/0028-completeness-axes-are-a-construction-procedure.md.

ADR-0029: The lexical incompleteness detector set is tiered by measured precision

Date: 2026-07-24 · Status: Accepted

REQ-033-C3's detector set is specified explicitly and tiered by measured precision, with each rule carrying its provenance and its measured accuracy where one exists. Full record: docs/adr/0029-lexical-detector-set-tiered-by-measured-precision.md.

ADR-0030: Provenance uses in-toto / SLSA attestations rather than a bespoke format

Date: 2026-07-24 · Status: Accepted

Adopt in-toto attestations as the provenance format, and SLSA as the level vocabulary. Full record: docs/adr/0030-provenance-uses-in-toto-slsa-attestations.md.

ADR-0031: Every gate decision carries its proof tree

Date: 2026-07-24 · Status: Accepted

Every governance decision carries its proof tree, produced by a Prolog meta-interpreter, and the tree is a first-class artefact: - Allow carries the derivation: rules fired, facts consumed. Full record: docs/adr/0031-gate-decisions-carry-proof-trees.md.

ADR-0032: The gate adopts the admission-control contract

Date: 2026-07-24 · Status: Accepted

Adopt the admission-control contract explicitly: 1. Full record: docs/adr/0032-gate-adopts-the-admission-control-contract.md.

ADR-0033: No agent merges its own work; dispatch gates on duplication and staleness

Date: 2026-07-24 · Status: Accepted

Full record: docs/adr/0033-no-agent-merges-its-own-work.md.

ADR-0034: Governed-action classification is property-derived, not name-enumerated

Date: 2026-07-24 · Status: Proposed

An action's category membership is DERIVED from typed attributes of the action and the resources it targets, never from the action's atom name. Full record: docs/adr/0034-classification-is-property-derived-not-name-enumerated.md.

ADR-0035: Authorization is a scoped grant matched to the action instance, from two sources

Date: 2026-07-24 · Status: Proposed

An action is authorized iff some grant's selector matches THIS action instance's attributes. Full record: docs/adr/0035-scoped-authorization-two-grant-sources.md.

ADR-0036: Classification facts are stamped at creation under the trusted boundary

Date: 2026-07-24 · Status: Proposed

A resource's classification attributes are written by its CREATOR at creation time, under the trusted-side identity, and are immutable to the acting (agent) identity. Full record: docs/adr/0036-classification-provenance-under-the-trust-boundary.md.

ADR-0037: Idempotent KG event ids are SHA1 content digests

Date: 2026-07-22 (decided by U:Ar in a live pipeline run); recorded here 2026-07-26 · Status: Accepted

Idempotent event ids are derived from a SHA1 digest of the event's identifying content, truncated to 16 hex chars, embedded in a typed, readable prefix: - Pipeline artifact... Full record: docs/adr/0037-idempotent-kg-event-ids-are-content-digests.md.

ADR-0038: The CXP envelope schema supersedes the pre-CXP Postman schema

Date: 2026-07-06 (the decision, as executed) · first written 2026-08-19, corrected same day · Status: Accepted

postman.types.MessageEnvelope's CXP-native shape (to/from_/thread_id/subject/ created_at) is canonical, and always has been — it is not a decision this ADR is recording the making-of; it predates commit... Full record: docs/adr/0038-cxp-envelope-schema-supersedes-postman-types.md.

ADR-0051: F13(A) decomposition map made total — buckets for §0, §1, §10

Date: 2026-08-29 · Status: Proposed

Round 16 (life-R16-9): F13(A)'s map buckets §2–§9 + clause D and omits §0 Doctrine, §1 Domain model and §10 Logic/data boundary — clauses B+C then block BOTH branches for those sections. Proposed: three new buckets (7xx doctrine · 8xx domain model · 9xx logic/data boundary) so "every future id is anticipated" is true. Full record: docs/adr/0051-f13-decomposition-map-totality.md

Date: 2026-08-29 · Status: Proposed

Round 16 (life-R16-7): of F13(C)'s eight named verification bindings, 2 are accurate, 1 partial, 5 false or unbound (check-traces is a net-count ratchet at --max 2219; trace-audit/trace_intel/spec-authority/factory B2+B3 bind to no failure point). Recommended option 1: WIRE them as named + a SPEC-115-scoped --max 0 lane — ratified text untouched. Option 2: amend the clause to the actual homes. Mohamed's binding condition on option 1 (2026-08-29, verbatim in the full record): gate functionality that does not exist is PLANNED, REVIEWED, DESIGNED and BUILT — never wired as a config flip. Full record: docs/adr/0052-f13-verification-bindings-wire-or-amend.md

ADR-0053: Infrastructure is guilty until proven live — probe, never trust

Date: 2026-08-30 · Status: Accepted (Mohamed's ruling, by fiat)

Mohamed deliberately deleted the entire prod orchgraph stack; for days every doc, gate and report kept asserting it existed — nothing probed it. Law: he may destroy any environment without notice; infrastructure claims carry live probe evidence or are violations; docs asserting dead infra are defects; graphs are derived caches of git-rooted truth, never a durable "home". A liveness gate is proposed work under the ADR-0052 build discipline. Full record: docs/adr/0053-infrastructure-guilty-until-proven-live.md

ADR-0054: Misplaced infrastructure seams relocate to a new L1 infra package

Date: 2026-09-21 · Status: Accepted (executed under Mohamed's direction)

The measured cluster of L3→L4 upward violations traced to misplaced modules, not bad consumers: orchestrator/prolog_bridge.py and orchestrator/redis_state.py are infrastructure. New src/orchestrata_ultimate/infra/ package (Layer 1, registered in LAYER_ASSIGNMENTS + standards doc) receives them — final-granularity placement mapping 1:1 onto the target orchestrata.infra. prolog_worker relocation queued (obsoletes a KNOWN_VIOLATIONS waiver). Full record: docs/adr/0054-infra-package-for-misplaced-seams.md

ADR-0055: volk_registry lives in the agents layer; L0 protocols never name concretes

Date: 2026-09-21 · Status: Accepted (executed under Mohamed's direction)

The agent registry moved kernel/ → agents/ (its domain layer), resolving the map-vs-plan contradiction in the plan's favor. Rule: L0 protocol modules import no concretes, even under TYPE_CHECKING — core/protocols/volk_health.py now depends only on the structural VolkRegistryProtocol/VolkHealthProbe. Precedent for K6 (core purity). Full record: docs/adr/0055-volk-registry-agents-layer.md

ADR-0056: Two-gate architecture measurement — runtime gate + static ratchet with a pinned baseline

Date: 2026-09-21 · Status: Accepted (executed under Mohamed's direction)

architecture_checker.py --strict (top-level, 0 violations) is joined by scripts/architecture_static_check.py (every edge incl. TYPE_CHECKING + function-scoped, plus Tarjan cycles) with a pinned baseline JSON (100 total / 6 SCCs at pinning) as the authoritative debt ledger and a blocking architecture-ratchet CI job. Debt can only decrease; the review's 141/10-cycle figures (deleted-branch snapshot) are superseded. Full record: docs/adr/0056-static-ratchet-baseline.md

ADR-0057: PEP 649/749 annotation convention — Any + named comment, never TYPE_CHECKING-only names in evaluable annotations

Date: 2026-09-21 · Status: Accepted (executed under Mohamed's direction)

Under Python 3.14 lazy annotation evaluation, TYPE_CHECKING-only names NameError when inspect.signature resolves the annotation. Where a type can't be imported at runtime (layer boundary or import side-effect cost like janus), annotate Any and name the real type in an adjacent comment with the reason. Three live instances fixed (volk_registry.audit, prolog_worker.query_explained ×2), surfaced by the regenerated generated-tests pins. Full record: docs/adr/0057-pep649-annotation-convention.md

ADR-0058: HA controller tests run against a dedicated two-node orchgraph sandbox, never the shared test node

Date: 2026-09-22 · Status: Accepted (ruled by Mohamed 2026-09-22)

Six test_memgraph_ha tests register an unreachable placeholder replica on the shared test orchgraph (10.53.2.10); the Debug-build fork then asserts in ShowReplicas (replication_handler.cpp:449) and core-dumps, and the registration persists across restarts (two crashes on 2026-09-22, 5 red tests, 1 reconnect log line per second). Proposed: two disposable orchgraph containers in orchestrata-test as TEST_MEMGRAPH_HA_MAIN_URI / TEST_MEMGRAPH_HA_REPLICA_URI, the fixture uses a real replica and restores both nodes at teardown, the shared node is repaired once and never mutated again. Fork fix is a follow-up. Full record: docs/adr/0058-ha-tests-dedicated-orchgraph-pair.md

ADR-0059: REQ propagation in generated tests is uncapped — traceability is not sampled

Date: 2026-09-22 · Status: Accepted (ruled by Mohamed 2026-09-22)

EnhancedTestGenerator._extract_traces used to truncate a symbol's @traces(reqs=[...]) to reqs[:3] at PARSE time, so a fourth requirement was gone before anything downstream could see it and showed up in the RTM as untested (measured casualty: REQ-004-US-009-017). Commit f260b6e73 (IR-1 item G-3) removed the cap; one old-tree test still asserted it. Ruled: REQ propagation is uncapped — every declared id reaches the generated test, in order, with no maximum and no silent truncation. The test asserting a cap of 3 asserted a defect and is corrected to the contract. Full record: docs/adr/0059-req-propagation-is-uncapped.md

ADR-0060: The RUL-032 content key covers every edge the selector routes on, not only imports

Date: 2026-09-22 · Status: Proposed (awaiting Mohamed's ruling)

RUL-032 defines a test module's "code state" as its own content, its transitive src/ import closure, its conftest chain and pyproject.toml — "nothing else is in the key". Built literally, the first probe showed tests/scripts/test_trace_intel.py keying on everything except scripts/trace_intel.py: the test loads its subject via importlib.util.spec_from_file_location, so there is no import edge, and the file is outside src/ anyway — both restrictions fail here independently. The same day, two real defects in that subject were fixed (95d375eb4, c28e70909) and took the module from 3 failed to 0; under the literal key neither fix would have moved the key, and the ledger would have reported the module proven while it was red. The hole covers tests/scripts/**, tests/claude/** and every .sh/.pl-subject test. Proposed: clause 2 becomes every first-party file (src/, scripts/, claude/) reached by the same four edge sources affected_tests.py routes selection on — imports, the test_<stem> convention, the manifest, reference edges — and the safety property is restated as "every file the selector routes to a test is one of that test's key inputs", asserted by TestSelectorAgreement against the live selector and the live snapshots. The amendment is monotone: it only ever ADDS key inputs, so it can forgo reuse but never fabricate it — which is why it was recorded as Proposed and flagged rather than blocking a ruling Mohamed had already given. Full record: docs/adr/0060-rul-032-key-covers-the-selector-not-only-imports.md

ADR-0061: The one ADR-body bypass also covers an empty factory body, not only a register-less node

Date: 2026-09-22 · Status: Proposed (awaiting Mohamed's ruling)

sync_adr_docs was writing NOTHING into the graph: it raised AdrImmutabilityError on ADR-0039 and aborted. That node held the WIKI shape — a 243-character decision, with context/alternatives/consequences all empty — because a pre-filter sync_adrs had upserted it from the mirror prose, stamping register = 'factory' on the way in and so putting it permanently beyond migrate_legacy_adr_registers' WHERE a.register IS NULL gate, while Accepted status locked the docs ingest out of correcting it. A live census found 20 stub-bodied nodes, four of them Accepted factory ADRs (0039, 0040, 0046, 0047). The cost was not four stuck records: the ingest raises on the FIRST such node, so 0 of 55 docs ADRs were reaching the graph — the factory register's third home (ADR-0046) had been silently broken for everything numbered 0039 and above, including ADR-0059 and ADR-0060 minted the same day. Proposed: widen the migration's predicate to also select a factory-registered node whose body is entirely empty, re-sourcing it from the docs file of record (ADR-0047) — never re-keying it, and skipping it when the docs record is itself bodiless. The justification is that an empty body was never the ratified content of an Accepted ADR, so filling it completes a stalled migration rather than editing a decision. A scripts/repair_*.py one-shot was rejected because it would create a SECOND site writing an Accepted body outside ruling-1's guard; this keeps exactly one, with a wider predicate. Result: 12 stubs re-sourced, 55 docs ADRs landed, ADR-0059 and ADR-0060 now OK in sync. Not fixed: ADR-0054..0058 exist only on the wiki with no docs/adr/ file and remain MISSING_FROM_GRAPH — an ADR-0047 question, not a repair. Full record: docs/adr/0061-adr-immutability-bypass-covers-empty-factory-bodies.md

ADR-0062: Production runs from a pinned-ref git checkout under /opt/orchestrata

Date: 2026-09-23 · Status: Proposed (awaiting Mohamed's ruling)

RUL-027 named ~/prod/orchestrata-ultimate as the production checkout; measured 2026-09-23, ~/prod does not exist on this host and never ran anything here (ADR-0053: a document asserting dead infrastructure is a defect), while the test container app already runs a git-archive copy at /opt/orchestrata under system units — host and container disagreed about the prod root. Rulings R1+R5 (Mohamed, 2026-09-23): /opt/orchestrata is a mohamed-owned git checkout reset --hard to the pinned sha by deploy/install-orchestrata.sh, with its own .venv on python3.14t, VERSION staged as .VERSION.deploying and promoted last, .env installed 0600, and an identity verifier (scripts/verify_deployment_identity.py) that refuses success unless the running units are that checkout (HEAD == VERSION.commit == expected sha; every unit's cwd/cmdline/exe under /opt/orchestrata; no unit path under /home/*/workspace/). Checkout rather than archive so promote_env's tree/drift/rollback stages are reused and rollback is a reset, not a re-install; the container keeps its archive copy as the one documented divergence. Units stay user scope this round with scope resolved per unit, so system units with User=mohamed are a later unit-file change. Rejected: keeping ~/prod (three shapes across dev/test/prod, a mutable HEAD as the only record) and an archive copy for prod (forks the promotion path). Supersedes RUL-027's path clause only; also records R3 (deploy assets cherry-picked from architecture/domain-model, never merged) and R4 (the rehearsal HA cluster re-IPs onto 10.53.2.x) without separate ADR ids. Full record: docs/adr/0062-prod-is-a-pinned-checkout-under-opt-orchestrata.md

ADR-0063: The Read tool is allowed on a module the session already read through the AST toolkit

Date: 2026-09-23 · Status: Accepted (ruling R9, Mohamed, 2026-09-23)

The 2026-08-02 mandate ("ZERO hand-reading of Python source — the AST toolkit serves everything") is enforced by .claude/hooks/force-ast-toolkit.sh, which denies the Read tool and every text tool on this repo's src/, scripts/ and tests/ Python. Edit and Write refuse a file the session has not Read, so measured 2026-09-23 on two swarm tasks (U-T3, U-T8a) an agent that had pulled the exact bytes through source could not land its patch by any route a sibling guard permitted; the method that grew up instead (build in the scratchpad, diff against git show HEAD:<path>, copy over) was a route around a guard — the failure mode the guard's own header warns about. Ruling R9: the Read tool is permitted on a Python file whose module the same session has already read through serialize_codebase_ast.py source <name>. Mechanism (RUL-014, orchestrata-ultimate 1395825c4, shipped 7b6ecb0f0): the hook's Bash branch records every source <name> argument into a per-session memo (${XDG_RUNTIME_DIR:-/tmp}/orchestrata-project-hooks/<session>.ast-read-allow, keyed by the payload's session_id); the Read branch allows a .py whose stem is a dotted segment of a recorded name; text tools stay denied; a payload without a session id records and unlocks nothing (47 guard tests unchanged, 8 new). Rejected: exempting tests/ — it would have restored hand-reading for the largest part of the tree and left src//scripts/ deadlocked. Consequence recorded: the plugin copy goes live only with a ship, so a hook change is sequenced before a swarm wave, never during one. Wiki ruling page: RUL-033. Full record: docs/adr/0063-read-allowed-after-ast-toolkit-source.md

ADR-0064: The deployed orchgraph package carries MAGE so the ratified pagerank SLO is measurable

Date: 2026-09-23 · Status: Accepted (ruling R13, Mohamed, 2026-09-23: "r13, we had our own orchgraph build")

The migration plan's Step 3.4 SLO "whole-graph MAGE analytical pass < 1 s" is measured with CALL pagerank.get() against the production coordinator, but the package deployed on every node (3.11.0-40-g83b722c-dirty, 2026-07-21) ships no MAGE pagerank module, so tests/scripts/test_benchmark_code_intel.py is red and every full-suite ship is refused. Proposed: rebuild the orchgraph package from the MAGE-bundling commit (fdf6dd8 or later) and deploy it to the test node and orchgraph-coord-1; the test is neither skipped nor weakened meanwhile. Full record: docs/adr/0064-orchgraph-package-carries-mage-for-the-pagerank-slo.md

ADR-0065: The production gateway's WS control plane binds loopback through the committed prod profile

Date: 2026-09-24 · Status: Accepted (ruling R15, Mohamed, 2026-09-24: "1, proceed with that")

Ship attempt 5's promote failed at services because the gateway's only GATEWAY_HOST was the workspace template's CHANGEME. env/prod.env now sets GATEWAY_HOST=127.0.0.1 explicitly, mirroring env/test.env; the HTTP observability surface keeps its own GATEWAY_HTTP_HOST. A test pins the prod value. Full record: docs/adr/0065-prod-gateway-binds-loopback-through-the-committed-profile.md

ADR-0066: /opt/orchestrata secrets live in ~/.config/orchestrata/.env and the installer never defaults to the workspace template

Date: 2026-09-24 · Status: Accepted (ruling R16, Mohamed, 2026-09-24: "1, proceed with that")

The installer's --secrets-env defaulted to the 56-placeholder workspace .env, so the first bootstrap shipped placeholders and U-BOOT3 now refuses them. The secrets file is ${XDG_CONFIG_HOME:-$HOME/.config}/orchestrata/.env (0600, secrets only, no config keys, no placeholders); the installer defaults to it and refuses an absent file. The conversation-graph endpoint keys live there per the consumer's contract; their value is still an open operational parameter (R16b). Full record: docs/adr/0066-opt-orchestrata-secrets-live-in-the-user-config-env.md

ADR-0067: Developer daemons are deployed code; the checkout they serve is a runtime parameter

Date: 2026-10-05 · Status: Accepted (rulings R1/R2 of plans/ast-daemon-deployment-plan.md, Mohamed, 2026-10-05)

The AST daemon and the codemod daemon ran as plain user units executing a developer checkout's code and venv, outside the repo, with no recorded commit, no installer, and no identity check — deploy-in-place in three forms. Both are now deployed code under /opt/orchestrata-tools (own venv, VERSION commit, install-tools.sh from a pinned ref); the served checkout is the systemd instance %I / --repo-root parameter, i.e. data. No daemon process executes from a workspace checkout under any condition; the session hook replaces one that does, and without the deployment the client takes the slow path. Identity (code_root, deployed_commit) is asserted by the installer and the hook; RUL-027's gate extends to ~/.config/systemd/user. The U-T2 "runtime-only" compromise is retired: an enabled instance for the primary checkout is permitted. The codemod daemon rides the same wave (R2). Full record: docs/adr/0067-dev-daemons-are-deployed-code-serving-checkouts-as-data.md

ADR-0068: SPEC-110 in-memory review checks run on the ctok lossless layer and CPython ast, not LibCST

Date: 2026-10-06 · Status: Accepted (ruling, Mohamed, 2026-10-06: "go with recommendatio . build s3'" — option 1; REQ-110-034 amended in the spec the same commit)

SPEC-110 REQ-110-034 requires the 40 in-memory review checks to run on LibCST trees as CSTVisitor subclasses, but LibCST is gone from the tree (0 hits in pyproject.toml/uv.lock, 0 imports) since the ctok migration superseded REQ-110-107, so FR-012 is unmeetable as worded and unbuilt. Proposed amendment: checks operate on the engine's in-memory lossless layer (ctok token array + the CPython ast overlay the forest holds), never re-parse from disk, never subprocess or call external linters; structural checks are ast.NodeVisitor subclasses over the MUTATED forest, lexical checks (line length, whitespace, tabs, final newline, comment/pattern scans) are token-array scanners, and the 22 existing verification/review/check_* functions are reused where they match. Rejected: re-adding LibCST, dropping FR-012, shelling out to linters. Full record: docs/adr/0068-spec-110-review-checks-run-on-ctok-and-cpython-ast-not-libcst.md

ADR-0069: Every spec's Definition of Done includes @traces annotations, RTM regeneration, documentation, wiki update and ≥90% coverage

Date: 2026-10-06 · Status: Accepted (ruling, Mohamed, 2026-10-06: "do not forget annotations, rtm, documentation, wiki update and 90% code coverage" then "it should br the definition of done for all specs")

The written DoD named only ≥90% coverage; the other four obligations were scattered or unstated, and SPEC-110 measured the result on 2026-10-06 (uncited working code, code citing undefined ids, a checklist row marked complete for absent code, a design built but never documented as wired). Ruling: every packet of every spec is DONE only when, in the same ship as the code, (1) every added/changed symbol and test carries @traces with spec-defined ids, (2) the RTM is regenerated and the packet's ids move to an implemented-and-tested proof class, (3) the spec checklist, docs/ page and plans/ design status are updated in the code commit, (4) the knowledge-wiki subsystem page gains the packet summary and is shipped, (5) ≥90% line coverage per touched source file. Builder briefs list the five under DONE WHEN; reviewer GO needs evidence for each. Wiki ruling RUL-034; AGENTS.md § Definition of Done extended. Enforcement: judgment until a gate exists (candidates named in the record). Full record: docs/adr/0069-definition-of-done-for-every-spec-traces-rtm-docs-wiki-90-coverage.md

ADR-0070: Hooks live at the user level only and scope themselves to the project in cwd, so they apply to every project

Date: 2026-10-06 · Status: Accepted (ruling, Mohamed, 2026-10-06: "hooks at user level only but apply to the project in cwd,soo they apply to all projects, add it to the rules")

Claude Code reads <repo>/.claude/settings.json only when the session's project directory IS that repo; measured 2026-08-23, a $HOME-rooted session never loaded it and all 25 guards registered there were dark. Delivery moved to the orchestrata plugin, whose _dispatch.sh scopes each guard to the repo owning the cwd, but both homes were kept: measured 2026-10-06, .claude/settings.json still registers 31 hooks (PreToolUse 15, SessionStart 8, Stop 5, PostToolUse 2, UserPromptSubmit 1), the plugin's hooks.json 42, and a stand-down branch in the dispatcher decides which copy runs from CLAUDE_PROJECT_DIR. The P4 review of the AST-daemon hook hit the consequence: the same hook registered twice, run location-dependent. Ruling: hooks are registered at the USER level only (~/.claude/settings.json, ~/.claude/hooks/, the plugin's hooks/hooks.json) and resolve the repo from cwd at run time, so one registration governs every project; no repo registers hooks in its own .claude/settings.json. Consequences: retire the 31 project-level registrations and the dispatcher stand-down branch (follow-up packet, ADR-0067 P7 at the earliest); candidate gate: fail when a tracked <repo>/.claude/settings.json carries a hooks key. Wiki ruling RUL-035; AGENTS.md Hard Rule 9; CLAUDE.md Key Rules. Enforcement: judgment until the gate lands. Full record: docs/adr/0070-hooks-live-at-user-level-only-and-scope-to-the-project-in-cwd.md

ADR-0071: REQ-110-135 amended: codemod daemon lifecycle is delegated to systemd user units

Date: 2026-10-06 · Status: Proposed (recommendation: Accept)

SPEC-110 REQ-110-135 reads "start SHALL fork to background ... stop SHALL send SIGTERM, wait 5s for graceful shutdown, and force kill if necessary". ADR-0067 (Accepted) made the codemod daemon deployed code run as a systemd user unit, and packet P4 of plans/ast-daemon-deployment-plan.md executed it: start() refuses an active instance or a missing /opt/orchestrata-tools launcher, runs systemctl --user start, and records the unit's MainPID in .codemod_daemon/pid; stop() on a loaded unit runs systemctl --user stop and signals no pid, and only with no unit loaded does a pid-file pid get SIGTERM, a 5s wait, then SIGKILL, after argv verification that it is the codemod daemon entry module. The P4 round-3 review found the code correct against ADR-0067 and contradictory to the clause; both @traces(reqs=["REQ-110-135"]) methods now certify text they do not implement. Proposed: amend REQ-110-135 to the systemd-delegated lifecycle (unit-first start/stop, MainPID recorded, legacy pid-file path only when no unit is loaded and only for a verified codemod pid). REQ-110-133/134/136/137 unchanged. Alternatives rejected: leave the clause and let the RTM grade it on contrary tests; restore the forking start (reverses ADR-0067 for one daemon); edit spec.md under the ADR-0067 waiver (ADR-0067 rules on deployment, not SPEC-110's words; ADR-0068 set the Proposed-ADR path for spec text). On Accepted: edit REQ-110-135 in specs/110-codemod-engine/spec.md, keep checklist row 119 [x] citing this ADR, record the ruling in Provenance. Full record: docs/adr/0071-req-110-135-amended-codemod-daemon-lifecycle-is-delegated-to-systemd-user-units.md

ADR-0072: The conversation graph endpoint is the prod orchgraph cluster, database orchkg

Date: 2026-10-06 · Status: Accepted (ruling, Mohamed, 2026-10-07: "cluster = Memgraph, DB = orchkg (ADR stands)"; docs flip 9efdaa570)

ADR-0066 (R16) left one value unnamed: which server and database host the conversation graph that orchestrata-conversation-consumer.service (SPEC-021 US-021-007) writes to. The consumer reads only CONVERSATION_KG_URI/CONVERSATION_KG_DATABASE and refuses to start without them (REQ-021-069: never resolved through the profile-driven KG keys a dev/test overlay redirects). Measured 2026-10-06: the P5 ship cleared both P5 prod blockers (plain units retired, test-env record GREEN), the first real prod promote ran and failed at verify on the consumer's RuntimeError: CONVERSATION_KG_URI and CONVERSATION_KG_DATABASE not set; no host, dev or test file names an endpoint today. Proposed: CONVERSATION_KG_URI=neo4j://10.53.1.160:7691, CONVERSATION_KG_DATABASE=orchkg in ~/.config/orchestrata/.env — the prod operational KG itself (the unit's own description says "-> orchkg graph", the SPEC-021 conversation labels are in the orchkg canonical schema, the nightly backup already covers it). Rejected: a dedicated conversation database (schema split, second root hub, every reader changes — nothing in SPEC-021 asks for it), the test-node Memgraph (prod never writes to the test fleet), resolving via KG_ROUTING_URI (REQ-021-069). On Accepted the keys are appended to the secrets file and the next promote copies them; remaining prod verify findings are plan PH1 (two failed timer oneshots) and P6 (verifier treatment of tool-tree template instances). Full record: docs/adr/0072-conversation-graph-endpoint-is-the-prod-orchgraph-cluster-database-orchkg.md

ADR-0073: ERR-110-002 amended: the default-on review engine aborts a commit on findings the change introduced (delta baseline)

Date: 2026-10-06 · Status: Accepted (ruling, Mohamed, 2026-10-07: "accept adr-0073")

Plan decision D6 of SPEC-110 deferred this ADR "until a packet measures a legacy-file abort in practice". Packet S3 wired the InMemoryReviewEngine on by default in CodemodWorkspace.commit() with baseline='absolute', and its reviewer measured the result on this repository: 134 of 3,234 files already carry an error-severity finding (419 errors, most false positives with named, fixable causes), and a codemod --apply touching any of them now exits 1 with nothing written. After fix round 1 removed the four false-positive causes the same probe gives 247 errors in 100 files (2 src, 17 scripts, 81 tests), the tests-side ones being real literal credentials and flushdb calls in shared fixtures. Proposed: the default engine's ERR-110-002 abort applies to findings the change INTRODUCED (delta between the pre-mutation and mutated forest, matched on path/rule/line-free message); 'absolute' stays as the opt-in clean-slate gate. The delta line-shift bug (reviewer finding 2) is fixed in ace6149cb. Full record: docs/adr/0073-err-110-002-amended-default-review-engine-aborts-on-introduced-findings-delta-baseline.md

Execution note (2026-10-07, Provenance of the record above; the Accepted body is unchanged): executed in orchestrata-ultimate 7db0f25e1 (default 'delta', CLI --baseline {delta,absolute}, ERR-110-002 amended) and refined in ac8188445 / c6946173a. The delta key is (path, rule, line-free message, stripped line text) with multiplicity, so an in-place edit of a line already carrying a content-free finding aborts; legacy findings are reported in CommitReport.legacy_findings, as FINDING_EMITTED with legacy: true and in REVIEW_COMPLETED.legacy_count, never vetoing. Measured on the whole tree at 7397f2c35: absolute 235 errors in 93 files, 12,786 warnings; delta 0 introduced.

ADR-0074: The prod promote re-embeds only changed semantic chunks and probes the embedding provider before the tree moves

Date: 2026-10-07 · Status: Superseded by ADR-0149 (Mohamed, 2026-10-29: "NO MORE rag OR EMBEDDIING"); was Accepted (ruling, Mohamed, 2026-10-07: "adr 0074 agreed"; docs flip 98f80b0df)

The promote's graphs stage runs bootstrap_graphs.py --all, whose Memgraph step re-embeds every semantic chunk through OpenRouter on every promote: chunk ids are positional and no content hash is stored, so 5,740 unchanged chunks cost 570 paid calls and 5 min 20 s per ship. On the c8c4ddd23 promote the account balance ran out mid-run (HTTP 402 on the 58th call); the stage failed after verify had passed and the promoter rolled back a working deploy. Proposed: (1) the ingester stores content_sha256 per chunk and embeds only new or changed chunks, deleting stale ids, so a no-change promote embeds nothing; (2) the infra stage probes the embedding provider (credit endpoint or a one-string embed) before the tree moves and refuses on 401/402/403 with no unit restarted; (3) graphs keeps --all. Rejected: taking the ingest out of the gate (graph lags code), --backend local in prod (different vector space, unmeasured), a --skip-semantic ship flag, topping up and changing nothing. Full record: docs/adr/0074-prod-promote-embeds-only-changed-chunks-and-probes-the-embedding-provider-at-infra.md

ADR-0075: The promote's infra stage proves the ADR-0066 secrets file holds every required env key before the tree moves

Date: 2026-10-07 · Status: Proposed (recommendation: Accept)

The c8c4ddd23 prod promote's rollback left orchestrata-conversation-consumer.service failed on CONVERSATION_KG_URI and CONVERSATION_KG_DATABASE not set: the secrets file lacked two keys a newly deployed unit requires, and nothing checked before the tree moved. Proposed: (1) the infra stage reads the ADR-0066 secrets file (~/.config/orchestrata/.env, the source of truth, not the installer's copy) and refuses the promote with [FAIL] infra env keys: missing <names> when any required key is absent or blank — no tree move, no restart, no rollback; (2) the required set is the infra_env_rule registry (validate_env.REQUIRED_KEYS + KG_URI + the two CONVERSATION_KG_* keys), imported, never a second list, with a test pinning probe and registry together; (3) every addition is recorded by key name, the probe never writes the file and never proposes values (RUL-003). Full record: docs/adr/0075-promote-infra-stage-proves-required-env-keys-before-the-tree-moves.md

ADR-0076: The semantic/RAG ingest leaves the prod promote; readers check freshness at runtime and trigger refresh on demand

Date: 2026-10-07 · Status: Superseded by ADR-0149 (Mohamed, 2026-10-29: "NO MORE rag OR EMBEDDIING"); was Accepted (ruling, Mohamed, 2026-10-07: "accept ADR-0076"; ADR-0074 item 3 superseded by this ADR)

Mohamed's ruling (2026-10-07): promotion ships code, not data — "no separate code promotion … when code runs it checks for freshness and triggers refresh if needed", scope semantic/RAG only; amended "we promote successfully and trigger a embedding refresh on successful promotion, we do not hide our heads in sand". Proposed: (1) the promote's graphs stage runs bootstrap_graphs.py --kg; the Memgraph ingest is no longer a promote stage, so no promote pays for, waits on or fails on embeddings; (2) a successful promote triggers the embedding refresh without waiting on or gating on it; (3) the refresh is single-flight and incremental (ADR-0074 item 1's content_sha256 engine) with a periodic safety net; (4) ADR-0074 item 2's provider probe re-homes to the trigger — a 401/402/403 or an unaffordable estimate defers and alerts, never fails a reader or a promote; (5) the ingest records the source commit it derived from; every semantic reader compares it with the deployed commit, triggers the refresh when stale and surfaces the staleness loudly instead of answering as if fresh; (6) ADR-0074 item 3 is superseded, items 1–2 survive re-homed. Rejected: keeping the ingest in the promote, serving stale with an annotation, a timer with no read-time check. Full record: docs/adr/0076-semantic-rag-ingest-leaves-the-prod-promote-readers-check-freshness-at-runtime.md

ADR-0077: Terraform owns every Incus environment; the live dev, test and prod fleets are imported, not rebuilt

Date: 2026-10-08 · Status: Accepted (ruling, Mohamed, 2026-10-08: "all environments must be imported")

Three IaC layers disagreed about the Incus topology: infra/terraform described prod only, was stale (nic incusbr0 vs live orch-prod-br) and its September tfstate no longer exists anywhere on the host; deploy/provision_environments.sh was the de-facto authority; the drift gate in health_check.py passes silently when the state file is missing and no timer runs it. Decided: (1) terraform (OpenTofu) is the single source of truth for projects, bridges, ACLs, the project default profiles and every container in default (prod), orchestrata-test and orchestrata-dev; shell provisioners keep only the in-container layer and Raft enrollment; (2) everything live is IMPORTED, never recreated — acceptance is tofu plan -detailed-exitcode = 0 after import.sh; (3) state lives outside every checkout at /var/lib/orchestrata/terraform/fleet.tfstate; (4) the drift gate FAILS on a missing state, runs tofu, and runs on a timer; (5) out of scope: rhbr0 + the four stale rh-* containers (retired, Mohamed deletes), the codetools orchestrata project, incusbr0, the rehearsal overlay; (6) first managed change after zero-diff: boot.autostart for every container and the four stopped prod nodes started. Rejected: shell provisioner as authority, repair-only re-import, recreate-from-HCL, state in the repo. Full record: docs/adr/0077-terraform-owns-every-incus-environment-and-the-live-fleets-are-imported.md

ADR-0078: The deployed codemod daemon reviews with every phase; the tools venv carries the free-threaded janus-swi

Date: 2026-10-08 · Status: Proposed (awaiting Mohamed's ruling)

/opt/orchestrata-tools vendored four hand-listed subtrees; measured 2026-10-08 the codemod daemon's eager import closure is 1 module while its first default review needs 103 (six packages, verification and openspec never vendored — task 580). WI-DEPLOY made the vendor list a computed, gate-pinned all-scopes closure (167 modules, nine packages) and made the deploy smoke run a real review; that smoke prints PrologSemanticReview: janus-swi not available, skipping, so the deployed review runs phases 1–2 only. Proposed: (1) the tools venv installs the same free-threaded janus-swi artifact the project venv uses (never upstream PyPI janus, which re-enables the GIL); (2) the smoke fails on any phase-3 skip marker and asserts the GIL stays off after import janus_swi; (3) the vendor list stays the all-scopes closure; (4) lazy-only third-party packages install when the closure lists them. Rejected: shipping phases 1–2 only, upstream janus-swi, vendoring the eager closure. Full record: docs/adr/0078-the-deployed-codemod-daemon-reviews-with-every-phase-the-tools-venv-carries-the-free-threaded-janus.md

ADR-0079: The prod interlock requires a green test-env record of the commit being promoted

Date: 2026-10-08 · Status: Superseded by ADR-0087 (2026-10-11)

Promoter.gate_for("prod") admits a prod promote when the test env's latest test record reads PASS — the record carries a timestamp and return code, not the commit it tested, so any latest green run admits any tree. Measured 2026-10-08: the ledger's test=PASS@10:27Z (recorded for 1d5f3e52c) would have admitted the promote of a32b14194, 25 commits later; the honest path was a fresh promote_env.py test test on the new tree before the ship. Proposed: (1) test <env> records the commit and ship's source id with the result; (2) gate_for("prod") refuses unless the record is PASS AND its sha equals the commit being promoted (a sha-less legacy record counts as absent); (3) ship.sh keeps its post-hoc 5a/5b identity checks and gains no test test step — the interlock refuses pre-hoc; (4) run_tests.py prints the freshness guard's cause on an aborted: freshness. Rejected: keeping the gate, a time window on the record, source-id only, folding test test into ship. Full record: docs/adr/0079-the-prod-interlock-requires-a-green-test-env-record-of-the-commit-being-promoted.md

ADR-0080: Every fleet container's address is pinned as nic ipv4.address

ADR-0081: Provisioners create topology only by generating Terraform

ADR-0082: The mcp-server-test-ssh profile's embedded key stays unrotated

ADR-0083: The retired rehearsal fleet stays parked, not deleted

ADR-0084: Governance predicate dispositions — wire 14, keep 8, hold 30

ADR-0085: Every ruling is recoverable, logged, and fed back into design

ADR-0086: Claude sessions get a project-scoped SPEC-106 context pack at SessionStart

ADR-0087: The prod gate is one correctness run of the promoted commit

ADR-0088: One shared green ledger per repo; a test reruns only when its own code or the code it tests changes

ADR-0089: Bare toolchain names fail the gate in Prolog, and the C toolchain is one declared file

ADR-0090: The git sentinel fails a test for its own mutations, not for sibling-worktree activity

ADR-0092: The orchestrata plugin is self-contained, pinned by a tag, and installed by one verifying command

ADR-0093: Promotion, test and gate work re-injects the process, test and gate memories, and compaction resets the injector

ADR-0094: Graph queries run with the ontology structure memory injected first

ADR-0095: SWI-Prolog is built from pinned source into a fixed project-owned prefix, and the runtime path leaves guix

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

ADR-0097: The resident AST daemon publishes the snapshot file from its warm cache — the post-edit hooks stop re-serializing the tree on every write, and the duplicate home-directory refresh hook is retired

ADR-0098: First-docs-capture rule — a graph ADR node whose body was never captured from docs/adr/ (it holds a wiki summary or is empty) is baselined once from its docs body; immutability binds from that first docs capture onward

ADR-0099: The gateway's MCP transport is a WebSocket JSON-RPC client of the running gateway, over one declarative method table that both transports read, and every method is approval-gated unless marked read-only

ADR-0100: Model review and the Prolog gate run once per slice at hand-back and once per batch, not on every commit; the deterministic gates stay per commit

ADR-0101: ADR-0100 rested on a wrong reading of the commit hook; the real hook's stages are measured first and placement is decided on the numbers; none of ADR-0100's rules execute

ADR-0102: Three graph ADR nodes overwritten by a mis-targeted codetools sync are re-baselined from docs, and the codetools register gets its own graph key before any further sync

ADR-0103: The byte-faithful LIFT is the parity oracle, not the deliverable; the clean target is the deliverable

ADR-0104: Git worktrees are not graph projects — orchkg holds one current, provenance-stamped copy per codebase

ADR-0105: The components branch pushes only after the affected-test gate learns the packages/** layout — a 345-commit push is not shipped past the gate with --no-verify

ADR-0106: Ruling-gated lift increments are not claimed by their package's parity suite until their ruling lands — the affected gate certifies the landed surface, and the held REQs stay UNLINKED in the RTM

ADR-0107: The frozen tools family lands as its own component package orchestrata-tools, and volks consumes it as a declared dependency (N-V3)

ADR-0108: The AST toolkit stays host-side — the volks codedirector consumes it through a contracts protocol injection seam (N-V4)

ADR-0109: Semantic-graph bulk writes run in transactions of at most 500 rows; replication stays SYNC

ADR-0110: The idle Prolog containers are retired from every fleet, and SWI-Prolog runs only embedded in the kernel

ADR-0111: Test runs never create containers; container creation is exercised only by explicit rehearsals

ADR-0112: Tools reaches Redis and embeddings through contracts protocols, not kernel imports

ADR-0113: Integration L1 builds now, and the master push is recorded as backup-and-deploy, not cut-over

ADR-0114: orchkg sees the component packages, and Spec and Requirement nodes are in scope

ADR-0115: E-1 ruled: the component DAG gains integration → knowledge_graph, governance, tools (27 → 30 edges)

ADR-0116: Staged source .py files enter the T21 env-key review at commit time

ADR-0117: SPEC-109 rename engine moves to codetools, and orchestrata consumes the deployed CLI

ADR-0118: Tier-1 host-side scripts transfer to codetools in two batches; review and RTM lane merges wait for their own rulings

ADR-0119: dr-hannah connects only to the prod orchgraph memgraph cluster; data stranded in another memgraph moves to prod

ADR-0120: Test-spawned subprocesses import from the installed environment, never the source tree

ADR-0121: The deployed Hermes subagent keeps persistent curated memory across runs; the user profile stays off

ADR-0122: One coordinator per worktree at a time; the shared handoff board is the coordination channel

ADR-0123: Every host service is registered in the runtime view with its purpose and architecture component, or it is retired

ADR-0124: Orchestrata runs in a test container and a prod container built from one OpenMandriva image, over always-on memgraph and Redis

ADR-0125: The host Claude writes no orchestrata code; it perfects the briefs, checks and workflow and measures the worker models

ADR-0126: The kg is branch-aware: each synced branch is its own project, serialized from a clean commit and checked after every sync

ADR-0127: The test runner stays a repo dev tool outside the integration release until codetools has an affected-set oracle

ADR-0128: The tracked codebase maps are regenerated at commit, by per-file delta, through the codetools ast map verb

ADR-0129: Installer tests that only read the install share one read-only install, an enforced exception to function-scoped fixtures

ADR-0130: ADRs are a publish step — rulings live in the scratch notes while a thread is open and are minted together at its end

ADR-0131: Deploys the classifier blocks run through approved user-level launchers that refuse unsafe states and verify or roll back

ADR-0132: One tree is edited and the deployment copy is built from it at a pinned version — which tree is edited at the cut-over

ADR-0133: orchestrata-mcp mints its own short-lived gateway token from the deployed JWT secret, and an exported GATEWAY_TOKEN still wins

ADR-0134: Dispatched Hermes workers get the read-only codetools verbs, the deployed Claude skills, the memory tool and the ast tool by default; no run writes skills

ADR-0135: Nothing starts at boot; one approved command starts the whole system and verifies it

ADR-0136: Secrets are not encrypted; a worktree's .env is the primary checkout's plaintext, refused when it carries placeholders

ADR-0137: The pre-commit framework config is removed; a gate counts only where an automatic runner executes it, and each orphaned gate is its own task

ADR-0138: Files are deleted through delete_file, which refuses directories; the Bash guard allows it

ADR-0139: The prod gate's full-suite run gets a 900-second test-phase cap; interactive runs keep 300

ADR-0140: The prod gate keeps RUL-038's 300-second test-phase cap; capped runs resume from the green ledger until one finishes

ADR-0141: Test selection and the green-ledger key read one edge set

ADR-0142: Prod installs orchestrata non-editable, like dev

ADR-0143: The green-ledger key hashes what tests run on, not all of pyproject.toml

ADR-0144: knowledge-wiki tests run in their own test database, never on MEMGRAPH_URI

ADR-0145: Test-created host resources use the orchtest- namespace, and the runner reaps them

ADR-0146: The run tag decides test-unit ownership; tests judged by prod verify keep their prod-scope names

ADR-0147: An agent's done status is stored before it is announced; the listener reads it after subscribing

ADR-0148: Every Hermes run declares its worker environment; the harness composes it, validates it before the model starts, and runs the agent and every check in it

ADR-0149: No RAG and no embedding; the knowledge graph answers

ADR-0150: The knowledge-wiki keeps its own RAG; ADR-0149 binds orchestrata only

ADR-0151: The Hermes agent keeps every provider key for the fallback, and env-reads refuses only unread set names

ADR-0152: ADR-0149 retirement scope: volk semantic roots move to the KG, EmbeddingService stays with a stable hash, the rag_context hook is retired

ADR-0153: Volk semantic roots look up KG symbols through an indexed name token, not a scan

ADR-0154: delete_file also removes empty directories; a non-empty directory still needs Mohamed's permission

ADR-0155: ADR-0140's graph body is re-baselined from its docs record

ADR-0156: The prod graphs stage stops enriching the semantic database with specs; nothing reads them

ADR-0157: A failed promotion is fixed forward and re-shipped; the runner never rolls back

ADR-0158: Reads are balanced across main and a synced replica

ADR-0159: RTM data lives in the operational graph, built from the @traces the AST carries from code

ADR-0160: Every push is recorded in full, with its exit code and its landing

ADR-0161: Ship's verified pushes go through the push record

ADR-0162: Worktree code nodes leave prod orchkg after their writer is closed

ADR-0163: A deployed tree is never rewritten after deploy

ADR-0164: Skipped verification and rollback get no exception; only ship's recorded push stays

ADR-0165: sync_traces_to_graph is retired

ADR-0166: python-dev is merged selectively and its test advice is rejected

ADR-0167: The IoC design is ruled for the new project only, and the old tree keeps its rules

ADR-0168: ADR-0162 is rebaselined to drop a time not taken from a clock read

ADR-0169: The growth claim in ADR-0162 is withdrawn

ADR-0170: The dev fleet starts in the default system-up run

ADR-0171: Test selection, the green ledger and batching move to codetools

ADR-0172: Test batching stays in orchestrata

ADR-0173: CI's test job verifies the ship's recorded authoritative run instead of re-running the suite

ADR-0174: A static gate whose inputs are content-identical to a passing run is reused, not re-run

ADR-0175: An orchestrata ship over 300 seconds finishes every stage, then fails

ADR-0176: The test preflight leaves the trace_intel KBs to their consumers

ADR-0177: The prod gate accepts the ship's verify run across its evidence-only commit

ADR-0178: Infra capabilities are tested once each against a small real fixture codebase, never the whole repo

ADR-0179: Tests are organised by a case catalogue, each case listed once and proved by exactly one test

ADR-0180: A per-file static gate re-checks only the files whose content changed

ADR-0181: REQ-109-042 to 044 retire with the RefactorRenameTool ADR-0117 deleted