Graduated Validation Protocol
Overview
The evolutionary loop generates candidate improvements continuously. Not
all of them should reach production. Any system that modifies itself in
production needs a safety envelope. Ch7 provides it through the RPO spine
and the Graduated Validation Protocol (GVP).
The RPO spine is three interlocking properties:
- Recursion — the improvement mechanisms are themselves part of the
codebase the agent can analyze and improve. The self-improvement system
applies to itself.
- Provenance — every change is cryptographically signed and committed
to an immutable ledger. This is source control for thought: complete
auditability and instant rollback for every model, prompt, or
architectural change.
lib.provenance_signature is the dev-time stand-in.
- Optimization — the GVP itself. Rather than a single approval gate that
must be either permissive or strict, it routes each candidate to a risk
tier and applies matching scrutiny.
The three tiers:
| Tier |
Risk class |
Gate |
Outcome |
| 1 canary release |
low: minor prompt updates, hyperparameter adjustments |
~1% live traffic; statistically significant target-metric lift with no core-KPI degradation |
pass or automatic rollback |
| 2 staging gauntlet |
moderate: SEAL/TPT fine-tune results, refined tool integration |
benchmark + regression (catastrophic forgetting) + safety/alignment (bias drift) + performance (latency/cost) suites; net-positive multi-objective utility U = w_accuracyaccuracy + w_cost(1-cost) + w_safety*safety_score, no safety regressions |
pass or archive |
| 3 airlock protocol |
high: modifies safety protocols, integrates a brand-new tool, or failed staging with large potential |
sandboxed isolated environment; automated risk/reward report |
escalated for human approve / reject / modify |
The second half is the entropy-collapse guard. In production the agent
evolves continuously, hundreds of small improvements per week, each passing
validation individually. The compounding problem is the accumulated weight
of all changes: contradictory learnings, stale fixes for resolved issues,
redundant nodes that slow retrieval. The Kepler architecture (OpenAI, 2026)
solves this with a dual-store pattern: Knowledge is human-authored and
version-controlled; Learnings are agent-generated and ephemeral. A daily
garbage-collection traversal walks the Learnings subgraph and removes a node
if any of three conditions holds: the issue was resolved and promoted to
Knowledge, a newer higher-confidence learning contradicts it, or it has not
been retrieved in 30 days.
When to Use
- Gating a continuous self-evolution loop: candidate changes must be
validated before they reach live traffic (the chapter's full-evolutionary-loop example, the
graduated_validation(candidate).passed branch)
- Routing a mixed stream of candidates (prompt tweaks, fine-tunes, new-tool
integrations) to the right level of scrutiny automatically
- Enforcing "no safety regression" as a hard constraint on a fine-tune
before it ships (Tier 2)
- Running the daily Learnings garbage-collection pass to prevent entropy
collapse in a long-running agent
- Monitoring the Learnings-to-Knowledge promotion rate to tune criteria
Phrases: "should this change ship", "which validation tier", "canary the
prompt update", "staging gauntlet", "airlock protocol", "graduated
validation", "RPO spine", "entropy collapse", "garbage-collect learnings",
"promotion rate".
When NOT to Use
- One-off manual deploys. A single human approval gate is enough; the
tiered protocol pays off only when candidates arrive continuously.
- Generating the candidate. This skill validates a candidate; it does
not diagnose, attribute, or intervene. Those are the execution-graph,
semantic-backpropagation, and intervention skills.
- Hyperparameter optimization of retrieval infrastructure. That
background optimization (chunk sizes, hop distances) is Ch8
production-hardening work; it runs alongside the loop, not inside this gate.
- As the ledger itself.
provenance_signature is a content hash for the
dev spike; production needs a real signing key and an append-only ledger.
Process
| Step |
Input |
Action |
Output |
Verification |
| 1 |
candidate dict {intervention_type, novel, touches_safety, new_tool} |
lib.assign_tier(candidate) |
one of TIERS |
Tier 3 flags override; prompt/hyperparameter -> TIER1, fine_tune/tool_integration -> TIER2 |
| 2 |
metrics {target_lift, target_pvalue, kpi_deltas} |
lib.canary_gate(metrics, min_lift, kpi_regression_tol) |
GateResult (TIER1) |
passes iff lift > min_lift AND pvalue < 0.05 AND no KPI below -tol; else auto-rollback reason |
| 3 |
scores {accuracy, cost, safety_score}, weights {w_accuracy, w_cost, w_safety} |
lib.staging_utility(scores, weights) |
float U |
U = w_accuracyaccuracy + w_cost(1-cost) + w_safety*safety_score |
| 4 |
scores (+ safety_regression), weights, optional baseline |
lib.staging_gate(scores, weights, min_utility, baseline) |
GateResult (TIER2) |
passes iff utility > baseline (or min_utility) AND safety_regression is False |
| 5 |
risk_reward dict, human_decision or None |
lib.airlock_gate(risk_reward, human_decision) |
GateResult (TIER3, requires_human=True) |
pending on None; passes only on "approve" |
| 6 |
candidate carrying gate fields |
lib.graduated_validation(candidate) |
GateResult |
assigns tier then runs matching gate from candidate fields |
| 7 |
candidate dict |
lib.provenance_signature(candidate) |
deterministic SHA-256 hex |
RPO Provenance: deterministic, content-sensitive |
| 8 |
list[Learning], ttl_days=30 |
lib.garbage_collect(learnings, ttl_days) |
(kept, removed) tuple |
removes promoted / contradicted / idle-past-TTL; keeps fresh |
| 9 |
total_learnings, promoted counts |
lib.promotion_rate(total, promoted) then lib.promotion_health(rate) |
float rate, flag string |
flags "criteria too strict" when rate < 0.10 |
Rationalizations
| Agent rationalization |
Documented rebuttal |
| "One approval gate is simpler than three tiers." |
Ch7 is explicit: a single gate "must be either permissive or strict." A permissive gate ships unsafe changes; a strict gate blocks safe ones. The GVP routes each candidate to the appropriate level of scrutiny instead of forcing one policy on all of them. |
| "The fine-tune raised accuracy a lot, ship it." |
Tier 2 passes only on net-positive multi-objective utility "with no safety regressions." Safety regression is a hard constraint in Ch7, not a term traded off inside the utility sum. staging_gate fails on safety_regression even when utility is high. |
| "The canary looks better, that's enough." |
Ch7 Tier 1 requires a "statistically significant improvement in the target metric with no degradation in core KPIs." A raw lift without significance (p < 0.05) or with a KPI regression triggers automatic rollback, not a ship. |
| "Human review on the new-tool change slows us down, run it as a fine-tune." |
Tier 3 overrides tier assignment: a change that "integrate[s] a brand-new external tool" or "modif[ies] safety protocols" is high-risk by definition and goes to the airlock regardless of its nominal type. assign_tier enforces the override. |
| "Learnings are cheap, keep them all." |
Ch7 names the failure: "contradictory learnings, stale fixes for resolved issues, and redundant knowledge nodes that slow retrieval." Without the daily GC traversal the Learnings subgraph accumulates entropy and degrades retrieval. Keeping everything is the entropy-collapse path. |
| "Promotion criteria should be strict so only the best patterns are curated." |
Ch7 Tip: "If fewer than 10% of learnings get promoted to curated knowledge within 30 days, your promotion criteria are too strict and you are discarding valuable patterns." promotion_health flags exactly this. |
Red Flags
- A fine-tune or new-tool change assigned to Tier 1. Tier 3 override was
skipped;
touches_safety / new_tool / novel flags are not being read.
- A staging pass with
safety_regression True. The hard safety
constraint was folded into the utility sum instead of gating on it.
- A Tier 3
GateResult with requires_human False. The airlock is not
escalating; human review is being bypassed.
- Learnings count grows unbounded across days. The daily GC pass is not
running, or TTL / promotion edges are never set. Entropy collapse follows.
- Promotion rate stuck below 10% with no flag.
promotion_health is not
wired into monitoring; valuable patterns are being discarded silently.
- CLI
--help exits non-zero. SKILL.md / CLI mismatch; the multi-harness
invariant is broken.
Non-Negotiable Verification
- Run the benchmark battery.
python cli.py benchmark must report
16/16 passed:
assign_tier routes prompt -> TIER1, fine_tune -> TIER2,
touches_safety / new_tool / novel -> TIER3 (override)
- canary passes on significant lift + no regression, fails on KPI
regression and on non-significant p-value
- staging fails when
safety_regression is True even with high utility,
passes net-positive over baseline with no regression
- airlock is pending on None, passes only on "approve", stays
requires_human
garbage_collect removes idle / promoted / contradicted, keeps a fresh
high-confidence learning, honors the 30-day TTL boundary
promotion_health flags below 10%
- Run the DevOps scenario.
python cli.py scenario prompt-canary routes
the CausalAttributionNode prompt refinement (stripe-python 3.2.1 -> 3.3.0
timeout 30s -> 10s cascade) into Tier 1 canary, shows lift with no
regression, then promotes the resolution to Knowledge and garbage-collects
the ephemeral Learnings.
- Verify CLI help.
python cli.py --help exits 0 and prints the
SKILL.md description.
Security Posture
- Prompt injection. Candidate metadata, risk/reward reports, and Learning
nodes may originate from agent-generated traces.
lib.py treats every
candidate field as untrusted data: it reads scalar metrics and boolean
flags, never evaluates any field as code, and never interpolates a field
into a shell or query. The airlock risk/reward report is truncated and
JSON-encoded before display, so an injected instruction string is inert.
- Data exfiltration. No network calls anywhere in
lib.py. Gate results
and GC output are returned to the caller / printed to stdout; the caller
owns downstream piping. provenance_signature is a local SHA-256 over the
candidate content, computed in-process.
- Privilege escalation. No shell invocation, no
eval/exec, no dynamic
import, no file writes. The CLI reads only the explicit --path JSON files
and writes nothing to disk. A candidate cannot escalate its own tier: the
Tier 3 override in assign_tier is checked first, so a safety-touching or
new-tool change cannot masquerade as a Tier 1 canary.
Composition
- Composes with the Anthropic
agent-skills Reviewer pattern at the
pattern layer and the Ghosh Workflow layer: it reviews a candidate change
and returns a pass/fail verdict for an orchestration loop above it.
- Consumes candidates produced by the execution-graph,
semantic-backpropagation, and intervention skills (Ch7). It is the
graduated_validation(candidate).passed branch of the full evolutionary
loop (the full-evolutionary-loop example).
- Composes with the RPO Provenance ledger:
provenance_signature signs a
candidate before the gate result is recorded, giving instant rollback.
- Pairs with the Kepler dual-store: the GC traversal runs on the same
graph the execution-graph skill writes, distinguishing Knowledge from
Learnings by provenance edges.
- Hands off to Ch8 production-hardening for the retrieval-infrastructure
hyperparameter optimization that runs alongside the loop rather than inside
this gate.
Source Attribution
Distilled from Agentic GraphRAG (O'Reilly, by Anthony Alcaraz and Sam Julien)
Chapter 7 — Self-Evolution and Evaluation, the sections "The RPO Spine and
Graduated Validation Protocol" and "Persistent Self-Learning Without Entropy
Collapse", plus the chapter's full-evolutionary-loop example. Key references
named in the chapter: the RPO spine (Recursion / Provenance / Optimization,
"source control for thought"); the three-tier Graduated Validation Protocol
(canary release / staging gauntlet / airlock protocol) shown in Figure 7-3;
the multi-objective utility U = w1accuracy + w2(1-cost) + w3*safety_score;
and the Kepler dual-store garbage-collection architecture (OpenAI, 2026) with
its 30-day TTL, daily GC pass, and 10% promotion-rate health threshold.
1---2name: graduated-validation-protocol3description: The Ch7 safety envelope for a self-evolving agent: the RPO spine (Recursion, Provenance, Optimization) plus the Graduated Validation Protocol that gates what reaches production. Assigns every candidate change a risk tier and applies the matching scrutiny: Tier 1 canary (1% traffic, automatic rollback), Tier 2 staging gauntlet (multi-objective utility, passes only net-positive with no safety regression), Tier 3 airlock (sandboxed risk/reward report escalated for human approve/reject/modify). Also the entropy-collapse guard (Kepler dual-store): daily garbage collection of agent-generated Learnings once promoted, contradicted, or idle past a 30-day TTL. Use to gate a continuous self-evolution loop before candidate changes reach users. NOT for a one-off manual deploy (a single approval gate is enough), NOT for the diagnosis / attribution / intervention steps that produce the candidate (this validates the candidate, it does not generate it).4---56# Graduated Validation Protocol78## Overview910The evolutionary loop generates candidate improvements continuously. Not11all of them should reach production. Any system that modifies itself in12production needs a safety envelope. Ch7 provides it through the RPO spine13and the Graduated Validation Protocol (GVP).1415The RPO spine is three interlocking properties:1617- **Recursion** — the improvement mechanisms are themselves part of the18 codebase the agent can analyze and improve. The self-improvement system19 applies to itself.20- **Provenance** — every change is cryptographically signed and committed21 to an immutable ledger. This is source control for thought: complete22 auditability and instant rollback for every model, prompt, or23 architectural change. `lib.provenance_signature` is the dev-time stand-in.24- **Optimization** — the GVP itself. Rather than a single approval gate that25 must be either permissive or strict, it routes each candidate to a risk26 tier and applies matching scrutiny.2728The three tiers:2930| Tier | Risk class | Gate | Outcome |31|------|-----------|------|---------|32| 1 canary release | low: minor prompt updates, hyperparameter adjustments | ~1% live traffic; statistically significant target-metric lift with no core-KPI degradation | pass or automatic rollback |33| 2 staging gauntlet | moderate: SEAL/TPT fine-tune results, refined tool integration | benchmark + regression (catastrophic forgetting) + safety/alignment (bias drift) + performance (latency/cost) suites; net-positive multi-objective utility U = w_accuracy*accuracy + w_cost*(1-cost) + w_safety*safety_score, no safety regressions | pass or archive |34| 3 airlock protocol | high: modifies safety protocols, integrates a brand-new tool, or failed staging with large potential | sandboxed isolated environment; automated risk/reward report | escalated for human approve / reject / modify |3536The second half is the entropy-collapse guard. In production the agent37evolves continuously, hundreds of small improvements per week, each passing38validation individually. The compounding problem is the accumulated weight39of all changes: contradictory learnings, stale fixes for resolved issues,40redundant nodes that slow retrieval. The Kepler architecture (OpenAI, 2026)41solves this with a dual-store pattern: Knowledge is human-authored and42version-controlled; Learnings are agent-generated and ephemeral. A daily43garbage-collection traversal walks the Learnings subgraph and removes a node44if any of three conditions holds: the issue was resolved and promoted to45Knowledge, a newer higher-confidence learning contradicts it, or it has not46been retrieved in 30 days.4748## When to Use4950- Gating a continuous self-evolution loop: candidate changes must be51 validated before they reach live traffic (the chapter's full-evolutionary-loop example, the52 `graduated_validation(candidate).passed` branch)53- Routing a mixed stream of candidates (prompt tweaks, fine-tunes, new-tool54 integrations) to the right level of scrutiny automatically55- Enforcing "no safety regression" as a hard constraint on a fine-tune56 before it ships (Tier 2)57- Running the daily Learnings garbage-collection pass to prevent entropy58 collapse in a long-running agent59- Monitoring the Learnings-to-Knowledge promotion rate to tune criteria6061Phrases: "should this change ship", "which validation tier", "canary the62prompt update", "staging gauntlet", "airlock protocol", "graduated63validation", "RPO spine", "entropy collapse", "garbage-collect learnings",64"promotion rate".6566## When NOT to Use6768- **One-off manual deploys.** A single human approval gate is enough; the69 tiered protocol pays off only when candidates arrive continuously.70- **Generating the candidate.** This skill validates a candidate; it does71 not diagnose, attribute, or intervene. Those are the execution-graph,72 semantic-backpropagation, and intervention skills.73- **Hyperparameter optimization of retrieval infrastructure.** That74 background optimization (chunk sizes, hop distances) is Ch875 production-hardening work; it runs alongside the loop, not inside this gate.76- **As the ledger itself.** `provenance_signature` is a content hash for the77 dev spike; production needs a real signing key and an append-only ledger.7879## Process8081| Step | Input | Action | Output | Verification |82|------|-------|--------|--------|--------------|83| 1 | candidate dict {intervention_type, novel, touches_safety, new_tool} | `lib.assign_tier(candidate)` | one of `TIERS` | Tier 3 flags override; prompt/hyperparameter -> TIER1, fine_tune/tool_integration -> TIER2 |84| 2 | metrics {target_lift, target_pvalue, kpi_deltas} | `lib.canary_gate(metrics, min_lift, kpi_regression_tol)` | `GateResult` (TIER1) | passes iff lift > min_lift AND pvalue < 0.05 AND no KPI below -tol; else auto-rollback reason |85| 3 | scores {accuracy, cost, safety_score}, weights {w_accuracy, w_cost, w_safety} | `lib.staging_utility(scores, weights)` | float U | U = w_accuracy*accuracy + w_cost*(1-cost) + w_safety*safety_score |86| 4 | scores (+ safety_regression), weights, optional baseline | `lib.staging_gate(scores, weights, min_utility, baseline)` | `GateResult` (TIER2) | passes iff utility > baseline (or min_utility) AND safety_regression is False |87| 5 | risk_reward dict, human_decision or None | `lib.airlock_gate(risk_reward, human_decision)` | `GateResult` (TIER3, requires_human=True) | pending on None; passes only on "approve" |88| 6 | candidate carrying gate fields | `lib.graduated_validation(candidate)` | `GateResult` | assigns tier then runs matching gate from candidate fields |89| 7 | candidate dict | `lib.provenance_signature(candidate)` | deterministic SHA-256 hex | RPO Provenance: deterministic, content-sensitive |90| 8 | list[`Learning`], ttl_days=30 | `lib.garbage_collect(learnings, ttl_days)` | (kept, removed) tuple | removes promoted / contradicted / idle-past-TTL; keeps fresh |91| 9 | total_learnings, promoted counts | `lib.promotion_rate(total, promoted)` then `lib.promotion_health(rate)` | float rate, flag string | flags "criteria too strict" when rate < 0.10 |9293## Rationalizations9495| Agent rationalization | Documented rebuttal |96|------------------------|--------------------|97| "One approval gate is simpler than three tiers." | Ch7 is explicit: a single gate "must be either permissive or strict." A permissive gate ships unsafe changes; a strict gate blocks safe ones. The GVP routes each candidate to the appropriate level of scrutiny instead of forcing one policy on all of them. |98| "The fine-tune raised accuracy a lot, ship it." | Tier 2 passes only on net-positive multi-objective utility "with no safety regressions." Safety regression is a hard constraint in Ch7, not a term traded off inside the utility sum. `staging_gate` fails on `safety_regression` even when utility is high. |99| "The canary looks better, that's enough." | Ch7 Tier 1 requires a "statistically significant improvement in the target metric with no degradation in core KPIs." A raw lift without significance (p < 0.05) or with a KPI regression triggers automatic rollback, not a ship. |100| "Human review on the new-tool change slows us down, run it as a fine-tune." | Tier 3 overrides tier assignment: a change that "integrate[s] a brand-new external tool" or "modif[ies] safety protocols" is high-risk by definition and goes to the airlock regardless of its nominal type. `assign_tier` enforces the override. |101| "Learnings are cheap, keep them all." | Ch7 names the failure: "contradictory learnings, stale fixes for resolved issues, and redundant knowledge nodes that slow retrieval." Without the daily GC traversal the Learnings subgraph accumulates entropy and degrades retrieval. Keeping everything is the entropy-collapse path. |102| "Promotion criteria should be strict so only the best patterns are curated." | Ch7 Tip: "If fewer than 10% of learnings get promoted to curated knowledge within 30 days, your promotion criteria are too strict and you are discarding valuable patterns." `promotion_health` flags exactly this. |103104## Red Flags105106- **A fine-tune or new-tool change assigned to Tier 1.** Tier 3 override was107 skipped; `touches_safety` / `new_tool` / `novel` flags are not being read.108- **A staging pass with `safety_regression` True.** The hard safety109 constraint was folded into the utility sum instead of gating on it.110- **A Tier 3 `GateResult` with `requires_human` False.** The airlock is not111 escalating; human review is being bypassed.112- **Learnings count grows unbounded across days.** The daily GC pass is not113 running, or TTL / promotion edges are never set. Entropy collapse follows.114- **Promotion rate stuck below 10% with no flag.** `promotion_health` is not115 wired into monitoring; valuable patterns are being discarded silently.116- **CLI `--help` exits non-zero.** SKILL.md / CLI mismatch; the multi-harness117 invariant is broken.118119## Non-Negotiable Verification1201211. **Run the benchmark battery.** `python cli.py benchmark` must report122 16/16 passed:123 - `assign_tier` routes prompt -> TIER1, fine_tune -> TIER2,124 touches_safety / new_tool / novel -> TIER3 (override)125 - canary passes on significant lift + no regression, fails on KPI126 regression and on non-significant p-value127 - staging fails when `safety_regression` is True even with high utility,128 passes net-positive over baseline with no regression129 - airlock is pending on None, passes only on "approve", stays130 `requires_human`131 - `garbage_collect` removes idle / promoted / contradicted, keeps a fresh132 high-confidence learning, honors the 30-day TTL boundary133 - `promotion_health` flags below 10%1342. **Run the DevOps scenario.** `python cli.py scenario prompt-canary` routes135 the CausalAttributionNode prompt refinement (stripe-python 3.2.1 -> 3.3.0136 timeout 30s -> 10s cascade) into Tier 1 canary, shows lift with no137 regression, then promotes the resolution to Knowledge and garbage-collects138 the ephemeral Learnings.1393. **Verify CLI help.** `python cli.py --help` exits 0 and prints the140 SKILL.md description.141142## Security Posture143144- **Prompt injection.** Candidate metadata, risk/reward reports, and Learning145 nodes may originate from agent-generated traces. `lib.py` treats every146 candidate field as untrusted data: it reads scalar metrics and boolean147 flags, never evaluates any field as code, and never interpolates a field148 into a shell or query. The airlock risk/reward report is truncated and149 JSON-encoded before display, so an injected instruction string is inert.150- **Data exfiltration.** No network calls anywhere in `lib.py`. Gate results151 and GC output are returned to the caller / printed to stdout; the caller152 owns downstream piping. `provenance_signature` is a local SHA-256 over the153 candidate content, computed in-process.154- **Privilege escalation.** No shell invocation, no `eval`/`exec`, no dynamic155 import, no file writes. The CLI reads only the explicit `--path` JSON files156 and writes nothing to disk. A candidate cannot escalate its own tier: the157 Tier 3 override in `assign_tier` is checked first, so a safety-touching or158 new-tool change cannot masquerade as a Tier 1 canary.159160## Composition161162- **Composes with** the Anthropic `agent-skills` Reviewer pattern at the163 pattern layer and the Ghosh Workflow layer: it reviews a candidate change164 and returns a pass/fail verdict for an orchestration loop above it.165- **Consumes** candidates produced by the execution-graph,166 semantic-backpropagation, and intervention skills (Ch7). It is the167 `graduated_validation(candidate).passed` branch of the full evolutionary168 loop (the full-evolutionary-loop example).169- **Composes with** the RPO Provenance ledger: `provenance_signature` signs a170 candidate before the gate result is recorded, giving instant rollback.171- **Pairs with** the Kepler dual-store: the GC traversal runs on the same172 graph the execution-graph skill writes, distinguishing Knowledge from173 Learnings by provenance edges.174- **Hands off to** Ch8 production-hardening for the retrieval-infrastructure175 hyperparameter optimization that runs alongside the loop rather than inside176 this gate.177178## Source Attribution179180Distilled from *Agentic GraphRAG* (O'Reilly, by Anthony Alcaraz and Sam Julien)181Chapter 7 — Self-Evolution and Evaluation, the sections "The RPO Spine and182Graduated Validation Protocol" and "Persistent Self-Learning Without Entropy183Collapse", plus the chapter's full-evolutionary-loop example. Key references184named in the chapter: the RPO spine (Recursion / Provenance / Optimization,185"source control for thought"); the three-tier Graduated Validation Protocol186(canary release / staging gauntlet / airlock protocol) shown in Figure 7-3;187the multi-objective utility U = w1*accuracy + w2*(1-cost) + w3*safety_score;188and the Kepler dual-store garbage-collection architecture (OpenAI, 2026) with189its 30-day TTL, daily GC pass, and 10% promotion-rate health threshold.