PAI Enforcement Map
This file is the system patching itself. Every constitutional rule in PAI_SYSTEM_PROMPT.md, CLAUDE.md, or doctrine files should appear here with its enforcement column populated.
Status legend:
- ENFORCED — a hook, shim, or other deterministic mechanism blocks or transforms the violating behavior.
- GAP — a mechanism exists for one or more engines but not the full set named in the rule’s scope.
- ASPIRATIONAL — only prose; no deterministic enforcement. Surfaced here so it can be promoted to ENFORCED or honestly demoted.
Engine legend:
- PNC — Claude Code (Anthropic, primary)
- PNK — opencode (CLI binary
opencode) - PNX — codex (CLI binary
codex) - PNG — antigravity / agy (Google,
agybinary, replaced Gemini CLI 2026-05-25) - PNO — Ollama local models (via
PAI/Tools/Inference.ts) - subagents — Agent-tool-spawned sub-tasks inside PNC
Identity & Fabrication
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
DA identity must match settings.json daidentity.name | PAI_SYSTEM_PROMPT.md Honesty section | IdentityValidator.hook.ts (Stop, SubagentStop) calls HonestyValidator.ts. 2026-05-28: structural enforcement closed — hook now emits Claude Code Stop-hook {"decision":"block","reason":"..."} JSON on stdout when verdict=fail (previously exit 2 only, which surfaces stderr but does NOT force regeneration — that’s why “block” mode was still letting Kai through). Reason text quotes the canonical DA name verbatim from cached settings.json and instructs explicit rewrite of the 🗣️ closing line. Anti-pingpong via stop_hook_active (Claude Code’s built-in flag) — second-pass failure exits 2 stderr-only with action: loop-detected telemetry. Rollout switch in honesty-ramp.json → block_emit_decision_json (default true) lets principal revert to stderr-only “loud warn” mode without code change. Signature regex anchored to last 600 chars of code-fence-stripped text — historical token quotes in body prose no longer false-positive. Per-Stop telemetry at ~/MEMORY/STATE.claude/identity-validator-actions.jsonl (one row per fire: pass / bypassed / warn-only / block-emitted / block-stderr-only / loop-detected / fail-open). pai-guard.ts --honesty post-exec validates non-interactive PNK (opencode), PNG (agy), and PNX (codex) output via same ramp. 2026-05-28 (later same day): PNO standalone covered via in-process integration at Inference.ts:inferenceOllama → hooks/lib/inference-honesty.ts — every ollama dispatch prepends canonical identity-pin to the system prompt (rendering caller-provided placeholders via identity-template) and runs HonestyValidator on the response, logging to honesty-shim.jsonl with source:'inference:ollama', engine:'PNO'. Fail-OPEN on validator/identity errors. The original Phase B plan called for a PAI/bin/llm PATH shim; replaced with in-process integration as a cleaner architecture (no bun-on-bun spawn, no PATH resolution). | PNC + subagents + PNK + PNG + PNX + PNO (standalone) | ENFORCED — block-and-regenerate for identity-mismatch on PNC + subagents (decision:block JSON forces regeneration). PNK + PNG + PNX shim path returns verdict=fail and surfaces BLOCK banner. PNO standalone now ENFORCED — warn (identity-pin injected pre-call; output validated post-call; shim telemetry written). NOTE: extending block-and-regenerate to fabricated-path and unsourced-claim kinds is now a single ramp.json edit away — both are in disabled_kinds; removing them lets the fixed primitive carry them through automatically once their telemetry is calibrated. | 2026-05-28T15:50Z |
| Identity tokens retrieved, not generated | PAI_SYSTEM_PROMPT.md Honesty section | SessionStart.hook.ts + AgentStart.hook.ts inject identity-pin into context. 2026-05-28: hooks/lib/identity-template.ts substitution layer added — LoadContext.hook.ts now resolves {{DA_NAME}}, {{DA_FULL_NAME}}, {{PRINCIPAL_NAME}}, {{PRINCIPAL_FULL_NAME}} placeholders against getIdentity()/getPrincipal() before injecting any loadAtStartup file. Fail-loud on unresolved tokens (preserves literal + stderr warn). Previously placeholders were aspirational doctrine — the model received literal {{DA_NAME}} strings because no renderer existed. End-to-end test against PAI_SYSTEM_PROMPT.md: all 26 placeholders resolve correctly (9 Nova / 17 Duane after substitution, 0 placeholders remaining). | PNC + subagents | ENFORCED (PNC injection pin + substitution layer for loadAtStartup files) / GAP (other engines; skill-tool load path also bypasses LoadContext — separate follow-up) | 2026-05-28T15:42Z |
| Identity placeholders in doctrine files resolved before injection | Phase B Tier 2 doctrine | hooks/lib/identity-template.ts renderer applied in LoadContext.hook.ts:loadStartupFiles() before pushing to context parts. Fail-loud preserves literal {{TOKEN}} and writes stderr warning when canonical identity is missing — silent empty-string substitution prevented by design. | PNC | ENFORCED for loadAtStartup files / GAP for Skill-tool-loaded markdown (skill load path is separate) | 2026-05-28T15:42Z |
| Identity files pinned at session start | settings.json loadAtStartup + postCompactRestore.fullFiles | Harness loads + restores on compaction | PNC only | ENFORCED (PNC) / N/A (other engines have own startup) | 2026-05-26 |
| Confident claims must be sourced | PAI_SYSTEM_PROMPT.md Honesty section | HonestyValidator.scanUnsourcedPathClaims (path-class MVP) cross-references claimed paths against hooks/lib/claim-attribution.ts getTouchedPathsForSession() which reads MEMORY/OBSERVABILITY/tool-activity.jsonl filtered by session_id. Full-file scan (not bounded-tail — advisor concern: long sessions where probes age out before being claimed). Past-tense verb patterns only (“Read”, “Found at”, “Verified at”, “defined in”, “located at”) — imperative-future suppressed. No double-flag: scanPaths’ fabricated-path findings preempt unsourced-claim emission. Finding payload includes ±60 chars surrounding context. Fail-OPEN with claim_attribution_log_unreadable counter in honesty-validator-stats.json per advisor concern. unsourced-claim kind stays in disabled_kinds (warn-only telemetry; never flips verdict to fail). Symbol-class and URL-class claim attribution remain GAP. | PNC | ENFORCED — warn (path-class only, MVP). GAP for symbol/URL classes. Promotion of unsourced-claim to block-mode requires separate doctrine update with measured FP-rate gate (advisor concern: 7-day calendar gate is theater, must be telemetry-gated). Known limitations documented in claim-attribution.ts header: Bash argv path extraction not implemented (FN for grep/find/cat-only probes); relative-path normalization not implemented; subagent session_id attribution unverified. | 2026-05-28T16:05Z |
| Success-claims must match the tool-call log (anti-placation) | PAI_SYSTEM_PROMPT.md Honesty enforcement Layer 3; upstream PAI #1303 | ClaimAttributionScan.hook.ts (Stop, top-level only; wired in hooks/dispatch/Stop.ts). Scans last_assistant_message for high-confidence success-claims (email/message sent, deployed, committed/pushed, file-written) and cross-checks the session transcript’s tool_use log for a corroborating call (by tool name OR by command-text pattern). A claim with no corroboration → finding appended to MEMORY/LEARNING/HONESTY/claim-attribution.jsonl. Strict fail-open: try/catch → exit 0 on any error, NEVER blocks/exits non-zero, honors PAI_HONESTY_BYPASS=1, skips SubagentStop, bounded message (100K) + transcript-tail (2MB) + linear-time regex. Distinct from the path-class scanner above (this is the success-claim/action class). Known limits (Cato audit 2026-06-05): transcript tool extraction is regex-over-tail (not JSONL parse) — tolerant of partial tails, may FN/FP at the margins; heuristic claim set is deliberately conservative for low FP during ramp. | PNC | ENFORCED — warn-only (telemetry). Block-mode never appropriate for a Stop hook without extreme care; promotion requires measured precision from the jsonl, not a calendar gate. | 2026-06-05T22:05Z |
| No fabrication in memory writes | PAI_SYSTEM_PROMPT.md Honesty section | MemoryWriteHonestyGate.hook.ts PreToolUse on Write/Edit/MultiEdit to PAI/MEMORY/KNOWLEDGE/**, PAI/USER/**, CLAUDE.md, PAI_SYSTEM_PROMPT.md, ENFORCEMENT_MAP.md calling HonestyValidator. Block-mode now supported via quarantine workflow: when env var PAI_MEMORY_QUARANTINE_ENABLED=1 AND ramp=block AND finding kind not in disabled_kinds, content is written to ~/MEMORY/STATE.claude/honesty-quarantine/<id>.json instead of the target path; original Write blocks with exit 2. Operator releases or discards via bun PAI/Tools/PaiQuarantine.ts list/show/release/discard/purge. When opt-in OFF (default), hook stays warn-only (backward compatible). | PNC | ENFORCED — warn (default, no env var); ENFORCED — block-with-quarantine (when PAI_MEMORY_QUARANTINE_ENABLED=1 AND ramp=block AND kind not disabled). | 2026-05-27 |
| No fabrication in inter-engine handoffs | PAI_SYSTEM_PROMPT.md Honesty section | TWO TIERS: (1) Proactive pre-dispatch: ~/OmniPulse/handoffs.ts prevalidateHandoff() runs HonestyValidator on the outgoing prompt before write. 2026-05-28 Phase B Tier 2 chunk 3: gate INVERTED to opt-OUT (default-ON) — runs on every dispatch; bypass via PAI_OMNIPULSE_PREVALIDATE=0 (or =false). Plus: outgoing prompt rendered through identity-template (renderIdentityInHandoffPrompt) BEFORE validation AND write — receiving engines see canonical “Nova”/“Duane” instead of {{DA_NAME}}/{{PRINCIPAL_NAME}} literals. Single artifact (rendered prompt is what gets validated AND written — no drift). Cross-repo strategy: dynamic require of central hooks/lib/identity-template.ts when present; inline regex fallback for {{DA_NAME}}/{{PRINCIPAL_NAME}} via settings.json read when module unavailable; fail-OPEN on both paths (preserves placeholders rather than emitting empty). Aborts dispatch with started: false + error when verdict=fail; logs prevalidate_blocked events. Symmetric telemetry added 2026-05-28: prevalidate_passed event written for non-fail verdicts so observability surface isn’t blocks-only (required for measured FP-rate ramp decisions). (2) Retrospective audit: PAI/Tools/OmniPulseHonestyAudit.ts validates handoff prompts AND logs post-hoc, writes per-handoff .honesty.json sidecars, exits 2 on any would-block finding. | PNC (both tiers) | ENFORCED — proactive (DEFAULT-ON, blocks pre-dispatch, identity-pin rendered) + retrospective audit (always runs on demand). | 2026-05-28T16:08Z |
| Honesty enforcement observability | Phase B Tier 2 chunk 4 doctrine | PAI/Tools/HonestyReport.ts rollup CLI — bun PAI/Tools/HonestyReport.ts [--since N] [--engine X] [--json] [--promote]. Reads 7 telemetry sources: honesty-telemetry.jsonl, honesty-shim.jsonl, honesty-bypass.jsonl, honesty-ramp.json, NEW 2026-05-28: identity-validator-actions.jsonl (per-Stop hook action), honesty-validator-stats.json (claim-attribution log-unreadable counter), omnipulse-handoffs/events.jsonl (prevalidate_passed/blocked). Outputs per-engine breakdown, shim activity, bypass activity, Stop-hook action distribution (pass/block-emitted/loop-detected/etc.), claim-attribution health, handoff prevalidate counts. JSON mode is the Pulse-consumable surface (TOML module to poll it is deferred — JSON output is the structural lever). Fail-OPEN per source: missing file → zero/empty aggregate. Exit code 2 informational when ramp promotion criteria met. | PNC | ENFORCED — observability live across all 7 sources. NOTE: Pulse dashboard widget integration deferred (JSON output is consumable; TOML module wrapping is decorative follow-up). | 2026-05-28T17:15Z |
Destructive Operations
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
No rm -rf / force-push to main / claude --bare / known destructive + cost-leak patterns | destructive-patterns.json | DestructiveOpGuard.hook.ts (PNC) + pai-guard.ts PATH shims (other engines) | PNC + PNK + PNX + PNG + PNO (via shell shims) | ENFORCED | 2026-05-27 |
| Override flow with TOTP + voice confirm | MemoryPromoter.ts | Dual-factor approval gate | PNC | ENFORCED (PNC) / N/A (override is principal-only) | 2026-05-26 |
| Pattern registry promotion | MemoPromotionExtractor.hook.ts | PostToolUse extracts → validator → SessionStart approval | PNC | ENFORCED | 2026-05-26 |
Path Containment
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| No hardcoded user-home paths in PAI files | CLAUDE.md ~/.claude private rules | ContainmentGuard.hook.ts (PreToolUse on Write/Edit) | PNC | ENFORCED (PNC) / GAP (PNK, PNX, PNG, PNO can write paths via shell) | 2026-05-26 |
~/.claude never pushed to public remote | PAI_SYSTEM_PROMPT.md privacy section | Release skill scrub + manual git remote review | PNC | GAP (relies on discipline + skill; no pre-push hook yet) | 2026-05-26 |
Output Format
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| Every response uses MINIMAL / NATIVE / ALGORITHM template | CLAUDE.md + PAI_SYSTEM_PROMPT.md | FormatComplianceScan.hook.ts (Stop, via dispatch/Stop.ts) — WARN-ONLY gauge: logs header-present + closing-present (ALGORITHM=SUMMARY 7/7 block + 🗣️; NATIVE=🗣️; MINIMAL lenient) per Stop to ~/MEMORY/STATE.claude/format-compliance.jsonl with raw lines; UNKNOWN bucketed (not scored); never blocks. IdentityValidator.hook.ts additionally validates the 🗣️ identity token. (Erratum 2026-06-13: the prior “FormatReminder.hook.ts (Stop) ENFORCED” entry was wrong on all axes — FormatReminder runs on UserPromptSubmit doing capability classification, not format compliance; it was stale at Algorithm v3.7.0.) | PNC | MEASURED (warn-only baseline live 2026-06-13) — escalation to a block/nudge is gated on a measured FP-rate over soak (mirrors honesty-ramp.json); N/A other engines | 2026-06-13 |
| Mode + Tier from classifier | PAI_SYSTEM_PROMPT.md Mode Architecture | PromptProcessing.hook.ts (UserPromptSubmit) | PNC | ENFORCED | 2026-05-26 |
| Algorithm phase transitions emit ISA phase edits | Algorithm/v5.7.2.md | PhaseTransitionGate.hook.ts (PreToolUse on ISA edit) + ISASync.hook.ts (PostToolUse) | PNC | ENFORCED | 2026-05-26 |
Secrets / Privacy
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| No secrets in output | PAI_SYSTEM_PROMPT.md Security Protocol | OutputSecretsScanner.hook.ts (Stop) | PNC | ENFORCED (PNC) / GAP (other engines) | 2026-05-26 |
| Customer/user data protected | PAI_SYSTEM_PROMPT.md Security Boundaries | Discipline + permission deny rules in settings.json | PNC | GAP — partial; relies on path-deny + agent boundary | 2026-05-26 |
| Prompt injection rejection | PAI_SYSTEM_PROMPT.md Security Protocol | ContentInjectionScanner.hook.ts + UnicodeInjectionScanner.hook.ts | PNC | ENFORCED (PNC) / GAP (other engines) | 2026-05-26 |
| OAuth scrubbing for non-principal channels | PAI_SYSTEM_PROMPT.md Personal Use Boundary | Channel-level env-var rules + code review + destructive-patterns.json claude-bare-billing-leak pattern blocks claude --bare Bash invocations across PNC and shells (DestructiveOpGuard + pai-guard) | code paths that spawn claude | GAP → ENFORCED-partial: the --bare flag is now blocked, but the broader rule “non-principal channels must set ANTHROPIC_API_KEY and not delete it; principal channels must delete it” still relies on discipline. Pattern enforcement covers the worst documented failure mode ($498 incident); the env-var-hygiene check across spawn sites remains GAP. | 2026-05-27 |
Sandbox Confinement
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| No guessed host / IP / asset-name enters PAI code/config | 2026-06-14 trust incident (guessed anthropic.com; later, NAS IP + asset names typed from memory) | pai-provenance.ts scan --staged (pre-commit) flags three classes ADDED to a code/config file (prose .md excluded): (1) public hostnames/URLs, (2) IP addresses (excl. loopback/0.0.0.0/link-local), (3) asset names in ssh/scp/rsync/sftp/smbclient host position (stopword-guarded against prose). Passes only if loopback/reserved, in a sourced registry, observation-backed, or provenance:-marked. Asset registry seeded from canonical ASSET_REGISTRY.md + ~/.ssh/config (re-seeded each commit). Changed-lines-only. Fail-injection verified for all 3 classes: guessed host/IP/ssh nonexistent-node/scp madebox: → exit 1; reserved/loopback/marked/registered pai-primary → pass; prose ssh into the box → pass. | PNC (commit-time, PAI-wide) | ENFORCED — host, IP, and asset-name guesses are all un-committable. | 2026-06-14 |
| Known infra/environment facts resolved, never recalled | 2026-06-14 trust incident (recalled NAS IP / API host) | READ path: pai-infra.ts resolve <ip/name/port/mount> returns the sourced fact + provenance, or UNKNOWN — DO NOT GUESS; probe: <hint> (exit 1). Registry infra-registry.json synced from canonical ASSET_REGISTRY.md + live probes (ss -ltn ports, /proc/mounts, ssh config). Verified: resolve pai-primary → sourced IPs; unknown name + unknown IP → refuse-to-guess. Constitutional rule added (PAI_SYSTEM_PROMPT.md Operational Rules). | PNC + agent discipline | ENFORCED (read path) — resolver refuses to guess; behavioral rule binds the agent. WRITE path is the provenance gate above. | 2026-06-14 |
| Sandbox egress allowlist hosts must be observation-backed | 2026-06-14 | pai-egress-provenance.ts check: every pinned host in egress-allowlist.ts traces to egress-observed/<engine>.json (discovered via PAI_EGRESS_OBSERVE=1). Wired into pre-commit. Fail-injection verified (pinned-but-unobserved → exit 1). | PNC (commit-time) | ENFORCED | 2026-06-14 |
| Engine FS confinement (deny-all bind allowlist) | Phase 1 (20260614-141500_sandbox-egress-scope) | PAI/bin/pai-sandbox.sh (bwrap) via pai-guard.ts resolveSpawn opt-in PAI_SANDBOX=1; opencode + codex profiles. Verified: secrets.env/age key ENOENT inside; engines functional. | PNC (opt-in) | ENFORCED (opt-in; not default-on pending soak) | 2026-06-14 |
| Engine egress confinement (netns + allowlist proxy) | Phase 2 | pai-egress-proxy.ts (allowlist CONNECT proxy) + pai-egress-relay.ts (in-namespace) via --egress, opt-in PAI_SANDBOX_EGRESS=1. Verified end-to-end (allow/deny/bypass) + opencode functional. | PNC (opt-in, opencode) | ENFORCED for opencode (opt-in); codex hosts undiscovered (no guess) | 2026-06-14 |
| Unsourced factual tokens — remaining classes | PAI_SYSTEM_PROMPT.md Honesty floor | Hosts, IPs, and ssh-context asset names in PAI code/config are now mechanized (provenance scan, above). STILL discipline-only: (a) ports, version strings, and other config values/magic numbers; (b) asset names used OUTSIDE ssh/scp host syntax (bare identifiers); (c) infra references in prose .md. | — | GAP (honest, narrowed) — candidate next: version-string class + a docs-aware narrative check | 2026-06-14 |
Algorithm Doctrine
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| Live-probe verification (Rule 1) | Algorithm/v5.7.2.md | Discipline + Inline Verification mandate + Stop-time audit | PNC | ENFORCED (audit catches violations post-hoc) / GAP (no pre-emit block) | 2026-05-26 |
| Advisor at PLAN→BUILD (Rule 2) | Algorithm/v5.7.2.md | PhaseTransitionGate.hook.ts blocks phase: build edit absent advisor/skip block | PNC | ENFORCED | 2026-05-26 |
| Cato cross-vendor audit (Rule 2a) at E4/E5 | Algorithm/v5.7.2.md | Cato agent + CrossVendorAudit.ts | PNC | ENFORCED (when invoked); no automatic trigger | 2026-05-26 |
| Re-Read check final gate | Algorithm/v5.7.2.md | Discipline + Stop-time audit | PNC | GAP (no pre-emit block) | 2026-05-26 |
| Capability binding (no phantom) | Algorithm/v5.7.2.md | Discipline + VERIFY-phase audit | PNC | GAP (audit catches post-hoc) | 2026-05-26 |
Budget & Cost
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| Per-window budget tracking | CLAUDE.md | BudgetGuard.hook.ts reads UsageProbe.ts canonical OAuth endpoint | PNC | ENFORCED | 2026-05-26 |
| OAuth subprocess flag scrubbing | CLAUDE.md Operational Rules | Code review + delete env.ANTHROPIC_API_KEY pattern in Inference.ts | code paths | GAP (no PreToolUse Bash scan for claude --bare) | 2026-05-26 |
Operational Conventions
| Rule | Source | Mechanism | Engine Coverage | Status | Last Audited |
|---|---|---|---|---|---|
| bun / bunx always, never npm / npx | CLAUDE.md Operational Rules | RTK proxy auto-rewrite for some commands; no hook block for npm direct | PNC | GAP (RTK partial; no PreToolUse Bash block on npm) | 2026-05-26 |
| TypeScript always, no Python without approval | CLAUDE.md Operational Rules | Discipline | none | ASPIRATIONAL | 2026-05-26 |
| Markdown over HTML | CLAUDE.md Operational Rules | Discipline | none | ASPIRATIONAL | 2026-05-26 |
~/.claude commits direct to main, no branches | CLAUDE.md Operational Rules | Discipline | none | ASPIRATIONAL (could add PreToolUse on git branch in ~/.claude) | 2026-05-26 |
How to Add a New Rule
- Write the rule in its canonical source file (
PAI_SYSTEM_PROMPT.md,CLAUDE.md, or a doctrine file). - Decide its enforcement class using this matrix:
| If the rule is… | Build… |
|---|---|
| A fact that shouldn’t change | A loadAtStartup pin |
| A tool-call pattern (block / rewrite) | A PreToolUse hook |
| An output format / content constraint | A Stop or SubagentStop hook |
| A path / permission boundary | A permissions.deny entry + ContainmentGuard-style hook |
| A cross-engine requirement | A PAI/bin/ PATH shim wrapping the engine binary |
| A memory/state write gate | A PreToolUse on Write/Edit matching path |
- Build the mechanism. Add tests. Wire into
settings.jsonevent arrays (PNC) or~/.bashrcPATH (other engines). - Add a row to this file with all six columns populated. If you can’t fill the mechanism column, mark the row
ASPIRATIONALhonestly — don’t leave it ENFORCED-by-implication. - Run
bun PAI/Tools/EnforcementMapAudit.ts(forthcoming Phase B tool) to confirm every rule in source files has a row here.
How to Demote an Aspirational Rule
If a rule has been ASPIRATIONAL for >90 days with no enforcement mechanism, raise it for one of:
- Promotion — build the mechanism and update the row.
- Demotion — move the rule to a “preferences” or “discipline” section in its source file so its status is honest. Aspirational rules masquerading as enforced rules are themselves a form of system-level fabrication.
Audit Schedule
A full audit (all rows re-checked, last_audited dates updated) should run quarterly or after any significant doctrine change. Append audit_log entries below.
Audit Log
- 2026-05-26 — Initial creation. Rows populated from grep of PAI_SYSTEM_PROMPT.md + CLAUDE.md + Algorithm/v5.7.2.md. Honesty enforcement section added Phase A; cross-engine gaps explicitly marked GAP/ASPIRATIONAL for Phase B promotion.
- 2026-05-26 (later) — Cato cross-vendor audit (codex GPT-5) returned verdict=fail with 5 critical findings against the initial Phase A. Addressed inline before
phase: complete: doctrine claim of “universal coverage” replaced with staged-coverage table; source-of-truth split (DAIDENTITY.md vs settings.json) resolved by declaring settings.json canonical and demoting markdown to descriptive; bypass posture changed frompasstowarnto prevent self-defeating escape; warn-only ramp now reads from~/MEMORY/STATE.claude/honesty-ramp.jsonso promotion is one file edit (and the gating criteria are documented in the file itself). Latent SETTINGS_PATH bug inhooks/lib/identity.tsgetObservabilityConfig fixed. Tests updated to match new bypass verdict semantics — 12/12 passing. - 2026-05-26 (later still) — Phase B Tier 1: extended
pai-guard.tswith--honestymode per advisor’s strong recommendation (rejected the parallel bash-shim approach). Installed shims atPAI/bin/opencodeandPAI/bin/agy. Cross-engine honesty enforcement now ENFORCED for PNK and PNG non-interactive invocations (opencode run/--print/--prompt,agy --print/-p/--prompt). Interactive TUI/REPL paths pass through pristinely — capture XOR passthrough decision at entry, no PTY breakage. 11/11 shim tests passing. PAI/bin/README.md created with full operator documentation. Remaining gaps: PNX codex (existing bash shim doesn’t use pai-guard pattern), PNO ollama via Inference.ts (Phase B Tier 2). - 2026-05-26 (Phase B Tier 2) — Closed PNX gap: refactored
PAI/bin/codexto delegate topai-guard.ts --honestywhile preserving the AssetRegistrySync side-effect. Added codex’s non-interactive surface (exec,e,review,apply,a) toNON_INTERACTIVE_PATTERNS. End-to-end verified:codex exectriggers[PAI honesty:PNX]finding on fabricated output;codex --helppasses through unchanged. PNO standalone-invocation gap honestly framed as residual — primary Inference.ts invocations come from PNC where the Stop hook already covers identity fabrication; standalone-shell invocations of Inference.ts are the small residual surface, deferred to a future tier rather than over-engineering a syntheticllmshim. - 2026-05-26 (Phase B Tier 3) — Shipped
PAI/Tools/HonestyReport.ts: rollup tool reading honesty-{telemetry,shim,bypass}.jsonl + honesty-ramp.json. Per-engine breakdown, ramp evaluation against documented criteria, promotion-command emitter. Closes the “warn-only ramp is permanent without observability” failure mode. Verified against 28 invocations across PNC + 5 engines; ramp correctly holds at warn (0.9h elapsed of 24h required). - 2026-05-26 (Phase B Tier 4) — Extended HonestyValidator with file-path fabrication detection (claim attribution v0). New finding kind
fabricated-path. PATH_PATTERNS targets backtick-absolute and “at/in/file /path” forms. Denylist covers transient prefixes (/tmp, /proc, /sys), example placeholders, URLs, single-segment paths, code-fenced examples. Tilde expansion + dedup. Tests 12 → 24, all passing. Coverage now: identity tokens ENFORCED for PNC + subagents + PNK + PNG + PNX; file-path claims ENFORCED everywhere the validator runs. - 2026-05-26 (Phase B Tier 5) — Shipped
MemoryWriteHonestyGate.hook.tsPreToolUse on Write/Edit/MultiEdit. Closes the “fabrication persisted to disk outlives the session” failure mode. Targets PAI/MEMORY/KNOWLEDGE/, PAI/USER/, CLAUDE.md, PAI_SYSTEM_PROMPT.md, ENFORCEMENT_MAP.md. Validates content against HonestyValidator before write completes; surfaces findings to stderr (visible to user) in warn-only ramp. Promotion to block-mode via the same ramp file as IdentityValidator. Memory-write rule promoted in this map from ASPIRATIONAL to ENFORCED. - 2026-05-26T23:10Z (deferred-debt closure) — Closed the hardcoded
--warn-onlydebt inpai-guard.tsflagged by the Phase A+ promotion. Shim now importsisWarnOnly()fromhooks/lib/honesty-ramp.ts(the same module IdentityValidator + HonestyValidator share) and passes--warn-onlyto the validator conditionally. With ramp=block + disabled_kinds=[fabricated-path, unsourced-claim], identity-mismatch on PNK/PNG/PNX shim-captured output now returns verdict=fail and surfaces a BLOCK banner; fabricated-path stays WARN per the per-kind filter. Validator stdout parsed in both exit-0 and exit-2 paths so block findings actually display. Telemetry now carriesramp_modeso HonestyReport can attribute findings per call. Fail-mode preserved: ramp lib unreadable defaults to warn-only. - 2026-05-26T23:10Z (still-deferred design) — Two related semantics deferrals remain, both data-destructive and explicitly tracked rather than rushed:
pai-guard.ts --honestyexit-code override. Shim currently propagates the real binary’s exit status regardless of honesty verdict. When ramp=block and an identity-mismatch is found, downstream automation has no exit-code signal that the output was flagged. Override would change the shape ofagy/opencode/codexexits — needs a documented contract before shipping (e.g. exit 3 = “honesty-block”; opt-in env varPAI_HONESTY_BLOCK_EXIT_CODE?).MemoryWriteHonestyGate.hook.tsblock semantics. Hook is deliberately fixed atALWAYS_WARN_ONLY = trueregardless of ramp. Blocking a memory write is destructive — the user authored content that would silently not save. Promotion needs: (a) quarantine to a side-channel directory + (b) dry-run preview surfacing what would have been blocked + (c) principal confirmation flow to release-or-discard quarantined writes. Tracked at ISC-33 ofMEMORY/WORK/20260526-225254_fix-structural-fact-vs-prior-fabrication/ISA.md.
- 2026-05-26T23:25Z (OmniPulse handoff audit) — Inter-engine handoffs row promoted from ASPIRATIONAL to ENFORCED (audit tier). New tool:
PAI/Tools/OmniPulseHonestyAudit.ts. Validates both outgoing prompts (PNC-authored) and incoming logs (engine responses) via HonestyValidator; writes per-handoff.honesty.jsonsidecars withverdictandwould_block_under_proactive_hookflag. Exit code 2 when any would-block finding present (signal for cron / shell automation). Validator hardening included: newTEMPLATE_PLACEHOLDER_TAILskip inscanIdentityso🗣️ NAME: <placeholder>,[...],{...}template documentation is not flagged as a real identity claim. Surfaced by the initial audit pass: 43 false positives across 83 handoffs all matched the OmniPulse PAI ENGINE INVOCATION CONTRACT template line🗣️ Assistant: <short close>. After detector fix, audit shows 2 real findings (opulse-20260519002304-dok4lfandopulse-20260522044250-776ly9— PNG engine emitted🗣️ Assistant:in actual log responses). Tests grew 24 → 27 (new T13/T14/T15 for placeholder skip). Separate finding from this audit: the OmniPulse handoff template ITSELF uses “🗣️ Assistant:” as its close-line example instead of the canonical “🗣️ Nova:” — that’s actual doctrinal drift in the OmniPulse dispatcher template (not in this commit’s scope; tracked as a documentation-drift finding for a follow-up workstream targeting OmniPulse source). - 2026-05-27 (OmniPulse template drift closed) — Fixed the two template literals in
~/OmniPulse/source flagged by the prior audit:engine-contract.ts:89close-line example changed from🗣️ Assistant: <short close>→🗣️ Nova: <short close>;pai-cli-format.ts:23formatter literal changed from🗣️ Assistant: ${...}→🗣️ Nova: ${...}(with a code comment noting the DA-name coupling). Smoke-testedbuildPaiEnginePrompt— template now emits the canonical name. Past handoffs in the corpus retain the old text (immutable history); future dispatches produce the corrected template. The OmniPulseHonestyAudit tool will continue to surface the old-text findings on historical handoffs until they’re archived, which is the desired behavior — historical accuracy preserved, forward drift closed.~/OmniPulse/is not git-tracked, so this edit is operator-local; the change is the canonical artifact for any future redistribution. - 2026-05-27 (claude —bare cost-leak pattern) — Added the
claude-bare-billing-leakpattern to~/MEMORY/STATE.claude/destructive-patterns.jsonas a manual (non-auto-promoted) entry. Provenance: the April 2026 $498 incident where Pulse heartbeats spawnedclaude --baresubprocesses, bypassed OAuth/keychain, and billed ANTHROPIC_API_KEY. Rule has been in CLAUDE.md Operational Rules since the incident but had no mechanism. Pattern blocks the literalclaude --bareinvocation pattern at PreToolUse (DestructiveOpGuard for PNC Bash; pai-guard.ts PATH shims for shell invocations). Verified against five test commands: positive match on direct +bash -c+ chained invocations; no match onclaude --printwithout--bare. Small false-positive surface on commentary likeecho claude --bare in commentary— acceptable per the override flow. Severity: high, warn_only: false (immediate block). Promoted the OAuth-scrubbing ENFORCEMENT_MAP row from full GAP to GAP→ENFORCED-partial: the--bareflag is now blocked, but the broader env-var-hygiene rule across all spawn sites still relies on discipline. - 2026-05-27 (deferred-debt #1 closed — pai-guard exit override) — Added opt-in env var
PAI_HONESTY_BLOCK_EXIT_CODEtopai-guard.ts. When set to a numeric value AND ramp=block AND real binary exited 0 AND validator returned verdict=fail, shim exits with the env var’s value instead of the real binary’s 0. Default OFF (env var unset → propagate real binary’s exit, no behavior change). All four guards required so the override never overrides a meaningful failure exit code. Smoke-tested: without env var, fabricated opencode output exits 0 (real binary); withPAI_HONESTY_BLOCK_EXIT_CODE=3, same scenario exits 3 with a diagnostic stderr line. Telemetry logsexit_code_overrideevents. Closes one of the two block-semantics deferrals named 2026-05-26T23:10Z. - 2026-05-27 (deferred-debt #2 closed — MemoryWriteHonestyGate quarantine) — Replaced the
ALWAYS_WARN_ONLY = truehardcode with a quarantine workflow gated by env varPAI_MEMORY_QUARANTINE_ENABLED=1. When opt-in is ON AND ramp=block AND a finding’s kind is not indisabled_kinds, the hook writes content to~/MEMORY/STATE.claude/honesty-quarantine/<ISO-ts>-<sha-prefix>.jsonand exits 2 (blocking the original Write/Edit/MultiEdit). Each entry carries: tool_name, target_path, content, findings, blocking_finding_kinds, status (pending/released/discarded), session_id. New operator CLIPAI/Tools/PaiQuarantine.tswith subcommands list/show/release/discard/purge. When opt-in is OFF (default), hook stays warn-only — backward compatible. Release operation backs up any existing target file before writing (audit trail). Discard marks the entry rather than deleting (audit trail preserved). End-to-end verified: opt-in-off → warn exit 0; opt-in-on → block exit 2 with quarantine entry created and operator instructions surfaced. Closes ISC-33 of WORK/20260526-225254_fix-structural-fact-vs-prior-fabrication. - 2026-05-27 (deferred-debt #3 closed — proactive OmniPulse pre-dispatch hook) — Added
prevalidateHandoff()to~/OmniPulse/handoffs.tswhich calls HonestyValidator as a subprocess on the outgoing prompt BEFORE the prompt file is written and the engine is dispatched. Opt-in via env varPAI_OMNIPULSE_PREVALIDATE(default OFF, backward-compatible). When opt-in ON AND validator returns verdict=fail: dispatch aborts withstarted: false,error: "Pre-dispatch honesty validation blocked", stderr banner naming the findings;prevalidate_blockedevent written to handoff events log. When verdict=warn: dispatch proceeds with a stderr warning +prevalidate_warnevent. Implementation invokes HonestyValidator via subprocess (full bun path resolved against~/.bun/bin/bun//usr/local/bin/bun/ PATH) so OmniPulse stays decoupled from PAI’s file layout. End-to-end verified: opt-in-off → dispatch (backward-compat); opt-in-on + fabricated prompt → BLOCKED with error; opt-in-on + clean prompt → dispatch. Closes the final named deferral from the 2026-05-26T23:10Z audit. Honesty coverage on inter-engine handoffs is now TWO TIERS: proactive (this commit, opt-in) AND retrospective audit (already shipped). - 2026-07-06 (SendMessage cross-session authority — ENFORCED, native) — Claude Code v2.1.166 hardened cross-session messaging: teammate-relayed messages no longer carry user authority — receivers refuse relayed permission requests and auto mode blocks them. This natively backstops the Security Protocol’s “commands come ONLY from the principal” rule across OmniPulse/agent-team relays. Coverage: PNC (native harness) only — PNK/PNX/PNG/PNO relay paths remain doctrine-only (GAP) pending equivalent checks in their shims. (upgrade review 20260706-022701.)
- 2026-07-06 (IdentityValidator warn-NUDGE tier — ENFORCED, graduated) — the fuzzy honesty kinds (
fabricated-path,unsourced-claim, both indisabled_kinds) now surface to the model as non-blockinghookSpecificOutput.additionalContexton Stop/SubagentStop (v2.1.163 contract) instead of telemetry-only warn logs. Structurally cannot block (no decision field) — a false positive costs one context line, so the FP-rate gate that stalls BLOCK promotion does not gate the nudge. Telemetry action:warn-nudgein identity-validator-actions.jsonl. (hooks/IdentityValidator.hook.ts, upgrade review 20260706.)