Skip to content

Adopt eva.consumption.v1 in petrova-hq

Date: 2026-05-08 Status: open Supersedes: docs/decisions/2026-05-06-sub-project-g-rocky-eva-surface-ratification.md (G.2 stance), docs/decisions/2026-05-06-sub-project-g-closure.md (G.2 outcome only — G.1 + G.3 unaffected) Superseded-by: none — current

Sub-project G closed on 2026-05-06 with G.2 ratifying that “eva-hq has no consumption surface; consumer-side eva is permanently not_applicable for every governed repo.” That stance held for two days.

On 2026-05-08, eva-hq ratified eva.consumption.v1: a per-surface consumption contract with three declared surfaces (events, control, prompts) and a producer-controlled evidence_consumer mirror. The schema lives at eva-hq:contracts/consumption.v1.json; helpers at eva-hq:bin/eva_consumption.py.

That ratification reverses G.2 — eva-hq now does have a consumption surface, and consumers that POST run events, call the control API, or pull pinned prompts can declare wired truthfully. Petrova’s upstream schema, probe, status verb, and verify-round mirror logic must be updated to accept the v1 shape. Until they are, every consumer is schema-locked into the legacy not_applicable envelope.

petrova-hq adopts eva.consumption.v1 as the canonical EVA integration shape. Specifically:

  1. Schema. contracts/contract.schema.json $defs.integration_eva becomes a oneOf discriminated by the presence of surfaces:
    • Legacy branch (integration_eva_legacy) — accepts the pre-v1 envelope, retained for backward compat for slugs not yet migrated. Forbids surfaces.
    • v1 branch$ref to eva-hq:contracts/consumption.v1.json, vendored at petrova-hq:contracts/vendor/eva-consumption.v1.json.
  2. Vendoring. The v1 schema is vendored, not cross-repo $ref’d at validate time. Refresh procedure documented in contracts/vendor/README.md. Vendoring keeps petrova doctor hermetic — the cli does not need a sibling checkout to validate.
  3. Probe. cli/src/probes/eva.ts rewritten:
    • Legacy block → unreachable with a migration pointer to this ADR.
    • v1 block → per-surface freshness check against verification_ttl_days (default 7). Each wired surface that passes contributes a fingerprint; aggregate evidence_sha is the 12-char hash of sorted fingerprints.
  4. Status verb. cli/src/verbs/eva_status.ts rewritten to surface per-surface state, evidence summaries, and the evidence_consumer mirror, replacing the bail_reason: not_implemented stub.
  5. Mirror. cli/src/eva-mirror.ts ports eva_consumption.py::compute_mirror + apply_mirror to TypeScript. sweepAndWriteState calls applyMirror after writing per-slug state when EVA_HQ_ROOT resolves to a git tree. Mirror writes are idempotent (semantic equality modulo mirrored_at).

For code:

  • New file: contracts/vendor/eva-consumption.v1.json (vendored from eva-hq HEAD bb5a8e0).
  • New file: contracts/vendor/README.md.
  • Edited: contracts/contract.schema.json (integration_evaoneOf).
  • Edited: cli/src/contract.ts (Ajv addSchema for vendored ref).
  • Edited: cli/src/types.ts (EvaIntegration = EvaIntegrationLegacy | EvaConsumptionV1).
  • Rewritten: cli/src/probes/eva.ts, cli/src/verbs/eva_status.ts.
  • New: cli/src/eva-mirror.ts, called from cli/src/verbs/doctor.ts::sweepAndWriteState.

For tests:

  • cli/tests/contract.test.ts — added 5 cases covering v1 valid, v1 fixture-on-disk, v1-wired-without-evidence, legacy-with-surfaces (discriminator), legacy not_applicable still valid.
  • New: cli/tests/probes/eva.test.ts — 8 cases (legacy reject, ok with no wired surfaces, fresh events, stale events, missing fields, stale control, prompts manifest missing, prompts unverified fallback).
  • New: cli/tests/eva-mirror.test.ts — 7 cases covering compute, idempotent apply, SHA drift, legacy-skip.
  • New fixtures: valid/eva-v1-all-surfaces-wired.yaml, invalid/eva-v1-wired-no-surface-evidence.yaml, invalid/eva-legacy-with-surfaces.yaml.
  • Existing fixture valid/all-wired.yaml updated to use the v1 shape for its eva block (the canonical “all-wired” example reflects the new normal).

For docs:

  • This ADR.
  • The G.2 closure doc (docs/decisions/2026-05-06-sub-project-g-closure.md) gets Superseded-by updated to point at this ADR for its G.2 section. G.1 and G.3 outcomes are unaffected.

For governance:

  • Existing registered slugs (ARES, Traceo, Rocky, devarno-cloud, STRATT, Choco, Grace, KAHN, Skyflow) keep their legacy eva: not_applicable blocks until a follow-up sweep migrates each to v1. The mirror writer skips legacy blocks, so the sweep is a no-op for them. Migration is one PR per consumer.
  • New consumers (smo1-io and onward) declare v1 directly.
  • Cross-repo $ref to eva-hq:contracts/consumption.v1.json — rejected. Ajv would have to walk the sibling checkout at validate time, breaking hermetic doctor runs in CI environments that don’t clone eva-hq. Vendoring + a documented refresh procedure is the same guarantee with less coupling.
  • Replace legacy schema entirely (no oneOf) — rejected. ~9 registered slugs currently carry legacy eva: not_applicable blocks; a hard cutover would invalidate all of them in one PR and force a coordinated registry-wide migration. The oneOf lets each slug migrate independently.
  • Shell out to eva consumption mirror for the evidence_consumer write — rejected. Adds a Python runtime dependency to the cli and couples petrova-hq’s CI to eva-hq’s pip env. The TS port is ~30 lines (file-system + git rev-parse) and the vendored schema + tests catch shape drift if the upstream impl evolves.
  • Wait for upstream to publish a stable producer-side contract.schema.json patch and consume it directly — rejected. No such patch is in flight on eva-hq, and the producer ADR is explicit that the schema lives in eva-hq for the producer side and in petrova-hq for the consumer-discovery side. Each repo owns its half.
  • eva-hq/docs/decisions/2026-05-08-eva-consumption-contract.md — upstream ratification.
  • eva-hq/docs/decisions/2026-05-07-eva-evidence-shape.md — the producer-side ADR that this is the consumer-side complement of.
  • eva-hq/contracts/consumption.v1.json — canonical schema (vendored copy at contracts/vendor/eva-consumption.v1.json, source SHA bb5a8e0).
  • eva-hq/bin/eva_consumption.py — reference impl for compute_mirror/apply_mirror.
  • core/prompts/10-eva-wire.md — already rewritten for v1 on branch eva-consumption-alignment (commit 1b57f59).
  • subagent: human:cli (this PR)
  • triggering: eva-hq#? — eva.consumption.v1 ratification