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,1887 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""context-budget.py — static context-inventory audit (advisory, never blocks).
|
|
3
|
+
|
|
4
|
+
PLAN-124 WS-4. Stdlib-only, loopback / read-only — like
|
|
5
|
+
``check-staleness.py`` and our other advisory scanners. This tool inventories
|
|
6
|
+
the **always-loaded / Gate-1 + skill surface** that we re-pay every session
|
|
7
|
+
(CLAUDE.md §0 cache discipline, ~44,786-token gate-boot cost) and produces:
|
|
8
|
+
|
|
9
|
+
* a per-category estimated-token table, and
|
|
10
|
+
* a top-N ranked list of reduction candidates (heaviest files / bloated
|
|
11
|
+
frontmatter / MCP over-subscription).
|
|
12
|
+
|
|
13
|
+
It harvests the **mechanism** from ECC's ``skills/context-budget/SKILL.md``
|
|
14
|
+
(token inventory + heavy-file flagging + top optimizations) re-implemented in
|
|
15
|
+
stdlib Python under our patterns. ECC is MIT; this is a re-implementation, not
|
|
16
|
+
a vendored copy.
|
|
17
|
+
|
|
18
|
+
## What is inventoried (categories)
|
|
19
|
+
|
|
20
|
+
| Category | Surface |
|
|
21
|
+
|-------------|----------------------------------------------------------|
|
|
22
|
+
| claude_md | ``CLAUDE.md`` |
|
|
23
|
+
| protocol | ``PROTOCOL.md`` |
|
|
24
|
+
| team | ``.claude/team.md`` + ``.claude/frontend-team.md`` |
|
|
25
|
+
| core_skill | ``.claude/skills/core/ceo-orchestration/SKILL.md`` |
|
|
26
|
+
| agents | ``.claude/agents/*.md`` |
|
|
27
|
+
| skills | ``.claude/skills/**/SKILL.md`` |
|
|
28
|
+
| commands | ``.claude/commands/*.md`` |
|
|
29
|
+
| mcp | MCP subscription surface (``.mcp.json`` / settings) |
|
|
30
|
+
|
|
31
|
+
## Heavy-file thresholds (from the ECC reference)
|
|
32
|
+
|
|
33
|
+
* agents > 200 lines
|
|
34
|
+
* skills > 400 lines
|
|
35
|
+
* rules/commands > 100 lines
|
|
36
|
+
* frontmatter ``description:`` > 200 chars (bloated description)
|
|
37
|
+
* MCP servers > 5 configured (over-subscription)
|
|
38
|
+
|
|
39
|
+
## Token estimate
|
|
40
|
+
|
|
41
|
+
Reuses the repo's documented chars/4 heuristic (see
|
|
42
|
+
``profile-opus-4-7.py:estimate_gate_boot_token_cost`` — "1 token ≈ 4 chars").
|
|
43
|
+
This is an **estimate** for monotonic diff tracking, NOT the Anthropic
|
|
44
|
+
tokenizer. Every report labels it as such.
|
|
45
|
+
|
|
46
|
+
## Usage
|
|
47
|
+
|
|
48
|
+
python3 .claude/scripts/context-budget.py
|
|
49
|
+
python3 .claude/scripts/context-budget.py --json
|
|
50
|
+
python3 .claude/scripts/context-budget.py --top 5
|
|
51
|
+
python3 .claude/scripts/context-budget.py --repo-root <path>
|
|
52
|
+
python3 .claude/scripts/context-budget.py --tool-loop-scan <audit-log.jsonl>
|
|
53
|
+
python3 .claude/scripts/context-budget.py --compact-decision \
|
|
54
|
+
--used-tokens 170000 --window-tokens 200000 # D1 auto-compaction probe
|
|
55
|
+
python3 .claude/scripts/context-budget.py --summarize-decision \
|
|
56
|
+
--output-sizes '[12000,800,30000,500]' # D2 summarize-oldest probe
|
|
57
|
+
python3 .claude/scripts/context-budget.py --middle-out-decision \
|
|
58
|
+
--message-sizes '[50000,800,50000,500]' \
|
|
59
|
+
--budget-tokens 60000 # D5 middle-out ladder probe
|
|
60
|
+
|
|
61
|
+
Exit code: always 0 (advisory) — never blocks a session, never writes outside
|
|
62
|
+
stdout. Use ``--strict`` to exit 1 when any heavy-file / over-subscription
|
|
63
|
+
flag fires (for an opt-in advisory CI lint).
|
|
64
|
+
|
|
65
|
+
## Stdlib-only
|
|
66
|
+
|
|
67
|
+
Filesystem walks + ``json`` for MCP config + a regex frontmatter parse. No
|
|
68
|
+
deps; never reads outside the given repo-root; never mutates anything.
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
from __future__ import annotations
|
|
72
|
+
|
|
73
|
+
import argparse
|
|
74
|
+
import json
|
|
75
|
+
import os
|
|
76
|
+
import re
|
|
77
|
+
import sys
|
|
78
|
+
from pathlib import Path
|
|
79
|
+
from typing import Any, Dict, List, Optional, Tuple
|
|
80
|
+
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
# Heuristic + thresholds
|
|
83
|
+
# ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
# Repo-canonical token estimate: 1 token ≈ 4 chars (English-Portuguese mix).
|
|
86
|
+
# Mirrors profile-opus-4-7.py. Estimate only; not the Anthropic tokenizer.
|
|
87
|
+
CHARS_PER_TOKEN = 4
|
|
88
|
+
|
|
89
|
+
# Heavy-file line thresholds (from the ECC context-budget reference).
|
|
90
|
+
THRESHOLD_AGENT_LINES = 200
|
|
91
|
+
THRESHOLD_SKILL_LINES = 400
|
|
92
|
+
THRESHOLD_RULE_LINES = 100 # commands / rules
|
|
93
|
+
# Bloated frontmatter `description:` length (chars).
|
|
94
|
+
THRESHOLD_DESCRIPTION_CHARS = 200
|
|
95
|
+
# MCP over-subscription: more than this many configured servers.
|
|
96
|
+
THRESHOLD_MCP_SERVERS = 5
|
|
97
|
+
|
|
98
|
+
# Category labels (stable keys for --json consumers).
|
|
99
|
+
CAT_CLAUDE_MD = "claude_md"
|
|
100
|
+
CAT_PROTOCOL = "protocol"
|
|
101
|
+
CAT_TEAM = "team"
|
|
102
|
+
CAT_CORE_SKILL = "core_skill"
|
|
103
|
+
CAT_AGENTS = "agents"
|
|
104
|
+
CAT_SKILLS = "skills"
|
|
105
|
+
CAT_COMMANDS = "commands"
|
|
106
|
+
CAT_MCP = "mcp"
|
|
107
|
+
|
|
108
|
+
_FRONTMATTER_RE = re.compile(r"^---\s*\n(.*?)\n---\s*\n", re.DOTALL)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# ---------------------------------------------------------------------------
|
|
112
|
+
# Primitives
|
|
113
|
+
# ---------------------------------------------------------------------------
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def estimate_tokens(char_count: int) -> int:
|
|
117
|
+
"""chars/4 token estimate (repo-canonical heuristic; estimate only)."""
|
|
118
|
+
if char_count <= 0:
|
|
119
|
+
return 0
|
|
120
|
+
return char_count // CHARS_PER_TOKEN
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _read_text(path: Path) -> Optional[str]:
|
|
124
|
+
"""Read a file as UTF-8; return None on any OS/decoding error.
|
|
125
|
+
|
|
126
|
+
Resilient by design — a missing or unreadable file MUST NOT crash an
|
|
127
|
+
advisory scan (fail-open, §5 doctrine).
|
|
128
|
+
"""
|
|
129
|
+
try:
|
|
130
|
+
return path.read_text(encoding="utf-8")
|
|
131
|
+
except (OSError, UnicodeDecodeError):
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _line_count(text: str) -> int:
|
|
136
|
+
if not text:
|
|
137
|
+
return 0
|
|
138
|
+
# Count lines without a spurious trailing-empty when file ends in \n.
|
|
139
|
+
n = text.count("\n")
|
|
140
|
+
if text and not text.endswith("\n"):
|
|
141
|
+
n += 1
|
|
142
|
+
return n
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# YAML block-scalar indicators that introduce a multi-line value on the
|
|
146
|
+
# following more-indented continuation lines (`description: >` etc.). An empty
|
|
147
|
+
# value after the colon is also treated as a possible block start so a plain
|
|
148
|
+
# `description:`\n text continuation is captured too.
|
|
149
|
+
_BLOCK_SCALAR_INDICATORS = frozenset({">", "|", ">-", "|-", ">+", "|+"})
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _key_indent(raw_line: str) -> int:
|
|
153
|
+
"""Leading-space indent width of a raw (un-stripped) frontmatter line."""
|
|
154
|
+
return len(raw_line) - len(raw_line.lstrip(" "))
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def parse_frontmatter(text: str) -> Dict[str, str]:
|
|
158
|
+
"""Parse a leading ``---`` YAML-ish frontmatter block into a flat dict.
|
|
159
|
+
|
|
160
|
+
Best-effort line-based parse (no YAML dep): ``key: value`` only, first
|
|
161
|
+
colon wins, ``#`` comment lines skipped. Mirrors check-staleness.py.
|
|
162
|
+
|
|
163
|
+
YAML folded/block scalars are handled: when a ``key:`` line has an empty
|
|
164
|
+
value OR a block indicator (``>``, ``|``, ``>-``, ``|-``, ``>+``, ``|+``),
|
|
165
|
+
the subsequent MORE-INDENTED continuation lines are consumed and
|
|
166
|
+
space-joined as the value. This is what lets ``bloated_description`` fire
|
|
167
|
+
on the ~49 real SKILL.md files that write ``description: >`` with the body
|
|
168
|
+
on following indented lines (otherwise the value reads as ``>``, len 1).
|
|
169
|
+
"""
|
|
170
|
+
if not text:
|
|
171
|
+
return {}
|
|
172
|
+
m = _FRONTMATTER_RE.match(text)
|
|
173
|
+
if not m:
|
|
174
|
+
return {}
|
|
175
|
+
result: Dict[str, str] = {}
|
|
176
|
+
raw_lines = m.group(1).splitlines()
|
|
177
|
+
i = 0
|
|
178
|
+
n = len(raw_lines)
|
|
179
|
+
while i < n:
|
|
180
|
+
raw = raw_lines[i]
|
|
181
|
+
s = raw.strip()
|
|
182
|
+
if not s or s.startswith("#"):
|
|
183
|
+
i += 1
|
|
184
|
+
continue
|
|
185
|
+
if ":" not in s:
|
|
186
|
+
i += 1
|
|
187
|
+
continue
|
|
188
|
+
k, _, v = s.partition(":")
|
|
189
|
+
key = k.strip()
|
|
190
|
+
value = v.strip()
|
|
191
|
+
key_indent = _key_indent(raw)
|
|
192
|
+
i += 1
|
|
193
|
+
if value == "" or value in _BLOCK_SCALAR_INDICATORS:
|
|
194
|
+
# Consume the following MORE-INDENTED (non-blank, non-comment)
|
|
195
|
+
# continuation lines as the block/folded scalar body.
|
|
196
|
+
parts: List[str] = []
|
|
197
|
+
while i < n:
|
|
198
|
+
cont_raw = raw_lines[i]
|
|
199
|
+
cont_stripped = cont_raw.strip()
|
|
200
|
+
if cont_stripped == "":
|
|
201
|
+
# Blank line: part of a block scalar — keep scanning, but
|
|
202
|
+
# contributes no token to a space-joined value.
|
|
203
|
+
i += 1
|
|
204
|
+
continue
|
|
205
|
+
if _key_indent(cont_raw) <= key_indent:
|
|
206
|
+
break # dedent back to (or above) the key → block ended
|
|
207
|
+
parts.append(cont_stripped)
|
|
208
|
+
i += 1
|
|
209
|
+
joined = " ".join(parts).strip()
|
|
210
|
+
# If the scalar had an explicit indicator but no body, fall back to
|
|
211
|
+
# the indicator text only if nothing was captured (len stays small).
|
|
212
|
+
if joined:
|
|
213
|
+
value = joined
|
|
214
|
+
result[key] = value
|
|
215
|
+
return result
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
def _file_entry(path: Path, repo: Path, category: str) -> Optional[Dict[str, Any]]:
|
|
219
|
+
"""Build a per-file inventory entry, or None if unreadable.
|
|
220
|
+
|
|
221
|
+
Carries the line count, byte/char size, token estimate, and (when a
|
|
222
|
+
frontmatter ``description:`` exists) its length for bloat-flagging.
|
|
223
|
+
"""
|
|
224
|
+
text = _read_text(path)
|
|
225
|
+
if text is None:
|
|
226
|
+
return None
|
|
227
|
+
chars = len(text)
|
|
228
|
+
lines = _line_count(text)
|
|
229
|
+
fm = parse_frontmatter(text)
|
|
230
|
+
description = fm.get("description", "")
|
|
231
|
+
try:
|
|
232
|
+
rel = str(path.relative_to(repo))
|
|
233
|
+
except ValueError:
|
|
234
|
+
rel = str(path)
|
|
235
|
+
return {
|
|
236
|
+
"category": category,
|
|
237
|
+
"path": rel,
|
|
238
|
+
"lines": lines,
|
|
239
|
+
"chars": chars,
|
|
240
|
+
"est_tokens": estimate_tokens(chars),
|
|
241
|
+
"description_chars": len(description),
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ---------------------------------------------------------------------------
|
|
246
|
+
# MCP discovery
|
|
247
|
+
# ---------------------------------------------------------------------------
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def discover_mcp_servers(repo: Path) -> Tuple[List[str], List[str]]:
|
|
251
|
+
"""Best-effort discovery of the MCP subscription surface.
|
|
252
|
+
|
|
253
|
+
Looks for an ``mcpServers`` object in (in order) ``.mcp.json``,
|
|
254
|
+
``.claude/.mcp.json``, ``.claude/settings.json``, and
|
|
255
|
+
``.claude/settings.local.json``. Returns ``(server_names, source_files)``.
|
|
256
|
+
Read-only; tolerant of malformed JSON / missing files (advisory).
|
|
257
|
+
"""
|
|
258
|
+
candidates = [
|
|
259
|
+
repo / ".mcp.json",
|
|
260
|
+
repo / ".claude" / ".mcp.json",
|
|
261
|
+
repo / ".claude" / "settings.json",
|
|
262
|
+
repo / ".claude" / "settings.local.json",
|
|
263
|
+
]
|
|
264
|
+
names: List[str] = []
|
|
265
|
+
sources: List[str] = []
|
|
266
|
+
for cand in candidates:
|
|
267
|
+
if not cand.is_file():
|
|
268
|
+
continue
|
|
269
|
+
text = _read_text(cand)
|
|
270
|
+
if text is None:
|
|
271
|
+
continue
|
|
272
|
+
try:
|
|
273
|
+
data = json.loads(text)
|
|
274
|
+
except (json.JSONDecodeError, ValueError):
|
|
275
|
+
continue
|
|
276
|
+
if not isinstance(data, dict):
|
|
277
|
+
continue
|
|
278
|
+
servers = data.get("mcpServers")
|
|
279
|
+
if isinstance(servers, dict) and servers:
|
|
280
|
+
try:
|
|
281
|
+
rel = str(cand.relative_to(repo))
|
|
282
|
+
except ValueError:
|
|
283
|
+
rel = str(cand)
|
|
284
|
+
sources.append(rel)
|
|
285
|
+
for key in servers.keys():
|
|
286
|
+
if key not in names:
|
|
287
|
+
names.append(str(key))
|
|
288
|
+
return names, sources
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# ---------------------------------------------------------------------------
|
|
292
|
+
# Inventory
|
|
293
|
+
# ---------------------------------------------------------------------------
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def _collect_files(repo: Path) -> Dict[str, List[Dict[str, Any]]]:
|
|
297
|
+
"""Walk the Gate-1 + skill surface and build per-category file entries."""
|
|
298
|
+
out: Dict[str, List[Dict[str, Any]]] = {
|
|
299
|
+
CAT_CLAUDE_MD: [],
|
|
300
|
+
CAT_PROTOCOL: [],
|
|
301
|
+
CAT_TEAM: [],
|
|
302
|
+
CAT_CORE_SKILL: [],
|
|
303
|
+
CAT_AGENTS: [],
|
|
304
|
+
CAT_SKILLS: [],
|
|
305
|
+
CAT_COMMANDS: [],
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
def _add(category: str, path: Path) -> None:
|
|
309
|
+
if path.is_file():
|
|
310
|
+
entry = _file_entry(path, repo, category)
|
|
311
|
+
if entry is not None:
|
|
312
|
+
out[category].append(entry)
|
|
313
|
+
|
|
314
|
+
_add(CAT_CLAUDE_MD, repo / "CLAUDE.md")
|
|
315
|
+
_add(CAT_PROTOCOL, repo / "PROTOCOL.md")
|
|
316
|
+
_add(CAT_TEAM, repo / ".claude" / "team.md")
|
|
317
|
+
_add(CAT_TEAM, repo / ".claude" / "frontend-team.md")
|
|
318
|
+
|
|
319
|
+
core_skill = repo / ".claude" / "skills" / "core" / "ceo-orchestration" / "SKILL.md"
|
|
320
|
+
_add(CAT_CORE_SKILL, core_skill)
|
|
321
|
+
|
|
322
|
+
agents_dir = repo / ".claude" / "agents"
|
|
323
|
+
if agents_dir.is_dir():
|
|
324
|
+
for p in sorted(agents_dir.glob("*.md")):
|
|
325
|
+
_add(CAT_AGENTS, p)
|
|
326
|
+
|
|
327
|
+
skills_dir = repo / ".claude" / "skills"
|
|
328
|
+
if skills_dir.is_dir():
|
|
329
|
+
for p in sorted(skills_dir.rglob("SKILL.md")):
|
|
330
|
+
# The core ceo-orchestration SKILL.md is its own category — don't
|
|
331
|
+
# double-count it under the generic skills bucket.
|
|
332
|
+
if p.resolve() == core_skill.resolve():
|
|
333
|
+
continue
|
|
334
|
+
_add(CAT_SKILLS, p)
|
|
335
|
+
|
|
336
|
+
commands_dir = repo / ".claude" / "commands"
|
|
337
|
+
if commands_dir.is_dir():
|
|
338
|
+
for p in sorted(commands_dir.glob("*.md")):
|
|
339
|
+
_add(CAT_COMMANDS, p)
|
|
340
|
+
|
|
341
|
+
return out
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def _flag_file(entry: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
345
|
+
"""Return reduction-candidate flags for a single file entry.
|
|
346
|
+
|
|
347
|
+
Heavy-file (line) flags use the per-category threshold; a bloated
|
|
348
|
+
frontmatter ``description:`` is a separate flag.
|
|
349
|
+
"""
|
|
350
|
+
flags: List[Dict[str, Any]] = []
|
|
351
|
+
category = entry["category"]
|
|
352
|
+
lines = entry["lines"]
|
|
353
|
+
|
|
354
|
+
if category == CAT_AGENTS:
|
|
355
|
+
threshold = THRESHOLD_AGENT_LINES
|
|
356
|
+
elif category in (CAT_SKILLS, CAT_CORE_SKILL):
|
|
357
|
+
threshold = THRESHOLD_SKILL_LINES
|
|
358
|
+
elif category == CAT_COMMANDS:
|
|
359
|
+
threshold = THRESHOLD_RULE_LINES
|
|
360
|
+
else:
|
|
361
|
+
threshold = None # claude_md / protocol / team have no line threshold
|
|
362
|
+
|
|
363
|
+
if threshold is not None and lines > threshold:
|
|
364
|
+
flags.append({
|
|
365
|
+
"kind": "heavy_file",
|
|
366
|
+
"category": category,
|
|
367
|
+
"path": entry["path"],
|
|
368
|
+
"lines": lines,
|
|
369
|
+
"threshold_lines": threshold,
|
|
370
|
+
"est_tokens": entry["est_tokens"],
|
|
371
|
+
"message": (
|
|
372
|
+
"{cat} file is {lines} lines (> {thr}); consider splitting or "
|
|
373
|
+
"trimming to reduce always-loaded context".format(
|
|
374
|
+
cat=category, lines=lines, thr=threshold,
|
|
375
|
+
)
|
|
376
|
+
),
|
|
377
|
+
})
|
|
378
|
+
|
|
379
|
+
if entry["description_chars"] > THRESHOLD_DESCRIPTION_CHARS:
|
|
380
|
+
flags.append({
|
|
381
|
+
"kind": "bloated_description",
|
|
382
|
+
"category": category,
|
|
383
|
+
"path": entry["path"],
|
|
384
|
+
"description_chars": entry["description_chars"],
|
|
385
|
+
"threshold_chars": THRESHOLD_DESCRIPTION_CHARS,
|
|
386
|
+
"est_tokens": entry["est_tokens"],
|
|
387
|
+
"message": (
|
|
388
|
+
"frontmatter description is {n} chars (> {thr}); trim to keep "
|
|
389
|
+
"the skill/agent index lean".format(
|
|
390
|
+
n=entry["description_chars"], thr=THRESHOLD_DESCRIPTION_CHARS,
|
|
391
|
+
)
|
|
392
|
+
),
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
return flags
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def build_inventory(repo: Path, top: int = 10) -> Dict[str, Any]:
|
|
399
|
+
"""Produce the full context-budget report dict.
|
|
400
|
+
|
|
401
|
+
Categories table + flat file list + flagged reduction candidates + a
|
|
402
|
+
top-N ranking by estimated tokens (heaviest first).
|
|
403
|
+
"""
|
|
404
|
+
files_by_cat = _collect_files(repo)
|
|
405
|
+
mcp_names, mcp_sources = discover_mcp_servers(repo)
|
|
406
|
+
|
|
407
|
+
categories: List[Dict[str, Any]] = []
|
|
408
|
+
all_files: List[Dict[str, Any]] = []
|
|
409
|
+
flags: List[Dict[str, Any]] = []
|
|
410
|
+
grand_tokens = 0
|
|
411
|
+
|
|
412
|
+
cat_order = [
|
|
413
|
+
CAT_CLAUDE_MD, CAT_PROTOCOL, CAT_TEAM, CAT_CORE_SKILL,
|
|
414
|
+
CAT_AGENTS, CAT_SKILLS, CAT_COMMANDS,
|
|
415
|
+
]
|
|
416
|
+
for cat in cat_order:
|
|
417
|
+
entries = files_by_cat.get(cat, [])
|
|
418
|
+
cat_tokens = sum(e["est_tokens"] for e in entries)
|
|
419
|
+
cat_lines = sum(e["lines"] for e in entries)
|
|
420
|
+
grand_tokens += cat_tokens
|
|
421
|
+
categories.append({
|
|
422
|
+
"category": cat,
|
|
423
|
+
"file_count": len(entries),
|
|
424
|
+
"total_lines": cat_lines,
|
|
425
|
+
"est_tokens": cat_tokens,
|
|
426
|
+
})
|
|
427
|
+
for e in entries:
|
|
428
|
+
all_files.append(e)
|
|
429
|
+
flags.extend(_flag_file(e))
|
|
430
|
+
|
|
431
|
+
# MCP category — count-based, not file-token-based.
|
|
432
|
+
mcp_over = len(mcp_names) > THRESHOLD_MCP_SERVERS
|
|
433
|
+
categories.append({
|
|
434
|
+
"category": CAT_MCP,
|
|
435
|
+
"file_count": len(mcp_sources),
|
|
436
|
+
"server_count": len(mcp_names),
|
|
437
|
+
"servers": mcp_names,
|
|
438
|
+
"sources": mcp_sources,
|
|
439
|
+
"over_subscribed": mcp_over,
|
|
440
|
+
"threshold_servers": THRESHOLD_MCP_SERVERS,
|
|
441
|
+
})
|
|
442
|
+
if mcp_over:
|
|
443
|
+
flags.append({
|
|
444
|
+
"kind": "mcp_over_subscription",
|
|
445
|
+
"category": CAT_MCP,
|
|
446
|
+
"server_count": len(mcp_names),
|
|
447
|
+
"threshold_servers": THRESHOLD_MCP_SERVERS,
|
|
448
|
+
"servers": mcp_names,
|
|
449
|
+
"message": (
|
|
450
|
+
"{n} MCP servers configured (> {thr}); each adds tool-schema "
|
|
451
|
+
"context — unsubscribe unused ones".format(
|
|
452
|
+
n=len(mcp_names), thr=THRESHOLD_MCP_SERVERS,
|
|
453
|
+
)
|
|
454
|
+
),
|
|
455
|
+
})
|
|
456
|
+
|
|
457
|
+
# Top-N reduction candidates: heaviest files by estimated tokens, desc.
|
|
458
|
+
# Stable tie-break on path so ordering is deterministic across runs.
|
|
459
|
+
ranked = sorted(
|
|
460
|
+
all_files,
|
|
461
|
+
key=lambda e: (-e["est_tokens"], e["path"]),
|
|
462
|
+
)
|
|
463
|
+
if top is not None and top >= 0:
|
|
464
|
+
ranked = ranked[:top]
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
"schema": "context-budget.v1",
|
|
468
|
+
"repo_root": str(repo),
|
|
469
|
+
"heuristic": "1 token ~= {} chars (ESTIMATE, not the Anthropic "
|
|
470
|
+
"tokenizer)".format(CHARS_PER_TOKEN),
|
|
471
|
+
"grand_total_est_tokens": grand_tokens,
|
|
472
|
+
"categories": categories,
|
|
473
|
+
"top_candidates": ranked,
|
|
474
|
+
"flags": flags,
|
|
475
|
+
"flag_count": len(flags),
|
|
476
|
+
"files": all_files,
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
# ---------------------------------------------------------------------------
|
|
481
|
+
# PLAN-133 D1 — proactive auto-compaction policy (hysteresis state machine)
|
|
482
|
+
# ---------------------------------------------------------------------------
|
|
483
|
+
#
|
|
484
|
+
# Default-OFF behavioral change. The *decision* (this module) is non-canonical
|
|
485
|
+
# and lives here in `scripts/`; the actual `context_auto_compacted` /
|
|
486
|
+
# `context_auto_compact_suppressed` closed-enum audit emit is CANONICAL
|
|
487
|
+
# (`.claude/hooks/_lib/audit_emit.py`) and is staged for Owner-GPG under
|
|
488
|
+
# `.claude/plans/PLAN-133/staged/D1.proposal.md` — this file never edits it.
|
|
489
|
+
#
|
|
490
|
+
# Doctrine compliance:
|
|
491
|
+
# * Default-OFF: the feature is INACTIVE unless `CEO_AUTO_COMPACT_THRESHOLD`
|
|
492
|
+
# is set to a sane int in (0, 100]. With the env unset, `decide_compaction`
|
|
493
|
+
# always returns a "disabled" decision (compact=False, suppressed=False).
|
|
494
|
+
# The default constant below (80) is the value used WHEN enabled; it is NOT
|
|
495
|
+
# a default-on flip.
|
|
496
|
+
# * Measure-first: every decision carries the numeric reason + ratios so the
|
|
497
|
+
# compaction-rate can be tabulated from logs before any default-on flip.
|
|
498
|
+
# * Hysteresis (perf must-fix): trigger at a HIGH-water mark, re-arm only
|
|
499
|
+
# after dropping below a LOW-water mark, plus a minimum-turns cooldown and
|
|
500
|
+
# a minimum-bytes-reclaimed floor. When the floor (or a still-disarmed
|
|
501
|
+
# re-arm gate, or cooldown) blocks a would-be compaction, the decision is
|
|
502
|
+
# `suppressed=True` so the caller emits `context_auto_compact_suppressed`.
|
|
503
|
+
# * Fail-open-on-infra: any malformed input / read error yields a "disabled"
|
|
504
|
+
# decision (never raises), so a buggy snapshot never blocks a session.
|
|
505
|
+
#
|
|
506
|
+
# This is a pure, side-effect-free decision function: it does NOT compact, does
|
|
507
|
+
# NOT emit, and does NOT write anything. The host wires the side effects.
|
|
508
|
+
|
|
509
|
+
# Env flags (default-OFF). `CEO_AUTO_COMPACT_THRESHOLD` is the high-water % of
|
|
510
|
+
# the model context window at which compaction is proposed. Unset/invalid ⇒ OFF.
|
|
511
|
+
ENV_AUTO_COMPACT_THRESHOLD = "CEO_AUTO_COMPACT_THRESHOLD"
|
|
512
|
+
ENV_AUTO_COMPACT_LOW_WATER = "CEO_AUTO_COMPACT_LOW_WATER"
|
|
513
|
+
ENV_AUTO_COMPACT_COOLDOWN_TURNS = "CEO_AUTO_COMPACT_COOLDOWN_TURNS"
|
|
514
|
+
ENV_AUTO_COMPACT_MIN_RECLAIM_PCT = "CEO_AUTO_COMPACT_MIN_RECLAIM_PCT"
|
|
515
|
+
|
|
516
|
+
# Defaults used ONLY when the feature is enabled (threshold env present + valid).
|
|
517
|
+
DEFAULT_AUTO_COMPACT_THRESHOLD_PCT = 80 # high-water trigger (% of window)
|
|
518
|
+
DEFAULT_AUTO_COMPACT_LOW_WATER_PCT = 60 # re-arm only after dropping below this
|
|
519
|
+
DEFAULT_AUTO_COMPACT_COOLDOWN_TURNS = 5 # min turns between compactions
|
|
520
|
+
DEFAULT_AUTO_COMPACT_MIN_RECLAIM_PCT = 10 # skip if < this % of bytes would be freed
|
|
521
|
+
|
|
522
|
+
# Decision reason codes (stable strings for log tabulation; closed set).
|
|
523
|
+
REASON_DISABLED = "disabled" # feature OFF (env unset/invalid)
|
|
524
|
+
REASON_BELOW_HIGH_WATER = "below_high_water" # usage under trigger
|
|
525
|
+
REASON_NOT_REARMED = "not_rearmed" # above low-water since last compaction
|
|
526
|
+
REASON_COOLDOWN = "cooldown" # min-turns cooldown not elapsed
|
|
527
|
+
REASON_RECLAIM_FLOOR = "reclaim_floor" # < min-bytes-reclaimed freed → skip
|
|
528
|
+
REASON_COMPACT = "compact" # all gates pass → compact now
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
def _env_int(name: str, env: Optional[Dict[str, str]]) -> Optional[int]:
|
|
532
|
+
"""Read an int from `env` (or os.environ) — None on absent/malformed.
|
|
533
|
+
|
|
534
|
+
Fail-open: never raises. A non-integer, empty, or whitespace value reads as
|
|
535
|
+
None (treated by callers as "not configured").
|
|
536
|
+
"""
|
|
537
|
+
src = env if env is not None else os.environ
|
|
538
|
+
raw = src.get(name)
|
|
539
|
+
if raw is None:
|
|
540
|
+
return None
|
|
541
|
+
try:
|
|
542
|
+
return int(str(raw).strip())
|
|
543
|
+
except (TypeError, ValueError):
|
|
544
|
+
return None
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
class CompactionPolicy:
|
|
548
|
+
"""Hysteresis config + re-arm state for the auto-compaction decision.
|
|
549
|
+
|
|
550
|
+
Stateless across processes by design — the host owns persistence. The host
|
|
551
|
+
passes the prior `armed` flag and `turns_since_last_compaction` from its own
|
|
552
|
+
session state; this object only derives the next decision + next state.
|
|
553
|
+
|
|
554
|
+
`armed` means "eligible to trigger again": it is set False right after a
|
|
555
|
+
compaction and re-set True once usage has dropped below the low-water mark.
|
|
556
|
+
"""
|
|
557
|
+
|
|
558
|
+
def __init__(
|
|
559
|
+
self,
|
|
560
|
+
high_water_pct: int,
|
|
561
|
+
low_water_pct: int,
|
|
562
|
+
cooldown_turns: int,
|
|
563
|
+
min_reclaim_pct: int,
|
|
564
|
+
) -> None:
|
|
565
|
+
# Clamp to a sane, monotone config (fail-open: never raise on bad nums).
|
|
566
|
+
self.high_water_pct = _clamp_pct(high_water_pct, DEFAULT_AUTO_COMPACT_THRESHOLD_PCT)
|
|
567
|
+
low = _clamp_pct(low_water_pct, DEFAULT_AUTO_COMPACT_LOW_WATER_PCT)
|
|
568
|
+
# Low-water MUST sit strictly below high-water for hysteresis to exist;
|
|
569
|
+
# if a caller inverts them, pin low to high-1 (degenerate but safe).
|
|
570
|
+
if low >= self.high_water_pct:
|
|
571
|
+
low = max(0, self.high_water_pct - 1)
|
|
572
|
+
self.low_water_pct = low
|
|
573
|
+
self.cooldown_turns = cooldown_turns if cooldown_turns is not None and cooldown_turns >= 0 else DEFAULT_AUTO_COMPACT_COOLDOWN_TURNS
|
|
574
|
+
self.min_reclaim_pct = _clamp_pct(min_reclaim_pct, DEFAULT_AUTO_COMPACT_MIN_RECLAIM_PCT)
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def _clamp_pct(value: Any, fallback: int) -> int:
|
|
578
|
+
"""Coerce `value` to an int in [0, 100]; `fallback` on any malformed input."""
|
|
579
|
+
try:
|
|
580
|
+
n = int(value)
|
|
581
|
+
except (TypeError, ValueError):
|
|
582
|
+
return fallback
|
|
583
|
+
if n < 0:
|
|
584
|
+
return 0
|
|
585
|
+
if n > 100:
|
|
586
|
+
return 100
|
|
587
|
+
return n
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
def load_policy_from_env(env: Optional[Dict[str, str]] = None) -> Optional[CompactionPolicy]:
|
|
591
|
+
"""Build a CompactionPolicy from env, or None when the feature is OFF.
|
|
592
|
+
|
|
593
|
+
The feature is OFF (returns None) unless `CEO_AUTO_COMPACT_THRESHOLD` is set
|
|
594
|
+
to an int in (0, 100]. All other knobs fall back to their documented
|
|
595
|
+
defaults when unset/invalid. Fail-open: never raises.
|
|
596
|
+
"""
|
|
597
|
+
threshold = _env_int(ENV_AUTO_COMPACT_THRESHOLD, env)
|
|
598
|
+
if threshold is None or threshold <= 0 or threshold > 100:
|
|
599
|
+
return None # default-OFF
|
|
600
|
+
return CompactionPolicy(
|
|
601
|
+
high_water_pct=threshold,
|
|
602
|
+
low_water_pct=(
|
|
603
|
+
_env_int(ENV_AUTO_COMPACT_LOW_WATER, env)
|
|
604
|
+
if _env_int(ENV_AUTO_COMPACT_LOW_WATER, env) is not None
|
|
605
|
+
else DEFAULT_AUTO_COMPACT_LOW_WATER_PCT
|
|
606
|
+
),
|
|
607
|
+
cooldown_turns=(
|
|
608
|
+
_env_int(ENV_AUTO_COMPACT_COOLDOWN_TURNS, env)
|
|
609
|
+
if _env_int(ENV_AUTO_COMPACT_COOLDOWN_TURNS, env) is not None
|
|
610
|
+
else DEFAULT_AUTO_COMPACT_COOLDOWN_TURNS
|
|
611
|
+
),
|
|
612
|
+
min_reclaim_pct=(
|
|
613
|
+
_env_int(ENV_AUTO_COMPACT_MIN_RECLAIM_PCT, env)
|
|
614
|
+
if _env_int(ENV_AUTO_COMPACT_MIN_RECLAIM_PCT, env) is not None
|
|
615
|
+
else DEFAULT_AUTO_COMPACT_MIN_RECLAIM_PCT
|
|
616
|
+
),
|
|
617
|
+
)
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def _safe_ratio_pct(numerator: Any, denominator: Any) -> Optional[float]:
|
|
621
|
+
"""numerator/denominator as a percent (0..100), or None if not derivable."""
|
|
622
|
+
try:
|
|
623
|
+
num = float(numerator)
|
|
624
|
+
den = float(denominator)
|
|
625
|
+
except (TypeError, ValueError):
|
|
626
|
+
return None
|
|
627
|
+
if den <= 0:
|
|
628
|
+
return None
|
|
629
|
+
pct = (num / den) * 100.0
|
|
630
|
+
if pct < 0:
|
|
631
|
+
return 0.0
|
|
632
|
+
return pct
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
def decide_compaction(
|
|
636
|
+
used_tokens: Any,
|
|
637
|
+
window_tokens: Any,
|
|
638
|
+
*,
|
|
639
|
+
reclaimable_tokens: Any = None,
|
|
640
|
+
armed: bool = True,
|
|
641
|
+
turns_since_last_compaction: Any = None,
|
|
642
|
+
policy: Optional[CompactionPolicy] = None,
|
|
643
|
+
env: Optional[Dict[str, str]] = None,
|
|
644
|
+
) -> Dict[str, Any]:
|
|
645
|
+
"""Decide whether to auto-compact NOW. Pure + side-effect-free + fail-open.
|
|
646
|
+
|
|
647
|
+
Parameters
|
|
648
|
+
----------
|
|
649
|
+
used_tokens, window_tokens
|
|
650
|
+
Current context usage and the model window size (tokens). The usage
|
|
651
|
+
ratio drives the high/low-water hysteresis.
|
|
652
|
+
reclaimable_tokens
|
|
653
|
+
Estimated tokens a compaction would free. Drives the minimum-reclaim
|
|
654
|
+
floor. When None, the floor is treated as PASSED (host could not
|
|
655
|
+
estimate — do not block on a missing estimate; fail-open).
|
|
656
|
+
armed
|
|
657
|
+
Host-supplied re-arm flag (False right after a prior compaction until
|
|
658
|
+
usage has dropped below the low-water mark).
|
|
659
|
+
turns_since_last_compaction
|
|
660
|
+
Host-supplied turn counter for the cooldown gate. None ⇒ cooldown
|
|
661
|
+
treated as elapsed (no prior compaction this session).
|
|
662
|
+
policy
|
|
663
|
+
Explicit policy; when None, derived from `env` (default-OFF if the
|
|
664
|
+
threshold env is unset/invalid).
|
|
665
|
+
|
|
666
|
+
Returns a decision dict (never raises):
|
|
667
|
+
{
|
|
668
|
+
"compact": bool, # caller should compact now
|
|
669
|
+
"suppressed": bool, # a would-be compaction was skipped by a gate
|
|
670
|
+
"reason": <REASON_*>, # stable reason code
|
|
671
|
+
"enabled": bool, # feature active
|
|
672
|
+
"usage_pct": float|None, # used/window * 100
|
|
673
|
+
"reclaim_pct": float|None, # reclaimable/used * 100 (estimate)
|
|
674
|
+
"next_armed": bool, # re-arm state the host should persist
|
|
675
|
+
"high_water_pct": int|None,
|
|
676
|
+
"low_water_pct": int|None,
|
|
677
|
+
"cooldown_turns": int|None,
|
|
678
|
+
"min_reclaim_pct": int|None,
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
NOTE — no payload echo: this dict carries ONLY numeric ratios + closed
|
|
682
|
+
reason codes. It never includes any transcript text, command bytes, env
|
|
683
|
+
values, or file paths. The canonical emit (staged proposal) scrubs to the
|
|
684
|
+
same closed-field allowlist.
|
|
685
|
+
"""
|
|
686
|
+
base = {
|
|
687
|
+
"compact": False,
|
|
688
|
+
"suppressed": False,
|
|
689
|
+
"reason": REASON_DISABLED,
|
|
690
|
+
"enabled": False,
|
|
691
|
+
"usage_pct": None,
|
|
692
|
+
"reclaim_pct": None,
|
|
693
|
+
"next_armed": bool(armed),
|
|
694
|
+
"high_water_pct": None,
|
|
695
|
+
"low_water_pct": None,
|
|
696
|
+
"cooldown_turns": None,
|
|
697
|
+
"min_reclaim_pct": None,
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if policy is None:
|
|
701
|
+
policy = load_policy_from_env(env)
|
|
702
|
+
if policy is None:
|
|
703
|
+
return base # default-OFF — disabled decision
|
|
704
|
+
|
|
705
|
+
base["enabled"] = True
|
|
706
|
+
base["high_water_pct"] = policy.high_water_pct
|
|
707
|
+
base["low_water_pct"] = policy.low_water_pct
|
|
708
|
+
base["cooldown_turns"] = policy.cooldown_turns
|
|
709
|
+
base["min_reclaim_pct"] = policy.min_reclaim_pct
|
|
710
|
+
|
|
711
|
+
usage_pct = _safe_ratio_pct(used_tokens, window_tokens)
|
|
712
|
+
base["usage_pct"] = usage_pct
|
|
713
|
+
if usage_pct is None:
|
|
714
|
+
# Cannot derive usage (bad/zero window) → fail-open: do nothing.
|
|
715
|
+
base["reason"] = REASON_BELOW_HIGH_WATER
|
|
716
|
+
return base
|
|
717
|
+
|
|
718
|
+
# Hysteresis re-arm: once usage drops below low-water, become eligible again.
|
|
719
|
+
next_armed = bool(armed)
|
|
720
|
+
if usage_pct < policy.low_water_pct:
|
|
721
|
+
next_armed = True
|
|
722
|
+
base["next_armed"] = next_armed
|
|
723
|
+
|
|
724
|
+
# Below the high-water trigger: nothing to do (and we've already updated the
|
|
725
|
+
# re-arm flag above for the drop-below-low case).
|
|
726
|
+
if usage_pct < policy.high_water_pct:
|
|
727
|
+
base["reason"] = REASON_BELOW_HIGH_WATER
|
|
728
|
+
return base
|
|
729
|
+
|
|
730
|
+
# At/above high-water but NOT re-armed (we are still riding the band above
|
|
731
|
+
# low-water since the last compaction) → hold (not a suppression event; we
|
|
732
|
+
# simply have not earned a fresh trigger).
|
|
733
|
+
if not next_armed:
|
|
734
|
+
base["reason"] = REASON_NOT_REARMED
|
|
735
|
+
return base
|
|
736
|
+
|
|
737
|
+
# Cooldown gate: a would-be compaction blocked by min-turns IS a suppression.
|
|
738
|
+
turns = turns_since_last_compaction
|
|
739
|
+
if turns is not None:
|
|
740
|
+
try:
|
|
741
|
+
turns_int = int(turns)
|
|
742
|
+
except (TypeError, ValueError):
|
|
743
|
+
turns_int = None
|
|
744
|
+
if turns_int is not None and turns_int < policy.cooldown_turns:
|
|
745
|
+
base["reason"] = REASON_COOLDOWN
|
|
746
|
+
base["suppressed"] = True
|
|
747
|
+
return base
|
|
748
|
+
|
|
749
|
+
# Minimum-reclaim floor: skip a compaction that would free too little.
|
|
750
|
+
reclaim_pct = _safe_ratio_pct(reclaimable_tokens, used_tokens)
|
|
751
|
+
base["reclaim_pct"] = reclaim_pct
|
|
752
|
+
if reclaim_pct is not None and reclaim_pct < policy.min_reclaim_pct:
|
|
753
|
+
base["reason"] = REASON_RECLAIM_FLOOR
|
|
754
|
+
base["suppressed"] = True
|
|
755
|
+
return base
|
|
756
|
+
|
|
757
|
+
# All gates pass → compact now; consume the re-arm (host disarms until the
|
|
758
|
+
# next drop below low-water).
|
|
759
|
+
base["compact"] = True
|
|
760
|
+
base["reason"] = REASON_COMPACT
|
|
761
|
+
base["next_armed"] = False
|
|
762
|
+
return base
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
# ---------------------------------------------------------------------------
|
|
766
|
+
# PLAN-133 D2 (Wave D) — cheap-tier summarization of oldest verbose subagent
|
|
767
|
+
# outputs (protect last N)
|
|
768
|
+
# ---------------------------------------------------------------------------
|
|
769
|
+
#
|
|
770
|
+
# Default-OFF behavioral change. The *decision* (this module) is non-canonical
|
|
771
|
+
# and lives here in `scripts/`; the actual `subagent_output_summarized` /
|
|
772
|
+
# `subagent_output_summarize_skipped` closed-enum audit emit is CANONICAL
|
|
773
|
+
# (`.claude/hooks/_lib/audit_emit.py`) and is staged for Owner-GPG under
|
|
774
|
+
# `.claude/plans/PLAN-133/staged/D2.proposal.md` — this file never edits it.
|
|
775
|
+
#
|
|
776
|
+
# The IDEA (re-implemented from scratch, stdlib-only, NOT vendored): when the
|
|
777
|
+
# context window fills, the OLDEST + most-VERBOSE subagent tool-outputs are the
|
|
778
|
+
# best candidates to compress — they are the least likely to be needed verbatim
|
|
779
|
+
# again, and they carry the most tokens. We route those oldest verbose outputs
|
|
780
|
+
# to a CHEAP model tier for a short digest, while PROTECTING the last N outputs
|
|
781
|
+
# (the recent working set the orchestrator is actively reasoning over) so a
|
|
782
|
+
# just-produced result is never silently summarized out from under the loop.
|
|
783
|
+
#
|
|
784
|
+
# Doctrine compliance (§3):
|
|
785
|
+
# * Default-OFF: INACTIVE unless `CEO_SUMMARIZE_OLDEST` is set to a truthy
|
|
786
|
+
# int budget (the max number of outputs to summarize in one pass, > 0).
|
|
787
|
+
# Unset/invalid ⇒ `decide_summarization` returns a "disabled" plan
|
|
788
|
+
# (selected=[], enabled=False). The DEFAULT constants below are the values
|
|
789
|
+
# used WHEN enabled; they are NOT a default-on flip.
|
|
790
|
+
# * Measure-first: the plan carries the selected count + reclaimable-token
|
|
791
|
+
# estimate + a closed reason so the summarization-rate (and the tokens it
|
|
792
|
+
# would reclaim) can be tabulated from logs before any default-on flip.
|
|
793
|
+
# Named promotion-measure: count(`subagent_output_summarized`) and the
|
|
794
|
+
# summed `reclaim_tokens` per week at /ceo-boot.
|
|
795
|
+
# * protect-last-N (the named AC): the `protect_last` most-recent outputs are
|
|
796
|
+
# NEVER eligible, regardless of size, so the active working set is safe.
|
|
797
|
+
# * verbosity floor: only outputs whose estimated size is >= a minimum-token
|
|
798
|
+
# floor are eligible (summarizing a tiny output costs a cheap-tier call to
|
|
799
|
+
# save nothing — `subagent_output_summarize_skipped` reason=below_floor).
|
|
800
|
+
# * budget cap: at most `max_summaries` oldest-first eligible outputs are
|
|
801
|
+
# selected in one pass (the rest are deferred, not lost).
|
|
802
|
+
# * Fail-open-on-infra: any malformed input / read error yields a "disabled"
|
|
803
|
+
# plan (never raises), so a buggy snapshot never blocks a session and a
|
|
804
|
+
# recent output is never accidentally selected.
|
|
805
|
+
# * No payload echo: the plan carries ONLY integer indices + token-size
|
|
806
|
+
# buckets + closed reason codes. It NEVER includes any subagent output
|
|
807
|
+
# text, agent name, file path, or command bytes. The canonical emit (staged
|
|
808
|
+
# proposal) scrubs to the same closed-field allowlist.
|
|
809
|
+
#
|
|
810
|
+
# This is a pure, side-effect-free decision function: it does NOT summarize,
|
|
811
|
+
# does NOT call any model, does NOT emit, and does NOT write anything. The host
|
|
812
|
+
# wires the cheap-tier digest call + the audit emit + the context rewrite.
|
|
813
|
+
|
|
814
|
+
# Env flags (default-OFF). `CEO_SUMMARIZE_OLDEST` is the per-pass budget (max
|
|
815
|
+
# number of oldest verbose outputs to summarize). Unset/invalid/<=0 ⇒ OFF.
|
|
816
|
+
ENV_SUMMARIZE_OLDEST = "CEO_SUMMARIZE_OLDEST"
|
|
817
|
+
ENV_SUMMARIZE_PROTECT_LAST = "CEO_SUMMARIZE_PROTECT_LAST"
|
|
818
|
+
ENV_SUMMARIZE_MIN_TOKENS = "CEO_SUMMARIZE_MIN_TOKENS"
|
|
819
|
+
|
|
820
|
+
# Defaults used ONLY when the feature is enabled (the budget env is present and
|
|
821
|
+
# a valid positive int).
|
|
822
|
+
DEFAULT_SUMMARIZE_PROTECT_LAST = 3 # never summarize the last N outputs
|
|
823
|
+
DEFAULT_SUMMARIZE_MIN_TOKENS = 2000 # verbosity floor: skip small outputs
|
|
824
|
+
DEFAULT_SUMMARIZE_MAX_PER_PASS = 5 # cap per pass when budget is degenerate
|
|
825
|
+
|
|
826
|
+
# Summarization-plan reason codes (stable strings for log tabulation; closed
|
|
827
|
+
# set, mirrored by the canonical `_SUBAGENT_SUMMARIZE_REASON_ENUM`).
|
|
828
|
+
SUMM_REASON_DISABLED = "disabled" # feature OFF (env unset/invalid)
|
|
829
|
+
SUMM_REASON_NO_CANDIDATES = "no_candidates" # nothing past protect-N over floor
|
|
830
|
+
SUMM_REASON_SELECTED = "selected" # >=1 output selected to summarize
|
|
831
|
+
|
|
832
|
+
# Per-output skip reason codes (why an individual output was NOT selected).
|
|
833
|
+
SUMM_SKIP_PROTECTED = "protected" # within the last-N working set
|
|
834
|
+
SUMM_SKIP_BELOW_FLOOR = "below_floor" # under the verbosity (min-tokens) floor
|
|
835
|
+
SUMM_SKIP_OVER_BUDGET = "over_budget" # eligible but past the per-pass cap
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
class SummarizationPolicy:
|
|
839
|
+
"""Config for the oldest-verbose-output summarization decision.
|
|
840
|
+
|
|
841
|
+
Stateless by design — the host owns the list of current subagent outputs
|
|
842
|
+
and applies the resulting plan. This object only holds the three knobs.
|
|
843
|
+
"""
|
|
844
|
+
|
|
845
|
+
def __init__(
|
|
846
|
+
self,
|
|
847
|
+
max_summaries: int,
|
|
848
|
+
protect_last: int,
|
|
849
|
+
min_tokens: int,
|
|
850
|
+
) -> None:
|
|
851
|
+
# Clamp to sane, fail-open values (never raise on a bad number).
|
|
852
|
+
self.max_summaries = _clamp_nonneg_int(
|
|
853
|
+
max_summaries, DEFAULT_SUMMARIZE_MAX_PER_PASS)
|
|
854
|
+
self.protect_last = _clamp_nonneg_int(
|
|
855
|
+
protect_last, DEFAULT_SUMMARIZE_PROTECT_LAST)
|
|
856
|
+
self.min_tokens = _clamp_nonneg_int(
|
|
857
|
+
min_tokens, DEFAULT_SUMMARIZE_MIN_TOKENS)
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
def _clamp_nonneg_int(value: Any, fallback: int) -> int:
|
|
861
|
+
"""Coerce `value` to an int >= 0; `fallback` on any malformed input."""
|
|
862
|
+
try:
|
|
863
|
+
n = int(value)
|
|
864
|
+
except (TypeError, ValueError):
|
|
865
|
+
return fallback
|
|
866
|
+
return 0 if n < 0 else n
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def load_summarization_policy_from_env(
|
|
870
|
+
env: Optional[Dict[str, str]] = None,
|
|
871
|
+
) -> Optional[SummarizationPolicy]:
|
|
872
|
+
"""Build a SummarizationPolicy from env, or None when the feature is OFF.
|
|
873
|
+
|
|
874
|
+
OFF (returns None) unless `CEO_SUMMARIZE_OLDEST` is set to a positive int
|
|
875
|
+
(the per-pass budget). Other knobs fall back to documented defaults when
|
|
876
|
+
unset/invalid. Fail-open: never raises.
|
|
877
|
+
"""
|
|
878
|
+
budget = _env_int(ENV_SUMMARIZE_OLDEST, env)
|
|
879
|
+
if budget is None or budget <= 0:
|
|
880
|
+
return None # default-OFF
|
|
881
|
+
protect = _env_int(ENV_SUMMARIZE_PROTECT_LAST, env)
|
|
882
|
+
min_tokens = _env_int(ENV_SUMMARIZE_MIN_TOKENS, env)
|
|
883
|
+
return SummarizationPolicy(
|
|
884
|
+
max_summaries=budget,
|
|
885
|
+
protect_last=protect if protect is not None else DEFAULT_SUMMARIZE_PROTECT_LAST,
|
|
886
|
+
min_tokens=min_tokens if min_tokens is not None else DEFAULT_SUMMARIZE_MIN_TOKENS,
|
|
887
|
+
)
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
def _output_token_size(record: Any) -> Optional[int]:
|
|
891
|
+
"""Best-effort estimated token size of one subagent-output record.
|
|
892
|
+
|
|
893
|
+
Accepts either a mapping with an ``est_tokens`` (preferred) or ``tokens``
|
|
894
|
+
or ``chars`` field, or a bare int (already a token count). Returns None when
|
|
895
|
+
no size can be derived (the record is then treated as below-floor and never
|
|
896
|
+
selected — fail-open: a record we cannot size is never summarized).
|
|
897
|
+
"""
|
|
898
|
+
if isinstance(record, bool):
|
|
899
|
+
# bool is an int subclass — reject it as a meaningless size.
|
|
900
|
+
return None
|
|
901
|
+
if isinstance(record, int):
|
|
902
|
+
return record if record >= 0 else None
|
|
903
|
+
if isinstance(record, dict):
|
|
904
|
+
for key in ("est_tokens", "tokens"):
|
|
905
|
+
if key in record:
|
|
906
|
+
try:
|
|
907
|
+
n = int(record[key])
|
|
908
|
+
except (TypeError, ValueError):
|
|
909
|
+
return None
|
|
910
|
+
return n if n >= 0 else None
|
|
911
|
+
if "chars" in record:
|
|
912
|
+
try:
|
|
913
|
+
c = int(record["chars"])
|
|
914
|
+
except (TypeError, ValueError):
|
|
915
|
+
return None
|
|
916
|
+
return estimate_tokens(c) if c >= 0 else None
|
|
917
|
+
return None
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
def decide_summarization(
|
|
921
|
+
outputs: Any,
|
|
922
|
+
*,
|
|
923
|
+
policy: Optional[SummarizationPolicy] = None,
|
|
924
|
+
env: Optional[Dict[str, str]] = None,
|
|
925
|
+
) -> Dict[str, Any]:
|
|
926
|
+
"""Decide which oldest verbose subagent outputs to digest on the cheap tier.
|
|
927
|
+
|
|
928
|
+
Pure + side-effect-free + fail-open. PROTECTS the last N outputs.
|
|
929
|
+
|
|
930
|
+
Parameters
|
|
931
|
+
----------
|
|
932
|
+
outputs
|
|
933
|
+
An ordered sequence of subagent-output records, OLDEST FIRST (index 0
|
|
934
|
+
is the oldest, index ``len-1`` the most recent). Each record may be a
|
|
935
|
+
mapping carrying an estimated size (``est_tokens`` / ``tokens`` /
|
|
936
|
+
``chars``) or a bare int token count. The order is the ONLY thing that
|
|
937
|
+
determines age; the host supplies it.
|
|
938
|
+
policy
|
|
939
|
+
Explicit policy; when None, derived from `env` (default-OFF if the
|
|
940
|
+
budget env is unset/invalid).
|
|
941
|
+
|
|
942
|
+
Returns a plan dict (never raises):
|
|
943
|
+
{
|
|
944
|
+
"enabled": bool, # feature active
|
|
945
|
+
"reason": <SUMM_REASON_*>, # stable plan-level reason code
|
|
946
|
+
"selected": [int, ...], # indices to summarize (oldest first)
|
|
947
|
+
"selected_count": int,
|
|
948
|
+
"reclaim_tokens": int, # est tokens the selected digests would free
|
|
949
|
+
"candidate_count": int, # eligible-before-budget count
|
|
950
|
+
"total_count": int, # len(outputs)
|
|
951
|
+
"protect_last": int|None,
|
|
952
|
+
"min_tokens": int|None,
|
|
953
|
+
"max_summaries": int|None,
|
|
954
|
+
"skipped": [ # per-index skip provenance (closed reasons)
|
|
955
|
+
{"index": int, "reason": <SUMM_SKIP_*>}, ...
|
|
956
|
+
],
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
NO payload echo: the plan carries ONLY integer indices + token-size buckets
|
|
960
|
+
+ closed reason codes. It NEVER includes any output text, agent name, file
|
|
961
|
+
path, or command bytes. The canonical emit (staged proposal) scrubs to the
|
|
962
|
+
same closed-field allowlist.
|
|
963
|
+
"""
|
|
964
|
+
plan: Dict[str, Any] = {
|
|
965
|
+
"enabled": False,
|
|
966
|
+
"reason": SUMM_REASON_DISABLED,
|
|
967
|
+
"selected": [],
|
|
968
|
+
"selected_count": 0,
|
|
969
|
+
"reclaim_tokens": 0,
|
|
970
|
+
"candidate_count": 0,
|
|
971
|
+
"total_count": 0,
|
|
972
|
+
"protect_last": None,
|
|
973
|
+
"min_tokens": None,
|
|
974
|
+
"max_summaries": None,
|
|
975
|
+
"skipped": [],
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
if policy is None:
|
|
979
|
+
policy = load_summarization_policy_from_env(env)
|
|
980
|
+
if policy is None:
|
|
981
|
+
return plan # default-OFF — disabled plan
|
|
982
|
+
|
|
983
|
+
plan["enabled"] = True
|
|
984
|
+
plan["protect_last"] = policy.protect_last
|
|
985
|
+
plan["min_tokens"] = policy.min_tokens
|
|
986
|
+
plan["max_summaries"] = policy.max_summaries
|
|
987
|
+
|
|
988
|
+
# Normalize the outputs list (fail-open: a non-sequence ⇒ empty).
|
|
989
|
+
try:
|
|
990
|
+
items = list(outputs)
|
|
991
|
+
except TypeError:
|
|
992
|
+
items = []
|
|
993
|
+
total = len(items)
|
|
994
|
+
plan["total_count"] = total
|
|
995
|
+
if total == 0:
|
|
996
|
+
plan["reason"] = SUMM_REASON_NO_CANDIDATES
|
|
997
|
+
return plan
|
|
998
|
+
|
|
999
|
+
# The protected window is the last `protect_last` indices (the recent
|
|
1000
|
+
# working set). Everything strictly before it is age-eligible.
|
|
1001
|
+
protect_last = policy.protect_last
|
|
1002
|
+
protect_from = max(0, total - protect_last) if protect_last > 0 else total
|
|
1003
|
+
# `protect_from` is the first PROTECTED index; indices [0, protect_from) are
|
|
1004
|
+
# age-eligible candidates (oldest first).
|
|
1005
|
+
|
|
1006
|
+
candidates: List[Tuple[int, int]] = [] # (index, est_tokens) oldest first
|
|
1007
|
+
for idx in range(total):
|
|
1008
|
+
if idx >= protect_from:
|
|
1009
|
+
# Within the protected last-N working set — never eligible.
|
|
1010
|
+
plan["skipped"].append(
|
|
1011
|
+
{"index": idx, "reason": SUMM_SKIP_PROTECTED})
|
|
1012
|
+
continue
|
|
1013
|
+
size = _output_token_size(items[idx])
|
|
1014
|
+
if size is None or size < policy.min_tokens:
|
|
1015
|
+
# Under the verbosity floor (or unsizeable) — not worth a cheap call.
|
|
1016
|
+
plan["skipped"].append(
|
|
1017
|
+
{"index": idx, "reason": SUMM_SKIP_BELOW_FLOOR})
|
|
1018
|
+
continue
|
|
1019
|
+
candidates.append((idx, size))
|
|
1020
|
+
|
|
1021
|
+
plan["candidate_count"] = len(candidates)
|
|
1022
|
+
if not candidates:
|
|
1023
|
+
plan["reason"] = SUMM_REASON_NO_CANDIDATES
|
|
1024
|
+
return plan
|
|
1025
|
+
|
|
1026
|
+
# Select the OLDEST-first candidates up to the per-pass budget. Candidates
|
|
1027
|
+
# are already in ascending-index (oldest-first) order; honoring that keeps
|
|
1028
|
+
# the selection deterministic and biased to the oldest outputs (the AC).
|
|
1029
|
+
budget = policy.max_summaries
|
|
1030
|
+
selected: List[int] = []
|
|
1031
|
+
reclaim = 0
|
|
1032
|
+
for pos, (idx, size) in enumerate(candidates):
|
|
1033
|
+
if budget > 0 and len(selected) >= budget:
|
|
1034
|
+
# Eligible but past the per-pass cap — deferred, not lost.
|
|
1035
|
+
plan["skipped"].append(
|
|
1036
|
+
{"index": idx, "reason": SUMM_SKIP_OVER_BUDGET})
|
|
1037
|
+
continue
|
|
1038
|
+
selected.append(idx)
|
|
1039
|
+
reclaim += size
|
|
1040
|
+
|
|
1041
|
+
plan["selected"] = selected
|
|
1042
|
+
plan["selected_count"] = len(selected)
|
|
1043
|
+
plan["reclaim_tokens"] = reclaim
|
|
1044
|
+
plan["reason"] = SUMM_REASON_SELECTED if selected else SUMM_REASON_NO_CANDIDATES
|
|
1045
|
+
# Keep the skip provenance deterministically ordered by index.
|
|
1046
|
+
plan["skipped"].sort(key=lambda s: s["index"])
|
|
1047
|
+
return plan
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
# ---------------------------------------------------------------------------
|
|
1051
|
+
# PLAN-133 D5 (Wave D) — middle-out degradation ladder on the context-overflow
|
|
1052
|
+
# path (drop growing fractions of tool-response messages, middle-out, before
|
|
1053
|
+
# failing)
|
|
1054
|
+
# ---------------------------------------------------------------------------
|
|
1055
|
+
#
|
|
1056
|
+
# Default-OFF behavioral change. The *decision + transform* (this module) is
|
|
1057
|
+
# non-canonical and lives here in `scripts/`; the actual
|
|
1058
|
+
# `context_middle_out_degraded` / `context_middle_out_degrade_failed`
|
|
1059
|
+
# closed-enum audit emit is CANONICAL (`.claude/hooks/_lib/audit_emit.py`) and is
|
|
1060
|
+
# staged for Owner-GPG under `.claude/plans/PLAN-133/staged/D5.proposal.md` —
|
|
1061
|
+
# this file never edits it.
|
|
1062
|
+
#
|
|
1063
|
+
# The IDEA (re-implemented from scratch, stdlib-only, NOT vendored): when the
|
|
1064
|
+
# assembled context would OVERFLOW the model window, do NOT hard-fail. Instead,
|
|
1065
|
+
# walk a **degradation ladder** — a sequence of growing fractions (e.g. 25% →
|
|
1066
|
+
# 50% → 75% → 90%) — and at each RUNG drop that fraction from the MIDDLE of the
|
|
1067
|
+
# largest tool-response messages, preserving a HEAD and a TAIL slice of each
|
|
1068
|
+
# (the head carries the request/the first lines of output; the tail carries the
|
|
1069
|
+
# conclusion/error/exit status — the two highest-signal regions). Keep climbing
|
|
1070
|
+
# rungs (degrading more, on more messages) only while still over budget; stop
|
|
1071
|
+
# the instant the projection fits (success) or the ladder is exhausted (the
|
|
1072
|
+
# caller then decides to summarize/compact/fail — D1/D2 are the upstream knobs).
|
|
1073
|
+
#
|
|
1074
|
+
# Why MIDDLE-out and not head/tail truncation: a tool response's first lines
|
|
1075
|
+
# (the command echoed + the start of stdout) and its last lines (the tail of
|
|
1076
|
+
# stdout + the exit/error) are what the orchestrator actually reasons over; the
|
|
1077
|
+
# bulk in the middle (repetitive log lines, large dumps) is the cheapest to drop
|
|
1078
|
+
# with the least loss of meaning. This is the same rationale as a unified-diff
|
|
1079
|
+
# context window: keep the edges, elide the center.
|
|
1080
|
+
#
|
|
1081
|
+
# Doctrine compliance (§3):
|
|
1082
|
+
# * Default-OFF: INACTIVE unless `CEO_MIDDLE_OUT_DEGRADE` is set to a truthy
|
|
1083
|
+
# int in (0, 100] — the per-message head+tail-preserved floor PERCENT (the
|
|
1084
|
+
# minimum fraction of each degraded message that MUST be kept; e.g. 40 ⇒ at
|
|
1085
|
+
# most 60% of any message is ever dropped). Unset/invalid ⇒
|
|
1086
|
+
# `decide_middle_out_degradation` returns a "disabled" plan (degraded=[],
|
|
1087
|
+
# enabled=False) and `apply_middle_out_degradation` returns the messages
|
|
1088
|
+
# UNCHANGED. The DEFAULT constants below are the values used WHEN enabled;
|
|
1089
|
+
# they are NOT a default-on flip.
|
|
1090
|
+
# * Measure-first: the plan carries the rung reached + reclaimed-token
|
|
1091
|
+
# estimate + a closed reason so the degradation-rate (and how often it
|
|
1092
|
+
# SAVED an overflow vs FAILED) can be tabulated from logs before any
|
|
1093
|
+
# default-on flip. Named promotion-measure: count(`context_middle_out_degraded`)
|
|
1094
|
+
# vs count(`context_middle_out_degrade_failed`) per week at /ceo-boot.
|
|
1095
|
+
# * protect-last-N + pinned: the `protect_last` most-recent messages and any
|
|
1096
|
+
# message marked `pinned`/`agent_visible`-True are NEVER degraded, so the
|
|
1097
|
+
# active working set and explicitly-pinned context are safe.
|
|
1098
|
+
# * growing-fraction ladder (the named AC): rungs are applied in ascending
|
|
1099
|
+
# aggressiveness; a rung is only entered if the prior projection still
|
|
1100
|
+
# overflows — never drop more than the overflow requires.
|
|
1101
|
+
# * head/tail floor: a degraded message ALWAYS keeps at least `min_keep_pct`
|
|
1102
|
+
# of its content (split head/tail), so a message is never reduced to a
|
|
1103
|
+
# meaningless stub. The floor is the env value.
|
|
1104
|
+
# * Fail-open-on-infra: any malformed input / read error yields a "disabled"
|
|
1105
|
+
# plan (never raises) and the apply function returns the input untouched, so
|
|
1106
|
+
# a buggy snapshot never blocks a session and a message is never corrupted.
|
|
1107
|
+
# * No payload echo: the plan carries ONLY integer indices + token-size
|
|
1108
|
+
# buckets + a rung integer + closed reason codes. It NEVER includes any
|
|
1109
|
+
# message text, tool name, agent name, file path, or command bytes. The
|
|
1110
|
+
# canonical emit (staged proposal) scrubs to the same closed-field allowlist.
|
|
1111
|
+
#
|
|
1112
|
+
# `decide_middle_out_degradation` is PURE + side-effect-free (does not mutate
|
|
1113
|
+
# inputs, does not emit, does not write). `apply_middle_out_degradation` returns
|
|
1114
|
+
# NEW message dicts (copies) with the middle elided — it likewise never emits,
|
|
1115
|
+
# never writes, and never mutates the inputs in place.
|
|
1116
|
+
|
|
1117
|
+
# Env flag (default-OFF). `CEO_MIDDLE_OUT_DEGRADE` is the per-message keep-floor
|
|
1118
|
+
# PERCENT (minimum % of each degraded message preserved, split head/tail).
|
|
1119
|
+
# Unset/invalid/<=0/>100 ⇒ OFF.
|
|
1120
|
+
ENV_MIDDLE_OUT_DEGRADE = "CEO_MIDDLE_OUT_DEGRADE"
|
|
1121
|
+
ENV_MIDDLE_OUT_PROTECT_LAST = "CEO_MIDDLE_OUT_PROTECT_LAST"
|
|
1122
|
+
ENV_MIDDLE_OUT_MIN_MSG_TOKENS = "CEO_MIDDLE_OUT_MIN_MSG_TOKENS"
|
|
1123
|
+
|
|
1124
|
+
# Defaults used ONLY when the feature is enabled (the keep-floor env is present
|
|
1125
|
+
# and a valid int in (0, 100]).
|
|
1126
|
+
DEFAULT_MIDDLE_OUT_KEEP_FLOOR_PCT = 40 # keep >= this % of any degraded message
|
|
1127
|
+
DEFAULT_MIDDLE_OUT_PROTECT_LAST = 3 # never degrade the last N messages
|
|
1128
|
+
DEFAULT_MIDDLE_OUT_MIN_MSG_TOKENS = 1000 # only degrade messages bigger than this
|
|
1129
|
+
|
|
1130
|
+
# The degradation ladder: ascending fractions of a message's content to TARGET
|
|
1131
|
+
# for removal at each rung. The actual removal is clamped so the kept fraction
|
|
1132
|
+
# never drops below the keep-floor (so a "90% drop" rung with a 40% keep-floor
|
|
1133
|
+
# removes at most 60%). A closed, ordered tuple — the rungs are stable for log
|
|
1134
|
+
# tabulation. Rung index 0 is the least aggressive.
|
|
1135
|
+
MIDDLE_OUT_LADDER = (0.25, 0.50, 0.75, 0.90)
|
|
1136
|
+
|
|
1137
|
+
# Marker inserted where the middle was elided (token-cheap, signals truncation).
|
|
1138
|
+
MIDDLE_OUT_ELISION_MARKER = "\n…[middle-out: {n} chars elided]…\n"
|
|
1139
|
+
|
|
1140
|
+
# Degradation-plan reason codes (stable strings for log tabulation; closed set,
|
|
1141
|
+
# mirrored by the canonical `_MIDDLE_OUT_REASON_ENUM`).
|
|
1142
|
+
MO_REASON_DISABLED = "disabled" # feature OFF (env unset/invalid)
|
|
1143
|
+
MO_REASON_NO_OVERFLOW = "no_overflow" # already within budget — nothing to do
|
|
1144
|
+
MO_REASON_DEGRADED = "degraded" # ladder reclaimed enough → fits now
|
|
1145
|
+
MO_REASON_FAILED = "failed" # ladder exhausted, still over budget
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
class MiddleOutPolicy:
|
|
1149
|
+
"""Config for the middle-out degradation ladder.
|
|
1150
|
+
|
|
1151
|
+
Stateless by design — the host owns the message list and applies the plan.
|
|
1152
|
+
This object only holds the three knobs + the (constant) ladder.
|
|
1153
|
+
"""
|
|
1154
|
+
|
|
1155
|
+
def __init__(
|
|
1156
|
+
self,
|
|
1157
|
+
keep_floor_pct: int,
|
|
1158
|
+
protect_last: int,
|
|
1159
|
+
min_msg_tokens: int,
|
|
1160
|
+
) -> None:
|
|
1161
|
+
# Clamp to sane, fail-open values (never raise on a bad number). The
|
|
1162
|
+
# keep-floor is a percent in [1, 100] (0 would allow dropping a whole
|
|
1163
|
+
# message — middle-out always keeps SOMETHING, so floor is >= 1).
|
|
1164
|
+
floor = _clamp_pct(keep_floor_pct, DEFAULT_MIDDLE_OUT_KEEP_FLOOR_PCT)
|
|
1165
|
+
self.keep_floor_pct = floor if floor >= 1 else 1
|
|
1166
|
+
self.protect_last = _clamp_nonneg_int(
|
|
1167
|
+
protect_last, DEFAULT_MIDDLE_OUT_PROTECT_LAST)
|
|
1168
|
+
self.min_msg_tokens = _clamp_nonneg_int(
|
|
1169
|
+
min_msg_tokens, DEFAULT_MIDDLE_OUT_MIN_MSG_TOKENS)
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
def load_middle_out_policy_from_env(
|
|
1173
|
+
env: Optional[Dict[str, str]] = None,
|
|
1174
|
+
) -> Optional[MiddleOutPolicy]:
|
|
1175
|
+
"""Build a MiddleOutPolicy from env, or None when the feature is OFF.
|
|
1176
|
+
|
|
1177
|
+
OFF (returns None) unless `CEO_MIDDLE_OUT_DEGRADE` is set to an int in
|
|
1178
|
+
(0, 100] (the per-message keep-floor percent). Other knobs fall back to
|
|
1179
|
+
documented defaults when unset/invalid. Fail-open: never raises.
|
|
1180
|
+
"""
|
|
1181
|
+
floor = _env_int(ENV_MIDDLE_OUT_DEGRADE, env)
|
|
1182
|
+
if floor is None or floor <= 0 or floor > 100:
|
|
1183
|
+
return None # default-OFF
|
|
1184
|
+
protect = _env_int(ENV_MIDDLE_OUT_PROTECT_LAST, env)
|
|
1185
|
+
min_tokens = _env_int(ENV_MIDDLE_OUT_MIN_MSG_TOKENS, env)
|
|
1186
|
+
return MiddleOutPolicy(
|
|
1187
|
+
keep_floor_pct=floor,
|
|
1188
|
+
protect_last=protect if protect is not None else DEFAULT_MIDDLE_OUT_PROTECT_LAST,
|
|
1189
|
+
min_msg_tokens=min_tokens if min_tokens is not None else DEFAULT_MIDDLE_OUT_MIN_MSG_TOKENS,
|
|
1190
|
+
)
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
def _message_is_pinned(record: Any) -> bool:
|
|
1194
|
+
"""True if a message record is explicitly pinned / kept-in-model.
|
|
1195
|
+
|
|
1196
|
+
A mapping carrying ``pinned``-truthy or ``agent_visible`` is NEVER degraded
|
|
1197
|
+
(the dual-visibility D3 marker + an explicit pin both protect a message).
|
|
1198
|
+
Anything we cannot interpret is treated as NOT pinned (fail-open: we never
|
|
1199
|
+
refuse to consider a message just because it lacks a flag — but see the
|
|
1200
|
+
size/protect-window gates which independently protect it).
|
|
1201
|
+
"""
|
|
1202
|
+
if isinstance(record, dict):
|
|
1203
|
+
if record.get("pinned"):
|
|
1204
|
+
return True
|
|
1205
|
+
if record.get("agent_visible") is True:
|
|
1206
|
+
return True
|
|
1207
|
+
return False
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
def _message_content(record: Any) -> Optional[str]:
|
|
1211
|
+
"""Best-effort text content of one message record, or None.
|
|
1212
|
+
|
|
1213
|
+
Accepts a mapping with a ``content`` (preferred) or ``text`` str field, or a
|
|
1214
|
+
bare str. Returns None when no text can be derived (the record is then never
|
|
1215
|
+
degraded — fail-open: we never elide content we cannot read).
|
|
1216
|
+
"""
|
|
1217
|
+
if isinstance(record, str):
|
|
1218
|
+
return record
|
|
1219
|
+
if isinstance(record, dict):
|
|
1220
|
+
for key in ("content", "text"):
|
|
1221
|
+
v = record.get(key)
|
|
1222
|
+
if isinstance(v, str):
|
|
1223
|
+
return v
|
|
1224
|
+
return None
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
def _message_token_size(record: Any) -> Optional[int]:
|
|
1228
|
+
"""Best-effort estimated token size of one message record.
|
|
1229
|
+
|
|
1230
|
+
Prefers an explicit ``est_tokens`` / ``tokens`` field; else estimates from
|
|
1231
|
+
the text content length (chars/4). Returns None when no size can be derived
|
|
1232
|
+
(the record is then treated as below-floor and never degraded).
|
|
1233
|
+
"""
|
|
1234
|
+
if isinstance(record, bool):
|
|
1235
|
+
return None
|
|
1236
|
+
if isinstance(record, int):
|
|
1237
|
+
return record if record >= 0 else None
|
|
1238
|
+
if isinstance(record, dict):
|
|
1239
|
+
for key in ("est_tokens", "tokens"):
|
|
1240
|
+
if key in record:
|
|
1241
|
+
try:
|
|
1242
|
+
n = int(record[key])
|
|
1243
|
+
except (TypeError, ValueError):
|
|
1244
|
+
return None
|
|
1245
|
+
return n if n >= 0 else None
|
|
1246
|
+
if "chars" in record:
|
|
1247
|
+
try:
|
|
1248
|
+
c = int(record["chars"])
|
|
1249
|
+
except (TypeError, ValueError):
|
|
1250
|
+
return None
|
|
1251
|
+
return estimate_tokens(c) if c >= 0 else None
|
|
1252
|
+
text = _message_content(record)
|
|
1253
|
+
if text is not None:
|
|
1254
|
+
return estimate_tokens(len(text))
|
|
1255
|
+
return None
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
def _elide_middle(text: str, drop_fraction: float, keep_floor_pct: int) -> Tuple[str, int]:
|
|
1259
|
+
"""Drop the MIDDLE of `text`, keeping head+tail. Returns (new_text, chars_dropped).
|
|
1260
|
+
|
|
1261
|
+
`drop_fraction` is the TARGET fraction (0..1) of chars to remove; the actual
|
|
1262
|
+
removal is clamped so the kept fraction never falls below `keep_floor_pct`%.
|
|
1263
|
+
The kept portion is split as evenly as possible head/tail (head gets the odd
|
|
1264
|
+
char on an odd split). A token-cheap elision marker replaces the gap.
|
|
1265
|
+
|
|
1266
|
+
Fail-open: a non-str, empty, or degenerate input returns the text unchanged
|
|
1267
|
+
with 0 dropped (never raises).
|
|
1268
|
+
"""
|
|
1269
|
+
if not isinstance(text, str) or not text:
|
|
1270
|
+
return text, 0
|
|
1271
|
+
total = len(text)
|
|
1272
|
+
try:
|
|
1273
|
+
frac = float(drop_fraction)
|
|
1274
|
+
except (TypeError, ValueError):
|
|
1275
|
+
return text, 0
|
|
1276
|
+
if frac <= 0:
|
|
1277
|
+
return text, 0
|
|
1278
|
+
if frac > 1:
|
|
1279
|
+
frac = 1.0
|
|
1280
|
+
# Clamp the drop so the kept fraction stays at/above the keep-floor.
|
|
1281
|
+
max_drop_frac = max(0.0, 1.0 - (keep_floor_pct / 100.0))
|
|
1282
|
+
eff_frac = min(frac, max_drop_frac)
|
|
1283
|
+
drop_chars = int(total * eff_frac)
|
|
1284
|
+
if drop_chars <= 0:
|
|
1285
|
+
return text, 0
|
|
1286
|
+
keep_chars = total - drop_chars
|
|
1287
|
+
if keep_chars <= 0:
|
|
1288
|
+
# Degenerate (keep-floor 0 path defended elsewhere) — keep 1 char head.
|
|
1289
|
+
keep_chars = 1
|
|
1290
|
+
drop_chars = total - 1
|
|
1291
|
+
if drop_chars <= 0:
|
|
1292
|
+
return text, 0
|
|
1293
|
+
head_len = (keep_chars + 1) // 2 # head gets the odd char
|
|
1294
|
+
tail_len = keep_chars - head_len
|
|
1295
|
+
head = text[:head_len]
|
|
1296
|
+
tail = text[total - tail_len:] if tail_len > 0 else ""
|
|
1297
|
+
marker = MIDDLE_OUT_ELISION_MARKER.format(n=drop_chars)
|
|
1298
|
+
new_text = head + marker + tail
|
|
1299
|
+
# Report the NET char delta actually removed (the marker adds a few back).
|
|
1300
|
+
net_dropped = total - len(new_text)
|
|
1301
|
+
if net_dropped <= 0:
|
|
1302
|
+
# The marker was longer than what we dropped (tiny message) — no-op.
|
|
1303
|
+
return text, 0
|
|
1304
|
+
return new_text, net_dropped
|
|
1305
|
+
|
|
1306
|
+
|
|
1307
|
+
def decide_middle_out_degradation(
|
|
1308
|
+
messages: Any,
|
|
1309
|
+
budget_tokens: Any,
|
|
1310
|
+
*,
|
|
1311
|
+
policy: Optional[MiddleOutPolicy] = None,
|
|
1312
|
+
env: Optional[Dict[str, str]] = None,
|
|
1313
|
+
) -> Dict[str, Any]:
|
|
1314
|
+
"""Decide which messages to degrade middle-out, and at which ladder rung.
|
|
1315
|
+
|
|
1316
|
+
Pure + side-effect-free + fail-open. PROTECTS the last N + pinned messages.
|
|
1317
|
+
Does NOT mutate `messages` and does NOT perform the elision — it returns a
|
|
1318
|
+
plan that `apply_middle_out_degradation` (or the host) executes.
|
|
1319
|
+
|
|
1320
|
+
Parameters
|
|
1321
|
+
----------
|
|
1322
|
+
messages
|
|
1323
|
+
An ordered sequence of message records, OLDEST FIRST (index 0 is the
|
|
1324
|
+
oldest, index ``len-1`` the most recent). Each record may be a mapping
|
|
1325
|
+
carrying ``content``/``text`` and/or a size (``est_tokens`` / ``tokens``
|
|
1326
|
+
/ ``chars``), or a bare str. The order determines the protect-last-N
|
|
1327
|
+
window; the host supplies it.
|
|
1328
|
+
budget_tokens
|
|
1329
|
+
The token budget the assembled context must fit within (e.g. the model
|
|
1330
|
+
window minus a safety margin). Overflow = sum(sizes) > budget.
|
|
1331
|
+
policy
|
|
1332
|
+
Explicit policy; when None, derived from `env` (default-OFF if the
|
|
1333
|
+
keep-floor env is unset/invalid).
|
|
1334
|
+
|
|
1335
|
+
Returns a plan dict (never raises):
|
|
1336
|
+
{
|
|
1337
|
+
"enabled": bool, # feature active
|
|
1338
|
+
"reason": <MO_REASON_*>, # stable plan-level reason code
|
|
1339
|
+
"rung": int, # ladder rung reached (-1 if none entered)
|
|
1340
|
+
"degraded": [ # per-message degradation directives
|
|
1341
|
+
{"index": int, "drop_fraction": float}, ...
|
|
1342
|
+
],
|
|
1343
|
+
"degraded_count": int,
|
|
1344
|
+
"reclaim_tokens": int, # est tokens the plan would reclaim
|
|
1345
|
+
"total_tokens": int, # sum of message sizes (pre-degrade)
|
|
1346
|
+
"budget_tokens": int, # the budget projected against
|
|
1347
|
+
"fits_after": bool, # projected to fit after degradation
|
|
1348
|
+
"protected_count": int, # last-N + pinned + below-floor skips
|
|
1349
|
+
"protect_last": int|None,
|
|
1350
|
+
"min_msg_tokens": int|None,
|
|
1351
|
+
"keep_floor_pct": int|None,
|
|
1352
|
+
"ladder_len": int,
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
NO payload echo: the plan carries ONLY integer indices + token totals + a
|
|
1356
|
+
rung integer + a float fraction + closed reason codes. It NEVER includes any
|
|
1357
|
+
message text, tool name, agent name, file path, or command bytes. The
|
|
1358
|
+
canonical emit (staged proposal) scrubs to the same closed-field allowlist.
|
|
1359
|
+
"""
|
|
1360
|
+
plan: Dict[str, Any] = {
|
|
1361
|
+
"enabled": False,
|
|
1362
|
+
"reason": MO_REASON_DISABLED,
|
|
1363
|
+
"rung": -1,
|
|
1364
|
+
"degraded": [],
|
|
1365
|
+
"degraded_count": 0,
|
|
1366
|
+
"reclaim_tokens": 0,
|
|
1367
|
+
"total_tokens": 0,
|
|
1368
|
+
"budget_tokens": 0,
|
|
1369
|
+
"fits_after": True,
|
|
1370
|
+
"protected_count": 0,
|
|
1371
|
+
"protect_last": None,
|
|
1372
|
+
"min_msg_tokens": None,
|
|
1373
|
+
"keep_floor_pct": None,
|
|
1374
|
+
"ladder_len": len(MIDDLE_OUT_LADDER),
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
if policy is None:
|
|
1378
|
+
policy = load_middle_out_policy_from_env(env)
|
|
1379
|
+
if policy is None:
|
|
1380
|
+
return plan # default-OFF — disabled plan
|
|
1381
|
+
|
|
1382
|
+
plan["enabled"] = True
|
|
1383
|
+
plan["protect_last"] = policy.protect_last
|
|
1384
|
+
plan["min_msg_tokens"] = policy.min_msg_tokens
|
|
1385
|
+
plan["keep_floor_pct"] = policy.keep_floor_pct
|
|
1386
|
+
|
|
1387
|
+
# Normalize the budget (fail-open: a bad/<=0 budget ⇒ disabled-ish no-op).
|
|
1388
|
+
try:
|
|
1389
|
+
budget = int(budget_tokens)
|
|
1390
|
+
except (TypeError, ValueError):
|
|
1391
|
+
budget = 0
|
|
1392
|
+
if budget <= 0:
|
|
1393
|
+
plan["reason"] = MO_REASON_NO_OVERFLOW
|
|
1394
|
+
return plan
|
|
1395
|
+
plan["budget_tokens"] = budget
|
|
1396
|
+
|
|
1397
|
+
# Normalize the messages list (fail-open: a non-sequence ⇒ empty).
|
|
1398
|
+
try:
|
|
1399
|
+
items = list(messages)
|
|
1400
|
+
except TypeError:
|
|
1401
|
+
items = []
|
|
1402
|
+
total_msgs = len(items)
|
|
1403
|
+
if total_msgs == 0:
|
|
1404
|
+
plan["reason"] = MO_REASON_NO_OVERFLOW
|
|
1405
|
+
return plan
|
|
1406
|
+
|
|
1407
|
+
# Size every message; sum the total (None-sized rows count as 0 — they are
|
|
1408
|
+
# never degraded so they cannot help, but they DO occupy real budget the
|
|
1409
|
+
# host is responsible for; we conservatively count what we can size).
|
|
1410
|
+
sizes: List[Optional[int]] = [_message_token_size(m) for m in items]
|
|
1411
|
+
total_tokens = sum(s for s in sizes if isinstance(s, int))
|
|
1412
|
+
plan["total_tokens"] = total_tokens
|
|
1413
|
+
|
|
1414
|
+
# No overflow → nothing to do (the common, cheap path).
|
|
1415
|
+
if total_tokens <= budget:
|
|
1416
|
+
plan["reason"] = MO_REASON_NO_OVERFLOW
|
|
1417
|
+
return plan
|
|
1418
|
+
|
|
1419
|
+
overflow = total_tokens - budget
|
|
1420
|
+
|
|
1421
|
+
# Determine the protected window: the last `protect_last` indices + any
|
|
1422
|
+
# pinned message + any below-floor (too-small to bother) message.
|
|
1423
|
+
protect_last = policy.protect_last
|
|
1424
|
+
protect_from = max(0, total_msgs - protect_last) if protect_last > 0 else total_msgs
|
|
1425
|
+
|
|
1426
|
+
# Eligible = age-eligible (before protect window) AND not pinned AND big
|
|
1427
|
+
# enough to bother (>= min_msg_tokens AND sizeable). Build (index, size),
|
|
1428
|
+
# LARGEST FIRST so we degrade the heaviest messages first within a rung.
|
|
1429
|
+
eligible: List[Tuple[int, int]] = []
|
|
1430
|
+
protected = 0
|
|
1431
|
+
for idx in range(total_msgs):
|
|
1432
|
+
size = sizes[idx]
|
|
1433
|
+
if idx >= protect_from:
|
|
1434
|
+
protected += 1
|
|
1435
|
+
continue
|
|
1436
|
+
if _message_is_pinned(items[idx]):
|
|
1437
|
+
protected += 1
|
|
1438
|
+
continue
|
|
1439
|
+
if size is None or size < policy.min_msg_tokens:
|
|
1440
|
+
protected += 1
|
|
1441
|
+
continue
|
|
1442
|
+
eligible.append((idx, size))
|
|
1443
|
+
plan["protected_count"] = protected
|
|
1444
|
+
|
|
1445
|
+
if not eligible:
|
|
1446
|
+
# Nothing we are allowed to degrade — the ladder cannot help. FAILED
|
|
1447
|
+
# (the caller must summarize/compact/fail upstream).
|
|
1448
|
+
plan["reason"] = MO_REASON_FAILED
|
|
1449
|
+
plan["fits_after"] = False
|
|
1450
|
+
return plan
|
|
1451
|
+
|
|
1452
|
+
# Largest-first ordering within a rung.
|
|
1453
|
+
eligible.sort(key=lambda t: (-t[1], t[0]))
|
|
1454
|
+
|
|
1455
|
+
keep_floor = policy.keep_floor_pct
|
|
1456
|
+
# The most a single message can ever reclaim (its size × max-drop-fraction).
|
|
1457
|
+
max_drop_frac = max(0.0, 1.0 - (keep_floor / 100.0))
|
|
1458
|
+
|
|
1459
|
+
# Climb the ladder. At rung r, every eligible message is degraded at the
|
|
1460
|
+
# rung's TARGET fraction (clamped by the keep-floor). We stop the instant
|
|
1461
|
+
# the cumulative reclaim covers the overflow, recording the per-message
|
|
1462
|
+
# directive + the rung reached. Higher rungs subsume lower ones (we recompute
|
|
1463
|
+
# from scratch per rung so the directive is the FINAL fraction per message).
|
|
1464
|
+
best_plan: Optional[Tuple[int, List[Dict[str, Any]], int]] = None
|
|
1465
|
+
for rung, target_frac in enumerate(MIDDLE_OUT_LADDER):
|
|
1466
|
+
eff_frac = min(float(target_frac), max_drop_frac)
|
|
1467
|
+
if eff_frac <= 0:
|
|
1468
|
+
continue
|
|
1469
|
+
directives: List[Dict[str, Any]] = []
|
|
1470
|
+
reclaim = 0
|
|
1471
|
+
for idx, size in eligible:
|
|
1472
|
+
drop = int(size * eff_frac)
|
|
1473
|
+
if drop <= 0:
|
|
1474
|
+
continue
|
|
1475
|
+
directives.append({"index": idx, "drop_fraction": round(eff_frac, 4)})
|
|
1476
|
+
reclaim += drop
|
|
1477
|
+
if reclaim >= overflow:
|
|
1478
|
+
break
|
|
1479
|
+
if reclaim >= overflow:
|
|
1480
|
+
# This rung fits — record and STOP (do not climb further).
|
|
1481
|
+
best_plan = (rung, directives, reclaim)
|
|
1482
|
+
break
|
|
1483
|
+
# This rung did not fit; remember the most-aggressive attempt so far
|
|
1484
|
+
# (the last rung, fully applied) for the FAILED-but-best report.
|
|
1485
|
+
best_plan = (rung, directives, reclaim)
|
|
1486
|
+
|
|
1487
|
+
if best_plan is None:
|
|
1488
|
+
# No applicable rung (Codex pair-rail #3): e.g. keep-floor=100% -> max_drop_frac=0
|
|
1489
|
+
# -> every rung is skipped. Fail-OPEN with an empty FAILED plan instead of
|
|
1490
|
+
# crashing on the unpack below.
|
|
1491
|
+
plan["rung"] = -1
|
|
1492
|
+
plan["degraded"] = []
|
|
1493
|
+
plan["degraded_count"] = 0
|
|
1494
|
+
plan["reclaim_tokens"] = 0
|
|
1495
|
+
plan["fits_after"] = False
|
|
1496
|
+
plan["reason"] = MO_REASON_FAILED
|
|
1497
|
+
return plan
|
|
1498
|
+
rung, directives, reclaim = best_plan # type: ignore[misc]
|
|
1499
|
+
# Sort directives by index for a deterministic, log-friendly order.
|
|
1500
|
+
directives.sort(key=lambda d: d["index"])
|
|
1501
|
+
plan["rung"] = rung
|
|
1502
|
+
plan["degraded"] = directives
|
|
1503
|
+
plan["degraded_count"] = len(directives)
|
|
1504
|
+
plan["reclaim_tokens"] = reclaim
|
|
1505
|
+
fits = reclaim >= overflow
|
|
1506
|
+
plan["fits_after"] = fits
|
|
1507
|
+
plan["reason"] = MO_REASON_DEGRADED if fits else MO_REASON_FAILED
|
|
1508
|
+
return plan
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
def apply_middle_out_degradation(
|
|
1512
|
+
messages: Any,
|
|
1513
|
+
plan: Dict[str, Any],
|
|
1514
|
+
*,
|
|
1515
|
+
policy: Optional[MiddleOutPolicy] = None,
|
|
1516
|
+
env: Optional[Dict[str, str]] = None,
|
|
1517
|
+
) -> List[Any]:
|
|
1518
|
+
"""Apply a `decide_middle_out_degradation` plan, returning NEW messages.
|
|
1519
|
+
|
|
1520
|
+
Does NOT mutate the input list or its records — it returns a new list whose
|
|
1521
|
+
degraded entries are shallow copies with the middle of their text elided.
|
|
1522
|
+
Non-degraded messages are passed through unchanged (same object). Fail-open:
|
|
1523
|
+
a disabled/empty plan, a malformed message list, or a record we cannot read
|
|
1524
|
+
text from returns the input messages (as a list) untouched; never raises.
|
|
1525
|
+
|
|
1526
|
+
`policy`/`env` resolve the keep-floor used by the elision; when None they are
|
|
1527
|
+
derived from env (default-OFF ⇒ the input is returned unchanged).
|
|
1528
|
+
"""
|
|
1529
|
+
try:
|
|
1530
|
+
items = list(messages)
|
|
1531
|
+
except TypeError:
|
|
1532
|
+
return []
|
|
1533
|
+
|
|
1534
|
+
if not isinstance(plan, dict) or not plan.get("enabled"):
|
|
1535
|
+
return items
|
|
1536
|
+
directives = plan.get("degraded") or []
|
|
1537
|
+
if not directives:
|
|
1538
|
+
return items
|
|
1539
|
+
|
|
1540
|
+
if policy is None:
|
|
1541
|
+
policy = load_middle_out_policy_from_env(env)
|
|
1542
|
+
if policy is None:
|
|
1543
|
+
return items # feature OFF at apply time ⇒ no-op
|
|
1544
|
+
keep_floor = policy.keep_floor_pct
|
|
1545
|
+
|
|
1546
|
+
# Map index → drop_fraction for O(1) lookup.
|
|
1547
|
+
drop_by_index: Dict[int, float] = {}
|
|
1548
|
+
for d in directives:
|
|
1549
|
+
if not isinstance(d, dict):
|
|
1550
|
+
continue
|
|
1551
|
+
try:
|
|
1552
|
+
i = int(d.get("index"))
|
|
1553
|
+
f = float(d.get("drop_fraction"))
|
|
1554
|
+
except (TypeError, ValueError):
|
|
1555
|
+
continue
|
|
1556
|
+
drop_by_index[i] = f
|
|
1557
|
+
|
|
1558
|
+
out: List[Any] = []
|
|
1559
|
+
n = len(items)
|
|
1560
|
+
for idx in range(n):
|
|
1561
|
+
rec = items[idx]
|
|
1562
|
+
frac = drop_by_index.get(idx)
|
|
1563
|
+
if frac is None or frac <= 0:
|
|
1564
|
+
out.append(rec)
|
|
1565
|
+
continue
|
|
1566
|
+
text = _message_content(rec)
|
|
1567
|
+
if text is None:
|
|
1568
|
+
out.append(rec) # cannot read text ⇒ pass through unchanged
|
|
1569
|
+
continue
|
|
1570
|
+
new_text, dropped = _elide_middle(text, frac, keep_floor)
|
|
1571
|
+
if dropped <= 0:
|
|
1572
|
+
out.append(rec) # nothing actually dropped ⇒ pass through
|
|
1573
|
+
continue
|
|
1574
|
+
if isinstance(rec, str):
|
|
1575
|
+
out.append(new_text)
|
|
1576
|
+
elif isinstance(rec, dict):
|
|
1577
|
+
new_rec = dict(rec) # shallow copy — never mutate the input
|
|
1578
|
+
if "content" in rec and isinstance(rec.get("content"), str):
|
|
1579
|
+
new_rec["content"] = new_text
|
|
1580
|
+
elif "text" in rec and isinstance(rec.get("text"), str):
|
|
1581
|
+
new_rec["text"] = new_text
|
|
1582
|
+
else:
|
|
1583
|
+
new_rec["content"] = new_text
|
|
1584
|
+
new_rec["middle_out_degraded"] = True
|
|
1585
|
+
out.append(new_rec)
|
|
1586
|
+
else:
|
|
1587
|
+
out.append(rec)
|
|
1588
|
+
return out
|
|
1589
|
+
|
|
1590
|
+
|
|
1591
|
+
# ---------------------------------------------------------------------------
|
|
1592
|
+
# Optional P3 fold-in: tool-loop scan (ECC ecc-context-monitor idea)
|
|
1593
|
+
# ---------------------------------------------------------------------------
|
|
1594
|
+
|
|
1595
|
+
|
|
1596
|
+
def scan_tool_loops(
|
|
1597
|
+
audit_log: Path, min_run: int = 3,
|
|
1598
|
+
) -> Dict[str, Any]:
|
|
1599
|
+
"""Flag runs of N identical *consecutive* tool-calls in an audit-log.
|
|
1600
|
+
|
|
1601
|
+
Reads a JSONL audit-log read-only; for each line, derives a tool key from
|
|
1602
|
+
``tool_name`` (fallback ``action``). A run of ``>= min_run`` identical
|
|
1603
|
+
consecutive keys is flagged (an agent stuck in a tool loop). Advisory:
|
|
1604
|
+
tolerant of malformed lines, never blocks, never echoes payload content.
|
|
1605
|
+
Returns ``{loops: [...], lines_scanned, error?}``.
|
|
1606
|
+
"""
|
|
1607
|
+
text = _read_text(audit_log)
|
|
1608
|
+
if text is None:
|
|
1609
|
+
return {"loops": [], "lines_scanned": 0, "error": "unreadable"}
|
|
1610
|
+
|
|
1611
|
+
keys: List[str] = []
|
|
1612
|
+
scanned = 0
|
|
1613
|
+
for line in text.splitlines():
|
|
1614
|
+
line = line.strip()
|
|
1615
|
+
if not line:
|
|
1616
|
+
continue
|
|
1617
|
+
scanned += 1
|
|
1618
|
+
try:
|
|
1619
|
+
obj = json.loads(line)
|
|
1620
|
+
except (json.JSONDecodeError, ValueError):
|
|
1621
|
+
# Malformed line breaks the consecutive run (use a sentinel).
|
|
1622
|
+
keys.append("\x00malformed")
|
|
1623
|
+
continue
|
|
1624
|
+
if not isinstance(obj, dict):
|
|
1625
|
+
keys.append("\x00malformed")
|
|
1626
|
+
continue
|
|
1627
|
+
key = obj.get("tool_name") or obj.get("action") or "\x00unknown"
|
|
1628
|
+
keys.append(str(key))
|
|
1629
|
+
|
|
1630
|
+
loops: List[Dict[str, Any]] = []
|
|
1631
|
+
i = 0
|
|
1632
|
+
n = len(keys)
|
|
1633
|
+
while i < n:
|
|
1634
|
+
j = i
|
|
1635
|
+
while j < n and keys[j] == keys[i]:
|
|
1636
|
+
j += 1
|
|
1637
|
+
run_len = j - i
|
|
1638
|
+
key = keys[i]
|
|
1639
|
+
if run_len >= min_run and not key.startswith("\x00"):
|
|
1640
|
+
loops.append({
|
|
1641
|
+
"tool": key,
|
|
1642
|
+
"consecutive_count": run_len,
|
|
1643
|
+
"start_index": i,
|
|
1644
|
+
"message": (
|
|
1645
|
+
"{n} consecutive '{tool}' calls (>= {m}) — possible tool "
|
|
1646
|
+
"loop".format(n=run_len, tool=key, m=min_run)
|
|
1647
|
+
),
|
|
1648
|
+
})
|
|
1649
|
+
i = j
|
|
1650
|
+
|
|
1651
|
+
return {"loops": loops, "lines_scanned": scanned}
|
|
1652
|
+
|
|
1653
|
+
|
|
1654
|
+
# ---------------------------------------------------------------------------
|
|
1655
|
+
# Rendering
|
|
1656
|
+
# ---------------------------------------------------------------------------
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
def _render_human(report: Dict[str, Any], top: int) -> str:
|
|
1660
|
+
lines: List[str] = []
|
|
1661
|
+
lines.append("# context-budget report")
|
|
1662
|
+
lines.append("# heuristic: {}".format(report["heuristic"]))
|
|
1663
|
+
lines.append(
|
|
1664
|
+
"# grand total: ~{} est tokens across the always-loaded surface".format(
|
|
1665
|
+
report["grand_total_est_tokens"],
|
|
1666
|
+
)
|
|
1667
|
+
)
|
|
1668
|
+
lines.append("")
|
|
1669
|
+
lines.append("## per-category")
|
|
1670
|
+
lines.append(" {:<12} {:>6} {:>8} {:>10}".format(
|
|
1671
|
+
"category", "files", "lines", "est_tok"))
|
|
1672
|
+
for c in report["categories"]:
|
|
1673
|
+
if c["category"] == CAT_MCP:
|
|
1674
|
+
extra = "servers={}".format(c.get("server_count", 0))
|
|
1675
|
+
if c.get("over_subscribed"):
|
|
1676
|
+
extra += " OVER-SUBSCRIBED"
|
|
1677
|
+
lines.append(" {:<12} {:>6} {:>8} {:>10} {}".format(
|
|
1678
|
+
c["category"], c["file_count"], "-", "-", extra))
|
|
1679
|
+
else:
|
|
1680
|
+
lines.append(" {:<12} {:>6} {:>8} {:>10}".format(
|
|
1681
|
+
c["category"], c["file_count"], c["total_lines"], c["est_tokens"]))
|
|
1682
|
+
lines.append("")
|
|
1683
|
+
|
|
1684
|
+
lines.append("## top {} reduction candidates (by est tokens)".format(top))
|
|
1685
|
+
if not report["top_candidates"]:
|
|
1686
|
+
lines.append(" (none — no files inventoried)")
|
|
1687
|
+
else:
|
|
1688
|
+
for e in report["top_candidates"]:
|
|
1689
|
+
lines.append(" ~{:>7} tok {:>5}L [{}] {}".format(
|
|
1690
|
+
e["est_tokens"], e["lines"], e["category"], e["path"]))
|
|
1691
|
+
lines.append("")
|
|
1692
|
+
|
|
1693
|
+
lines.append("## flags ({} total)".format(report["flag_count"]))
|
|
1694
|
+
if not report["flags"]:
|
|
1695
|
+
lines.append(" OK: no heavy-file / bloat / over-subscription flags.")
|
|
1696
|
+
else:
|
|
1697
|
+
for f in report["flags"]:
|
|
1698
|
+
lines.append(" [{}] {}".format(f["kind"], f.get("path", f["category"])))
|
|
1699
|
+
lines.append(" {}".format(f["message"]))
|
|
1700
|
+
lines.append("")
|
|
1701
|
+
lines.append("# advisory only — this tool never blocks and never writes "
|
|
1702
|
+
"outside stdout.")
|
|
1703
|
+
return "\n".join(lines)
|
|
1704
|
+
|
|
1705
|
+
|
|
1706
|
+
def _render_loops_human(result: Dict[str, Any]) -> str:
|
|
1707
|
+
lines: List[str] = []
|
|
1708
|
+
lines.append("# tool-loop scan")
|
|
1709
|
+
lines.append("# lines scanned: {}".format(result.get("lines_scanned", 0)))
|
|
1710
|
+
if result.get("error"):
|
|
1711
|
+
lines.append("# error: {}".format(result["error"]))
|
|
1712
|
+
loops = result.get("loops", [])
|
|
1713
|
+
if not loops:
|
|
1714
|
+
lines.append(" OK: no tool loops detected.")
|
|
1715
|
+
else:
|
|
1716
|
+
for lp in loops:
|
|
1717
|
+
lines.append(" [tool_loop] {}".format(lp["message"]))
|
|
1718
|
+
lines.append("")
|
|
1719
|
+
lines.append("# advisory only.")
|
|
1720
|
+
return "\n".join(lines)
|
|
1721
|
+
|
|
1722
|
+
|
|
1723
|
+
# ---------------------------------------------------------------------------
|
|
1724
|
+
# CLI
|
|
1725
|
+
# ---------------------------------------------------------------------------
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
def _cli(argv: List[str]) -> int:
|
|
1729
|
+
parser = argparse.ArgumentParser(
|
|
1730
|
+
description="ceo-orchestration context-budget audit (advisory, "
|
|
1731
|
+
"read-only, never blocks)",
|
|
1732
|
+
)
|
|
1733
|
+
parser.add_argument(
|
|
1734
|
+
"--repo-root", default=".", help="project root (default: cwd)")
|
|
1735
|
+
parser.add_argument(
|
|
1736
|
+
"--json", action="store_true", help="machine-readable JSON output")
|
|
1737
|
+
parser.add_argument(
|
|
1738
|
+
"--top", type=int, default=10,
|
|
1739
|
+
help="how many top reduction candidates to rank (default: 10)")
|
|
1740
|
+
parser.add_argument(
|
|
1741
|
+
"--strict", action="store_true",
|
|
1742
|
+
help="exit 1 if any flag fires (opt-in advisory CI lint)")
|
|
1743
|
+
parser.add_argument(
|
|
1744
|
+
"--tool-loop-scan", metavar="AUDIT_LOG", default=None,
|
|
1745
|
+
help="(P3) flag N identical consecutive tool-calls in an audit-log "
|
|
1746
|
+
"JSONL file, then exit")
|
|
1747
|
+
parser.add_argument(
|
|
1748
|
+
"--loop-min", type=int, default=3,
|
|
1749
|
+
help="min consecutive identical tool-calls to flag a loop (default: 3)")
|
|
1750
|
+
# PLAN-133 D1 — auto-compaction decision probe (advisory; default-OFF unless
|
|
1751
|
+
# CEO_AUTO_COMPACT_THRESHOLD is set in the environment).
|
|
1752
|
+
parser.add_argument(
|
|
1753
|
+
"--compact-decision", action="store_true",
|
|
1754
|
+
help="(D1) print the proactive auto-compaction decision for a context "
|
|
1755
|
+
"snapshot, then exit. Default-OFF: requires CEO_AUTO_COMPACT_THRESHOLD.")
|
|
1756
|
+
parser.add_argument("--used-tokens", type=int, default=None,
|
|
1757
|
+
help="(D1) current context usage in tokens")
|
|
1758
|
+
parser.add_argument("--window-tokens", type=int, default=None,
|
|
1759
|
+
help="(D1) model context window in tokens")
|
|
1760
|
+
parser.add_argument("--reclaimable-tokens", type=int, default=None,
|
|
1761
|
+
help="(D1) estimated tokens a compaction would free")
|
|
1762
|
+
parser.add_argument("--armed", dest="armed", action="store_true", default=True,
|
|
1763
|
+
help="(D1) re-arm flag is set (default)")
|
|
1764
|
+
parser.add_argument("--disarmed", dest="armed", action="store_false",
|
|
1765
|
+
help="(D1) re-arm flag is cleared (post-compaction)")
|
|
1766
|
+
parser.add_argument("--turns-since-compaction", type=int, default=None,
|
|
1767
|
+
help="(D1) turns elapsed since the last compaction")
|
|
1768
|
+
# PLAN-133 D2 — oldest-verbose-output summarization decision probe
|
|
1769
|
+
# (advisory; default-OFF unless CEO_SUMMARIZE_OLDEST is set). Reads an
|
|
1770
|
+
# ordered list of per-output token sizes (oldest first) from a JSON file or
|
|
1771
|
+
# inline, and prints the summarization plan, then exits.
|
|
1772
|
+
parser.add_argument(
|
|
1773
|
+
"--summarize-decision", action="store_true",
|
|
1774
|
+
help="(D2) print the oldest-verbose-output summarization plan for a "
|
|
1775
|
+
"list of subagent output token-sizes, then exit. Default-OFF: "
|
|
1776
|
+
"requires CEO_SUMMARIZE_OLDEST.")
|
|
1777
|
+
parser.add_argument(
|
|
1778
|
+
"--output-sizes", metavar="JSON", default=None,
|
|
1779
|
+
help="(D2) JSON array of per-output est-token sizes (OLDEST FIRST), "
|
|
1780
|
+
"e.g. '[12000, 800, 30000, 500]'")
|
|
1781
|
+
parser.add_argument(
|
|
1782
|
+
"--output-sizes-file", metavar="PATH", default=None,
|
|
1783
|
+
help="(D2) path to a JSON file holding the per-output size array")
|
|
1784
|
+
# PLAN-133 D5 — middle-out degradation ladder decision probe (advisory;
|
|
1785
|
+
# default-OFF unless CEO_MIDDLE_OUT_DEGRADE is set). Reads an ordered list of
|
|
1786
|
+
# per-message token sizes (oldest first) + a budget, and prints the
|
|
1787
|
+
# degradation plan, then exits. Decision only — never elides anything.
|
|
1788
|
+
parser.add_argument(
|
|
1789
|
+
"--middle-out-decision", action="store_true",
|
|
1790
|
+
help="(D5) print the middle-out degradation plan for a list of message "
|
|
1791
|
+
"token-sizes + a token budget, then exit. Default-OFF: requires "
|
|
1792
|
+
"CEO_MIDDLE_OUT_DEGRADE.")
|
|
1793
|
+
parser.add_argument(
|
|
1794
|
+
"--message-sizes", metavar="JSON", default=None,
|
|
1795
|
+
help="(D5) JSON array of per-message est-token sizes (OLDEST FIRST), "
|
|
1796
|
+
"e.g. '[50000, 800, 50000, 500]'")
|
|
1797
|
+
parser.add_argument(
|
|
1798
|
+
"--message-sizes-file", metavar="PATH", default=None,
|
|
1799
|
+
help="(D5) path to a JSON file holding the per-message size array")
|
|
1800
|
+
parser.add_argument(
|
|
1801
|
+
"--budget-tokens", type=int, default=None,
|
|
1802
|
+
help="(D5) the token budget the assembled context must fit within")
|
|
1803
|
+
args = parser.parse_args(argv)
|
|
1804
|
+
|
|
1805
|
+
# Clamp a negative --top to 0 (least-surprising): a negative limit would
|
|
1806
|
+
# otherwise SKIP the slice and return ALL candidates plus print a
|
|
1807
|
+
# nonsensical "top -N" header. 0 cleanly means "rank nothing".
|
|
1808
|
+
if args.top is not None and args.top < 0:
|
|
1809
|
+
args.top = 0
|
|
1810
|
+
|
|
1811
|
+
# D1 fold-in mode — independent of the inventory. Advisory + read-only:
|
|
1812
|
+
# prints the decision dict, never compacts, never emits, always exit 0.
|
|
1813
|
+
if args.compact_decision:
|
|
1814
|
+
decision = decide_compaction(
|
|
1815
|
+
args.used_tokens,
|
|
1816
|
+
args.window_tokens,
|
|
1817
|
+
reclaimable_tokens=args.reclaimable_tokens,
|
|
1818
|
+
armed=args.armed,
|
|
1819
|
+
turns_since_last_compaction=args.turns_since_compaction,
|
|
1820
|
+
)
|
|
1821
|
+
print(json.dumps(decision, indent=2))
|
|
1822
|
+
return 0
|
|
1823
|
+
|
|
1824
|
+
# D2 fold-in mode — independent of the inventory. Advisory + read-only:
|
|
1825
|
+
# prints the summarization plan, never summarizes, never emits, exit 0.
|
|
1826
|
+
if args.summarize_decision:
|
|
1827
|
+
sizes: Any = []
|
|
1828
|
+
raw = None
|
|
1829
|
+
if args.output_sizes_file:
|
|
1830
|
+
raw = _read_text(Path(args.output_sizes_file))
|
|
1831
|
+
elif args.output_sizes is not None:
|
|
1832
|
+
raw = args.output_sizes
|
|
1833
|
+
if raw is not None:
|
|
1834
|
+
try:
|
|
1835
|
+
sizes = json.loads(raw)
|
|
1836
|
+
except (json.JSONDecodeError, ValueError):
|
|
1837
|
+
sizes = [] # fail-open: malformed input ⇒ empty (disabled-ish)
|
|
1838
|
+
plan = decide_summarization(sizes)
|
|
1839
|
+
print(json.dumps(plan, indent=2))
|
|
1840
|
+
return 0
|
|
1841
|
+
|
|
1842
|
+
# D5 fold-in mode — independent of the inventory. Advisory + read-only:
|
|
1843
|
+
# prints the degradation plan, never elides, never emits, exit 0.
|
|
1844
|
+
if args.middle_out_decision:
|
|
1845
|
+
msg_sizes: Any = []
|
|
1846
|
+
raw = None
|
|
1847
|
+
if args.message_sizes_file:
|
|
1848
|
+
raw = _read_text(Path(args.message_sizes_file))
|
|
1849
|
+
elif args.message_sizes is not None:
|
|
1850
|
+
raw = args.message_sizes
|
|
1851
|
+
if raw is not None:
|
|
1852
|
+
try:
|
|
1853
|
+
msg_sizes = json.loads(raw)
|
|
1854
|
+
except (json.JSONDecodeError, ValueError):
|
|
1855
|
+
msg_sizes = [] # fail-open: malformed input ⇒ empty
|
|
1856
|
+
budget = args.budget_tokens if args.budget_tokens is not None else 0
|
|
1857
|
+
plan = decide_middle_out_degradation(msg_sizes, budget)
|
|
1858
|
+
print(json.dumps(plan, indent=2))
|
|
1859
|
+
return 0
|
|
1860
|
+
|
|
1861
|
+
# P3 fold-in mode — independent of the inventory.
|
|
1862
|
+
if args.tool_loop_scan is not None:
|
|
1863
|
+
result = scan_tool_loops(Path(args.tool_loop_scan), min_run=args.loop_min)
|
|
1864
|
+
if args.json:
|
|
1865
|
+
print(json.dumps(result, indent=2))
|
|
1866
|
+
else:
|
|
1867
|
+
print(_render_loops_human(result))
|
|
1868
|
+
# Advisory: exit 0 unless --strict and loops were found.
|
|
1869
|
+
if args.strict and result.get("loops"):
|
|
1870
|
+
return 1
|
|
1871
|
+
return 0
|
|
1872
|
+
|
|
1873
|
+
repo = Path(args.repo_root).resolve()
|
|
1874
|
+
report = build_inventory(repo, top=args.top)
|
|
1875
|
+
|
|
1876
|
+
if args.json:
|
|
1877
|
+
print(json.dumps(report, indent=2))
|
|
1878
|
+
else:
|
|
1879
|
+
print(_render_human(report, args.top))
|
|
1880
|
+
|
|
1881
|
+
if args.strict and report["flag_count"] > 0:
|
|
1882
|
+
return 1
|
|
1883
|
+
return 0
|
|
1884
|
+
|
|
1885
|
+
|
|
1886
|
+
if __name__ == "__main__":
|
|
1887
|
+
sys.exit(_cli(sys.argv[1:]))
|