Phase ISR — Independent second reviewer (Thinking freeze)
Status: Reviewed → pass (ISR-r4). ISR-a is spec-only and now frozen; no
code, no skill edit, and no honesty schema change land in this phase. ISR-b
(Auto) is cleared to build mechanically against this contract.
phase: ISR
outputs:
- id: isr-independent-second-reviewer
path: docs/archive/phases/PHASE-ISR-INDEPENDENT-SECOND-REVIEWER.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: k9a-honesty
path: docs/archive/phases/PHASE-K9A-L1-L2-MODULE-FREEZE.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: lt-loop-tightening
path: docs/archive/phases/PHASE-LT-LOOP-TIGHTENING.md
- id: ons-operator-next
path: docs/archive/phases/PHASE-ONS-OPERATOR-NEXT-SURFACING.md
- id: kh1-relay
path: docs/archive/phases/PHASE-KH1-HANDOVER-RELAY-STANDARD.md
- id: check-ok
path: docs/archive/phases/PHASE-CHECK-OK.md
- id: build-verification-skill
path: cursor/skills/build-verification-review/SKILL.md
- id: build-verification-rule
path: cursor/rules/build-verification-required.mdc
- id: honesty-types
path: tools/honesty/types.py
- id: honesty-status
path: tools/honesty/status.py
- id: honesty-validate
path: tools/honesty/validate.py
- id: honesty-config
path: adapters/config.py
- id: verification-evidence-gate
path: tools/verification_evidence_gate/surface.py
- id: governance-hygiene-engine
path: tools/governance_hygiene/engine.py
- id: status-exit
path: cli/commands/status.py
- id: layered-honesty-vision-l0
path: docs/archive/thinking/OVERSEER-KIT-LAYERED-HONESTY-VISION.md
- id: test-tiers
path: policy/test-tiers.yaml
- id: model-labels
path: policy/model-labels.yaml
- id: kit-boundary
path: AGENTS.md
review_stamp:
reviewed_at: '2026-09-02T12:24:04Z'
verdict: pass
reviewer_mode: agent
reviewer_model: thinking-high
reviewer_provider: local
kit_version: 0.1.0
artifact_digest: sha256:e6284150fc755facb5a008ce33eb425d55081e798096a0373d5e54715f5b3bba
Downstream edge: ISR-b treats this document as ground truth without re-deriving it (SPEC §6 mandatory reviewed freeze). The second chat / separate verifier runtime performs the review; the kit only records and optionally gates the verdict. The kit never dispatches, hosts, or calls a second model.
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 |
|---|---|---|---|
| ISR-r1 | Freeze-review loop (checklist + thinking, thinking-high) |
findings | Semantic R1-M1–M2 + R1-N1. Fixed in-tree before CLI stamp. |
| ISR-r2 | Freeze-review loop (checklist + thinking, thinking-high) |
findings | R2-M1 governance-sync wiring named ReadFailure (coverage path) instead of the LT Mode B engine-footer path. R2-N1 validate helper “or equivalent”; R2-N2 live skill dests vs ok sync. Fixed in-tree. |
| ISR-r3 | Freeze-review loop (CLI checklist + thinking, thinking-high) |
findings | R3-C4 CLI blocked on a C4 false positive (gate-token equals-sign). Rephrased. |
| ISR-r4 | Freeze-review loop (CLI checklist + thinking, thinking-high) |
pass | R1–R3 confirmed RESOLVED. Boundary held (kit records/gates; no model dispatch). Mode D resolution + engine-footer wiring frozen. Seven-tier matrix complete. Stamp written by ok review --freeze. |
Freeze-review findings ledger (ISR-r1)
| ID | Severity | Category | Citation | Message |
|---|---|---|---|---|
| R1-M1 | MAJOR | consistency | :575-586 (pre-fix) |
V9 required an ISR ledger line as part of BV, but §ISR.7.3 appended that line only after BV pass — Auto could not order the steps. Frozen: V1–V8 then append then DONE-unlock V9. |
| R1-M2 | MAJOR | completeness | :648 (pre-fix) |
Exit constant lived in status.py or honesty_status.py. Frozen to tools/honesty/status.py only. |
| R1-N1 | MINOR | completeness | :457 (pre-fix) |
Mode D --json on usage/38/4 and _usage_result extension were implied, not frozen. Now explicit. |
| R2-M1 | MAJOR | completeness | :510 (pre-fix) |
Governance-sync ReadFailure("independent-second-reviewer") pointed Auto at reads.py (coverage). LT Mode B fails in engine.py after the footer. Frozen to engine-footer + status _exit_code_from_conditions. |
| R2-N1 | MINOR | completeness | :247 (pre-fix) |
find_matching_* “or equivalent” weasel. Frozen to tools/honesty/validate.py. |
| R2-N2 | MINOR | consistency | :596 (pre-fix) |
“Amend live .cursor/ / .claude/ copies” vs required ok sync --yes. Frozen: edit cursor/ source only. |
| R3-C4 | BLOCKER | security | :541 (pre-fix) |
Checklist C4 matched a gate-token equals-sign as a secret assignment. Rephrased to “the gate token is …”. |
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).
§ISR.0 — Simple summary
After an Auto build, the same chat that wrote the code can run
/build-verification-review, type DONE, and walk away. The build-verification
rule already asks for an independent verifier and a thinking-high model — "if
possible." That weasel is the hole. Loop tightening (LT) recorded the hole and
explicitly deferred it: no second chat, no different session id.
Independent second reviewer freezes the missing gate: before an Auto slice may be claimed DONE, a second chat or separate verifier — not the agent that built — must record a passing verdict. The kit records and optionally gates that verdict on the honesty ledger. The kit does not run another model, does not open a new IDE chat, and does not call any reviewer API for this gate.
Technical summary: add ledger kind independent_second_review (additive to the
K9a / P-evidence enum); require producer_session_id ≠ actor_session_id at
append time; add honesty.require_independent_second_reviewer: off|warn|require
(default off; HONESTY_KEYS + HonestyConfig field); add honesty-status
Mode D (--independent-second-review PHASE_ID, shared optional
--producer-session / --frozen-spec); add exit 38 + token
missing_independent_second_review; add an LT-shaped active-slice surface on
ok status / governance-sync; vendor a portable paste doc + twin skill; amend
build-verification V9 + the always-on BV rule. Portable CLI + docs are complete
without Cursor. No model dispatch. No ISR-b code in this Thinking phase.
§ISR.1 — Verified problem (do not redesign)
| Fact | Evidence |
|---|---|
| BV skill says independent verifier "if possible" — not a gate | cursor/skills/build-verification-review/SKILL.md Model section |
Always-on BV rule requires /build-verification-review before DONE; it does not require a different session |
cursor/rules/build-verification-required.mdc |
LT explicitly deferred second chat / different agent_id |
docs/archive/phases/PHASE-LT-LOOP-TIGHTENING.md §LT.2 non-goal + §LT.5.3 |
K9a session inequality exists only for Mode A verdict hooks, and only when --producer-session is supplied |
PHASE-K9A §K9.8; tools/honesty/status.py _match_verdicts |
Mode B (verification_evidence) matches last bv_verdict=pass — no producer/session compare |
P-evidence §PE.6.1; find_matching_verification_evidence |
A producer may self-declare actor_role: verifier and append evidence |
P-evidence §PE.3 role rule is role-string only |
| Kit is rule-holder, never model executor | P-route §PR.0; AGENTS.md; SPEC §6 reviewer is a separate freeze surface, not a dispatcher for DONE |
Honesty Mode A/B/C + _resolve_mode already treat --producer-session as a Mode A partial |
tools/honesty/status.py _resolve_mode (P-deploy §PD.5.0) |
| Active-slice Mode B surface already exists (warn/require, no historical retro-fail) | tools/verification_evidence_gate/surface.py §LT.5.2 |
Used honesty / CLI exits include 33–37 |
P-evidence 33, P-deploy 34, workspace 35, PLS 36, ONS 37 |
| Cursor cannot be required; ONS/LT: CLI + docs primary | PHASE-ONS; PHASE-LT §LT.4.1 / §LT.7 |
§ISR.2 — Scope
In scope (ISR-a freezes; ISR-b implements):
- Ledger kind
independent_second_review+ append/validate rules (§ISR.3). - Config
honesty.require_independent_second_reviewer+HONESTY_KEYS/HonestyConfigwiring (§ISR.4). - Honesty-status Mode D flags, mode-resolution amendment, JSON, error token (§ISR.5).
- Active-slice status / governance-sync surface (§ISR.6).
- Portable CLI + docs + twin skill + BV V9 / rule amendment (§ISR.7).
- Exit code
38and reuse of existing codes (§ISR.8). - Boundary + rejection table — governance, not runtime (§ISR.9).
- SPEC §5 additive row (§ISR.10).
- Seven-tier matrix (§ISR.11).
- Definition of Done (§ISR.12).
Out of scope (explicit non-goals):
| Non-goal | Why rejected now |
|---|---|
| Kit dispatches / hosts / calls a second model | P-route + AGENTS.md boundary. Runtime / operator opens the second chat. |
| Automate Cursor "new chat" / tab open | No honest host command. Print instructions. Same family as tab-reload reject. |
| Require ISR for every consumer | Default off. Kit dogfood starts at warn (ISR-b writes; not this phase). |
require as Auto v1 dogfood |
High friction. Promote later. |
| Replace build-verification or K5 freeze review | ISR who certified DONE; BV what matches the spec; K5 before Auto starts. |
| Apply ISR to Thinking freeze-review DONE | "Not the same agent that built." Thinking stays K5. ISR = Auto slices only. |
New Mode A verdict hook or SHA co-requirement |
Different layer. Do not overload verdict. |
Reuse / extend verification_evidence with session fields |
That kind is artifact hashes (V8). ISR is independence of the certifier. |
Make --producer-session required on Mode D |
Lost token must not make the check unusable. Pin when supplied; entry still stores both ids. |
Cryptographic proof of chat identity as git-only baseline |
P0 provenance remains optional / soft under git-only. Kit records the claim. |
| Session-type bookends (idle / Operator+Auto) | Separate backlog row. ISR skips non-Auto active slices. |
| KH2 remask, tab reload, auto-enable hooks | Unchanged backlog. |
Wire ok review --freeze to Mode D |
Wrong gate: freeze is pre-Auto. Same as LT Mode B. |
New top-level CLI verb (ok isr, ok isr-status) |
Check = Mode D on ok honesty-status; record = ok ledger append. No second engine. |
| Block historical DONE rows | Active slice only (LT §LT.5.2 posture). |
| MuseHub-only identity / signature as the gate | K7: baseline on git-only. |
| ISR-b Auto implementation in this Thinking phase | SD-3 split. |
| 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. |
§ISR.3 — Ledger kind independent_second_review (frozen schema)
Additive amendment of the K9a / P-evidence entry-kind enum: add exactly one
new value. Every prior kind's required fields and semantics stay byte-identical.
Auto must extend ENTRY_KINDS in tools/honesty/types.py and the matching
validate_append_body branches — no second ledger, no renumbering.
independent_second_review
Envelope (unchanged K9a / P0 rules): every non-genesis entry carries v: 1,
kind, ts (server may fill), prev_hash / entry_hash (server fills),
actor_role, actor_session_id, and optional provenance.
Role rule (frozen): actor_role MUST be verifier. Any other role → exit 23.
Independence invariant (frozen, enforced at append):
producer_session_idis a required opaque non-empty string (the builder session / separate-producer nonce the operator supplied).actor_session_idis the second reviewer's session (envelope; required on every non-genesis kind).- If
actor_session_id == producer_session_id→ exit2(malformed; not a role violation). The builder cannot honestly append their own ISR pass. - The kit does not invent, scrape, or infer either id. The caller supplies both. The kit records the claim.
Kind-specific required fields (frozen):
| Field | Type | Rule |
|---|---|---|
phase_id |
non-empty string | Opaque phase / slice id (same family as P-evidence). |
frozen_spec |
non-empty string | Opaque path-shaped string. Append checks non-empty string only — no must-exist, no path-confine of the stored string (same as §PE.3). |
round |
integer ≥ 1 | ISR review round. < 1 or non-int → exit 2. |
isr_verdict |
string enum | Closed vocabulary: pass | findings | blocked (lowercase). Any other value → exit 2. |
producer_session_id |
non-empty string | Builder / producer session nonce. Empty / missing / non-string → exit 2. |
Optional fields (frozen):
| Field | Type | Rule |
|---|---|---|
producer_agent_id |
string | Opaque. When both producer_agent_id and verifier_agent_id are present and equal → exit 2. One present, one absent → allowed. |
verifier_agent_id |
string | Opaque. Inequality rule above. Does not require P0 provenance. |
bound_verification_evidence_hash |
string | Optional entry_hash of a verification_evidence line. Auto v1 does not require or resolve this at match time (Mode B 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 BV. |
provenance |
object | Optional; identical to P0 rules. |
Example (normative shape, illustrative ids):
{
"v": 1,
"kind": "independent_second_review",
"ts": "2026-09-02T12:00:00Z",
"actor_role": "verifier",
"actor_session_id": "verifier-chat-2",
"phase_id": "ISR-b",
"frozen_spec": "docs/archive/phases/PHASE-ISR-INDEPENDENT-SECOND-REVIEWER.md",
"round": 1,
"isr_verdict": "pass",
"producer_session_id": "builder-chat-1",
"notes": "second chat re-ran build-verification V1-V9",
"prev_hash": "…",
"entry_hash": "…"
}
Genesis must not carry any of these kind-specific keys. Extend the existing
genesis forbid-list in validate_append_body to include phase_id,
frozen_spec, round, isr_verdict, producer_session_id,
producer_agent_id, verifier_agent_id, bound_verification_evidence_hash
— additive to keys already refused. (phase_id / frozen_spec / round may
already be forbidden from P-evidence; do not remove them.)
CLI record surface (frozen): reuse
ok ledger append --kind independent_second_review (--file / --stdin).
No new top-level verb. ok ledger verify / show treat the new kind like any
other (hash continuity). Kind authority: CLI --kind remains authoritative vs
body kind.
Pure helper Auto MUST add:
find_matching_independent_second_review(entries, *, phase_id, frozen_spec, producer_session) -> entry | None
Implemented beside find_matching_verification_evidence /
find_matching_deploy_health in tools/honesty/validate.py.
Must not open a network connection, must not call a model, must not read
session ids from the IDE.
§ISR.4 — Config: honesty.require_independent_second_reviewer (frozen)
Extend the existing honesty: block with one additive key (default preserves
current behavior):
honesty:
enabled: false
require_independent_second_reviewer: off # off | warn | require — default off
| Value | Meaning |
|---|---|
off |
(default) Mode D may still be invoked; the match is computed for JSON but never fails the exit code (0 on the match dimension even when no entry exists). Repos that never set the key stay inert. |
warn |
Mode D on miss: stderr warning (warning: no matching independent_second_review entry) + exit 0. Active-slice status / governance-sync: reminder only (never fail). |
require |
Mode D on miss: exit 38. Active-slice status --exit-code / governance-sync: reuse exit 2 (no new status exit). |
Parse rules (frozen):
- Value MUST be one of
off|warn|require(string); anything else → config exit2. - Auto MUST add
require_independent_second_reviewertoHONESTY_KEYSinadapters/config.py(unknown-key fail-closed). Omitting that frozenset update would reject a valid config asunknown honesty keys. - Default when the key is absent:
off. - The flag is meaningless when
honesty.enabled: false(module short-circuit exit4on ledger / honesty-status paths remains unchanged). - Auto MUST add
require_independent_second_reviewer: str = "off"to theHonestyConfigdataclass and wire the parsed value intoload_config/ the returned config object (same pattern asrequire_verification_evidence/require_deploy_health). - Unknown keys under
honesty:remain fail-closed (existing rule).
Regime: regime-agnostic git-only baseline. No Muse dependency. Optional
provenance on ISR entries follows P0 soft/hard rules independently.
Kit dogfood (ISR-b writes; not this phase): this repo's
.overseer/config.yaml sets require_independent_second_reviewer: warn.
Do not set require. Do not enable the key in ok init defaults or
templates. Consumers stay off until they opt in.
Operator amend 2026-09-02 — default require (closed loop)
Authority: operator Tier-3 posture flip (Aaron). Premise: the independent second pass is the closed loop; default opt-out was portability, not optionality of the gate.
| Was (ISR-r4) | Now |
|---|---|
Absent key → off |
Absent key → require |
HonestyConfig default off |
default require |
Kit dogfood warn |
Kit dogfood require |
Tip when off: enable warn|require |
Tip when off: you opted out; set require to re-enable |
Opt out per repo: honesty.require_independent_second_reviewer: off (or warn).
Rejection row “Default require for all consumers” is superseded by this
amend for shipped defaults; frozen Mode D / ledger / exit 38 mechanics are
unchanged.
§ISR.5 — honesty-status Mode D (frozen)
§ISR.5.1 — Flags
Exact CLI flag names are frozen (no aliases in this slice):
| Mode | Required flags | Forbidden together with |
|---|---|---|
| A — verdict co-requirement (existing) | --hook HOOK + --artifact PATH |
--verification-evidence, --frozen-spec, --deploy-health, --independent-second-review |
| B — verification evidence (existing) | --verification-evidence PHASE_ID |
--hook, --artifact, --producer-session, --deploy-health, --independent-second-review |
| C — deploy health (existing) | --deploy-health PHASE_ID |
--hook, --artifact, --producer-session, --verification-evidence, --independent-second-review |
| D — independent second review (new) | --independent-second-review PHASE_ID |
--hook, --artifact, --verification-evidence, --deploy-health |
Shared optional flags:
--frozen-spec PATH_STRING— allowed with Mode B, C, or D (not more than one of those modes in one invocation). Opaque string; not a filesystem must-exist check. Forbidden with Mode A.--producer-session ID— allowed with Mode A (existing optional pin) or Mode D (optional pin). Forbidden with Mode B and Mode C (unchanged).
Auto wiring (frozen — required for Mode D to be reachable):
HonestyStatusOptionsgains additive fieldindependent_second_review: str | None = None.cli/main.pyregisters argparse--independent-second-review PHASE_IDon the honesty-status parser (metavarPHASE_ID).cli/commands/honesty_status.pypassesindependent_second_review=getattr(args, "independent_second_review", None)intoHonestyStatusOptionsand maps exit38→ stderr textmissing independent second review.HonestyStatusJsongains additive optional fieldindependent_second_review: dict | None = Noneemitted only on Mode D responses (Mode A/B/C omit the key).
§ISR.5.2 — Mode-resolution algorithm (frozen; amends §PD.5.0)
Today _resolve_mode treats --producer-session as a Mode A partial and
rejects it with Mode B/C / --frozen-spec. Auto must replace that logic
with the following (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
frozen = frozen_spec is set
producer = producer_session is set
# --producer-session is SHARED metadata for Mode A (optional) and Mode D (optional).
# It does NOT by itself imply Mode A when Mode D is selected.
mode_a_partial = mode_a_core or (producer and not mode_d_full)
if (mode_b_full + mode_c_full + mode_d_full) > 1:
return None
if mode_a_partial and (mode_b_full or mode_c_full or mode_d_full or frozen):
return None
if frozen and not mode_b_full and not mode_c_full and not mode_d_full:
return None
if not mode_a_full and not mode_b_full and not mode_c_full and not mode_d_full:
return None
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):
--independent-second-review PHASE --frozen-spec PATH→mode_d.--independent-second-review PHASE --producer-session ID→mode_d.--independent-second-review PHASE --producer-session ID --frozen-spec PATH→mode_d.--independent-second-review PHASEalone →mode_d.--producer-session IDalone → usage1(unchanged).--verification-evidence PHASE --producer-session ID→ usage1(unchanged).--deploy-health PHASE --producer-session ID→ usage1(unchanged).--hook H --artifact P --independent-second-review PHASE→ usage1.- When Mode D flags are absent, Mode A/B/C behavior is byte-identical to
pre-ISR for every invocation that does not pass
--independent-second-review.
Usage exit 1 when the algorithm returns None.
Mode D applies require_independent_second_reviewer per §ISR.4
(off → always 0 for the match dimension and still emits the JSON block;
warn → stderr warning + 0 on miss; require → 38 on miss).
Module disabled → existing 4 short-circuit before mode logic.
§ISR.5.3 — Mode D match rule (frozen)
A matching independent_second_review entry for inputs
(phase_id, frozen_spec?, producer_session?) is an entry where all of:
kind == independent_second_reviewactor_role == verifierisr_verdict == passphase_idequals the requested phase id (exact string match)- If the caller supplies
frozen_spec, it equals the entry'sfrozen_spec; if omitted, anyfrozen_specmatches actor_session_id != producer_session_id(entry-internal; already append-enforced)- If the caller supplies
producer_session, it equals the entry'sproducer_session_idandactor_session_id !=that same id; if omitted, rule 7 is skipped (last ISR pass for the phase still must satisfy 1–6)
Scan order: ledger file order; last matching entry wins.
findings / blocked entries never satisfy the gate. A later pass is a
separate append (new round).
§ISR.5.4 — Mode D JSON + error token (frozen)
Extend HonestyErrorToken with exactly one additive value:
missing_independent_second_review
Used when Mode D exits 38. Do not overload missing_verdict,
missing_verification_evidence, or missing_deploy_health.
Mode D JSON (nested key present only on Mode D responses):
{
"ok": false,
"exit_code": 38,
"command": "honesty-status",
"hook": null,
"artifact": null,
"artifact_sha256": null,
"producer_session": "builder-chat-1",
"matched_verdict_hash": null,
"error": "missing_independent_second_review",
"independent_second_review": {
"phase_id": "ISR-b",
"frozen_spec": null,
"producer_session": "builder-chat-1",
"require": "require",
"matched_entry_hash": null
}
}
| Nested field | Rule |
|---|---|
phase_id |
Echo of --independent-second-review |
frozen_spec |
Echo of --frozen-spec or null |
producer_session |
Echo of --producer-session or null |
require |
Effective config value off|warn|require |
matched_entry_hash |
entry_hash of the last matching pass entry, or null |
Top-level producer_session continues to echo --producer-session or null
(existing Mode A field; Mode D reuses it).
On Mode D success (0): ok: true, error: null, matched_entry_hash set
when a match exists; under off with no match, ok: true,
matched_entry_hash: null, error: null. On warn miss: ok: true,
error: null, matched_entry_hash: null, plus stderr warning.
Mode A/B/C responses must not emit independent_second_review.
Mode D responses must not emit verification_evidence or deploy_health.
--json emits this object on every Mode D exit, including 1 / 4 /
38 / 0 (existing honesty-status always-emit pattern). Usage (1) that
included --independent-second-review still echoes phase_id in the nested
block when the phase argument was present; matched_entry_hash is null.
Auto MUST extend _usage_result in tools/honesty/status.py so it can
carry independent_second_review= the same way it already carries
verification_evidence= / deploy_health=.
§ISR.6 — Active-slice status / governance-sync surface (frozen)
Reuse the LT §LT.5.2 skip / claim posture. New helper module
tools/independent_second_reviewer/ (IndependentSecondReviewerGateReport /
build_independent_second_reviewer_gate) parallel to
tools/verification_evidence_gate/.
When honesty.enabled is true and require_independent_second_reviewer is
warn or require:
- Resolve the KH1.9 active slice (same scan as
scan_governance_gates). - If there is no active slice, or the active Model is not
Autoand not the Auto half of a split ({step}b), skip. - If the active Auto slice status is
TODOorWIPand the handover does not claim BVpass/ DONE, skip. - If the handover or roadmap claims that active Auto slice is DONE or BV
pass, run §ISR.5.3 with:phase_id= the active phase id string from KH1.9--frozen-spec: if the active ROADMAP deliverable cell contains exactly one path matchingdocs/archive/phases/PHASE-*.md(or consumer equivalent underdocs/), pass that path; if zero or more than one, omitproducer_sessionomitted (status cannot know the builder chat)
| Mode | Missing match | Status --exit-code |
governance-sync |
|---|---|---|---|
off |
n/a | unchanged | unchanged |
warn |
reminder line + JSON independent_second_reviewer_gate: {ok: true, mode: warn, matched: false} |
0 (never fail) | footer reminder only |
require |
same JSON with ok: false + token missing_independent_second_review |
2 | engine footer + return 2 (not reads.py ReadFailure) |
Do not invent a new ok status exit code. Token stays
missing_independent_second_review.
Auto wiring (frozen — parallel to LT Mode B, not to footprint-coverage):
tools/independent_second_reviewer/__init__.pyexportsIndependentSecondReviewerGateReport,build_independent_second_reviewer_gate,format_independent_second_reviewer_gate_line,independent_second_reviewer_gate_payload.cli/commands/status.pycalls the builder (same handover/roadmap texts as Mode B), prints the human line, attaches JSON when the probe did not skip, and foldsindependent_second_reviewer_gate.okinto_exit_code_from_conditionsas a newindependent_second_reviewer_gate_okargument (defaultTrue) on the existing2tier. Do not renumber2 > 6 > 35 > 3 > 0.tools/governance_hygiene/engine.pycalls the same builder beside the existingverification_gateblock: emit the human line; whenokis false,modeisrequire, and the gate token ismissing_independent_second_review, return2. Do not add aReadFailureintools/governance_hygiene/reads.py(that path is for VCS / coverage / muse-sync reads, not honesty claim gates).
JSON key (when the probe did not skip): independent_second_reviewer_gate
{ok, mode, matched} plus phase_id when known plus token when set.
Human line when a message exists:
independent_second_reviewer_gate: <message>
Exact miss message (require):
missing independent_second_review ledger entry for active Auto slice
Exact miss message (warn):
warning: no matching independent_second_review entry for active Auto slice
Exact remediation string (require path / engine footer / status JSON):
second chat: append independent_second_review then ok honesty-status --independent-second-review PHASE
ok review --freeze is not wired to this surface.
Do not fail old DONE rows. Do not mark ROADMAP DONE. Do not dispatch a model from status or governance-sync.
§ISR.7 — Portable primary (CLI + docs) + optional host niceties
§ISR.7.1 — Portable contract (complete without Cursor)
| Action | Command / doc |
|---|---|
| Record the second verdict | ok ledger append --kind independent_second_review |
| Check the gate | ok honesty-status --independent-second-review PHASE [--producer-session ID] [--frozen-spec PATH] [--json] |
| Print NEXT for the second chat | ok next / ok governance-sync --print-next |
| Paste instructions (Copilot / any host) | docs/INDEPENDENT-SECOND-REVIEWER.md |
Claude Code, Copilot, and paste-only hosts stay on this table. Missing Cursor skills or hooks is not pass and not fail — degrade to CLI + paste doc.
The kit never opens a second chat. The operator / host runtime does.
§ISR.7.2 — Paste doc (ISR-b writes)
Path: docs/INDEPENDENT-SECOND-REVIEWER.md (kit docs; same family as
docs/CHECK-OK.md / docs/PRINT-NEXT.md).
Auto must include, verbatim as the opening sentence:
The kit records and gates the second verdict. It does not run another model. Open a new chat or a separate verifier runtime; then use the CLI below.
The doc must tell the builder to invent or copy an opaque
producer_session nonce and give it to the second chat (chat / composer id
when the host exposes one; otherwise a human-chosen nonce). Auto v1 does
not add a new handover HTML anchor for this nonce (GS-PASTE sole NEXT
regen; do not reopen).
The doc must include the two CLI lines from §ISR.7.1 and state that a human counts as the second verifier.
§ISR.7.3 — Twin skill (ISR-b writes)
Source (Auto writes): cursor/skills/independent-second-reviewer/SKILL.md.
Dest twins after the required ISR-b ok sync --yes:
.cursor/skills/independent-second-reviewer/SKILL.md and
.claude/skills/independent-second-reviewer/SKILL.md (existing dual glob).
Invoke: /independent-second-reviewer.
Process rules (frozen):
- Confirm this session is not the builder session. If it is, stop and tell the operator to open a second chat. Do not append a pass. Do not write ROADMAP DONE.
- Re-run
/build-verification-reviewV1–V8 only against the frozen spec- diff (implementation honesty). V9 is not part of this step — it is the DONE-unlock check in §ISR.7.4 and cannot be satisfied before the append in step 3.
- On V1–V8
pass, appendindependent_second_reviewwithisr_verdict: pass, this session asactor_session_id, and the builder nonce asproducer_session_id. - When
honesty.require_verification_evidenceiswarnorrequire, the second session also appends / confirms Mode Bverification_evidence(V8) before claiming DONE. ISR does not replace Mode B. - ROADMAP DONE is allowed only after step 3 (and step 4 when it applies).
That is when V9 holds if ISR is
warnorrequire. - When ISR config is
off, the skill is advisory; Mode D / status do not fail. findings/blockedon V1–V8: do not appendisr_verdict: pass. AfindingsISR append is allowed but not required (same family as P-evidence rule 6).- Never merge to
main. Never call a model via the kit CLI for this gate (ok review --freezeremains the K5 spec reviewer, not the ISR dispatcher).
§ISR.7.4 — Build-verification skill + always-on rule (ISR-b amends)
Amend the source twin cursor/skills/build-verification-review/SKILL.md.
Live .cursor/ / .claude/ copies update via the required ISR-b
ok sync --yes — do not require a separate hand-edit of those dests.
Model section — replace "if possible":
Always
thinking-high. Whenhonesty.require_independent_second_revieweriswarnorrequire, this review must run in a second chat or separate verifier runtime — not the session that built. A builder-session BVpassdoes not unlock DONE. When the flag isoff, prefer a second session but do not fail the kit gate (process honesty only).
Add V9 (DONE-unlock only — not a V1–V8 implementation check):
| # | Check | Dishonesty signal |
|---|---|---|
| V9 | When ISR is warn or require, ROADMAP/HANDOVER may claim DONE only after a matching independent_second_review pass exists for this Auto slice with actor_session_id ≠ producer_session_id |
Builder chat wrote DONE; no ISR ledger line; equal session ids |
V1–V8 meaning unchanged. V9 does not block a V1–V8 implementation pass
and does not require the ISR line to exist before the second session
appends it (§ISR.7.3 order: V1–V8 → ISR append → Mode B when it applies →
DONE). V9 is N/A (not
a fail) when the flag is off or honesty is disabled. A builder-session
V1–V8 pass still does not unlock DONE when ISR is warn or require.
Amend cursor/rules/build-verification-required.mdc (alwaysApply) with one
short paragraph: when ISR is warn or require, do not mark DONE in the
builder chat; open a second chat or follow docs/INDEPENDENT-SECOND-REVIEWER.md.
Do not add a new alwaysApply rule file in Auto v1 (coverage blast).
§ISR.7.5 — Other doc pointers (ISR-b writes)
Auto must add one pointer sentence (no new ceremony) to:
AGENTS.mddocs/consumers/scooling/OVERSEER-SETUP.mddocs/consumers/knowtation/OVERSEER-SETUP.md
Each sentence names docs/INDEPENDENT-SECOND-REVIEWER.md and states the kit
does not run another model. No live consumer ok init.
Amend tools/optional_feature_tips/surface.py: when honesty.enabled is true
and require_independent_second_reviewer is off, append one tip naming the
config key and the paste doc. When honesty is off, extend the existing honesty
tip to mention ISR as well as verification-evidence. Do not fail status on tips.
§ISR.7.6 — Tool neutrality (normative)
| Host | Record | Check | Instructions |
|---|---|---|---|
Any (ok CLI) |
ledger append |
Mode D + status surface | paste doc |
| Cursor | same | same | skill + amended BV rule (if repo root) |
| Claude Code | same | same | .claude/skills after sync |
| Copilot / paste | same | same | docs/INDEPENDENT-SECOND-REVIEWER.md |
No MuseHub-only behavior. Mode D and the status surface run on git-only.
Cursor hooks / Automations are not in scope and are not a DONE gate.
§ISR.8 — Exit codes (frozen)
Additive code; non-overlapping with existing
1, 2, 4, 5, 7, 8, 10–11, 20–26, 30–37:
| Code | Meaning | Where |
|---|---|---|
38 |
Independent second review required but missing (no matching isr_verdict=pass under §ISR.5.3) |
honesty-status Mode D when require_independent_second_reviewer: require; JSON error = missing_independent_second_review |
Constant name (frozen): EXIT_MISSING_INDEPENDENT_SECOND_REVIEW = 38 in
tools/honesty/status.py. CLI and tests import that name. Do not reuse
33 / 34 / 20.
Reused (no renumbering):
| Code | Reuse |
|---|---|
1 |
Usage — Mode D combined with A/B/C or other §ISR.5.2 None |
2 |
Malformed schema (bad isr_verdict, round < 1, empty producer_session_id, same-session ids, both agent ids equal, …); and ok status --exit-code / governance-sync when the active-slice require probe misses |
4 |
Honesty module disabled / config refuse |
23 |
Role violation (actor_role ≠ verifier) |
25 / 26 |
Provenance (P0; unchanged) |
38 is confined to honesty-status Mode D. It does not change
status --exit-code precedence (2 > 6 > 35 > 3 > 0).
§ISR.9 — Boundary, capability, rejection (governance, not runtime)
The single most important frozen rule: the kit records and optionally gates the second-reviewer claim. It never runs another model, never opens a second chat, and never treats host UI as a control surface.
| Concern | Overseer Kit | Operator / host runtime |
|---|---|---|
Append independent_second_review |
Yes (validate + chain) | Supplies JSON body + session ids |
| Gate Mode D / status / governance-sync | Yes (off/warn/require) | Decides when to enable |
| 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 |
Run /build-verification-review thinking |
Never (skill is process; K5 ok review --freeze is a different gate) |
Second chat / verifier |
| Prove chat identity cryptographically | Optional P0 only | Muse / operator |
| Tier-3 merge authorization | Never | Operator |
Capability tiers:
| Capability | git-only (baseline) |
muse+git-mirror / muse-only |
|---|---|---|
| Record + gate ISR 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 second reviewer" |
Reject |
| Cursor hook that clicks "New Chat" | Reject — no honest API; not portable |
| Same session appends ISR 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 this phase |
| Waive BV because ISR passed | Reject — both gates; V1–V8 still apply |
| Waive ISR because Mode B evidence exists | Reject — evidence ≠ independence |
| Apply ISR to this Thinking freeze before the kind exists | Reject — K5 freeze-review is the ISR-a gate |
§ISR.10 — SPEC §5 additive row (ISR-b writes)
Amend the existing ok honesty-status row. Do not add a new command row.
Additive clause (normative text Auto must include):
ISR additive: Mode D
--independent-second-review PHASE_IDwith optional--producer-session/--frozen-spec; exit38+missing_independent_second_reviewwhenrequire_independent_second_reviewer: requireand no match. Frozen:docs/archive/phases/PHASE-ISR-INDEPENDENT-SECOND-REVIEWER.md.
ok status additive JSON key: independent_second_reviewer_gate (optional;
absent when the probe skips). --exit-code folds
independent_second_reviewer_gate.ok (require mode only) into the existing
2 tier. Frozen in this document §ISR.6.
SPEC §5 ok status row must gain an ISR additive clause naming that JSON
key and the exit-2 fold.
§ISR.11 — Seven-tier matrix (ISR-b)
| Tier | Must prove |
|---|---|
| unit | independent_second_review in ENTRY_KINDS; validate accepts a minimal valid body; rejects same actor_session_id/producer_session_id → 2; empty/missing producer_session_id → 2; non-verifier → 23; bad isr_verdict → 2; round < 1 → 2; both agent ids equal → 2; one agent id only → accept; genesis forbid-list includes new keys; frozen_spec opaque non-empty without must-exist; require_independent_second_reviewer parse (off\|warn\|require, default off, unknown → config 2); key in HONESTY_KEYS; HonestyConfig field default off; HonestyErrorToken includes missing_independent_second_review; _resolve_mode invariants §ISR.5.2 (1)–(8); find_matching_independent_second_review last-wins, pin when producer supplied, reject findings. |
| integration | ledger append --kind independent_second_review writes a hash-chained line; ledger verify → 0; Mode D require + no match → 38 + JSON token; matching pass → 0 + matched_entry_hash; warn miss → 0 + stderr warning; off → not enforced; Mode D + Mode B flags → 1; Mode D + --hook → 1; Mode A without Mode D flags remains byte-identical; honesty.enabled: false → 4; fixture lock/status: Auto DONE claim + require + no ISR → status --exit-code 2 + JSON gate; after append, coverage of this gate no longer forces 2. |
| e2e | git-only fixture: enable honesty + ISR warn + active Auto DONE without ledger → status exit 0 + warn payload; require → exit 2 + token; Mode D with --producer-session matching entry → 0; same session ids refused at append; ok next still extracts the same fence after docs pointer edit. Identical unsigned path under a Muse-regime fixture. |
| stress | Ledger with ≥ 50 ISR entries; match scan last-wins; no unbounded walk. |
| data-integrity | Canonical hash includes producer_session_id / isr_verdict / session ids (tamper breaks verify → 22); append does not embed chat transcripts; dry-run / validate-fail writes nothing; Mode D omit-producer vs pin-producer do not rewrite the ledger. |
| performance | Append + Mode D match + active-slice probe finish in a bounded time (same order as ok status). |
| security | Session ids / notes that look like URLs or shell metacharacters are opaque — never fetched, never executed; no network and no model call on append/verify/match/status paths (asserted); no secrets required in ISR fields; producer role cannot append (23); equal session ids cannot pass; exit 38 cannot be waived by omitting Mode D when CI invokes it under require; no absolute machine paths in JSON gate payload. |
Exact test file prefix: test_isr_ (under tests/ seven-tier folders). Do not
invent a second family name.
§ISR.12 — Definition of Done
ISR-a (this phase): this document reviewed → pass with a CLI stamp;
ROADMAP ISR-a → DONE; NEXT → ISR-b; no Auto code; no main merge; no live
posture flips; no secrets.
ISR-b: every in-scope deliverable exists at the path this freeze names;
§ISR.11 green; kit dogfood require_independent_second_reviewer: warn written;
ok sync --yes so new skill twins land in the lock (coverage stays ok);
SPEC §5 + AGENTS + consumer stubs + paste doc + BV V9 + BV rule + optional
tips updated; no consumer defaults; no model dispatch; no tab/new-chat claim;
ok status --exit-code not failing this gate on this repo unless an active
Auto slice falsely claims DONE; ROADMAP + HANDOVER updated together;
/build-verification-review → pass from a second chat before ISR-b
DONE (dogfood the gate at warn). Merge remains Tier 3.
§ISR.13 — Operator paste for ISR-b (informational; GS-PASTE may regen)
Model: Auto. Build exactly against this file. Do not redesign. Do not
dispatch a model. Do not enable ISR require for consumers. Do not claim the
kit opened a second chat.
§ISR.14 — Cross-references
- LT §LT.2 / §LT.5.3 — deferred this gate; active-slice skip posture reused
- P-evidence — Mode B / V8; not replaced
- P-deploy — Mode C / §PD.5.0 resolution pattern this phase amends
- P-route — rule-holder, not executor
- K5 / K9a / K10 — freeze review, roles, ledger
- K7 — no MuseHub-only baseline
- ONS — portable CLI + docs; no tab-reload claim
- Check OK — ad-hoc honesty; not a substitute for ISR on Auto DONE