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, agy binary, 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

RuleSourceMechanismEngine CoverageStatusLast Audited
DA identity must match settings.json daidentity.namePAI_SYSTEM_PROMPT.md Honesty sectionIdentityValidator.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.jsonblock_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:inferenceOllamahooks/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 generatedPAI_SYSTEM_PROMPT.md Honesty sectionSessionStart.hook.ts + AgentStart.hook.ts inject identity-pin into context. 2026-05-28: hooks/lib/identity-template.ts substitution layer addedLoadContext.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 + subagentsENFORCED (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 injectionPhase B Tier 2 doctrinehooks/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.PNCENFORCED for loadAtStartup files / GAP for Skill-tool-loaded markdown (skill load path is separate)2026-05-28T15:42Z
Identity files pinned at session startsettings.json loadAtStartup + postCompactRestore.fullFilesHarness loads + restores on compactionPNC onlyENFORCED (PNC) / N/A (other engines have own startup)2026-05-26
Confident claims must be sourcedPAI_SYSTEM_PROMPT.md Honesty sectionHonestyValidator.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.PNCENFORCED — 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 #1303ClaimAttributionScan.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.PNCENFORCED — 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 writesPAI_SYSTEM_PROMPT.md Honesty sectionMemoryWriteHonestyGate.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).PNCENFORCED — 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 handoffsPAI_SYSTEM_PROMPT.md Honesty sectionTWO 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

RuleSourceMechanismEngine CoverageStatusLast Audited
No rm -rf / force-push to main / claude --bare / known destructive + cost-leak patternsdestructive-patterns.jsonDestructiveOpGuard.hook.ts (PNC) + pai-guard.ts PATH shims (other engines)PNC + PNK + PNX + PNG + PNO (via shell shims)ENFORCED2026-05-27
Override flow with TOTP + voice confirmMemoryPromoter.tsDual-factor approval gatePNCENFORCED (PNC) / N/A (override is principal-only)2026-05-26
Pattern registry promotionMemoPromotionExtractor.hook.tsPostToolUse extracts → validator → SessionStart approvalPNCENFORCED2026-05-26

Path Containment

RuleSourceMechanismEngine CoverageStatusLast Audited
No hardcoded user-home paths in PAI filesCLAUDE.md ~/.claude private rulesContainmentGuard.hook.ts (PreToolUse on Write/Edit)PNCENFORCED (PNC) / GAP (PNK, PNX, PNG, PNO can write paths via shell)2026-05-26
~/.claude never pushed to public remotePAI_SYSTEM_PROMPT.md privacy sectionRelease skill scrub + manual git remote reviewPNCGAP (relies on discipline + skill; no pre-push hook yet)2026-05-26

Output Format

RuleSourceMechanismEngine CoverageStatusLast Audited
Every response uses MINIMAL / NATIVE / ALGORITHM templateCLAUDE.md + PAI_SYSTEM_PROMPT.mdFormatComplianceScan.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.)PNCMEASURED (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 engines2026-06-13
Mode + Tier from classifierPAI_SYSTEM_PROMPT.md Mode ArchitecturePromptProcessing.hook.ts (UserPromptSubmit)PNCENFORCED2026-05-26
Algorithm phase transitions emit ISA phase editsAlgorithm/v5.7.2.mdPhaseTransitionGate.hook.ts (PreToolUse on ISA edit) + ISASync.hook.ts (PostToolUse)PNCENFORCED2026-05-26

Secrets / Privacy

RuleSourceMechanismEngine CoverageStatusLast Audited
No secrets in outputPAI_SYSTEM_PROMPT.md Security ProtocolOutputSecretsScanner.hook.ts (Stop)PNCENFORCED (PNC) / GAP (other engines)2026-05-26
Customer/user data protectedPAI_SYSTEM_PROMPT.md Security BoundariesDiscipline + permission deny rules in settings.jsonPNCGAP — partial; relies on path-deny + agent boundary2026-05-26
Prompt injection rejectionPAI_SYSTEM_PROMPT.md Security ProtocolContentInjectionScanner.hook.ts + UnicodeInjectionScanner.hook.tsPNCENFORCED (PNC) / GAP (other engines)2026-05-26
OAuth scrubbing for non-principal channelsPAI_SYSTEM_PROMPT.md Personal Use BoundaryChannel-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 claudeGAP → 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

RuleSourceMechanismEngine CoverageStatusLast Audited
No guessed host / IP / asset-name enters PAI code/config2026-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 recalled2026-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 disciplineENFORCED (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-backed2026-06-14pai-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)ENFORCED2026-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 2pai-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 classesPAI_SYSTEM_PROMPT.md Honesty floorHosts, 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 check2026-06-14

Algorithm Doctrine

RuleSourceMechanismEngine CoverageStatusLast Audited
Live-probe verification (Rule 1)Algorithm/v5.7.2.mdDiscipline + Inline Verification mandate + Stop-time auditPNCENFORCED (audit catches violations post-hoc) / GAP (no pre-emit block)2026-05-26
Advisor at PLAN→BUILD (Rule 2)Algorithm/v5.7.2.mdPhaseTransitionGate.hook.ts blocks phase: build edit absent advisor/skip blockPNCENFORCED2026-05-26
Cato cross-vendor audit (Rule 2a) at E4/E5Algorithm/v5.7.2.mdCato agent + CrossVendorAudit.tsPNCENFORCED (when invoked); no automatic trigger2026-05-26
Re-Read check final gateAlgorithm/v5.7.2.mdDiscipline + Stop-time auditPNCGAP (no pre-emit block)2026-05-26
Capability binding (no phantom)Algorithm/v5.7.2.mdDiscipline + VERIFY-phase auditPNCGAP (audit catches post-hoc)2026-05-26

Budget & Cost

RuleSourceMechanismEngine CoverageStatusLast Audited
Per-window budget trackingCLAUDE.mdBudgetGuard.hook.ts reads UsageProbe.ts canonical OAuth endpointPNCENFORCED2026-05-26
OAuth subprocess flag scrubbingCLAUDE.md Operational RulesCode review + delete env.ANTHROPIC_API_KEY pattern in Inference.tscode pathsGAP (no PreToolUse Bash scan for claude --bare)2026-05-26

Operational Conventions

RuleSourceMechanismEngine CoverageStatusLast Audited
bun / bunx always, never npm / npxCLAUDE.md Operational RulesRTK proxy auto-rewrite for some commands; no hook block for npm directPNCGAP (RTK partial; no PreToolUse Bash block on npm)2026-05-26
TypeScript always, no Python without approvalCLAUDE.md Operational RulesDisciplinenoneASPIRATIONAL2026-05-26
Markdown over HTMLCLAUDE.md Operational RulesDisciplinenoneASPIRATIONAL2026-05-26
~/.claude commits direct to main, no branchesCLAUDE.md Operational RulesDisciplinenoneASPIRATIONAL (could add PreToolUse on git branch in ~/.claude)2026-05-26

How to Add a New Rule

  1. Write the rule in its canonical source file (PAI_SYSTEM_PROMPT.md, CLAUDE.md, or a doctrine file).
  2. Decide its enforcement class using this matrix:
If the rule is…Build…
A fact that shouldn’t changeA loadAtStartup pin
A tool-call pattern (block / rewrite)A PreToolUse hook
An output format / content constraintA Stop or SubagentStop hook
A path / permission boundaryA permissions.deny entry + ContainmentGuard-style hook
A cross-engine requirementA PAI/bin/ PATH shim wrapping the engine binary
A memory/state write gateA PreToolUse on Write/Edit matching path
  1. Build the mechanism. Add tests. Wire into settings.json event arrays (PNC) or ~/.bashrc PATH (other engines).
  2. Add a row to this file with all six columns populated. If you can’t fill the mechanism column, mark the row ASPIRATIONAL honestly — don’t leave it ENFORCED-by-implication.
  3. 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 from pass to warn to prevent self-defeating escape; warn-only ramp now reads from ~/MEMORY/STATE.claude/honesty-ramp.json so promotion is one file edit (and the gating criteria are documented in the file itself). Latent SETTINGS_PATH bug in hooks/lib/identity.ts getObservabilityConfig fixed. Tests updated to match new bypass verdict semantics — 12/12 passing.
  • 2026-05-26 (later still) — Phase B Tier 1: extended pai-guard.ts with --honesty mode per advisor’s strong recommendation (rejected the parallel bash-shim approach). Installed shims at PAI/bin/opencode and PAI/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/codex to delegate to pai-guard.ts --honesty while preserving the AssetRegistrySync side-effect. Added codex’s non-interactive surface (exec, e, review, apply, a) to NON_INTERACTIVE_PATTERNS. End-to-end verified: codex exec triggers [PAI honesty:PNX] finding on fabricated output; codex --help passes 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 synthetic llm shim.
  • 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.ts PreToolUse 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-only debt in pai-guard.ts flagged by the Phase A+ promotion. Shim now imports isWarnOnly() from hooks/lib/honesty-ramp.ts (the same module IdentityValidator + HonestyValidator share) and passes --warn-only to 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 carries ramp_mode so 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:
    1. pai-guard.ts --honesty exit-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 of agy/opencode/codex exits — needs a documented contract before shipping (e.g. exit 3 = “honesty-block”; opt-in env var PAI_HONESTY_BLOCK_EXIT_CODE?).
    2. MemoryWriteHonestyGate.hook.ts block semantics. Hook is deliberately fixed at ALWAYS_WARN_ONLY = true regardless 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 of MEMORY/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.json sidecars with verdict and would_block_under_proactive_hook flag. Exit code 2 when any would-block finding present (signal for cron / shell automation). Validator hardening included: new TEMPLATE_PLACEHOLDER_TAIL skip in scanIdentity so 🗣️ 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-dok4lf and opulse-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:89 close-line example changed from 🗣️ Assistant: <short close>🗣️ Nova: <short close>; pai-cli-format.ts:23 formatter literal changed from 🗣️ Assistant: ${...}🗣️ Nova: ${...} (with a code comment noting the DA-name coupling). Smoke-tested buildPaiEnginePrompt — 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-leak pattern to ~/MEMORY/STATE.claude/destructive-patterns.json as a manual (non-auto-promoted) entry. Provenance: the April 2026 $498 incident where Pulse heartbeats spawned claude --bare subprocesses, 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 literal claude --bare invocation 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 on claude --print without --bare. Small false-positive surface on commentary like echo 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 --bare flag 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_CODE to pai-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); with PAI_HONESTY_BLOCK_EXIT_CODE=3, same scenario exits 3 with a diagnostic stderr line. Telemetry logs exit_code_override events. 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 = true hardcode with a quarantine workflow gated by env var PAI_MEMORY_QUARANTINE_ENABLED=1. When opt-in is ON AND ramp=block AND a finding’s kind is not in disabled_kinds, the hook writes content to ~/MEMORY/STATE.claude/honesty-quarantine/<ISO-ts>-<sha-prefix>.json and 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 CLI PAI/Tools/PaiQuarantine.ts with 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.ts which calls HonestyValidator as a subprocess on the outgoing prompt BEFORE the prompt file is written and the engine is dispatched. Opt-in via env var PAI_OMNIPULSE_PREVALIDATE (default OFF, backward-compatible). When opt-in ON AND validator returns verdict=fail: dispatch aborts with started: false, error: "Pre-dispatch honesty validation blocked", stderr banner naming the findings; prevalidate_blocked event written to handoff events log. When verdict=warn: dispatch proceeds with a stderr warning + prevalidate_warn event. 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 in disabled_kinds) now surface to the model as non-blocking hookSpecificOutput.additionalContext on 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-nudge in identity-validator-actions.jsonl. (hooks/IdentityValidator.hook.ts, upgrade review 20260706.)