6.4 KiB
Agreement log: the schema spec
The agreement log records what an engine proposed, what its guardrail said, what a human decided, and whether the two agreed. It is the substrate the autonomy doctrine reads: agreement rates per lane earn a gate class its auto-pass, and post-merge regressions revoke it. Autonomy Review reads this log; Incident Response and Lane Demotion reads its post_merge_outcome; nothing else mutates it.
This file is the public schema, generalized from the krine agreement-rate table (migration 0007). The schema is what you get. The instance, its write path, the designation allowlist, and every promotion decision are operated, not published. A reader who implements this schema gets their own log; they do not get ours.
The agreement log has no connector class, by design. It is operated substrate, not a connectable capability (see CONNECTORS.md). Workflow files that touch it split their done-when conditions into a public gate and an operated-log note, so a stranger running the workflow never depends on infrastructure that is not published.
Reference schema (migration 0007, quoted with types)
The canonical source is the krine agreement-rate migration. Its columns and types, quoted as the reference:
create type human_verdict_kind as enum ('merge', 'reject', 'revise');
create type agreement_kind as enum ('true_pass', 'false_pass', 'true_fail', 'false_fail');
create table agreements (
id uuid primary key default gen_random_uuid(),
project_id uuid references projects(id) on delete cascade,
decision_id text not null,
pr_id text,
lane text not null,
risk_tier text not null,
agent_id text not null,
guardrail_verdict text not null, -- pass or fail
guardrail_confidence numeric, -- graded score; null for deterministic checks
guardrail_checks jsonb, -- which checks fired and their results, plus the proposal pointer
human_verdict human_verdict_kind, -- merge | reject | revise; filled after human review
human_reason text, -- the rationale; filled after human review
proposal_to_merge_diff jsonb, -- the proposal-to-merge diff or a pointer; filled after merge
human_review_latency numeric, -- seconds from PR open to human verdict
agreement agreement_kind, -- authored after human review
post_merge_outcome text, -- null at merge, filled later by continuous verification
created_at timestamptz not null default now()
);
The public spec
The public schema carries the fields a reader implementing this tier needs. It converges with the reference above rather than restating it from memory.
Retained from 0007 as-is:
| Field | Type | Meaning |
|---|---|---|
| agreement | enum: true_pass, false_pass, true_fail, false_fail | the four-way agreement value, authored (see below), never derived from the verdict pair |
| lane | text, not null | the autonomy lane, e.g. content_roadmap. Per-lane agreement rates are the unit the promotion thresholds apply to; without lane, false-pass-among-passes cannot be computed per lane |
| risk_tier | text | the risk classification; per-tier thresholds govern promotion, and Tier 3 is permanently excluded |
| guardrail_confidence | numeric, nullable | the graded score; null for purely deterministic checks. The confidence-cutoff promotion for graded lanes is impossible without it |
| guardrail_checks | jsonb | which checks fired and their results, and the pointer to the proposal |
| human_verdict | enum: merge, reject, revise (+ waive, added below) | what happened to the work; a separate axis from agreement, and neither maps from the other |
| human_reason | text | the rationale, filled after human review; required on revise and waive in this tier |
| proposal_to_merge_diff | jsonb | the proposal-to-merge diff or a pointer to it; the primary correction signal, and the cold-start recovery reads merged-versus-rejected diffs |
| post_merge_outcome | text | null at merge, filled later by continuous verification; the second ground truth that demotion and the hardened rung read |
Added for this tier:
| Field | Type | Meaning |
|---|---|---|
| property | text, designation-guarded | the showcase property the row belongs to; the publish path enforces the allowlist against it |
| workflow_slug | text | which workflow produced the proposal |
| phase | text | which phase of that workflow |
| artifact_ref | text | pointer to the held artifact the row is about |
| waive | value on human_verdict | a fourth human verdict alongside merge, reject, revise |
Agreement is authored, never derived
Agreement is AUTHORED by the human who saw the diff, never derived from the verdict pair. A guardrail pass that a human overrides to revise is a false_pass, and no naive rule produces that mapping; the human writes it. The verdict axis (what happened to the work) and the agreement axis (whether the guardrail was right) are independent, and neither is computed from the other.
Waive rows carry an authored agreement value plus a required human_reason, are excluded from false-pass and false-fail rate computations, and report as their own line in Autonomy Review. Waives stay visible without contaminating the promotion thresholds: a gate waived because it was too strict, and a risk waived because it was knowingly accepted, are both recorded and both kept out of the rates that earn a lane its autonomy.
The designation guard
The publish path refuses any public row whose property is not on the maintained showcase allowlist. The guard sits at the write boundary, not only in authoring convention: a row for a non-designated property can never become public output, and its property name can never appear in published material. The allowlist is data, maintained in one place, not a per-row judgment.
Open versus operated
The schema is public. The instance, the write path, the allowlist, and every promotion decision are operated. A reader who implements this schema gets their own log; they do not get ours. Forking the repo yields the gates and this spec, and a reader's own log if they build one; it does not yield RampStack's rows.
Storage
One append-only table in an operational Postgres store. Autonomy Review reads it, Incident Response and Lane Demotion reads post_merge_outcome, and nothing else mutates it. Do not add a second table until there is a second writer.