Local reviewer wave¶
Use only after user explicitly approves this bounded paid reviewer wave. The Codex CLI starts separate local review sessions when the native launcher cannot establish mandatory reviewer controls. Unsupported controls fail closed; a successful check certifies only the observed runtime. This route does not enable write remediation or promote sibling workflows.
Boundary¶
Parent owns launcher, frozen plan, returned text, evidence files, final verdict, canonical gates. Independent ephemeral local reviewer sessions inspect non-sensitive context under observed read-only/never controls. The adapter disables configured MCP servers and other external capabilities for its invocation; empty MCP table alone does not disable inherited entries. No installed configuration or authentication store is edited. Existing CLI authentication remains opaque. Missing CLI/authentication is user-owned prerequisite, never reason to install or inspect credentials.
Evidence is app-server-parent-observed: the field is retained for compatibility with saved review records. It records observations collected by the owning helper, not native collaboration lineage or cryptographic host attestation. The parent correlation ID does not establish that local reviewer sessions descend from that native thread. Filesystem credential isolation remains unverified; read-only does not imply secrets are unreadable. Never supply sensitive contexts or market this route as hostile-child isolation. An accepted artifact validates retained observations and bindings, not their resistance to hostile parent rewriting all evidence.
Freeze and execute¶
- Complete normal risk routing and primary review first. Freeze one to four unique canonical Sol/Luna roles; explicitly selected architecture/security advisors remain unsupported by this adapter. Parent substitutes cannot be counted as independent QA/challenger evidence.
- Copy the exact installed
roles/<role>/ROLE.mdbytes for each triggered role to<run-directory>/role-cards/<role>/ROLE.mdbefore dispatch. Create one context per role, beginning with those full exact bytes, followed by narrow task evidence, questions, output contract, stop rule. Retain the copied cards with the run so promoted-result intake can verify their manifest digests after the installed cards change. Reviewers return findings and a scoped assessment; write-producing probes stay parent-owned under shared probe policy. Require one raw JSON object, without Markdown fences or outside prose, with exactlysource_sha256,diff_sha256,findings, andassessment. Copy the plan's source and review-input digests respectively.assessmenthas exactlysource_rating_version=1,rating(integer 1–5 or JSON null),verification_readiness(complete|blocked|incomplete), andrationale(nonblank evidence-backed string), including whenfindingsis empty. Legend: 1 = Approve · 2 = Minor changes · 3 = Major revision · 4 = Insufficient, but a good initiative · 5 = Block. Stage 4 describes a promising but substantially incomplete implementation; stage 5 requires an explained documented-direction or binding-constraint conflict. Unavailable prerequisites can leave the source judgment null with blocked readiness; unfinished feasible checks require incomplete readiness. Source judgment and process readiness remain separate. Historical plans without the source-rating marker retain their original two-field assessment contract and historical legend for read-only validation; never relabel their raw rating 4. Each finding has exactlysignature(nonblank stable string),tier(security|critical|high|medium|low|nit),structural(boolean),disposition(open|fixed-pending-verification|verified-fixed|rejected),evidence(nonempty array of nonblank strings). Include locations, reasoning, closure or required action, confidence and material limits in evidence; return every assigned prior finding and every new defect. Empty findings means no findings, not missing coverage. This structured contract replaces role-card free-form output sections, not review responsibilities. Hash context bytes after completion. - Write schema-2 JSON plan with
consumer_id="code-review",source_rating_version=1,task_sensitivity="non-sensitive",review_run_id,parent_thread_id, exactreview_input_sha256for run'sdiff.patch, absolute existingcwd,nodes. Write the complete scoped source snapshot fromshared/collect_diff.pyto a relativesource_path, then bind it withsource_sha256; bind the exact frozen diff at relativediff_pathwithdiff_sha256, which must equalreview_input_sha256. This route requires nonempty explicit leaf-file scopes, withscope_pathsexactly matching record paths (including tracked missing-file records). Enumerate required files first, then pass each literal file to the collector; directory/.scopes are rejected because partial inventories cannot prove their completeness. The general collector's directory support remains unchanged. Include the complete exact bytes of both files in every role context, after its full installedroles/<role>/ROLE.mdprefix; hashes or paths alone are rejected. Each node containsrole_id, canonicalmodel,reasoning_effort,role_card_sha256, relativecontext_pathbeneath plan directory,context_sha256. - Each schema-2 node carries a
capacity_receiptwith exactlycontext_sha256,model,tokenizer,input_tokens,instruction_reserve_tokens,output_reserve_tokens,supported_capacity_tokens,default_context_window,effective_window_percent,source_path,source_sha256,capacity_evidence_path,capacity_evidence_sha256. - Bind capacity evidence:
capacity_evidence_pathnames bounded local JSON with exactlyschema_version=1,model,observed_supported_capacity_tokens,observed_default_context_window; its digest and values must match the receipt. - Use
tokenizer="utf8-byte-upper-bound"andinput_tokensequal to the exact frozen context's UTF-8 byte length. The adapter recomputes this conservative bound for byte-level text tokenization; unknown methods and mismatched counts fail before host launch. It needs no tokenizer dependency or download. Character counts and unverified operator proxy counts are not accepted measurements. Account separately for host instructions, message framing, the history trigger when used, output in the positive integer reserves; the byte bound does not certify those reserves or actual hosted capacity. - Require positive integer input/instruction/output/supported/default values and a 1–100 effective-window percentage. Select
model_context_windowwhen present, otherwise the evidenced default window; it may not exceed evidenced supported capacity. Admit only wheninput_tokens + instruction_reserve_tokens + output_reserve_tokensfitsselected_window * effective_window_percent // 100. The byte bound can reject text whose exact tokenizer count would fit: reduce the approved scope to required complete source and consumers, never truncate it or invent a smaller count. Revisit this conservative method only with a separately scoped, locally verifiable tokenizer requirement. - The optional window goes only to
thread/start; no global setting changes. The snapshot proves included bytes, not semantic scope sufficiency or effective hosted capacity. Retain these limits and the measurement source. Freeze the plan before launching; never repair historical plans retroactively. - Inspect
PLUGIN_ROOT/bin/python PLUGIN_ROOT/shared/local_reviewer_wave.py --help. First runPLUGIN_ROOT/bin/python PLUGIN_ROOT/shared/local_reviewer_wave.py --plan <plan.json> --check-host: this checks effective host controls and any required history loading without starting a model turn, does not count as completed review. After that succeeds, execute explicitly approved wave withPLUGIN_ROOT/bin/python PLUGIN_ROOT/shared/local_reviewer_wave.py --plan <plan.json> --out <new-output-directory>. Each owning command uses host's external-execution approval boundary and required action/capability/credential/filesystem/retry brief. Place plan directly in review run; adapter requires new output directory beneath resolved plan directory, rejecting existing symlink escapes before creation. Never callthread/shellCommand, unsandboxed filesystem/process APIs, or another launcher as silent fallback. - The adapter checks controls before turns, dispatches bounded wave, joins terminal outputs, proves owned-process cleanup. After output setup succeeds, failure attempts diagnostic persistence and retains completed output but cannot promote successful wave. Input validation or unavailable output storage may leave no artifact; report returned error without claiming evidence exists. No automatic second paid wave: stop this launcher, preserve its evidence and recurrence count, continue permitted source inspection using native instruction-bounded route or disclosed parent-serial fallback from
SKILL.md. Request new scope/approval only when necessary next action actually needs it; missing user-required independence still withholds completion, but does not stop remaining inspection.
Contexts must be valid UTF-8 and at most 2 MiB each; metadata and role cards remain bounded to 256 KiB, final responses to 128 KiB. Request and input-echo frames account for worst-case JSON escaping without increasing the prior aggregate buffering envelope. These are transport limits, not model token-capacity guarantees. --check-host validates input and observed controls without a model turn; it cannot certify model acceptance. Never truncate source or replace complete evidence with hashes or paths to fit a limit. Oversized, unsupported, stale, or capacity-inadmissible contexts stop this route; no automatic paid retry. Historical schema-1 plans may be inspected with direct adapter evidence validation, but --check-host, --out, and Code Review acceptance reject them because they lack schema-2 source and capacity bindings.
The supported CLI turn-input ceiling is 1,048,576 aggregate Unicode characters, independent of UTF-8 bytes and model tokens. Contexts at or below it use direct turn/start input. Larger bounded contexts use documented thread/inject_items to append the complete exact context as a user message in the same ephemeral thread, followed by one short review-trigger turn. Splitting text items does not remove the aggregate ceiling. Every required preload must acknowledge before any reviewer turn starts; unsupported history loading stops with zero turns attempted. Context bytes, role prefix, source/diff inclusion and drift checks remain unchanged. A successful no-model preload does not prove model capacity or independent review completion.
Large-context evidence nodes require context_delivery containing exactly method="thread/inject_items", the frozen context_sha256, and boolean acknowledged=true. This binds the adapter's observed preload to that reviewer context; it is not a model-read attestation or cryptographic receipt. Direct-input historical evidence remains valid without this field; a large context cannot qualify through an unmarked historical record.
Protocol failure recovery¶
Every new review turn sends the shared finding schema through the local review process's turn/start.outputSchema, binding source/diff values and forbidding unknown fields. The runner also validates the returned raw JSON and finding shape before successful completion; a provider refusal, malformed response, unsupported schema or wrong source binding fails closed. Original output bytes are retained when available; never strip fences, repair JSON, fall back to unconstrained output or automatically retry. Historical evidence stays readable under its original contract. Syntax enforcement does not prove review accuracy or hosted-model availability; --check-host makes no model request.
Documented planning notifications (turn/plan/updated, item/plan/delta, and typed plan items) are accepted only for active thread/turn and valid shapes. Id-less account/updated and schema-shaped warning and configWarning notifications are discarded without retaining their payloads; account updates can arrive during an active turn or cleanup and do not alter review controls. Unknown events, approval requests, and unsafe item types remain rejected; protocol tolerance never authorizes execution.
For app-server-event-rejected, failure artifact retains only failure_diagnostic fields: stage, reason, method_category, recovery. method_category is a public notification name selected from the adapter's fixed generated-schema allowlist, or unrecognized for any other or malformed method. This classification does not accept the event. It never retains arbitrary method text, payload, tool arguments, or credentials. Historical evidence without a recognized category cannot identify the original event; never invent exact root cause. Maintainers compare the category with the installed CLI's offline generated schema, then add narrowly validated protocol support with regression tests. An unchanged paid retry provides no new protocol evidence.
RPC rejections retain a separate safe diagnostic: stage="rpc-response", an allowlisted method category, recognized standard rpc_code or null, static reason and recovery guidance. Recognized input-length rejection reports input-character-limit; unsupported methods report method-not-supported. Raw RPC messages, error data and arbitrary codes are discarded. The CLI emits this safe diagnostic on failure, including no-model host checks; ordinary execution also retains it in failed evidence. Unknown errors remain unclassified, never an invented cause or permission to retry.
Apply Actionable Pauses: explain that the local reviewer wave stopped, cite its failure evidence and retry rule, state which source inspection continues, name owner/action/resume condition for this launcher only. Never tell user that protocol repair, different host, or manual review is mandatory while authorized inspection route remains available. Never erase prior failed waves or count their output as accepted review.
Bind the result¶
After successful adapter completion, write specialist-manifest.json with schema_version=4, normal review identity and triggered-pass fields, and app_server_execution containing exactly plan_path, evidence_path, and evidence_sha256. Paths resolve beneath review run; evidence digest binds adapter's evidence.json.
Each isolated pass uses mode="app-server", canonical role_card_sha256, ordinary role, axis, trigger, confidence, blocking_findings, plus exact adapter-produced output_path. Never populate native attempts, selected_attempt, or runtime_execution. Any optional parent substitute remains mode="substituted" and cannot satisfy mandatory independence. Copy pass records into result metadata as for native reviews.
Run existing review manifest preflight. It validates adapter evidence, role/card/context/output bindings, current input identity, effective controls, unique completed threads, and cleanup. Mirror its runtime classification in metadata.execution_mode; use execution_evidence_level="app-server-parent-observed" and write_parallel_eligible=false. Claim parallel only for validated substantive overlap, otherwise independent-spawned; two threads alone do not prove parallelism.
Retain each returned readiness in final reconciliation; blocked or incomplete reviewer checks cannot become complete merely because another reviewer has a favorable source rating. Complete review notes, findings reconciliation, confidence limits, final handoff rendering, candidate validation, promotion, and find-review-report.py --complete-run. Adapter success and two output files are not completed review. Keep final report lookup as distinct acceptance check for PR-scoped runs; local review must not invent PR identity to exercise it.