Working code is not clean code. Small pieces are not simple. Familiar patterns are not correct patterns. Own the result beyond the edit — local changes have system-level consequences.
- File size: flag >500 LOC new file; propose extraction >800 LOC existing; mandatory refactor >1500 LOC
- Function size: ≤50 LOC target; >100 alert; >200 blocking — extract sub-functions, never keep adding
- Cyclomatic complexity: ≤10 target; >15 alert; >25 blocking
- Single responsibility: before adding to a file — "does this belong here?", "am I adding a second responsibility?", "is this helper reusable elsewhere?"
- No global state: no
staticglobals, no singletons (getInstance()). Prefer injection via parameter or owner member. If unavoidable:// WHY: [precise technical reason] - Dependency direction: UI → Core → Types. Never reverse. Use forward declarations or interfaces to break upward deps.
- No circular dependencies: a dependency that "climbs" the hierarchy is a circular dep in formation. Resolve by forward declaration or interface extraction.
This is the single statement of the error-handling policy. Other sections point here rather than restating it.
- Never swallow errors silently: no empty
catch {}, no ignoredResult, no_ = - Rust:
?,map_err(), oranyhow::bail!—unwrap()/expect()forbidden in production code except on a proven invariant carrying// SAFETY: [reason] - C++: return codes or
std::optional/std::expectedover exceptions in hot paths and critical code; nevercatch(...) {} - At system boundaries (I/O, HTTP, network, user input, external parsing): always handle explicitly
- Internal trusted boundaries may
assert/debug_assertin debug, panic in Rust
- Language: English everywhere — code, comments, commits, PR descriptions. One language per repo.
- Names: explicit over short —
processAudioFrame()>process(),userEmailAddress>email. One term per concept across the codebase. - No cryptic abbreviations:
idx→index,cnt→count,mgr→manager(exceptions:ptr,id,num) - Comments: WHY only — hidden constraint, subtle invariant, workaround for a specific bug. Never describe WHAT the code does, and never to explain confusing code: simplify the code instead. (One exception, in §Senior reflexes: public interface contracts.)
- Dead code: delete immediately, never comment out.
git log -S "functionName"recovers any deleted code.
- No magic numbers or strings appearing more than once → named constant
- Rust:
constat module level or inimplblock - C++:
constexprorstatic constexpr; never bare#definefor typed values - C++ resources: no naked
new/delete—std::unique_ptr,std::make_unique, RAII always. Every acquired resource is released via RAII.
- Commit format:
<type>(<scope>): <description>— types:feat,fix,refactor,perf,docs,test,chore - PR size: ≤400 LOC changed. Beyond: split into sequential autonomous PRs, each independently buildable
- Squash merge preferred: one clean commit per PR in main history; never merge-commit noise in
main - Pre-commit (before every non-trivial commit):
- Rust:
cargo clippy --all-targets -- -D warnings && cargo test - C++:
cmake --build build/ --config Release - TS/JS:
tsc --noEmit && eslint src/
- Rust:
- One authoritative source per piece of system knowledge (DRY). When knowledge is copied, choose one owner and derive or trace the rest.
- Orthogonality: unrelated concerns, business rules, and volatile details don't change together. When changes fan out widely, restore ownership.
- Keep important decisions reversible until evidence justifies commitment. When uncertain or hard to reverse, seek feedback or make the step smaller.
- Automate repeatable work; keep automation versioned.
- Debug from reproduced facts and measured behavior — never coincidence or blame.
- Leave touched code, docs, tests, and tooling in a condition you can stand behind.
- Preserve behavior, write for the next reader, leave touched code cleaner within scope.
- Split boolean flags and mixed abstraction levels out of functions. (Naming itself: see §Naming & comments.)
- Separate commands from queries. No hidden side effects.
- When touching code: remove the smell most likely to make the next change risky or unclear.
- Preserve observable behavior; isolate feature changes, migrations, and cleanup into separate steps.
- Small buildable, testable, reviewable steps — split if too large to reason about locally.
- Get a safety net (tests) before risky structural edits; characterize current behavior before modifying legacy code.
- Refactor the smell blocking the current change, not every smell nearby.
- When the same edit appears for a third time: centralize ownership instead of copying again.
- Stop when the change is easy, the code is clearer, and further cleanup would be speculative.
- Optimize for lower cognitive load — not shorter files, familiar patterns, or clever compactness.
- Prefer deep modules: small interfaces hiding significant internal complexity. Reject wrappers that don't hide real complexity.
- Hide volatile decisions, representations, protocol facts, and messy edge handling in one owning module.
- When naming is hard or comments get long: treat it as design evidence, not a comment problem.
- When one change spreads widely: look for duplicated knowledge, hidden dependencies, or the wrong owner.
- Add complexity for performance or patterns only when evidence justifies it.
Before any analysis, audit, or review, estimate scope and classify intent.
Estimate scope (run this first):
git ls-files | grep -E "\.(py|rs|cpp|c|h|hpp|ts|js|go|sh)$" | xargs wc -c 2>/dev/null | tail -1
# → divide by 4 = estimated tokens (±20% heuristic)
git ls-files | grep -E "\.(py|rs|cpp|c|h|hpp|ts|js|go|sh)$" | wc -l
# → file countClassify intent:
| Signal in the request | Mode | Strategy |
|---|---|---|
| "Where is X?", "find Y" | Lookup | Explore sub-agent |
| "How does X work?" | Understanding | Sub-agent + targeted read |
| "Review", "analyse the architecture" | Review | Central synthesis + list of read/unread files |
| "Exhaustive", "nothing missing", "audit" | Audit | Manifest-driven direct read + verified coverage |
Secondary complexity signal: if tokens < 50k but files > 100 → prefer a clarification round even for Audit (many small files = complex dependency graph).
Strategy by size:
< 50 000 tokens → read ALL files directly in the main context (100% coverage guaranteed)
50k – 150k → deterministic cartography (ctags/AST) + layered reads
> 150 000 tokens → multi-phase workflow (cartography → parallel reads → synthesis)
Verified coverage (mandatory in Audit mode):
- Before starting: generate the complete file list —
git ls-files | grep -E "..."— this is the execution contract - Declare legitimate exclusions upfront by path (
generated/,vendor/,build/) - Read every remaining file in sequence
- Report at the end:
Coverage — Audit [repo]
Files: 11 total | Excluded (generated): 0 | Excluded (vendor): 0 | To read: 11
Read: 11/11 (100%) ✅
Unread business-logic files: none
Central unread modules (>5 incoming imports): none
Confidence rule derived from coverage:
≥ 80%→ conclusions without qualifier60–80%→ prefix each conclusion with "Partial analysis:"< 60%→ prefix with "⚠️ Provisional — insufficient coverage"
Note: ctags/AST tools give structural exhaustiveness (all symbols), NOT behavioral exhaustiveness (same signature ≠ same logic). Direct read remains necessary for behavioral audits. Never use a sub-agent for Audit mode.
Measured 2026-08-30 via git ls-files (image excluded). Re-measure with
python3 scripts/measure_scope.py; CI fails when these figures drift.
| Scope | Tokens (÷4) | Files | Strategy |
|---|---|---|---|
| Core stack (excl. anti-debt) | ~127 000 | 75 | Layered read — cartography first, then targeted reads |
| Anti-debt agent | ~130 000 | 118 | Read its AI_CONTEXT.md and ADRs before its sources |
| Whole repo | ~246 000 | 191 | Multi-phase workflow — never a single direct read |
Do not read the whole repo in one pass: at ~246k tokens it does not fit, and the strategy table above applies in full. Pick the scope the task needs — most work touches only one of the two halves.
This block said "~22 000 tokens, 11 files, direct read always" until 2026-08-27, measured ten weeks and 178 files earlier. Every agent read that instruction at session start and would have blown its context following it. A measurement in an instruction file is a fact with an expiry date: when you add one, add the check that fails when it expires.
The rules above are the always-on core. The reflexes below are the full senior playbook — apply them proactively, without being asked, scaled to the project's language and risk. They are the canonical source: per-tool configs (CLAUDE.md, MiniMax agent.md, .cursorrules) should reference this file rather than re-state these rules.
- ADR (Architecture Decision Record) — documents a decision already made. Retrospective, in
docs/adr/NNNN-short-title.md: Context · Decision · Rejected alternatives · Consequences. Triggers: new central pattern, lib choice, thread-model constraint, public-API change. - RFC (Request for Comments) — requests feedback before a major change. Prospective, in
docs/rfcs/: Motivation · Detailed proposal · Alternatives · Open questions · Review deadline. // See ADR-NNNNin code — when a block implements a documented decision, link it so a reader reaches the "why" without searching the docs.- Documentation proportional to size: >10 source files →
CLAUDE.md; >3,000 LOC →ARCHITECTURE.md(thread model, data flow, ownership, red zones); >5,000 LOC →CONTRIBUTING.md(conventions, how to add a module, PR checklist). - Domain glossary — for any jargon-dense domain (audio, finance, medical, network, games), create
docs/glossary.mddefining terms operationally (precise definition + link to the implementing module + concrete in-project example). A dev without domain background introduces subtle bugs by misreading a technical term. - Data format versioning & migrations — every persisted format carries an explicit version + one migration function per delta (
upgradeProjectV6toV7()). Without migrations a refactor that changes the format makes all old files unreadable. - CHANGELOG.md — on any project with releases, maintain it from Conventional Commits:
## [VERSION] - YYYY-MM-DDwith### Added/Fixed/Changed/Removed.
- Propose tests at service creation — when a stateless service / pure business logic is created or extracted, proactively offer a test (don't wait to be asked). Stateless free functions are the highest-priority, easiest wins.
- Test naming:
Component_Scenario_ExpectedBehavior(e.g.ProjectReader_LoadCorruptedJson_DoesNotCrash). - Three classified suites:
*_Unit(pre-commit + CI, zero I/O, <100ms) ·*_Integration(CI nightly, mocked devices/files) ·*_Device/*_AudioDevice(manual, real hardware). - Integration & golden tests on deterministic outputs: golden (render a known output, compare checksum/RMS), replay (import → edit → undo → render → verify), session-load (load N historical projects → migrations still work).
- Fuzz & property-based: fuzz every parser of external data (libFuzzer /
cargo-fuzz) — malformed input must fail cleanly, never corrupt state silently. Property-based test algorithms with math invariants (proptest/quickcheck/rapidcheck) — e.g. "audio output stays within [-1.0, 1.0] for any input". - Invariants as runtime asserts — every critical invariant documented in ARCHITECTURE.md has a matching
assert()/debug_assert!()in code. An unverified invariant is just a promise. Free in release, immediate detection in debug. - Zero-alloc CI check — any real-time thread has a test asserting
heap_alloc_count == 0after N iterations. An accidental allocation in a hot path is invisible until user reports ("crash after 2h").
- Ownership graph = DAG — never an ownership cycle. Upward (child→parent) or lateral (sibling→sibling) references use
weak_ptr/observer/callback, never a strong ref. Destruction order = reverse of construction. - Shutdown sequence — in any multi-threaded system, document in ARCHITECTURE.md which thread is joined first, in what order queues drain, when OS handles are released. A service destroyed while the audio thread holds a reference = guaranteed crash.
- Lock hierarchy — document the mandatory acquisition order (e.g.
ProjectMutex → AudioGraphMutex → TrackMutex). Never acquire a level-N lock while holding level-N+1. Prevents deadlocks; TSan detects violations. - Thread annotations — comment every method with
// THREAD: audio | ui | anyso the model is explicit in code, not only in ARCHITECTURE.md. - RT threads (audio callback, video decode) — no logging, no mutex, no I/O, no allocation. Communicate via a lock-free ring buffer: RT thread pushes
(EventId, timestamp, value)with atomics; a low-priority thread drains to log/UI. Without it, "it crackles sometimes" reports are undebuggable. - Structured logging — 4 levels (ERROR irrecoverable · WARN degraded · INFO session events · DEBUG off in release). Per-domain macros when justified (
LOG_AUDIO_WARN). RT threads log only via the ring buffer above.
- Error handling policy — see §Error handling above. It is stated once, there.
- RAII (C++) — no naked
new/delete;make_unique/make_shared/stack. FFI opaque handles wrapped in a RAII type immediately (no naked handle circulating). using namespacebanned at file scope — in headers (0 exceptions, fully qualify) and production.cpp(function scope or explicit aliasnamespace fs = std::filesystem;only).- Sanitizers in dedicated CI builds: ASan (use-after-free, overflow) + UBSan (signed overflow, null deref) can combine; TSan (data races) separate build; MSan (uninit reads). Rust FFI modules:
cargo miri test(nightly) catches UB at theextern "C"boundary that C++ sanitizers miss. - Clang-Tidy (C++) — beyond cppcheck. Priority checks:
bugprone-use-after-move,bugprone-dangling-handle,performance-unnecessary-copy-initialization,modernize-use-override/make-unique,readability-function-size. Ship a.clang-tidy+ run in pre-commit/CI. - Hardware abstraction for testability — any service touching OS resources consumes an interface, never the hardware directly. Priority interfaces:
IFileSystem,IClock(timers/autosave),IAudioSink. Lets CI simulate disk errors / latency without real hardware.
cargo audit --deny warnings(RustSec CVE scan ofCargo.lock) andcargo-deny(crate bans, license policy, duplicate versions) on any serious Rust project.osv-scanner --recursive .ortrivy fs .for vendored/system C++ deps (SDL3, ImGui, FFmpeg, codecs). C++ CVEs are rarer but graver (codec overflow = RCE). Nightly CI.- CODEOWNERS —
.github/CODEOWNERSassigning ownership by domain + mandatory reviewer on frozen cores / public APIs / CI. Create it even solo: it prepares a second dev with zero ambiguity.
- Code review checklist (before approving any PR): Correctness · Security (secret/injection/missing validation) · Thread safety (shared data protected, atomics correct) · Resources (no leak) · Performance (no alloc in hot path, no avoidable O(n²)) · Readability (a senior understands it in 30s) · Tests (logic covered / no broken test).
- Performance budgets — document per subsystem and check in CI: audio callback <2ms · UI frame <16.6ms (60fps) · undo/redo <50ms · project load <3s · heavy ops (scan, waveform) async non-blocking.
- Tech debt SLA — build/clippy warning: immediate (don't commit) · race condition: 24h · architecture violation: 7 days · legacy TODO: next sprint. "Stop-the-line" on the first two.
- Feature flags — isolate unfinished/experimental code behind a runtime flag (preferred,
config.json) or compile-time#ifdefwith// FEATURE: ... — remove when: ....#if 0is forbidden (that's dead code — delete it or use a real flag). - Public interface contracts (exception to "comments = WHY only") — public interface headers document non-inferable contracts in one line:
// @pre Must NOT be called from audio thread,// @thread-safety lock-free, MT-safe,// @throws never (noexcept). - FFI conventions (C++ ↔ Rust) — the most dangerous boundary. Every
extern "C": return anint32_t/ResultCodeerror code (never implicit); complex errors via a thread-localget_last_error_str(); ownership documented explicitly (Box::into_raw()→ C++unique_ptrwith a deleter calling back into Rust; neverfree()C++-side on Rust-allocated memory). Capture conventions in an "Interop Error Handling + Memory Ownership" ADR. - Boy Scout rule — when editing a file and you spot neighbouring debt fixable in <15 min (un-injected global, over-long function, untested helper), fix it in the same commit with a note. If >15 min: create a TODO/ticket and move on.
Routine fixes (lint, typo, single-line, doc, test):
- Use existing AGENTS.md rules (Senior reflexes, Clean code, Refactoring)
- No extra overhead
- Existing pre-commit checks per language (§Git & collaboration) are sufficient
Architectural changes — any of these touched:
context/orproviders/directory (DI, scope, hierarchy)routes?/(route nesting, layout, navigation flow)- Dependency order in DI chain
- Exported types/interfaces from
types/orexports/ - Module-level singletons/state
- Root app component (
app.tsx,App.tsx)
REQUIRED before proposing the change:
- Run
graphify path <symbol>and cite the consumer tree in your commit message - Read ≥ 3 call sites of the changed symbol directly (not grep summary)
- State scope explicitly in the commit message: "Affects: [list]. Does not affect: [list]."
- If
git difftouches ≥ 2 files in architectural scope → ask user to confirm scope before applying - Tag the commit with
[arch-change]for review priority
Rationale (from 2026-06-26 incident): The FileStoreProvider bug was introduced by a fix that placed a directory-scoped provider inside session-scoped providers. The fix author (Rwanbt) understood the immediate wiring (viewer → FileStore.markClean) but missed the directory-vs-session scope distinction. This rule forces scope reasoning via graphify + call-site reading
- explicit user confirmation before arch changes are applied.
Enforcement:
- Mavis pretool-arch-change-detect hook (auto on Edit/Write arch-scope files)
- Mavis arch-change-gate skill (loaded on hook trigger)
- These are the canonical mechanisms — don't duplicate as manual checklists
See also: <OBSIDIAN_VAULT>/projects/ai-native-dev-stack/AGENTS.md
for the project-specific mirror of this section + cross-references to
hook/skill implementations. The legacy Systeme-Agentique/ path is
historical and is no longer part of the v4 vault layout.
Before marking any task done:
- Behavior preserved (or intentionally changed with tests)?
- One authoritative source per fact modified?
- Local reasoning clear without external context?
- No silent errors, no magic numbers, no dead code?
- Named accurately? Comments WHY only?
- File/function within size budget?
- Pre-commit checks pass (lint + tests)?
- PR ≤400 LOC or split planned?
Cross-model operating rules for autonomous analysis, planning, implementation, debugging, code review and architecture. Designed to hold on Claude, Gemini, GPT, DeepSeek, Qwen, GLM and Minimax — including under long context and weaker self-control.
Written in English on purpose: it is the most reliably-followed instruction language across all of the above. Layer project-specific rules (LOC gates, frozen core, naming, stack) on top in a separate file.
Reliability, not speed, and not volume of text.
A plausible explanation is not the goal. An explanation whose alternatives you have actively ruled out, with cited evidence, is.
Structured prose that merely looks thorough is the exact failure mode this file
exists to prevent. Every claim of completeness, safety, or confidence must be backed
by a located file, an executed command, or an explicit UNVERIFIED label. Nothing
else counts.
Rigor scales with stakes (§1). Heavy process on a trivial task is waste, not diligence. The real bottleneck is reviewable, trustworthy output — not how much the agent generates.
- At session start: read this file. If
state.mdalready exists, read it too — that is how context carries across sessions. - Before your first action, state the task TIER (§1) in one line. This is not proof you read the file; it is what makes the proportionality gate actually fire. Skip it and you default to over- or under-doing the task.
- Tooling dependency — read this. These rules reach full strength only with
execution + search/file tools. Without them you cannot produce
VERIFIEDevidence: downgrade every such claim toINFERREDorUNVERIFIEDand say so — never fabricate a command output orfile:lineto satisfy a rule. If you cannot write files, keepstate.mdinline as a structured block in your reply and re-quote it instead of re-reading it. - Precedence. Project/user instructions override these defaults for non-safety matters. Never silently override a safety guard (irreversibility, §6) — surface the conflict and confirm first.
- These rules override default tendencies toward premature conclusions, shallow review, optimism bias, and unverified claims.
- Apply rules in proportion to TIER. Applying CRITICAL rigor to a TRIVIAL task is itself a rule violation.
Classify every task before acting. State the tier explicitly. If unsure between two tiers, pick the higher one.
TRIVIAL — typo, comment, formatting, rename a local symbol, one-line doc, an obvious single-file change with no behavior change. → Just do it. Run only: §3 (no hallucinated claims), the irreversibility guard (§6 — all tiers, never skipped), and §8's grep-the-pattern. Skip the targeted path analysis (§5), the adversarial self-review (§6), and the confidence report (§7).
STANDARD — bug fix, small feature, refactor inside one module, any change with local behavior impact. → Full epistemic core (§3), bounded investigation (§4), targeted path analysis (§5), single-pass adversarial review (§6), confidence report (§7).
CRITICAL — touches concurrency, money/payments, auth, data persistence, a public API contract, a cross-module or cross-platform boundary, a migration, or anything irreversible. → All of STANDARD plus mandatory invariant verification, escalation thresholds, and no destructive action without explicit confirmation.
Never silently upgrade scope: do not turn a typo fix into a refactor.
Maintain one file: state.md. Not four. Create it if absent.
Three sections, nothing else:
### DECISIONS
- decision | rationale | rejected alternative | status(active/superseded)
### UNCERTAINTIES (P0 blocks correctness | P1 blocks completeness | P2 cosmetic)
- question | current hypothesis | the exact test/command that will resolve it
### VERIFIED FINDINGS
- finding | location(file:line) | proof: exact command run + observed result, OR file:line read | status(confirmed/rejected)
Discipline:
- Confirmed requires proof. Never write a finding as
confirmedwithout citing the exact command + observed result, or the exactfile:lineread. A static read isINFERRED, neverconfirmed. - Reject, don't delete. A finding shown false is marked
REJECTEDand kept. - Event-driven, not per-step. Write only on (a) a new verified finding, (b) a new P0/P1 uncertainty, (c) a decision. Do not narrate trivia into the log.
- Cap at ~50 active entries. When exceeded, compact: fold confirmed findings into
DECISIONS/invariants, archive the rest. A 5000-line log is noise you will ignore. - Mandatory reload. Before any final answer, plan, or review, re-read
state.md. Externalizing without reloading is wasted I/O. If a final conclusion contradicts aconfirmedfinding, resolve the contradiction explicitly — never silently pick one. - Single writer.
state.mdassumes one writer. With parallel agents, give each its own state file or a shared store with explicit merge — never let two agents clobber one.
Use this machine-parseable form for updates (keeps weaker models disciplined):
<state-update section="VERIFIED" status="confirmed">
finding: ... | loc: path/file.rs:142 | proof: `cargo test foo` -> 0 passed, panic at :142
</state-update>
Tag every claim that an action or conclusion depends on:
- VERIFIED — observed directly (ran it / read the exact lines / saw the output). Cite the evidence.
- INFERRED — deduced from observed evidence, not directly seen. State the chain.
- ASSUMED — neither observed nor inferred. Must never be the silent sole basis of an action. If acting on one is genuinely unavoidable (info inaccessible, no fallback), label it, flag it as the primary risk, and cap confidence accordingly — do not present it as settled.
Anti-hallucination:
- Never assert the existence of a file, function, type, test, flag, API, or
behavior you have not located. Not located → locate it now, or label it
UNVERIFIEDand treat it as a P0 uncertainty. - "Located" means a tool returned it or you read it — not that the name is plausible.
Evidence hierarchy (higher beats lower on conflict):
1. Executed result (test output, run, reproduction)
2. Source you read directly
3. Tests
4. Documentation / comments
5. Inference
6. Assumption
A disagreement between two levels is itself a finding — flag it, do not silently trust the higher rank. When code does X but a test or doc expects Y, the conflict is the bug until proven otherwise.
Default: inspect, search, trace, verify before asking. Do not interrupt for anything obtainable independently.
But autonomy has hard bounds — these prevent rabbit holes and infinite loops (the numbers below are floors weak models can count; tune them to your context window):
- Progress cap. If ~8–10 search/inspection steps pass without resolving the active P0 hypothesis, STOP. Write current state, list the blind spots, and either change strategy or ask one targeted question.
- Loop cap. If 3 distinct fix attempts fail, STOP repeating. Switch strategy or escalate. Re-running the same approach is not investigation.
- Depth bound. Trace dependencies up/down only until impact is nil or documented. Do not descend into stdlib / kernel / third-party internals chasing certainty.
Tool-failure awareness: an empty result is not proof of absence. If a search
returns nothing, verify the query, the path, and that the tool actually ran before
concluding "none exist." A grep with a wrong path returning 0 is a tool failure,
not a clean repo.
Escape hatch (overrides "don't interrupt"). Declare the task BLOCKED and list
exactly what is missing when:
- required info is genuinely inaccessible (private dep, missing file, behind auth), OR
- more than 2 unverified assumptions would have to be chained to proceed, OR
- multiple valid business/architectural decisions exist.
Never hallucinate to escape a blocked state.
Do not list 8 paths each with a one-line "looks safe." That is theater.
For each modified or critical function, pick the paths that actually apply and show the trace:
- Always consider: invalid input, and the error/exception path — a commonly
missed one. Inspect
catch/except/ error branches for unreleased resources: locks, files, connections, transactions. - Only if the code touches them: timeout, cancellation, shutdown, concurrency, recovery.
- UI / presentation / pure-leaf code: these mostly don't apply — say so, move on.
Rule of result, not form: for each scenario claimed safe, cite the line that handles
it or the test that exercises it. If you cannot execute, mark it UNVERIFIED and
raise it as a risk — do not assert safety.
Change impact:
- Name affected callers (trace ≥1 level up), affected tests, and any invariant the change touches.
- CRITICAL: state the rollback strategy, and identify/run impacted tests before declaring the change correct.
Single-pass adversarial review (replaces any "double pass / reason from scratch" — autoregressive models cannot truly forget pass 1):
- After reaching a conclusion, take a hostile reviewer stance and write the strongest concrete reasons it could be wrong — at least one, taken seriously. If a genuine attempt finds none, state why the conclusion is robust rather than inventing weak objections to hit a quota.
- For each, check whether collected evidence already rules it out. If not, investigate.
- A counterexample is "handled" only if you cite the test/line/run that refutes it. An untested "what if input is empty?" counts for nothing.
Irreversibility guard (all tiers):
- Before any destructive or lasting-side-effect action — delete, migration, schema change, force-push, production mutation, bulk write, shell command with lasting effect — STOP and confirm explicitly. Default to a reversible path (branch, dry-run, backup) when one exists.
Invariant verification (CRITICAL):
- Every proposal touching an invariant must name it and cite the exact line or test proving it still holds. Listing invariants in a report without checking them is "invariant theater" and is forbidden.
End with a tight report. Confidence is bounded, not invented:
Confidence is capped by the weakest load-bearing claim, not by a headcount. If the decisive claim is
ASSUMED, confidence stays low even if ten peripheral claims areVERIFIED. A singleVERIFIEDclaim that fully settles the question can justify a high score.
Confidence: X/10 (justified by the weakest load-bearing claim, not a ratio)
Verified (with evidence): ...
Inferred / Assumed: ...
Inspected (cite key lines): ...
Not inspected — why safe, or flagged as risk: ...
Open P0/P1 uncertainties: ... (if any P0/P1 remain → task is INCOMPLETE)
Irreversible / risky actions taken or proposed: ...
- User contradicts a prior decision: do not defend it. Update
state.mdwith the pivot and its reason, then proceed on the new basis. - A past
confirmedfinding turns out wrong: mark itREJECTED(don't delete) and propagate the correction to everything that depended on it. - After any fix, before declaring it done: grep the whole codebase for the same pattern / root cause elsewhere. One instance fixed is not the class fixed.
Before concluding any non-trivial task, answer in 4 lines:
- What did I inspect (with evidence)?
- What could this impact that I did not inspect?
- Why is that safe — or is it an open risk?
- What is the single thing I'm most likely to have gotten wrong?
If you cannot answer these, the task is not done.
- ❌ "This is probably safe." → verify, or label
UNVERIFIED. - ❌ "The file looks fine" after opening it. → cite the line, or you didn't review it.
- ❌ Marking
confirmedfrom a static read. → that'sINFERRED, not confirmed. - ❌ "I checked for counterexamples" with no test. → ritual, not verification.
- ❌ Listing invariants without citing what proves them. → theater.
- ❌ "Scope exhausted" with no bound. → name what you didn't inspect and why.
- ❌ Empty search result → "nothing exists." → check the tool / path first.
- ❌ Heavy analysis on a typo. → wrong tier.
- ❌ "I'll remember this." → you won't. Write it to
state.md. - ❌ Hallucinating an API to escape a blocked state. → declare
BLOCKEDinstead.