Constructdocs
section · decisions

0043 Oracle Meta Controller

4 min read·decisions / adr / 0043-oracle-meta-controller

ADR-0043: Oracle meta-controller — bounded-auto system health review

  • Date: 2026-06-18
  • Status: accepted
  • Deciders: Gerald Dagher (owner), Construct maintainers (cx-architect)
  • Relates to: ADR-0035 (extend-not-rebuild), ADR-0039 (surface model), alignment program (Phase 0–3)
  • Surface note (2026-06-29, self-audit construct-rr63.1.3): construct oracle is registered as a user-facing Core observability command beside construct status / construct doctor (lib/cli-commands.mjs), aligning with the ADR-0039 amendment (2026-06-25) that lists it as a thin-human-CLI observability surface. The prior internal: true registration is removed.

Note: ADR-0042 covers LLM credential resolution. Oracle meta-controller is ADR-0043 to preserve monotonic ADR numbering.

Problem

Construct operates three overlapping health layers that no single surface unifies:

  1. L0 doctor (lib/doctor/) — deterministic watchers, auto-recovery, audit log at ~/.cx/doctor-log.jsonl.
  2. Embed daemon (lib/embed/) — continuous observation ingest and snapshot generation.
  3. L1 gateway (lib/roles/) — event-driven persona invocations with rate limits and approval queues.

Operators and agents lack a read-model → verdict → bounded action loop that:

  • Collects project-scoped signals (observations, outcomes, contract violations, parity, alignment census) without an LLM on the hot path.
  • Synthesizes gaps deterministically before any specialist is dispatched.
  • Executes only safe, reversible maintenance (census, registry validate, tool-repo adapter sync) automatically.
  • Queues consequential remediation (specialist dispatch, doctor follow-up) for human approval.

Without this layer, alignment regressions and parity drift are discovered only during manual construct doctor runs or release gates — too late for continuous correction.

Decision

Ship the Oracle meta-controller as a daemon-backed L0.5 layer:

ComponentPathResponsibility
Read modellib/oracle/read-model.mjsCollect signals from .cx/observations/, .cx/outcomes/_summary.json, .cx/contract-violations.jsonl, ~/.cx/doctor-log.jsonl, audit-artifacts/alignment-census.json, checkProjectParity()
Synthesislib/oracle/synthesize.mjsPure synthesizeVerdict(readModel){ verdict, gaps, recommendedActions }
Policylib/oracle/policy.mjsclassifyAction(kind)auto | approve | deny
Actionslib/oracle/actions.mjsrunOracleTick() executes auto actions; queues approve actions to .cx/oracle/pending.jsonl
Daemonlib/oracle/index.mjscreateDaemon contract; killswitch CONSTRUCT_ORACLE=off; heartbeat ~/.cx/runtime/oracle/heartbeat.json
CLIlib/oracle/cli.mjsconstruct oracle start|status|review|pending|approve|gaps|reconcile
Specialistcx-oracleRoutes gaps to owning specialists via get_skill; internal, reasoning tier
APIGET /api/oracle, GET /api/oracle/pendingDashboard read surfaces
Capabilityoracle.meta-reviewRegistry entry with functional verification

Bounded-auto policy

Auto (no approval):

  • census-run — spawn scripts/alignment/census.mjs
  • registry-validate — import validateCapabilityRegistry
  • adapters-syncsyncProjectAdapters only when isConstructPackageRepo(projectDir)

Approve (append to .cx/oracle/pending.jsonl):

  • Specialist dispatch (specialist-review, trace-review, doctor-followup, outcomes-aggregate, …)

Deny (never via Oracle):

  • git-push, git-commit, destructive deletes, force sync

Gap surfaces and auto-raise policy

Hygiene and meta gaps (beads-hygiene, workflow-misaligned, propagation-stale, census-stale, outcomes-missing) are verdict-only: they appear in .cx/oracle/verdicts/, construct doctor, session prelude, and construct oracle gaps, but Oracle never auto-raises tracker beads for them. Novel actionable high gaps (e.g. doctor-escalation, dead-code-regression, parity-drift) may auto-raise at most one open bead per gapId via persistent fingerprinting and open-bead lookup. detectBeadsDrift() excludes [oracle/*] meta beads from stuck/stale counts so Oracle does not reinforce its own alerts. One-time duplicate cleanup: construct oracle reconcile [--dry-run].

Read/write contract

  • Read: Oracle reads durable JSON/JSONL artifacts only. No MCP, no LLM, no network on the read-model path.
  • Write: Oracle may append to .cx/oracle/pending.jsonl, write per-tick verdicts to .cx/oracle/verdicts/\<date>.json, routing artifacts to .cx/oracle/routing/, idempotent beads issues via lib/oracle/issues.mjs, heartbeat/last-tick under ~/.cx/runtime/oracle/, and spawn bounded maintenance subprocesses. Approve actions execute via lib/oracle/execute.mjs (L1 dispatch, outcomes aggregate). It does not mutate specialist prompts or git state autonomously.

Relationship to doctor, embed, and L1 gateway

flowchart TB
  subgraph L0["L0 — Doctor (deterministic)"]
    D[construct-doctor daemon]
    DL[~/.cx/doctor-log.jsonl]
    D --> DL
  end

  subgraph L05["L0.5 — Oracle (deterministic + bounded-auto)"]
    RM[read-model.mjs]
    SY[synthesize.mjs]
    AC[actions.mjs]
    RM --> SY --> AC
    AC --> PQ[.cx/oracle/pending.jsonl]
  end

  subgraph Embed["Embed daemon"]
    E[observation ingest]
    OBS[.cx/observations/]
    E --> OBS
  end

  subgraph L1["L1 — Role gateway"]
    G[role-pending.jsonl]
    P[cx-* personas]
    G --> P
  end

  DL --> RM
  OBS --> RM
  OUT[.cx/outcomes/_summary.json] --> RM
  CV[.cx/contract-violations.jsonl] --> RM
  AC -->|approve actions| G
  O[cx-oracle specialist] -->|routes gaps| P
  • Doctor: Oracle reads doctor audit lines; it does not replace doctor watchers. Doctor escalations become Oracle gaps routed to cx-sre / cx-operations.
  • Embed: Oracle reads observation index counts; embed continues ingest independently.
  • L1 gateway: Approve-queue actions may surface as role events; Oracle does not bypass gateway rate limits or fences.

Consequences

Positive

  • Continuous parity and alignment visibility without waiting for release gates.
  • Clear separation: deterministic collection/synthesis vs LLM routing (cx-oracle).
  • Bounded-auto reduces toil on the Construct tool repo (census, registry validate, adapters).

Negative

  • Another daemon to monitor; mitigated by shared createDaemon contract and killswitch.
  • False-positive gaps when outcomes summary is absent on greenfield projects; severities are tiered (low for missing summary).

Neutral

  • construct doctor remains the operator-facing diagnostic; Oracle complements it with periodic synthesis and action queue.
  • Contract-violation hygiene: workflow_contract_validate enriches bare construct→orchestrator goal packets before logging; construct oracle reconcile may write .cx/contract-violations-superseded.json so pre-fix homogeneous violations drop from oracle counts without deleting the forensic JSONL.

Verification

  • tests/functional/oracle-read-model.functional.test.mjs
  • tests/functional/oracle-bounded-auto.functional.test.mjs
  • tests/functional/oracle-hygiene-policy.functional.test.mjs
  • Capability registry entry oracle.meta-review with humanGate: approve-only