Phase AFF — Adversarial-freeze honesty gate (Thinking freeze)
Status: Reviewed → pass (AFF-ADV-r5). AFF-a is spec-only and is
now ROADMAP DONE. A different-chat attack review independently re-derived
ADV4-M1–M2 closed at the claimed fail-closed layers and re-derived every
ADV1–ADV3 repair intact (not narrowed). No CLI edit, honesty schema change,
skill edit, or test file landed in this phase. No adversarial_freeze entry
was appended (AFF-a bootstrap; the kind does not exist until AFF-b), and
auto_may_start: true remains absent. No FRV freeze_review rebind was
required (no prior bound entry). NEXT is AFF-b (Auto). The
review_stamp below is the post-AFF-ADV-r5 mechanical stamp; it remains
non-authorizing.
phase: AFF
outputs:
- id: aff-adversarial-freeze-honesty-gate
path: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md
frozen: true
frozen_inputs:
- id: kit-spec
path: docs/OVERSEER-KIT-SPEC.md
- id: k5-freeze-reviewer
path: docs/archive/phases/PHASE-K5-FREEZE-REVIEWER-CONTRACT.md
- id: frv-verdict-integrity
path: docs/archive/phases/PHASE-FRV-FREEZE-REVIEW-VERDICT-INTEGRITY.md
- id: isr-independent-second-reviewer
path: docs/archive/phases/PHASE-ISR-INDEPENDENT-SECOND-REVIEWER.md
- id: p-evidence
path: docs/archive/phases/PHASE-TRACK-P-P-EVIDENCE.md
- id: p-deploy
path: docs/archive/phases/PHASE-TRACK-P-P-DEPLOY.md
- id: p-route
path: docs/archive/phases/PHASE-TRACK-P-P-ROUTE-MODEL-ROUTING.md
- id: gs-paste
path: docs/archive/phases/PHASE-GS-PASTE-READY-REGEN.md
- id: ons-operator-next
path: docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md
- id: lt-loop-tightening
path: docs/archive/phases/PHASE-LT-LOOP-TIGHTENING.md
- id: check-ok
path: docs/archive/phases/PHASE-CHECK-OK.md
- id: freeze-review-loop-skill
path: cursor/skills/freeze-review-loop/SKILL.md
- id: freeze-review-skill
path: cursor/skills/freeze-review/SKILL.md
- id: check-ok-thinking-rule
path: cursor/rules/check-ok-thinking.mdc
- id: honesty-types
path: tools/honesty/types.py
- id: honesty-status
path: tools/honesty/status.py
- id: honesty-ledger
path: tools/honesty/ledger.py
- id: honesty-validate
path: tools/honesty/validate.py
- id: honesty-config
path: adapters/config.py
- id: freeze-authorization
path: tools/freeze_authorization/resolve.py
- id: next-regen
path: tools/governance_hygiene/next_regen.py
- id: governance-hygiene-engine
path: tools/governance_hygiene/engine.py
- id: isr-surface
path: tools/independent_second_reviewer/surface.py
- id: status-exit
path: cli/commands/status.py
- id: kit-boundary
path: AGENTS.md
- id: test-tiers
path: policy/test-tiers.yaml
- id: model-labels
path: policy/model-labels.yaml
review_stamp:
gate: mechanical
reviewed_at: '2026-09-20T14:13:27Z'
mechanical_verdict: pass
produced_by: checklist_engine
provider_kind: rule_engine
reviewer_mode: agent
reviewer_model: null
reviewer_provider: local
checklist_ids:
- C1
- C2
- C3
- C4
- C5
- C6
- C7
- C8
checklist_source: builtin
findings_count: 0
override_applied: false
kit_version: 0.1.0
artifact_digest: sha256:5b8a9aa52ee25e9d4824e72b1df4154f8c184cc82bd30703a9b1bb5737eb96c3
Downstream edge: AFF-b treats this document as ground truth without re-deriving it (SPEC §6 mandatory reviewed freeze). The second chat / separate verifier performs the attack-posture review. The kit only records and optionally gates the verdict. The kit never dispatches, hosts, or calls a second model. A later host may spawn a second agent; that is out of kit scope.
Review record (§6.2): every freeze-review finding MUST cite file+line.
Uncited findings are invalid and are discarded. Fixes are Tier 1 on the feature
branch. Merge to main is Tier 3 and is never part of this loop.
| Round | Reviewer | Verdict | Resolution |
|---|---|---|---|
| AFF-r1 | Freeze-review loop (checklist + thinking, thinking-high) |
findings | R1-M1–M3 + R1-N1–N2. Fixed in-tree before CLI stamp. |
| AFF-r2 | Freeze-review loop (checklist + thinking, thinking-high) |
findings | R2-N1 digest contradiction; R2-N2 skip last-wins key; R2-N3 two match helpers named. Fixed in-tree. |
| AFF-r3 | Freeze-review loop (checklist + thinking, thinking-high) |
pass | R1–R2 confirmed RESOLVED. R3-N1 paste nonce placeholder (no IDE scrape). Mechanical stamp was then written at historical digest sha256:f60ad824…; AFF-ADV-r1 later changed artifact bytes. |
| AFF-ADV-r1 | Adversarial freeze (different chat, attack posture, Thinking) |
findings | ADV1-B1, ADV1-M1–M3, ADV1-N1–N2. Author fix required; no adversarial pass recorded; AFF-a remains WIP. |
| AFF-r4 | Freeze-review loop (checklist + thinking, thinking-high) |
pass | ADV1-B1, ADV1-M1–M3, and ADV1-N1–N2 resolved in §AFF.5.1/§AFF.5.3/§AFF.5.5–§AFF.5.6, §AFF.7.2–§AFF.7.4, §AFF.8.1–§AFF.8.3, §AFF.10, and §AFF.14–§AFF.15. Fresh adversarial review next; AFF-a remains WIP. |
| AFF-ADV-r2 | Adversarial freeze (different chat from producer nonce aff-a-author-2026-09-19, attack posture, Thinking) |
findings | R1 repairs independently confirmed, but ADV2-M1–M2 and ADV2-N1–N3 remain. No adversarial pass or ledger append; AFF-a remains WIP. |
| AFF-r5 | Freeze-review loop (checklist + thinking, thinking-high) |
pass | ADV2-M1–M2 and ADV2-N1–N3 resolved in §AFF.2, §AFF.5.2, §AFF.7.1, §AFF.8.1–§AFF.8.2, §AFF.9, §AFF.14, and §AFF.16. Fresh adversarial review next; AFF-a remains WIP. |
| AFF-ADV-r3 | Adversarial freeze (different chat from producer nonce aff-a-author-fix-r2-2026-09-20, attack posture, Thinking) |
findings | ADV2-M1–M2/N1–N3 independently confirmed closed and ADV1 repairs re-derived intact, but ADV3-M1–M3 remain. No adversarial ledger append; AFF-a remains WIP. |
| AFF-r6 | Freeze-review loop (checklist + thinking, thinking-high) |
pass | ADV3-M1–M3 resolved in §AFF.4.3, §AFF.5.5–§AFF.5.6, §AFF.7.1, §AFF.9, and §AFF.14. Fresh adversarial review next; AFF-a remains WIP. |
| AFF-ADV-r4 | Adversarial freeze (different chat from producer nonce aff-a-author-fix-r3-2026-09-20, attack posture, Thinking) |
findings | ADV4-M1–M2: hash-valid malformed AFF entries can still pass the envelope/type boundary and authorize. No adversarial ledger append; AFF-a remains WIP. |
| AFF-r7 | Freeze-review loop (checklist + thinking, thinking-high) |
pass | ADV4-M1–M2 resolved in §AFF.5, §AFF.5.2–§AFF.5.5, §AFF.8.3, §AFF.14, and §AFF.16; ADV1–ADV3 re-derived in the AFF-r7 resolution map. Fresh adversarial review next; AFF-a remains WIP. |
| AFF-ADV-r5 | Adversarial freeze (different chat from producer nonce aff-a-author-fix-r4-2026-09-20, attack posture, Thinking) |
pass | ADV4-M1–M2 independently re-derived closed at the claimed layers; ADV1–ADV3 repairs re-derived intact and not narrowed. AFF-a bootstrap: Review-record only; no adversarial_freeze append; no FRV rebind required; no auto_may_start: true. AFF-a → DONE; AFF-b Auto is queued. |
Freeze-review findings ledger (AFF-r1)
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| R1-M1 | BLOCKER | completeness | §AFF.5.5 / next_regen.py:478 (pre-fix) |
Matching AFF pass only on compact_step_id of the open Auto row misses a pass recorded during {id}-a (this repo's two-row convention). Same class as FRV-r4. Frozen: Auto-hold match is frozen_spec + artifact_digest. |
| R1-M2 | MAJOR | completeness | §AFF.7.1 (pre-fix); next_regen.py:475-476 |
Hold was specified only when FRV would emit Auto. decide_split_emission returns Thinking rows unchanged, so after author freeze-review-loop pass ok next would keep the author paste, not the adversarial paste. Frozen: second trigger on Thinking / {step}a after author-loop complete. |
| R1-M3 | MAJOR | completeness | §AFF.8.3 (pre-fix) | Mode E skip vs --producer-session unspecified; a skip body forbids producer_session_id, so a pinned producer would miss a valid skip. Frozen: skip match ignores --producer-session. |
| R1-N1 | MINOR | completeness | next_regen.py:435-457 |
discover_freeze_candidates is top-level docs/*.md plus deliverable-cited paths. Archive freezes are found only via the backtick path in the Auto row deliverable. Frozen: AFF-b deliverable must cite this artifact. |
| R1-N2 | MINOR | completeness | §AFF.8.1 (pre-fix) | --artifact-digest as the only digest source is extra ceremony when --frozen-spec is a real file. Frozen: digest source order. |
| R2-N1 | MINOR | completeness | §AFF.8.1 | Both --artifact-digest and a hashable --frozen-spec with unequal values was unspecified. Frozen: usage 1. |
| R2-N2 | MINOR | consistency | §AFF.5.3 | Skip last-wins key still named (phase_id, artifact_digest) after R1-M1. Frozen: (frozen_spec, artifact_digest). |
| R2-N3 | MINOR | completeness | §AFF.5.5 | Match helper signature was (...). Frozen: two named helpers (_pass / _skip) so skip cannot be queried as pass. |
| R3-N1 | MINOR | completeness | §AFF.7.2 | Paste said "including the author producer_session_id" without saying next_regen must not scrape IDE ids. Frozen: placeholder <AUTHOR_PRODUCER_SESSION_NONCE>. |
Citation discipline: every review finding in this artifact must include
path:line so the operator can verify — never trust uncited review output
(§6.2 / K5).
§AFF.0 — Simple summary
After a Thinking freeze, the same chat that wrote the spec can run
/freeze-review-loop, get ok review --freeze to stamp pass, and treat Auto
as cleared. A second look that tries to break the spec is something the
operator invented by hand. Independent freeze review lives in handover folklore.
Independent-second-reviewer only runs after Auto claims DONE. Complex security
freezes (NFT transfer, KYC) needed extra attack-posture passes the operator
ran outside the kit. Those extra passes found real holes.
Adversarial freeze makes that extra pass a kit honesty gate. After the
author loop stamps a freeze, ok next prints an attack-posture Thinking
paste for a different chat (prefer a different model) until that side-check
records a real pass — or, if the repo chose suggest, the operator records
skip once. The kit still does not call a model and still holds no key.
Technical summary: add honesty.adversarial_freeze: off|suggest|require
(derived default suggest when freeze_contract.human_escalation includes
security; require is operator-opt-in). Add ledger kind
adversarial_freeze (pass/findings/blocked/skip). Author
/freeze-review-loop MUST NOT write auto_may_start: true and MUST NOT treat
mechanical stamp as Auto-cleared. After FRV would emit Auto, ok next emits
an adversarial Thinking paste until a digest-bound pass exists, or a skip
exists under suggest. Honesty-status Mode E; exit 40; active-slice
status/governance-sync surface; portable paste doc + twin skill. Four review
kinds stay distinct. No model dispatch. No AFF-b code in this Thinking phase.
§AFF.1 — Verified problem (do not redesign)
| Fact | Evidence |
|---|---|
| Author freeze-review-loop treats CLI stamp as success and exits | cursor/skills/freeze-review-loop/SKILL.md:60-62 — on pass, run ok review --freeze, stamp, "EXIT success". No adversarial paste. No auto_may_start prohibition. No ledger append. |
| Mechanical CLI stamp cannot authorize Auto (FRV) | SPEC §6.2 FRV amendment; tools/freeze_reviewer/ writes gate: mechanical |
Same-session freeze_review ledger can authorize Auto |
tools/honesty/validate.py:402-408 — producer_session_id is optional on freeze_review. tools/honesty/validate.py:187-194 — session inequality is skipped when that field is absent. Author can append freeze_review pass in the same chat. |
| FRV deliberately did not import session independence for freeze | docs/archive/phases/PHASE-FRV-FREEZE-REVIEW-VERDICT-INTEGRITY.md — "ledger record required, session independence not imported" |
| ISR rejected applying ISR to Thinking freeze-review DONE | docs/archive/phases/PHASE-ISR-INDEPENDENT-SECOND-REVIEWER.md:182 — ISR = Auto slices only |
| ISR is post-Auto ROADMAP DONE | cursor/skills/independent-second-reviewer/SKILL.md:1-6; docs/INDEPENDENT-SECOND-REVIEWER.md:11-14 |
| Independent freeze review is folklore, not a kit gate | docs/archive/thinking/OVERSEER-KIT-MASTER-THINKING-PROMPT.md:5 — "Remaining: independent freeze review … before K9b Auto". cursor/skills/freeze-review/SKILL.md:48-51 — multi-round loop is optional; no second-chat gate |
ok next emits Auto when FRV state is substantive |
tools/governance_hygiene/next_regen.py:491-493 (plain Auto); :510-511 (Thinking → Auto → {step}b) |
auto_may_start: true does not grant Auto |
tools/freeze_authorization/resolve.py:142-143; FRV §FRV.8.1 — only false blocks; true has no effect. Kit never writes the key (FRV §FRV.8.1 / docs/CHECK-OK.md:27-28) |
Check-OK thinking rule starts Auto on freeze pass |
cursor/rules/check-ok-thinking.mdc:21 — "Do not start Auto until verdict is pass". No adversarial hold |
Kit dogfood already escalates security |
.overseer/config.yaml:33-37 — human_escalation includes security |
No adversarial_freeze honesty key exists |
adapters/config.py:34-47 HONESTY_KEYS; .overseer/config.yaml:53-57 honesty block |
| Honesty-status modes stop at D | tools/honesty/status.py:146-175 _resolve_mode — A/B/C/D only |
Used additive honesty/CLI exits include 33–39 |
P-evidence 33, P-deploy 34, workspace 35, PLS 36, ONS 37, ISR 38, FRV stamp 39 |
| Kit is rule-holder, never model executor | P-route; AGENTS.md; SPEC §6 |
| Operator-observed extra attack passes found real holes | Operator report: NFT transfer / KYC freezes needed hand-invented adversarial rounds (K1–K5, R2-A1–A5, R3-I1). Those rounds are not a kit gate today. This freeze does not import consumer product code |
§AFF.2 — Scope
In scope (AFF-a freezes; AFF-b implements):
- Four-way review vocabulary (§AFF.3).
- Config
honesty.adversarial_freeze+ derived default (§AFF.4). - Ledger kind
adversarial_freeze+ skip rules (§AFF.5). - Author freeze-review-loop MUST NOT set
auto_may_start: true(§AFF.6). ok next/next_regenadversarial Thinking paste until pass or skip (§AFF.7).- Honesty-status Mode E (§AFF.8).
- Active-slice status / governance-sync surface (§AFF.9).
- Portable CLI + docs + twin skill + freeze-review / check-ok-thinking amendments (§AFF.10).
- Exit code
40and reuse of existing codes (§AFF.11). - Boundary + rejection table — governance, not runtime (§AFF.12).
- SPEC §5 additive clauses (§AFF.13).
- Seven-tier matrix (§AFF.14).
- Definition of Done (§AFF.15).
Out of scope (explicit non-goals):
| Non-goal | Why rejected now |
|---|---|
| Kit dispatches / hosts / calls a second model | P-route + AGENTS.md. Runtime / operator opens the second chat. Host spawn is out of kit scope. |
| Automate Cursor "new chat" / tab open | No honest host command. Print the paste. Same family as tab-reload reject. |
require as shipped default or kit-dogfood Auto v1 |
Operator-opt-in per consumer. Derived / dogfood default is suggest. |
Replace FRV freeze_review Auto authorization |
AFF is an additional hold when enabled. FRV still required. |
Force session inequality on freeze_review |
That would redesign FRV. Independent freeze review stays distinct; AFF carries the required independence for attack posture. |
| Apply ISR to Thinking freeze-review DONE | Already rejected (ISR §ISR.2). ISR stays post-Auto implementation. |
Reuse independent_second_review or freeze_review for attack posture |
Wrong lifecycle and wrong posture. New kind. |
Reuse warn as the middle mode |
ISR warn reminds and does not hold Auto. AFF suggest holds Auto until pass or skip. Different word, different semantics. |
Write auto_may_start: false from freeze-review-loop |
FRV: kit never writes the key. Writing false would block AFF-b until flipped, and flipping invalidates the digest-bound ledger. Prohibition is "MUST NOT set true", not "MUST write false". |
Treat auto_may_start: true as granting Auto |
FRV already forbids the grant. AFF does not reopen it. |
| Make docs/reviews Check-OK files themselves require AFF | Recursion. AFF applies to roadmap-discovered freeze candidates (discover_freeze_candidates), same as FRV. |
New top-level CLI verb (ok adversarial-freeze) |
Record = ok ledger append; check = Mode E on ok honesty-status; paste = ok next. |
| Block historical DONE rows | Active slice only (LT / ISR posture). |
| MuseHub-only identity as the gate | K7: baseline on git-only. |
| Cryptographic proof of chat identity as git-only baseline | P0 remains optional / soft under git-only. Kit records the claim. |
Require different reviewer_model as a hard gate |
Paste prefers a different model. Kit cannot honestly know models. reviewer_model is required on pass/findings/blocked as a recorded label (§AFF.5.2). Inequality vs optional producer_model is preference only; equal labels still accept. Skip does not carry reviewer_model. |
| AFF-b Auto implementation in this Thinking phase | SD-3 split. |
| Consumer product Auto, bornfree-hub product code, hub Main deploy | Operator hard stop. Kit contract only. |
| Tier-3 merge, staging push, live posture flips | Never authorized here. |
| Secrets, API keys, or model endpoints in config / ledger | Names and opaque session strings only. |
§AFF.3 — Four review kinds (frozen vocabulary)
These four names are normative. Skills, paste docs, NEXT paste, and this freeze MUST use them without collapsing two kinds into one.
| Kind | When | Posture | Session | What a pass means | Kit record |
|---|---|---|---|---|---|
| freeze-review-loop | Author Thinking session, same chat that wrote the spec | Improve until clean | Same session | Mechanical CLI stamp + review-record rounds | ok review --freeze mechanical stamp. Does not authorize Auto. |
| independent freeze review | After the author claims close | Verify claimed close (did they actually freeze what they said?) | Different chat, recommended | Substantive freeze_review ledger pass bound to digest |
Existing kind freeze_review (FRV). Session inequality remains optional (FRV). Not a new kind. Not this gate. |
| adversarial freeze | After freeze-review-loop pass, before Auto | Try to kill the spec (attack, fail-open, self-auth, missing tests, injection) | Different chat, prefer different model | Digest-bound adversarial_freeze aff_verdict: pass (or skip once under suggest) |
New kind adversarial_freeze. This phase. |
| independent second reviewer (ISR) | After Auto implementation, before ROADMAP DONE | Re-check the build against the freeze | Different chat from the builder | independent_second_review pass |
Existing ISR. Unchanged. |
Ordering (frozen):
author Thinking
→ freeze-review-loop (same session) → mechanical stamp
→ independent freeze review (optional folklore unless the operator appends freeze_review)
→ adversarial freeze (this gate, when suggest|require)
→ Auto build
→ build-verification
→ ISR (when warn|require)
→ ROADMAP DONE
Independent freeze review and adversarial freeze MAY run in the same second
chat only if that chat is not the author session. They remain different
postures and different ledger kinds. A chat MUST NOT append
adversarial_freeze pass and then start Auto in that same chat — Auto is a
fresh session after the gate clears (ok next then emits Auto).
§AFF.4 — Config: honesty.adversarial_freeze (frozen)
§AFF.4.1 — Key, vocabulary, HONESTY_KEYS
Additive honesty key. Unknown-key fail-closed still applies
(adapters/config.py:773-775).
honesty:
adversarial_freeze: suggest # off | suggest | require
Closed vocabulary (frozen): off | suggest | require. Any other value →
ConfigError exit 2, message names the key.
Auto MUST add adversarial_freeze to HONESTY_KEYS in
adapters/config.py. Omitting that frozenset update would reject a valid
config as unknown honesty keys.
Do not reuse L1_EVIDENCE_MODES (off|warn|require). Frozen new
constant:
ADVERSARIAL_FREEZE_MODES = frozenset({"off", "suggest", "require"})
in adapters/config.py next to L1_EVIDENCE_MODES.
Auto MUST add adversarial_freeze: str = "suggest" to HonestyConfig.
The dataclass default matches the common derived default (SPEC
human_escalation example includes security). Parse, not the dataclass,
is authoritative for a real config file.
§AFF.4.2 — Derived default (frozen)
When the key is absent:
freeze_contract.human_escalation contains token security |
Resolved mode |
|---|---|
| yes | suggest |
| no | off |
require is never derived. Operator-opt-in: the key must be present and
equal to require.
When the key is present, use it. Derivation does not override an explicit
off even if security is in human_escalation.
Parse wiring (frozen): _parse_honesty today does not see
human_escalation (adapters/config.py:432-442 parse escalation, then
:442 _parse_k9_modules(raw, path)). Auto MUST pass the already-validated
escalation list into honesty parse. Do not re-open freeze_contract
inside honesty parse. Do not default-derive by reading a second file.
Empty human_escalation list → absent key resolves off.
freeze_contract.enabled: false does not skip derivation: the escalation
list still exists and still decides the absent-key default.
§AFF.4.3 — Mode semantics (frozen)
| Mode | ok next after FRV would emit Auto |
Status / governance-sync | Mode E miss | Skip ledger |
|---|---|---|---|---|
off |
FRV behavior unchanged | Probe skips (JSON key absent) | Match dimension always 0 if Mode E is invoked |
Skip does not authorize (and is unnecessary) |
suggest |
Hold Auto; emit adversarial Thinking paste until pass or skip | Warn surface; --exit-code stays non-failing for this gate |
0 + warning |
A latest skip authorizes for its path/digest until a later verdict supersedes it |
require |
Hold Auto; emit adversarial Thinking paste until pass. Skip does not authorize | Fail-closed: fold into existing exit 2 like ISR require |
exit 40 + token missing_adversarial_freeze |
Inert if present; does not authorize |
suggest holds Auto. That is the difference from ISR warn. Naming it
warn would teach the wrong lesson.
Honesty-module bypass (ADV3-M1; frozen): honesty.enabled: false is a
NEXT bypass for both Trigger A and Trigger B, evaluated before any
AFF probe, even when the resolved adversarial_freeze mode is an explicit
or derived suggest or require. Status and governance-sync already skip
when honesty is disabled. Helper state is off. Helper off is never a
hold and is never mapped to pending. Mode E with the module disabled
remains exit 4 (refused); that explicit query is not a NEXT bypass.
§AFF.4.4 — Kit dogfood vs shipped consumers (AFF-b writes)
| Repo | What AFF-b writes |
|---|---|
Kit .overseer/config.yaml |
Explicit adversarial_freeze: suggest (not require) |
| Consumer init template | Key absent (derived default applies) |
| This Thinking phase | No config write |
§AFF.5 — Ledger kind adversarial_freeze (frozen schema)
Additive amendment of the K9a / FRV entry-kind enum: add exactly one
new value. Every prior kind's required fields and semantics stay
byte-identical apart from the shared envelope/exact-integer hardening frozen
below. Auto must extend ENTRY_KINDS in tools/honesty/types.py
and the matching validate_append_body branches — no second ledger, no
renumbering.
adversarial_freeze
Envelope (strict K9a / P0 rules, hardened by ADV4-M1): every stored entry,
including genesis, carries v: 1 where type(v) is int (JSON/Python boolean
is rejected), and ts as a string whose strip() is non-empty. Every
non-genesis entry also carries kind, prev_hash / entry_hash (server
fills), actor_role, actor_session_id, and optional
provenance.
AFF-b MUST harden both shared boundaries rather than rely on AFF-kind schema alone:
validate_append_bodyrejects a suppliedvunlesstype(v) is intandv == 1(exit2). A client may omittsfor server fill; if supplied,tsMUST be a string whosestrip()is non-empty or append exits2. The server's_finalize_entryfillstsonly when it is omitted, before hashing.verify_chainchecks every stored entry, genesis included, before hash or provenance acceptance:type(entry.get("v")) is int, value exactly1, andtsis a string whosestrip()is non-empty. Missing/blank/non-stringts, booleanv, or otherwise invalidvare ledger breakage (exit22), even when the attacker recomputed a matchingentry_hash.
This is shared envelope validation only. verify_chain does not re-run each
kind's body schema; the AFF resolver remains the defensive kind-schema
boundary for phase_id, round, reviewer_model, role, posture, sessions,
path, digest, and verdict.
Shared exact-round repair (ADV4-M2): AFF-b MUST replace every
validate_append_body positive-integer round check with one shared exact-type
rule: type(round) is int and round >= 1. This applies to the existing
verification_evidence, independent_second_review, and freeze_review
branches as well as new adversarial_freeze pass/findings/blocked/skip
bodies. It changes no other schema or semantics; it only rejects JSON/Python
booleans that the existing isinstance(round, int) checks admit.
Genesis forbid-list: Auto MUST add the new kind-specific keys to the
genesis forbid list in validate_append_body (tools/honesty/validate.py:228-256).
§AFF.5.1 — Closed verdict vocabulary
AFF_VERDICTS = frozenset({"pass", "findings", "blocked", "skip"})
in tools/honesty/types.py next to FREEZE_VERDICTS. Any other
aff_verdict → exit 2.
findings / blocked never authorize Auto. Every completed adversarial
review appends its actual verdict; a reviewer MUST NOT omit a negative verdict
and leave an older pass live. A later pass is a new append (new round). For
one match subject, ledger file order is authoritative: the latest eligible
pass|findings|blocked|skip entry is the verdict. Therefore a later
findings or blocked entry revokes an older pass for the same subject and
digest until a still-later pass is appended.
§AFF.5.2 — Pass body (attack posture)
Role rule: actor_role MUST be verifier. Any other role → exit 23.
Independence invariant (frozen, enforced at append — unlike freeze_review):
producer_session_idis a required opaque non-empty string (author freeze-review-loop session / nonce).actor_session_idis the adversarial reviewer's session.- If
actor_session_id == producer_session_id→ exit2. The author cannot honestly append their own adversarial pass. - The kit does not invent, scrape, or infer either id.
Kind-specific required fields (pass / findings / blocked):
| Field | Type | Rule |
|---|---|---|
phase_id |
non-empty string | Opaque, required at append. Recommended value: freeze-block phase: (here AFF) so {id}-a and {id}-b share one id. Not the Auto-hold match key (§AFF.5.5). |
frozen_spec |
non-empty string | Opaque path-shaped string. Append checks non-empty string only — no must-exist (same as §PE.3 / §ISR.3). |
round |
exact integer ≥ 1 | type(round) is not int (including JSON/Python boolean) or < 1 → exit 2. |
aff_verdict |
string enum | pass | findings | blocked for this body. |
aff_posture |
string enum | Closed: attack. Any other value → exit 2. |
artifact_digest |
string | sha256: + 64 lowercase hex. Same shape as freeze_review (validate.py:387-388). |
producer_session_id |
non-empty string | Author nonce. Empty / missing / non-string → exit 2. |
reviewer_model |
non-empty string | Label, never a vendor slug. Required on pass/findings/blocked (missing, empty, or non-string → exit 2). This is the only optionality rule: the field is recorded, not optional. Equal to an optional producer_model is allowed. Inequality is preference, never a gate. Skip does not carry this field. |
Optional fields (pass / findings / blocked):
| Field | Type | Rule |
|---|---|---|
producer_model |
string | Opaque label. When both producer_model and reviewer_model are present and equal → still accept. Paste prefers inequality; kit does not gate it. |
producer_agent_id / verifier_agent_id |
string | Same inequality rule as ISR when both present. One present, one absent → allowed. |
bound_freeze_review_hash |
string | Optional entry_hash of a freeze_review line. Auto v1 does not require or resolve this at match time (FRV remains a separate gate). If present: non-empty string; no live ledger lookup at append. |
notes |
string | Advisory; never a substitute for independence or for attack posture. |
side_check_path |
string | Optional path-shaped string for a Check-OK file under docs/reviews/. Opaque at append (no must-exist). Never authorizes by itself. |
provenance |
object | Optional; identical to P0 rules. |
§AFF.5.3 — Skip body (operator skip ledger)
Used only to record "operator skipped adversarial freeze once" under
suggest.
Role rule: actor_role MUST be owner. Any other role → exit 23.
Required fields:
| Field | Type | Rule |
|---|---|---|
phase_id |
non-empty string | Same as pass. |
frozen_spec |
non-empty string | Same as pass. |
round |
exact integer ≥ 1 | Same exact-type rule as pass; boolean is rejected. |
aff_verdict |
string | Must be skip. |
artifact_digest |
string | Same digest shape as pass. Skip of digest D does not cover digest D′. |
Forbidden on skip: aff_posture, producer_session_id (skip is not a
second-session review). If either is present → exit 2.
Optional: notes, provenance.
Skip is structurally valid at append regardless of config (validate stays
config-free, same as ISR). Authorization honors skip only when resolved
mode is suggest (§AFF.4.3). Under require, a skip line is inert. Under
off, skip is inert.
Last-verdict-wins: skip participates in the one §AFF.5.5 resolver with
pass, findings, and blocked; it is not resolved in a skip-only scan. Two
skips for the same (frozen_spec, artifact_digest) are both structurally
valid and the later eligible entry wins. Process says "once"; the kit does
not refuse a second skip append. phase_id is stored but is not the
Auto-hold authorization key.
§AFF.5.4 — Example pass (normative shape, illustrative ids)
{
"v": 1,
"kind": "adversarial_freeze",
"actor_role": "verifier",
"actor_session_id": "adversarial-chat-2",
"phase_id": "AFF",
"frozen_spec": "docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md",
"round": 1,
"aff_verdict": "pass",
"aff_posture": "attack",
"artifact_digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"producer_session_id": "aff-a-author-session",
"reviewer_model": "thinking-high"
}
§AFF.5.5 — Match helper (frozen)
New functions in tools/honesty/validate.py:
find_latest_adversarial_freeze_verdict(
entries, *, frozen_spec: str, artifact_digest: str,
phase_id: str | None = None, producer_session: str | None = None,
) -> dict | None
find_matching_adversarial_freeze_pass(
entries, *, frozen_spec: str, artifact_digest: str,
phase_id: str | None = None, producer_session: str | None = None,
) -> dict | None
find_matching_adversarial_freeze_skip(
entries, *, frozen_spec: str, artifact_digest: str,
phase_id: str | None = None,
) -> dict | None
find_latest_adversarial_freeze_verdict is the only scanner. The pass and
skip helpers are narrow wrappers over its result: the pass wrapper returns
the winner only when aff_verdict == pass; the skip wrapper returns it only
when aff_verdict == skip; otherwise each returns None. Neither wrapper may
filter ledger entries by verdict before the latest entry is selected. The
authorization helper in §AFF.5.6 MUST call the latest-verdict resolver once,
not call the pass and skip wrappers independently.
Auto-hold / status omit phase_id and producer_session. Mode E may pass
them as pins (phase_id on every verdict; producer_session on
pass|findings|blocked only). Skip ignores the producer pin because its body
forbids producer_session_id.
Auto-hold / status probe match (frozen): frozen_spec + artifact_digest
of the freeze candidate file. phase_id is not part of this match.
That is the FRV-r4 repair for this gate: a pass recorded during {id}-a
still clears {id}-b Auto if the file path and digest still match.
A ledger entry is eligible for Auto-hold subject
(frozen_spec, artifact_digest) when every applicable rule below holds.
The resolver scans ledger file order and returns the last eligible entry
across all four verdicts. An ineligible line is skipped; it cannot win
and cannot authorize, including when verify_chain returns 0 (ADV3-M3).
kind == adversarial_freeze- for
pass|findings|blocked:actor_role == verifier aff_verdictis one ofpass|findings|blocked|skip- for
pass|findings|blocked:aff_posture == attack frozen_specequals the candidate's repo-relative path (POSIX)artifact_digestequals the candidate's current digest (required)- for
pass|findings|blocked: both session ids are non-empty strings andactor_session_id != producer_session_id - for
skip:actor_role == owner, and bothaff_postureandproducer_session_idare absent phase_idis a non-empty string (isinstance(str)andstr.strip()non-empty). Applies to all four verdicts.roundis an exact integer ≥ 1 (type(round) is intand>= 1; the same rule asvalidate_append_body). JSON/Python boolean is ineligible. Applies to all four verdicts.- for
pass|findings|blocked:reviewer_modelis a non-empty string (same rule asphase_id). Skip does not carry this field.
Append validation remains the primary schema boundary; these checks are
defensive so a malformed historical line cannot authorize. verify_chain
confirms the strict common envelope, hashes, and provenance but does not
re-run kind schema validation; eligibility rules 9–11 are the fail-closed
AFF schema defense.
A latest winner authorizes as follows:
| Latest winner | suggest |
require |
off |
|---|---|---|---|
pass |
authorize | authorize | gate not evaluated |
skip |
authorize | pending | gate not evaluated |
findings / blocked |
pending; older pass revoked | pending; older pass revoked | gate not evaluated |
| none | pending | pending | gate not evaluated |
Mode E match adds optional pins before latest selection: if the caller
supplies phase_id, it must equal the entry's phase_id; if the caller
supplies producer_session, rule 12 applies to pass|findings|blocked while
skip ignores producer_session (R1-M3).
Mode E extra pin for pass|findings|blocked when producer_session is
supplied:
producer_session_idequals the caller value andactor_session_iddiffers from that value.
Does not open a network connection, call a model, or read IDE session ids.
§AFF.5.6 — Shared authorization helper (frozen)
New module tools/adversarial_freeze/ (ISR-shaped; not folded into
tools/freeze_authorization/resolve.py).
adversarial_authorization_state(repo_root, artifact_path, *, config)
returns a frozen dataclass.
It hashes artifact_path with the same artifact_digest() FRV uses
(tools/freeze_reviewer/artifact.py:150-154) and matches on that digest plus
the repo-relative POSIX path. It does not take phase_id for the Auto-hold
match (R1-M1). Mode E may call the validate helper with extra pins.
state |
Meaning |
|---|---|
off |
Mode off or honesty disabled — not a hold. Callers MUST treat this as a bypass, never as Trigger A's "otherwise hold" fallthrough and never as Trigger B pending. |
pass |
Latest eligible verdict is pass |
skipped |
Latest eligible verdict is skip and mode is suggest |
pending |
Mode suggest or require, and the latest eligible verdict is findings, blocked, a non-authorizing skip, or none. Never assigned for honesty disabled or mode off. |
absent |
Fail-closed read error (broken chain, unreadable artifact) — treat as hold when mode is suggest or require |
Do not change AuthState in tools/freeze_authorization/resolve.py.
FRV substantive stays "freeze_review matched". AFF is a second question.
The helper verifies the full ledger chain/provenance before resolving, calls
find_latest_adversarial_freeze_verdict exactly once, and maps that winner by
the table above. It never separately asks "is there any pass?" and "is there
any skip?" because that would resurrect an older favorable entry after a
later negative verdict.
Candidate discovery reuses discover_freeze_candidates
(next_regen.py:415-459) — top-level docs/PHASE-*.md and
backtick-cited docs/…/*.md paths in the row deliverable. Archive freezes
(this artifact lives under docs/archive/phases/) are reached only via
the deliverable citation (R1-N1). AFF-b's roadmap deliverable MUST cite
this path in backticks.
Named helpers in tools/adversarial_freeze/ (frozen; shared by NEXT and
status so the two surfaces cannot drift):
aff_hold_bypassed(config) -> bool
True when honesty.enabled is false OR resolved adversarial_freeze is off.
frv_authorizing_freeze_paths(repo_root, candidates, *, phase_id, config)
-> list[Path]
Discover-order paths whose freeze_authorization_state is substantive.
This is Trigger A's candidate subset and the status/governance-sync
probe subset (ADV3-M2).
aggregate_adversarial_authorization_states(states) -> str
Worst-state aggregate over pass|skipped|pending|absent. Frozen rank
(worst first): absent > pending > skipped > pass. Empty input is not
called (probe skip). Helper off is dropped before aggregation; if none
remain, treat as bypass / probe skip, never pending.
§AFF.6 — Author freeze-review-loop MUST NOT set auto_may_start: true
§AFF.6.1 — Skill contract (AFF-b edits cursor/skills/ source only)
Amend cursor/skills/freeze-review-loop/SKILL.md (live .cursor/ / .claude/
copies via ok sync --yes, same as ISR-r2 / R2-N2):
- On pass (today
:60-62): write the Review-record row and finish all artifact edits before runningok review --freeze; then stamp the final bytes. Never update the Review record after stamping without immediately restamping. This is the author-loop half of §AFF.7.4. - MUST NOT write, insert, or flip
auto_may_starttotrue. - MUST NOT write
auto_may_startat all (FRV: kit never writes the key; the skill is not a back door). - MUST NOT append
adversarial_freezepassin the author session. - MUST NOT claim Auto is cleared. Replace "EXIT success" with: stop.
Print that
ok nextwill emit the adversarial paste whenhonesty.adversarial_freezeissuggestorrequire. Invent / copy aproducer_sessionnonce into the handover NEXT block. - Appending
freeze_reviewin the author session remains allowed (independent freeze review / FRV substantive record). It does not satisfy AFF.
Amend cursor/skills/freeze-review/SKILL.md with the §AFF.3 table and a
pointer to /adversarial-freeze-review.
Amend cursor/rules/check-ok-thinking.mdc:21: freeze pass is the author
loop, not Auto-cleared, when AFF is suggest or require.
§AFF.6.2 — auto_may_start semantics unchanged (FRV)
AFF does not amend FRV §FRV.8:
| Value | Effect (still) |
|---|---|
| absent | No effect |
true |
No effect (cannot grant) |
false |
blocked_by_operator — outranks freeze_review and adversarial pass |
| non-boolean | Fail-closed block |
Tests under §AFF.14 must prove the skill/docs prohibition and that
next_regen does not emit Auto from author-loop success alone when AFF is
on. They must not re-open FRV's grant-path prohibition as a redesign.
§AFF.7 — ok next emits adversarial Thinking paste (frozen)
§AFF.7.1 — When the hold applies
Apply AFF in plan_next_regen after decide_split_emission
(next_regen.py:544-557), not only inside it. Thinking-only rows return
early at next_regen.py:475-476 and would otherwise never see the gate
(R1-M2).
aff_hold_bypassed(config) → no hold, FRV/Thinking emission unchanged.
That is true for resolved mode off and for honesty.enabled: false,
even when the resolved AFF mode is an explicit or derived suggest or
require (ADV3-M1). Evaluate this bypass before Trigger A or Trigger B
probes. Operator + Auto → no hold.
Helper off is never pending. If a probe still receives off after the
bypass, Trigger A treats it as cleared and Trigger B does not rewrite the
paste.
Trigger A — FRV would emit Auto (emit_model == "Auto" or
is_step_b is True):
- If
aff_hold_bypassed(config), stop: emit Auto as FRV would. - Collect the same freeze candidates FRV used (
discover_freeze_candidates). - If there are no candidates, AFF does not hold (FRV already emits Auto
with nothing to bind —
next_regen.py:482-483). Do not invent a freeze. - Restrict to
frv_authorizing_freeze_paths(FRVstate == substantive). If that subset is empty, AFF does not hold. - For every path in that subset, run
adversarial_authorization_state(path + digest). - If every such candidate is
pass, or (modesuggestandskipped), oroff, emit Auto as FRV would. Advisoryadversarial_freeze_skipwhen at least one candidate authorized via skip. - Otherwise hold (
pendingorabsentonly):emit_model = "Thinking",is_step_b = False,reason = None(still regenerate),advisory = ADVISORY_ADVERSARIAL_FREEZE_PENDING("adversarial_freeze_pending").
Trigger B — author freeze-review-loop complete, Auto not yet the emission
(open row Model is Thinking, or Thinking → Auto emitting {step}a /
Thinking):
- If
aff_hold_bypassed(config), do not hold (keep the author freeze paste). - Collect freeze candidates for that row.
- If none, do not hold (still drafting; keep the author freeze paste).
- Author-loop complete when any candidate satisfies the Trigger-B
fresh-stamp predicate below.
absent/non_pass/blocked_by_operator→ not complete. - If complete and any completed candidate's AFF state is
pendingorabsent, hold with the same Thinking +adversarial_freeze_pendingpaste as Trigger A. - If complete and every completed candidate is
pass,skipped, oroff, do not rewrite the paste into Auto (the row is still Thinking). Leave FRV/Thinking emission. Operator marks the Thinking row DONE; the next row is Auto, which is Trigger A.
Trigger-B fresh-stamp predicate (ADV2-M1; Trigger-B only):
A candidate is author-loop complete when the matching row below is yes:
FRV state |
Additional required check | Complete? |
|---|---|---|
substantive |
None. FRV already matched freeze_review to the current digest. |
yes |
mechanical_only |
Fresh-stamp: extract_existing_stamp(parsed)["artifact_digest"] is a well-formed sha256: + 64 lowercase hex string and equals the current artifact_digest(parsed) computed by FRV tools/freeze_reviewer/artifact.py:150-154. |
yes only when the equality holds |
mechanical_only |
Stamp digest missing, not a string, malformed, or unequal to the current digest (post-stamp byte edit outside review_stamp). |
no — keep the author freeze paste |
| any other state | — | no |
Do not change AuthState or freeze_authorization_state
(tools/freeze_authorization/resolve.py). A stale mechanical stamp may
still resolve mechanical_only for FRV. That FRV result still cannot
authorize Auto (substantive remains the only Auto authorizer). Trigger B
must not treat that stale mechanical_only as author-loop complete.
Auto implements the predicate as
author_loop_complete(frv_state, *, stamp_digest, current_digest) -> bool
in tools/adversarial_freeze/ (not in tools/freeze_authorization/).
next_regen Trigger B calls that helper after freeze_authorization_state.
It never remaps FRV mechanical_only to absent and never consults the
stamp digest when deciding FRV Auto emission.
Do not reuse REASON_FREEZE_NOT_SUBSTANTIVE — that fails regen. AFF
pending must still print NEXT.
§AFF.7.2 — Paste body when advisory is adversarial_freeze_pending
render_paste_ready (next_regen.py:653-700) currently dumps the roadmap
deliverable. When decision.advisory == ADVISORY_ADVERSARIAL_FREEZE_PENDING,
Auto MUST render the frozen AFF paste instead of the Auto-deliverable list.
Frozen paste requirements (all must appear in the fence body):
Model: Thinking- Attack posture: try to kill the spec; do not rubber-stamp close
- Different chat from the author; if this is the author session, stop
- Prefer a different model than the author (preference, not a kit gate)
- Read the freeze artifact path
- Cite every finding
path:line - Follow the mandatory Review-record/restamp/FRV-rebind/AFF-append transaction in §AFF.7.4; no ledger verdict is written before the artifact is final
- On pass: append
adversarial_freezewith the §AFF.5.2 fields only as the final transaction step, includingaff_posture: attackandproducer_session_id: <AUTHOR_PRODUCER_SESSION_NONCE>(next_regenv1 emits that placeholder; it does not scrape IDE session ids — same rule as ISR) - On findings/blocked: append that actual verdict as the final transaction
step; never append
pass, and never omit the negative append merely to preserve an older pass for the same subject/digest - Under
suggest, operator skip is a separate owner append (aff_verdict: skip) — the reviewer chat does not skip for the operator - Kit performs no model call and holds no key
- No merge to
main
render_next_session heading stays the open row's title. **Model:** Thinking. THE ONE NEXT STEP text MUST say adversarial freeze, not Auto
build.
ok next stdout layout (ONS/NXP twelve-step provenance) is unchanged. Only
the fence body and Model label change.
§AFF.7.3 — Side-check (what "exists with substantive pass" means)
Authoritative side-check = matching adversarial_freeze ledger pass
(§AFF.5.5), or matching skip under suggest.
A docs/reviews/<date>-<phase_id>-adversarial-freeze.md Check-OK file is
optional evidence (side_check_path). It does not authorize Auto.
It does not itself require AFF (no recursion). Mechanical stamp on that
file does not authorize anything.
The freeze artifact's Review-record table MUST gain an adversarial round row before any digest-bound ledger append. That row is review history, not the gate; its bytes do participate in the artifact digest.
§AFF.7.4 — Review-record / restamp / rebind / append transaction
This is a narrow AFF supersession of FRV §FRV.9.3 steps 2–4 whenever the Review-record row is being added: the row must precede the stamp whose digest the ledger records.
For every completed adversarial round after AFF-b exists, the reviewer MUST
perform this exact order. It applies to pass, findings, and blocked:
- Finish the review and decide the verdict without appending an AFF ledger entry.
- Write the adversarial round, verdict, and cited finding/resolution summary into the freeze artifact's Review-record table. Complete every other edit to that artifact now.
- Run
ok review --freeze <artifact>and require mechanical pass. Recompute with FRVartifact_digest()and require the stamp'sartifact_digestto equal the current valueD. Becausereview_stampis excluded from the canonical bytes, this restamp MUST leaveDunchanged. - If Auto requires FRV authorization, append a new
freeze_reviewpass for the same repo-relativefrozen_specandartifact_digest: D. This step is mandatory when a previousfreeze_reviewpass was bound to the pre-row digest; the old entry is historical and cannot be reused. Itsphase_idremains FRV's compact id for the Auto row being authorized. Verify the ledger after the append before continuing. - Append exactly one
adversarial_freezeentry carrying the round's actualpass|findings|blockedverdict, the samefrozen_spec, andartifact_digest: D. This is the final binding operation. Verify the ledger again. - Do not edit the freeze artifact after step 5. Any later byte change outside
review_stampinvalidates both bindings and requires restarting at step 2: update the Review record, restamp, rebind FRV when required, then append a fresh AFF verdict for the new digest.
ok next, active-slice status, and Mode E may authorize only when their
independently computed current path/digest select the latest AFF verdict and,
where Auto requires it, FRV independently selects freeze_review for that
same current digest. They MUST NOT treat the AFF append as repairing a stale
FRV binding or vice versa.
AFF-a bootstrap exception: AFF-a is freezing the kind before AFF-b creates
it. Its fresh adversarial reviewer records the Review-record row before the
final restamp and may append/rebind existing freeze_review, but MUST NOT
append the nonexistent adversarial_freeze kind. The different-chat Review
record is sufficient only to close the AFF-a Thinking freeze and queue AFF-b;
it is not a runtime AFF authorization and does not waive FRV for AFF-b.
§AFF.8 — Honesty-status Mode E (frozen)
§AFF.8.1 — Flag
Additive flag on ok honesty-status:
--adversarial-freeze PHASE_ID
Shared optional --producer-session / --frozen-spec (same as Mode D).
Optional Mode-E-only metadata --artifact-digest DIGEST. It never selects a
mode by itself and is invalid unless both --adversarial-freeze and
--frozen-spec are present. Digest/path resolution (R1-N2, R2-N1, ADV1-N1):
- If
--frozen-specis supplied, confine it under the repo and normalize it to the repo-relative POSIX path used by the ledger. Path escape or a confine/statI/O error is refusal4; no ledger match runs. A successfulstatof an existing non-regular path is not an I/O error. - If
--artifact-digestis supplied, it must matchsha256:+ 64 lowercase hex or the invocation is usage1. It is the effective digest. - When both flags are supplied and the confined path is an existing readable
regular file, hash it with FRV
artifact_digest(); unequal flag/file digests are usage1(caller contradiction). When the confined path is absent, the explicit digest remains usable for this explicit ledger query. - When both flags are supplied and the confined path exists and is not a
readable regular file (directory, fifo, socket, device, or other
non-regular): do not hash it, do not emit usage
1, and do not emit refusal4unless confine/stat itself failed. The confined repo-relative POSIX path plus the valid explicit digest remain usable for this explicit ledger query — the same query class as an absent path (ADV2-N1). Classify with a successfulstatafter confine; do not open the path as a freeze artifact. - Without
--artifact-digest, an existing readable--frozen-specfile is hashed with FRVartifact_digest()and supplies the effective digest. - Without an effective path or digest, Mode E is a fail-closed miss. A
missing/non-file
--frozen-specwithout an explicit digest is also a miss (this includes an existing non-regular path without--artifact-digest). There is no "last pass for phase regardless of digest" shortcut.
Complete flag matrix:
| Invocation shape | Result |
|---|---|
No --adversarial-freeze, no --artifact-digest |
Pre-AFF Mode A/B/C/D resolution, byte-identical |
--artifact-digest without --adversarial-freeze (alone or with A/B/C/D) |
usage 1; never silently ignored |
--adversarial-freeze plus any Mode A core or B/C/D selector |
usage 1 |
--adversarial-freeze alone, or plus only --producer-session |
Mode E; forced miss because effective path/digest are null |
--adversarial-freeze --frozen-spec PATH |
Mode E; hash readable file, otherwise fail-closed miss (path escape/I/O → 4) |
--adversarial-freeze --frozen-spec PATH --artifact-digest D |
Mode E when D is valid and agrees with a readable existing file; absent file may be queried by normalized path + explicit D |
--adversarial-freeze --frozen-spec PATH --artifact-digest D where PATH exists and is not a readable regular file, D valid |
Mode E; explicit ledger query by confined POSIX path + D; no hash; not usage 1; not refusal 4 |
--adversarial-freeze --artifact-digest D without --frozen-spec |
usage 1 |
| Any supplied malformed digest, or flag/file digest mismatch | usage 1 |
§AFF.8.2 — Mode-resolution algorithm (amends §ISR.5.2)
Replace the Mode B/C/D mutex with B/C/D/E. --producer-session is shared
metadata for Mode A (optional), Mode D (optional), and Mode E (optional).
It does not by itself imply Mode A when Mode D or E is selected.
Normative pseudocode:
mode_a_core = hook or artifact
mode_a_full = hook and artifact
mode_b_full = verification_evidence is set
mode_c_full = deploy_health is set
mode_d_full = independent_second_review is set
mode_e_full = adversarial_freeze is set
frozen = frozen_spec is set
producer = producer_session is set
digest = artifact_digest is set
mode_a_partial = mode_a_core or (producer and not mode_d_full and not mode_e_full)
if digest and not mode_e_full:
return None
if mode_e_full and digest and not frozen:
return None
if (mode_b_full + mode_c_full + mode_d_full + mode_e_full) > 1:
return None
if mode_a_partial and (mode_b_full or mode_c_full or mode_d_full or mode_e_full or frozen):
return None
if frozen and not mode_b_full and not mode_c_full and not mode_d_full and not mode_e_full:
return None
if not mode_a_full and not mode_b_full and not mode_c_full and not mode_d_full and not mode_e_full:
return None
if mode_e_full:
return "mode_e"
if mode_d_full:
return "mode_d"
if mode_c_full:
return "mode_c"
if mode_b_full:
return "mode_b"
return "mode_a"
Invariants (frozen):
--adversarial-freeze PHASE --frozen-spec PATH→mode_e.--adversarial-freeze PHASE --producer-session ID→mode_e.--adversarial-freeze PHASE --producer-session ID --frozen-spec PATH→mode_e.--adversarial-freeze PHASEalone →mode_e.--adversarial-freeze PHASE --artifact-digest Dwithout--frozen-spec→ usage1.--artifact-digest Dwithout--adversarial-freeze→ usage1, with any other flags or alone.--adversarial-freeze PHASE --independent-second-review PHASE→ usage1.--hook H --artifact P --adversarial-freeze PHASE→ usage1.- When both AFF flags are absent, Mode A/B/C/D behavior is byte-identical
to pre-AFF for every invocation that passes neither
--adversarial-freezenor--artifact-digest. - Pre-ISR invariants 5–8 remain true when both AFF flags are absent.
--adversarial-freeze PHASE --frozen-spec PATH --artifact-digest Dwhen PATH exists and is not a readable regular file →mode_e(not usage), providedDis well-formed. Effective path is the confined POSIX path; effective digest isD.
HonestyStatusOptions gains adversarial_freeze: str | None = None and
artifact_digest: str | None = None.
§AFF.8.3 — JSON + error token
HonestyErrorToken gains missing_adversarial_freeze.
HonestyStatusJson gains optional adversarial_freeze: dict | None. A valid
Mode E invocation always emits the block below; a valid Mode A/B/C/D
invocation omits it. In valid Mode E, the other optional mode blocks
verification_evidence, deploy_health, and independent_second_review are
all absent (not JSON null). Mode-A top-level fields remain present and are
fixed as shown:
{
"ok": true,
"exit_code": 0,
"command": "honesty-status",
"hook": null,
"artifact": null,
"artifact_sha256": null,
"producer_session": null,
"matched_verdict_hash": null,
"error": null,
"adversarial_freeze": {
"phase_id": "AFF",
"frozen_spec": "docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md",
"artifact_digest": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"producer_session": null,
"mode": "suggest",
"matched_via": "pass",
"matched_entry_hash": "example-entry-hash"
}
}
Exact nested types/nullability:
| Key | Type | Value |
|---|---|---|
phase_id |
string | Exact --adversarial-freeze value |
frozen_spec |
string or null | Effective confined repo-relative POSIX path, else null |
artifact_digest |
string or null | Effective validated/hashed digest, else null |
producer_session |
string or null | Exact optional pin |
mode |
off\|suggest\|require |
Resolved config mode |
matched_via |
pass\|skip or null |
Authorizing latest verdict only |
matched_entry_hash |
string or null | entry_hash of that authorizing verdict only |
The top-level producer_session equals the same pin; it is null in the
example only because the flag is absent. matched_verdict_hash remains null
because that field belongs to Mode A. A miss, off, refusal, chain failure,
or usage result has matched_via: null and matched_entry_hash: null.
Mode E applies honesty.adversarial_freeze per §AFF.4.3:
| Outcome | ok |
exit | error |
warning |
|---|---|---|---|---|
off |
true | 0 |
null | none; no ledger match is attempted |
suggest, latest winner is pass/skip |
true | 0 |
null | none |
suggest, miss/findings/blocked |
true | 0 |
null | warning: no authorizing adversarial_freeze entry |
require, latest winner is pass |
true | 0 |
null | none |
require, miss/skip/findings/blocked |
false | 40 |
missing_adversarial_freeze |
none beyond existing role warning |
| module disabled / path or ledger refusal | false | 4 |
refused |
existing refusal text |
Skip under suggest counts as matched_via: skip; under require it is a
miss. Skip ignores --producer-session (R1-M3). A later findings or
blocked winner produces a miss even when an older matching pass exists.
Integrity-before-match (ADV1-M2, ADV4-M1): for suggest and require, after the
ledger is parsed and before find_latest_adversarial_freeze_verdict runs,
Mode E MUST call verify_chain(entries, regime=config.vcs.regime, require_agent_signature=config.honesty.require_agent_signature). It verifies
the entire non-empty ledger, including the strict v/ts envelope and
provenance, not merely matching lines.
The resolver is never called on nonzero verification:
verify_chain result |
Mode E result |
|---|---|
22 |
exit 22, ok: false, error: ledger_broken |
2, 25, or 26 |
preserve that exit, ok: false, error: refused |
suggest does not soften integrity failures to exit 0; a stored pass in a
tampered chain can never match. Missing/empty ledger is an ordinary miss, not
a chain failure. off performs no ledger match and therefore no ledger read.
When --adversarial-freeze is present but mode resolution returns usage 1,
the response is not Mode E: ok: false, error: usage; its diagnostic
adversarial_freeze block uses the supplied phase_id and producer pin,
resolved config mode, null effective path/digest, and null match fields.
Other explicitly selected B/C/D diagnostic blocks may also be present. A
configuration failure before mode resolution keeps the pre-AFF config-error
JSON shape and omits every optional mode block.
§AFF.9 — Active-slice status / governance-sync surface (frozen)
ISR-shaped (tools/independent_second_reviewer/surface.py). New
tools/adversarial_freeze/surface.py.
When honesty.enabled is true and resolved mode is suggest or
require and the active slice is an Auto-authorizable row (plain Auto
or {step}b after FRV would emit Auto):
- Discover the same freeze candidates Trigger A uses
(
discover_freeze_candidates). Empty discovery → probe skip (JSON key absent); AFF does not apply (Trigger A no-candidate path). - Restrict the probe to
frv_authorizing_freeze_paths— the identical FRV-authorizing (substantive) subset Trigger A probes (ADV3-M2). Non-substantive siblings (mechanical_only,absent,non_pass,blocked_by_operator) are not probed and cannot create a status-only hold. Empty authorizing subset → probe skip. - For each path in that subset, run
adversarial_authorization_state(path + digest; notcompact_step_idas the ledger match key). - Aggregate those helper states with
aggregate_adversarial_authorization_states. Auto v1 JSON stays a single scalarstate; do not emit a per-candidate payload. Mixed outcomes follow the frozen rankabsent > pending > skipped > pass: pass+pending →pending(NEXT holds); pass+absent →absent(NEXT holds); pass+skipped →skipped(NEXT Auto + skip advisory); all pass →pass(NEXT Auto). - Helper
absent(broken chain, unreadable artifact) is a probe result, not a probe skip.ok nextalready holds onabsent; status and governance-sync MUST surface that hold (ADV2-N3). require+ aggregated pending/absent →okfalse;ok status --exit-codefolds into existing2(not40). Tokenmissing_adversarial_freeze.suggest+ aggregated pending → warn line; JSON key present; exit still0for this gate.suggest+ aggregated absent → warn line that names the read-error hold; JSON key present (never omitted); exit still0for this gate.offor probe skip (honesty disabled, modeoff, the slice is not Auto-authorizable, no freeze candidates, or empty FRV-authorizing subset) → JSON key absent. Helperabsentis not a skip. Helperoffis not a skip-vs-hold conflict: it is a skip.
ok status additive JSON key: adversarial_freeze_gate (optional; absent
when the probe skips). When the probe runs, the object is:
{
"ok": true,
"mode": "suggest",
"state": "absent",
"matched": false
}
Exact nested fields:
| Key | Type | Value |
|---|---|---|
ok |
bool | false only for require + pending/absent. true for suggest + pending and suggest + absent. |
mode |
suggest\|require |
Resolved config mode |
state |
pass\|skipped\|pending\|absent |
Aggregated helper state of the FRV-authorizing subset. Distinguishes pending (no authorizing verdict) from absent (read-error hold). |
matched |
bool | true only when state is pass or skipped |
token |
string, omitted if null | missing_adversarial_freeze on require + pending/absent only |
Exact warn / footer strings (human line; also the governance-sync footer):
| Outcome | Line |
|---|---|
suggest + pending |
warning: no authorizing adversarial_freeze entry for active Auto slice |
suggest + absent |
warning: adversarial_freeze unreadable (broken ledger or artifact) for active Auto slice |
require + pending/absent |
existing fail-closed message; token missing_adversarial_freeze; no additional suggest-style warning |
Governance-sync footer: same probe, ISR-shaped engine-footer path
(tools/governance_hygiene/engine.py after the ISR footer, not a new
ReadFailure in reads.py — ISR-r2 / R2-M1 lesson). The footer MUST
print the suggest + absent line when the aggregated state is
absent; it MUST NOT look like a skipped probe. Mixed candidate sets MUST
agree with ok next on hold vs Auto (same subset, same aggregate).
--exit-code precedence unchanged: 2 > 6 > 35 > 3 > 0. AFF require miss
is a 2. 40 is confined to honesty-status Mode E.
Optional-feature tips: when honesty is on and adversarial_freeze resolves
off, one tip naming the key and the paste doc (ISR §ISR.7.5 shape).
§AFF.10 — Portable CLI + docs + twin skill (AFF-b)
Primary portable surface: docs/ADVERSARIAL-FREEZE-REVIEW.md (ISR twin of
docs/INDEPENDENT-SECOND-REVIEWER.md).
Twin skill (edit cursor/skills/ source only; ok sync writes both
.cursor/skills/ and .claude/skills/):
cursor/skills/adversarial-freeze-review/SKILL.md
Invoke: /adversarial-freeze-review. Extending /freeze-review with a
new skill is the frozen choice (keep /freeze-review as the author/single
pass path; do not overload it with attack posture).
Skill process (frozen):
- Confirm this session is not the author freeze-review-loop session. If it is, stop. Do not append pass. Do not start Auto.
- Attack posture: try to kill the spec. Re-read the freeze + frozen_inputs. Do not trust the author Review-record.
- Cite every finding
path:line. - For every completed verdict, execute §AFF.7.4 in exact order: write the
Review-record row; complete artifact edits; restamp and establish final
digest
D; rebind required FRVfreeze_reviewtoD; then append the actual AFF verdict againstDas the final binding operation. - On pass: append
adversarial_freezewithaff_verdict: pass,aff_posture: attack, this session asactor_session_id, and the author nonce asproducer_session_id. On findings/blocked: append that negative verdict, never pass; the latest-verdict rule revokes any older pass for the same subject/digest. - Any later freeze-artifact edit restarts the full §AFF.7.4 sequence. Never claim that an AFF append repaired a stale FRV binding.
- Never merge to
main. Never call a model via the kit CLI.
Also amend:
cursor/skills/freeze-review-loop/SKILL.md(§AFF.6.1)cursor/skills/freeze-review/SKILL.md(§AFF.3 table)cursor/rules/check-ok-thinking.mdcdocs/CHECK-OK.md(one sentence: author freeze pass ≠ Auto when AFF is on)AGENTS.md(ISR-shaped short section)docs/consumers/scooling/OVERSEER-SETUP.mddocs/consumers/knowtation/OVERSEER-SETUP.md
No live consumer ok init. No bornfree-hub product edit.
Footprint: new skill files under cursor/skills/ are picked up by the
existing resolve_footprint rglob (cli/footprint.py:135-155). No
footprint-resolver redesign.
§AFF.11 — Exit codes (frozen)
Additive code; non-overlapping with existing
1, 2, 4, 5, 7, 8, 10–11, 20–26, 30–39:
| Code | Meaning | Where |
|---|---|---|
40 |
Adversarial freeze required but the latest eligible verdict is not pass (or none exists) | honesty-status Mode E when adversarial_freeze: require; JSON error = missing_adversarial_freeze |
Constant name (frozen): EXIT_MISSING_ADVERSARIAL_FREEZE = 40 in
tools/honesty/status.py. CLI and tests import that name. Do not reuse
38 / 39 / 33.
Reused (no renumbering):
| Code | Reuse |
|---|---|
1 |
Usage — Mode E combined with A/B/C/D or other §AFF.8.2 None |
2 |
Malformed schema; and ok status --exit-code / governance-sync when the active-slice require probe misses |
4 |
Honesty module disabled / config refuse |
22 |
Mode E ledger chain broken; JSON error = ledger_broken |
23 |
Role violation (pass body actor_role ≠ verifier; skip body ≠ owner) |
25 / 26 |
Mode E provenance failure / required signature absent (P0; unchanged) |
39 |
FRV stamp escalation — unchanged, not an AFF code |
40 is confined to honesty-status Mode E. It does not change
status --exit-code precedence (2 > 6 > 35 > 3 > 0).
§AFF.12 — Boundary, capability, rejection (governance, not runtime)
The single most important frozen rule: the kit records and optionally gates the adversarial-review claim. It never runs another model, never opens a second chat, and never treats host UI as a control surface. A host may later spawn a second agent; that is not a kit feature and not an AFF-b deliverable.
| Concern | Overseer Kit | Operator / host runtime |
|---|---|---|
Append adversarial_freeze |
Yes (validate + chain) | Supplies JSON body + session ids |
| Gate Mode E / status / next_regen | Yes (off/suggest/require) |
Decides require opt-in |
| Open a second chat / composer | Never | Yes |
| Dispatch / host / call a reviewer model | Never | Yes (Cursor picker, Claude, human, CI agent) |
| Infer session ids from the IDE | Never | Supplies opaque strings |
| Spawn a second agent automatically | Never (out of kit scope) | Host may, later |
Write auto_may_start: true |
Never | Operator could hand-edit; it still does not grant Auto |
| Prove chat identity cryptographically | Optional P0 only | Muse / operator |
| Tier-3 merge authorization | Never | Operator |
| Consumer product Auto / hub Main deploy | Never | Operator |
Capability tiers:
| Capability | git-only (baseline) |
muse+git-mirror / muse-only |
|---|---|---|
| Record + gate AFF on file ledger | Full | Full (identical) |
Optional signed provenance |
Soft (unsigned OK) | Hard when require_agent_signature: true (P0) |
| Dispatch a second model | Not in the kit | Not in the kit |
| Temptation | Verdict |
|---|---|
ok shells out to a reviewer model to "be the attacker" |
Reject |
| Cursor hook that clicks "New Chat" | Reject |
| Same session appends AFF pass with a made-up second id as a kit-blessed pass | Reject as process; kit cannot stop a liar, only refuse equal ids |
Default require for all consumers |
Reject |
Waive FRV freeze_review because AFF passed |
Reject — both gates |
Waive AFF because freeze_review exists |
Reject — verify-claimed-close ≠ try-to-kill |
| Waive ISR because AFF passed | Reject — pre-Auto spec vs post-Auto build |
Treat mechanical ok review --freeze as AFF pass |
Reject |
Author freeze-review-loop sets auto_may_start: true |
Reject |
Fold AFF into freeze_authorization_state AuthState |
Reject — second question, second helper |
Apply AFF to docs/reviews/ Check-OK artifacts |
Reject — recursion |
| AFF-b Auto in this Thinking phase | Reject |
§AFF.13 — SPEC §5 additive clauses (AFF-b writes)
Amend the existing ok honesty-status row. Do not add a new command row.
Additive clause (normative text Auto must include):
AFF additive: Mode E
--adversarial-freeze PHASE_IDwith optional--producer-session/--frozen-spec; optional--artifact-digestrequires--frozen-specand is Mode-E-only. Exit40+missing_adversarial_freezewhenhonesty.adversarial_freeze: requireand the latest eligible verdict is not pass. Frozen:docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md.
ok status additive JSON key: adversarial_freeze_gate (optional; absent
when the probe skips). --exit-code folds adversarial_freeze_gate.ok
(require mode only) into the existing 2 tier.
ok next / paste-regen: when FRV would emit Auto and AFF is suggest or
require without a matching pass (or suggest skip), emit Thinking + the
adversarial paste. Frozen in this document §AFF.7.
SPEC §6.2 gains one sentence: author freeze-review-loop + mechanical stamp
do not clear Auto when AFF is on; Auto also needs digest-bound
adversarial_freeze pass (or suggest skip).
§AFF.14 — Seven-tier matrix (AFF-b)
Prefix: test_aff_. All seven tiers required before AFF-b DONE.
| Tier | Must prove |
|---|---|
| unit | adversarial_freeze in ENTRY_KINDS; validate accepts a minimal valid pass body and a minimal valid findings body and a minimal valid blocked body (each with required reviewer_model, producer_session_id, aff_posture: attack, and distinct session ids); shared append validation rejects client v: true, every integer other than exact 1, and supplied empty/non-string ts, while omitted ts is server-filled; shared verify_chain rejects stored missing/empty/non-string ts and v: true with 22; every round-bearing append kind (verification_evidence, independent_second_review, freeze_review, and every adversarial_freeze verdict) rejects round: true; missing reviewer_model on pass/findings/blocked → 2; rejects same-session ids → 2; missing producer_session_id on pass → 2; missing aff_posture on pass → 2; aff_posture ≠ attack → 2; skip with aff_posture present → 2; skip with non-owner role → 23; pass with non-verifier → 23; bad aff_verdict → 2; round < 1 and non-int round → 2; digest not sha256:+64 hex → 2; genesis forbid-list includes new keys; adversarial_freeze parse (off\|suggest\|require; unknown → config 2); absent key + security in human_escalation → suggest; absent key without security → off; explicit off wins over security; require never derived; key in HONESTY_KEYS; HonestyConfig field default suggest; HonestyErrorToken includes missing_adversarial_freeze; every _resolve_mode / --artifact-digest combination in §AFF.8.1–§AFF.8.2 including existing non-regular --frozen-spec + valid --artifact-digest → mode_e; Auto-hold match is path+digest and ignores phase_id; Mode E optional phase pin; skip match ignores producer_session; the common resolver selects the last eligible verdict before pass/skip wrappers inspect it; pass → findings, pass → blocked, and pass → skip never return the older pass; author_loop_complete is true for substantive and for mechanical_only only when stamp digest equals current digest, and false for mechanical_only with missing/unequal stamp digest; aff_hold_bypassed is true for honesty disabled and for mode off, false for honesty enabled + suggest/require; helper off is never classified as pending; resolver eligibility rejects missing/empty phase_id, non-int/<1/boolean round, and missing/empty reviewer_model on pass/findings/blocked, and rejects missing/empty phase_id or invalid/boolean round on skip; frv_authorizing_freeze_paths returns only substantive paths; aggregate_adversarial_authorization_states uses rank absent > pending > skipped > pass. |
| integration | ledger append --kind adversarial_freeze writes a hash-chained line for a valid pass body and for a valid findings body and for a valid blocked body (same required reviewer/session/posture fields); ledger verify → 0 after each; these three append round-trips MUST be proven before any last-verdict revocation assertion that consumes a findings or blocked winner. Mode E require + no match → 40 + JSON token; matching pass → 0 + exact §AFF.8.3 JSON; suggest miss → 0 + stderr warning; off → exact block/no ledger read; valid Mode E excludes B/C/D blocks; Mode E + Mode D flags → 1 diagnostic shape; all digest-only/malformed/mismatch combinations match §AFF.8.1; existing non-regular --frozen-spec + valid --artifact-digest is Mode E explicit ledger query (not usage 1, not refusal 4); honesty.enabled: false → 4; skip authorizes under suggest and does not under require; fixture status: Auto would-emit + require + no AFF → status --exit-code 2 + JSON gate; after pass append, this gate no longer forces 2; fixture status suggest + helper absent → exit 0, JSON key present, state: absent, exact §AFF.9 absent warning; mixed FRV-authorizing candidate sets (pass+pending, pass+absent, pass+skipped) produce the same hold-vs-Auto decision on ok status / governance-sync as ok next (identical subset + aggregate); a non-substantive sibling candidate cannot create a status-only hold. |
| e2e | git-only fixture, two-row convention (AFF-a Thinking + AFF-b Auto; Auto deliverable backtick-cites docs/archive/phases/…) and Thinking → Auto split. Trigger B: after mechanical stamp, ok next on the still-open Thinking row is attack-posture Thinking (adversarial_freeze_pending), not the author freeze paste. Post-stamp mutation (ADV2-M1): edit one byte of the freeze artifact outside review_stamp → ok next returns to the author freeze paste (not adversarial) until restamped; the same mutation on an Auto row must not emit Auto (FRV still requires substantive). Restamp → Trigger B holds again with the adversarial paste. Append AFF pass with phase_id AFF (not AFF-b) + path + digest → Trigger B releases to ordinary Thinking paste; mark {id}-a DONE. Trigger A: open {id}-b Auto + FRV freeze_review (phase_id {id}-b, FRV unchanged) → without AFF, ok next is still adversarial Thinking; the same path+digest pass recorded during {id}-a must clear Auto (R1-M1). Execute the §AFF.7.4 transaction: adding the Review-record row invalidates old FRV/AFF bindings; restamp alone does not restore Auto; rebind FRV alone still leaves AFF pending; appending AFF last restores both gates for the final digest. One-byte later artifact edit withdraws Auto again. Same loop with suggest + skip → Auto, advisory adversarial_freeze_skip. off → Auto immediately after FRV. Disabled honesty (ADV3-M1): honesty.enabled: false plus explicit adversarial_freeze: suggest and the derived-suggest shape (key absent + security in human_escalation): Trigger B after a fresh mechanical stamp keeps the author freeze paste (not adversarial_freeze_pending); Trigger A on an Auto row with freeze candidates stays FRV freeze_not_substantive (not an AFF hold); Trigger A on an Auto row with no freeze candidates still emits Auto; ok status omits adversarial_freeze_gate. Identical loops under a Muse-regime fixture. Operator + Auto unchanged. |
| stress | 200-row roadmap with one open Auto row + large ledger; AFF probe bounded; no OOM. |
| data-integrity | Last-verdict matrix for one path/digest: pass→pass = last pass; pass→findings and pass→blocked = pending with older pass revoked; findings→pass = pass; skip→pass = pass; pass→skip = skip only under suggest; skip→findings = pending. The pass → findings and pass → blocked rows MUST use entries that survived validate_append_body / CLI append (the integration findings/blocked round-trips), not in-memory dicts that skip append validation. Different digest/path entries do not revoke each other. Skip digest D does not authorize digest D′. ok next twice with no ledger change → identical fence bytes. Broken ledger chain → absent hold, never Auto; suggest + that absent still emits the §AFF.9 JSON key and absent warning on status/governance-sync. Mode E itself is exercised with a valid authorizing pass followed by mutations of prev_hash, body bytes/entry_hash, malformed provenance, bad signature, and required-signature absence: it returns 22/2/25/26 per §AFF.8.3 and never 0, including suggest. Hash-consistent malformed ledger (ADV3-M3 / ADV4-M1–M2): write mutations as hash-consistent JSONL (not via ledger append, which would reject them). Lines with omitted/empty phase_id, non-int or <1 round, or omitted/empty reviewer_model retain the strict envelope and are chain-valid (verify_chain → 0) but MUST NOT win the resolver, authorize Auto, or produce Mode E matched_via: pass. A matching pass with round: true likewise has verify_chain → 0 but is resolver-ineligible. Independently, recompute valid hashes after omitting ts or setting v: true; despite matching entry_hash, shared envelope verification MUST return 22, every AFF surface MUST fail closed, and the resolver MUST never run. |
| performance | Mode E + ok next AFF probe complete within the same bound family as ISR Mode D / ok next on the ISR fixture size. |
| security | No secret/key/URL in paste, JSON, ledger example, or skill; templating injection-safe; fail-closed on read failure (absent holds when mode is on, and suggest + absent still surfaces the §AFF.9 JSON/warning); Mode E verifies the strict envelope/full chain/provenance before resolving and cannot soften integrity failure under suggest; author session cannot append pass with equal ids; auto_may_start: true still does not grant Auto; freeze-review-loop skill source bytes contain the MUST NOT auto_may_start: true prohibition and do not contain an instruction to set it true; mechanical stamp + same-session freeze_review without AFF does not emit Auto when mode is suggest or require; a stale mechanical_only stamp (digest ≠ current) does not satisfy Trigger B and does not authorize FRV Auto; a hash-consistent malformed pass (missing ts, boolean v, missing phase_id, invalid/boolean round, or missing reviewer_model) cannot authorize; helper off under disabled honesty cannot hold Auto; no network; no model call; no subprocess to a reviewer. |
§AFF.15 — Definition of Done
AFF-a (this Thinking phase)
- This document exists with
frozen: true. - Author
/freeze-review-loopreachedpasswithout settingauto_may_start: true. - Mechanical
ok review --freezestamp written. auto_may_startabsent or nottrue.- No AFF-b code, no test file, no CLI edit, no honesty schema change, no skill edit, no consumer product edit, no hub Main deploy.
- ROADMAP + HANDOVER updated together; NEXT is the adversarial Thinking paste (different chat), not AFF-b Auto.
- Feature-branch commit. No merge to
main. - Do not add AFF-b as an open queue row while AFF-a is WIP
(
next_regenmultiple_open_rows—next_regen.py:383-384). Queue AFF-b when AFF-a → DONE.
AFF-a is not DONE on author freeze-review-loop pass alone. The
adversarial freeze of this freeze is THE ONE NEXT STEP. After that pass,
the bootstrap rule in §AFF.7.4 applies: record the different-chat pass in the
artifact before its final restamp, rebind freeze_review for the final digest
when AFF-b is queued, but do not append the not-yet-implemented AFF kind.
Then AFF-a → DONE and AFF-b Auto is cleared to start.
AFF-b (Auto, later)
- Built exactly to §AFF.2–§AFF.14.
test_aff_seven tiers green./build-verification-reviewpassthen ISRpass(kit dogfoodrequire_independent_second_reviewer: require).- Kit dogfood config writes
adversarial_freeze: suggest. - No model dispatch. No
auto_may_start: truewriter. No consumerrequiredefault.
§AFF.16 — Auto deliverable list (mechanical; AFF-b)
adapters/config.py—HONESTY_KEYS,ADVERSARIAL_FREEZE_MODES,HonestyConfig.adversarial_freeze, parse + derived default.tools/honesty/types.py— kind, verdicts, error token, JSON field.tools/honesty/validate.py— strict client envelope/type validation, append rules + match helpers + genesis forbid-list.tools/honesty/ledger.py— strict storedv/tsenvelope verification before hash/provenance acceptance; server timestamp fill only on omission.tools/adversarial_freeze/— authorization state + status/governance surface + Trigger-Bauthor_loop_complete+aff_hold_bypassed+frv_authorizing_freeze_paths+aggregate_adversarial_authorization_states(does not edittools/freeze_authorization/resolve.py).tools/honesty/status.py— Mode E, exit40, options,_resolve_mode.cli/commands/honesty_status.py—--adversarial-freeze/--artifact-digest.tools/governance_hygiene/next_regen.py— hold + paste template + advisory constants.tools/governance_hygiene/engine.py— footer (ISR path, notReadFailure).cli/commands/status.py— JSON key + exit-2fold.tools/optional_feature_tips/surface.py— off-mode tip.cursor/skills/adversarial-freeze-review/SKILL.md+ amendments in freeze-review-loop, freeze-review, check-ok-thinking.docs/ADVERSARIAL-FREEZE-REVIEW.md+ CHECK-OK / AGENTS / consumer pointers + SPEC §5/§6.2.- Kit dogfood
.overseer/config.yamlexplicitsuggest. tests/**/test_aff_*.py— seven tiers, prefixtest_aff_.
No new argparse top-level command. No FRV AuthState extension. No
bornfree-hub files.
Adversarial-freeze findings ledger (AFF-ADV-r1)
The citations below name the pre-fix AFF-ADV-r1 locations. AFF-r4 resolution is frozen immediately after the historical findings table.
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| ADV1-B1 | BLOCKER | security / fail-open | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:370-371, :487-498, :975 |
A prior pass remains authorizing after a later same-subject findings or blocked append because both frozen matchers select only pass/skip entries. The matrix tests only rejection of a lone findings, not pass → findings or pass → blocked. Freeze a last-verdict resolver across all AFF verdicts so a later non-pass revokes an earlier pass for the same subject/digest. |
| ADV1-M1 | MAJOR | consistency / digest binding | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:688-689, :842-847; tools/freeze_reviewer/artifact.py:119-130 |
The artifact SHOULD gain an adversarial Review-record row, while the pass procedure appends a digest-bound ledger entry, but no ordering/rebind rule is frozen. A prose row is inside the digest (only review_stamp is excluded), so recording the round after append invalidates AFF and FRV; recording it after the existing mechanical stamp also makes that stamp digest stale. Freeze the exact sequence: record round, restamp current bytes, refresh any required freeze_review, then append AFF against the final digest. |
| ADV1-M2 | MAJOR | security / integrity | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:776-783, :979; tools/honesty/status.py:551-568; tools/honesty/ledger.py:31-77 |
Mode E is told to read/match entries but is never required to run verify_chain; the only broken-chain assertion is for ok next. The existing Mode D-shaped status path reads and matches without chain verification, so following that precedent can return exit 0 for a tampered ledger even while Auto-hold correctly fails closed. Require full chain/provenance verification before every Mode E match and add tamper tests for Mode E itself. |
| ADV1-M3 | MAJOR | completeness / public contract | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:770-783; tools/honesty/types.py:58-93 |
Mode E says only that HonestyStatusJson gains an optional dict and names matched_via: skip; unlike Modes B–D, it freezes no exact nested fields, nullability, success/miss payloads, or mode-exclusion behavior. AFF-b therefore cannot mechanically implement a stable CLI JSON contract. Freeze the complete adversarial_freeze block, including effective digest/path, mode, match hash, matched_via, and which other mode blocks must be absent. |
| ADV1-N1 | MINOR | completeness / CLI usage | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:703-714, :722-753 |
--artifact-digest is introduced as Mode E metadata but is absent from the frozen mode-resolution algorithm. The contract therefore permits it to be silently ignored with Mode B/C/D and does not state the outcome for Mode E with a digest but no --frozen-spec, even though the matcher requires an exact frozen_spec. Add the flag to resolution/usage invariants and freeze these combinations. |
| ADV1-N2 | MINOR | consistency | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:3-6, :109-110 |
The author-close status said the mechanical stamp was next after the stamp already existed. This round corrects the heading, but the author must rewrite the AFF-r3 resolution when producing the fresh post-fix stamp so the durable review history is not contradictory. |
AFF-r4 resolution map
| Finding | Resolution |
|---|---|
| ADV1-B1 | §AFF.5.1 and §AFF.5.5 freeze one latest-verdict resolver across all four verdicts; pass/skip helpers inspect only its winner. §AFF.14 freezes revocation sequences. |
| ADV1-M1 | §AFF.6.1 and §AFF.7.3–§AFF.7.4 make the Review-record row mandatory before restamp, required FRV rebind, and final AFF append; the bootstrap exception forbids the not-yet-built kind. |
| ADV1-M2 | §AFF.8.3 requires full verify_chain chain/provenance validation before Mode E resolution, preserves integrity exits, and §AFF.14 adds Mode E tamper/provenance coverage. |
| ADV1-M3 | §AFF.8.3 freezes the full nested block, top-level nulls, outcome matrix, nullability, and valid-mode exclusion of B/C/D blocks. |
| ADV1-N1 | §AFF.8.1–§AFF.8.2 freeze the complete --artifact-digest matrix, usage behavior, digest/path derivation, and mode-resolution pseudocode. |
| ADV1-N2 | The status and AFF-r3 Review-record row now describe the historical pre-ADV stamp accurately; AFF-r4 records the post-fix author pass before restamping. |
Adversarial-freeze findings ledger (AFF-ADV-r2)
This review was performed in a session different from producer nonce
aff-a-author-2026-09-19. The citations name the AFF-r4 bytes reviewed before
this findings record and final mechanical restamp.
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| ADV2-M1 | MAJOR | digest / ordering | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:669-672; tools/freeze_authorization/resolve.py:155-158, :189-207 |
Trigger B declares the author loop complete from FRV state mechanical_only, but the current shared resolver computes the current digest and then returns mechanical_only solely from the stamp verdict; it never compares the stamp's artifact_digest with that current digest. An author edit after stamping can therefore replace the author NEXT with an adversarial paste on stale mechanical evidence. Freeze a trigger-specific fresh-stamp check (or repair the shared state contract deliberately) and add a mutation proving a post-stamp byte edit returns to the author loop until restamped. |
| ADV2-M2 | MAJOR | test honesty / revocation | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:374-380, :395-406, :1174-1178 |
The contract requires every negative review to append findings/blocked, but the frozen tests require append validation only for a minimal pass and can exercise the revocation matrix with directly constructed entries. A build can reject valid negative bodies at the CLI while every named resolver test stays green, leaving the operational pass → findings/blocked revocation path unusable. Require append/round-trip tests for valid findings and blocked bodies, including their required reviewer/session/posture fields, before running the last-verdict matrix. |
| ADV2-N1 | MINOR | CLI completeness | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:795-808, :818-821 |
The claimed complete --artifact-digest matrix defines readable regular files and absent paths, and defines non-files only when no explicit digest is present. It never decides Mode E for an existing non-regular path (for example a directory) plus a valid explicit digest. Freeze whether that shape is usage, refusal, miss, or an explicit ledger query, and test it. |
| ADV2-N2 | MINOR | consistency | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:225, :395-406 |
The rejection table calls the recorded reviewer_model fields optional, while the normative pass/findings/blocked schema requires a non-empty reviewer_model. Use one rule throughout; model inequality may remain only a preference. |
| ADV2-N3 | MINOR | status honesty | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:565-571, :984-994 |
The shared helper says absent is a read-error hold under both suggest and require, but the active-slice surface freezes a warning only for suggest + pending; it does not define suggest + absent. Specify the JSON/warning outcome so ok next cannot hold on a broken ledger while status/governance-sync silently omit the reason. |
AFF-r5 resolution map
| Finding | Resolution |
|---|---|
| ADV2-M1 | §AFF.7.1 freezes Trigger-B-only author_loop_complete: mechanical_only counts only when stamp artifact_digest equals the current FRV digest. FRV AuthState / Auto authorization are unchanged. §AFF.14 e2e requires a post-stamp byte-edit return to the author paste. |
| ADV2-M2 | §AFF.14 unit/integration require validate_append_body / CLI append round trips for valid findings and blocked bodies before last-verdict revocation. Data-integrity revocation rows must use those append-accepted entries. |
| ADV2-N1 | §AFF.8.1–§AFF.8.2 treat existing non-regular --frozen-spec + valid --artifact-digest as Mode E explicit ledger query (not usage, not refusal). |
| ADV2-N2 | §AFF.2 rejection table and §AFF.5.2 now use one rule: reviewer_model is required on pass/findings/blocked; inequality remains preference only. |
| ADV2-N3 | §AFF.9 freezes adversarial_freeze_gate.state, the suggest + absent warning, and that helper absent is not a probe skip. |
Adversarial-freeze findings ledger (AFF-ADV-r3)
This review was performed in a session different from producer nonce
aff-a-author-fix-r2-2026-09-20. The citations name the AFF-r5 bytes reviewed
before this findings record and final mechanical restamp.
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| ADV3-M1 | MAJOR | configuration / availability | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:570-574, :648-664, :1025-1042 |
The shared helper defines off for honesty-disabled as “not a hold,” and the status probe skips when honesty is disabled, but Trigger A authorizes only pass/eligible skipped; its early bypass names resolved mode off, not honesty.enabled: false. With an explicit/derived suggest plus disabled honesty, a conforming implementation can receive helper off and still take the “otherwise hold” branch while status omits the gate. Freeze disabled-honesty as a NEXT bypass (or include helper off in the non-holding branch) and test both triggers. |
| ADV3-M2 | MAJOR | status honesty / candidate aggregation | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:654-664, :1025-1064; tools/governance_hygiene/next_regen.py:479-492 |
Trigger A probes only candidates FRV treated as authorizing (substantive) and requires all of that subset to clear, while §AFF.9 says to probe the slice's freeze candidates generally and exposes one scalar state without defining target selection or aggregation. With multiple discovered candidates, status/governance-sync can disagree with ok next, or hide which pending/absent candidate holds Auto. Freeze the identical FRV-authorizing subset and deterministic worst-state aggregation (or a per-candidate payload), plus mixed pass/pending/absent tests. |
| ADV3-M3 | MAJOR | security / defensive validation | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:399-410, :515-532; tools/honesty/ledger.py:48-76 |
The append schema requires non-empty phase_id, valid round, and non-empty reviewer_model on pass/findings/blocked, and §AFF.5.5 claims its defensive rules prevent malformed historical lines from authorizing. The eligibility list checks none of those fields. verify_chain verifies hashes/provenance but does not re-run kind schema validation, so a hash-consistent malformed pass with matching path/digest, posture, role, and unequal sessions can authorize. Add the omitted required-field checks to the resolver and mutation tests over a valid hash chain before claiming defensive fail-closed behavior. |
AFF-r6 resolution map
| Finding | Resolution |
|---|---|
| ADV3-M1 | §AFF.4.3, §AFF.5.6, and §AFF.7.1 freeze aff_hold_bypassed: honesty disabled or mode off bypasses both Trigger A and Trigger B before probing. Helper off is never pending. §AFF.14 e2e covers disabled honesty under explicit and derived non-off modes. |
| ADV3-M2 | §AFF.5.6 / §AFF.9 freeze frv_authorizing_freeze_paths as the shared Trigger A and status/governance-sync subset, plus worst-state rank absent > pending > skipped > pass. Scalar JSON state is that aggregate. §AFF.14 tests mixed pass/pending/absent against ok next parity. |
| ADV3-M3 | §AFF.5.5 eligibility rules 9–11 require non-empty phase_id, exact-integer round ≥ 1, and non-empty reviewer_model on pass/findings/blocked. verify_chain enforces the shared envelope but still does not re-run AFF kind schema. §AFF.14 data-integrity/security require hash-consistent malformed-ledger mutations that cannot authorize. |
Adversarial-freeze findings ledger (AFF-ADV-r4)
The citations below name the AFF-r6 bytes reviewed before this findings record
and final mechanical restamp. AFF-a remains WIP; no adversarial_freeze entry
was appended because AFF-b has not created that kind.
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| ADV4-M1 | BLOCKER | security / envelope validation | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:374-376, :525-551; tools/honesty/ledger.py:48-60 |
The frozen envelope requires v: 1 and ts, but the defensive eligibility rules never check either field. verify_chain checks only entry.get("v") != 1, prev/hash linkage, and the computed hash; it does not require ts, so a hash-valid adversarial_freeze pass with ts omitted still passes chain verification and rules 1–11, then authorizes Auto/Mode E. The same comparison also accepts JSON v: true as equal to integer 1; the resolver has no exact-type check. Freeze strict envelope validation (or make verify_chain strict) and add hash-valid missing-ts / boolean-v mutations to the AFF fail-closed matrix. |
| ADV4-M2 | MAJOR | security / type validation | docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:417, :545-553; tools/honesty/validate.py:319-321 |
The contract says round is an integer and calls the resolver rule the same as validate_append_body, but both the frozen isinstance(int) wording and the cited implementation admit JSON true because Python bool subclasses int. A hash-valid pass with round: true therefore satisfies the stated defensive rule and can authorize despite being an invalid round. Freeze an exact-integer rule (type(round) is int, or equivalent) in append validation and resolver eligibility, and add a boolean-round mutation. |
AFF-r7 resolution and full ADV1–ADV4 re-derivation map
Every resolution below cites the current frozen contract by path:line.
ADV1–ADV3 were re-derived from the named paths rather than presumed closed;
ADV4 is the repaired round. No scope from an earlier repair is removed.
| Finding | Current resolution evidence |
|---|---|
| ADV1-B1 | Latest eligible verdict across all four outcomes revokes an older favorable entry, and wrappers inspect only that winner: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:427-433, :546-601; revocation matrix :1368. |
| ADV1-M1 | Review-record → final artifact edits → restamp → conditional FRV rebind → actual AFF verdict append is mandatory, with the AFF-a bootstrap prohibition: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:848-896. |
| ADV1-M2 | Mode E verifies the entire ledger before resolving and preserves integrity exits: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:1088-1103; tamper coverage :1368-1370. |
| ADV1-M3 | Exact Mode E block, types/nullability, mode exclusion, success/miss outcomes, and diagnostic shape are frozen: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:1022-1111. |
| ADV1-N1 | Digest/path derivation and the full usage matrix, including digest-without-path rejection, are frozen: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:902-952, :954-1020. |
| ADV1-N2 | Current status and Review record distinguish historical stamps from the current repaired round: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:3-17, :114-127. |
| ADV2-M1 | Trigger B requires a fresh mechanical stamp whose recorded digest equals the current FRV digest; it does not alter FRV Auto authorization: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:757-797; mutation coverage :1366. |
| ADV2-M2 | Valid pass/findings/blocked append round trips precede and feed negative revocation assertions: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:427-433, :1364-1368. |
| ADV2-N1 | Existing non-regular path plus explicit valid digest is a confined Mode E ledger query, not usage/refusal: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:915-938, :940-952, :1014-1017. |
| ADV2-N2 | reviewer_model is required and non-empty for pass/findings/blocked; only model inequality is optional: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:448-470, :585-586. |
| ADV2-N3 | suggest + absent is a visible non-failing status/governance warning and never a probe skip: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:1141-1154; coverage :1365, :1368-1370. |
| ADV3-M1 | Disabled honesty or resolved off bypasses both NEXT triggers; helper off never becomes pending: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:349-355, :629-635, :729-755, :757-773; coverage :1364-1366. |
| ADV3-M2 | Trigger A and status share the FRV-substantive candidate subset and deterministic worst-state aggregation absent > pending > skipped > pass: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:659-669, :739-755, :1124-1143; parity coverage :1364-1365. |
| ADV3-M3 | The resolver defensively requires non-empty phase_id, exact-integer positive round, and non-empty reviewer_model after common-envelope verification: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:564-592; hash-consistent mutation coverage :1364, :1368-1370. |
| ADV4-M1 | Shared append and chain verification enforce exact integer v: 1 plus required non-blank stored ts; hash-consistent missing-ts and boolean-v entries fail chain verification with 22 before resolution: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:380-405, :1088-1103, :1364, :1368-1370; AFF-b implementation locus :1416-1419. |
| ADV4-M2 | All append branches and resolver eligibility use type(round) is int, explicitly rejecting JSON/Python boolean; the boolean-round AFF mutation remains chain-valid but cannot win or authorize: docs/archive/phases/PHASE-AFF-ADVERSARIAL-FREEZE-HONESTY-GATE.md:407-413, :448-459, :479-487, :582-592, :1364, :1368-1370. |
Adversarial-freeze confirmation (AFF-ADV-r5)
This review was performed in a session different from producer nonce
aff-a-author-fix-r4-2026-09-20. The author Review-record was not trusted.
Live contract holes that AFF-b must close were re-derived from source:
tools/honesty/ledger.py:50 (entry.get("v") != 1 admits True because
True == 1); no stored-ts check in verify_chain (:48-60);
tools/honesty/validate.py:320, :340, :379 (isinstance(round, int)
admits True because bool subclasses int). The repaired freeze closes
those holes at the layers named below. No new findings. AFF-a bootstrap:
Review-record only; no adversarial_freeze append; no FRV rebind (no prior
bound freeze_review entry); auto_may_start absent.
| ID | Independent confirmation |
|---|---|
| ADV4-M1 | Hash-consistent missing/blank/ts or boolean v cannot reach an AFF resolver or authorizing surface: stored envelope requires type(v) is int and non-empty ts (:376-396); Mode E calls verify_chain first and never resolves on nonzero (:1084-1089); helper verifies the full chain before resolving (:635-636); missing-ts / v: true mutations with matching entry_hash MUST return 22 and MUST NOT run the resolver (:1360, :1364). Live True == 1 / missing-ts holes remain in current code because AFF-a is spec-only. |
| ADV4-M2 | Boolean round cannot pass any round-bearing append kind, the AFF append branch, or AFF resolver eligibility: shared type(round) is int and round >= 1 replaces every isinstance(int) check (:403-409) including verification_evidence / independent_second_review / freeze_review / every AFF verdict (:450, :481); resolver rule 10 uses the same exact-type test (:578-580); round: true remains chain-valid (verify_chain → 0) and resolver-ineligible (:1360, :1364). Layer split vs ADV4-M1 is explicit: envelope failures are 22 before resolve; boolean-round is kind-schema defense. |
| ADV3-M1 | Disabled honesty bypasses both NEXT triggers before any AFF probe; helper off is never pending; status skips (:345-351, :627-631, :652-653, :725-733, :735-738). e2e coverage :1362. Status cannot hold while NEXT skips, or the reverse. |
| ADV3-M2 | Trigger A and status/governance-sync share frv_authorizing_freeze_paths and worst-state rank absent > pending > skipped > pass (:655-665, :1123-1136). Mixed-candidate parity is required (:1360). |
| ADV3-M3 | Resolver eligibility 9–11 still reject missing phase_id / invalid round / missing reviewer_model after envelope verification (:560-588). Not replaced by the ADV4 envelope checks. |
| ADV1-B1 | Latest eligible verdict across all four outcomes; later findings/blocked revokes (:423-429, :542-548, :1364). Not narrowed. |
| ADV1-M1 | §AFF.7.4 ordering plus AFF-a bootstrap prohibition (:848, :887-892). This round followed it: Review-record before restamp; no AFF append. |
| ADV1-M2 / ADV1-M3 / ADV1-N1 | Mode E full-chain (:1084-1089), exact JSON (:1018), digest/path matrix including non-regular+digest (:909-917, :1010-1013). Not narrowed. |
| ADV2-M1 | Trigger-B fresh-stamp vs current FRV digest; FRV Auto unchanged (:771; e2e :1362). Not narrowed. |
| ADV2-M2 | Valid findings/blocked append round trips before revocation matrix (:1360, :1364). Not narrowed. |
| ADV2-N1 / ADV2-N2 / ADV2-N3 | Non-regular+digest Mode E query (:1010-1013); required reviewer_model (:455); suggest + absent visible non-skip (:1138-1150). Not narrowed. |