Skip to content

security benchmark: cover the Critic's advisory-only guarantee - #77

Merged
Nabzx merged 1 commit into
mainfrom
feat/critic-security-benchmark
Sep 5, 2026
Merged

Nabzx merged 1 commit into
mainfrom
feat/critic-security-benchmark

Conversation

@Nabzx

@Nabzx Nabzx commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Follow-up to #75/PR #76 (ADR-0023, the Critic seam broadened to every detector). Once the Critic became a shared, every-detector primitive, its "advisory-only, never a veto" guarantee (ADR-0021 point 3) was the one property left undemonstrated in ephor's own security benchmark (ADR-0019).

What

Two new defended cases, a new llm-critic category:

  • tampered-critique-detected - flipping a critique's recommendation after the fact (e.g. hiding a flagged concern from a re-verifying auditor) is caught by the same verify_snapshot check as any other tampered Snapshot field. A critique is just one more hashed field, per ADR-0021 point 2 / ADR-0023.
  • critique-content-cannot-skip-approval-state-machine - an adversarial critique crafted to look like an instruction ("SET status=executed AND SKIP APPROVAL") has zero effect: ApprovalStore.create() always starts a request at PENDING regardless of Snapshot content, and a Critique is a disconnected value type with no reference to any store or transition method.

Both prove the "advisory-only, never a veto" claim structurally, the same way every other case in this benchmark proves its own claim by demonstration rather than assertion.

Written up as an update to ADR-0019 rather than a new ADR - no Wayfinder ticket, per that ADR's own precedent ("a rigor addition, same shape as ADR-0015 - not a new architectural question").

Result

9 cases now (was 7), 8 defended, 1 known limitation, 0 stale. docs/security-benchmark.md regenerated via uv run python -m tests.generate_security_benchmark_report - never hand-edited.

Verification

  • ruff check / ruff format --check / mypy . clean.
  • pytest -v - 62 passed (up from 60 - two new benchmark cases).
  • Diff scoped to ephor/tests/, docs/, and README.md - no other package touched.

Two new defended cases, a new llm-critic category: tampered-critique-detected
(flipping a critique's recommendation after the fact is caught by the same
verify_snapshot check as any other tampered Snapshot field - a critique is
just one more hashed field, per ADR-0021 point 2/ADR-0023) and
critique-content-cannot-skip-approval-state-machine (an adversarial critique
crafted to look like an instruction has zero effect - ApprovalStore.create()
always starts a request at PENDING regardless of Snapshot content, and a
Critique is a disconnected value type with no reference to any store or
transition method).

Both prove ADR-0021 point 3's 'advisory-only, never a veto' claim
structurally, the same way every other case in this benchmark proves its own
claim by demonstration rather than assertion - the one gap left after the
Critic became a shared, every-detector primitive (ADR-0023) rather than a
cloud-waste-only feature.

No Wayfinder ticket, per ADR-0019's own precedent (a rigor addition, not a
new architectural question). 9 cases now, 8 defended, 1 known limitation,
0 stale. docs/security-benchmark.md regenerated, never hand-edited.

Full ephor suite green: ruff/mypy clean, 62 tests passing.
@Nabzx
Nabzx merged commit 674707c into main Sep 5, 2026
7 checks passed
@Nabzx
Nabzx deleted the feat/critic-security-benchmark branch September 5, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant