ceo-orchestration 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/adr/ADR-001-runtime-state-directory.md +164 -0
- package/.claude/adr/ADR-002-hooks-package-layout.md +228 -0
- package/.claude/adr/ADR-003-branch-protection-replaces-skill-signing.md +266 -0
- package/.claude/adr/ADR-004-defer-bash-legacy-removal.md +171 -0
- package/.claude/adr/ADR-005-event-stream-v2.md +153 -0
- package/.claude/adr/ADR-006-registry-derived-manifests.md +145 -0
- package/.claude/adr/ADR-007-spec-v1-semver-rc-policy.md +159 -0
- package/.claude/adr/ADR-008-hook-adapter-layer.md +169 -0
- package/.claude/adr/ADR-009-squad-contract.md +167 -0
- package/.claude/adr/ADR-010-canonical-edit-sentinel.md +181 -0
- package/.claude/adr/ADR-011-event-stream-v2.1-injection-flag.md +150 -0
- package/.claude/adr/ADR-012-cross-adapter-golden-fixtures.md +182 -0
- package/.claude/adr/ADR-013-squad-trading-hft.md +135 -0
- package/.claude/adr/ADR-014-hook-migration-batch-policy.md +197 -0
- package/.claude/adr/ADR-015-reflexion-v2-outcome-loop.md +248 -0
- package/.claude/adr/ADR-016-spawn-token-tracking.md +179 -0
- package/.claude/adr/ADR-017-lesson-pruning-policy.md +193 -0
- package/.claude/adr/ADR-018-claim-grammar.md +302 -0
- package/.claude/adr/ADR-019-AMEND-1-confidence-gate-block-mode-lifecycle.md +128 -0
- package/.claude/adr/ADR-019-AMEND-2-CLASS-SHA_EXISTS-promote-to-high-confidence-block.md +67 -0
- package/.claude/adr/ADR-019-confidence-gate-enforcement-lifecycle.md +221 -0
- package/.claude/adr/ADR-020-lesson-pruning-policy-v2.md +171 -0
- package/.claude/adr/ADR-021-e2e-harness-contract.md +189 -0
- package/.claude/adr/ADR-022-reserved-slot.md +52 -0
- package/.claude/adr/ADR-023-docs-freshness-lifecycle.md +184 -0
- package/.claude/adr/ADR-024-perf-baseline-policy.md +222 -0
- package/.claude/adr/ADR-025-squad-edtech.md +236 -0
- package/.claude/adr/ADR-026-squad-government.md +263 -0
- package/.claude/adr/ADR-027-unified-agent-state-backend.md +266 -0
- package/.claude/adr/ADR-028-multi-llm-canonical-parity.md +244 -0
- package/.claude/adr/ADR-029-lexical-tfidf-retrieval.md +205 -0
- package/.claude/adr/ADR-030-llm-as-judge-methodology.md +336 -0
- package/.claude/adr/ADR-031-self-improving-skills.md +221 -0
- package/.claude/adr/ADR-032-interactive-debate-protocol.md +337 -0
- package/.claude/adr/ADR-033-cost-budget-enforcement.md +275 -0
- package/.claude/adr/ADR-034-shared-working-memory.md +233 -0
- package/.claude/adr/ADR-035-otel-export.md +242 -0
- package/.claude/adr/ADR-036-output-safety.md +263 -0
- package/.claude/adr/ADR-037-chaos-testing-methodology.md +289 -0
- package/.claude/adr/ADR-038-session-graph-continuity.md +243 -0
- package/.claude/adr/ADR-039-skill-marketplace-protocol.md +170 -0
- package/.claude/adr/ADR-040-AMEND-2-credential-blocking.md +390 -0
- package/.claude/adr/ADR-040-live-adapter-activation-contract.md +285 -0
- package/.claude/adr/ADR-041-transition-log-convention.md +272 -0
- package/.claude/adr/ADR-042-AMEND-1-read-only-mcp-tools-expansion.md +214 -0
- package/.claude/adr/ADR-042-mcp-server-contract.md +727 -0
- package/.claude/adr/ADR-043-soc2-audit-trail-mapping.md +503 -0
- package/.claude/adr/ADR-044-formal-verification-pilot.md +505 -0
- package/.claude/adr/ADR-045-policy-as-code-engine.md +705 -0
- package/.claude/adr/ADR-046-deterministic-replay.md +167 -0
- package/.claude/adr/ADR-047-predictive-budgeting.md +213 -0
- package/.claude/adr/ADR-048-cross-plan-memory.md +227 -0
- package/.claude/adr/ADR-049-policy-engine-dual-path-deprecation.md +96 -0
- package/.claude/adr/ADR-049a-worktree-orchestration-policy.md +414 -0
- package/.claude/adr/ADR-050-native-subagents-dual-rail.md +165 -0
- package/.claude/adr/ADR-051-skill-reference-expanded-trust-boundary.md +282 -0
- package/.claude/adr/ADR-052-multi-model-dispatch-by-role.md +444 -0
- package/.claude/adr/ADR-053-sentinel-hmac-deferred.md +227 -0
- package/.claude/adr/ADR-054-AMEND-1-anthropic-admin-key-tier.md +131 -0
- package/.claude/adr/ADR-054-github-token-rotation.md +111 -0
- package/.claude/adr/ADR-055-AMEND-1-spool-writer-async-drain.md +170 -0
- package/.claude/adr/ADR-055-AMEND-2-chain-reset-marker.md +126 -0
- package/.claude/adr/ADR-055-AMEND-3-opportunistic-drain-nonblocking.md +183 -0
- package/.claude/adr/ADR-055-audit-log-hmac-chain.md +264 -0
- package/.claude/adr/ADR-056-hook-lifecycle-expansion.md +261 -0
- package/.claude/adr/ADR-057-output-scan-redaction.md +268 -0
- package/.claude/adr/ADR-058-brainstorm-gate-and-two-pass-review.md +240 -0
- package/.claude/adr/ADR-059-skill-bootstrap-env-knob.md +204 -0
- package/.claude/adr/ADR-060-curated-skill-import-pipeline.md +464 -0
- package/.claude/adr/ADR-061-runtime-cost-streaming.md +171 -0
- package/.claude/adr/ADR-062-AMEND-1-rag-conditional-default-on-supersedes-opt-in.md +232 -0
- package/.claude/adr/ADR-062-rag-sidecar-mcp-opt-in.md +231 -0
- package/.claude/adr/ADR-063-agent-eval-empirical-dispatch-validation.md +609 -0
- package/.claude/adr/ADR-064-dynamic-tier-policy-learned-dispatch.md +288 -0
- package/.claude/adr/ADR-065-audit-event-naming-convention.md +185 -0
- package/.claude/adr/ADR-066-context-mode-orthogonal-to-manifest.md +92 -0
- package/.claude/adr/ADR-067-ceo-model-downshift-static-routing.md +219 -0
- package/.claude/adr/ADR-069-wondelai-skills-import-refused.md +183 -0
- package/.claude/adr/ADR-070-audit-emit-package-layout.md +228 -0
- package/.claude/adr/ADR-071-benchmark-comparison-methodology.md +209 -0
- package/.claude/adr/ADR-072-test-discovery-via-conftest.md +184 -0
- package/.claude/adr/ADR-073-semver-bump-criteria-sprint-32.md +209 -0
- package/.claude/adr/ADR-074-sprint-32-phase-3-b1-refused.md +320 -0
- package/.claude/adr/ADR-075-sprint-32-phase-5-b5-benchmark-refused.md +250 -0
- package/.claude/adr/ADR-076-sprint-32-final-closure.md +218 -0
- package/.claude/adr/ADR-077-2026-04-24-webfetch-injection-incident.md +203 -0
- package/.claude/adr/ADR-078-sentinel-cosign-clarification.md +295 -0
- package/.claude/adr/ADR-079-prompt-sha-salt-hmac-impact.md +221 -0
- package/.claude/adr/ADR-080-rail-anomaly-h4-defense-in-depth.md +1143 -0
- package/.claude/adr/ADR-081-token-as-time-unit.md +272 -0
- package/.claude/adr/ADR-082-l7c-mitigation-default-on.md +240 -0
- package/.claude/adr/ADR-083-mcp-injection-scanner.md +225 -0
- package/.claude/adr/ADR-084-multi-adapter-refused-claude-only.md +152 -0
- package/.claude/adr/ADR-085-framework-landscape-claude-only.md +183 -0
- package/.claude/adr/ADR-086-checkpointing-refused.md +124 -0
- package/.claude/adr/ADR-087-AMEND-1-otel-consume-native-opt-in.md +217 -0
- package/.claude/adr/ADR-087-otel-emit-refused.md +136 -0
- package/.claude/adr/ADR-088-guardrails-library-refused.md +128 -0
- package/.claude/adr/ADR-089-sec-cluster-disposition.md +182 -0
- package/.claude/adr/ADR-090-framework-activation-defaults.md +217 -0
- package/.claude/adr/ADR-091-dogfood-validation-deferred.md +128 -0
- package/.claude/adr/ADR-092-plan-closure-honest-deferral.md +165 -0
- package/.claude/adr/ADR-093-refused-adr-moratorium.md +181 -0
- package/.claude/adr/ADR-094-claude-sdk-compat-version-pinning.md +160 -0
- package/.claude/adr/ADR-095-calendar-gate-retraction.md +202 -0
- package/.claude/adr/ADR-096-vibecoder-only-by-design.md +215 -0
- package/.claude/adr/ADR-097-function-length-advisory-permanent.md +186 -0
- package/.claude/adr/ADR-098-ceo-boot-audit-emit-register.md +251 -0
- package/.claude/adr/ADR-099-changesets-adoption.md +245 -0
- package/.claude/adr/ADR-100-trusted-dependencies-re-affirm.md +208 -0
- package/.claude/adr/ADR-101-replay-redact-helper.md +106 -0
- package/.claude/adr/ADR-102-mcp-introspection-extends-042.md +165 -0
- package/.claude/adr/ADR-103-calendar-gate-final-purge.md +121 -0
- package/.claude/adr/ADR-104-AMEND-1-aek-dated-promotion-criteria.md +338 -0
- package/.claude/adr/ADR-104-adaptive-execution-kernel-advisory.md +210 -0
- package/.claude/adr/ADR-105-multi-llm-coordinated-supersede.md +126 -0
- package/.claude/adr/ADR-106-codex-mcp-adapter-contract.md +153 -0
- package/.claude/adr/ADR-107-pair-rail-mandatory-l2-plus.md +189 -0
- package/.claude/adr/ADR-108-cross-llm-veto-floor.md +129 -0
- package/.claude/adr/ADR-109-codex-skill-rehash-protocol.md +104 -0
- package/.claude/adr/ADR-110-codex-pretool-enforcement.md +94 -0
- package/.claude/adr/ADR-111-locked-corpus-governance.md +191 -0
- package/.claude/adr/ADR-112-grandfather-cap-scope-clarification.md +192 -0
- package/.claude/adr/ADR-113-plan-084-canonical-guard-extension.md +59 -0
- package/.claude/adr/ADR-114-codex-egress-redaction-symmetry.md +72 -0
- package/.claude/adr/ADR-115-post-sota-maintenance-mode.md +152 -0
- package/.claude/adr/ADR-116-AMEND-1-kernel-extension-v2.md +640 -0
- package/.claude/adr/ADR-116-kernel-hard-deny-tier-0-extension.md +465 -0
- package/.claude/adr/ADR-117-adr-id-collision-rename-policy.md +279 -0
- package/.claude/adr/ADR-118-AMEND-1-phase-c-enforcing-flip.md +191 -0
- package/.claude/adr/ADR-118-god-mode-auto-usable-state.md +338 -0
- package/.claude/adr/ADR-119-sentinel-unlock-contract.md +133 -0
- package/.claude/adr/ADR-120-pii-core-promotion.md +280 -0
- package/.claude/adr/ADR-121-sentinel-signers-rotation-policy.md +434 -0
- package/.claude/adr/ADR-122-dpop-mcp-bearer-replay-defense.md +232 -0
- package/.claude/adr/ADR-123-streaming-adapter-canonical-source.md +130 -0
- package/.claude/adr/ADR-124-post-audit-sota-execution-mode.md +362 -0
- package/.claude/adr/ADR-125-risk-tiered-defaulting-doctrine.md +355 -0
- package/.claude/adr/ADR-126-governed-sidecar-capability-model.md +509 -0
- package/.claude/adr/ADR-127-pair-rail-advisory-promotion.md +218 -0
- package/.claude/adr/ADR-128-c2-vector-memory-capability-class.md +380 -0
- package/.claude/adr/ADR-129-AMEND-1-key-floor-waiver-lift.md +249 -0
- package/.claude/adr/ADR-129-c1-crypto-capability-class.md +289 -0
- package/.claude/adr/ADR-131-c5-dev-tools-capability-class.md +215 -0
- package/.claude/adr/ADR-132-goap-advisory-planning-doctrine.md +333 -0
- package/.claude/adr/ADR-133-autonomous-loop-opt-in-capability-doctrine.md +440 -0
- package/.claude/adr/ADR-135-AMEND-1-write-mode-trust-boundary.md +457 -0
- package/.claude/adr/ADR-135-AMEND-2-write-mode-activation.md +175 -0
- package/.claude/adr/ADR-135-federation-contract-mvp.md +253 -0
- package/.claude/adr/ADR-136-AMEND-1-workflow-primitive-adoption.md +139 -0
- package/.claude/adr/ADR-136-workflow-engine-doctrine.md +155 -0
- package/.claude/adr/ADR-137-skill-priority-stack-decision.md +162 -0
- package/.claude/adr/ADR-138-ac-format-priority-and-story-anchor.md +149 -0
- package/.claude/adr/ADR-139-coverage-doctrine-tiered.md +133 -0
- package/.claude/adr/ADR-140-receiving-review-doctrine.md +136 -0
- package/.claude/adr/ADR-141-reduce-protocol.md +124 -0
- package/.claude/adr/ADR-142-opus-4-8-model-bump.md +116 -0
- package/.claude/adr/ADR-143-git-hook-bypass-guard.md +166 -0
- package/.claude/adr/ADR-144-subagent-model-tiering-frontmatter.md +111 -0
- package/.claude/adr/ADR-145-cross-model-review-persona-demand-modality.md +103 -0
- package/.claude/adr/ADR-146-adversary-review-hook.md +122 -0
- package/.claude/adr/ADR-147-eval-harness-doctrine.md +109 -0
- package/.claude/adr/ADR-148-canonical-pricing-source.md +123 -0
- package/.claude/adr/ADR-149-model-id-allowlist.md +196 -0
- package/.claude/adr/ADR-150-commit-signing-policy.md +12 -0
- package/.claude/adr/ADR-151-fan-plan-advisory-bridge.md +178 -0
- package/.claude/adr/ADR-152-claude-md-decomposition.md +262 -0
- package/.claude/adr/ADR-153-compaction-continuity.md +141 -0
- package/.claude/adr/ADR-154-updatedinput-single-rewriter.md +68 -0
- package/.claude/adr/ADR-155-install-baseline-manifest.md +66 -0
- package/.claude/adr/ADR-156-constitution-sync-cascade.md +122 -0
- package/.claude/adr/README.md +392 -0
- package/.claude/adversary.md +116 -0
- package/.claude/agent-metrics.md +101 -0
- package/.claude/agents/_dispatch.md +30 -0
- package/.claude/agents/_probe_architect.md +45 -0
- package/.claude/agents/_probe_canonical_edit.md +46 -0
- package/.claude/agents/_probe_missing_skill.md +42 -0
- package/.claude/agents/code-reviewer.md +166 -0
- package/.claude/agents/devops.md +114 -0
- package/.claude/agents/identity-trust-architect.md +234 -0
- package/.claude/agents/incident-commander.md +285 -0
- package/.claude/agents/llm-finops-architect.md +265 -0
- package/.claude/agents/performance-engineer.md +148 -0
- package/.claude/agents/qa-architect.md +167 -0
- package/.claude/agents/security-engineer.md +192 -0
- package/.claude/agents/threat-detection-engineer.md +238 -0
- package/.claude/benchmarks/_schemas/judge-prompt.md +26 -0
- package/.claude/benchmarks/_schemas/judge-rubric-example.json +11 -0
- package/.claude/benchmarks/_schemas/judge-rubric.yaml +39 -0
- package/.claude/benchmarks/calibration-grades.jsonl +6 -0
- package/.claude/benchmarks/human-sample-calibration.md +232 -0
- package/.claude/benchmarks/judge-rotation-schedule.md +61 -0
- package/.claude/benchmarks/retrieval-judgment-set.yaml +194 -0
- package/.claude/benchmarks/tests/test_retrieval_recall_gate.py +330 -0
- package/.claude/commands/agent-budget.md +105 -0
- package/.claude/commands/architect.md +130 -0
- package/.claude/commands/audit-page.md +149 -0
- package/.claude/commands/audit-tokens.md +89 -0
- package/.claude/commands/ceo-boot.md +118 -0
- package/.claude/commands/ceo-info.md +71 -0
- package/.claude/commands/debate.md +258 -0
- package/.claude/commands/effort.md +99 -0
- package/.claude/commands/fan-plan.md +129 -0
- package/.claude/commands/goap.md +163 -0
- package/.claude/commands/lesson-review.md +66 -0
- package/.claude/commands/memory-scratchpad.md +100 -0
- package/.claude/commands/onboard.md +204 -0
- package/.claude/commands/pitfall.md +54 -0
- package/.claude/commands/resume.md +90 -0
- package/.claude/commands/self-test.md +83 -0
- package/.claude/commands/skill-review.md +102 -0
- package/.claude/commands/spawn.md +212 -0
- package/.claude/commands/squad-install.md +94 -0
- package/.claude/commands/status.md +177 -0
- package/.claude/commands/terse.md +81 -0
- package/.claude/commands/veto-check.md +63 -0
- package/.claude/data/audit-registry.golden.txt +306 -0
- package/.claude/data/canonical_models.json +1030 -0
- package/.claude/data/confidence-gate-class-tiers.json +24 -0
- package/.claude/data/cookbook_patterns.json +139 -0
- package/.claude/data/federation/enabled.md +34 -0
- package/.claude/data/federation/lan-enabled.md +38 -0
- package/.claude/data/federation/peers.example.yaml +89 -0
- package/.claude/data/goap/action-cost-baseline.json +29 -0
- package/.claude/dispatcher/disable_predicate_eval.py +630 -0
- package/.claude/dispatcher/routing-matrix-loader.py +874 -0
- package/.claude/dispatcher/routing-matrix.yaml +343 -0
- package/.claude/dispatcher/tests/conftest.py +11 -0
- package/.claude/dispatcher/tests/test_disable_predicate_eval.py +424 -0
- package/.claude/dispatcher/tests/test_routing_matrix_loader.py +461 -0
- package/.claude/docs/dpop-scope.md +79 -0
- package/.claude/docs/sentinel-signers-rotation-DRAFT.md +117 -0
- package/.claude/eval/README.md +73 -0
- package/.claude/eval/reporter.py +109 -0
- package/.claude/eval/runner.py +532 -0
- package/.claude/eval/self_test.yaml +57 -0
- package/.claude/eval/tasks/__init__.py +185 -0
- package/.claude/eval/tasks/t01_fix_off_by_one.py +52 -0
- package/.claude/eval/tasks/t02_implement_fizzbuzz.py +65 -0
- package/.claude/eval/tasks/t03_json_config_parse.py +80 -0
- package/.claude/eval/tasks/t04_refactor_dedupe.py +71 -0
- package/.claude/eval/tasks/t05_add_unit_test.py +77 -0
- package/.claude/eval/tasks/t06_palindrome.py +58 -0
- package/.claude/eval/tasks/t07_sql_param_fix.py +69 -0
- package/.claude/eval/tasks/t08_word_count.py +53 -0
- package/.claude/eval/tasks/t09_readme_doc.py +64 -0
- package/.claude/eval/tasks/t10_binary_search.py +58 -0
- package/.claude/frontend-team.md +202 -0
- package/.claude/governance/README.md +37 -0
- package/.claude/governance/audit_tokens_allowlist.json +37 -0
- package/.claude/governance/codex-cli-binary-sha256.txt +32 -0
- package/.claude/governance/codex-cli-pin.txt +26 -0
- package/.claude/governance/function-length-grandfather.yaml +2095 -0
- package/.claude/governance/governance-waivers.yaml +28 -0
- package/.claude/governance/pair-rail-inputs-hash-manifest.txt +32 -0
- package/.claude/governance/pair-rail-verdict-template.md +58 -0
- package/.claude/governance/pair-rail-verdict-v1.16.0-rc.1.md +120 -0
- package/.claude/governance/pair-rail-verdict-v1.16.0.md +64 -0
- package/.claude/gpg-revocations.jsonl +1 -0
- package/.claude/hooks/SessionEnd.py +353 -0
- package/.claude/hooks/SessionStart.py +345 -0
- package/.claude/hooks/Stop.py +195 -0
- package/.claude/hooks/UserPromptSubmit.py +329 -0
- package/.claude/hooks/_lib/EXECUTION-CONTEXT-DEFERRED.md +82 -0
- package/.claude/hooks/_lib/__init__.py +26 -0
- package/.claude/hooks/_lib/action_required.py +592 -0
- package/.claude/hooks/_lib/adapters/__init__.py +87 -0
- package/.claude/hooks/_lib/adapters/_constants.py +127 -0
- package/.claude/hooks/_lib/adapters/claude.py +167 -0
- package/.claude/hooks/_lib/adapters/codex.py +754 -0
- package/.claude/hooks/_lib/adapters/live/__init__.py +378 -0
- package/.claude/hooks/_lib/adapters/live/_breaker.py +309 -0
- package/.claude/hooks/_lib/adapters/live/_cost.py +389 -0
- package/.claude/hooks/_lib/adapters/live/_policy.py +319 -0
- package/.claude/hooks/_lib/adapters/live/_result.py +206 -0
- package/.claude/hooks/_lib/adapters/live/_transport.py +681 -0
- package/.claude/hooks/_lib/adapters/live/claude.py +1027 -0
- package/.claude/hooks/_lib/adapters/live/claude_batch.py +652 -0
- package/.claude/hooks/_lib/adapters/live/gemini.py +270 -0
- package/.claude/hooks/_lib/adapters/live/local.py +195 -0
- package/.claude/hooks/_lib/adapters/live/openai.py +371 -0
- package/.claude/hooks/_lib/adversary_rules.py +196 -0
- package/.claude/hooks/_lib/agent_frontmatter.py +288 -0
- package/.claude/hooks/_lib/audit_emit.py +11746 -0
- package/.claude/hooks/_lib/audit_emit_dispatch.py +179 -0
- package/.claude/hooks/_lib/audit_hmac.py +1146 -0
- package/.claude/hooks/_lib/audit_rotation.py +101 -0
- package/.claude/hooks/_lib/canonical_json.py +145 -0
- package/.claude/hooks/_lib/codex_cli_shape.py +502 -0
- package/.claude/hooks/_lib/codex_egress_redact.py +185 -0
- package/.claude/hooks/_lib/confidence_labels.py +338 -0
- package/.claude/hooks/_lib/contract.py +254 -0
- package/.claude/hooks/_lib/cookbook_patterns.py +136 -0
- package/.claude/hooks/_lib/cost_envelope.py +719 -0
- package/.claude/hooks/_lib/credentials.py +188 -0
- package/.claude/hooks/_lib/effective_config.py +767 -0
- package/.claude/hooks/_lib/egress_taxonomy.py +448 -0
- package/.claude/hooks/_lib/embeddings.py +322 -0
- package/.claude/hooks/_lib/env_guard.py +353 -0
- package/.claude/hooks/_lib/env_persist_allowlist.py +147 -0
- package/.claude/hooks/_lib/escalation_signals.py +335 -0
- package/.claude/hooks/_lib/estimation/__init__.py +12 -0
- package/.claude/hooks/_lib/estimation/bayesian.py +147 -0
- package/.claude/hooks/_lib/estimation/pipeline.py +209 -0
- package/.claude/hooks/_lib/exceptions.py +101 -0
- package/.claude/hooks/_lib/execution_context.py +208 -0
- package/.claude/hooks/_lib/federation/__init__.py +104 -0
- package/.claude/hooks/_lib/federation/audit_chain.py +118 -0
- package/.claude/hooks/_lib/federation/audit_chain_ext.py +408 -0
- package/.claude/hooks/_lib/federation/cert_inspector.py +573 -0
- package/.claude/hooks/_lib/federation/client.py +327 -0
- package/.claude/hooks/_lib/federation/handlers/__init__.py +30 -0
- package/.claude/hooks/_lib/federation/handlers/audit_event_batch.py +346 -0
- package/.claude/hooks/_lib/federation/handlers/audit_event_push.py +395 -0
- package/.claude/hooks/_lib/federation/handlers/peer_register.py +484 -0
- package/.claude/hooks/_lib/federation/handlers/peer_revoke.py +356 -0
- package/.claude/hooks/_lib/federation/identity.py +1056 -0
- package/.claude/hooks/_lib/federation/rate_limit.py +476 -0
- package/.claude/hooks/_lib/federation/replay.py +284 -0
- package/.claude/hooks/_lib/federation/scopes.py +168 -0
- package/.claude/hooks/_lib/federation/server.py +2218 -0
- package/.claude/hooks/_lib/file_walker.py +145 -0
- package/.claude/hooks/_lib/filelock.py +191 -0
- package/.claude/hooks/_lib/frontmatter.py +124 -0
- package/.claude/hooks/_lib/git_bypass.py +971 -0
- package/.claude/hooks/_lib/gpg_verify.py +356 -0
- package/.claude/hooks/_lib/guardrail_validator.py +478 -0
- package/.claude/hooks/_lib/injection_patterns.py +252 -0
- package/.claude/hooks/_lib/injection_salt.py +160 -0
- package/.claude/hooks/_lib/mcp/__init__.py +5 -0
- package/.claude/hooks/_lib/mcp/bearer_replay.py +279 -0
- package/.claude/hooks/_lib/mcp/canonical_guard.py +1140 -0
- package/.claude/hooks/_lib/mcp_bearer_friction.py +475 -0
- package/.claude/hooks/_lib/mcp_injection_scan.py +250 -0
- package/.claude/hooks/_lib/mcp_routing.py +151 -0
- package/.claude/hooks/_lib/memory_shared.py +592 -0
- package/.claude/hooks/_lib/metrics.py +241 -0
- package/.claude/hooks/_lib/model_routing.py +227 -0
- package/.claude/hooks/_lib/otel/__init__.py +34 -0
- package/.claude/hooks/_lib/otel/bounded_exporter.py +373 -0
- package/.claude/hooks/_lib/otel/hook_bridge.py +53 -0
- package/.claude/hooks/_lib/otel/queue.py +229 -0
- package/.claude/hooks/_lib/otel_emit.py +604 -0
- package/.claude/hooks/_lib/output_scan.py +1062 -0
- package/.claude/hooks/_lib/output_scan_dedup.py +379 -0
- package/.claude/hooks/_lib/pair_rail_decide.py +244 -0
- package/.claude/hooks/_lib/payload.py +195 -0
- package/.claude/hooks/_lib/persona_routing.py +244 -0
- package/.claude/hooks/_lib/pii_patterns.py +851 -0
- package/.claude/hooks/_lib/plan_frontmatter.py +166 -0
- package/.claude/hooks/_lib/policy.py +1527 -0
- package/.claude/hooks/_lib/policy_preprocessors.py +462 -0
- package/.claude/hooks/_lib/rag_bridge.py +624 -0
- package/.claude/hooks/_lib/rag_events.py +171 -0
- package/.claude/hooks/_lib/rag_router.py +253 -0
- package/.claude/hooks/_lib/redact.py +228 -0
- package/.claude/hooks/_lib/replay_redact.py +511 -0
- package/.claude/hooks/_lib/scratchpad_lib.py +225 -0
- package/.claude/hooks/_lib/secret_patterns.py +905 -0
- package/.claude/hooks/_lib/sentinel_signers.py +740 -0
- package/.claude/hooks/_lib/spec_context_sanitizer.py +258 -0
- package/.claude/hooks/_lib/spool_writer.py +2613 -0
- package/.claude/hooks/_lib/state_store.py +476 -0
- package/.claude/hooks/_lib/subagent_dispatch.py +244 -0
- package/.claude/hooks/_lib/swarm_circuit_breaker.py +203 -0
- package/.claude/hooks/_lib/swarm_enable_gate.py +152 -0
- package/.claude/hooks/_lib/team.py +128 -0
- package/.claude/hooks/_lib/test_isolation.py +352 -0
- package/.claude/hooks/_lib/testing.py +351 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_attack_surface.py +251 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_audit_stitching.py +135 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_identity.py +234 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_replay.py +204 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_sentinel_stage2.py +214 -0
- package/.claude/hooks/_lib/tests/federation/test_federation_server.py +385 -0
- package/.claude/hooks/_lib/tests/test_confidence_gate_class_block.py +313 -0
- package/.claude/hooks/_lib/tests/test_cost_envelope.py +759 -0
- package/.claude/hooks/_lib/tests/test_execution_context.py +254 -0
- package/.claude/hooks/_lib/tests/test_goap_advisory_invariant.py +134 -0
- package/.claude/hooks/_lib/tests/test_goap_planner.py +368 -0
- package/.claude/hooks/_lib/tests/test_plan104_audit_emit.py +324 -0
- package/.claude/hooks/_lib/tests/test_plan104_demand_resolver.py +584 -0
- package/.claude/hooks/_lib/tests/test_plan104_demand_scan.py +164 -0
- package/.claude/hooks/_lib/tests/test_plan104_microbench.py +109 -0
- package/.claude/hooks/_lib/tests/test_plan104_waive_parser.py +113 -0
- package/.claude/hooks/_lib/tests/test_plan105_audit_emit.py +259 -0
- package/.claude/hooks/_lib/tests/test_plan105_check_roadmap_binding.py +68 -0
- package/.claude/hooks/_lib/tests/test_plan105_goap_planner.py +158 -0
- package/.claude/hooks/_lib/tests/test_plan105_spawn_outcome.py +234 -0
- package/.claude/hooks/_lib/tests/test_rag_dead_code_disposition.py +262 -0
- package/.claude/hooks/_lib/tests/test_rag_router.py +209 -0
- package/.claude/hooks/_lib/tests/test_swarm_circuit_breaker.py +278 -0
- package/.claude/hooks/_lib/tests/test_swarm_kill_switch_chain.py +360 -0
- package/.claude/hooks/_lib/tier_policy/__init__.py +123 -0
- package/.claude/hooks/_lib/tier_policy/_agent_frontmatter.py +509 -0
- package/.claude/hooks/_lib/tier_policy/_constants.py +376 -0
- package/.claude/hooks/_lib/tier_policy/_types.py +355 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/baseline.json +17 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/oversize_64kib.json +1 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/prototype_pollution_attack.yaml +14 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/schema_v1_sample.json +5 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/schema_v2_sample.json +17 -0
- package/.claude/hooks/_lib/tier_policy/fixtures/yaml_bomb_attack.yaml +20 -0
- package/.claude/hooks/_lib/tier_policy/loader.py +476 -0
- package/.claude/hooks/_lib/tokens.py +136 -0
- package/.claude/hooks/_lib/tool_lifecycle.py +488 -0
- package/.claude/hooks/_lib/trusted_env.py +77 -0
- package/.claude/hooks/_python-hook.sh +242 -0
- package/.claude/hooks/accel_dispatch.py +172 -0
- package/.claude/hooks/adequacy_gate.py +424 -0
- package/.claude/hooks/audit_log.py +1352 -0
- package/.claude/hooks/auto_boot.py +518 -0
- package/.claude/hooks/check_adversary.py +273 -0
- package/.claude/hooks/check_agent_spawn.py +2696 -0
- package/.claude/hooks/check_anti_ceo_overhead.py +786 -0
- package/.claude/hooks/check_arbitration_kernel.py +544 -0
- package/.claude/hooks/check_bash_canonical_forensic.py +180 -0
- package/.claude/hooks/check_bash_safety.py +1483 -0
- package/.claude/hooks/check_budget.py +916 -0
- package/.claude/hooks/check_canonical_edit.py +1197 -0
- package/.claude/hooks/check_closeout_guard.py +154 -0
- package/.claude/hooks/check_codex_filewrite.py +366 -0
- package/.claude/hooks/check_codex_response.py +403 -0
- package/.claude/hooks/check_confidence_gate.py +545 -0
- package/.claude/hooks/check_config_change.py +346 -0
- package/.claude/hooks/check_config_protection.py +381 -0
- package/.claude/hooks/check_cost_envelope.py +286 -0
- package/.claude/hooks/check_fluency_nudge.py +747 -0
- package/.claude/hooks/check_mcp_response.py +234 -0
- package/.claude/hooks/check_output_safety.py +237 -0
- package/.claude/hooks/check_output_secrets.py +518 -0
- package/.claude/hooks/check_pair_rail.py +1700 -0
- package/.claude/hooks/check_plan_edit.py +905 -0
- package/.claude/hooks/check_postcompact_reinject.py +265 -0
- package/.claude/hooks/check_precompact_continuity.py +379 -0
- package/.claude/hooks/check_protocol_semver_cascade.py +401 -0
- package/.claude/hooks/check_read_injection.py +366 -0
- package/.claude/hooks/check_scratchpad_access.py +228 -0
- package/.claude/hooks/check_setup_verification.py +297 -0
- package/.claude/hooks/check_skill_bootstrap_post.py +339 -0
- package/.claude/hooks/check_skill_patch_sentinel.py +413 -0
- package/.claude/hooks/check_skill_reference_read.py +518 -0
- package/.claude/hooks/check_subagent_fabrication.py +45 -0
- package/.claude/hooks/check_subagent_start.py +232 -0
- package/.claude/hooks/check_tier_policy.py +211 -0
- package/.claude/hooks/check_tier_policy_misrouting_24h.py +187 -0
- package/.claude/hooks/check_webfetch_injection.py +277 -0
- package/.claude/hooks/check_worktree_writer.py +773 -0
- package/.claude/hooks/codex_review_user_code.py +304 -0
- package/.claude/hooks/emit_architect_outcome.py +232 -0
- package/.claude/hooks/latency_report.py +343 -0
- package/.claude/hooks/policy_dispatch.py +168 -0
- package/.claude/hooks/review_loop.py +560 -0
- package/.claude/hooks/route.py +115 -0
- package/.claude/hooks/tests/_agent_fixture.py +153 -0
- package/.claude/hooks/tests/adapters/__init__.py +0 -0
- package/.claude/hooks/tests/adapters/live/__init__.py +0 -0
- package/.claude/hooks/tests/adapters/live/test_adapters.py +488 -0
- package/.claude/hooks/tests/adapters/live/test_audit_wiring.py +81 -0
- package/.claude/hooks/tests/adapters/live/test_breaker.py +272 -0
- package/.claude/hooks/tests/adapters/live/test_cost.py +191 -0
- package/.claude/hooks/tests/adapters/live/test_o7_modernization.py +670 -0
- package/.claude/hooks/tests/adapters/live/test_policy.py +168 -0
- package/.claude/hooks/tests/conftest.py +139 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/agent_spawn_compliant.json +9 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/bash_safe_command.json +8 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/in/post_audit_event.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/claude/out/block_with_reason.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/codex/in/.gitkeep +1 -0
- package/.claude/hooks/tests/fixtures/adapters/codex/out/.gitkeep +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/GAPS.md +46 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/in/agent_spawn_minimal.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/in/bash_minimal.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/gemini/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/local/in/agent_spawn_ollama.json +19 -0
- package/.claude/hooks/tests/fixtures/adapters/local/in/bash_minimal.json +8 -0
- package/.claude/hooks/tests/fixtures/adapters/local/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/in/agent_spawn_chat_completions.json +13 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/in/bash_responses_api.json +9 -0
- package/.claude/hooks/tests/fixtures/adapters/openai/out/allow.json +1 -0
- package/.claude/hooks/tests/fixtures/anti_ceo_overhead/should-NOT-block-on-Y.ndjson +13 -0
- package/.claude/hooks/tests/fixtures/anti_ceo_overhead/should-block-on-X.ndjson +9 -0
- package/.claude/hooks/tests/fixtures/byte_identity/__init__.py +5 -0
- package/.claude/hooks/tests/fixtures/byte_identity/bash_safety_fuzzer.py +287 -0
- package/.claude/hooks/tests/fixtures/byte_identity/plan_edit_fuzzer.py +364 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/aws-iam-policy-arn-id-25.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/blog-paragraph-18.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/boilerplate-26.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/cdn-cache-key-12.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/certificate-fingerprint-10.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/changelog-19.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/commit-sha-01.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/django-csrf-token-24.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/docker-image-04.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/docs-example-22.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/haiku-20.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/hex-placeholder-15.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/hex-short-23.txt +5 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/image-thumbnail-09.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/jwt-payload-decoded-08.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/kubernetes-uid-06.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/md5-hash-02.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/phone-number-16.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/postgres-uuid-05.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/redis-cluster-node-13.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/session-token-11.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/sha256-checksum-03.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/short-token-21.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/software-license-14.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/telemetry-trace-07.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/negative/zip-postal-17.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-alnum-03.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-hex-01.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/binance-api-key-hex-02.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-12-31.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-12-33.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bip39-mnemonic-24-32.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-11.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-12.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitfinex-api-key-13.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitstamp-api-key-30.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bitstamp-customer-id-29.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-key-18.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-key-19.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-api-secret-20.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/bybit-combined-21.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-api-key-uuid-04.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-api-secret-b64-05.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-combined-07.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/coinbase-passphrase-06.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-34.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-35.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/evm-private-key-36.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-37.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-38.txt +3 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/generic-api-key-39.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-api-key-08.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-api-secret-09.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kraken-combined-10.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-api-key-uuid-26.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-api-secret-uuid-27.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/kucoin-passphrase-28.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-api-key-uuid-22.txt +1 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-api-secret-23.txt +2 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-combined-25.txt +4 -0
- package/.claude/hooks/tests/fixtures/exchange_keys/positive/okx-passphrase-24.txt +1 -0
- package/.claude/hooks/tests/fixtures/hooks/audit_log/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/audit_log/out.json +0 -0
- package/.claude/hooks/tests/fixtures/hooks/check_agent_spawn/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_agent_spawn/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_bash_safety/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_bash_safety/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_canonical_edit/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_canonical_edit/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_confidence_gate/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_confidence_gate/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_plan_edit/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_plan_edit/out.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_read_injection/in.json +1 -0
- package/.claude/hooks/tests/fixtures/hooks/check_read_injection/out.json +1 -0
- package/.claude/hooks/tests/fixtures/lifecycle/concurrent_interleaved.json +36 -0
- package/.claude/hooks/tests/fixtures/lifecycle/orphaned_pre.json +8 -0
- package/.claude/hooks/tests/fixtures/lifecycle/paired_bash_post.json +8 -0
- package/.claude/hooks/tests/fixtures/lifecycle/paired_bash_pre.json +9 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_chat_completions.json +36 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_compliant.json +24 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_minimal.json +24 -0
- package/.claude/hooks/tests/fixtures/normalized/agent_spawn_ollama.json +42 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_minimal.json +23 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_responses_api.json +32 -0
- package/.claude/hooks/tests/fixtures/normalized/bash_safe_command.json +23 -0
- package/.claude/hooks/tests/fixtures/normalized/post_audit_event.json +31 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/01_random_hash_log.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/02_docs_mention_email_no_address.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/03_partial_jwt_two_segments.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/04_random_11_digits_no_cpf_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/control/05_credit_card_shape_invalid_luhn.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/01_api_key_anthropic.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/02_api_key_github_pat_classic.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/03_api_key_github_fine_grained.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/04_api_key_aws_access_key.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/05_api_key_aws_secret_assignment.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/06_jwt.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/07_bearer.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/08_cpf_with_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/09_cnpj_with_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/10_credit_card_luhn_valid.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/11_email_in_login_context.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/12_nfkc_full_width.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/13_zero_width_evasion.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/14_bidi_evasion.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_safety/positive/15_base64_encoded_secret.txt +1 -0
- package/.claude/hooks/tests/fixtures/output_scan/scenarios.jsonl +45 -0
- package/.claude/hooks/tests/fixtures/sample_payload_clean.json +13 -0
- package/.claude/hooks/tests/fixtures/sample_payload_with_secrets.json +12 -0
- package/.claude/hooks/tests/mutations/README.md +86 -0
- package/.claude/hooks/tests/mutations/__init__.py +14 -0
- package/.claude/hooks/tests/mutations/engine_mutations/__init__.py +15 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_01_parser_accepts_anchor.py +51 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_02_parser_skip_depth_limit.py +38 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_03_parser_accept_multi_doc.py +47 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_04_parser_accepts_bom.py +41 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_05_parser_scalar_len_off_by_one.py +61 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_06_parser_accepts_python_tag.py +50 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_07_parser_accepts_tab_indent.py +56 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_08_compiler_skip_regex_compile.py +45 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_09_compiler_regex_pattern_cap_off.py +31 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_10_compiler_accept_unknown_form.py +42 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_11_compiler_missing_predicate_tolerated.py +79 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_12_compiler_duplicate_rule_id_tolerated.py +66 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_13_compiler_missing_top_level_key_tolerated.py +46 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_14_compiler_schema_version_passthrough.py +43 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_15_evaluator_any_empty_returns_true.py +41 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_16_evaluator_all_empty_returns_true.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_17_evaluator_not_passthrough.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_18_evaluator_eq_true_on_type_mismatch.py +51 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_19_evaluator_regex_match_only.py +43 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_20_evaluator_path_under_no_realpath.py +48 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_21_evaluator_in_accepts_any.py +37 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_22_evaluator_length_off_by_one.py +45 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_23_evaluator_first_match_becomes_last.py +66 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_24_error_model_wrong_kind_on_parse.py +39 -0
- package/.claude/hooks/tests/mutations/engine_mutations/mutation_25_error_model_fail_open_on_load.py +42 -0
- package/.claude/hooks/tests/mutations/policy_mutations/__init__.py +16 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_01_remove_credential_leak.py +49 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_02_remove_rm_rf.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_03_remove_git_reset_hard.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_04_remove_git_push_force.py +44 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_05_reorder_rules.py +59 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_06_change_reason_enum.py +54 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_07_default_flipped_to_block.py +56 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_bash_08_flip_rm_rf_to_allow.py +49 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_01_remove_illegal_transition.py +79 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_02_remove_illegal_status.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_03_remove_missing_reviewed_at.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_04_remove_missing_completed_at.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_05_remove_missing_related_commits.py +79 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_06_remove_missing_abandonment_reason.py +80 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_07_scope_guard_inverted.py +93 -0
- package/.claude/hooks/tests/mutations/policy_mutations/mutation_plan_08_default_block.py +90 -0
- package/.claude/hooks/tests/probes/test_architect_probe.py +286 -0
- package/.claude/hooks/tests/probes/test_canonical_edit_probe.py +190 -0
- package/.claude/hooks/tests/probes/test_skill_content_probe.py +219 -0
- package/.claude/hooks/tests/test_SessionEnd.py +59 -0
- package/.claude/hooks/tests/test_SessionStart.py +42 -0
- package/.claude/hooks/tests/test_UserPromptSubmit.py +47 -0
- package/.claude/hooks/tests/test_accel_dispatch.py +96 -0
- package/.claude/hooks/tests/test_action_required_invariants.py +274 -0
- package/.claude/hooks/tests/test_adapter_drift_detector.py +254 -0
- package/.claude/hooks/tests/test_adapter_golden.py +198 -0
- package/.claude/hooks/tests/test_adequacy_gate.py +86 -0
- package/.claude/hooks/tests/test_adr_052_role_to_model_coverage.py +112 -0
- package/.claude/hooks/tests/test_adr_058_brainstorm_structure.py +280 -0
- package/.claude/hooks/tests/test_adversary_rules_live.py +400 -0
- package/.claude/hooks/tests/test_agent_frontmatter.py +377 -0
- package/.claude/hooks/tests/test_anti_ceo_overhead.py +591 -0
- package/.claude/hooks/tests/test_audit_emit.py +1707 -0
- package/.claude/hooks/tests/test_audit_emit_api_contract.py +693 -0
- package/.claude/hooks/tests/test_audit_emit_async_flush.py +563 -0
- package/.claude/hooks/tests/test_audit_emit_backpressure.py +138 -0
- package/.claude/hooks/tests/test_audit_emit_callsite_coverage_matrix.py +101 -0
- package/.claude/hooks/tests/test_audit_emit_chain_length.py +357 -0
- package/.claude/hooks/tests/test_audit_emit_coverage.py +2679 -0
- package/.claude/hooks/tests/test_audit_emit_ghost_action_guard.py +447 -0
- package/.claude/hooks/tests/test_audit_emit_plan088_canonical13.py +323 -0
- package/.claude/hooks/tests/test_audit_emit_rotation.py +218 -0
- package/.claude/hooks/tests/test_audit_emit_veto_v214.py +202 -0
- package/.claude/hooks/tests/test_audit_emit_wire_audit.py +699 -0
- package/.claude/hooks/tests/test_audit_hmac.py +334 -0
- package/.claude/hooks/tests/test_audit_hmac_branch_coverage.py +212 -0
- package/.claude/hooks/tests/test_audit_hmac_chain_monotonicity_property.py +136 -0
- package/.claude/hooks/tests/test_audit_hmac_coverage_v214.py +358 -0
- package/.claude/hooks/tests/test_audit_hmac_hardening.py +302 -0
- package/.claude/hooks/tests/test_audit_hmac_rotation_scenarios.py +231 -0
- package/.claude/hooks/tests/test_audit_hmac_verify_chain.py +443 -0
- package/.claude/hooks/tests/test_audit_log.py +280 -0
- package/.claude/hooks/tests/test_audit_log_coverage.py +173 -0
- package/.claude/hooks/tests/test_audit_log_path_d.py +516 -0
- package/.claude/hooks/tests/test_audit_log_phase1.py +358 -0
- package/.claude/hooks/tests/test_audit_log_schema_consistency.py +97 -0
- package/.claude/hooks/tests/test_audit_log_security.py +289 -0
- package/.claude/hooks/tests/test_audit_log_tokens.py +92 -0
- package/.claude/hooks/tests/test_audit_log_v2_7.py +378 -0
- package/.claude/hooks/tests/test_audit_log_v2_8_model.py +201 -0
- package/.claude/hooks/tests/test_audit_rotation.py +158 -0
- package/.claude/hooks/tests/test_audit_stream_verbose_protection.py +86 -0
- package/.claude/hooks/tests/test_audit_tokens_content_ban.py +512 -0
- package/.claude/hooks/tests/test_auto_boot.py +28 -0
- package/.claude/hooks/tests/test_available_models_mirror.py +226 -0
- package/.claude/hooks/tests/test_bash_canonical_forensic.py +74 -0
- package/.claude/hooks/tests/test_bash_canonical_interceptor.py +79 -0
- package/.claude/hooks/tests/test_brotli_passthrough.py +145 -0
- package/.claude/hooks/tests/test_byte_identity_fuzzer.py +185 -0
- package/.claude/hooks/tests/test_byte_identity_harness.py +953 -0
- package/.claude/hooks/tests/test_canonical_guard_typed_exceptions.py +117 -0
- package/.claude/hooks/tests/test_canonical_json.py +153 -0
- package/.claude/hooks/tests/test_chain_invariants_property.py +132 -0
- package/.claude/hooks/tests/test_check_adversary_live.py +149 -0
- package/.claude/hooks/tests/test_check_agent_spawn.py +1084 -0
- package/.claude/hooks/tests/test_check_agent_spawn_coverage.py +277 -0
- package/.claude/hooks/tests/test_check_agent_spawn_effort_token.py +74 -0
- package/.claude/hooks/tests/test_check_agent_spawn_import_isolation.py +82 -0
- package/.claude/hooks/tests/test_check_agent_spawn_model_routing_mode.py +245 -0
- package/.claude/hooks/tests/test_check_agent_spawn_reference_bypass.py +385 -0
- package/.claude/hooks/tests/test_check_agent_spawn_routing_promotion.py +302 -0
- package/.claude/hooks/tests/test_check_agent_spawn_skill_reference.py +336 -0
- package/.claude/hooks/tests/test_check_arbitration_kernel.py +472 -0
- package/.claude/hooks/tests/test_check_arbitration_kernel_v214.py +157 -0
- package/.claude/hooks/tests/test_check_bash_safety.py +546 -0
- package/.claude/hooks/tests/test_check_bash_safety_canonical_matrix.py +336 -0
- package/.claude/hooks/tests/test_check_bash_safety_cp_chaining.py +120 -0
- package/.claude/hooks/tests/test_check_bash_safety_h5_rewrite.py +462 -0
- package/.claude/hooks/tests/test_check_budget.py +580 -0
- package/.claude/hooks/tests/test_check_budget_max_tokens.py +397 -0
- package/.claude/hooks/tests/test_check_budget_quota_hint.py +115 -0
- package/.claude/hooks/tests/test_check_canonical_edit.py +302 -0
- package/.claude/hooks/tests/test_check_canonical_edit_coverage.py +370 -0
- package/.claude/hooks/tests/test_check_canonical_edit_kernel_v2.py +401 -0
- package/.claude/hooks/tests/test_check_canonical_edit_markers.py +473 -0
- package/.claude/hooks/tests/test_check_canonical_edit_mcp.py +401 -0
- package/.claude/hooks/tests/test_check_canonical_edit_session67_format.py +245 -0
- package/.claude/hooks/tests/test_check_codex_filewrite.py +964 -0
- package/.claude/hooks/tests/test_check_codex_response.py +419 -0
- package/.claude/hooks/tests/test_check_compaction_continuity.py +450 -0
- package/.claude/hooks/tests/test_check_confidence_gate.py +326 -0
- package/.claude/hooks/tests/test_check_config_change.py +369 -0
- package/.claude/hooks/tests/test_check_config_protection.py +364 -0
- package/.claude/hooks/tests/test_check_fluency_nudge.py +321 -0
- package/.claude/hooks/tests/test_check_mcp_response.py +261 -0
- package/.claude/hooks/tests/test_check_output_safety.py +314 -0
- package/.claude/hooks/tests/test_check_output_secrets.py +488 -0
- package/.claude/hooks/tests/test_check_output_secrets_coverage.py +321 -0
- package/.claude/hooks/tests/test_check_pair_rail.py +897 -0
- package/.claude/hooks/tests/test_check_pair_rail_decide_canonical.py +297 -0
- package/.claude/hooks/tests/test_check_pair_rail_golden.py +362 -0
- package/.claude/hooks/tests/test_check_pair_rail_hook_integration.py +120 -0
- package/.claude/hooks/tests/test_check_pair_rail_matrix.py +1077 -0
- package/.claude/hooks/tests/test_check_plan_edit.py +679 -0
- package/.claude/hooks/tests/test_check_plan_edit_stranded.py +310 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade.py +141 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade_settings_wired.py +297 -0
- package/.claude/hooks/tests/test_check_protocol_semver_cascade_synccascade.py +365 -0
- package/.claude/hooks/tests/test_check_read_injection.py +143 -0
- package/.claude/hooks/tests/test_check_read_injection_coverage.py +237 -0
- package/.claude/hooks/tests/test_check_read_injection_pathbound.py +153 -0
- package/.claude/hooks/tests/test_check_scratchpad_access.py +244 -0
- package/.claude/hooks/tests/test_check_skill_bootstrap_post.py +256 -0
- package/.claude/hooks/tests/test_check_skill_patch_sentinel.py +439 -0
- package/.claude/hooks/tests/test_check_skill_reference_read.py +170 -0
- package/.claude/hooks/tests/test_check_skill_reference_read_v2.py +388 -0
- package/.claude/hooks/tests/test_check_subagent_fabrication.py +54 -0
- package/.claude/hooks/tests/test_check_subagent_start.py +505 -0
- package/.claude/hooks/tests/test_check_tier_policy.py +48 -0
- package/.claude/hooks/tests/test_check_tier_policy_misrouting_24h.py +294 -0
- package/.claude/hooks/tests/test_check_webfetch_injection.py +49 -0
- package/.claude/hooks/tests/test_claim_producer_pair_end_to_end_loop_perf.py +227 -0
- package/.claude/hooks/tests/test_claude_adapter_thinking.py +731 -0
- package/.claude/hooks/tests/test_claude_batch_adapter.py +672 -0
- package/.claude/hooks/tests/test_closeout_guard.py +184 -0
- package/.claude/hooks/tests/test_codex_adapter.py +777 -0
- package/.claude/hooks/tests/test_codex_cli_shape.py +217 -0
- package/.claude/hooks/tests/test_codex_egress_proof_telemetry.py +214 -0
- package/.claude/hooks/tests/test_codex_egress_redact.py +342 -0
- package/.claude/hooks/tests/test_codex_egress_redact_outgoing.py +236 -0
- package/.claude/hooks/tests/test_codex_reply_multi_turn.py +72 -0
- package/.claude/hooks/tests/test_codex_review_user_code.py +44 -0
- package/.claude/hooks/tests/test_codex_strict_json.py +123 -0
- package/.claude/hooks/tests/test_confidence_gate_producer_pair.py +522 -0
- package/.claude/hooks/tests/test_confidence_labels.py +362 -0
- package/.claude/hooks/tests/test_contract.py +237 -0
- package/.claude/hooks/tests/test_cookbook_advisor_hook.py +208 -0
- package/.claude/hooks/tests/test_credentials.py +195 -0
- package/.claude/hooks/tests/test_detect_repo_profile_branches.py +116 -0
- package/.claude/hooks/tests/test_e2e_hook_chain.py +184 -0
- package/.claude/hooks/tests/test_effective_config.py +648 -0
- package/.claude/hooks/tests/test_emit_architect_outcome.py +175 -0
- package/.claude/hooks/tests/test_env_persist_allowlist.py +365 -0
- package/.claude/hooks/tests/test_escalation_signals.py +357 -0
- package/.claude/hooks/tests/test_estimation_bayesian_pipeline.py +140 -0
- package/.claude/hooks/tests/test_execution_context_deferral.py +222 -0
- package/.claude/hooks/tests/test_fail_open_contract.py +118 -0
- package/.claude/hooks/tests/test_file_walker.py +332 -0
- package/.claude/hooks/tests/test_filelock.py +131 -0
- package/.claude/hooks/tests/test_filelock_contract.py +172 -0
- package/.claude/hooks/tests/test_find_sentinels_pattern_matrix.py +114 -0
- package/.claude/hooks/tests/test_flip_closures.py +219 -0
- package/.claude/hooks/tests/test_frontmatter.py +139 -0
- package/.claude/hooks/tests/test_git_bypass_guard.py +1095 -0
- package/.claude/hooks/tests/test_gpg_verify.py +578 -0
- package/.claude/hooks/tests/test_hook_byte_fidelity.py +113 -0
- package/.claude/hooks/tests/test_hook_latency.py +245 -0
- package/.claude/hooks/tests/test_hook_latency_import.py +178 -0
- package/.claude/hooks/tests/test_injection_patterns.py +276 -0
- package/.claude/hooks/tests/test_injection_patterns_bypass.py +276 -0
- package/.claude/hooks/tests/test_injection_salt.py +191 -0
- package/.claude/hooks/tests/test_kernel_subsumes_security_critical_lib.py +88 -0
- package/.claude/hooks/tests/test_kill_switch_godmode_enforcing.py +101 -0
- package/.claude/hooks/tests/test_latency_report.py +28 -0
- package/.claude/hooks/tests/test_lib_canonical_import.py +355 -0
- package/.claude/hooks/tests/test_lifecycle_edge_cases.py +565 -0
- package/.claude/hooks/tests/test_live_adapters.py +463 -0
- package/.claude/hooks/tests/test_live_audit_isolation.py +357 -0
- package/.claude/hooks/tests/test_mcp_bearer_friction_buffer.py +276 -0
- package/.claude/hooks/tests/test_mcp_bearer_friction_emit.py +117 -0
- package/.claude/hooks/tests/test_mcp_canonical_guard.py +1989 -0
- package/.claude/hooks/tests/test_mcp_injection_repro_harness.py +437 -0
- package/.claude/hooks/tests/test_mcp_injection_scan.py +228 -0
- package/.claude/hooks/tests/test_mcp_routing_resolve.py +246 -0
- package/.claude/hooks/tests/test_memory_shared.py +412 -0
- package/.claude/hooks/tests/test_metrics.py +115 -0
- package/.claude/hooks/tests/test_migrated_hooks_fixtures.py +121 -0
- package/.claude/hooks/tests/test_model_routing.py +175 -0
- package/.claude/hooks/tests/test_model_routing_resolve.py +97 -0
- package/.claude/hooks/tests/test_model_routing_resolve_full.py +318 -0
- package/.claude/hooks/tests/test_otel_bounded_exporter.py +521 -0
- package/.claude/hooks/tests/test_otel_emit.py +243 -0
- package/.claude/hooks/tests/test_otel_queue.py +334 -0
- package/.claude/hooks/tests/test_otel_wire_defaultoff.py +392 -0
- package/.claude/hooks/tests/test_output_scan.py +1119 -0
- package/.claude/hooks/tests/test_output_scan_dedup.py +329 -0
- package/.claude/hooks/tests/test_output_scan_fixtures.py +136 -0
- package/.claude/hooks/tests/test_pair_rail_decide.py +141 -0
- package/.claude/hooks/tests/test_payload.py +89 -0
- package/.claude/hooks/tests/test_persona_coverage_wire.py +376 -0
- package/.claude/hooks/tests/test_persona_routing_enforcing.py +119 -0
- package/.claude/hooks/tests/test_phase_c_advisory_audit.py +75 -0
- package/.claude/hooks/tests/test_pii_patterns.py +558 -0
- package/.claude/hooks/tests/test_plan114_wires.py +468 -0
- package/.claude/hooks/tests/test_plan128_emit_wiring.py +74 -0
- package/.claude/hooks/tests/test_plan132_codex_review_observe.py +99 -0
- package/.claude/hooks/tests/test_plan133_a1_env_guard.py +221 -0
- package/.claude/hooks/tests/test_plan133_a2_canonical_skill_unicode.py +359 -0
- package/.claude/hooks/tests/test_plan133_a2_invisible_unicode.py +239 -0
- package/.claude/hooks/tests/test_plan133_a3_egress_taxonomy.py +221 -0
- package/.claude/hooks/tests/test_plan133_e1_adversary.py +360 -0
- package/.claude/hooks/tests/test_plan_085_wave_c_callsites_preserved.py +147 -0
- package/.claude/hooks/tests/test_plan_091_expected_callsites.py +206 -0
- package/.claude/hooks/tests/test_plan_frontmatter.py +217 -0
- package/.claude/hooks/tests/test_policy_coverage_residual_session73.py +597 -0
- package/.claude/hooks/tests/test_policy_coverage_v214.py +1099 -0
- package/.claude/hooks/tests/test_policy_dispatch.py +454 -0
- package/.claude/hooks/tests/test_policy_engine.py +791 -0
- package/.claude/hooks/tests/test_policy_fuzz_bomb.py +356 -0
- package/.claude/hooks/tests/test_policy_golden_error_kinds.py +287 -0
- package/.claude/hooks/tests/test_policy_mutations.py +359 -0
- package/.claude/hooks/tests/test_policy_preprocessors.py +514 -0
- package/.claude/hooks/tests/test_policy_redos_guards.py +393 -0
- package/.claude/hooks/tests/test_rag_bridge.py +675 -0
- package/.claude/hooks/tests/test_rag_events.py +202 -0
- package/.claude/hooks/tests/test_red_team_fixtures.py +427 -0
- package/.claude/hooks/tests/test_redact.py +506 -0
- package/.claude/hooks/tests/test_redact_redos.py +254 -0
- package/.claude/hooks/tests/test_redact_secrets_parity.py +334 -0
- package/.claude/hooks/tests/test_replay_determinism.py +263 -0
- package/.claude/hooks/tests/test_review_loop.py +28 -0
- package/.claude/hooks/tests/test_review_loop_wiring.py +206 -0
- package/.claude/hooks/tests/test_route.py +36 -0
- package/.claude/hooks/tests/test_rubric_catalogue.py +359 -0
- package/.claude/hooks/tests/test_scratchpad_lib.py +259 -0
- package/.claude/hooks/tests/test_secret_patterns.py +680 -0
- package/.claude/hooks/tests/test_secret_patterns_provenance.py +82 -0
- package/.claude/hooks/tests/test_sentinel_session_cache.py +324 -0
- package/.claude/hooks/tests/test_sentinel_session_cache_tier1.py +205 -0
- package/.claude/hooks/tests/test_sentinel_signers.py +641 -0
- package/.claude/hooks/tests/test_session_75_kernel_findings.py +180 -0
- package/.claude/hooks/tests/test_session_76_audit_v3_findings.py +493 -0
- package/.claude/hooks/tests/test_session_77_audit_v3_backlog_findings.py +644 -0
- package/.claude/hooks/tests/test_session_77_round_2_findings.py +135 -0
- package/.claude/hooks/tests/test_session_77_round_3_findings.py +159 -0
- package/.claude/hooks/tests/test_session_77_round_4_findings.py +120 -0
- package/.claude/hooks/tests/test_session_end.py +113 -0
- package/.claude/hooks/tests/test_session_start.py +293 -0
- package/.claude/hooks/tests/test_skill_unknown_ratio_path_d.py +249 -0
- package/.claude/hooks/tests/test_smart_loading_resolver_caching.py +140 -0
- package/.claude/hooks/tests/test_spec_context_sanitizer.py +179 -0
- package/.claude/hooks/tests/test_spool_drain_contended_skip.py +249 -0
- package/.claude/hooks/tests/test_spool_drain_rotation_property_b.py +227 -0
- package/.claude/hooks/tests/test_spool_drain_rotation_race.py +395 -0
- package/.claude/hooks/tests/test_spool_writer_cache.py +463 -0
- package/.claude/hooks/tests/test_state_store.py +302 -0
- package/.claude/hooks/tests/test_stop.py +133 -0
- package/.claude/hooks/tests/test_streaming_rate_cap.py +108 -0
- package/.claude/hooks/tests/test_subagent_dispatch.py +248 -0
- package/.claude/hooks/tests/test_subagent_model_override_removed.py +108 -0
- package/.claude/hooks/tests/test_team.py +95 -0
- package/.claude/hooks/tests/test_template_dogfood_parity.py +106 -0
- package/.claude/hooks/tests/test_terminal_compress.py +135 -0
- package/.claude/hooks/tests/test_test_env_context_agent_binding.py +140 -0
- package/.claude/hooks/tests/test_testing_helper.py +53 -0
- package/.claude/hooks/tests/test_thinking_budget_command.py +229 -0
- package/.claude/hooks/tests/test_tier_policy_agent_frontmatter.py +421 -0
- package/.claude/hooks/tests/test_tier_policy_agent_frontmatter_disposition.py +175 -0
- package/.claude/hooks/tests/test_tier_policy_constants.py +336 -0
- package/.claude/hooks/tests/test_tier_policy_loader.py +544 -0
- package/.claude/hooks/tests/test_tier_policy_loader_fallback_observed.py +169 -0
- package/.claude/hooks/tests/test_tier_policy_types.py +270 -0
- package/.claude/hooks/tests/test_tokens_lib.py +118 -0
- package/.claude/hooks/tests/test_tool_lifecycle.py +598 -0
- package/.claude/hooks/tests/test_tool_lifecycle_perf.py +110 -0
- package/.claude/hooks/tests/test_turbo_profile.py +28 -0
- package/.claude/hooks/tests/test_turbo_sessionstart.py +79 -0
- package/.claude/hooks/tests/test_two_writer_chain.py +175 -0
- package/.claude/hooks/tests/test_upgrade_retry.py +346 -0
- package/.claude/hooks/tests/test_user_prompt_submit.py +254 -0
- package/.claude/hooks/tests/test_user_prompt_submit_salt.py +204 -0
- package/.claude/hooks/tests/test_verify_after_edit.py +100 -0
- package/.claude/hooks/tests/test_veto_floor_bijection.py +174 -0
- package/.claude/hooks/tests/test_w5_cookbook_remediation.py +712 -0
- package/.claude/hooks/tests/test_w5_scrub_enforcement.py +371 -0
- package/.claude/hooks/tests/test_webfetch_injection.py +280 -0
- package/.claude/hooks/tests/test_wiredeadmod_estimation_wiring.py +283 -0
- package/.claude/hooks/tests/test_wiredeadmod_spawn_wiring.py +303 -0
- package/.claude/hooks/tests/test_worktree_writer.py +509 -0
- package/.claude/hooks/turbo_profile.py +554 -0
- package/.claude/hooks/turbo_sessionstart.py +472 -0
- package/.claude/hooks/verify_after_edit.py +281 -0
- package/.claude/pitfalls-catalog.yaml +150 -0
- package/.claude/plans/AUDIT-LOG-SCHEMA.md +548 -0
- package/.claude/plans/DEBATE-SCHEMA.md +539 -0
- package/.claude/plans/PLAN-128/AB-PROTOCOL.md +121 -0
- package/.claude/plans/PLAN-128/measure-state.sh +101 -0
- package/.claude/plans/PLAN-139-canonical-invariants-and-debt-ledger.md +253 -0
- package/.claude/plans/PLAN-140/architect/round-1/approved.md +40 -0
- package/.claude/plans/PLAN-140-compaction-hook-origin-dropfix.md +95 -0
- package/.claude/plans/PLAN-141/architect/round-1/approved.md +28 -0
- package/.claude/plans/PLAN-141-mcp-smoke-staging-ruff-tolerance.md +72 -0
- package/.claude/plans/PLAN-142/architect/round-1/anonymization-map.md +11 -0
- package/.claude/plans/PLAN-142/architect/round-1/consensus.md +95 -0
- package/.claude/plans/PLAN-142/architect/round-1/devops-engineer.md +57 -0
- package/.claude/plans/PLAN-142/architect/round-1/proposal.md +57 -0
- package/.claude/plans/PLAN-142/architect/round-1/security-engineer.md +55 -0
- package/.claude/plans/PLAN-142/architect/round-1/vp-engineering.md +58 -0
- package/.claude/plans/PLAN-142/architect/round-2/anonymization-map.md +11 -0
- package/.claude/plans/PLAN-142/architect/round-2/approved.md +65 -0
- package/.claude/plans/PLAN-142/architect/round-2/consensus.md +78 -0
- package/.claude/plans/PLAN-142/architect/round-2/devops-engineer.md +58 -0
- package/.claude/plans/PLAN-142/architect/round-2/security-engineer.md +56 -0
- package/.claude/plans/PLAN-142/architect/round-2/vp-engineering.md +54 -0
- package/.claude/plans/PLAN-142/staging/EXECUTION-RUNBOOK.md +74 -0
- package/.claude/plans/PLAN-142/staging/STAGING-NOTES.md +63 -0
- package/.claude/plans/PLAN-142/staging/check_pair_rail__invoke_and_consume.py.txt +644 -0
- package/.claude/plans/PLAN-142/staging/codex_adapter_parsers.py.txt +677 -0
- package/.claude/plans/PLAN-142/staging/codex_cli_shape.py +433 -0
- package/.claude/plans/PLAN-142-codex-cli-0139-adapter-migration.md +224 -0
- package/.claude/plans/PLAN-143/architect/round-1/anonymization-map.md +22 -0
- package/.claude/plans/PLAN-143/architect/round-1/consensus.md +108 -0
- package/.claude/plans/PLAN-143/architect/round-1/devops-engineer.md +228 -0
- package/.claude/plans/PLAN-143/architect/round-1/proposal.md +48 -0
- package/.claude/plans/PLAN-143/architect/round-1/security-engineer.md +224 -0
- package/.claude/plans/PLAN-143/architect/round-1/vp-engineering.md +166 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item1-env-inventory.NOTE.md +106 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item2-spool-writer-rotate-guard.patch +41 -0
- package/.claude/plans/PLAN-143/patches/PLAN143-item3-audit-emit-exit-code.patch +32 -0
- package/.claude/plans/PLAN-143-repo-hygiene-debt.md +201 -0
- package/.claude/plans/PLAN-SCHEMA.md +870 -0
- package/.claude/plans/README.md +208 -0
- package/.claude/plans/examples/debate-round-1/consensus.md +166 -0
- package/.claude/plans/examples/debate-round-1/devops-engineer.md +133 -0
- package/.claude/plans/examples/debate-round-1/proposal.md +66 -0
- package/.claude/plans/examples/debate-round-1/security-engineer.md +109 -0
- package/.claude/plans/examples/debate-round-1/vp-engineering.md +110 -0
- package/.claude/policies/.drift-manifest.json +16 -0
- package/.claude/policies/bash-safety.policy.yaml +37 -0
- package/.claude/policies/fixtures/.gitkeep +0 -0
- package/.claude/policies/fixtures/bash-safety.fixtures.jsonl +46 -0
- package/.claude/policies/fixtures/plan-edit.fixtures.jsonl +36 -0
- package/.claude/policies/grandfather-cap.policy.yaml +85 -0
- package/.claude/policies/plan-edit.policy.yaml +152 -0
- package/.claude/policies/rubric-violation-catalogue.yaml +187 -0
- package/.claude/policies/schemas/repo-profile-skill-binding.schema.json +126 -0
- package/.claude/policies/schemas/repo-profile.schema.json +83 -0
- package/.claude/policies/schemas/squad-bundle-frontmatter.schema.json +152 -0
- package/.claude/policies/secret-patterns-exchange.yaml +368 -0
- package/.claude/policies/smart-loading-cap-table.yaml +34 -0
- package/.claude/proposals/.gitkeep +0 -0
- package/.claude/proposals/README.md +42 -0
- package/.claude/proposals/SP-001-code-review-checklist-2026-04-20.md +65 -0
- package/.claude/proposals/SP-001-code-review-checklist-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-002-security-and-auth-2026-04-20.md +74 -0
- package/.claude/proposals/SP-002-security-and-auth-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-003-design-system-and-components-2026-04-20.md +67 -0
- package/.claude/proposals/SP-003-design-system-and-components-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-004-accessibility-and-wcag-2026-04-20.md +68 -0
- package/.claude/proposals/SP-004-accessibility-and-wcag-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-005-ux-and-user-journeys-2026-04-20.md +63 -0
- package/.claude/proposals/SP-005-ux-and-user-journeys-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-006-chaos-and-resilience-2026-04-20.md +79 -0
- package/.claude/proposals/SP-006-chaos-and-resilience-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-007-ai-llm-orchestration-2026-04-20.md +76 -0
- package/.claude/proposals/SP-007-ai-llm-orchestration-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-008-performance-engineering-2026-04-20.md +82 -0
- package/.claude/proposals/SP-008-performance-engineering-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-009-code-review-checklist-2026-04-20.md +76 -0
- package/.claude/proposals/SP-009-code-review-checklist-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-010-accessibility-and-wcag-adopter-note-2026-04-20.md +77 -0
- package/.claude/proposals/SP-010-accessibility-and-wcag-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-011-design-system-and-components-adopter-note-2026-04-20.md +79 -0
- package/.claude/proposals/SP-011-design-system-and-components-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-012-ux-and-user-journeys-adopter-note-2026-04-20.md +83 -0
- package/.claude/proposals/SP-012-ux-and-user-journeys-adopter-note-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-013-frontend-performance-optimization-2026-04-20.md +82 -0
- package/.claude/proposals/SP-013-frontend-performance-optimization-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-014-observability-and-ops-2026-04-20.md +80 -0
- package/.claude/proposals/SP-014-observability-and-ops-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-015-testing-strategy-2026-04-20.md +87 -0
- package/.claude/proposals/SP-015-testing-strategy-2026-04-20.md.asc +8 -0
- package/.claude/proposals/SP-016-code-review-checklist-fluency-rubric-2026-04-28.md +111 -0
- package/.claude/proposals/SP-016-code-review-checklist-fluency-rubric-2026-04-28.md.asc +8 -0
- package/.claude/proposals/SP-017-chaos-and-resilience-adopter-note-2026-04-28.md +87 -0
- package/.claude/proposals/SP-017-chaos-and-resilience-adopter-note-2026-04-28.md.asc +8 -0
- package/.claude/proposals/SP-018-ceo-orchestration-inventory-regen-2026-04-21.md +64 -0
- package/.claude/proposals/SP-018-ceo-orchestration-inventory-regen-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-019-terse-mode-2026-04-21.md +107 -0
- package/.claude/proposals/SP-019-terse-mode-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-020-ceo-orchestration-audit-tokens-2026-04-21.md +74 -0
- package/.claude/proposals/SP-020-ceo-orchestration-audit-tokens-2026-04-21.md.asc +8 -0
- package/.claude/proposals/SP-021-ceo-orchestration-autonomous-loop-2026-04-21.md +71 -0
- package/.claude/proposals/SP-021-ceo-orchestration-autonomous-loop-2026-04-21.md.asc +8 -0
- package/.claude/rag/_index_core.py +344 -0
- package/.claude/rag/indexignore +101 -0
- package/.claude/rag/install-sidecar.sh +275 -0
- package/.claude/rag/models.manifest.json +19 -0
- package/.claude/rag/requirements.lock +40 -0
- package/.claude/rag/sidecar-config.template.json +53 -0
- package/.claude/rag/tests/test_index_core.py +262 -0
- package/.claude/rag/tests/test_install_sidecar.sh +132 -0
- package/.claude/scripts/.known_actions_floor.lock +0 -0
- package/.claude/scripts/admin-invite.py +199 -0
- package/.claude/scripts/adopter-metrics.py +712 -0
- package/.claude/scripts/aek-calibration-c2.py +253 -0
- package/.claude/scripts/aek-calibration-c3.py +382 -0
- package/.claude/scripts/aggregate-changesets.py +350 -0
- package/.claude/scripts/architect-bundle-validate.py +227 -0
- package/.claude/scripts/audit-dashboard.py +1320 -0
- package/.claude/scripts/audit-log-labels.jsonl +0 -0
- package/.claude/scripts/audit-log-retain.py +404 -0
- package/.claude/scripts/audit-query.py +3333 -0
- package/.claude/scripts/audit-telemetry.py +337 -0
- package/.claude/scripts/audit-tokens.py +502 -0
- package/.claude/scripts/audit-verify-chain.py +537 -0
- package/.claude/scripts/backup-audit.py +247 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/README.md +194 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/fixtures/baseline.json +1 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/fixtures/expected_quantiles.json +11 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/import_floor_bench.py +791 -0
- package/.claude/scripts/benchmark/plan-071-import-floor/run_bench.sh +180 -0
- package/.claude/scripts/benchmark-fallback-scorer.py +254 -0
- package/.claude/scripts/benchmark-judge.py +621 -0
- package/.claude/scripts/budget-summary.py +946 -0
- package/.claude/scripts/build-canonical-models.py +645 -0
- package/.claude/scripts/calibration-kappa.py +262 -0
- package/.claude/scripts/cc-analytics-pull.py +393 -0
- package/.claude/scripts/ceo-backup.sh +307 -0
- package/.claude/scripts/ceo-boot.py +3017 -0
- package/.claude/scripts/ceo-cost.py +1116 -0
- package/.claude/scripts/ceo-diagnose.py +486 -0
- package/.claude/scripts/ceo-escalation-detector.py +743 -0
- package/.claude/scripts/ceo-health.py +584 -0
- package/.claude/scripts/ceo-info.py +1001 -0
- package/.claude/scripts/ceo-restore.sh +215 -0
- package/.claude/scripts/chaos-inject.py +439 -0
- package/.claude/scripts/check-action-sha-drift.py +275 -0
- package/.claude/scripts/check-active-hooks-executable.py +119 -0
- package/.claude/scripts/check-adr-chain.py +617 -0
- package/.claude/scripts/check-audit-action-name-convention.py +221 -0
- package/.claude/scripts/check-audit-hmac-null.py +253 -0
- package/.claude/scripts/check-audit-read-api-stable.py +239 -0
- package/.claude/scripts/check-audit-registry-coverage.py +999 -0
- package/.claude/scripts/check-auto-activation-flags.py +180 -0
- package/.claude/scripts/check-canonical-doc-freshness.py +222 -0
- package/.claude/scripts/check-claude-md-claims.py +346 -0
- package/.claude/scripts/check-confidence-gate-drift.py +295 -0
- package/.claude/scripts/check-conformance-harness-mapping.py +503 -0
- package/.claude/scripts/check-contamination.sh +25 -0
- package/.claude/scripts/check-creative-rewrite.py +596 -0
- package/.claude/scripts/check-debate-round-lifecycle.py +185 -0
- package/.claude/scripts/check-debt-ledger.py +305 -0
- package/.claude/scripts/check-docs-drift.py +259 -0
- package/.claude/scripts/check-docs-freshness.py +487 -0
- package/.claude/scripts/check-flip-criteria-drift.py +426 -0
- package/.claude/scripts/check-flip-release-gate-consistency.py +134 -0
- package/.claude/scripts/check-framework-updates.sh +239 -0
- package/.claude/scripts/check-function-length.py +426 -0
- package/.claude/scripts/check-model-deprecations.py +377 -0
- package/.claude/scripts/check-originator-residue.py +248 -0
- package/.claude/scripts/check-pitfall-regression.sh +153 -0
- package/.claude/scripts/check-policy-drift.py +74 -0
- package/.claude/scripts/check-roadmap-binding.py +170 -0
- package/.claude/scripts/check-rule-invariants.py +385 -0
- package/.claude/scripts/check-sdk-compat.sh +76 -0
- package/.claude/scripts/check-secret-pattern-coverage.py +175 -0
- package/.claude/scripts/check-sidecar-manifest.py +493 -0
- package/.claude/scripts/check-skill-activation-mode.py +41 -0
- package/.claude/scripts/check-skill-health.sh +179 -0
- package/.claude/scripts/check-spec-drift.py +147 -0
- package/.claude/scripts/check-staleness.py +506 -0
- package/.claude/scripts/check-stdlib-only.py +373 -0
- package/.claude/scripts/check-substrate-watch.py +285 -0
- package/.claude/scripts/check-swarm-harness-mapping.py +380 -0
- package/.claude/scripts/check-test-audit-isolation.py +622 -0
- package/.claude/scripts/check-test-env-hygiene.py +509 -0
- package/.claude/scripts/check-threat-model-freshness.py +313 -0
- package/.claude/scripts/check-tier-boundaries.py +233 -0
- package/.claude/scripts/check-tla-schema-drift.py +272 -0
- package/.claude/scripts/check_atlas_fpr.py +595 -0
- package/.claude/scripts/check_contamination.py +337 -0
- package/.claude/scripts/check_known_actions_floor.py +155 -0
- package/.claude/scripts/check_threat_model_coverage.py +214 -0
- package/.claude/scripts/check_translations_drift.py +199 -0
- package/.claude/scripts/codex_invoke.py +436 -0
- package/.claude/scripts/compare-adopters.py +549 -0
- package/.claude/scripts/confidence-gate-backfill.py +261 -0
- package/.claude/scripts/confidence_gate.py +736 -0
- package/.claude/scripts/context-budget.py +1887 -0
- package/.claude/scripts/contextual-recommender.py +815 -0
- package/.claude/scripts/cost-table.yaml +99 -0
- package/.claude/scripts/debate-converge.py +335 -0
- package/.claude/scripts/debate-emit.py +132 -0
- package/.claude/scripts/debate-orchestrate.py +972 -0
- package/.claude/scripts/detect-repo-profile.py +1280 -0
- package/.claude/scripts/detectors/__init__.py +19 -0
- package/.claude/scripts/detectors/looping.py +127 -0
- package/.claude/scripts/detectors/overpowered.py +96 -0
- package/.claude/scripts/detectors/retry_churn.py +119 -0
- package/.claude/scripts/detectors/schema.py +94 -0
- package/.claude/scripts/detectors/tests/__init__.py +0 -0
- package/.claude/scripts/detectors/tests/fixtures.py +420 -0
- package/.claude/scripts/detectors/tests/test_looping.py +124 -0
- package/.claude/scripts/detectors/tests/test_overpowered.py +114 -0
- package/.claude/scripts/detectors/tests/test_retry_churn.py +101 -0
- package/.claude/scripts/detectors/tests/test_schema.py +109 -0
- package/.claude/scripts/detectors/tests/test_tool_cascade.py +131 -0
- package/.claude/scripts/detectors/tests/test_wasteful_thinking.py +112 -0
- package/.claude/scripts/detectors/tests/test_weak_model.py +104 -0
- package/.claude/scripts/detectors/tool_cascade.py +127 -0
- package/.claude/scripts/detectors/wasteful_thinking.py +99 -0
- package/.claude/scripts/detectors/weak_model.py +92 -0
- package/.claude/scripts/env-inventory-check.py +268 -0
- package/.claude/scripts/env-inventory.json +3305 -0
- package/.claude/scripts/extract-skill.py +456 -0
- package/.claude/scripts/fan-plan-parser.py +370 -0
- package/.claude/scripts/find-orphan-sentinels.py +89 -0
- package/.claude/scripts/first-run-wizard.py +1151 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/.env.example +1 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/exchanges/binance.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/exchanges/coinbase.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/package.json +5 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/strategies/grid.py +3 -0
- package/.claude/scripts/fixtures/cloned-trading-repo/strategies/pairs.py +3 -0
- package/.claude/scripts/fixtures/missing-package-manifest/README.md +3 -0
- package/.claude/scripts/fixtures/missing-package-manifest/src/main.py +1 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/package.json +9 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/requirements.txt +2 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/src/api/handler.py +2 -0
- package/.claude/scripts/fixtures/mixed-frontend-backend/src/pages/index.tsx +1 -0
- package/.claude/scripts/fixtures/monorepo/apps/app-a/README.md +1 -0
- package/.claude/scripts/fixtures/monorepo/apps/app-b/index.ts +1 -0
- package/.claude/scripts/fixtures/monorepo/package.json +5 -0
- package/.claude/scripts/fixtures/monorepo/packages/lib-a/index.js +1 -0
- package/.claude/scripts/fixtures/monorepo/packages/lib-b/index.js +1 -0
- package/.claude/scripts/fixtures/monorepo/pnpm-workspace.yaml +3 -0
- package/.claude/scripts/fixtures/persona-coverage-expected-thresholds.yaml +20 -0
- package/.claude/scripts/flip-criteria-drift-allowlist.txt +31 -0
- package/.claude/scripts/generate-adr-index.py +339 -0
- package/.claude/scripts/generate-available-models.py +280 -0
- package/.claude/scripts/generate-dispatch.py +430 -0
- package/.claude/scripts/generate-sbom.py +287 -0
- package/.claude/scripts/generate-skill-inventory.sh +193 -0
- package/.claude/scripts/github-api-client.py +297 -0
- package/.claude/scripts/goap-planner.py +742 -0
- package/.claude/scripts/hook-profiler.py +671 -0
- package/.claude/scripts/import-skill.py +569 -0
- package/.claude/scripts/import_ui_ux_pro_max.py +137 -0
- package/.claude/scripts/inject-agent-context.sh +948 -0
- package/.claude/scripts/k-calibration.py +456 -0
- package/.claude/scripts/key-hygiene.py +511 -0
- package/.claude/scripts/lesson-restore.py +171 -0
- package/.claude/scripts/lesson_ranker.py +100 -0
- package/.claude/scripts/lessons.py +883 -0
- package/.claude/scripts/lint-skills.py +555 -0
- package/.claude/scripts/local/README.md +280 -0
- package/.claude/scripts/local/check-doc-skill-paths.sh +124 -0
- package/.claude/scripts/local/dependency-graph.py +684 -0
- package/.claude/scripts/local/estimate-calibrator.py +240 -0
- package/.claude/scripts/local/findings-pretty-print.py +78 -0
- package/.claude/scripts/local/generate-ceremony.sh +558 -0
- package/.claude/scripts/local/pair-rail-gate.sh +156 -0
- package/.claude/scripts/local/release-dry-run.py +853 -0
- package/.claude/scripts/local/tests/test_dependency_graph.py +364 -0
- package/.claude/scripts/local/tests/test_generate_ceremony.sh +144 -0
- package/.claude/scripts/local/tests/test_release_dry_run.py +743 -0
- package/.claude/scripts/local/validate-findings.py +168 -0
- package/.claude/scripts/local/validate-saved-workflows.js +69 -0
- package/.claude/scripts/local/verify-counts.sh +420 -0
- package/.claude/scripts/local/verify-scope-coverage.py +205 -0
- package/.claude/scripts/local/verify-staging-manifest.py +188 -0
- package/.claude/scripts/local/wave-readonly-monitor.py +271 -0
- package/.claude/scripts/log-friction.sh +290 -0
- package/.claude/scripts/mcp/code_nav_bridge.py +259 -0
- package/.claude/scripts/mcp-server/__init__.py +16 -0
- package/.claude/scripts/mcp-server/auth.py +333 -0
- package/.claude/scripts/mcp-server/cost.py +108 -0
- package/.claude/scripts/mcp-server/dispatch.py +853 -0
- package/.claude/scripts/mcp-server/handlers/__init__.py +16 -0
- package/.claude/scripts/mcp-server/handlers/audit_query.py +384 -0
- package/.claude/scripts/mcp-server/handlers/get_audit_log.py +163 -0
- package/.claude/scripts/mcp-server/handlers/get_cost_budget.py +130 -0
- package/.claude/scripts/mcp-server/handlers/get_debate_state.py +207 -0
- package/.claude/scripts/mcp-server/handlers/get_skill.py +199 -0
- package/.claude/scripts/mcp-server/handlers/list_agents.py +236 -0
- package/.claude/scripts/mcp-server/handlers/list_pitfalls.py +192 -0
- package/.claude/scripts/mcp-server/handlers/list_skills.py +197 -0
- package/.claude/scripts/mcp-server/handlers/plan_status.py +489 -0
- package/.claude/scripts/mcp-server/handlers/server_capabilities.py +127 -0
- package/.claude/scripts/mcp-server/handlers/spawn_agent.py +274 -0
- package/.claude/scripts/mcp-server/http_transport.py +373 -0
- package/.claude/scripts/mcp-server/rate_limit.py +345 -0
- package/.claude/scripts/mcp-server/server.py +212 -0
- package/.claude/scripts/mcp-server/start-mcp-server.sh +111 -0
- package/.claude/scripts/mcp-server/stdio_transport.py +150 -0
- package/.claude/scripts/mcp-server/tests/__init__.py +1 -0
- package/.claude/scripts/mcp-server/tests/test_auth.py +454 -0
- package/.claude/scripts/mcp-server/tests/test_cost.py +122 -0
- package/.claude/scripts/mcp-server/tests/test_dispatch.py +448 -0
- package/.claude/scripts/mcp-server/tests/test_dispatch_bearer_replay_wire.py +358 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_get_audit_log.py +107 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_get_skill.py +108 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_agents.py +92 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_pitfalls.py +103 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_list_skills.py +121 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_server_capabilities.py +128 -0
- package/.claude/scripts/mcp-server/tests/test_handlers_spawn_agent.py +275 -0
- package/.claude/scripts/mcp-server/tests/test_http_transport.py +418 -0
- package/.claude/scripts/mcp-server/tests/test_rate_limit.py +239 -0
- package/.claude/scripts/mcp-server/tests/test_server.py +125 -0
- package/.claude/scripts/mcp-server/tests/test_stdio_transport.py +196 -0
- package/.claude/scripts/mcp-soak-monitor.py +224 -0
- package/.claude/scripts/memory-prioritize.py +516 -0
- package/.claude/scripts/migrate-grandfather-to-sha256.py +384 -0
- package/.claude/scripts/model-deprecations.json +165 -0
- package/.claude/scripts/morning-ceremony.py +266 -0
- package/.claude/scripts/morning_ledger.py +446 -0
- package/.claude/scripts/mutation-floors.yaml +51 -0
- package/.claude/scripts/mutation-test.py +506 -0
- package/.claude/scripts/nightly-proposals.py +210 -0
- package/.claude/scripts/optimizer/__init__.py +46 -0
- package/.claude/scripts/optimizer/_codex_redaction.py +101 -0
- package/.claude/scripts/optimizer/_skeleton.py +137 -0
- package/.claude/scripts/optimizer/codex_phase_gate.py +257 -0
- package/.claude/scripts/optimizer/complexity_gate.py +208 -0
- package/.claude/scripts/optimizer/fanout.py +249 -0
- package/.claude/scripts/optimizer/model_choice.py +151 -0
- package/.claude/scripts/optimizer/model_normalize.py +118 -0
- package/.claude/scripts/optimizer/rag_recommender.py +110 -0
- package/.claude/scripts/optimizer/recommender.py +213 -0
- package/.claude/scripts/optimizer/tests/__init__.py +0 -0
- package/.claude/scripts/optimizer/tests/test_codex_phase_gate.py +314 -0
- package/.claude/scripts/optimizer/tests/test_codex_review_invoked_emission.py +225 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_complexity_gate.py +122 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_fanout.py +134 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_model_choice.py +124 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_model_normalize.py +155 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_rag_recommender.py +190 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_recommender.py +131 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_skeleton.py +117 -0
- package/.claude/scripts/optimizer/tests/test_optimizer_types.py +53 -0
- package/.claude/scripts/optimizer/types.py +122 -0
- package/.claude/scripts/osv_check.py +559 -0
- package/.claude/scripts/otel-export.py +329 -0
- package/.claude/scripts/otel-local-sink.py +470 -0
- package/.claude/scripts/persona_demand_resolver.py +658 -0
- package/.claude/scripts/persona_demand_scan.py +382 -0
- package/.claude/scripts/persona_waive_parser.py +127 -0
- package/.claude/scripts/pitfall-query.py +218 -0
- package/.claude/scripts/plan-tokens.py +843 -0
- package/.claude/scripts/policy-shadow-runner.py +445 -0
- package/.claude/scripts/predict-budget/predict-plan-cost.py +581 -0
- package/.claude/scripts/predict-budget/tests/test_predict_plan_cost.py +375 -0
- package/.claude/scripts/profile-opus-4-7.py +557 -0
- package/.claude/scripts/prune-lessons.py +453 -0
- package/.claude/scripts/rate-card-calibrate.py +283 -0
- package/.claude/scripts/rate-card-fixtures.json +18 -0
- package/.claude/scripts/reality-ledger.py +2175 -0
- package/.claude/scripts/red-team-corpus/.byte-identity-check.txt +86 -0
- package/.claude/scripts/red-team-corpus/README.md +132 -0
- package/.claude/scripts/red-team-corpus/external/EXT-001-prompt-inject.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-002-hackaprompt.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-003-gcg.md +31 -0
- package/.claude/scripts/red-team-corpus/external/EXT-004-tap.md +23 -0
- package/.claude/scripts/red-team-corpus/external/EXT-005-cybersecurity-eval.md +30 -0
- package/.claude/scripts/red-team-corpus/external/EXT-006-anthropic-samples.md +26 -0
- package/.claude/scripts/red-team-corpus/external/EXT-007-trojan-source.md +26 -0
- package/.claude/scripts/red-team-corpus/external/EXT-008-owasp-llm-top10.md +33 -0
- package/.claude/scripts/red-team-corpus/external/EXT-009-jailbreak-bench.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-010-advbench.md +22 -0
- package/.claude/scripts/red-team-corpus/external/EXT-011-mitre-atlas.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-012-npm-typosquat.md +23 -0
- package/.claude/scripts/red-team-corpus/external/EXT-013-log-tamper-poc.md +25 -0
- package/.claude/scripts/red-team-corpus/external/EXT-014-cwe-798-credentials.md +24 -0
- package/.claude/scripts/red-team-corpus/external/EXT-015-garak.md +28 -0
- package/.claude/scripts/red-team-corpus/external/EXT-016-skill-content-injection-via-markdown.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-017-persona-impersonation-ceo.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-018-file-assignment-wildcard-escape.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-019-veto-bypass-force-proceed.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-020-canonical-edit-circumvent-settings.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-021-spawn-without-agent-profile.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-022-hidden-unicode-in-skill-name.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-023-mcp-spawn-governance-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-024-adapter-credential-in-error-trace.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-025-sandbox-escape-nested-subshell.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-026-plan-edit-without-debate.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-027-audit-log-rotation-race.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-028-npm-dependency-confusion.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-029-output-safety-unicode-confusable.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-030-adapter-retry-storm-dos.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-031-team-md-direct-edit.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-032-sandbox-env-var-exfil.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-033-mcp-rate-limit-bypass-headers.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-034-otel-span-attribute-leak.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-035-skill-patch-polyglot-payload.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-036-output-safety-base64-triple-wrap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-037-plan-id-cross-plan-memory-read.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-038-npm-slsa-provenance-strip.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-039-adapter-exfil-streaming-chunk.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/EXT-040-sandbox-symlink-to-secrets.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/external/README.md +63 -0
- package/.claude/scripts/red-team-corpus/flake-budget.yaml +244 -0
- package/.claude/scripts/red-team-corpus/provenance.md +74 -0
- package/.claude/scripts/red-team-corpus/regression/REG-001-s3-audit-emission-gap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-002-audit-registry-miss.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-003-breaker-provider-kwarg-missing.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-004-canonical-edit-conftest-block.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-005-mcp-dispatch-oversized-handler.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-006-audit-registry-false-orphan.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-007-spec-count-undercount.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-008-adr-reserved-slot-phantom.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-009-tlc-pending-placeholder.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-010-mutation-kill-rate-fake.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-011-byte-identity-governance-persona.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-012-conformance-mapping-partial-path.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-013-l1-fairness-lazy-fire.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-014-mcp-path-traversal-skill.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/regression/REG-015-mcp-hmac-timestamp-skew.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-001-skill-patch-bidi-trojan.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-002-skill-patch-zero-width-smuggle.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-003-skill-patch-exec-smuggled-fence.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-004-skill-patch-oversized-diff.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-005-audit-log-byte-rewrite.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-006-audit-log-truncation.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-007-audit-log-lock-race.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-008-plan-id-env-spoof.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-009-plan-id-frontmatter-hijack.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-010-plan-id-cross-plan-read.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-011-sandbox-escape-curl-exfil.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-012-sandbox-escape-env-dump.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-013-sandbox-escape-symlink-plant.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-014-mcp-handler-governance-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-015-mcp-handler-acl-enumeration.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-016-mcp-handler-rate-limit-evasion.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-017-adapter-exfil-via-error-message.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-018-adapter-exfil-otel-attr.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-019-adapter-exfil-retry-replay.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-020-output-safety-nfkc-bypass.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-021-output-safety-base64-double-wrap.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-022-output-safety-entropy-below-threshold.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-023-output-safety-regex-obfuscation.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-024-output-safety-luhn-partial.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-025-npm-tamper-supply-chain.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-026-npm-tamper-typo-squat.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/synthetic/SYN-027-npm-tamper-unsigned-slsa.jsonl +1 -0
- package/.claude/scripts/red-team-corpus/v1/fixtures.jsonl +67 -0
- package/.claude/scripts/red-team-corpus/v1/fixtures.jsonl.sha256 +1 -0
- package/.claude/scripts/red-team-corpus/v1/labels.json +88 -0
- package/.claude/scripts/red-team-eval.py +1099 -0
- package/.claude/scripts/registry.py +438 -0
- package/.claude/scripts/replay/__init__.py +0 -0
- package/.claude/scripts/replay/replay-session.py +1232 -0
- package/.claude/scripts/replay/tests/__init__.py +0 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/api-key-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/cpf-cnpj-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/email-in-log-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/homoglyph-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/jwt-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/os-path-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-01-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-02-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-03-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-04-positive.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-05-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-06-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-07-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/fixtures/pan-08-negative.jsonl +1 -0
- package/.claude/scripts/replay/tests/test_replay_redact_lib.py +971 -0
- package/.claude/scripts/replay/tests/test_replay_session.py +396 -0
- package/.claude/scripts/replay/tests/test_replay_session_capture.py +522 -0
- package/.claude/scripts/repo-profile.schema.json +83 -0
- package/.claude/scripts/run-promotion-gate.py +631 -0
- package/.claude/scripts/run-skill-benchmark.py +1276 -0
- package/.claude/scripts/scan-injection-strict.sh +162 -0
- package/.claude/scripts/scan-injection.py +305 -0
- package/.claude/scripts/scan-upstream-injection.py +663 -0
- package/.claude/scripts/scratchpad.py +427 -0
- package/.claude/scripts/self_test.py +602 -0
- package/.claude/scripts/session-graph-build.py +728 -0
- package/.claude/scripts/session-resume.py +363 -0
- package/.claude/scripts/set-quality-profile.sh +229 -0
- package/.claude/scripts/skill-budget-generator.py +599 -0
- package/.claude/scripts/skill-import-rubric.py +368 -0
- package/.claude/scripts/skill-index-build.py +534 -0
- package/.claude/scripts/skill-patch-apply.py +1088 -0
- package/.claude/scripts/skill-patch-propose.py +690 -0
- package/.claude/scripts/skill-retrieve.py +522 -0
- package/.claude/scripts/skill_grandfather_parser.py +295 -0
- package/.claude/scripts/smart-loading-resolver.py +994 -0
- package/.claude/scripts/spot-check-findings.py +211 -0
- package/.claude/scripts/squad-export.py +437 -0
- package/.claude/scripts/squad-import.py +741 -0
- package/.claude/scripts/status.py +315 -0
- package/.claude/scripts/statusline-ceo.py +597 -0
- package/.claude/scripts/substrate-watch.json +54 -0
- package/.claude/scripts/success-receipt.py +1038 -0
- package/.claude/scripts/swarm/__init__.py +42 -0
- package/.claude/scripts/swarm/_benchmark_replay.py +259 -0
- package/.claude/scripts/swarm/_child_isolation.py +113 -0
- package/.claude/scripts/swarm/_coordinator_sim.py +293 -0
- package/.claude/scripts/swarm/_governors.py +277 -0
- package/.claude/scripts/swarm/_integration.py +547 -0
- package/.claude/scripts/swarm/_parent_death.py +176 -0
- package/.claude/scripts/swarm/_process_group.py +250 -0
- package/.claude/scripts/swarm/_replay_tournament.py +214 -0
- package/.claude/scripts/swarm/_spawn_gate.py +292 -0
- package/.claude/scripts/swarm/_subagent_fabrication.py +444 -0
- package/.claude/scripts/swarm/_worktree_pool.py +276 -0
- package/.claude/scripts/swarm/coordinator.py +543 -0
- package/.claude/scripts/swarm/file_assignment.py +111 -0
- package/.claude/scripts/swarm/fixtures/mcp_corpus.json +111 -0
- package/.claude/scripts/swarm/kill_switch.py +260 -0
- package/.claude/scripts/swarm/loop_runner.py +486 -0
- package/.claude/scripts/swarm/recovery.py +178 -0
- package/.claude/scripts/swarm/test_mcp_injection_repro.py +518 -0
- package/.claude/scripts/swarm/test_rail_anomaly_repro.py +586 -0
- package/.claude/scripts/swarm/tests/__init__.py +1 -0
- package/.claude/scripts/swarm/tests/test_benchmark_manifest_schema.py +227 -0
- package/.claude/scripts/swarm/tests/test_benchmark_replay.py +248 -0
- package/.claude/scripts/swarm/tests/test_child_isolation.py +138 -0
- package/.claude/scripts/swarm/tests/test_coordinator.py +289 -0
- package/.claude/scripts/swarm/tests/test_coordinator_production_integration.py +434 -0
- package/.claude/scripts/swarm/tests/test_coordinator_sim.py +192 -0
- package/.claude/scripts/swarm/tests/test_coordinator_tick.py +165 -0
- package/.claude/scripts/swarm/tests/test_file_assignment.py +100 -0
- package/.claude/scripts/swarm/tests/test_governors.py +269 -0
- package/.claude/scripts/swarm/tests/test_integration.py +344 -0
- package/.claude/scripts/swarm/tests/test_kill_switch.py +307 -0
- package/.claude/scripts/swarm/tests/test_loop_runner.py +168 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_circuit_breaker.py +555 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_gate_enforcement.py +304 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_gate_kill_switch.py +147 -0
- package/.claude/scripts/swarm/tests/test_loop_runner_sentinel_revocation_slo.py +112 -0
- package/.claude/scripts/swarm/tests/test_optimizer_killswitch.py +205 -0
- package/.claude/scripts/swarm/tests/test_parent_death.py +128 -0
- package/.claude/scripts/swarm/tests/test_parent_death_integration.py +305 -0
- package/.claude/scripts/swarm/tests/test_process_group.py +132 -0
- package/.claude/scripts/swarm/tests/test_process_group_reap.py +212 -0
- package/.claude/scripts/swarm/tests/test_rail_anomaly_repro.py +516 -0
- package/.claude/scripts/swarm/tests/test_recovery.py +165 -0
- package/.claude/scripts/swarm/tests/test_replay_tournament.py +284 -0
- package/.claude/scripts/swarm/tests/test_spawn_gate.py +265 -0
- package/.claude/scripts/swarm/tests/test_subagent_fabrication.py +824 -0
- package/.claude/scripts/swarm/tests/test_swarm_activation_smoke.py +112 -0
- package/.claude/scripts/swarm/tests/test_tournament.py +195 -0
- package/.claude/scripts/swarm/tests/test_worktree_pool.py +252 -0
- package/.claude/scripts/swarm/tournament.py +261 -0
- package/.claude/scripts/task-route.py +807 -0
- package/.claude/scripts/test-env-hygiene-allowlist.yaml +1093 -0
- package/.claude/scripts/tests/DEFERRED.md +99 -0
- package/.claude/scripts/tests/conftest.py +42 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/bad-type.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/missing-frontmatter.md +1 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/multidoc.md +6 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/sample-CHANGELOG.md +29 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/second-minor.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/single-patch.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/third-major.md +4 -0
- package/.claude/scripts/tests/fixtures/aggregate-changesets/unknown-key.md +6 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/bidi_override.md +12 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/fenced_python.md +19 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/homoglyph.md +11 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/injection.md +11 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/long_line.md +9 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/oversized.md +261 -0
- package/.claude/scripts/tests/fixtures/bad_lessons/zero_width.md +11 -0
- package/.claude/scripts/tests/fixtures/budget_summary/generate_fixtures.py +368 -0
- package/.claude/scripts/tests/fixtures/claims/README.md +21 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/neg-missing.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/neg-no-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-extract.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-main.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/pos-verify.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/function_exists/quoted-colon-path.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/codeblock-skipped.txt +8 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/neg-blocked-os.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/neg-relative.txt +5 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/pos-dotted.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/import_resolves/pos-stdlib-like.txt +5 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/neg-missing-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/neg-too-long.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/pos-large.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/pos-small.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/line_range/quoted-path.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/codeblock-skipped.txt +7 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-absolute-outside.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-dotdot-escape.txt +7 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-imaginary.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-proc-self.txt +6 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-symlink-escape.txt +8 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/neg-typo.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-claude.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-readme.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/path_exists/pos-self.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/neg-fake.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/neg-not-sha.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-head.txt +4 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-root.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/sha_exists/pos-short.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/neg-missing-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/neg-wrong-test.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-audit-emit.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-extra.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/pos-file.txt +1 -0
- package/.claude/scripts/tests/fixtures/claims/test_passes/quoted-pytest-selector.txt +1 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-1/a.md +39 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-1/b.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-2/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/converged-pair-1/round-2/b.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-1/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-1/b.md +34 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-2/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/not-converged-pair-1/round-2/b.md +34 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/partial-overlap/round-1/a.md +35 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/partial-overlap/round-2/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-1/a.md +36 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-1/b.md +33 -0
- package/.claude/scripts/tests/fixtures/debate_convergence/with-secret/round-2/a.md +34 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_anchor_only.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_broken.md +5 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_external_url.md +9 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_fenced_code.md +18 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_frontmatter.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_html_comment.md +10 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_inline_code.md +7 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_in_table.md +6 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_relative_parent.md +7 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/link_url_encoded.md +5 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/real_target.md +3 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/sub/dir.md +3 -0
- package/.claude/scripts/tests/fixtures/docs_freshness/with%20space.md +3 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_auth.md +11 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_logging.md +11 -0
- package/.claude/scripts/tests/fixtures/good_lessons/clean_retry.md +11 -0
- package/.claude/scripts/tests/fixtures/gpg-keyring-fixture.py +209 -0
- package/.claude/scripts/tests/fixtures/injection/benign-01.txt +8 -0
- package/.claude/scripts/tests/fixtures/injection/benign-02.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/benign-03.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-04.txt +9 -0
- package/.claude/scripts/tests/fixtures/injection/benign-05.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-06.txt +7 -0
- package/.claude/scripts/tests/fixtures/injection/benign-07.txt +11 -0
- package/.claude/scripts/tests/fixtures/injection/benign-08.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-01.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-02.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-03.txt +4 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-04.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-05.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-06.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-07.txt +5 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-08.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-09.txt +3 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-10.txt +2 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-11.txt +3 -0
- package/.claude/scripts/tests/fixtures/injection/malicious-12.txt +5 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/manifest.json +49 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-051.md +36 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-052.md +32 -0
- package/.claude/scripts/tests/fixtures/plan-tokens-calibration/plan-058.md +31 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-boundary/docs/SAMPLE.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-negative/.claude/scripts/sample.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-negative/docs/SAMPLE.md +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-positive/.claude/scripts/sample.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-1-positive/docs/SAMPLE.md +9 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-boundary/README.md +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-negative/.claude/rag/requirements.lock +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-2-positive/.claude/rag/requirements.lock +2 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-boundary/.claude/agents/devops.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-negative/.claude/agents/devops.md +5 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-negative/audit-log.jsonl +2 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-positive/.claude/agents/devops.md +7 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-3-positive/audit-log.jsonl +4 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-boundary/.claude/adr/ADR-997-fixture-superseded.md +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-negative/.claude/adr/ADR-998-fixture-negative.md +16 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-4-positive/.claude/adr/ADR-999-fixture-positive.md +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/hooks/_lib/audit_emit.py +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-boundary/.claude/scripts/dynamic_action.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/hooks/_lib/audit_emit.py +11 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-negative/.claude/scripts/registered_emitter.py +8 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/hooks/_lib/.do-not-import-from-here +15 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/hooks/_lib/audit_emit.py +12 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/detector-6-positive/.claude/scripts/phantom_emitter.py +13 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/issue-body-template.md +47 -0
- package/.claude/scripts/tests/fixtures/reality-ledger/redaction/_test_corpus.py +7 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/.env.example +5 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/Cargo.toml +9 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/exchanges/binance.py +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/cloned-trading-repo/strategies/triangular.py +4 -0
- package/.claude/scripts/tests/fixtures/repo_profile/missing-package-manifest/README.md +7 -0
- package/.claude/scripts/tests/fixtures/repo_profile/missing-package-manifest/notes.md +1 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/api/server.js +4 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/package.json +15 -0
- package/.claude/scripts/tests/fixtures/repo_profile/mixed-frontend-backend/pages/index.tsx +3 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/README.md +6 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/apps/backend/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/apps/frontend/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/package.json +5 -0
- package/.claude/scripts/tests/fixtures/repo_profile/monorepo/packages/shared/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/sample_audit_log.jsonl +50 -0
- package/.claude/scripts/tests/fixtures/siem/.gitkeep +0 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-engine.yaml +8 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-fail-closed.yaml +7 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-fintech.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-frontend.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-generic.yaml +8 -0
- package/.claude/scripts/tests/fixtures/smart_loading/profile-trading-readonly.yaml +9 -0
- package/.claude/scripts/tests/fixtures/smart_loading/synthetic-skill-catalog.yaml +186 -0
- package/.claude/scripts/tests/fixtures/squad_marketplace/.gitkeep +4 -0
- package/.claude/scripts/tests/fixtures/task-route/calibration-holdout.json +49 -0
- package/.claude/scripts/tests/fixtures/task-route/calibration-train.json +174 -0
- package/.claude/scripts/tests/perf/__init__.py +3 -0
- package/.claude/scripts/tests/perf/perf_utils.py +134 -0
- package/.claude/scripts/tests/perf/test_kernel_hard_deny_microbench.py +149 -0
- package/.claude/scripts/tests/perf/test_optimizer_complexity_gate_p99.py +145 -0
- package/.claude/scripts/tests/perf/test_wave_c_canonical_json.py +132 -0
- package/.claude/scripts/tests/perf/test_wave_c_filelock_mkdir.py +71 -0
- package/.claude/scripts/tests/perf/test_wave_c_plan_glob_cache.py +84 -0
- package/.claude/scripts/tests/perf/test_wave_c_preview_collapse.py +98 -0
- package/.claude/scripts/tests/perf/test_wave_c_sys_modules.py +104 -0
- package/.claude/scripts/tests/test_a4_pricing_doctrine.py +127 -0
- package/.claude/scripts/tests/test_admin_invite.py +173 -0
- package/.claude/scripts/tests/test_adopter_metrics.py +723 -0
- package/.claude/scripts/tests/test_aek_calibration_c2.py +107 -0
- package/.claude/scripts/tests/test_aek_calibration_c3.py +192 -0
- package/.claude/scripts/tests/test_aek_state_machine.py +385 -0
- package/.claude/scripts/tests/test_aggregate_changesets.py +646 -0
- package/.claude/scripts/tests/test_architect_bundle_validate.py +159 -0
- package/.claude/scripts/tests/test_audit_dashboard.py +822 -0
- package/.claude/scripts/tests/test_audit_log_dispatch_hint.py +91 -0
- package/.claude/scripts/tests/test_audit_log_retain.py +394 -0
- package/.claude/scripts/tests/test_audit_query.py +1177 -0
- package/.claude/scripts/tests/test_audit_query_by_domain.py +576 -0
- package/.claude/scripts/tests/test_audit_query_claims.py +92 -0
- package/.claude/scripts/tests/test_audit_query_critical.py +267 -0
- package/.claude/scripts/tests/test_audit_query_tokens.py +106 -0
- package/.claude/scripts/tests/test_audit_telemetry.py +214 -0
- package/.claude/scripts/tests/test_audit_tokens.py +255 -0
- package/.claude/scripts/tests/test_audit_verify_chain.py +189 -0
- package/.claude/scripts/tests/test_backup_audit.py +295 -0
- package/.claude/scripts/tests/test_benchmark_fallback_scorer.py +299 -0
- package/.claude/scripts/tests/test_benchmark_judge.py +569 -0
- package/.claude/scripts/tests/test_benchmarks_replay.py +313 -0
- package/.claude/scripts/tests/test_budget_summary.py +628 -0
- package/.claude/scripts/tests/test_build_canonical_models.py +349 -0
- package/.claude/scripts/tests/test_calibration_kappa.py +234 -0
- package/.claude/scripts/tests/test_cc_analytics_pull.py +296 -0
- package/.claude/scripts/tests/test_ceo_backup.py +318 -0
- package/.claude/scripts/tests/test_ceo_boot.py +643 -0
- package/.claude/scripts/tests/test_ceo_boot_audit_emit.py +484 -0
- package/.claude/scripts/tests/test_ceo_boot_enhanced.py +706 -0
- package/.claude/scripts/tests/test_ceo_boot_persona_cadence.py +392 -0
- package/.claude/scripts/tests/test_ceo_boot_plan_082.py +365 -0
- package/.claude/scripts/tests/test_ceo_boot_tamper_tripwires.py +556 -0
- package/.claude/scripts/tests/test_ceo_boot_task_candidate.py +868 -0
- package/.claude/scripts/tests/test_ceo_cost.py +221 -0
- package/.claude/scripts/tests/test_ceo_cost_stream.py +1076 -0
- package/.claude/scripts/tests/test_ceo_diagnose.py +314 -0
- package/.claude/scripts/tests/test_ceo_escalation_detector.py +591 -0
- package/.claude/scripts/tests/test_ceo_health.py +202 -0
- package/.claude/scripts/tests/test_ceo_info.py +542 -0
- package/.claude/scripts/tests/test_chaos_inject_lockdown.py +384 -0
- package/.claude/scripts/tests/test_check_action_sha_drift.py +174 -0
- package/.claude/scripts/tests/test_check_active_hooks_executable.py +79 -0
- package/.claude/scripts/tests/test_check_adr_chain.py +665 -0
- package/.claude/scripts/tests/test_check_audit_hmac_null.py +178 -0
- package/.claude/scripts/tests/test_check_audit_read_api_stable.py +176 -0
- package/.claude/scripts/tests/test_check_audit_registry_coverage.py +744 -0
- package/.claude/scripts/tests/test_check_auto_activation_flags.py +140 -0
- package/.claude/scripts/tests/test_check_canonical_doc_freshness.py +149 -0
- package/.claude/scripts/tests/test_check_claude_md_claims.py +223 -0
- package/.claude/scripts/tests/test_check_conformance_harness_mapping.py +243 -0
- package/.claude/scripts/tests/test_check_contamination.py +161 -0
- package/.claude/scripts/tests/test_check_creative_rewrite.py +183 -0
- package/.claude/scripts/tests/test_check_debate_round_lifecycle.py +162 -0
- package/.claude/scripts/tests/test_check_debt_ledger.py +227 -0
- package/.claude/scripts/tests/test_check_doc_skill_paths.py +99 -0
- package/.claude/scripts/tests/test_check_docs_freshness.py +224 -0
- package/.claude/scripts/tests/test_check_flip_criteria_drift.py +343 -0
- package/.claude/scripts/tests/test_check_flip_release_gate_consistency.py +195 -0
- package/.claude/scripts/tests/test_check_function_length.py +519 -0
- package/.claude/scripts/tests/test_check_model_deprecations.py +368 -0
- package/.claude/scripts/tests/test_check_originator_residue.py +165 -0
- package/.claude/scripts/tests/test_check_rule_invariants.py +327 -0
- package/.claude/scripts/tests/test_check_sdk_compat.py +88 -0
- package/.claude/scripts/tests/test_check_sidecar_manifest_sbom_sync.py +177 -0
- package/.claude/scripts/tests/test_check_spec_drift.py +358 -0
- package/.claude/scripts/tests/test_check_staleness.py +128 -0
- package/.claude/scripts/tests/test_check_stdlib_only_exceptions.py +91 -0
- package/.claude/scripts/tests/test_check_substrate_watch.py +234 -0
- package/.claude/scripts/tests/test_check_test_audit_isolation.py +322 -0
- package/.claude/scripts/tests/test_check_test_env_hygiene.py +432 -0
- package/.claude/scripts/tests/test_check_threat_model_coverage.py +251 -0
- package/.claude/scripts/tests/test_check_threat_model_freshness.py +235 -0
- package/.claude/scripts/tests/test_check_tier_boundaries.py +225 -0
- package/.claude/scripts/tests/test_check_tla_schema_drift.py +246 -0
- package/.claude/scripts/tests/test_check_translations_drift.py +262 -0
- package/.claude/scripts/tests/test_code_nav_bridge.py +192 -0
- package/.claude/scripts/tests/test_compaction_template.py +163 -0
- package/.claude/scripts/tests/test_compare_adopters.py +646 -0
- package/.claude/scripts/tests/test_confidence_gate.py +611 -0
- package/.claude/scripts/tests/test_confidence_gate_backfill.py +212 -0
- package/.claude/scripts/tests/test_context_budget.py +1400 -0
- package/.claude/scripts/tests/test_contextual_recommender.py +723 -0
- package/.claude/scripts/tests/test_coverage_audit_marker.py +109 -0
- package/.claude/scripts/tests/test_debate_converge.py +399 -0
- package/.claude/scripts/tests/test_debate_emit_cli.py +153 -0
- package/.claude/scripts/tests/test_debate_orchestrate.py +575 -0
- package/.claude/scripts/tests/test_detect_repo_profile.py +434 -0
- package/.claude/scripts/tests/test_discover_foreign_context.py +208 -0
- package/.claude/scripts/tests/test_dispatch_archetype_hint.py +429 -0
- package/.claude/scripts/tests/test_dispatch_frontmatter_validation.py +274 -0
- package/.claude/scripts/tests/test_drift_wire.py +259 -0
- package/.claude/scripts/tests/test_embeddings.py +249 -0
- package/.claude/scripts/tests/test_env_inventory_check.py +197 -0
- package/.claude/scripts/tests/test_eval_c3.py +474 -0
- package/.claude/scripts/tests/test_extract_skill.py +572 -0
- package/.claude/scripts/tests/test_fan_plan_parser.py +213 -0
- package/.claude/scripts/tests/test_find_orphan_sentinels.py +62 -0
- package/.claude/scripts/tests/test_first_run_wizard.py +634 -0
- package/.claude/scripts/tests/test_generate_adr_index.py +146 -0
- package/.claude/scripts/tests/test_generate_available_models.py +209 -0
- package/.claude/scripts/tests/test_generate_dispatch.py +90 -0
- package/.claude/scripts/tests/test_generate_skill_inventory.py +76 -0
- package/.claude/scripts/tests/test_github_api_client.py +146 -0
- package/.claude/scripts/tests/test_governance_waivers_gate.py +176 -0
- package/.claude/scripts/tests/test_hook_profiler.py +426 -0
- package/.claude/scripts/tests/test_import_skill.py +927 -0
- package/.claude/scripts/tests/test_import_skill_skip_rubric_auth.py +198 -0
- package/.claude/scripts/tests/test_inject_agent_context_mitigated_dispatch.py +266 -0
- package/.claude/scripts/tests/test_inject_agent_context_reference_mode.py +105 -0
- package/.claude/scripts/tests/test_inspired_by_validator.py +307 -0
- package/.claude/scripts/tests/test_install_dispatcher_present_maintainer.py +76 -0
- package/.claude/scripts/tests/test_install_maintainer_unchanged.py +86 -0
- package/.claude/scripts/tests/test_install_npm_sha256.py +113 -0
- package/.claude/scripts/tests/test_install_sh_placeholders.py +268 -0
- package/.claude/scripts/tests/test_install_sh_self_sha.py +244 -0
- package/.claude/scripts/tests/test_install_sh_session_75_flags.py +147 -0
- package/.claude/scripts/tests/test_install_user_dispatcher_present.py +75 -0
- package/.claude/scripts/tests/test_install_user_no_writes_outside_claude.py +75 -0
- package/.claude/scripts/tests/test_install_user_passes_validate_governance.py +73 -0
- package/.claude/scripts/tests/test_install_user_preserves_existing_repo.py +135 -0
- package/.claude/scripts/tests/test_install_user_skips_governance_hooks.py +102 -0
- package/.claude/scripts/tests/test_k_calibration.py +415 -0
- package/.claude/scripts/tests/test_key_hygiene.py +372 -0
- package/.claude/scripts/tests/test_lesson_ranker.py +82 -0
- package/.claude/scripts/tests/test_lesson_restore.py +91 -0
- package/.claude/scripts/tests/test_lessons.py +278 -0
- package/.claude/scripts/tests/test_lessons_concurrency.py +118 -0
- package/.claude/scripts/tests/test_lessons_emit.py +114 -0
- package/.claude/scripts/tests/test_lessons_inject.py +144 -0
- package/.claude/scripts/tests/test_lessons_v2.py +264 -0
- package/.claude/scripts/tests/test_lint_skills.py +525 -0
- package/.claude/scripts/tests/test_log_friction.py +436 -0
- package/.claude/scripts/tests/test_memory_prioritize.py +315 -0
- package/.claude/scripts/tests/test_morning_ledger.py +415 -0
- package/.claude/scripts/tests/test_mutation_test.py +144 -0
- package/.claude/scripts/tests/test_npm_rebuild.py +154 -0
- package/.claude/scripts/tests/test_osv_check.py +411 -0
- package/.claude/scripts/tests/test_otel_export.py +613 -0
- package/.claude/scripts/tests/test_otel_local_sink.py +262 -0
- package/.claude/scripts/tests/test_owasp_llm_top_10_benchmark.py +235 -0
- package/.claude/scripts/tests/test_parse_coverage_tier1.py +107 -0
- package/.claude/scripts/tests/test_pitfall_query.py +148 -0
- package/.claude/scripts/tests/test_plan_frontmatter_status.py +217 -0
- package/.claude/scripts/tests/test_plan_id_uniqueness.py +133 -0
- package/.claude/scripts/tests/test_plan_schema_enforcement.py +251 -0
- package/.claude/scripts/tests/test_plan_tokens.py +513 -0
- package/.claude/scripts/tests/test_plan_vcheck_gate.py +257 -0
- package/.claude/scripts/tests/test_policy_shadow_runner.py +312 -0
- package/.claude/scripts/tests/test_prune_lessons.py +341 -0
- package/.claude/scripts/tests/test_quality_profile.py +392 -0
- package/.claude/scripts/tests/test_rate_card_calibrate.py +185 -0
- package/.claude/scripts/tests/test_reality_ledger.py +1723 -0
- package/.claude/scripts/tests/test_red_team_eval.py +566 -0
- package/.claude/scripts/tests/test_red_team_eval_sha.py +260 -0
- package/.claude/scripts/tests/test_registry.py +290 -0
- package/.claude/scripts/tests/test_run_benchmark.py +639 -0
- package/.claude/scripts/tests/test_run_skill_benchmark_emit.py +195 -0
- package/.claude/scripts/tests/test_run_skill_benchmark_judge_mode.py +306 -0
- package/.claude/scripts/tests/test_scan_injection.py +191 -0
- package/.claude/scripts/tests/test_scan_injection_strict.sh +201 -0
- package/.claude/scripts/tests/test_scratchpad_cli.py +317 -0
- package/.claude/scripts/tests/test_self_test.py +369 -0
- package/.claude/scripts/tests/test_session_graph.py +511 -0
- package/.claude/scripts/tests/test_session_resume.py +306 -0
- package/.claude/scripts/tests/test_siem_rule_fixtures_have_paired_positive_negative.py +112 -0
- package/.claude/scripts/tests/test_skill_budget_generator.py +329 -0
- package/.claude/scripts/tests/test_skill_grandfather_parser.py +314 -0
- package/.claude/scripts/tests/test_skill_import_rubric.py +497 -0
- package/.claude/scripts/tests/test_skill_patch_apply_create_new_skill.py +459 -0
- package/.claude/scripts/tests/test_skill_patch_propose.py +294 -0
- package/.claude/scripts/tests/test_skill_patch_shadow_race.py +271 -0
- package/.claude/scripts/tests/test_skill_retrieval.py +486 -0
- package/.claude/scripts/tests/test_skill_retrieve_rag_wire.py +747 -0
- package/.claude/scripts/tests/test_smart_loading_resolver.py +808 -0
- package/.claude/scripts/tests/test_squad_export.py +265 -0
- package/.claude/scripts/tests/test_squad_grandfather_cap.py +434 -0
- package/.claude/scripts/tests/test_squad_import.py +905 -0
- package/.claude/scripts/tests/test_statusline_ceo.py +543 -0
- package/.claude/scripts/tests/test_success_receipt.py +448 -0
- package/.claude/scripts/tests/test_task_route.py +456 -0
- package/.claude/scripts/tests/test_token_budget_guard.py +418 -0
- package/.claude/scripts/tests/test_token_estimator.py +395 -0
- package/.claude/scripts/tests/test_trading_readonly.py +705 -0
- package/.claude/scripts/tests/test_ui_ux_imports.py +223 -0
- package/.claude/scripts/tests/test_validate_skill_frontmatter_pii_core.py +630 -0
- package/.claude/scripts/tests/test_validate_spec_context.py +128 -0
- package/.claude/scripts/tests/test_validate_squad_contract.py +221 -0
- package/.claude/scripts/tests/test_value_dashboard.py +593 -0
- package/.claude/scripts/tests/test_verify_adr_118_rationale.py +183 -0
- package/.claude/scripts/tests/test_verify_atlas_binding.py +159 -0
- package/.claude/scripts/tests/test_verify_counts.py +138 -0
- package/.claude/scripts/tests/test_verify_counts_remediation.py +258 -0
- package/.claude/scripts/tests/test_verify_persona_coverage.py +576 -0
- package/.claude/scripts/tests/test_veto_check.py +171 -0
- package/.claude/scripts/tests/test_workflow_devops_p2.py +229 -0
- package/.claude/scripts/tier_policy_cli/__init__.py +43 -0
- package/.claude/scripts/tier_policy_cli/_agent_frontmatter.py +196 -0
- package/.claude/scripts/tier_policy_cli/_constants.py +92 -0
- package/.claude/scripts/tier_policy_cli/_types.py +228 -0
- package/.claude/scripts/tier_policy_cli/apply.py +1139 -0
- package/.claude/scripts/tier_policy_cli/cli.py +795 -0
- package/.claude/scripts/tier_policy_cli/learn.py +846 -0
- package/.claude/scripts/tier_policy_cli/loader.py +535 -0
- package/.claude/scripts/tier_policy_cli/setup.py +33 -0
- package/.claude/scripts/tier_policy_cli/tests/__init__.py +0 -0
- package/.claude/scripts/tier_policy_cli/tests/test_adversarial.py +605 -0
- package/.claude/scripts/tier_policy_cli/tests/test_agent_frontmatter.py +231 -0
- package/.claude/scripts/tier_policy_cli/tests/test_apply.py +698 -0
- package/.claude/scripts/tier_policy_cli/tests/test_check_tier_policy_hook.py +187 -0
- package/.claude/scripts/tier_policy_cli/tests/test_cli.py +434 -0
- package/.claude/scripts/tier_policy_cli/tests/test_constants.py +113 -0
- package/.claude/scripts/tier_policy_cli/tests/test_learn.py +1380 -0
- package/.claude/scripts/tier_policy_cli/tests/test_learn_mutation.py +549 -0
- package/.claude/scripts/tier_policy_cli/tests/test_loader.py +368 -0
- package/.claude/scripts/tier_policy_cli/tests/test_types.py +152 -0
- package/.claude/scripts/token-budget-guard.py +657 -0
- package/.claude/scripts/token-estimator.py +957 -0
- package/.claude/scripts/tournament/__init__.py +22 -0
- package/.claude/scripts/tournament/check_fixture.py +271 -0
- package/.claude/scripts/tournament/fixtures/CORPUS_SHA256.txt +10 -0
- package/.claude/scripts/tournament/fixtures/code-review.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/docs-writing.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/performance-triage.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/security-review.jsonl +10 -0
- package/.claude/scripts/tournament/fixtures/test-design.jsonl +10 -0
- package/.claude/scripts/tournament/judge.py +269 -0
- package/.claude/scripts/tournament/loader.py +262 -0
- package/.claude/scripts/tournament/regen_corpus_sha.py +93 -0
- package/.claude/scripts/tournament/reporter.py +328 -0
- package/.claude/scripts/tournament/runner.py +707 -0
- package/.claude/scripts/tournament/scorer.py +118 -0
- package/.claude/scripts/tournament/tests/__init__.py +0 -0
- package/.claude/scripts/tournament/tests/_fake_dispatcher.py +233 -0
- package/.claude/scripts/tournament/tests/golden/strict_report_seed42.jsonl +6 -0
- package/.claude/scripts/tournament/tests/test_fixture_envelope.py +106 -0
- package/.claude/scripts/tournament/tests/test_fixture_security.py +227 -0
- package/.claude/scripts/tournament/tests/test_judge.py +299 -0
- package/.claude/scripts/tournament/tests/test_loader.py +223 -0
- package/.claude/scripts/tournament/tests/test_model_id_parity.py +136 -0
- package/.claude/scripts/tournament/tests/test_reporter.py +450 -0
- package/.claude/scripts/tournament/tests/test_reporter_golden.py +182 -0
- package/.claude/scripts/tournament/tests/test_runner.py +313 -0
- package/.claude/scripts/tournament/tests/test_runner_fail_open.py +204 -0
- package/.claude/scripts/tournament/tests/test_scorer.py +138 -0
- package/.claude/scripts/tournament/tests/test_tournament_e2e_smoke.py +147 -0
- package/.claude/scripts/tournament/tests/test_tournament_properties.py +181 -0
- package/.claude/scripts/trading-readonly-escape-hatch.sh +244 -0
- package/.claude/scripts/trading-readonly-guardrails.py +1136 -0
- package/.claude/scripts/translations-pairs.yaml +60 -0
- package/.claude/scripts/validate-findings.py +243 -0
- package/.claude/scripts/validate-governance.sh +1238 -0
- package/.claude/scripts/validate-skill-frontmatter.py +679 -0
- package/.claude/scripts/validate-spec-context.py +146 -0
- package/.claude/scripts/validate-squad-contract.py +318 -0
- package/.claude/scripts/validate_governance_fast.py +555 -0
- package/.claude/scripts/value-dashboard.py +851 -0
- package/.claude/scripts/verify-adr-118-rationale.py +285 -0
- package/.claude/scripts/verify-atlas-binding.py +331 -0
- package/.claude/scripts/verify-persona-coverage.py +531 -0
- package/.claude/scripts/verify-sprint3-invariants.sh +133 -0
- package/.claude/scripts/veto-check.py +218 -0
- package/.claude/security/README.md +200 -0
- package/.claude/security/sentinel-signers-registry.yaml +60 -0
- package/.claude/sentinel-signers.txt +24 -0
- package/.claude/settings.json +786 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/README.md +89 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/boundary_test.py +114 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/install.sh +45 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/manifest.json +52 -0
- package/.claude/sidecars/c1-crypto/cryptography-mvp/sidecar_code/cert_inspector.py +775 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/boundary_test.py +318 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/install.sh +57 -0
- package/.claude/sidecars/c1-crypto/stdlib-ssl-mvp/manifest.json +48 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/README.md +88 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/boundary_test.py +221 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/install.sh +33 -0
- package/.claude/sidecars/c2-vector-memory/lightrag-mvp/manifest.json +59 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/boundary_test.py +142 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/install.sh +46 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/manifest.json +52 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/__init__.py +0 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_audit_emit_known_actions_property.py +123 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_canonical_guard_symmetry_property.py +67 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_payload_roundtrip_property.py +73 -0
- package/.claude/sidecars/c5-dev-tools/hypothesis/tests/test_redact_idempotence_property.py +68 -0
- package/.claude/skill-governance-grandfather.yaml +39 -0
- package/.claude/skill-patch-signers.txt +19 -0
- package/.claude/skills/core/agent-architect/SKILL.md +126 -0
- package/.claude/skills/core/ai-llm-orchestration/SKILL.md +620 -0
- package/.claude/skills/core/ai-llm-orchestration/SKILL.md.shadow.md +121 -0
- package/.claude/skills/core/architecture-decisions/SKILL.md +364 -0
- package/.claude/skills/core/architecture-decisions/benchmarks/architecture-decisions.yaml +257 -0
- package/.claude/skills/core/ceo-orchestration/SKILL-frontend.md +117 -0
- package/.claude/skills/core/ceo-orchestration/SKILL.md +700 -0
- package/.claude/skills/core/chaos-and-resilience/SKILL.md +568 -0
- package/.claude/skills/core/chaos-and-resilience/SKILL.md.shadow.md +553 -0
- package/.claude/skills/core/code-intelligence-lsp/SKILL.md +375 -0
- package/.claude/skills/core/code-review-checklist/SKILL.md +675 -0
- package/.claude/skills/core/code-review-checklist/SKILL.md.shadow.md +337 -0
- package/.claude/skills/core/code-review-checklist/benchmarks/code-review-checklist.yaml +444 -0
- package/.claude/skills/core/codebase-onboarding/SKILL.md +515 -0
- package/.claude/skills/core/compliance-lgpd/SKILL-frontend.md +513 -0
- package/.claude/skills/core/compliance-lgpd/SKILL.md +817 -0
- package/.claude/skills/core/consent-lifecycle/SKILL.md +149 -0
- package/.claude/skills/core/cookbook-advisor/SKILL.md +191 -0
- package/.claude/skills/core/coverage-audit/SKILL.md +116 -0
- package/.claude/skills/core/cross-llm-pair-review/SKILL.md +212 -0
- package/.claude/skills/core/data-schema-design/SKILL.md +933 -0
- package/.claude/skills/core/devops-ci-cd/SKILL.md +659 -0
- package/.claude/skills/core/dpo-reporting/SKILL.md +187 -0
- package/.claude/skills/core/evidence-based-qa/SKILL.md +565 -0
- package/.claude/skills/core/git-workflow-discipline/SKILL.md +600 -0
- package/.claude/skills/core/growth-and-launch/SKILL-frontend.md +800 -0
- package/.claude/skills/core/growth-and-launch/SKILL.md +903 -0
- package/.claude/skills/core/help-me/SKILL.md +177 -0
- package/.claude/skills/core/help-me/tests/test_help_me_skill.py +490 -0
- package/.claude/skills/core/identity-and-trust-architecture/SKILL.md +1062 -0
- package/.claude/skills/core/incident-management/SKILL.md +421 -0
- package/.claude/skills/core/incremental-refactoring/SKILL-frontend.md +210 -0
- package/.claude/skills/core/incremental-refactoring/SKILL.md +226 -0
- package/.claude/skills/core/llm-routing-and-finops/SKILL.md +828 -0
- package/.claude/skills/core/mcp-server-authoring/SKILL.md +685 -0
- package/.claude/skills/core/minimal-change-discipline/SKILL.md +545 -0
- package/.claude/skills/core/monetization-and-billing/SKILL-frontend.md +562 -0
- package/.claude/skills/core/monetization-and-billing/SKILL.md +585 -0
- package/.claude/skills/core/observability-and-ops/SKILL-frontend.md +290 -0
- package/.claude/skills/core/observability-and-ops/SKILL.md +612 -0
- package/.claude/skills/core/observability-and-ops/SKILL.md.shadow.md +324 -0
- package/.claude/skills/core/parallelization-by-default/SKILL.md +176 -0
- package/.claude/skills/core/parallelization-by-default/tests/test_parallelization_skill.py +490 -0
- package/.claude/skills/core/performance-engineering/SKILL.md +219 -0
- package/.claude/skills/core/performance-engineering/SKILL.md.shadow.md +204 -0
- package/.claude/skills/core/pii-data-flow/SKILL.md +166 -0
- package/.claude/skills/core/pre-plan-brainstorm/CHECKLIST.md +87 -0
- package/.claude/skills/core/pre-plan-brainstorm/SKILL.md +186 -0
- package/.claude/skills/core/product-conversion-readiness/SKILL-frontend.md +668 -0
- package/.claude/skills/core/product-conversion-readiness/SKILL.md +941 -0
- package/.claude/skills/core/public-api-design/SKILL.md +603 -0
- package/.claude/skills/core/public-api-design/benchmarks/public-api-design.yaml +261 -0
- package/.claude/skills/core/receiving-review/SKILL.md +131 -0
- package/.claude/skills/core/receiving-review/benchmarks/receiving-review.yaml +254 -0
- package/.claude/skills/core/requirement-quality-checklist/SKILL.md +97 -0
- package/.claude/skills/core/security-and-auth/SKILL.md +868 -0
- package/.claude/skills/core/security-and-auth/SKILL.md.shadow.md +500 -0
- package/.claude/skills/core/security-and-auth/benchmarks/owasp-basics.yaml +491 -0
- package/.claude/skills/core/security-and-auth/benchmarks/owasp-llm-top-10.yaml +769 -0
- package/.claude/skills/core/spec-clarify/SKILL.md +120 -0
- package/.claude/skills/core/state-machines-and-invariants/SKILL.md +288 -0
- package/.claude/skills/core/technical-writing/SKILL.md +432 -0
- package/.claude/skills/core/terse-mode/SKILL.md +80 -0
- package/.claude/skills/core/terse-mode/SKILL.md.shadow.md +65 -0
- package/.claude/skills/core/testing-strategy/SKILL.md +1026 -0
- package/.claude/skills/core/testing-strategy/SKILL.md.shadow.md +983 -0
- package/.claude/skills/domains/academic-humanities/examples/PLAN-EXAMPLE-ACH.md +126 -0
- package/.claude/skills/domains/academic-humanities/pitfalls.yaml +68 -0
- package/.claude/skills/domains/academic-humanities/skills/anthropologist/SKILL.md +394 -0
- package/.claude/skills/domains/academic-humanities/skills/geographer/SKILL.md +453 -0
- package/.claude/skills/domains/academic-humanities/skills/historian/SKILL.md +255 -0
- package/.claude/skills/domains/academic-humanities/skills/narratologist/SKILL.md +398 -0
- package/.claude/skills/domains/academic-humanities/skills/psychologist/SKILL.md +271 -0
- package/.claude/skills/domains/academic-humanities/task-chains.yaml +125 -0
- package/.claude/skills/domains/academic-humanities/team-personas.md +278 -0
- package/.claude/skills/domains/business-support/examples/PLAN-EXAMPLE-BSP.md +115 -0
- package/.claude/skills/domains/business-support/pitfalls.yaml +69 -0
- package/.claude/skills/domains/business-support/skills/analytics-reporter/SKILL.md +339 -0
- package/.claude/skills/domains/business-support/skills/executive-summary/SKILL.md +268 -0
- package/.claude/skills/domains/business-support/skills/finance-tracker/SKILL.md +321 -0
- package/.claude/skills/domains/business-support/skills/support-responder/SKILL.md +341 -0
- package/.claude/skills/domains/business-support/task-chains.yaml +118 -0
- package/.claude/skills/domains/business-support/team-personas.md +259 -0
- package/.claude/skills/domains/civil-engineering/skills/civil-engineer/SKILL.md +275 -0
- package/.claude/skills/domains/community/NOTICE.md +83 -0
- package/.claude/skills/domains/community/skills/advanced-evaluation/SKILL.md +463 -0
- package/.claude/skills/domains/community/skills/agent-evaluation/SKILL.md +400 -0
- package/.claude/skills/domains/community/skills/agentic-actions-auditor/SKILL.md +410 -0
- package/.claude/skills/domains/community/team-personas.md +41 -0
- package/.claude/skills/domains/devrel/examples/api-deprecation-comms.md +180 -0
- package/.claude/skills/domains/devrel/pitfalls.yaml +74 -0
- package/.claude/skills/domains/devrel/skills/developer-advocate/SKILL.md +382 -0
- package/.claude/skills/domains/devrel/task-chains.yaml +129 -0
- package/.claude/skills/domains/devrel/team-personas.md +260 -0
- package/.claude/skills/domains/edtech/examples/PLAN-EXAMPLE.md +89 -0
- package/.claude/skills/domains/edtech/pitfalls.yaml +98 -0
- package/.claude/skills/domains/edtech/skills/assessment-integrity/SKILL.md +208 -0
- package/.claude/skills/domains/edtech/skills/learning-analytics/SKILL.md +212 -0
- package/.claude/skills/domains/edtech/skills/student-data-privacy/SKILL.md +197 -0
- package/.claude/skills/domains/edtech/skills/study-abroad-advisory/SKILL.md +582 -0
- package/.claude/skills/domains/edtech/task-chains.yaml +122 -0
- package/.claude/skills/domains/edtech/team-personas.md +252 -0
- package/.claude/skills/domains/embedded/skills/embedded-firmware/SKILL.md +471 -0
- package/.claude/skills/domains/finance-accounting/examples/new-subscription-revenue.md +135 -0
- package/.claude/skills/domains/finance-accounting/pitfalls.yaml +74 -0
- package/.claude/skills/domains/finance-accounting/skills/bookkeeper-controller/SKILL.md +427 -0
- package/.claude/skills/domains/finance-accounting/skills/financial-analyst/SKILL.md +348 -0
- package/.claude/skills/domains/finance-accounting/skills/fpa-analyst/SKILL.md +366 -0
- package/.claude/skills/domains/finance-accounting/skills/tax-strategist/SKILL.md +358 -0
- package/.claude/skills/domains/finance-accounting/task-chains.yaml +90 -0
- package/.claude/skills/domains/finance-accounting/team-personas.md +281 -0
- package/.claude/skills/domains/fintech/ORG_CHART.md +167 -0
- package/.claude/skills/domains/fintech/commands/audit-ai.md +124 -0
- package/.claude/skills/domains/fintech/commands/deploy.md +15 -0
- package/.claude/skills/domains/fintech/commands/status.md +13 -0
- package/.claude/skills/domains/fintech/frontend-team-personas.md +503 -0
- package/.claude/skills/domains/fintech/pitfalls.yaml +58 -0
- package/.claude/skills/domains/fintech/scripts/check-pitfall-regression.sh +80 -0
- package/.claude/skills/domains/fintech/scripts/check-type-sync.sh +110 -0
- package/.claude/skills/domains/fintech/skills/blockchain-security-audit/SKILL.md +492 -0
- package/.claude/skills/domains/fintech/skills/equity-research/SKILL.md +459 -0
- package/.claude/skills/domains/fintech/skills/exchange-api-integration/SKILL.md +315 -0
- package/.claude/skills/domains/fintech/skills/exchange-onboarding-playbook/SKILL.md +527 -0
- package/.claude/skills/domains/fintech/skills/financial-correctness-and-math/SKILL-frontend.md +308 -0
- package/.claude/skills/domains/fintech/skills/financial-correctness-and-math/SKILL.md +340 -0
- package/.claude/skills/domains/fintech/skills/financial-display/SKILL.md +193 -0
- package/.claude/skills/domains/fintech/skills/frontend-data-layer/SKILL.md +206 -0
- package/.claude/skills/domains/fintech/skills/frontend-patterns/SKILL.md +387 -0
- package/.claude/skills/domains/fintech/skills/prediction-markets/SKILL.md +139 -0
- package/.claude/skills/domains/fintech/skills/real-time-market-systems/SKILL.md +315 -0
- package/.claude/skills/domains/fintech/skills/solidity-smart-contracts/SKILL.md +356 -0
- package/.claude/skills/domains/fintech/skills/trading-execution/SKILL.md +126 -0
- package/.claude/skills/domains/fintech/task-chains.yaml +46 -0
- package/.claude/skills/domains/fintech/team-personas.md +773 -0
- package/.claude/skills/domains/government/examples/PLAN-EXAMPLE.md +158 -0
- package/.claude/skills/domains/government/pitfalls.yaml +114 -0
- package/.claude/skills/domains/government/skills/accessibility-section-508/SKILL.md +183 -0
- package/.claude/skills/domains/government/skills/digital-presales/SKILL.md +359 -0
- package/.claude/skills/domains/government/skills/foia-and-records/SKILL.md +211 -0
- package/.claude/skills/domains/government/skills/public-procurement/SKILL.md +264 -0
- package/.claude/skills/domains/government/task-chains.yaml +88 -0
- package/.claude/skills/domains/government/team-personas.md +296 -0
- package/.claude/skills/domains/healthcare/examples/patient-portal-symptom-checker.md +130 -0
- package/.claude/skills/domains/healthcare/pitfalls.yaml +74 -0
- package/.claude/skills/domains/healthcare/skills/healthcare-customer-service/SKILL.md +369 -0
- package/.claude/skills/domains/healthcare/skills/marketing-compliance/SKILL.md +367 -0
- package/.claude/skills/domains/healthcare/task-chains.yaml +87 -0
- package/.claude/skills/domains/healthcare/team-personas.md +273 -0
- package/.claude/skills/domains/hospitality/skills/guest-services/SKILL.md +417 -0
- package/.claude/skills/domains/hr/examples/attrition-model-launch.md +128 -0
- package/.claude/skills/domains/hr/pitfalls.yaml +74 -0
- package/.claude/skills/domains/hr/skills/hr-onboarding/SKILL.md +435 -0
- package/.claude/skills/domains/hr/skills/recruitment-specialist/SKILL.md +400 -0
- package/.claude/skills/domains/hr/task-chains.yaml +91 -0
- package/.claude/skills/domains/hr/team-personas.md +251 -0
- package/.claude/skills/domains/i18n-business/examples/PLAN-EXAMPLE-I18N.md +115 -0
- package/.claude/skills/domains/i18n-business/pitfalls.yaml +68 -0
- package/.claude/skills/domains/i18n-business/skills/cultural-intelligence/SKILL.md +448 -0
- package/.claude/skills/domains/i18n-business/skills/french-consulting/SKILL.md +347 -0
- package/.claude/skills/domains/i18n-business/skills/korean-business/SKILL.md +360 -0
- package/.claude/skills/domains/i18n-business/skills/language-translator/SKILL.md +389 -0
- package/.claude/skills/domains/i18n-business/task-chains.yaml +117 -0
- package/.claude/skills/domains/i18n-business/team-personas.md +258 -0
- package/.claude/skills/domains/identity-systems/examples/passkey-rollout.md +137 -0
- package/.claude/skills/domains/identity-systems/pitfalls.yaml +74 -0
- package/.claude/skills/domains/identity-systems/skills/identity-graph-operator/SKILL.md +353 -0
- package/.claude/skills/domains/identity-systems/task-chains.yaml +90 -0
- package/.claude/skills/domains/identity-systems/team-personas.md +233 -0
- package/.claude/skills/domains/legal/examples/client-intake-pii-flow.md +177 -0
- package/.claude/skills/domains/legal/pitfalls.yaml +77 -0
- package/.claude/skills/domains/legal/skills/client-intake/SKILL.md +407 -0
- package/.claude/skills/domains/legal/skills/document-review/SKILL.md +373 -0
- package/.claude/skills/domains/legal/skills/legal-billing/SKILL.md +331 -0
- package/.claude/skills/domains/legal/task-chains.yaml +131 -0
- package/.claude/skills/domains/legal/team-personas.md +260 -0
- package/.claude/skills/domains/lgpd-heavy-saas/examples/PLAN-EXAMPLE.md +120 -0
- package/.claude/skills/domains/lgpd-heavy-saas/pitfalls.yaml +90 -0
- package/.claude/skills/domains/lgpd-heavy-saas/task-chains.yaml +83 -0
- package/.claude/skills/domains/lgpd-heavy-saas/team-personas.md +159 -0
- package/.claude/skills/domains/marketing-global/skills/agentic-search-optimizer/SKILL.md +391 -0
- package/.claude/skills/domains/marketing-global/skills/ai-citation-strategist/SKILL.md +343 -0
- package/.claude/skills/domains/marketing-global/skills/app-store-optimizer/SKILL.md +495 -0
- package/.claude/skills/domains/marketing-global/skills/book-co-author/SKILL.md +220 -0
- package/.claude/skills/domains/marketing-global/skills/carousel-growth-engine/SKILL.md +393 -0
- package/.claude/skills/domains/marketing-global/skills/content-creator/SKILL.md +416 -0
- package/.claude/skills/domains/marketing-global/skills/growth-hacker/SKILL.md +495 -0
- package/.claude/skills/domains/marketing-global/skills/instagram-curator/SKILL.md +419 -0
- package/.claude/skills/domains/marketing-global/skills/linkedin-content-creator/SKILL.md +291 -0
- package/.claude/skills/domains/marketing-global/skills/podcast-strategist/SKILL.md +408 -0
- package/.claude/skills/domains/marketing-global/skills/reddit-community-builder/SKILL.md +295 -0
- package/.claude/skills/domains/marketing-global/skills/seo-specialist/SKILL.md +352 -0
- package/.claude/skills/domains/marketing-global/skills/social-media-strategist/SKILL.md +349 -0
- package/.claude/skills/domains/marketing-global/skills/tiktok-strategist/SKILL.md +329 -0
- package/.claude/skills/domains/marketing-global/skills/twitter-engager/SKILL.md +382 -0
- package/.claude/skills/domains/marketing-global/skills/video-optimization-specialist/SKILL.md +386 -0
- package/.claude/skills/domains/mobile/examples/PLAN-EXAMPLE-MOB.md +129 -0
- package/.claude/skills/domains/mobile/pitfalls.yaml +69 -0
- package/.claude/skills/domains/mobile/skills/mobile-app-builder/SKILL.md +446 -0
- package/.claude/skills/domains/mobile/task-chains.yaml +126 -0
- package/.claude/skills/domains/mobile/team-personas.md +292 -0
- package/.claude/skills/domains/paid-media/examples/new-channel-launch.md +122 -0
- package/.claude/skills/domains/paid-media/pitfalls.yaml +79 -0
- package/.claude/skills/domains/paid-media/skills/auditor/SKILL.md +362 -0
- package/.claude/skills/domains/paid-media/skills/creative-strategist/SKILL.md +457 -0
- package/.claude/skills/domains/paid-media/skills/paid-social-strategist/SKILL.md +493 -0
- package/.claude/skills/domains/paid-media/skills/ppc-strategist/SKILL.md +450 -0
- package/.claude/skills/domains/paid-media/skills/programmatic-buyer/SKILL.md +396 -0
- package/.claude/skills/domains/paid-media/skills/search-query-analyst/SKILL.md +336 -0
- package/.claude/skills/domains/paid-media/skills/tracking-specialist/SKILL.md +457 -0
- package/.claude/skills/domains/paid-media/task-chains.yaml +121 -0
- package/.claude/skills/domains/paid-media/team-personas.md +251 -0
- package/.claude/skills/domains/project-management/examples/PLAN-EXAMPLE-PMG.md +117 -0
- package/.claude/skills/domains/project-management/pitfalls.yaml +68 -0
- package/.claude/skills/domains/project-management/skills/experiment-tracker/SKILL.md +293 -0
- package/.claude/skills/domains/project-management/skills/project-shepherd/SKILL.md +312 -0
- package/.claude/skills/domains/project-management/skills/studio-operations/SKILL.md +333 -0
- package/.claude/skills/domains/project-management/skills/studio-producer/SKILL.md +329 -0
- package/.claude/skills/domains/project-management/task-chains.yaml +118 -0
- package/.claude/skills/domains/project-management/team-personas.md +264 -0
- package/.claude/skills/domains/real-estate-finance/examples/PLAN-EXAMPLE-REF.md +129 -0
- package/.claude/skills/domains/real-estate-finance/pitfalls.yaml +68 -0
- package/.claude/skills/domains/real-estate-finance/skills/buyer-seller-agent/SKILL.md +410 -0
- package/.claude/skills/domains/real-estate-finance/skills/loan-officer-assistant/SKILL.md +415 -0
- package/.claude/skills/domains/real-estate-finance/task-chains.yaml +123 -0
- package/.claude/skills/domains/real-estate-finance/team-personas.md +287 -0
- package/.claude/skills/domains/retail/skills/customer-returns/SKILL.md +363 -0
- package/.claude/skills/domains/saas-platforms/examples/enterprise-tier-isolation.md +147 -0
- package/.claude/skills/domains/saas-platforms/pitfalls.yaml +74 -0
- package/.claude/skills/domains/saas-platforms/skills/cms-developer/SKILL.md +377 -0
- package/.claude/skills/domains/saas-platforms/skills/filament-specialist/SKILL.md +316 -0
- package/.claude/skills/domains/saas-platforms/skills/salesforce-architect/SKILL.md +369 -0
- package/.claude/skills/domains/saas-platforms/task-chains.yaml +90 -0
- package/.claude/skills/domains/saas-platforms/team-personas.md +283 -0
- package/.claude/skills/domains/sales/examples/qbr-revenue-forecast.md +158 -0
- package/.claude/skills/domains/sales/pitfalls.yaml +73 -0
- package/.claude/skills/domains/sales/skills/account-strategist/SKILL.md +408 -0
- package/.claude/skills/domains/sales/skills/deal-strategist/SKILL.md +292 -0
- package/.claude/skills/domains/sales/skills/discovery-coach/SKILL.md +257 -0
- package/.claude/skills/domains/sales/skills/outbound-strategist/SKILL.md +262 -0
- package/.claude/skills/domains/sales/skills/pipeline-analyst/SKILL.md +317 -0
- package/.claude/skills/domains/sales/skills/proposal-strategist/SKILL.md +288 -0
- package/.claude/skills/domains/sales/skills/sales-coach/SKILL.md +306 -0
- package/.claude/skills/domains/sales/skills/sales-engineer/SKILL.md +272 -0
- package/.claude/skills/domains/sales/skills/sales-outreach/SKILL.md +338 -0
- package/.claude/skills/domains/sales/task-chains.yaml +123 -0
- package/.claude/skills/domains/sales/team-personas.md +249 -0
- package/.claude/skills/domains/supply-chain/skills/supply-chain-strategist/SKILL.md +340 -0
- package/.claude/skills/domains/trading-hft/examples/PLAN-EXAMPLE.md +145 -0
- package/.claude/skills/domains/trading-hft/pitfalls.yaml +99 -0
- package/.claude/skills/domains/trading-hft/skills/kill-switches/SKILL.md +128 -0
- package/.claude/skills/domains/trading-hft/skills/latency-budgets/SKILL.md +117 -0
- package/.claude/skills/domains/trading-hft/skills/order-routing/SKILL.md +97 -0
- package/.claude/skills/domains/trading-hft/task-chains.yaml +97 -0
- package/.claude/skills/domains/trading-hft/team-personas.md +155 -0
- package/.claude/skills/domains/training-l-and-d/skills/corporate-training-designer/SKILL.md +268 -0
- package/.claude/skills/domains/voice-ai/skills/voice-ai-integration/SKILL.md +405 -0
- package/.claude/skills/frontend/NOTICE.md +80 -0
- package/.claude/skills/frontend/accessibility-and-wcag/SKILL.md +395 -0
- package/.claude/skills/frontend/accessibility-and-wcag/SKILL.md.shadow.md +181 -0
- package/.claude/skills/frontend/accessibility-and-wcag/benchmarks/accessibility-and-wcag.yaml +420 -0
- package/.claude/skills/frontend/accessibility-and-wcag/reference/charts-accessibility.yaml +357 -0
- package/.claude/skills/frontend/code-quality-and-typescript/SKILL.md +167 -0
- package/.claude/skills/frontend/design-system-and-components/SKILL.md +155 -0
- package/.claude/skills/frontend/design-system-and-components/SKILL.md.shadow.md +138 -0
- package/.claude/skills/frontend/design-system-and-components/reference/fonts.yaml +811 -0
- package/.claude/skills/frontend/design-system-and-components/reference/palettes.yaml +3066 -0
- package/.claude/skills/frontend/frontend-accessibility/SKILL.md +213 -0
- package/.claude/skills/frontend/frontend-data-layer/SKILL.md +310 -0
- package/.claude/skills/frontend/frontend-patterns/SKILL.md +771 -0
- package/.claude/skills/frontend/frontend-performance-optimization/SKILL.md +228 -0
- package/.claude/skills/frontend/frontend-performance-optimization/SKILL.md.shadow.md +213 -0
- package/.claude/skills/frontend/ux-and-user-journeys/SKILL.md +153 -0
- package/.claude/skills/frontend/ux-and-user-journeys/SKILL.md.shadow.md +138 -0
- package/.claude/skills/frontend/ux-and-user-journeys/reference/guidelines.yaml +997 -0
- package/.claude/squad-revocations.jsonl +5 -0
- package/.claude/task-chains.yaml +151 -0
- package/.claude/team.md +825 -0
- package/.claude/templates/squad-bundle/README.md +208 -0
- package/.claude/templates/squad-bundle/conftest.py +27 -0
- package/.claude/templates/squad-bundle/examples/template-example.md.template +94 -0
- package/.claude/templates/squad-bundle/pitfalls.yaml.template +88 -0
- package/.claude/templates/squad-bundle/task-chains.yaml.template +92 -0
- package/.claude/templates/squad-bundle/team-personas.md.template +161 -0
- package/.claude/trust/README.md +89 -0
- package/.claude/trust/owner.asc +11 -0
- package/.claude/workflows/README.md +124 -0
- package/.claude/workflows/audit-fanout.js +204 -0
- package/.claude/workflows/eval-baseline-n20.js +330 -0
- package/.claude/workflows/nightly-hygiene.js +176 -0
- package/LICENSE +21 -0
- package/PROTOCOL.md +597 -0
- package/README.md +167 -0
- package/SPEC/v1/README.md +181 -0
- package/SPEC/v1/adapters.schema.md +272 -0
- package/SPEC/v1/audit-log.schema.md +1514 -0
- package/SPEC/v1/audit-query.schema.md +152 -0
- package/SPEC/v1/benchmarks.schema.md +166 -0
- package/SPEC/v1/claude-sdk-compat.md +123 -0
- package/SPEC/v1/debate.schema.md +35 -0
- package/SPEC/v1/hook-io.schema.md +94 -0
- package/SPEC/v1/install-cli.md +234 -0
- package/SPEC/v1/judge-payload.schema.md +98 -0
- package/SPEC/v1/live-adapters-policy.schema.md +118 -0
- package/SPEC/v1/mcp-server.schema.md +558 -0
- package/SPEC/v1/memory-shared.schema.md +365 -0
- package/SPEC/v1/normalized_envelope.schema.md +183 -0
- package/SPEC/v1/npm-shim.md +95 -0
- package/SPEC/v1/plan.schema.md +34 -0
- package/SPEC/v1/policy-dsl.schema.md +466 -0
- package/SPEC/v1/predict-budget.schema.md +289 -0
- package/SPEC/v1/rag-sidecar.schema.md +222 -0
- package/SPEC/v1/red-team-corpus.schema.md +186 -0
- package/SPEC/v1/replay.schema.md +272 -0
- package/SPEC/v1/scratchpad.schema.md +172 -0
- package/SPEC/v1/sentinel-format.schema.md +306 -0
- package/SPEC/v1/session-graph.schema.md +236 -0
- package/SPEC/v1/skill-frontmatter.schema.md +83 -0
- package/SPEC/v1/skill-index.schema.md +197 -0
- package/SPEC/v1/skill-proposals.schema.md +175 -0
- package/SPEC/v1/soc2-control-map.schema.md +797 -0
- package/SPEC/v1/squad-manifest.schema.md +157 -0
- package/SPEC/v1/state-stores.schema.md +146 -0
- package/SPEC/v1/tier-policy.schema.md +264 -0
- package/SPEC/v1/tournament-report.schema.md +156 -0
- package/VERSION +1 -0
- package/bin/ceo-orch-init.js +55 -0
- package/package.json +42 -0
- package/scripts/_framework_manifest_set.sh +237 -0
- package/scripts/_hash_lib.sh +92 -0
- package/scripts/build-plugin.py +351 -0
- package/scripts/discover_foreign_context.py +151 -0
- package/scripts/install-accelerators.sh +166 -0
- package/scripts/install-npm.sh +254 -0
- package/scripts/install.sh +1932 -0
- package/scripts/local/OWNER-CEREMONY-PLAN-094-WAVE-A.sh +648 -0
- package/scripts/local/OWNER-CEREMONY-S82-V1120.sh +169 -0
- package/scripts/local/plan-093-apply-kernel-edits.py +496 -0
- package/scripts/local/plan-093-execute-ceremony.sh +118 -0
- package/scripts/local/plan-093-kernel-override-restart.sh +115 -0
- package/scripts/local/plan-093-ship-v1.26.0.sh +226 -0
- package/scripts/local/plan-094-apply-wave-a-c-e.py +398 -0
- package/scripts/local/smoke-install-parity.sh +168 -0
- package/scripts/local/trading-readonly-escape-hatch.sh +244 -0
- package/scripts/measure-repo-size.sh +98 -0
- package/scripts/npm-rebuild.sh +172 -0
- package/scripts/publish-plugin.sh +144 -0
- package/scripts/tests/smoke-install.sh +260 -0
- package/scripts/tests/test-install-sandbox-merge.sh +137 -0
- package/scripts/tests/test_install_baseline_manifest.sh +392 -0
- package/scripts/uninstall.sh +282 -0
- package/scripts/upgrade.sh +1260 -0
- package/templates/.claude/tier-policy.json +35 -0
- package/templates/.claude/tier-policy.json.sigchain +1 -0
- package/templates/.env.example +134 -0
- package/templates/.github/CODEOWNERS.template +33 -0
- package/templates/.github/workflows/benchmarks.yml.template +145 -0
- package/templates/.github/workflows/validate.yml.template +226 -0
- package/templates/.mcp.json +13 -0
- package/templates/CLAUDE.md +125 -0
- package/templates/MEMORY.md +36 -0
- package/templates/README.md +46 -0
- package/templates/compaction.md +130 -0
- package/templates/docs/BRANCH-PROTECTION.md +203 -0
- package/templates/docs/rotation-log.md +18 -0
- package/templates/oidc-proxy/README.md +141 -0
- package/templates/oidc-proxy/broker.config.example.json +29 -0
- package/templates/oidc-proxy/oidc_key_broker.py +361 -0
- package/templates/oidc-proxy/tests/test_oidc_key_broker.py +361 -0
- package/templates/scripts/statusline-ceo.py +597 -0
- package/templates/settings/settings.base.json +708 -0
- package/templates/settings/settings.stack.node.json +19 -0
- package/templates/settings/settings.stack.otel.json +25 -0
- package/templates/settings/settings.stack.sandbox.json +57 -0
- package/templates/settings/settings.user.json +265 -0
- package/templates/team-personas-reference.md +269 -0
|
@@ -0,0 +1,1700 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""PLAN-075 Phase 0A → PRODUCTION (PLAN-091 A.6 status promotion) — `check_pair_rail.py` PreToolUse hook.
|
|
3
|
+
|
|
4
|
+
Cross-LLM gate enforcement: when Claude is about to perform an L3+
|
|
5
|
+
tool call against a high-blast-radius governance path, this hook
|
|
6
|
+
invokes Codex MCP (`mcp__codex__codex`) in **read-only review mode**.
|
|
7
|
+
Codex returns a textual review. The hook validates that the review
|
|
8
|
+
contains NO write-shaped patches (any `*** Update File:`, unified
|
|
9
|
+
diff, or JSON Patch RFC 6902 envelope is rejected — Codex is
|
|
10
|
+
read-only by contract here, NOT a coder).
|
|
11
|
+
|
|
12
|
+
## Hook contract
|
|
13
|
+
|
|
14
|
+
- **Trigger:** PreToolUse with tool_name in {Edit, Write, MultiEdit,
|
|
15
|
+
NotebookEdit} AND target path classified as L3+ (see
|
|
16
|
+
`_is_l3_plus_path` heuristic).
|
|
17
|
+
- **Codex unavailable** (binary missing / connect timeout / spawn
|
|
18
|
+
error) → fail-OPEN with `{decision: allow}` + audit
|
|
19
|
+
`pair_rail_codex_unavailable` (advisory).
|
|
20
|
+
- **Codex returns clean review** (no write-shaped patch detected) →
|
|
21
|
+
audit `pair_rail_review_passed` + `{decision: allow}`.
|
|
22
|
+
- **Codex returns write-shaped patch** → audit
|
|
23
|
+
`pair_rail_codex_violation` + `{decision: block, reason: ...}`.
|
|
24
|
+
- **Sentinel override** (Owner-signed sentinel grants the path) →
|
|
25
|
+
short-circuit allow + audit `pair_rail_sentinel_bypass`.
|
|
26
|
+
- **Tool not in scope** (non-write tool, or path not L3+) → silent
|
|
27
|
+
allow.
|
|
28
|
+
|
|
29
|
+
## L3+ path heuristic (production heuristic — to be replaced by formal
|
|
30
|
+
classifier in Phase 1)
|
|
31
|
+
|
|
32
|
+
A target path is L3+ iff its repo-relative form matches any of:
|
|
33
|
+
- `.claude/hooks/_lib/*.py`
|
|
34
|
+
- `.claude/hooks/check_*.py`
|
|
35
|
+
- `.claude/scripts/local/*`
|
|
36
|
+
- `.claude/policies/*`
|
|
37
|
+
- `SPEC/v1/*`
|
|
38
|
+
- `.github/workflows/*`
|
|
39
|
+
|
|
40
|
+
Documented in `routing-matrix.md` §L3-classifier.
|
|
41
|
+
|
|
42
|
+
## Environment
|
|
43
|
+
|
|
44
|
+
- `CEO_PAIR_RAIL_TIMEOUT_S` (default 30) — Codex invoke wall-clock
|
|
45
|
+
cap. On timeout: fail-OPEN.
|
|
46
|
+
- `CEO_PAIR_RAIL_DISABLE` — kill-switch: when set to `1`, hook is a
|
|
47
|
+
no-op (allow). For incident response.
|
|
48
|
+
- `CEO_PAIR_RAIL_CODEX_BIN` (test-only) — override path to Codex
|
|
49
|
+
binary; defaults to `codex` on `$PATH`.
|
|
50
|
+
- `CEO_PAIR_RAIL_FIXTURE_RESPONSE` (test-only) — preset Codex
|
|
51
|
+
stdout (bypasses subprocess invoke). Test-fixture injection point.
|
|
52
|
+
|
|
53
|
+
## Fail-open contract
|
|
54
|
+
|
|
55
|
+
Any unexpected exception → allow. Hook NEVER blocks the user on its
|
|
56
|
+
own bug — same invariant as `check_canonical_edit.py`. The L3+
|
|
57
|
+
canonical path is still gated downstream by the canonical-edit
|
|
58
|
+
hook (sentinel ceremony) so the cross-LLM rail is purely additive
|
|
59
|
+
defense-in-depth.
|
|
60
|
+
|
|
61
|
+
stdlib-only. Python ≥3.9. `from __future__ import annotations`.
|
|
62
|
+
"""
|
|
63
|
+
|
|
64
|
+
from __future__ import annotations
|
|
65
|
+
|
|
66
|
+
import json
|
|
67
|
+
import os
|
|
68
|
+
import re
|
|
69
|
+
import subprocess
|
|
70
|
+
import sys
|
|
71
|
+
from pathlib import Path
|
|
72
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
73
|
+
|
|
74
|
+
# Promoted from staging on 2026-05-09 (S96-cont-2 v1.13.x patch ceremony,
|
|
75
|
+
# enforcement_commit __FILLED_AT_COMMIT__).
|
|
76
|
+
|
|
77
|
+
# PLAN-091 Wave A.6 (W4.1) status promotion: this hook is now formally
|
|
78
|
+
# PRODUCTION (not "spike"). The PURE decision module
|
|
79
|
+
# `_lib/pair_rail_decide.py` (PLAN-088 W4.1) is the canonical decision
|
|
80
|
+
# kernel; this script is the PreToolUse harness shim that bridges hook-IO
|
|
81
|
+
# (stdin JSON envelope) to the kernel.
|
|
82
|
+
#
|
|
83
|
+
# DEFERRED to PLAN-092 (per R1 code-reviewer escalation clause):
|
|
84
|
+
# The R2 P1 SHADOW-invariant "grep -nE 'decision.*block|return.*deny'
|
|
85
|
+
# returns ZERO" requires stripping the current procedural block path
|
|
86
|
+
# (line ~630 where Codex returning a write-shaped patch yields
|
|
87
|
+
# `{decision: block}`). That is a behavior change with adopter-facing
|
|
88
|
+
# blast radius (regression of the v1.13.x enforcement that has been
|
|
89
|
+
# live in production since S96-cont-2). Per ADR-115 anti-churn +
|
|
90
|
+
# PLAN-091 §3 hotfix discipline, behavior changes are out-of-scope.
|
|
91
|
+
# PLAN-092 owns the SHADOW-strip + its ADR. PLAN-091 ships only the
|
|
92
|
+
# docstring promotion + this `_PRODUCTION_PROMOTED_BY_PLAN_091`
|
|
93
|
+
# constant.
|
|
94
|
+
#
|
|
95
|
+
# See `.claude/plans/PLAN-091/wave-a-pair-rail-defer.md` for the full
|
|
96
|
+
# escalation rationale + PLAN-092 handoff contract.
|
|
97
|
+
_PRODUCTION_PROMOTED_BY_PLAN_091: bool = True
|
|
98
|
+
|
|
99
|
+
# ---------------------------------------------------------------------
|
|
100
|
+
# L3+ path classifier — spike heuristic (Phase 0A only)
|
|
101
|
+
# ---------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
# Glob patterns mirroring `check_canonical_edit._CANONICAL_GUARDS`
|
|
104
|
+
# subset. Conservative: matches the smallest blast-radius surface that
|
|
105
|
+
# justifies cross-LLM review. Phase 1 replaces this with the formal
|
|
106
|
+
# tier-policy classifier (PLAN-071).
|
|
107
|
+
_L3_PLUS_GLOB_PATTERNS: Tuple[str, ...] = (
|
|
108
|
+
".claude/hooks/_lib/*.py",
|
|
109
|
+
".claude/hooks/_lib/**/*.py",
|
|
110
|
+
".claude/hooks/check_*.py",
|
|
111
|
+
".claude/hooks/audit_*.py",
|
|
112
|
+
".claude/scripts/local/*",
|
|
113
|
+
".claude/policies/*.yaml",
|
|
114
|
+
".claude/policies/*.yml",
|
|
115
|
+
"SPEC/v1/*.md",
|
|
116
|
+
".github/workflows/*.yml",
|
|
117
|
+
".github/workflows/*.yaml",
|
|
118
|
+
"PROTOCOL.md",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _fnmatch_segments(path: str, pattern: str) -> bool:
|
|
123
|
+
"""Segment-wise glob matcher with `*` (one segment) and `**` (zero+).
|
|
124
|
+
|
|
125
|
+
Stripped-down port of `check_canonical_edit._fnmatch_segments`.
|
|
126
|
+
"""
|
|
127
|
+
import fnmatch as _fn
|
|
128
|
+
|
|
129
|
+
p_parts = path.split("/")
|
|
130
|
+
pat_parts = pattern.split("/")
|
|
131
|
+
|
|
132
|
+
def _match(p: List[str], pat: List[str]) -> bool:
|
|
133
|
+
if not pat:
|
|
134
|
+
return not p
|
|
135
|
+
head, rest = pat[0], pat[1:]
|
|
136
|
+
if head == "**":
|
|
137
|
+
for i in range(len(p) + 1):
|
|
138
|
+
if _match(p[i:], rest):
|
|
139
|
+
return True
|
|
140
|
+
return False
|
|
141
|
+
if not p:
|
|
142
|
+
return False
|
|
143
|
+
if head == "*" or _fn.fnmatchcase(p[0], head):
|
|
144
|
+
return _match(p[1:], rest)
|
|
145
|
+
return False
|
|
146
|
+
|
|
147
|
+
return _match(p_parts, pat_parts)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _is_l3_plus_path(path_str: str, repo_root: Path) -> bool:
|
|
151
|
+
"""True if path classifies as L3+ per the production heuristic."""
|
|
152
|
+
if not path_str:
|
|
153
|
+
return False
|
|
154
|
+
p = Path(path_str)
|
|
155
|
+
try:
|
|
156
|
+
rel_path = (
|
|
157
|
+
p.resolve().relative_to(repo_root.resolve())
|
|
158
|
+
if p.is_absolute()
|
|
159
|
+
else Path(path_str)
|
|
160
|
+
)
|
|
161
|
+
except (ValueError, OSError):
|
|
162
|
+
# Path outside repo or non-resolvable — not L3+.
|
|
163
|
+
return False
|
|
164
|
+
rel_str = str(rel_path).replace(os.sep, "/")
|
|
165
|
+
for pattern in _L3_PLUS_GLOB_PATTERNS:
|
|
166
|
+
if _fnmatch_segments(rel_str, pattern):
|
|
167
|
+
return True
|
|
168
|
+
return False
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ---------------------------------------------------------------------
|
|
172
|
+
# Codex response — write-shaped patch detection (REUSE detectors from
|
|
173
|
+
# `_lib/mcp/canonical_guard.py`). Phase 0A spike: inline copies the
|
|
174
|
+
# regexes for staging-isolation. Phase 1 will import the canonical
|
|
175
|
+
# helpers directly. The regex constants below are intentionally a
|
|
176
|
+
# byte-identical subset of the canonical_guard.py originals.
|
|
177
|
+
# ---------------------------------------------------------------------
|
|
178
|
+
|
|
179
|
+
# Codex apply_patch envelope: `*** {Update,Add,Delete} File[:?] <path>`
|
|
180
|
+
_CODEX_PATCH_RE = re.compile(
|
|
181
|
+
r"^\*\*\*\s+(Update|Add|Delete|Move|Rename)\s+File:?\s+(.+?)\s*$",
|
|
182
|
+
re.MULTILINE,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Codex `*** Move to:?` directive (R3-01 / R4-01 from PLAN-070).
|
|
186
|
+
_CODEX_MOVE_RE = re.compile(
|
|
187
|
+
r"^\*\*\*\s+(?:Move|Rename)\s+to:?\s+(.+?)\s*$",
|
|
188
|
+
re.MULTILINE,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Unified diff: `--- a/foo` / `+++ b/foo`.
|
|
192
|
+
_UNIFIED_DIFF_RE = re.compile(
|
|
193
|
+
r"^(?:---|\+\+\+)\s+(?:[ab]/)?(.+?)\s*$", re.MULTILINE,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# JSON Patch (RFC 6902) — legacy regex fallback for non-JSON-shape
|
|
197
|
+
# bodies that embed JSON-looking substrings. The primary parser uses
|
|
198
|
+
# json.loads on bodies that lstrip-start with `[` or `{`.
|
|
199
|
+
_JSON_PATCH_PATH_RE = re.compile(
|
|
200
|
+
r'"path"\s*:\s*"(/[^"\\]*(?:\\.[^"\\]*)*)"'
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# ReDoS defense: cap response size before regex invocation.
|
|
204
|
+
_MAX_RESPONSE_BYTES = 4 * 1024 * 1024 # 4 MiB
|
|
205
|
+
_MAX_RESPONSE_LINES = 200_000
|
|
206
|
+
|
|
207
|
+
# PLAN-142: hard cap on bytes read back from the helper-built last-message
|
|
208
|
+
# output file (the untrusted binary is the WRITER — TOCTOU). The redactor
|
|
209
|
+
# independently truncates at 256 KB; this is a defense-in-depth read-time cap
|
|
210
|
+
# so an oversize / disk-filling file cannot be slurped whole before redaction.
|
|
211
|
+
# Oversize (file larger than this) → ADVISORY degradation, never raise.
|
|
212
|
+
_MAX_OUTPUT_FILE_BYTES: int = 1 * 1024 * 1024 # 1 MiB
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _detect_write_shaped_patch(response_text: str) -> Optional[str]:
|
|
216
|
+
"""Detect any write-shaped patch in a Codex review response.
|
|
217
|
+
|
|
218
|
+
Returns the matched grammar tag (`codex_apply_patch`, `unified_diff`,
|
|
219
|
+
`codex_move`, `json_patch`) on first detection, or None if response
|
|
220
|
+
is clean. Order is: Codex envelope → unified diff → JSON patch.
|
|
221
|
+
|
|
222
|
+
Defense:
|
|
223
|
+
- Length cap (4 MiB) — pathological responses skipped (treated as
|
|
224
|
+
clean by production heuristic; future revision should fail-CLOSED).
|
|
225
|
+
- Line cap (200k) — bound regex iteration.
|
|
226
|
+
- All regexes anchored with `^...$` (multiline) — no nested
|
|
227
|
+
quantifiers susceptible to ReDoS.
|
|
228
|
+
"""
|
|
229
|
+
if not isinstance(response_text, str) or not response_text:
|
|
230
|
+
return None
|
|
231
|
+
if len(response_text) > _MAX_RESPONSE_BYTES:
|
|
232
|
+
# Spike: treat oversize as clean (advisory). Production note:
|
|
233
|
+
# ADR-110 PROPOSED Phase 1 should fail-CLOSED here.
|
|
234
|
+
return None
|
|
235
|
+
# Cap line count via early exit on findall-like inspection.
|
|
236
|
+
line_count = response_text.count("\n")
|
|
237
|
+
if line_count > _MAX_RESPONSE_LINES:
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
# Grammar 1a: Codex apply_patch envelope.
|
|
241
|
+
if _CODEX_PATCH_RE.search(response_text) is not None:
|
|
242
|
+
return "codex_apply_patch"
|
|
243
|
+
|
|
244
|
+
# Grammar 1b: Codex move directive.
|
|
245
|
+
if _CODEX_MOVE_RE.search(response_text) is not None:
|
|
246
|
+
return "codex_move"
|
|
247
|
+
|
|
248
|
+
# Grammar 2: Unified diff. Filter false positives from prose by
|
|
249
|
+
# requiring the second-half marker to also exist (`---` AND `+++`).
|
|
250
|
+
has_minus = re.search(r"^---\s+", response_text, re.MULTILINE) is not None
|
|
251
|
+
has_plus = re.search(r"^\+\+\+\s+", response_text, re.MULTILINE) is not None
|
|
252
|
+
if has_minus and has_plus:
|
|
253
|
+
return "unified_diff"
|
|
254
|
+
|
|
255
|
+
# Grammar 3: JSON Patch (RFC 6902). Two-pass:
|
|
256
|
+
# (a) JSON-shape body — try strict json.loads.
|
|
257
|
+
stripped = response_text.lstrip()
|
|
258
|
+
if stripped.startswith(("[", "{")):
|
|
259
|
+
try:
|
|
260
|
+
parsed = json.loads(response_text)
|
|
261
|
+
except (ValueError, TypeError):
|
|
262
|
+
parsed = None
|
|
263
|
+
if isinstance(parsed, list):
|
|
264
|
+
for op in parsed:
|
|
265
|
+
if (
|
|
266
|
+
isinstance(op, dict)
|
|
267
|
+
and isinstance(op.get("op"), str)
|
|
268
|
+
and isinstance(op.get("path"), str)
|
|
269
|
+
and op["path"].startswith("/")
|
|
270
|
+
and op["op"] in {"add", "remove", "replace", "move", "copy"}
|
|
271
|
+
):
|
|
272
|
+
return "json_patch"
|
|
273
|
+
elif isinstance(parsed, dict):
|
|
274
|
+
# Single op object (uncommon but valid).
|
|
275
|
+
if (
|
|
276
|
+
isinstance(parsed.get("op"), str)
|
|
277
|
+
and isinstance(parsed.get("path"), str)
|
|
278
|
+
and parsed["path"].startswith("/")
|
|
279
|
+
and parsed["op"] in {"add", "remove", "replace", "move", "copy"}
|
|
280
|
+
):
|
|
281
|
+
return "json_patch"
|
|
282
|
+
# (b) Legacy regex fallback for embedded JSON-Patch fragments in
|
|
283
|
+
# mixed prose.
|
|
284
|
+
if (
|
|
285
|
+
'"op"' in response_text
|
|
286
|
+
and '"path"' in response_text
|
|
287
|
+
and _JSON_PATCH_PATH_RE.search(response_text) is not None
|
|
288
|
+
):
|
|
289
|
+
return "json_patch"
|
|
290
|
+
|
|
291
|
+
return None
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
# ---------------------------------------------------------------------
|
|
295
|
+
# Codex MCP invoke — subprocess wrapper. Spike-only; Phase 1 replaces
|
|
296
|
+
# with the typed `_lib/adapters/codex.py` adapter.
|
|
297
|
+
# ---------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
class CodexUnavailable(Exception):
|
|
301
|
+
"""Raised when Codex binary is missing or invoke fails non-recoverably."""
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class CodexTimeout(Exception):
|
|
305
|
+
"""Raised when Codex exceeds the wall-clock cap (CEO_PAIR_RAIL_TIMEOUT_S)."""
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
class CodexMalformed(Exception):
|
|
309
|
+
"""Raised when Codex stdout cannot be parsed as a valid review envelope."""
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def _resolve_codex_bin() -> Optional[str]:
|
|
313
|
+
"""Return path to Codex binary, or None if not on PATH.
|
|
314
|
+
|
|
315
|
+
Test-friendly: env `CEO_PAIR_RAIL_CODEX_BIN` overrides discovery.
|
|
316
|
+
"""
|
|
317
|
+
override = os.environ.get("CEO_PAIR_RAIL_CODEX_BIN")
|
|
318
|
+
if override:
|
|
319
|
+
return override if Path(override).exists() else None
|
|
320
|
+
# Lightweight PATH discovery — `which` semantics without subprocess.
|
|
321
|
+
for entry in os.environ.get("PATH", "").split(os.pathsep):
|
|
322
|
+
candidate = Path(entry) / "codex"
|
|
323
|
+
if candidate.exists() and os.access(candidate, os.X_OK):
|
|
324
|
+
return str(candidate)
|
|
325
|
+
return None
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _build_codex_prompt(
|
|
329
|
+
tool_name: str, file_path: str, proposed_content: str
|
|
330
|
+
) -> str:
|
|
331
|
+
"""Build the read-only review prompt sent to Codex.
|
|
332
|
+
|
|
333
|
+
Production contract: prompt asks Codex to review for governance issues
|
|
334
|
+
+ return REVIEW-ONLY. ANY `*** Update File:` / unified diff /
|
|
335
|
+
JSON-Patch in the response → automatic violation (regardless of
|
|
336
|
+
intent — the hook contract is purely structural).
|
|
337
|
+
"""
|
|
338
|
+
# Truncate proposed_content for prompt size sanity. Phase 1 will
|
|
339
|
+
# use chunked streaming; spike caps at 32 KiB.
|
|
340
|
+
capped = proposed_content[:32 * 1024] if proposed_content else ""
|
|
341
|
+
return (
|
|
342
|
+
f"PAIR-RAIL READ-ONLY REVIEW (PLAN-075 Phase 0A spike)\n\n"
|
|
343
|
+
f"Tool: {tool_name}\n"
|
|
344
|
+
f"Target path: {file_path}\n\n"
|
|
345
|
+
"You are a READ-ONLY reviewer. Do NOT emit any patch, diff, "
|
|
346
|
+
"apply_patch envelope, or JSON-Patch op.\n"
|
|
347
|
+
"If you would change the file, describe the change in PROSE "
|
|
348
|
+
"ONLY (no code-fenced patches, no `*** Update File:` lines, "
|
|
349
|
+
"no `--- a/...` / `+++ b/...` markers).\n\n"
|
|
350
|
+
f"Proposed content (truncated to 32 KiB):\n```\n{capped}\n```"
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _resolve_codex_cli_shape(): # type: ignore[no-untyped-def]
|
|
355
|
+
"""Resolve the NEW non-kernel `_lib.codex_cli_shape` module.
|
|
356
|
+
|
|
357
|
+
Mirrors the canonical-layout resolution used elsewhere: the
|
|
358
|
+
`.claude/hooks/` dir that houses this file also houses `_lib/`. Returns
|
|
359
|
+
the module or None (fail-OPEN — the caller treats None as
|
|
360
|
+
CodexUnavailable, the ADR-106 fail-open path). NEVER raises.
|
|
361
|
+
"""
|
|
362
|
+
try:
|
|
363
|
+
hooks_dir = Path(__file__).resolve().parent
|
|
364
|
+
if str(hooks_dir) not in sys.path:
|
|
365
|
+
sys.path.insert(0, str(hooks_dir))
|
|
366
|
+
from _lib import codex_cli_shape as _shape # type: ignore
|
|
367
|
+
return _shape
|
|
368
|
+
except Exception:
|
|
369
|
+
return None
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
def _invoke_codex_review(
|
|
373
|
+
tool_name: str,
|
|
374
|
+
file_path: str,
|
|
375
|
+
proposed_content: str,
|
|
376
|
+
timeout_s: float,
|
|
377
|
+
) -> str:
|
|
378
|
+
"""Invoke Codex review on codex-cli 0.139.0; return the REDACTED
|
|
379
|
+
last-message file content (one structured JSON object) as a str.
|
|
380
|
+
|
|
381
|
+
PLAN-142: the verdict is obtained by having the CLI write ONLY the final
|
|
382
|
+
agent message to a private output file (verified on 0.139: a one-line
|
|
383
|
+
JSON object). ALL flag-shape lives in the NON-kernel
|
|
384
|
+
``_lib.codex_cli_shape`` helper (D2); this kernel function constructs NO
|
|
385
|
+
argv literals.
|
|
386
|
+
|
|
387
|
+
Signature contract UNCHANGED for the consumer: returns a single str.
|
|
388
|
+
But it is now the isolated last agent message (one structured object),
|
|
389
|
+
ALREADY single-pass redacted (R-SEC-1 — redaction at the lowest-trust
|
|
390
|
+
file-read site, before any json.loads in the consumer).
|
|
391
|
+
|
|
392
|
+
Test-fixture path: env `CEO_PAIR_RAIL_FIXTURE_RESPONSE` short-circuits
|
|
393
|
+
the subprocess invoke and is treated as the already-isolated
|
|
394
|
+
last-message string; it is STILL single-pass redacted so fixture tests
|
|
395
|
+
exercise the same ingress trust boundary as a real file read.
|
|
396
|
+
|
|
397
|
+
tmpfile TOCTOU hygiene (R-SEC-4 / R-VP-E): a private `mkdtemp(0o700)`
|
|
398
|
+
dir per call; the output file is pre-created O_CREAT|O_EXCL|0o600 at an
|
|
399
|
+
absolute path; after the run we REFUSE to read if it is a symlink / not
|
|
400
|
+
a regular file / not owned by us; `finally:` unlink (output + schema) +
|
|
401
|
+
rmdir on EVERY exit path (success, read error, timeout, exception).
|
|
402
|
+
|
|
403
|
+
Degradation matrix → CodexUnavailable / CodexTimeout / CodexMalformed
|
|
404
|
+
(all map to ADVISORY in `_decide`), NEVER raise past the typed wall:
|
|
405
|
+
helper/binary missing, spawn error, non-zero exit → CodexUnavailable;
|
|
406
|
+
timeout → CodexTimeout; output file missing-after-exit-0 / symlink /
|
|
407
|
+
non-regular / not-owned / empty / oversize → CodexMalformed.
|
|
408
|
+
|
|
409
|
+
Raises:
|
|
410
|
+
CodexUnavailable, CodexTimeout, CodexMalformed (all consumed as
|
|
411
|
+
ADVISORY fail-open by `_decide`).
|
|
412
|
+
"""
|
|
413
|
+
import os as _os # local alias to avoid any chance of shadowing
|
|
414
|
+
import stat as _stat
|
|
415
|
+
import tempfile as _tempfile
|
|
416
|
+
|
|
417
|
+
fixture = _os.environ.get("CEO_PAIR_RAIL_FIXTURE_RESPONSE")
|
|
418
|
+
if fixture is not None:
|
|
419
|
+
# Fixture is the already-isolated last-message string. STILL
|
|
420
|
+
# single-pass redact it so the fixture path exercises the same
|
|
421
|
+
# ingress trust boundary as a real file read (R-SEC-6).
|
|
422
|
+
try:
|
|
423
|
+
from _lib import codex_egress_redact as _redact
|
|
424
|
+
return _redact.redact(fixture)
|
|
425
|
+
except Exception:
|
|
426
|
+
# Un-redactable ingress fixture → malformed so the consumer
|
|
427
|
+
# degrades to ADVISORY rather than parsing un-redacted text.
|
|
428
|
+
# (This is the INGRESS fail-open-to-ADVISORY path, distinct from
|
|
429
|
+
# the ADR-114 fail-CLOSED egress contract below.)
|
|
430
|
+
raise CodexMalformed(
|
|
431
|
+
"codex_egress_redact unavailable on ingress (fixture)"
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
codex_bin = _resolve_codex_bin()
|
|
435
|
+
if codex_bin is None:
|
|
436
|
+
raise CodexUnavailable("codex binary not on PATH")
|
|
437
|
+
|
|
438
|
+
shape = _resolve_codex_cli_shape()
|
|
439
|
+
if shape is None:
|
|
440
|
+
# The single argv builder is gone/unimportable. Fail-OPEN to
|
|
441
|
+
# ADVISORY rather than hand-roll a (possibly rejected) argv.
|
|
442
|
+
raise CodexUnavailable("codex_cli_shape helper unavailable")
|
|
443
|
+
|
|
444
|
+
prompt = _build_codex_prompt(tool_name, file_path, proposed_content)
|
|
445
|
+
# PLAN-084 Wave 0.5 (ADR-114 + AC9 — Codex egress redaction symmetry).
|
|
446
|
+
# proposed_content is raw FILE CONTENT being reviewed (potentially
|
|
447
|
+
# secret-laden source). Redact the OUTGOING prompt BEFORE it leaves the
|
|
448
|
+
# framework. This stays fail-CLOSED per ADR-114: a redactor-import
|
|
449
|
+
# failure REFUSES to ship the prompt.
|
|
450
|
+
try:
|
|
451
|
+
from _lib import codex_egress_redact as _redact
|
|
452
|
+
_egress_bytes = len(prompt.encode("utf-8", "replace")) if isinstance(prompt, str) else 0
|
|
453
|
+
prompt, _egress_findings = _redact.redact_outgoing_with_findings(prompt)
|
|
454
|
+
except ImportError:
|
|
455
|
+
# Fail-CLOSED per ADR-114: refuse to ship unredacted prompt to Codex.
|
|
456
|
+
raise CodexUnavailable("codex_egress_redact unavailable — fail-CLOSED per ADR-114")
|
|
457
|
+
# PLAN-112-FOLLOWUP-codex-egress-proof-telemetry (F-7.9): positive-proof
|
|
458
|
+
# emit on EVERY outbound redaction (empty allowed). Fail-OPEN — wraps ONLY
|
|
459
|
+
# the emit; the redact above stays fail-CLOSED per ADR-114.
|
|
460
|
+
try:
|
|
461
|
+
from _lib import audit_emit as _ae
|
|
462
|
+
_ae.emit_pair_rail_outgoing_redaction_applied(
|
|
463
|
+
signal="outbound",
|
|
464
|
+
match_count=len(_egress_findings),
|
|
465
|
+
bytes_scanned=_egress_bytes,
|
|
466
|
+
callsite="check_pair_rail.py:_invoke_codex_review",
|
|
467
|
+
session_id=os.environ.get("CLAUDE_SESSION_ID", ""),
|
|
468
|
+
project=os.environ.get("CLAUDE_PROJECT_DIR", ""),
|
|
469
|
+
)
|
|
470
|
+
except Exception:
|
|
471
|
+
pass
|
|
472
|
+
|
|
473
|
+
# -----------------------------------------------------------------
|
|
474
|
+
# tmpfile setup — we own the dir (0o700) and pre-create the output
|
|
475
|
+
# file with O_EXCL|0o600 to win the symlink race; the CLI writes to it
|
|
476
|
+
# by absolute path. A sibling schema file (written by US, not the
|
|
477
|
+
# untrusted binary) carries the CLI-enforced verdict shape.
|
|
478
|
+
# -----------------------------------------------------------------
|
|
479
|
+
tmp_dir = _tempfile.mkdtemp(prefix="ceo_pairrail_")
|
|
480
|
+
try:
|
|
481
|
+
_os.chmod(tmp_dir, 0o700)
|
|
482
|
+
except OSError:
|
|
483
|
+
pass # mkdtemp already creates 0o700 on POSIX
|
|
484
|
+
out_path = _os.path.join(tmp_dir, "codex_last_message.json")
|
|
485
|
+
schema_path = _os.path.join(tmp_dir, "codex_verdict_schema.json")
|
|
486
|
+
|
|
487
|
+
def _cleanup() -> None:
|
|
488
|
+
"""Unlink both tmpfiles + rmdir the dir; never raises."""
|
|
489
|
+
for _p in (out_path, schema_path):
|
|
490
|
+
try:
|
|
491
|
+
_os.unlink(_p)
|
|
492
|
+
except OSError:
|
|
493
|
+
pass
|
|
494
|
+
try:
|
|
495
|
+
_os.rmdir(tmp_dir)
|
|
496
|
+
except OSError:
|
|
497
|
+
pass
|
|
498
|
+
|
|
499
|
+
try:
|
|
500
|
+
# Pre-create O_CREAT|O_EXCL|0o600 — if a symlink/file already sits
|
|
501
|
+
# at out_path, O_EXCL fails and we treat it as unavailable.
|
|
502
|
+
try:
|
|
503
|
+
fd = _os.open(out_path, _os.O_CREAT | _os.O_EXCL | _os.O_WRONLY, 0o600)
|
|
504
|
+
_os.close(fd)
|
|
505
|
+
except FileNotFoundError:
|
|
506
|
+
raise CodexUnavailable("tmpdir vanished before pre-create")
|
|
507
|
+
except FileExistsError:
|
|
508
|
+
raise CodexUnavailable("tmpfile pre-create lost O_EXCL race")
|
|
509
|
+
except OSError as e:
|
|
510
|
+
raise CodexUnavailable(f"tmpfile pre-create failed: {type(e).__name__}")
|
|
511
|
+
|
|
512
|
+
# Write the CLI-enforced verdict schema to our schema tmpfile
|
|
513
|
+
# (PLAN-142 §3 [P1], R-SEC-2). Best-effort: if the helper cannot
|
|
514
|
+
# serialize it, proceed WITHOUT enforcement (parser-side
|
|
515
|
+
# parse_verdict_strict still validates the shape).
|
|
516
|
+
schema_arg: Optional[str] = None
|
|
517
|
+
try:
|
|
518
|
+
schema_json = shape.verdict_output_schema_json()
|
|
519
|
+
sfd = _os.open(schema_path, _os.O_CREAT | _os.O_EXCL | _os.O_WRONLY, 0o600)
|
|
520
|
+
try:
|
|
521
|
+
_os.write(sfd, schema_json.encode("utf-8"))
|
|
522
|
+
finally:
|
|
523
|
+
_os.close(sfd)
|
|
524
|
+
schema_arg = schema_path
|
|
525
|
+
except Exception:
|
|
526
|
+
schema_arg = None
|
|
527
|
+
|
|
528
|
+
# Build argv via the NON-kernel helper. The live-rail shape writes
|
|
529
|
+
# the verdict to our output file and drops usage telemetry (R-SEC-5);
|
|
530
|
+
# we pass only semantic intent — the helper owns flag names, the
|
|
531
|
+
# model id, and the dead-flag migration.
|
|
532
|
+
try:
|
|
533
|
+
cli_args = shape.build_verdict_argv(
|
|
534
|
+
prompt,
|
|
535
|
+
output_file=out_path,
|
|
536
|
+
schema_file=schema_arg,
|
|
537
|
+
)
|
|
538
|
+
except Exception as e:
|
|
539
|
+
raise CodexUnavailable(
|
|
540
|
+
f"codex_cli_shape.build_verdict_argv failed: {type(e).__name__}"
|
|
541
|
+
)
|
|
542
|
+
if not isinstance(cli_args, (list, tuple)) or not cli_args:
|
|
543
|
+
raise CodexUnavailable("codex_cli_shape returned empty argv")
|
|
544
|
+
|
|
545
|
+
cmd = [codex_bin] + list(cli_args)
|
|
546
|
+
|
|
547
|
+
# Invoke. The prompt is the trailing positional built by the helper;
|
|
548
|
+
# close stdin via input="" so the child never blocks on a pipe.
|
|
549
|
+
try:
|
|
550
|
+
proc = subprocess.run(
|
|
551
|
+
cmd,
|
|
552
|
+
input="",
|
|
553
|
+
capture_output=True,
|
|
554
|
+
text=True,
|
|
555
|
+
timeout=timeout_s,
|
|
556
|
+
check=False,
|
|
557
|
+
)
|
|
558
|
+
except subprocess.TimeoutExpired:
|
|
559
|
+
raise CodexTimeout(f"codex invoke exceeded {timeout_s}s")
|
|
560
|
+
except (FileNotFoundError, PermissionError, OSError, ConnectionError) as e:
|
|
561
|
+
raise CodexUnavailable(f"codex invoke failed: {type(e).__name__}: {e}")
|
|
562
|
+
except ValueError as e:
|
|
563
|
+
# UnicodeDecodeError IS-A ValueError; map to malformed so
|
|
564
|
+
# `_decide` degrades to ADVISORY (preserve concrete name).
|
|
565
|
+
raise CodexMalformed(f"codex invoke {type(e).__name__}: {e}")
|
|
566
|
+
|
|
567
|
+
# Post-subprocess audit breadcrumb (UNCHANGED behavior).
|
|
568
|
+
try:
|
|
569
|
+
from _lib import audit_emit as _ae # type: ignore # noqa: F811
|
|
570
|
+
if hasattr(_ae, "emit_generic"):
|
|
571
|
+
_ae.emit_generic("codex_invoke_dispatched", exit_code=int(proc.returncode))
|
|
572
|
+
except Exception:
|
|
573
|
+
pass
|
|
574
|
+
|
|
575
|
+
if proc.returncode != 0:
|
|
576
|
+
# Non-zero exit → unavailable (fail-OPEN). A present output file
|
|
577
|
+
# after a non-zero exit is IGNORED (not read) and cleaned up.
|
|
578
|
+
raise CodexUnavailable(
|
|
579
|
+
f"codex returned exit={proc.returncode}; stderr_head="
|
|
580
|
+
f"{(proc.stderr or '')[:240]!r}"
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
# -------------------------------------------------------------
|
|
584
|
+
# Read back the output file with TOCTOU re-validation. Re-stat via
|
|
585
|
+
# os.lstat (NOT following symlinks) and refuse anything that is not
|
|
586
|
+
# a regular file we own.
|
|
587
|
+
# -------------------------------------------------------------
|
|
588
|
+
try:
|
|
589
|
+
st = _os.lstat(out_path)
|
|
590
|
+
except FileNotFoundError:
|
|
591
|
+
raise CodexMalformed("codex last-message file missing after exit-0")
|
|
592
|
+
except OSError as e:
|
|
593
|
+
raise CodexMalformed(f"codex last-message lstat failed: {type(e).__name__}")
|
|
594
|
+
|
|
595
|
+
if _stat.S_ISLNK(st.st_mode):
|
|
596
|
+
raise CodexMalformed("codex last-message path is a symlink; refusing to read")
|
|
597
|
+
if not _stat.S_ISREG(st.st_mode):
|
|
598
|
+
raise CodexMalformed("codex last-message path is not a regular file; refusing")
|
|
599
|
+
try:
|
|
600
|
+
if st.st_uid != _os.getuid():
|
|
601
|
+
raise CodexMalformed("codex last-message file not owned by us; refusing")
|
|
602
|
+
except AttributeError:
|
|
603
|
+
# os.getuid absent (non-POSIX) — the 0o700 mkdtemp + O_EXCL
|
|
604
|
+
# pre-create are the primary controls; skip the uid check.
|
|
605
|
+
pass
|
|
606
|
+
if st.st_size == 0:
|
|
607
|
+
raise CodexMalformed("codex last-message file is empty")
|
|
608
|
+
if st.st_size > _MAX_OUTPUT_FILE_BYTES:
|
|
609
|
+
raise CodexMalformed(
|
|
610
|
+
f"codex last-message oversize ({st.st_size} > {_MAX_OUTPUT_FILE_BYTES})"
|
|
611
|
+
)
|
|
612
|
+
|
|
613
|
+
# Open refusing to follow a symlink swapped in post-lstat.
|
|
614
|
+
try:
|
|
615
|
+
open_flags = _os.O_RDONLY
|
|
616
|
+
if hasattr(_os, "O_NOFOLLOW"):
|
|
617
|
+
open_flags |= _os.O_NOFOLLOW
|
|
618
|
+
rfd = _os.open(out_path, open_flags)
|
|
619
|
+
except OSError as e:
|
|
620
|
+
raise CodexMalformed(f"codex last-message open failed: {type(e).__name__}")
|
|
621
|
+
try:
|
|
622
|
+
raw_bytes = _os.read(rfd, _MAX_OUTPUT_FILE_BYTES + 1)
|
|
623
|
+
finally:
|
|
624
|
+
try:
|
|
625
|
+
_os.close(rfd)
|
|
626
|
+
except OSError:
|
|
627
|
+
pass
|
|
628
|
+
if len(raw_bytes) > _MAX_OUTPUT_FILE_BYTES:
|
|
629
|
+
raise CodexMalformed("codex last-message grew past cap during read")
|
|
630
|
+
|
|
631
|
+
content = raw_bytes.decode("utf-8", errors="replace")
|
|
632
|
+
|
|
633
|
+
# -------------------------------------------------------------
|
|
634
|
+
# SINGLE-PASS redact the FULL byte-string BEFORE returning (and
|
|
635
|
+
# thus before any json.loads in the consumer). R-SEC-1. Ingress
|
|
636
|
+
# redaction is fail-OPEN to ADVISORY (distinct from the ADR-114
|
|
637
|
+
# fail-CLOSED *egress* contract above): if the redactor is
|
|
638
|
+
# unavailable we refuse to hand un-redacted text to the parser and
|
|
639
|
+
# degrade to ADVISORY via CodexMalformed.
|
|
640
|
+
# -------------------------------------------------------------
|
|
641
|
+
try:
|
|
642
|
+
from _lib import codex_egress_redact as _redact # noqa: F811
|
|
643
|
+
redacted = _redact.redact(content)
|
|
644
|
+
except Exception:
|
|
645
|
+
raise CodexMalformed(
|
|
646
|
+
"codex_egress_redact unavailable on ingress; refusing raw parse"
|
|
647
|
+
)
|
|
648
|
+
return redacted
|
|
649
|
+
finally:
|
|
650
|
+
_cleanup()
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
# ---------------------------------------------------------------------
|
|
654
|
+
# Sentinel bypass — share the same sentinel discovery as
|
|
655
|
+
# check_canonical_edit. A path that is canonical-edit-approved via
|
|
656
|
+
# sentinel is implicitly Pair-Rail-approved (Codex review still
|
|
657
|
+
# advisory, not gating). Phase 0A simplification.
|
|
658
|
+
# ---------------------------------------------------------------------
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
def _sentinel_grants_pair_rail_bypass(
|
|
662
|
+
file_path: str, repo_root: Path
|
|
663
|
+
) -> bool:
|
|
664
|
+
"""True if any Architect sentinel covers `file_path` in its scope.
|
|
665
|
+
|
|
666
|
+
Production: piggybacks on `check_canonical_edit._sentinel_grants_path`
|
|
667
|
+
if that helper is importable. Otherwise returns False (no bypass).
|
|
668
|
+
"""
|
|
669
|
+
try:
|
|
670
|
+
# Best-effort import; staging file should not depend on
|
|
671
|
+
# production import path. Fail soft.
|
|
672
|
+
hooks_dir = repo_root / ".claude" / "hooks"
|
|
673
|
+
if str(hooks_dir) not in sys.path:
|
|
674
|
+
sys.path.insert(0, str(hooks_dir))
|
|
675
|
+
try:
|
|
676
|
+
import check_canonical_edit as _cce # type: ignore
|
|
677
|
+
except Exception:
|
|
678
|
+
return False
|
|
679
|
+
try:
|
|
680
|
+
rel = (
|
|
681
|
+
Path(file_path).resolve().relative_to(repo_root.resolve())
|
|
682
|
+
)
|
|
683
|
+
except (ValueError, OSError):
|
|
684
|
+
return False
|
|
685
|
+
rel_str = str(rel).replace(os.sep, "/")
|
|
686
|
+
sentinels = _cce._find_sentinels(repo_root) # type: ignore[attr-defined]
|
|
687
|
+
for sentinel in sentinels:
|
|
688
|
+
try:
|
|
689
|
+
if _cce._sentinel_grants_path(sentinel, rel_str): # type: ignore[attr-defined]
|
|
690
|
+
return True
|
|
691
|
+
except Exception:
|
|
692
|
+
continue
|
|
693
|
+
return False
|
|
694
|
+
except Exception:
|
|
695
|
+
return False
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
# ---------------------------------------------------------------------
|
|
699
|
+
# Audit emit — best-effort; never raises.
|
|
700
|
+
# ---------------------------------------------------------------------
|
|
701
|
+
|
|
702
|
+
# Audit action labels. Post Phase 0B/1 ceremony:
|
|
703
|
+
# - REGISTERED in audit_emit._KNOWN_ACTIONS (lines 338-341 of audit_emit.py):
|
|
704
|
+
# pair_rail_review_passed, pair_rail_codex_unavailable,
|
|
705
|
+
# pair_rail_codex_violation, pair_rail_sentinel_bypass
|
|
706
|
+
# - PENDING registration (still breadcrumb-only to stderr; future
|
|
707
|
+
# Owner-signed sentinel ceremony will promote them):
|
|
708
|
+
# pair_rail_out_of_scope, pair_rail_kill_switch_used,
|
|
709
|
+
# pair_rail_fatal_failopen
|
|
710
|
+
# The registered labels are durable audit records; the pending ones
|
|
711
|
+
# still surface via stderr for forensic sampling until promoted.
|
|
712
|
+
_AUDIT_REVIEW_PASSED = "pair_rail_review_passed"
|
|
713
|
+
_AUDIT_CODEX_VIOLATION = "pair_rail_codex_violation"
|
|
714
|
+
_AUDIT_CODEX_UNAVAILABLE = "pair_rail_codex_unavailable"
|
|
715
|
+
_AUDIT_SENTINEL_BYPASS = "pair_rail_sentinel_bypass"
|
|
716
|
+
_AUDIT_OUT_OF_SCOPE = "pair_rail_out_of_scope"
|
|
717
|
+
_AUDIT_KILL_SWITCH = "pair_rail_kill_switch_used"
|
|
718
|
+
# U10 NEW — uniform breadcrumb when main()'s catch-all swallows an
|
|
719
|
+
# unexpected exception. Without this, a hidden bug fails open silently
|
|
720
|
+
# with only a stderr line; with this, the audit sink keeps a single
|
|
721
|
+
# structured record that SPIKE-VERDICT.md can sample for U10 evidence.
|
|
722
|
+
_AUDIT_FATAL_FAILOPEN = "pair_rail_fatal_failopen"
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
def _emit_audit(action: str, **fields: Any) -> None:
|
|
726
|
+
"""Best-effort audit. Production fallback: stderr breadcrumb when no audit sink configured.
|
|
727
|
+
|
|
728
|
+
Phase 1 wires through `_lib/audit_emit.emit_generic` after
|
|
729
|
+
register-ceremony lands the action labels in `_KNOWN_ACTIONS`.
|
|
730
|
+
"""
|
|
731
|
+
# Test capture hook: env-controlled file sink for unit tests.
|
|
732
|
+
sink = os.environ.get("CEO_PAIR_RAIL_AUDIT_SINK")
|
|
733
|
+
if sink:
|
|
734
|
+
try:
|
|
735
|
+
event = {"action": action, **fields}
|
|
736
|
+
with open(sink, "a", encoding="utf-8") as f:
|
|
737
|
+
f.write(json.dumps(event, ensure_ascii=False) + "\n")
|
|
738
|
+
except Exception:
|
|
739
|
+
pass # advisory; never blocks
|
|
740
|
+
# Stderr breadcrumb (spike — visible in test output).
|
|
741
|
+
try:
|
|
742
|
+
preview = ", ".join(
|
|
743
|
+
f"{k}={v!r}" for k, v in list(fields.items())[:5]
|
|
744
|
+
)
|
|
745
|
+
sys.stderr.write(
|
|
746
|
+
f"[check_pair_rail SPIKE] {action} {preview}\n"
|
|
747
|
+
)
|
|
748
|
+
except Exception:
|
|
749
|
+
pass
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
# PLAN-122 WS3 — per-phase Codex-review audit event. ONE emit-site: fired once
|
|
753
|
+
# when a Codex review actually COMPLETES (any verdict). The kill-switch /
|
|
754
|
+
# unavailable / timeout / malformed paths represent NO completed invocation and
|
|
755
|
+
# do NOT emit here (consistent with WS3-SPEC: codex_review_disabled covers the
|
|
756
|
+
# kill-switch path; an unavailable Codex never ran). Trust boundary: the raw
|
|
757
|
+
# review text crosses a LOWER-trust boundary and is folded into the audit channel
|
|
758
|
+
# ONLY as the redacted PhaseReview (enum / bounded int / stable hash / fixed
|
|
759
|
+
# slug). FAIL-CLOSED: any import / mapping failure emits nothing. Never raises.
|
|
760
|
+
def _emit_codex_review_invoked(review_text: str, grammar: "Optional[str]") -> None:
|
|
761
|
+
"""Emit codex_review_invoked for a completed Codex review (best-effort).
|
|
762
|
+
|
|
763
|
+
``grammar`` is the write-shaped-patch verdict from ``_detect_write_shaped_patch``
|
|
764
|
+
(``None`` == clean/passed; non-``None`` == a flagged violation/failed). We feed
|
|
765
|
+
the review through the WS-3 driver (the single redaction source) so the raw
|
|
766
|
+
text is hashed, never echoed, then route the redacted PhaseReview fields
|
|
767
|
+
through ``optimizer._skeleton.safe_emit`` (silent until the action registers).
|
|
768
|
+
"""
|
|
769
|
+
try:
|
|
770
|
+
repo_root = Path(__file__).resolve().parents[2]
|
|
771
|
+
scripts_dir = str((repo_root / ".claude" / "scripts").resolve())
|
|
772
|
+
if scripts_dir not in sys.path:
|
|
773
|
+
sys.path.insert(0, scripts_dir)
|
|
774
|
+
from optimizer import codex_phase_gate as _pg # type: ignore[import]
|
|
775
|
+
from optimizer import _skeleton as _sk # type: ignore[import]
|
|
776
|
+
|
|
777
|
+
# Map the already-obtained review into a driver result. We INJECT a
|
|
778
|
+
# closure returning that result so review_phase does the verdict
|
|
779
|
+
# classification + redaction (status, violation-count normalisation,
|
|
780
|
+
# thread/summary hashing) — we never re-implement that boundary here.
|
|
781
|
+
# The kill-switch is intentionally bypassed: we only reach this site
|
|
782
|
+
# AFTER a real invocation completed, so we drive review_phase with
|
|
783
|
+
# CEO_CODEX_REVIEW unset semantics via a direct injected result.
|
|
784
|
+
verdict = "block" if grammar is not None else "accept"
|
|
785
|
+
injected = {
|
|
786
|
+
"status": verdict,
|
|
787
|
+
"summary": review_text if isinstance(review_text, str) else "",
|
|
788
|
+
}
|
|
789
|
+
review = _pg.review_phase(
|
|
790
|
+
0, "", codex_invoke=lambda _p, _m: injected,
|
|
791
|
+
)
|
|
792
|
+
# review_disabled_signal is NOT forwarded — it routes the disabled
|
|
793
|
+
# sibling instead; forwarding a bool would break canonical-json/HMAC.
|
|
794
|
+
_sk.safe_emit(
|
|
795
|
+
"codex_review_invoked",
|
|
796
|
+
repo_root=repo_root,
|
|
797
|
+
session_id=os.environ.get("CLAUDE_SESSION_ID", ""),
|
|
798
|
+
phase_number=review.phase_number,
|
|
799
|
+
review_status=review.review_status,
|
|
800
|
+
summary_hash=review.summary_hash,
|
|
801
|
+
thread_id_redacted=review.thread_id_redacted,
|
|
802
|
+
codex_model=review.codex_model,
|
|
803
|
+
duration_ms=review.duration_ms,
|
|
804
|
+
violations_found_count=review.violations_found_count,
|
|
805
|
+
)
|
|
806
|
+
except Exception:
|
|
807
|
+
# FAIL-CLOSED on the emit only — an audit-emit failure must NEVER block
|
|
808
|
+
# or crash the Pair-Rail hook (ADR-005 never-blocks), and must NEVER
|
|
809
|
+
# launder unredacted text (we simply emit nothing on any error).
|
|
810
|
+
return
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
# ---------------------------------------------------------------------
|
|
814
|
+
# Consume side (PLAN-142) — structured-verdict primary signal (D3).
|
|
815
|
+
# ---------------------------------------------------------------------
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def _load_codex_adapter(): # type: ignore[no-untyped-def]
|
|
819
|
+
"""Resolve `_lib.adapters.codex` (the structured-verdict parser).
|
|
820
|
+
|
|
821
|
+
Same canonical-layout resolution as the other `_lib` loaders. Returns
|
|
822
|
+
the module or None (fail-OPEN — caller degrades to ADVISORY). NEVER
|
|
823
|
+
raises.
|
|
824
|
+
"""
|
|
825
|
+
try:
|
|
826
|
+
hooks_dir = Path(__file__).resolve().parent
|
|
827
|
+
if str(hooks_dir) not in sys.path:
|
|
828
|
+
sys.path.insert(0, str(hooks_dir))
|
|
829
|
+
from _lib.adapters import codex as _codex # type: ignore
|
|
830
|
+
return _codex
|
|
831
|
+
except Exception:
|
|
832
|
+
return None
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
# Mirror of `_lib.adapters.codex._VALID_VERDICTS` so the kernel can validate
|
|
836
|
+
# without re-importing a private name. These are verdict LABELS (the
|
|
837
|
+
# trust-boundary vocabulary the §3 grep gate KEEPS in the kernel), not CLI
|
|
838
|
+
# literals.
|
|
839
|
+
_VALID_VERDICTS_LOCAL: Tuple[str, ...] = ("PASS", "ADVISORY", "BLOCK")
|
|
840
|
+
|
|
841
|
+
|
|
842
|
+
def _consume_codex_review(redacted_review: str) -> Tuple[str, Optional[str]]:
|
|
843
|
+
"""Derive (verdict, secondary_patch_grammar) from a REDACTED review.
|
|
844
|
+
|
|
845
|
+
PRIMARY signal (D3): `parse_verdict_strict` — the verdict is accepted
|
|
846
|
+
ONLY from a structured, schema-validated object (verdict ∈
|
|
847
|
+
`_VALID_VERDICTS_LOCAL`). A forged free-text 'PASS' with no structured
|
|
848
|
+
object → ADVISORY (fail-CLOSED-to-ADVISORY per R-SEC-2 / ADR-106).
|
|
849
|
+
|
|
850
|
+
SECONDARY signal (D3): `_detect_write_shaped_patch` runs on the SAME
|
|
851
|
+
redacted text as defense-in-depth annotation ONLY — it never upgrades a
|
|
852
|
+
verdict to a hard block; the structured verdict is authoritative.
|
|
853
|
+
|
|
854
|
+
Returns (verdict, patch_grammar) where verdict ∈ {"PASS","ADVISORY",
|
|
855
|
+
"BLOCK"} and patch_grammar is the `_detect_write_shaped_patch` tag (or
|
|
856
|
+
None). NEVER raises.
|
|
857
|
+
"""
|
|
858
|
+
# Secondary defense-in-depth scan (advisory annotation only).
|
|
859
|
+
try:
|
|
860
|
+
patch_grammar = _detect_write_shaped_patch(redacted_review)
|
|
861
|
+
except Exception:
|
|
862
|
+
patch_grammar = None
|
|
863
|
+
|
|
864
|
+
codex = _load_codex_adapter()
|
|
865
|
+
if codex is None:
|
|
866
|
+
# Adapter unimportable — fail-CLOSED-to-ADVISORY (cannot validate a
|
|
867
|
+
# structured verdict, so we do not trust one).
|
|
868
|
+
return "ADVISORY", patch_grammar
|
|
869
|
+
|
|
870
|
+
# parse_verdict_strict is fail-CLOSED-to-ADVISORY and never raises, but
|
|
871
|
+
# wrap defensively anyway and coerce any surprise to ADVISORY. We do NOT
|
|
872
|
+
# fall back to the free-text patch scan as the verdict — it stays SECONDARY.
|
|
873
|
+
try:
|
|
874
|
+
envelope = codex.parse_verdict_strict(redacted_review)
|
|
875
|
+
verdict = envelope.get("verdict")
|
|
876
|
+
if verdict not in _VALID_VERDICTS_LOCAL:
|
|
877
|
+
return "ADVISORY", patch_grammar
|
|
878
|
+
return str(verdict), patch_grammar
|
|
879
|
+
except Exception:
|
|
880
|
+
return "ADVISORY", patch_grammar
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
# ---------------------------------------------------------------------
|
|
884
|
+
# Decision logic — pure function, easy to test.
|
|
885
|
+
# ---------------------------------------------------------------------
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
def _decide(
|
|
889
|
+
*,
|
|
890
|
+
tool_name: str,
|
|
891
|
+
file_path: str,
|
|
892
|
+
proposed_content: str,
|
|
893
|
+
repo_root: Path,
|
|
894
|
+
timeout_s: float,
|
|
895
|
+
) -> Dict[str, Any]:
|
|
896
|
+
"""Pure decision returning a JSON-shape dict.
|
|
897
|
+
|
|
898
|
+
Returns:
|
|
899
|
+
Dict with keys `decision` (allow|block) and optionally
|
|
900
|
+
`reason` (block) or `systemMessage` (allow with note).
|
|
901
|
+
"""
|
|
902
|
+
# Kill-switch.
|
|
903
|
+
if os.environ.get("CEO_PAIR_RAIL_DISABLE", "").strip() == "1":
|
|
904
|
+
_emit_audit(
|
|
905
|
+
_AUDIT_KILL_SWITCH,
|
|
906
|
+
tool_name=tool_name, file_path=file_path,
|
|
907
|
+
)
|
|
908
|
+
return {} # schema-compliant allow (Claude Code hook schema rejects top-level "allow")
|
|
909
|
+
|
|
910
|
+
# Out-of-scope: tool not in write set.
|
|
911
|
+
write_tools = {"Edit", "Write", "MultiEdit", "NotebookEdit"}
|
|
912
|
+
if tool_name not in write_tools:
|
|
913
|
+
_emit_audit(
|
|
914
|
+
_AUDIT_OUT_OF_SCOPE,
|
|
915
|
+
tool_name=tool_name, reason="non_write_tool",
|
|
916
|
+
)
|
|
917
|
+
return {} # schema-compliant allow (Claude Code hook schema rejects top-level "allow")
|
|
918
|
+
|
|
919
|
+
# Out-of-scope: path not L3+.
|
|
920
|
+
if not _is_l3_plus_path(file_path, repo_root):
|
|
921
|
+
_emit_audit(
|
|
922
|
+
_AUDIT_OUT_OF_SCOPE,
|
|
923
|
+
tool_name=tool_name, file_path=file_path,
|
|
924
|
+
reason="not_l3_plus",
|
|
925
|
+
)
|
|
926
|
+
return {} # schema-compliant allow (Claude Code hook schema rejects top-level "allow")
|
|
927
|
+
|
|
928
|
+
# Sentinel bypass — Owner-signed approval covers this path.
|
|
929
|
+
if _sentinel_grants_pair_rail_bypass(file_path, repo_root):
|
|
930
|
+
_emit_audit(
|
|
931
|
+
_AUDIT_SENTINEL_BYPASS,
|
|
932
|
+
tool_name=tool_name, file_path=file_path,
|
|
933
|
+
)
|
|
934
|
+
return {
|
|
935
|
+
"systemMessage": (
|
|
936
|
+
f"PAIR-RAIL: bypass via Architect sentinel "
|
|
937
|
+
f"({file_path})"
|
|
938
|
+
),
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
# Invoke Codex review. `_invoke_codex_review` now returns the REDACTED
|
|
942
|
+
# last-message content (one structured JSON object).
|
|
943
|
+
try:
|
|
944
|
+
redacted_review = _invoke_codex_review(
|
|
945
|
+
tool_name=tool_name,
|
|
946
|
+
file_path=file_path,
|
|
947
|
+
proposed_content=proposed_content,
|
|
948
|
+
timeout_s=timeout_s,
|
|
949
|
+
)
|
|
950
|
+
except CodexUnavailable as e:
|
|
951
|
+
_emit_audit(
|
|
952
|
+
_AUDIT_CODEX_UNAVAILABLE,
|
|
953
|
+
tool_name=tool_name, file_path=file_path,
|
|
954
|
+
error=str(e),
|
|
955
|
+
)
|
|
956
|
+
# Substring "Codex unavailable" PRESERVED for _base_to_verdicts.
|
|
957
|
+
return {
|
|
958
|
+
"systemMessage": (
|
|
959
|
+
f"PAIR-RAIL: Codex unavailable ({e}); fail-OPEN "
|
|
960
|
+
"advisory mode."
|
|
961
|
+
),
|
|
962
|
+
}
|
|
963
|
+
except CodexTimeout as e:
|
|
964
|
+
_emit_audit(
|
|
965
|
+
_AUDIT_CODEX_UNAVAILABLE,
|
|
966
|
+
tool_name=tool_name, file_path=file_path,
|
|
967
|
+
error=f"timeout:{e}",
|
|
968
|
+
)
|
|
969
|
+
# Substring "Codex timeout" PRESERVED for _base_to_verdicts.
|
|
970
|
+
return {
|
|
971
|
+
"systemMessage": (
|
|
972
|
+
f"PAIR-RAIL: Codex timeout ({e}); fail-OPEN."
|
|
973
|
+
),
|
|
974
|
+
}
|
|
975
|
+
except CodexMalformed as e:
|
|
976
|
+
_emit_audit(
|
|
977
|
+
_AUDIT_CODEX_UNAVAILABLE,
|
|
978
|
+
tool_name=tool_name, file_path=file_path,
|
|
979
|
+
error=f"malformed:{e}",
|
|
980
|
+
)
|
|
981
|
+
# Substring "Codex malformed" PRESERVED for _base_to_verdicts.
|
|
982
|
+
return {
|
|
983
|
+
"systemMessage": (
|
|
984
|
+
f"PAIR-RAIL: Codex malformed response ({e}); "
|
|
985
|
+
"fail-OPEN."
|
|
986
|
+
),
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
# PRIMARY: structured verdict (parse_verdict_strict, fail-CLOSED-to-
|
|
990
|
+
# ADVISORY). SECONDARY: _detect_write_shaped_patch annotation (D3).
|
|
991
|
+
verdict, patch_grammar = _consume_codex_review(redacted_review)
|
|
992
|
+
|
|
993
|
+
# PLAN-122 WS3 — record the completed Codex review (any verdict) as
|
|
994
|
+
# codex_review_invoked (advisory; redacted PhaseReview; never blocks).
|
|
995
|
+
# `grammar` keeps its historical meaning (write-shape tag). PLAN-142 V2
|
|
996
|
+
# cross-model fold: a structured BLOCK with prose-only findings (no
|
|
997
|
+
# write-shaped patch) has patch_grammar=None, which the WS3 driver would
|
|
998
|
+
# otherwise map to 'accept' — under-reporting BLOCKs. Pass a synthetic
|
|
999
|
+
# block tag so the telemetry agrees with the PRIMARY structured verdict.
|
|
1000
|
+
_emit_codex_review_invoked(
|
|
1001
|
+
redacted_review,
|
|
1002
|
+
patch_grammar or ("structured_block" if verdict == "BLOCK" else None),
|
|
1003
|
+
)
|
|
1004
|
+
|
|
1005
|
+
if verdict == "BLOCK":
|
|
1006
|
+
# Structured BLOCK from a schema-validated object. Per PLAN-092 /
|
|
1007
|
+
# ADR-127 SHADOW-strip the rail stays ADVISORY-ONLY at the
|
|
1008
|
+
# user-facing surface (no top-level block); the matrix wrapper owns
|
|
1009
|
+
# any block promotion via Case-B preconditions. The "PAIR-RAIL-
|
|
1010
|
+
# ADVISORY" + "write-shaped" substrings are PRESERVED so
|
|
1011
|
+
# _base_to_verdicts classifies this as Case B (codex_verdict=BLOCK).
|
|
1012
|
+
_emit_audit(
|
|
1013
|
+
_AUDIT_CODEX_VIOLATION,
|
|
1014
|
+
tool_name=tool_name, file_path=file_path,
|
|
1015
|
+
verdict="BLOCK",
|
|
1016
|
+
grammar=(patch_grammar or ""),
|
|
1017
|
+
response_len=len(redacted_review),
|
|
1018
|
+
)
|
|
1019
|
+
return {
|
|
1020
|
+
"systemMessage": (
|
|
1021
|
+
"PAIR-RAIL-ADVISORY: Codex returned a structured BLOCK "
|
|
1022
|
+
"verdict (advisory-only per ADR-127). A write-shaped "
|
|
1023
|
+
f"secondary signal ({patch_grammar or 'none'}) was "
|
|
1024
|
+
f"{'also ' if patch_grammar else 'not '}detected. See "
|
|
1025
|
+
"routing-matrix.md §threat-model."
|
|
1026
|
+
),
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
if patch_grammar is not None and verdict != "BLOCK":
|
|
1030
|
+
# Defense-in-depth ONLY: a write-shaped patch under a non-BLOCK
|
|
1031
|
+
# structured verdict. The structured verdict is authoritative (D3),
|
|
1032
|
+
# so we do NOT block; surface an advisory note + emit the violation
|
|
1033
|
+
# audit for forensic continuity. "PAIR-RAIL-ADVISORY" + "write-shaped"
|
|
1034
|
+
# keep the matrix Case-B classification stable.
|
|
1035
|
+
_emit_audit(
|
|
1036
|
+
_AUDIT_CODEX_VIOLATION,
|
|
1037
|
+
tool_name=tool_name, file_path=file_path,
|
|
1038
|
+
verdict=verdict,
|
|
1039
|
+
grammar=patch_grammar,
|
|
1040
|
+
response_len=len(redacted_review),
|
|
1041
|
+
note="secondary_writeshape_under_nonblock_verdict",
|
|
1042
|
+
)
|
|
1043
|
+
return {
|
|
1044
|
+
"systemMessage": (
|
|
1045
|
+
"PAIR-RAIL-ADVISORY: secondary defense-in-depth detected a "
|
|
1046
|
+
f"write-shaped patch ({patch_grammar}) under a non-BLOCK "
|
|
1047
|
+
f"structured verdict ({verdict}); advisory-only per ADR-127 "
|
|
1048
|
+
"+ D3 (structured verdict is authoritative)."
|
|
1049
|
+
),
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
if verdict == "ADVISORY":
|
|
1053
|
+
# Parse miss / forged free-text / oversize / adapter-missing →
|
|
1054
|
+
# ADVISORY (fail-open). No "review clean" substring (NOT a clean
|
|
1055
|
+
# pass); no matrix Case-A.
|
|
1056
|
+
_emit_audit(
|
|
1057
|
+
_AUDIT_REVIEW_PASSED,
|
|
1058
|
+
tool_name=tool_name, file_path=file_path,
|
|
1059
|
+
verdict="ADVISORY",
|
|
1060
|
+
response_len=len(redacted_review),
|
|
1061
|
+
)
|
|
1062
|
+
return {
|
|
1063
|
+
"systemMessage": (
|
|
1064
|
+
"PAIR-RAIL: Codex verdict ADVISORY (no structured PASS/BLOCK "
|
|
1065
|
+
"parsed); fail-OPEN advisory mode."
|
|
1066
|
+
),
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
# verdict == "PASS" — structured clean review. "review clean" substring
|
|
1070
|
+
# PRESERVED for _base_to_verdicts Case-A classification.
|
|
1071
|
+
_emit_audit(
|
|
1072
|
+
_AUDIT_REVIEW_PASSED,
|
|
1073
|
+
tool_name=tool_name, file_path=file_path,
|
|
1074
|
+
verdict="PASS",
|
|
1075
|
+
response_len=len(redacted_review),
|
|
1076
|
+
)
|
|
1077
|
+
return {
|
|
1078
|
+
"systemMessage": "PAIR-RAIL: Codex review clean (structured PASS verdict).",
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
# ---------------------------------------------------------------------
|
|
1083
|
+
# Hook entry point. Reads PreToolUse JSON envelope from stdin per
|
|
1084
|
+
# SPEC/v1/hook-io.schema.md L14.
|
|
1085
|
+
# ---------------------------------------------------------------------
|
|
1086
|
+
|
|
1087
|
+
|
|
1088
|
+
def _read_event_from_stdin() -> Optional[Dict[str, Any]]:
|
|
1089
|
+
"""Parse PreToolUse JSON envelope. Returns None on parse failure."""
|
|
1090
|
+
try:
|
|
1091
|
+
raw = sys.stdin.read()
|
|
1092
|
+
except Exception:
|
|
1093
|
+
return None
|
|
1094
|
+
if not raw:
|
|
1095
|
+
return None
|
|
1096
|
+
try:
|
|
1097
|
+
return json.loads(raw)
|
|
1098
|
+
except (ValueError, TypeError):
|
|
1099
|
+
return None
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
def _extract_proposed_content(tool_input: Dict[str, Any]) -> str:
|
|
1103
|
+
"""Pull the proposed-write content from tool_input.
|
|
1104
|
+
|
|
1105
|
+
Edit → `new_string`
|
|
1106
|
+
Write → `content`
|
|
1107
|
+
MultiEdit → concatenation of all `new_string` values
|
|
1108
|
+
NotebookEdit → `new_source`
|
|
1109
|
+
Fallback → empty string (Codex review still proceeds with path-only context).
|
|
1110
|
+
"""
|
|
1111
|
+
if not isinstance(tool_input, dict):
|
|
1112
|
+
return ""
|
|
1113
|
+
if "content" in tool_input and isinstance(tool_input["content"], str):
|
|
1114
|
+
return tool_input["content"]
|
|
1115
|
+
if "new_string" in tool_input and isinstance(tool_input["new_string"], str):
|
|
1116
|
+
return tool_input["new_string"]
|
|
1117
|
+
if "new_source" in tool_input and isinstance(tool_input["new_source"], str):
|
|
1118
|
+
return tool_input["new_source"]
|
|
1119
|
+
edits = tool_input.get("edits")
|
|
1120
|
+
if isinstance(edits, list):
|
|
1121
|
+
chunks: List[str] = []
|
|
1122
|
+
for e in edits:
|
|
1123
|
+
if isinstance(e, dict) and isinstance(e.get("new_string"), str):
|
|
1124
|
+
chunks.append(e["new_string"])
|
|
1125
|
+
if chunks:
|
|
1126
|
+
return "\n".join(chunks)
|
|
1127
|
+
return ""
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
def main() -> int:
|
|
1131
|
+
"""Hook entry point — fail-OPEN on any uncaught exception."""
|
|
1132
|
+
try:
|
|
1133
|
+
event = _read_event_from_stdin()
|
|
1134
|
+
if event is None:
|
|
1135
|
+
sys.stdout.write(json.dumps({}) + "\n") # schema-compliant allow
|
|
1136
|
+
return 0
|
|
1137
|
+
tool_name = str(event.get("tool_name") or "")
|
|
1138
|
+
tool_input = event.get("tool_input") or {}
|
|
1139
|
+
if not isinstance(tool_input, dict):
|
|
1140
|
+
tool_input = {}
|
|
1141
|
+
file_path = str(tool_input.get("file_path") or "")
|
|
1142
|
+
proposed = _extract_proposed_content(tool_input)
|
|
1143
|
+
repo_root = Path(
|
|
1144
|
+
os.environ.get("CLAUDE_PROJECT_DIR") or os.getcwd()
|
|
1145
|
+
)
|
|
1146
|
+
try:
|
|
1147
|
+
timeout_s = float(
|
|
1148
|
+
os.environ.get("CEO_PAIR_RAIL_TIMEOUT_S", "30")
|
|
1149
|
+
)
|
|
1150
|
+
except (TypeError, ValueError):
|
|
1151
|
+
timeout_s = 30.0
|
|
1152
|
+
if timeout_s <= 0 or timeout_s > 600:
|
|
1153
|
+
timeout_s = 30.0
|
|
1154
|
+
|
|
1155
|
+
# PLAN-081 Phase 3: route through the asymmetric VETO matrix
|
|
1156
|
+
# wrapper instead of the spike _decide() directly. The matrix
|
|
1157
|
+
# wrapper invokes _decide() internally + applies Cases A-F per
|
|
1158
|
+
# spec.md §11 + emits pair_rail_case per evaluation.
|
|
1159
|
+
decision = _decide_with_matrix(
|
|
1160
|
+
tool_name=tool_name,
|
|
1161
|
+
file_path=file_path,
|
|
1162
|
+
proposed_content=proposed,
|
|
1163
|
+
repo_root=repo_root,
|
|
1164
|
+
timeout_s=timeout_s,
|
|
1165
|
+
)
|
|
1166
|
+
sys.stdout.write(json.dumps(decision, ensure_ascii=False) + "\n")
|
|
1167
|
+
return 0
|
|
1168
|
+
except Exception as e:
|
|
1169
|
+
# Fail-OPEN — never block the user on hook bug. U10 contract:
|
|
1170
|
+
# emit a structured breadcrumb so SPIKE-VERDICT.md can audit the
|
|
1171
|
+
# rate of catch-all firings (a high rate = a real bug masked by
|
|
1172
|
+
# fail-open, not a healthy contract). The stderr write is kept
|
|
1173
|
+
# for human visibility during the spike.
|
|
1174
|
+
try:
|
|
1175
|
+
# Codex MCP review F3 — keep the 240-char preview AND emit
|
|
1176
|
+
# stable `error_type` + `error_len` fields so SPIKE-VERDICT.md
|
|
1177
|
+
# sampling can group by exception class without parsing the
|
|
1178
|
+
# truncated preview.
|
|
1179
|
+
err_type = type(e).__name__
|
|
1180
|
+
err_str = str(e)
|
|
1181
|
+
_emit_audit(
|
|
1182
|
+
_AUDIT_FATAL_FAILOPEN,
|
|
1183
|
+
error_type=err_type,
|
|
1184
|
+
error_len=len(err_str),
|
|
1185
|
+
error=f"{err_type}: {err_str}"[:240],
|
|
1186
|
+
)
|
|
1187
|
+
except Exception:
|
|
1188
|
+
pass
|
|
1189
|
+
try:
|
|
1190
|
+
sys.stderr.write(
|
|
1191
|
+
f"[check_pair_rail SPIKE] FATAL: {type(e).__name__}: {e}\n"
|
|
1192
|
+
)
|
|
1193
|
+
except Exception:
|
|
1194
|
+
pass
|
|
1195
|
+
sys.stdout.write(json.dumps({}) + "\n") # schema-compliant allow
|
|
1196
|
+
return 0
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
# Codex iter 1 P0-1 fix: original `if __name__ == "__main__"` block moved
|
|
1200
|
+
# to the END of this file (line ~1180) so the Phase 3 helper functions
|
|
1201
|
+
# defined below are available when ``main()`` runs. Runtime import order:
|
|
1202
|
+
# Python parses + defines all module-level symbols top-to-bottom, then
|
|
1203
|
+
# the `if __name__` guard at the bottom triggers `main()` — which
|
|
1204
|
+
# references `_decide_with_matrix` (defined further down). Without this
|
|
1205
|
+
# move, `main()` would NameError at runtime since the helper was not
|
|
1206
|
+
# yet defined when the original guard fired.
|
|
1207
|
+
|
|
1208
|
+
|
|
1209
|
+
# =====================================================================
|
|
1210
|
+
# PLAN-081 Phase 3 — Asymmetric VETO matrix Cases A-F + rubric catalogue
|
|
1211
|
+
# + Case-B precondition validation + audit emit.
|
|
1212
|
+
#
|
|
1213
|
+
# Layered onto the spike _decide() (which handles review-only Phase 1
|
|
1214
|
+
# semantics: write-shape detection + fail-OPEN). The Phase 3 wrapper
|
|
1215
|
+
# `_decide_with_matrix()` invokes the spike _decide() to get an initial
|
|
1216
|
+
# verdict, then applies the asymmetric matrix per spec.md §11:
|
|
1217
|
+
#
|
|
1218
|
+
# Case A: claude=PASS + codex=PASS → dispatch
|
|
1219
|
+
# Case B: claude=PASS + codex=BLOCK with preconditions met → block
|
|
1220
|
+
# (preconditions: file:line + rubric_violation_id catalogue
|
|
1221
|
+
# + severity ∈ {P0, P1})
|
|
1222
|
+
# Case B': claude=PASS + codex=BLOCK without preconditions → fail-OPEN
|
|
1223
|
+
# advisory (per ADR-106 + R1 spec.md auto-Round-2 path)
|
|
1224
|
+
# Case C: claude=BLOCK + codex=PASS → not reachable at PreToolUse
|
|
1225
|
+
# (Claude already passed to invoke this hook); recorded for
|
|
1226
|
+
# Phase 4 corpus-replay parity.
|
|
1227
|
+
# Case D: claude=BLOCK + codex=BLOCK → not reachable at PreToolUse;
|
|
1228
|
+
# recorded for Phase 4 corpus-replay parity.
|
|
1229
|
+
# Case E: divergent (Jaccard similarity ≤ 0.3) → flag for human
|
|
1230
|
+
# review; allow with systemMessage warning.
|
|
1231
|
+
# Case F: timeout / outage / malformed → fail-OPEN per ADR-106.
|
|
1232
|
+
#
|
|
1233
|
+
# 24h human-triage grace per R1 S-TDE-4: severity P1 with grace remaining
|
|
1234
|
+
# closes-as-advisory after T+24h (env CEO_PAIR_RAIL_HUMAN_TRIAGE_HOURS).
|
|
1235
|
+
# =====================================================================
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
_RUBRIC_CATALOGUE_CACHE: Optional[Dict[str, Dict[str, Any]]] = None
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
def _load_rubric_catalogue(repo_root: Path) -> Dict[str, Dict[str, Any]]:
|
|
1242
|
+
"""Load + cache the rubric violation catalogue.
|
|
1243
|
+
|
|
1244
|
+
Returns an empty dict if the catalogue cannot be loaded (fail-OPEN —
|
|
1245
|
+
Phase 3 hook MUST NOT block on missing catalogue; it just downgrades
|
|
1246
|
+
Case-B to advisory because the rubric_violation_id can never be
|
|
1247
|
+
validated against an empty catalogue).
|
|
1248
|
+
"""
|
|
1249
|
+
global _RUBRIC_CATALOGUE_CACHE
|
|
1250
|
+
if _RUBRIC_CATALOGUE_CACHE is not None:
|
|
1251
|
+
return _RUBRIC_CATALOGUE_CACHE
|
|
1252
|
+
catalogue_path = (
|
|
1253
|
+
repo_root / ".claude" / "policies" / "rubric-violation-catalogue.yaml"
|
|
1254
|
+
)
|
|
1255
|
+
if not catalogue_path.exists():
|
|
1256
|
+
_RUBRIC_CATALOGUE_CACHE = {}
|
|
1257
|
+
return _RUBRIC_CATALOGUE_CACHE
|
|
1258
|
+
try:
|
|
1259
|
+
text = catalogue_path.read_text(encoding="utf-8")
|
|
1260
|
+
# Inline minimal YAML parse for the `violations:` section.
|
|
1261
|
+
# Matches the routing-matrix-loader pattern (stdlib only).
|
|
1262
|
+
catalogue: Dict[str, Dict[str, Any]] = {}
|
|
1263
|
+
in_violations = False
|
|
1264
|
+
current: Optional[Dict[str, Any]] = None
|
|
1265
|
+
for raw_line in text.splitlines():
|
|
1266
|
+
line = raw_line.split("#", 1)[0].rstrip() if "#" in raw_line else raw_line.rstrip()
|
|
1267
|
+
if not line.strip():
|
|
1268
|
+
continue
|
|
1269
|
+
if line.startswith("violations:"):
|
|
1270
|
+
in_violations = True
|
|
1271
|
+
continue
|
|
1272
|
+
if not in_violations:
|
|
1273
|
+
continue
|
|
1274
|
+
# Detect new entry: ' - id: <slug>' at 2-space indent
|
|
1275
|
+
stripped = line.lstrip()
|
|
1276
|
+
indent = len(line) - len(stripped)
|
|
1277
|
+
if indent == 2 and stripped.startswith("- id:"):
|
|
1278
|
+
if current is not None and "id" in current:
|
|
1279
|
+
catalogue[current["id"]] = current
|
|
1280
|
+
current = {}
|
|
1281
|
+
_, _, val = stripped.partition(":")
|
|
1282
|
+
current["id"] = val.strip()
|
|
1283
|
+
elif indent == 4 and current is not None and ":" in stripped:
|
|
1284
|
+
key, _, val = stripped.partition(":")
|
|
1285
|
+
current[key.strip()] = val.strip()
|
|
1286
|
+
elif indent < 2 and current is not None and "id" in current:
|
|
1287
|
+
# Section ended
|
|
1288
|
+
catalogue[current["id"]] = current
|
|
1289
|
+
current = None
|
|
1290
|
+
in_violations = False
|
|
1291
|
+
if current is not None and "id" in current:
|
|
1292
|
+
catalogue[current["id"]] = current
|
|
1293
|
+
_RUBRIC_CATALOGUE_CACHE = catalogue
|
|
1294
|
+
return catalogue
|
|
1295
|
+
except Exception:
|
|
1296
|
+
_RUBRIC_CATALOGUE_CACHE = {}
|
|
1297
|
+
return _RUBRIC_CATALOGUE_CACHE
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
def _validate_provider_pair(
|
|
1301
|
+
*,
|
|
1302
|
+
codex_verdict: str,
|
|
1303
|
+
rubric_violation_id: str,
|
|
1304
|
+
severity: str,
|
|
1305
|
+
file_line_cited: bool,
|
|
1306
|
+
repo_root: Path,
|
|
1307
|
+
) -> Tuple[bool, str]:
|
|
1308
|
+
"""Validate Case-B preconditions per spec.md §11.
|
|
1309
|
+
|
|
1310
|
+
A Case-B verdict from Codex (BLOCK with PASS from Claude) must carry:
|
|
1311
|
+
- reproducible evidence (file:line OR command cited)
|
|
1312
|
+
- rubric_violation_id ∈ rubric-violation-catalogue.yaml
|
|
1313
|
+
- severity ∈ {P0, P1}
|
|
1314
|
+
|
|
1315
|
+
R1 S-CR-1 codifies: this function is a greenfield helper (NOT
|
|
1316
|
+
preserving any prior provider-pair grandfather entry). ADR-097 was
|
|
1317
|
+
"Function-length advisory-permanent + 344-function grandfather list"
|
|
1318
|
+
— NO LLM/dispatcher/pair-rail content per `head -1` audit.
|
|
1319
|
+
|
|
1320
|
+
Returns:
|
|
1321
|
+
(preconditions_met: bool, reason: str). Reason is "ok" when met;
|
|
1322
|
+
otherwise a slug naming the specific precondition that failed
|
|
1323
|
+
(downstream audit emit + reason_code).
|
|
1324
|
+
"""
|
|
1325
|
+
if codex_verdict != "BLOCK":
|
|
1326
|
+
# Not a Case-B candidate — vacuously "met" for the dispatcher
|
|
1327
|
+
return True, "not_case_b"
|
|
1328
|
+
if not file_line_cited:
|
|
1329
|
+
return False, "missing_file_line"
|
|
1330
|
+
if not rubric_violation_id or len(rubric_violation_id) > 64:
|
|
1331
|
+
return False, "missing_or_invalid_rubric_id"
|
|
1332
|
+
catalogue = _load_rubric_catalogue(repo_root)
|
|
1333
|
+
if not catalogue:
|
|
1334
|
+
return False, "catalogue_not_loaded"
|
|
1335
|
+
if rubric_violation_id not in catalogue:
|
|
1336
|
+
return False, "rubric_id_not_in_catalogue"
|
|
1337
|
+
if severity not in ("P0", "P1"):
|
|
1338
|
+
return False, "invalid_severity"
|
|
1339
|
+
return True, "ok"
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
def _compute_jaccard_bucket(claude_findings: List[str], codex_findings: List[str]) -> str:
|
|
1343
|
+
"""Bucket the Jaccard similarity for Case-E divergence detection.
|
|
1344
|
+
|
|
1345
|
+
Phase 3 uses bucketed similarity (NEVER raw float) per Sec MF-3
|
|
1346
|
+
`_PAIR_RAIL_CASE_EMIT_ALLOWLIST` (raw float would leak prompt
|
|
1347
|
+
content / response content via correlated audit-log readout).
|
|
1348
|
+
|
|
1349
|
+
Buckets per spec.md §11 R1.5-4 fix:
|
|
1350
|
+
- "<=0.3" → low similarity = high divergence → Case-E flag
|
|
1351
|
+
- "0.3-0.5"
|
|
1352
|
+
- "0.5-0.8"
|
|
1353
|
+
- ">0.8" → high similarity = aligned reviews
|
|
1354
|
+
"""
|
|
1355
|
+
if not claude_findings and not codex_findings:
|
|
1356
|
+
return ">0.8" # both empty = perfectly aligned
|
|
1357
|
+
set_c = {f.strip().lower() for f in claude_findings if f.strip()}
|
|
1358
|
+
set_x = {f.strip().lower() for f in codex_findings if f.strip()}
|
|
1359
|
+
if not set_c and not set_x:
|
|
1360
|
+
return ">0.8"
|
|
1361
|
+
inter = len(set_c & set_x)
|
|
1362
|
+
union = len(set_c | set_x)
|
|
1363
|
+
if union == 0:
|
|
1364
|
+
return ">0.8"
|
|
1365
|
+
sim = inter / union
|
|
1366
|
+
if sim <= 0.3:
|
|
1367
|
+
return "<=0.3"
|
|
1368
|
+
if sim <= 0.5:
|
|
1369
|
+
return "0.3-0.5"
|
|
1370
|
+
if sim <= 0.8:
|
|
1371
|
+
return "0.5-0.8"
|
|
1372
|
+
return ">0.8"
|
|
1373
|
+
|
|
1374
|
+
|
|
1375
|
+
def _hash_file_path_prefix(file_path: str) -> str:
|
|
1376
|
+
"""Compute 16-hex SHA-256 prefix of file path (LLM06 side-channel guard)."""
|
|
1377
|
+
import hashlib
|
|
1378
|
+
if not file_path:
|
|
1379
|
+
return ""
|
|
1380
|
+
return hashlib.sha256(file_path.encode("utf-8")).hexdigest()[:16]
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
def _resolve_human_triage_grace_h(severity: str) -> int:
|
|
1384
|
+
"""Return human-triage grace hours per R1 S-TDE-4.
|
|
1385
|
+
|
|
1386
|
+
P1 violations get a 24h grace window (env-overridable via
|
|
1387
|
+
CEO_PAIR_RAIL_HUMAN_TRIAGE_HOURS, clamped to [0, 24] per ADR-108
|
|
1388
|
+
+ Codex iter 1 P1-2). P0 = 0h (immediate block).
|
|
1389
|
+
Outside-of-grace P1 closes-as-advisory.
|
|
1390
|
+
|
|
1391
|
+
Codex iter 1 P1-2 fix: env override is clamped to ``min(value, 24)``
|
|
1392
|
+
so an Owner setting `CEO_PAIR_RAIL_HUMAN_TRIAGE_HOURS=1000` cannot
|
|
1393
|
+
extend the grace beyond the ADR-108-mandated 24h ceiling. Lower
|
|
1394
|
+
bound stays 0 (allows mechanical-immediate-close override).
|
|
1395
|
+
"""
|
|
1396
|
+
if severity != "P1":
|
|
1397
|
+
return 0
|
|
1398
|
+
raw = os.environ.get("CEO_PAIR_RAIL_HUMAN_TRIAGE_HOURS", "24")
|
|
1399
|
+
try:
|
|
1400
|
+
h = int(raw)
|
|
1401
|
+
# Clamp to [0, 24] per ADR-108 §Operational labeling protocol.
|
|
1402
|
+
return max(0, min(h, 24))
|
|
1403
|
+
except (TypeError, ValueError):
|
|
1404
|
+
return 24
|
|
1405
|
+
|
|
1406
|
+
|
|
1407
|
+
def _emit_pair_rail_case(
|
|
1408
|
+
*,
|
|
1409
|
+
case: str,
|
|
1410
|
+
claude_verdict: str,
|
|
1411
|
+
codex_verdict: str,
|
|
1412
|
+
tool_name: str,
|
|
1413
|
+
file_path: str,
|
|
1414
|
+
precondition_met: bool = False,
|
|
1415
|
+
rubric_violation_id: str = "",
|
|
1416
|
+
severity: str = "",
|
|
1417
|
+
jaccard_bucket: str = "",
|
|
1418
|
+
repo_root: Optional[Path] = None,
|
|
1419
|
+
) -> None:
|
|
1420
|
+
"""Best-effort audit emit of pair_rail_case. Fail-OPEN.
|
|
1421
|
+
|
|
1422
|
+
Import resolution order (first hit wins):
|
|
1423
|
+
|
|
1424
|
+
1. Test-only env override ``CEO_PAIR_RAIL_STAGED_AUDIT_EMIT_DIR``
|
|
1425
|
+
points at a directory containing ``_lib/audit_emit.py``. Used by
|
|
1426
|
+
the Phase 3 staging tests to load the staged audit_emit before
|
|
1427
|
+
the ceremony cp lands it canonical. Removed post-ceremony.
|
|
1428
|
+
2. Canonical layout: ``Path(__file__).resolve().parent`` (the
|
|
1429
|
+
canonical ``.claude/hooks/`` dir) contains ``_lib/audit_emit.py``.
|
|
1430
|
+
Standard production path post-ceremony.
|
|
1431
|
+
3. PYTHONPATH-discovered ``_lib.audit_emit`` (rare adopter
|
|
1432
|
+
scenario where the canonical hooks dir isn't this file's parent).
|
|
1433
|
+
|
|
1434
|
+
Any failure → return silently (fail-OPEN per ADR-106).
|
|
1435
|
+
"""
|
|
1436
|
+
_ae = None
|
|
1437
|
+
try:
|
|
1438
|
+
# Resolution 1: test-only staged-dir override.
|
|
1439
|
+
staged_dir = os.environ.get("CEO_PAIR_RAIL_STAGED_AUDIT_EMIT_DIR")
|
|
1440
|
+
if staged_dir:
|
|
1441
|
+
staged_path = Path(staged_dir)
|
|
1442
|
+
if staged_path.is_dir() and (staged_path / "_lib" / "audit_emit.py").exists():
|
|
1443
|
+
if str(staged_path) not in sys.path:
|
|
1444
|
+
sys.path.insert(0, str(staged_path))
|
|
1445
|
+
try:
|
|
1446
|
+
from _lib import audit_emit as _ae # type: ignore
|
|
1447
|
+
except Exception:
|
|
1448
|
+
_ae = None
|
|
1449
|
+
# Resolution 2: canonical layout.
|
|
1450
|
+
if _ae is None:
|
|
1451
|
+
hooks_dir = Path(__file__).resolve().parent
|
|
1452
|
+
if str(hooks_dir) not in sys.path:
|
|
1453
|
+
sys.path.insert(0, str(hooks_dir))
|
|
1454
|
+
try:
|
|
1455
|
+
from _lib import audit_emit as _ae # type: ignore # noqa: F811
|
|
1456
|
+
except Exception:
|
|
1457
|
+
_ae = None
|
|
1458
|
+
# Resolution 3: PYTHONPATH already configured.
|
|
1459
|
+
if _ae is None:
|
|
1460
|
+
try:
|
|
1461
|
+
from _lib import audit_emit as _ae # type: ignore # noqa: F811
|
|
1462
|
+
except Exception:
|
|
1463
|
+
_ae = None
|
|
1464
|
+
# Defense-in-depth: ALSO breadcrumb to CEO_PAIR_RAIL_AUDIT_SINK
|
|
1465
|
+
# (the spike's per-test file sink). Used by Phase 3 matrix tests
|
|
1466
|
+
# to capture matrix decisions in the same JSONL surface as the
|
|
1467
|
+
# spike's `_emit_audit`. Production deployment relies on
|
|
1468
|
+
# audit_emit.emit_pair_rail_case being reachable; the sink
|
|
1469
|
+
# breadcrumb is a forensic continuity bridge for tests + adopters
|
|
1470
|
+
# without canonical audit-log writability.
|
|
1471
|
+
sink = os.environ.get("CEO_PAIR_RAIL_AUDIT_SINK")
|
|
1472
|
+
if sink:
|
|
1473
|
+
try:
|
|
1474
|
+
with open(sink, "a", encoding="utf-8") as f:
|
|
1475
|
+
f.write(json.dumps({
|
|
1476
|
+
"action": "pair_rail_case",
|
|
1477
|
+
"case": case,
|
|
1478
|
+
"claude_verdict": claude_verdict,
|
|
1479
|
+
"codex_verdict": codex_verdict,
|
|
1480
|
+
"tool_name": tool_name,
|
|
1481
|
+
"file_path_hash_prefix": _hash_file_path_prefix(file_path),
|
|
1482
|
+
"precondition_met": precondition_met,
|
|
1483
|
+
"rubric_violation_id": rubric_violation_id,
|
|
1484
|
+
"severity": severity,
|
|
1485
|
+
"jaccard_similarity_bucket": jaccard_bucket,
|
|
1486
|
+
"human_triage_grace_h": _resolve_human_triage_grace_h(severity),
|
|
1487
|
+
}, ensure_ascii=False) + "\n")
|
|
1488
|
+
except Exception:
|
|
1489
|
+
pass
|
|
1490
|
+
|
|
1491
|
+
if _ae is None or not hasattr(_ae, "emit_pair_rail_case"):
|
|
1492
|
+
return
|
|
1493
|
+
_ae.emit_pair_rail_case(
|
|
1494
|
+
case=case,
|
|
1495
|
+
claude_verdict=claude_verdict,
|
|
1496
|
+
codex_verdict=codex_verdict,
|
|
1497
|
+
tool_name=tool_name,
|
|
1498
|
+
file_path_hash_prefix=_hash_file_path_prefix(file_path),
|
|
1499
|
+
precondition_met=precondition_met,
|
|
1500
|
+
rubric_violation_id=rubric_violation_id,
|
|
1501
|
+
severity=severity,
|
|
1502
|
+
jaccard_similarity_bucket=jaccard_bucket,
|
|
1503
|
+
human_triage_grace_h=_resolve_human_triage_grace_h(severity),
|
|
1504
|
+
)
|
|
1505
|
+
except Exception:
|
|
1506
|
+
pass # fail-OPEN — never block on audit
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
def _load_pair_rail_decide(): # type: ignore[no-untyped-def]
|
|
1510
|
+
"""Resolve the canonical pure decision module `_lib.pair_rail_decide`.
|
|
1511
|
+
|
|
1512
|
+
Mirrors `_emit_pair_rail_case`'s Resolution-2 (canonical layout):
|
|
1513
|
+
the `.claude/hooks/` dir that houses this file also houses `_lib/`.
|
|
1514
|
+
Returns the module or None (fail-OPEN — caller must tolerate None).
|
|
1515
|
+
"""
|
|
1516
|
+
try:
|
|
1517
|
+
hooks_dir = Path(__file__).resolve().parent
|
|
1518
|
+
if str(hooks_dir) not in sys.path:
|
|
1519
|
+
sys.path.insert(0, str(hooks_dir))
|
|
1520
|
+
from _lib import pair_rail_decide as _prd # type: ignore
|
|
1521
|
+
return _prd
|
|
1522
|
+
except Exception:
|
|
1523
|
+
return None
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
def _base_to_verdicts(base: Dict[str, Any]) -> Tuple[str, str, str]:
|
|
1527
|
+
"""Translate the procedural `base` decision dict into the verdict
|
|
1528
|
+
triple `_lib.pair_rail_decide.detect_case()` consumes.
|
|
1529
|
+
|
|
1530
|
+
PLAN-112-FOLLOWUP-pair-rail-decide-canonical (W1). PURE + fail-OPEN:
|
|
1531
|
+
any malformed input yields the no-case tuple `("", "", "")` (which
|
|
1532
|
+
`detect_case()` maps to None → no matrix emit), never raises.
|
|
1533
|
+
|
|
1534
|
+
The substring contract is byte-identical to the LEGACY inline
|
|
1535
|
+
classification in `_decide_with_matrix` (verified against
|
|
1536
|
+
`_decide()` returns, source lines 595-679). Precedence MUST match
|
|
1537
|
+
the inline arm order: F (Codex fail) → B (write-shape/block) →
|
|
1538
|
+
A (review clean) → None (sentinel / kill-switch / out-of-scope).
|
|
1539
|
+
|
|
1540
|
+
Returns:
|
|
1541
|
+
(claude_verdict, codex_verdict, jaccard_bucket).
|
|
1542
|
+
claude_verdict is "PASS" for every reachable matrix case
|
|
1543
|
+
(Claude already passed to reach a PreToolUse write). Sentinel
|
|
1544
|
+
bypass + non-matrix short-circuits return ("", "", "").
|
|
1545
|
+
"""
|
|
1546
|
+
try:
|
|
1547
|
+
sysmsg = base.get("systemMessage", "")
|
|
1548
|
+
if not isinstance(sysmsg, str):
|
|
1549
|
+
sysmsg = ""
|
|
1550
|
+
decision = base.get("decision", "allow")
|
|
1551
|
+
# Arm 1 — Case F (Codex unavailable / timeout / malformed).
|
|
1552
|
+
if (
|
|
1553
|
+
"Codex unavailable" in sysmsg
|
|
1554
|
+
or "Codex timeout" in sysmsg
|
|
1555
|
+
or "Codex malformed" in sysmsg
|
|
1556
|
+
):
|
|
1557
|
+
sysmsg_lower = sysmsg.lower()
|
|
1558
|
+
if "malformed" in sysmsg_lower:
|
|
1559
|
+
return "PASS", "MALFORMED", ""
|
|
1560
|
+
# timeout AND unavailable both coerce to TIMEOUT (schema-
|
|
1561
|
+
# compatible; precise reason stays in base[systemMessage]).
|
|
1562
|
+
return "PASS", "TIMEOUT", ""
|
|
1563
|
+
# Arm 2 — sentinel bypass is NOT a matrix case (no verdicts).
|
|
1564
|
+
if "bypass via Architect sentinel" in sysmsg:
|
|
1565
|
+
return "", "", ""
|
|
1566
|
+
# Arm 3 — Case B (write-shape advisory OR legacy block path).
|
|
1567
|
+
is_advisory_writeshape = (
|
|
1568
|
+
"PAIR-RAIL-ADVISORY" in sysmsg and "write-shaped" in sysmsg
|
|
1569
|
+
)
|
|
1570
|
+
if decision == "block" or is_advisory_writeshape:
|
|
1571
|
+
return "PASS", "BLOCK", ""
|
|
1572
|
+
# Arm 4 — Case A (clean review).
|
|
1573
|
+
if "review clean" in sysmsg:
|
|
1574
|
+
return "PASS", "PASS", ""
|
|
1575
|
+
# Arm 5 — non-matrix short-circuit (kill-switch / out-of-scope).
|
|
1576
|
+
return "", "", ""
|
|
1577
|
+
except Exception:
|
|
1578
|
+
# Fail-OPEN: derivation error → no-case tuple (detect_case → None).
|
|
1579
|
+
return "", "", ""
|
|
1580
|
+
|
|
1581
|
+
|
|
1582
|
+
def _decide_with_matrix(
|
|
1583
|
+
*,
|
|
1584
|
+
tool_name: str,
|
|
1585
|
+
file_path: str,
|
|
1586
|
+
proposed_content: str,
|
|
1587
|
+
repo_root: Path,
|
|
1588
|
+
timeout_s: float,
|
|
1589
|
+
) -> Dict[str, Any]:
|
|
1590
|
+
"""Phase 3 asymmetric VETO matrix wrapper around `_decide()`.
|
|
1591
|
+
|
|
1592
|
+
Calls the canonical `_decide()` codepath to get the Phase 1 verdict
|
|
1593
|
+
(review-only semantics), then applies the Cases A-F matrix:
|
|
1594
|
+
|
|
1595
|
+
- canonical path returns ALLOW with no matrix-relevant signal → Case A
|
|
1596
|
+
- canonical path returns advisory write-shape (PLAN-092 Wave B
|
|
1597
|
+
SHADOW-strip per ADR-127) → validate Case-B preconditions:
|
|
1598
|
+
+ preconditions met → Case B (advisory + audit)
|
|
1599
|
+
+ preconditions NOT met → Case B' fail-OPEN (advisory)
|
|
1600
|
+
- canonical path returns ALLOW with `systemMessage` containing
|
|
1601
|
+
"Codex unavailable" / "timeout" / "malformed" → Case F (allow)
|
|
1602
|
+
- canonical path returns ALLOW with sentinel bypass → not a matrix case
|
|
1603
|
+
(already authorized by Owner sentinel)
|
|
1604
|
+
|
|
1605
|
+
Each matrix arm emits `pair_rail_case` with case + verdicts +
|
|
1606
|
+
preconditions + rubric metadata.
|
|
1607
|
+
|
|
1608
|
+
R1 S-Perf-3: matrix lookup uses O(1) dict (NOT linear scan); the
|
|
1609
|
+
``_MATRIX_DECISIONS`` table below dispatches in constant time.
|
|
1610
|
+
"""
|
|
1611
|
+
# Compute base decision via spike _decide()
|
|
1612
|
+
base = _decide(
|
|
1613
|
+
tool_name=tool_name,
|
|
1614
|
+
file_path=file_path,
|
|
1615
|
+
proposed_content=proposed_content,
|
|
1616
|
+
repo_root=repo_root,
|
|
1617
|
+
timeout_s=timeout_s,
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
sysmsg = base.get("systemMessage", "")
|
|
1621
|
+
|
|
1622
|
+
# PLAN-112-FOLLOWUP-pair-rail-decide-canonical (W2): delegate the
|
|
1623
|
+
# verdict→case CLASSIFICATION to the canonical pure module
|
|
1624
|
+
# `_lib.pair_rail_decide.detect_case()`. The procedural shell
|
|
1625
|
+
# (Codex invoke, patch detect — both inside `_decide()` above), the
|
|
1626
|
+
# B'/precondition resolution, and every audit emit STAY INLINE.
|
|
1627
|
+
# `evaluate()` is DELIBERATELY NOT called: it would convert a
|
|
1628
|
+
# precondition-unmet Case B into B' (pair_rail_decide.py:197-204),
|
|
1629
|
+
# diverging from production's byte-identical `case="B"` emit.
|
|
1630
|
+
#
|
|
1631
|
+
# Fail-OPEN: any error in verdict-derivation / classification / lib
|
|
1632
|
+
# import returns `base` (implicit allow), never raises.
|
|
1633
|
+
try:
|
|
1634
|
+
cv, xv, jb = _base_to_verdicts(base)
|
|
1635
|
+
_prd = _load_pair_rail_decide()
|
|
1636
|
+
matrix_case = (
|
|
1637
|
+
_prd.detect_case(claude_verdict=cv, codex_verdict=xv, jaccard_bucket=jb)
|
|
1638
|
+
if _prd is not None
|
|
1639
|
+
else None
|
|
1640
|
+
)
|
|
1641
|
+
except Exception:
|
|
1642
|
+
return base # fail-OPEN — never block the user on a classifier bug
|
|
1643
|
+
|
|
1644
|
+
if matrix_case is None:
|
|
1645
|
+
# Sentinel bypass / kill-switch / out-of-scope / non-matrix →
|
|
1646
|
+
# no case emit (byte-identical to the legacy fall-through arms).
|
|
1647
|
+
return base
|
|
1648
|
+
|
|
1649
|
+
case_value = getattr(matrix_case, "value", matrix_case)
|
|
1650
|
+
|
|
1651
|
+
if case_value == "F":
|
|
1652
|
+
# Case F — fail-OPEN. The codex_verdict sub-discrimination
|
|
1653
|
+
# (MALFORMED vs TIMEOUT, with UNAVAILABLE coercing to TIMEOUT)
|
|
1654
|
+
# is carried by `_base_to_verdicts()` in `xv`; emit it verbatim.
|
|
1655
|
+
_emit_pair_rail_case(
|
|
1656
|
+
case="F", claude_verdict="PASS", codex_verdict=xv,
|
|
1657
|
+
tool_name=tool_name, file_path=file_path,
|
|
1658
|
+
)
|
|
1659
|
+
return base
|
|
1660
|
+
|
|
1661
|
+
if case_value == "B":
|
|
1662
|
+
# Procedural Case-B audit emit (advisory-only per ADR-127).
|
|
1663
|
+
# B'/precondition resolution stays INLINE (NOT via evaluate()).
|
|
1664
|
+
# precondition_met reflects whether substantive rubric evidence
|
|
1665
|
+
# was attached (False at Phase 3; True at Phase 4 corpus-replay).
|
|
1666
|
+
preconditions_met, reason_slug = _validate_provider_pair(
|
|
1667
|
+
codex_verdict="BLOCK",
|
|
1668
|
+
rubric_violation_id="", # not extracted from procedural grammar
|
|
1669
|
+
severity="",
|
|
1670
|
+
file_line_cited=False,
|
|
1671
|
+
repo_root=repo_root,
|
|
1672
|
+
)
|
|
1673
|
+
_emit_pair_rail_case(
|
|
1674
|
+
case="B", claude_verdict="PASS", codex_verdict="BLOCK",
|
|
1675
|
+
tool_name=tool_name, file_path=file_path,
|
|
1676
|
+
precondition_met=preconditions_met,
|
|
1677
|
+
rubric_violation_id="",
|
|
1678
|
+
severity="P0", # write-shape violation defaulted P0 procedural
|
|
1679
|
+
)
|
|
1680
|
+
# Advisory-only return — `base` already carries the advisory
|
|
1681
|
+
# systemMessage (Site 1). No `decision` key — schema treats
|
|
1682
|
+
# absence as implicit allow.
|
|
1683
|
+
return base
|
|
1684
|
+
|
|
1685
|
+
if case_value == "A":
|
|
1686
|
+
_emit_pair_rail_case(
|
|
1687
|
+
case="A", claude_verdict="PASS", codex_verdict="PASS",
|
|
1688
|
+
tool_name=tool_name, file_path=file_path,
|
|
1689
|
+
)
|
|
1690
|
+
return base
|
|
1691
|
+
|
|
1692
|
+
# Defensive: any other detected case (C/D/E — confirmed unreachable
|
|
1693
|
+
# from the procedural `base`, plan §2a.2) → no emit, fail-OPEN allow.
|
|
1694
|
+
return base
|
|
1695
|
+
|
|
1696
|
+
|
|
1697
|
+
# Codex iter 1 P0-1 fix: __main__ guard moved to end-of-file so the
|
|
1698
|
+
# Phase 3 matrix helpers above are bound before main() executes.
|
|
1699
|
+
if __name__ == "__main__":
|
|
1700
|
+
sys.exit(main())
|