@danmoisan/drm-copilot-mcp 1.1.22 → 1.1.24
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/out/mcp-server.js +18758 -12030
- package/package.json +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -1
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_test_files_count_against_500_cap.md +4 -4
- package/resources/claude-customizations/.claude/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/discovery-capability-sentinel.md +34 -0
- package/resources/claude-customizations/.claude/agents/feature-review.md +8 -0
- package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +101 -43
- package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +107 -43
- package/resources/claude-customizations/.claude/agents/orchestrator.md +1 -1
- package/resources/claude-customizations/.claude/agents/parallel-orchestrator.md +60 -6
- package/resources/claude-customizations/.claude/agents/parallel-planner.md +21 -1
- package/resources/claude-customizations/.claude/agents/powershell-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/pr-author.md +48 -7
- package/resources/claude-customizations/.claude/agents/python-typed-engineer.md +1 -1
- package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +117 -42
- package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +103 -43
- package/resources/claude-customizations/.claude/hooks/discovery-capability-probe.ps1 +102 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +69 -194
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-planning-gate.ps1 +87 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate-green-ci.ps1 +325 -0
- package/resources/claude-customizations/.claude/hooks/enforce-epic-merge-gate.ps1 +29 -7
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate-resolution.ps1 +23 -10
- package/resources/claude-customizations/.claude/hooks/enforce-epic-worktree-removal-gate.ps1 +29 -21
- package/resources/claude-customizations/.claude/hooks/enforce-file-size-limit.ps1 +244 -0
- package/resources/claude-customizations/.claude/hooks/enforce-model-routing-receipt.ps1 +51 -0
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +168 -48
- package/resources/claude-customizations/.claude/hooks/enforce-orchestration-preimplementation-gate.ps1 +1 -1
- package/resources/claude-customizations/.claude/hooks/enforce-parallel-worktree-removal-gate.ps1 +22 -11
- package/resources/claude-customizations/.claude/hooks/enforce-powershell-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-command-allowlist.ps1 +51 -4
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill-helpers.ps1 +72 -11
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.current-branch.ps1 +149 -0
- package/resources/claude-customizations/.claude/hooks/enforce-pr-author-skill.epic-base-branch.ps1 +4 -2
- package/resources/claude-customizations/.claude/hooks/enforce-python-batch-budget.ps1 +59 -20
- package/resources/claude-customizations/.claude/hooks/record-discovery-agent-start.ps1 +132 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +56 -212
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-feature-folder.ps1 +146 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output-rejection.ps1 +172 -0
- package/resources/claude-customizations/.claude/hooks/validate-orchestrator-output.ps1 +34 -4
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadius.psm1 +9 -3
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusAggregate.psm1 +154 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusCombination.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusExtraction.psm1 +1 -0
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusNormalization.psm1 +4 -2
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusScheduling.psm1 +63 -16
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusTokenShape.psm1 +56 -1
- package/resources/claude-customizations/.claude/lib/blast-radius/BlastRadiusWriteIntent.psm1 +4 -1
- package/resources/claude-customizations/.claude/lib/cleanup-manifest/CleanupWorktreeManifest.psm1 +33 -6
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/claude-customizations/.claude/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/claude-customizations/.claude/lib/discovery-validation/DiscoveryValidation.psm1 +188 -341
- package/resources/claude-customizations/.claude/lib/file-size-policy/FileSizePolicy.psm1 +434 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateFeatureFolderRecord.psm1 +166 -0
- package/resources/claude-customizations/.claude/lib/orchestrator-state/OrchestratorStateIssueAdoption.psm1 +8 -3
- package/resources/claude-customizations/.claude/lib/worktree-resolution/HookTargetWorktree.psm1 +391 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunRecordPath.psm1 +185 -0
- package/resources/claude-customizations/.claude/lib/worktree-resolution/WorktreeRunResolution.psm1 +11 -21
- package/resources/claude-customizations/.claude/rules/general-code-change.md +4 -1
- package/resources/claude-customizations/.claude/rules/orchestrator-state.md +29 -5
- package/resources/claude-customizations/.claude/rules/parallel-orchestration.md +152 -20
- package/resources/claude-customizations/.claude/rules/powershell.md +1 -1
- package/resources/claude-customizations/.claude/rules/shell.md +1 -1
- package/resources/claude-customizations/.claude/settings.json +36 -3
- package/resources/claude-customizations/.claude/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/claude-customizations/.claude/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +2 -2
- package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +28 -47
- package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +32 -48
- package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +28 -62
- package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +28 -45
- package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +28 -61
- package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +55 -139
- package/resources/claude-customizations/.claude/skills/execution-environment/SKILL.md +25 -10
- package/resources/claude-customizations/.claude/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/claude-customizations/.claude/skills/feature-promotion-lifecycle/SKILL.md +1 -0
- package/resources/claude-customizations/.claude/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/orchestrate/SKILL.md +15 -7
- package/resources/claude-customizations/.claude/skills/parallel-add/SKILL.md +25 -2
- package/resources/claude-customizations/.claude/skills/parallel-close/SKILL.md +11 -1
- package/resources/claude-customizations/.claude/skills/parallel-orchestrate/SKILL.md +124 -14
- package/resources/claude-customizations/.claude/skills/parallel-plan/SKILL.md +72 -7
- package/resources/claude-customizations/.claude/skills/parallel-remove/SKILL.md +15 -0
- package/resources/claude-customizations/.claude/skills/parallel-run/SKILL.md +6 -0
- package/resources/claude-customizations/.claude/skills/pr-author/SKILL.md +56 -9
- package/resources/claude-customizations/.claude/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/claude-customizations/.claude/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/claude-customizations/.claude/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/claude-customizations/.claude-variants/csharp-legacy/agents/csharp-typed-engineer.md +1 -1
- package/resources/claude-customizations/config/blast-radius.json +6 -5
- package/resources/claude-customizations/config/orchestration-routing.json +61 -1
- package/resources/claude-customizations/pack-manifests/core.json +40 -1
- package/resources/codex-and-agents-customizations/.agents/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/codex-and-agents-customizations/.agents/skills/atomic-planner/SKILL.md +7 -0
- package/resources/codex-and-agents-customizations/.agents/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/codex-and-agents-customizations/.agents/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execution-environment/SKILL.md +25 -10
- package/resources/codex-and-agents-customizations/.agents/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/codex-and-agents-customizations/.agents/skills/feature-promotion-lifecycle/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/feature-review/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/general-code-change/SKILL.md +4 -1
- package/resources/codex-and-agents-customizations/.agents/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/codex-and-agents-customizations/.agents/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/orchestrator-workflow/SKILL.md +8 -0
- package/resources/codex-and-agents-customizations/.agents/skills/powershell/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.agents/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/codex-and-agents-customizations/.agents/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/codex-and-agents-customizations/.agents/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/discovery-capability-sentinel.toml +51 -0
- package/resources/codex-and-agents-customizations/.codex/agents/feature-review.toml +8 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c1.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c2.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3-elevated.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c3.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst-c4.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/legacy-parity-analyst.toml +148 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c1.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c2.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3-elevated.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c3.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer-c4.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/migration-coverage-reviewer.toml +154 -0
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/powershell-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c1.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c2.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3-elevated.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c3.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer-c4.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/python-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c1.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c2.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3-elevated.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c3.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler-c4.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/requirements-reconciler.toml +164 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c1.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c2.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3-elevated.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c3.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst-c4.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/agents/runtime-characterization-analyst.toml +150 -0
- package/resources/codex-and-agents-customizations/.codex/config.toml +39 -3
- package/resources/codex-and-agents-customizations/.codex/hooks/codex-agent-profile-attestation.ps1 +22 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-capability-probe.ps1 +97 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/discovery-start-attestation.ps1 +171 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-codex-model-routing.ps1 +4 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-artifact-gate.ps1 +187 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-discovery-planning-gate.ps1 +149 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-file-size-limit.ps1 +282 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate-epic-scope.ps1 +239 -2
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-orchestration-preimplementation-gate.ps1 +6 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-powershell-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/enforce-python-batch-budget.ps1 +54 -15
- package/resources/codex-and-agents-customizations/.codex/hooks/file-size-policy.ps1 +421 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/hook-target-worktree.ps1 +369 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/record-subagent-routing-attestation.ps1 +8 -0
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-codex-subagent-routing.ps1 +22 -1
- package/resources/codex-and-agents-customizations/.codex/hooks/validate-discovery-agent-output.ps1 +178 -0
- package/resources/codex-and-agents-customizations/.codex/scripts/Resolve-CodexTopology.ps1 +11 -1
- package/resources/codex-and-agents-customizations/.codex-variants/csharp-legacy/agents/csharp-typed-engineer.toml +1 -1
- package/resources/codex-and-agents-customizations/AGENTS.md +4 -1
- package/resources/codex-and-agents-customizations/pack-manifests/core.json +65 -1
- package/resources/config/orchestration-routing.json +61 -1
- package/resources/customizations/.github/agents/commentary-remediation.agent.md +1 -1
- package/resources/customizations/.github/agents/discovery-capability-sentinel.agent.md +34 -0
- package/resources/customizations/.github/agents/legacy-parity-analyst.agent.md +122 -0
- package/resources/customizations/.github/agents/migration-coverage-reviewer.agent.md +128 -0
- package/resources/customizations/.github/agents/python-execution-only-typed.agent.md +1 -1
- package/resources/customizations/.github/agents/python-typed-engineer.agent.md +1 -1
- package/resources/customizations/.github/agents/requirements-reconciler.agent.md +138 -0
- package/resources/customizations/.github/agents/runtime-characterization-analyst.agent.md +124 -0
- package/resources/customizations/.github/hooks/discovery-agent-start.ps1 +139 -0
- package/resources/customizations/.github/hooks/discovery-agent-stop.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery-capability-probe.ps1 +98 -0
- package/resources/customizations/.github/hooks/discovery-planning.ps1 +91 -0
- package/resources/customizations/.github/hooks/discovery-pre-tool.ps1 +123 -0
- package/resources/customizations/.github/hooks/discovery.json +35 -0
- package/resources/customizations/.github/instructions/general-code-change.instructions.md +5 -2
- package/resources/customizations/.github/instructions/mermaid.instructions.md +85 -0
- package/resources/customizations/.github/instructions/powershell-code-change.instructions.md +1 -1
- package/resources/customizations/.github/prompts/execute-hard-lock.prompt.md +105 -0
- package/resources/customizations/.github/prompts/remediate-comments.prompt.md +1 -1
- package/resources/customizations/.github/skills/adjudicate-unspecified-behavior/SKILL.md +135 -0
- package/resources/customizations/.github/skills/characterize-runtime-behavior/SKILL.md +134 -0
- package/resources/customizations/.github/skills/discovery-behavior-reconciliation/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-coverage-ledger/SKILL.md +50 -0
- package/resources/customizations/.github/skills/discovery-parity-matrix/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-repo-inventory/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-runtime-characterization/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-validate-artifacts/SKILL.md +46 -0
- package/resources/customizations/.github/skills/discovery-workflow/SKILL.md +62 -0
- package/resources/customizations/.github/skills/execution-environment/SKILL.md +25 -10
- package/resources/customizations/.github/skills/extract-feature-contract/SKILL.md +133 -0
- package/resources/customizations/.github/skills/feature-review-workflow/SKILL.md +8 -0
- package/resources/customizations/.github/skills/generate-acceptance-scenarios/SKILL.md +132 -0
- package/resources/customizations/.github/skills/initialize-discovery-workspace/SKILL.md +131 -0
- package/resources/customizations/.github/skills/inventory-legacy-system/SKILL.md +131 -0
- package/resources/customizations/.github/skills/reconcile-parity-matrix/SKILL.md +131 -0
- package/resources/customizations/.github/skills/review-discovery-coverage/SKILL.md +129 -0
- package/resources/customizations/.github/skills/validate-discovery-artifacts/SKILL.md +127 -0
- package/resources/lib/codex-routing/CodexDeployment.psm1 +5 -1
- package/resources/lib/codex-routing/CodexDiscoveryRouting.psm1 +161 -0
- package/resources/lib/codex-routing/CodexTopology.psm1 +25 -2
- package/resources/lib/discovery-validation/DiscoveryAuthority.psd1 +90 -0
- package/resources/lib/discovery-validation/DiscoveryAuthority.psm1 +493 -0
- package/resources/lib/discovery-validation/DiscoveryAuthorization.psm1 +479 -0
- package/resources/lib/discovery-validation/DiscoveryCapability.psm1 +468 -0
- package/resources/lib/discovery-validation/DiscoveryEncoding.psm1 +156 -0
- package/resources/lib/discovery-validation/DiscoveryManifest.psm1 +384 -0
- package/resources/lib/discovery-validation/DiscoveryObservation.psm1 +217 -0
- package/resources/lib/discovery-validation/DiscoveryPayload.psm1 +276 -0
- package/resources/lib/discovery-validation/DiscoveryPlanning.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryRootGrant.psm1 +164 -0
- package/resources/lib/discovery-validation/DiscoveryStart.psm1 +440 -0
- package/resources/lib/discovery-validation/DiscoveryStartRecord.psm1 +296 -0
- package/resources/lib/discovery-validation/DiscoveryStop.psm1 +336 -0
- package/resources/lib/discovery-validation/DiscoveryToolRouting.psm1 +228 -0
- package/resources/powershell/PoshQC/PoshQC.Parallel.psm1 +452 -0
- package/resources/powershell/PoshQC/PoshQC.Shard.psm1 +106 -8
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +12 -0
- package/resources/powershell/PoshQC/PoshQC.psd1 +6 -1
- package/resources/powershell/PoshQC/PoshQC.psm1 +7 -1
- package/resources/powershell/PoshQC/README.md +20 -1
- package/resources/templates/policy_audit/code-review.yyyy-MM-ddTHH-mm.md +4 -4
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +4 -4
|
@@ -7,14 +7,28 @@
|
|
|
7
7
|
operation. When the target file is a Python file (.py), it decides whether the
|
|
8
8
|
change may proceed in direct mode.
|
|
9
9
|
|
|
10
|
-
Direct mode counts distinct production Python paths per Claude Code session
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The
|
|
17
|
-
|
|
10
|
+
Direct mode counts distinct production Python paths per Claude Code session and per
|
|
11
|
+
resolved target worktree, and repeated edits to the same file are counted once. The
|
|
12
|
+
4th distinct production path in one worktree is denied with a
|
|
13
|
+
PYTHON_LARGE_PATH_REQUIRED reason that instructs the caller to route the change
|
|
14
|
+
through /orchestrate.
|
|
15
|
+
|
|
16
|
+
The edited file is placed with Resolve-HookTargetWorktree from
|
|
17
|
+
.claude/lib/worktree-resolution/HookTargetWorktree.psm1. An absolute path resolves to
|
|
18
|
+
its nearest enclosing registered git worktree; a relative path, a path inside no
|
|
19
|
+
registered worktree, and an ambiguous result use the session root (the checkout that
|
|
20
|
+
holds this hook). The route is read from
|
|
21
|
+
artifacts/orchestration/orchestrator-state.json in the resolved target worktree.
|
|
22
|
+
The running set is kept under the session root, in
|
|
23
|
+
.claude/state/python-batch-budget.<session_id>.json when the resolved target worktree
|
|
24
|
+
is the session root and in
|
|
25
|
+
.claude/state/python-batch-budget.<session_id>.<worktree key>.json otherwise, where
|
|
26
|
+
the key comes from Get-HookTargetWorktreeKey; no state is written under another
|
|
27
|
+
worktree. A path under the root-level artifacts/ directory of the resolved target worktree
|
|
28
|
+
is gitignored scratch: it is allowed, consumes no slot, and writes no state. A
|
|
29
|
+
nested directory named artifacts elsewhere in the tree still counts.
|
|
30
|
+
|
|
31
|
+
The selected route is the
|
|
18
32
|
route_id value when that key is present, otherwise the path_selected value, and it
|
|
19
33
|
is usable only as a non-blank string. When the selected route is large,
|
|
20
34
|
remediation, or preparation and the checkpoint is not terminal (next_step is not
|
|
@@ -38,9 +52,9 @@
|
|
|
38
52
|
is composed into a file name, so a hostile id cannot escape the state
|
|
39
53
|
directory. Resolving the id never creates the state directory.
|
|
40
54
|
|
|
41
|
-
Candidate paths are contained to the resolved root. A candidate
|
|
42
|
-
outside it is discarded: the decision is 'allow', no slot is consumed,
|
|
43
|
-
state is written. Persisted entries that fail the same containment test are
|
|
55
|
+
Candidate paths are contained to the resolved target worktree root. A candidate
|
|
56
|
+
that resolves outside it is discarded: the decision is 'allow', no slot is consumed,
|
|
57
|
+
and no state is written. Persisted entries that fail the same containment test are
|
|
44
58
|
dropped when state is rehydrated, so a state file carried between worktrees
|
|
45
59
|
cannot spend this worktree's budget.
|
|
46
60
|
|
|
@@ -48,9 +62,12 @@
|
|
|
48
62
|
hookSpecificOutput.permissionDecision = 'deny' and exits 0. Files already counted
|
|
49
63
|
are always allowed through.
|
|
50
64
|
|
|
51
|
-
Known
|
|
52
|
-
|
|
53
|
-
|
|
65
|
+
Known limitations: an 8.3 short-name path, or a path reached through a junction,
|
|
66
|
+
that differs textually from the long path git reports matches no registered
|
|
67
|
+
worktree and falls back to the session root. A stale non-terminal large-path
|
|
68
|
+
checkpoint in a worktree exempts a later direct-mode session editing that worktree;
|
|
69
|
+
orchestrator checkpoint hygiene (issue #673) moves foreign checkpoints aside before
|
|
70
|
+
a new run.
|
|
54
71
|
|
|
55
72
|
.NOTES
|
|
56
73
|
Compatible with PowerShell 7+.
|
|
@@ -61,6 +78,7 @@ $script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot
|
|
|
61
78
|
|
|
62
79
|
|
|
63
80
|
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
81
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/worktree-resolution/HookTargetWorktree.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookTargetWorktree.psm1' -ErrorRecord $_ }
|
|
64
82
|
$script:PythonBatchBudgetRouteImportFailure = $null; try { . (Join-Path $PSScriptRoot 'enforce-batch-budget-route.ps1') } catch { $script:PythonBatchBudgetRouteImportFailure = 'enforce-batch-budget-route.ps1' }
|
|
65
83
|
|
|
66
84
|
function Test-PythonBatchBudgetPathInRoot {
|
|
@@ -354,7 +372,8 @@ function Invoke-PythonBatchBudgetHook {
|
|
|
354
372
|
[scriptblock] $WriteState = {
|
|
355
373
|
param([string] $Path, [System.Collections.IDictionary] $State)
|
|
356
374
|
$State | ConvertTo-Json -Depth 5 | Set-Content -Path $Path -Encoding UTF8
|
|
357
|
-
}
|
|
375
|
+
},
|
|
376
|
+
[scriptblock] $WorktreeListInvoker
|
|
358
377
|
)
|
|
359
378
|
|
|
360
379
|
$payload = Resolve-ClaudeHookToolInput -Raw $ToolInputRaw
|
|
@@ -376,6 +395,25 @@ function Invoke-PythonBatchBudgetHook {
|
|
|
376
395
|
}
|
|
377
396
|
if ($script:PythonBatchBudgetRouteImportFailure) { return Get-PythonBatchBudgetBlockDecision -Reason "PYTHON_LARGE_PATH_REQUIRED: the route helper '$($script:PythonBatchBudgetRouteImportFailure)' failed to load, so the batch budget for '$normalized' cannot be evaluated; the gate fails closed." }
|
|
378
397
|
|
|
398
|
+
# The file is evaluated against the registered worktree that holds it. The session root
|
|
399
|
+
# stays the fallback for a relative path, a path in no registered worktree, and an
|
|
400
|
+
# ambiguous result, which keeps today's checkpoint, containment, and state-file name.
|
|
401
|
+
$resolverArguments = @{ SessionRoot = $Root; FilePath = @($filePath) }
|
|
402
|
+
if ($PSBoundParameters.ContainsKey('WorktreeListInvoker')) { $resolverArguments['WorktreeListInvoker'] = $WorktreeListInvoker }
|
|
403
|
+
$resolution = Resolve-HookTargetWorktree @resolverArguments
|
|
404
|
+
$targetRoot = $Root
|
|
405
|
+
$isSessionRoot = $true
|
|
406
|
+
if (-not $resolution.Ambiguous -and $null -ne $resolution.WorktreeRoot -and -not [string]::Equals($resolution.WorktreeRoot, (ConvertTo-HookTargetWorktreeNormalizedPath -Path $Root), [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
407
|
+
$targetRoot = $resolution.WorktreeRoot
|
|
408
|
+
$isSessionRoot = $false
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
# The root-level artifacts/ directory is gitignored scratch, never a production file.
|
|
412
|
+
$relativePath = if ($normalized -match '^(/|[A-Za-z]:/)') { Get-HookTargetWorktreeRelativePath -Path $normalized -WorktreeRoot $targetRoot } else { $normalized }
|
|
413
|
+
if ($null -ne $relativePath -and $relativePath.StartsWith('artifacts/', [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
414
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
415
|
+
}
|
|
416
|
+
|
|
379
417
|
$stateDir = Join-Path -Path $Root -ChildPath '.claude/state'
|
|
380
418
|
|
|
381
419
|
# Resolved before the directory is ensured, because reading the session-id
|
|
@@ -386,11 +424,12 @@ function Invoke-PythonBatchBudgetHook {
|
|
|
386
424
|
-SessionIdFilePath (Join-Path -Path $stateDir -ChildPath 'current-session-id') `
|
|
387
425
|
-ReadSessionIdFile $ReadSessionIdFile
|
|
388
426
|
|
|
389
|
-
$
|
|
427
|
+
$stateLeaf = if ($isSessionRoot) { "python-batch-budget.$resolvedSessionId.json" } else { "python-batch-budget.$resolvedSessionId.$(Get-HookTargetWorktreeKey -WorktreeRoot $targetRoot).json" }
|
|
428
|
+
$stateFile = Join-Path -Path $stateDir -ChildPath $stateLeaf
|
|
390
429
|
|
|
391
430
|
# The checkpoint is read before any state operation, so the large path neither
|
|
392
431
|
# creates the state directory nor reads or writes the state file.
|
|
393
|
-
$checkpointPath = Join-Path -Path $
|
|
432
|
+
$checkpointPath = Join-Path -Path $targetRoot -ChildPath 'artifacts/orchestration/orchestrator-state.json'
|
|
394
433
|
$checkpointText = ''
|
|
395
434
|
try {
|
|
396
435
|
$checkpointText = [string](& $ReadCheckpoint $checkpointPath)
|
|
@@ -402,7 +441,7 @@ function Invoke-PythonBatchBudgetHook {
|
|
|
402
441
|
$isLargePath = Test-BatchBudgetLargePathRoute -CheckpointText $checkpointText
|
|
403
442
|
$observedRoute = Get-BatchBudgetSelectedRoute -CheckpointText $checkpointText
|
|
404
443
|
if ($isLargePath) {
|
|
405
|
-
return Invoke-PythonBatchBudgetDecision -FilePath $filePath -State (Get-PythonBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $
|
|
444
|
+
return Invoke-PythonBatchBudgetDecision -FilePath $filePath -State (Get-PythonBatchBudgetState -ProdCap $ProdCap) -StateFile $stateFile -Root $targetRoot -LargePathRoute
|
|
406
445
|
}
|
|
407
446
|
|
|
408
447
|
if (-not (& $TestPathExists $stateDir)) {
|
|
@@ -414,13 +453,13 @@ function Invoke-PythonBatchBudgetHook {
|
|
|
414
453
|
if (& $TestPathExists $stateFile) {
|
|
415
454
|
try {
|
|
416
455
|
$loaded = & $ReadState $stateFile | ConvertFrom-Json -ErrorAction Stop
|
|
417
|
-
$state = ConvertTo-PythonBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $
|
|
456
|
+
$state = ConvertTo-PythonBatchBudgetState -InputObject $loaded -ProdCap $ProdCap -Root $targetRoot
|
|
418
457
|
} catch {
|
|
419
458
|
Write-Verbose "Ignoring unreadable Python batch-budget state file '$stateFile': $($_.Exception.Message)"
|
|
420
459
|
}
|
|
421
460
|
}
|
|
422
461
|
|
|
423
|
-
$decision = Invoke-PythonBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $
|
|
462
|
+
$decision = Invoke-PythonBatchBudgetDecision -FilePath $filePath -State $state -StateFile $stateFile -Root $targetRoot -ObservedRoute $observedRoute
|
|
424
463
|
if ($decision.shouldWriteState) {
|
|
425
464
|
try {
|
|
426
465
|
& $WriteState $stateFile $decision.state
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Native SubagentStart attestation adapter for Claude Code discovery agents.
|
|
4
|
+
|
|
5
|
+
.DESCRIPTION
|
|
6
|
+
Invoked by the Claude Code SubagentStart hook. The hook reads the start envelope,
|
|
7
|
+
derives the launch context from the payload alone (session, the host-assigned
|
|
8
|
+
agent_id and agent_type, and the literal parent root), and takes its decision
|
|
9
|
+
from the shared DiscoveryStart module. The start is observational: Claude Code
|
|
10
|
+
does not let a SubagentStart hook prevent the agent from running.
|
|
11
|
+
|
|
12
|
+
- a start whose agent type is not a discovery specialist is left to the
|
|
13
|
+
ordinary and epic attestation path and produces no output;
|
|
14
|
+
- a discovery specialist is attested when the protected store holds exactly one
|
|
15
|
+
prepared discovery-invocation bound to this host, session, parent and agent
|
|
16
|
+
type and the activation, deployment, agent profile hash and capability pins
|
|
17
|
+
agree; the start-attestation is recorded and the invocation moves to started;
|
|
18
|
+
- a start that cannot be attested writes the DISCOVERY_START_ATTESTATION_BLOCKED:
|
|
19
|
+
reason as the SubagentStart system message; the PreToolUse adapter then binds
|
|
20
|
+
the prepared invocation at the first controlled call or denies every grant.
|
|
21
|
+
|
|
22
|
+
No orchestrator checkpoint is read or written. An envelope the hook cannot read
|
|
23
|
+
and a dependency that fails to load write the reason to stderr at exit 2
|
|
24
|
+
(issue #980).
|
|
25
|
+
|
|
26
|
+
.NOTES
|
|
27
|
+
Requires PowerShell 7+. Invokes NO external process and never reads a profile,
|
|
28
|
+
locator or payload field to decide identity or authority.
|
|
29
|
+
#>
|
|
30
|
+
[CmdletBinding()]
|
|
31
|
+
param()
|
|
32
|
+
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
33
|
+
|
|
34
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/hook-payload/HookPayload.psm1') -Force -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'HookPayload.psm1' -ErrorRecord $_ }
|
|
35
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
36
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
37
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
38
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
39
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStart.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStart.psm1' -ErrorRecord $_ }
|
|
40
|
+
|
|
41
|
+
$script:DiscoveryStartReasonPrefix = 'DISCOVERY_START_ATTESTATION_BLOCKED:'
|
|
42
|
+
$script:DiscoveryStartHandlerPath = $PSCommandPath
|
|
43
|
+
|
|
44
|
+
function Get-DiscoveryStartHandlerSha256 {
|
|
45
|
+
<#
|
|
46
|
+
.SYNOPSIS
|
|
47
|
+
Returns the SHA-256 of this handler's own bytes for the attestation writer record.
|
|
48
|
+
#>
|
|
49
|
+
[CmdletBinding()]
|
|
50
|
+
[OutputType([string])]
|
|
51
|
+
param([Parameter(Mandatory = $false)][AllowNull()][string]$HandlerPath = $script:DiscoveryStartHandlerPath)
|
|
52
|
+
|
|
53
|
+
if ([string]::IsNullOrEmpty($HandlerPath) -or -not (Test-Path -LiteralPath $HandlerPath -PathType Leaf)) {
|
|
54
|
+
return ('0' * 64)
|
|
55
|
+
}
|
|
56
|
+
return Get-DiscoveryBytesSha256Hex -Bytes ([System.IO.File]::ReadAllBytes($HandlerPath))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function Invoke-DiscoveryAgentStartDecision {
|
|
60
|
+
<#
|
|
61
|
+
.SYNOPSIS
|
|
62
|
+
Parses the SubagentStart envelope and returns the shared start outcome.
|
|
63
|
+
.DESCRIPTION
|
|
64
|
+
Returns the outcome object (Decision skip, observe or attest; Code; Reason;
|
|
65
|
+
Attestation; AttestationPath; Invocation). Every seam defaults to the real
|
|
66
|
+
host and is injectable so tests run over in-memory values. A recorded
|
|
67
|
+
dependency failure denies before the envelope is read.
|
|
68
|
+
#>
|
|
69
|
+
[CmdletBinding()]
|
|
70
|
+
[OutputType([pscustomobject])]
|
|
71
|
+
param(
|
|
72
|
+
[Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw,
|
|
73
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
74
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
75
|
+
[Parameter(Mandatory = $false)][AllowNull()][nullable[datetime]]$Now = $null,
|
|
76
|
+
[Parameter(Mandatory = $false)][AllowNull()][string]$Nonce = $null,
|
|
77
|
+
[Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null
|
|
78
|
+
)
|
|
79
|
+
if (Test-HookDependencyFailure) {
|
|
80
|
+
$reason = Get-HookDependencyFailureReason -ReasonPrefix $script:DiscoveryStartReasonPrefix
|
|
81
|
+
return [pscustomobject]@{ Decision = 'deny'; Code = 'DEPENDENCY'; Reason = $reason.Substring($script:DiscoveryStartReasonPrefix.Length).TrimStart(); Attestation = $null; AttestationPath = $null; Invocation = $null }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Seams resolve only after the dependency check so a missing module denies
|
|
85
|
+
# instead of raising while a default is evaluated.
|
|
86
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
87
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryStartStore }
|
|
88
|
+
if ($null -eq $Now) { $Now = [datetime]::UtcNow }
|
|
89
|
+
if ([string]::IsNullOrEmpty($Nonce)) { $Nonce = Get-DiscoveryAuthorizationNonceText }
|
|
90
|
+
|
|
91
|
+
$normalized = ConvertFrom-DiscoveryHostPayloadText -HostName 'claude-code' -Text $PayloadRaw
|
|
92
|
+
$parameters = @{
|
|
93
|
+
Normalized = $normalized; HostEnvironment = $HostEnvironment
|
|
94
|
+
HandlerSha256 = (Get-DiscoveryStartHandlerSha256); Store = $Store; Now = $Now; Nonce = $Nonce
|
|
95
|
+
}
|
|
96
|
+
if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
|
|
97
|
+
return Get-DiscoveryStartDecision @parameters
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function Invoke-DiscoveryAgentStartEntryPoint {
|
|
101
|
+
<#
|
|
102
|
+
.SYNOPSIS
|
|
103
|
+
Reads one SubagentStart payload, writes the hook output and returns the process exit code.
|
|
104
|
+
.DESCRIPTION
|
|
105
|
+
An unreadable envelope or a dependency failure writes its reason to stderr
|
|
106
|
+
and returns 2. An observed (unattested) start writes the SubagentStart output
|
|
107
|
+
JSON to stdout and returns 0. A skipped or attested start writes nothing and returns 0.
|
|
108
|
+
#>
|
|
109
|
+
[CmdletBinding()]
|
|
110
|
+
[OutputType([int])]
|
|
111
|
+
param([Parameter(Mandatory = $false)][AllowNull()][AllowEmptyString()][string]$PayloadRaw)
|
|
112
|
+
|
|
113
|
+
$outcome = Invoke-DiscoveryAgentStartDecision -PayloadRaw $PayloadRaw
|
|
114
|
+
if ($outcome.Decision -notin @('deny', 'observe')) { return 0 }
|
|
115
|
+
if ($outcome.Code -in @('ENVELOPE', 'DEPENDENCY')) {
|
|
116
|
+
[Console]::Error.WriteLine("$($script:DiscoveryStartReasonPrefix) $($outcome.Reason)")
|
|
117
|
+
return 2
|
|
118
|
+
}
|
|
119
|
+
$output = ConvertTo-DiscoveryStartHookOutput -Outcome $outcome -ReasonPrefix $script:DiscoveryStartReasonPrefix
|
|
120
|
+
[Console]::Out.WriteLine(($output | ConvertTo-Json -Compress -Depth 5))
|
|
121
|
+
return 0
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
125
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
if ($script:HookDependencyGuardLoadFailed) { [Console]::Error.WriteLine('DISCOVERY_START_ATTESTATION_BLOCKED: hook-dependency-guard.ps1 failed to load; the gate fails closed.'); exit 2 }
|
|
129
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix 'DISCOVERY_START_ATTESTATION_BLOCKED:'
|
|
130
|
+
if ($null -ne $dependencyDecision) { [Console]::Error.WriteLine($dependencyDecision.Reason); exit $dependencyDecision.ExitCode }
|
|
131
|
+
|
|
132
|
+
exit (Invoke-DiscoveryAgentStartEntryPoint -PayloadRaw (Read-ClaudeHookRawPayload))
|
|
@@ -1,244 +1,88 @@
|
|
|
1
1
|
<#
|
|
2
2
|
.SYNOPSIS
|
|
3
|
-
SubagentStop hook that validates discovery
|
|
4
|
-
terminating subagent's final output.
|
|
3
|
+
SubagentStop hook that validates a discovery specialist's protected output authority.
|
|
5
4
|
|
|
6
5
|
.DESCRIPTION
|
|
7
6
|
Invoked by the Claude Code SubagentStop hook under the existing broad
|
|
8
|
-
generic-agent matcher group. The hook reads the SubagentStop envelope
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
enforce-discovery-artifact-gate.ps1. Neither hook implements or
|
|
31
|
-
reimplements discovery-validator logic; both only route to the validator
|
|
32
|
-
CLI delivered by a separate feature and interpret its exit code and
|
|
33
|
-
captured output.
|
|
7
|
+
generic-agent matcher group. The hook reads the SubagentStop envelope through
|
|
8
|
+
the shared envelope helper (subagentstop-envelope.ps1), derives the stopping
|
|
9
|
+
principal from the payload alone (session, the host-assigned agent_id and
|
|
10
|
+
agent_type, and the literal parent root), and takes its decision from the
|
|
11
|
+
shared DiscoveryStop module:
|
|
12
|
+
|
|
13
|
+
- a stop whose agent type is not a discovery specialist is allowed, so the
|
|
14
|
+
other SubagentStop validators keep their behavior;
|
|
15
|
+
- a discovery specialist may stop only when its protected invocation was
|
|
16
|
+
finalized through the gateway and the completion receipt is the gateway's
|
|
17
|
+
validation-receipt for this invocation, session, role and gate mode, bound to
|
|
18
|
+
the current activation and workspace, with every required output present,
|
|
19
|
+
every input unchanged since the receipt and output_valid true; the
|
|
20
|
+
migration-coverage-reviewer may stop on a valid failing report;
|
|
21
|
+
- filenames or success prose in the final message never admit a stop, and a
|
|
22
|
+
blank final message never skips the validation.
|
|
23
|
+
|
|
24
|
+
A stop that cannot be validated blocks: the reason is written with the
|
|
25
|
+
DISCOVERY_ARTIFACT_GATE_BLOCKED: prefix to stderr and the hook exits 2 through
|
|
26
|
+
the shared envelope helper. An invalid envelope blocks with a "payload anomaly"
|
|
27
|
+
reason. An unhandled error during validation blocks with exit 2 and a reason
|
|
28
|
+
(issue #928). No orchestrator checkpoint is read or written.
|
|
34
29
|
|
|
35
30
|
.NOTES
|
|
36
|
-
Requires PowerShell 7
|
|
37
|
-
|
|
38
|
-
invokes NO external process: validation runs in-process through
|
|
39
|
-
`.claude/lib/discovery-validation/DiscoveryValidation.psm1` (issue #475).
|
|
40
|
-
An unhandled error during validation blocks with exit 2 and a reason (issue #928).
|
|
31
|
+
Requires PowerShell 7+. Invokes NO external process and never reads a profile,
|
|
32
|
+
locator or final-message field to decide identity or authority (issue #980).
|
|
41
33
|
#>
|
|
42
34
|
[CmdletBinding()]
|
|
43
35
|
param()
|
|
44
36
|
$script:HookDependencyGuardLoadFailed = $false; try { . (Join-Path $PSScriptRoot 'hook-dependency-guard.ps1') } catch { $script:HookDependencyGuardLoadFailed = $true }
|
|
45
37
|
try { . (Join-Path $PSScriptRoot 'subagentstop-envelope.ps1') } catch { Add-HookDependencyFailure -Name 'subagentstop-envelope.ps1' -ErrorRecord $_ }
|
|
46
|
-
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/
|
|
38
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryEncoding.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryEncoding.psm1' -ErrorRecord $_ }
|
|
39
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryAuthority.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryAuthority.psm1' -ErrorRecord $_ }
|
|
40
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryManifest.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryManifest.psm1' -ErrorRecord $_ }
|
|
41
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryPayload.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryPayload.psm1' -ErrorRecord $_ }
|
|
42
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStartRecord.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStartRecord.psm1' -ErrorRecord $_ }
|
|
43
|
+
try { Import-Module (Join-Path $PSScriptRoot '../lib/discovery-validation/DiscoveryStop.psm1') -Force -Global -ErrorAction Stop } catch { Add-HookDependencyFailure -Name 'DiscoveryStop.psm1' -ErrorRecord $_ }
|
|
47
44
|
|
|
48
|
-
|
|
49
|
-
<#
|
|
50
|
-
.SYNOPSIS
|
|
51
|
-
Wrapper around the discovery-artifact validator. Mockable seam.
|
|
52
|
-
.DESCRIPTION
|
|
53
|
-
Delegates to the portable PowerShell implementation in
|
|
54
|
-
`.claude/lib/discovery-validation/DiscoveryValidation.psm1`, keeping this
|
|
55
|
-
function's name, its `-ValidatorArgs <string[]>` parameter, and its
|
|
56
|
-
`@{ ExitCode; Output }` return shape unchanged so existing mocks and
|
|
57
|
-
`Should -Invoke` assertions continue to bind.
|
|
58
|
-
|
|
59
|
-
This no longer invokes a Python interpreter (issue #475). The `.claude/**`
|
|
60
|
-
payload ships to destinations with no guaranteed Python, Poetry, or
|
|
61
|
-
`scripts/dev_tools`, where the previous `python -m ...` call failed
|
|
62
|
-
obscurely or blocked every operation.
|
|
63
|
-
|
|
64
|
-
Success is SILENT by contract: a passing validation returns `ExitCode = 0`
|
|
65
|
-
with an EMPTY `Output`. The caller denies on a non-zero exit code OR on
|
|
66
|
-
non-empty output, so any success chatter here would deny a passing
|
|
67
|
-
validation (defect D-2).
|
|
68
|
-
#>
|
|
69
|
-
[CmdletBinding()]
|
|
70
|
-
[OutputType([hashtable])]
|
|
71
|
-
param(
|
|
72
|
-
[Parameter(Mandatory = $true)]
|
|
73
|
-
[string[]] $ValidatorArgs
|
|
74
|
-
)
|
|
75
|
-
|
|
76
|
-
$modulePath = Join-Path -Path $PSScriptRoot `
|
|
77
|
-
-ChildPath '../lib/discovery-validation/DiscoveryValidation.psm1'
|
|
78
|
-
if (-not (Test-Path -LiteralPath $modulePath -PathType Leaf)) {
|
|
79
|
-
return @{ ExitCode = 1; Output = "Discovery-validation module not found: $modulePath" }
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
Import-Module -Name $modulePath -Force -ErrorAction Stop
|
|
83
|
-
return Invoke-DiscoveryArtifactValidation -ValidatorArgs $ValidatorArgs
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function Get-DiscoveryArtifactType {
|
|
87
|
-
<#
|
|
88
|
-
.SYNOPSIS
|
|
89
|
-
Maps a normalized file path to a discovery-artifact-type token.
|
|
90
|
-
.DESCRIPTION
|
|
91
|
-
Returns one of the eight validator subcommand tokens (profile,
|
|
92
|
-
feature-contract, coverage-ledger, runtime-scenario, parity-matrix,
|
|
93
|
-
unspecified-behavior, product-decision, evidence-reference), or $null
|
|
94
|
-
when the path does not resolve to a recognized discovery-artifact
|
|
95
|
-
type.
|
|
96
|
-
|
|
97
|
-
# TODO(#9002): this is a narrow, replaceable directory/filename lookup.
|
|
98
|
-
The schema-versioned directory/filename convention this mapping
|
|
99
|
-
depends on is owned by #9002 and is not finalized in this branch.
|
|
100
|
-
Replace this lookup once #9002 ships its versioning convention.
|
|
101
|
-
#>
|
|
102
|
-
[CmdletBinding()]
|
|
103
|
-
[OutputType([string])]
|
|
104
|
-
param(
|
|
105
|
-
[Parameter(Mandatory = $true)]
|
|
106
|
-
[string] $Path
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
$normalized = $Path -replace '\\', '/'
|
|
110
|
-
|
|
111
|
-
$typeMap = [ordered]@{
|
|
112
|
-
'discovery/profile' = 'profile'
|
|
113
|
-
'discovery/feature-contract' = 'feature-contract'
|
|
114
|
-
'discovery/coverage-ledger' = 'coverage-ledger'
|
|
115
|
-
'discovery/runtime-scenario' = 'runtime-scenario'
|
|
116
|
-
'discovery/parity-matrix' = 'parity-matrix'
|
|
117
|
-
'discovery/unspecified-behavior' = 'unspecified-behavior'
|
|
118
|
-
'discovery/product-decision' = 'product-decision'
|
|
119
|
-
'discovery/evidence-reference' = 'evidence-reference'
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
foreach ($prefix in $typeMap.Keys) {
|
|
123
|
-
if ($normalized -match "(^|/)$([regex]::Escape($prefix))") {
|
|
124
|
-
return $typeMap[$prefix]
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return $null
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function Get-RequiredDiscoveryArtifactDeclaration {
|
|
132
|
-
<#
|
|
133
|
-
.SYNOPSIS
|
|
134
|
-
Reads the domain-profile required-artifact declaration, if present.
|
|
135
|
-
.DESCRIPTION
|
|
136
|
-
# TODO(#9001): this is a narrow, injectable RequiredArtifactPathsReader
|
|
137
|
-
seam. The discovery-workspace root and which of the eight artifact
|
|
138
|
-
types are "required" for a given gate are domain-profile runtime
|
|
139
|
-
configuration owned by #9001, which has no shipped parser/schema in
|
|
140
|
-
this branch.
|
|
141
|
-
|
|
142
|
-
Default behavior on absence is documented inline as fail-open
|
|
143
|
-
(allow/exit 0): when no domain profile is present, this function
|
|
144
|
-
returns an object with Present = $false, and callers must treat that
|
|
145
|
-
as "always allow, never invoke the validator" rather than as an error.
|
|
146
|
-
#>
|
|
147
|
-
[CmdletBinding()]
|
|
148
|
-
[OutputType([hashtable])]
|
|
149
|
-
param(
|
|
150
|
-
[Parameter(Mandatory = $false)]
|
|
151
|
-
[scriptblock] $ProfileReader = { $null }
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
$declaration = & $ProfileReader
|
|
155
|
-
if ($null -eq $declaration) {
|
|
156
|
-
# Fail open: no domain profile / required-artifact declaration present.
|
|
157
|
-
return @{ Present = $false }
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return @{ Present = $true; Declaration = $declaration }
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function Find-DiscoveryArtifactReference {
|
|
164
|
-
<#
|
|
165
|
-
.SYNOPSIS
|
|
166
|
-
Extracts candidate discovery-artifact path references from subagent
|
|
167
|
-
output text.
|
|
168
|
-
.DESCRIPTION
|
|
169
|
-
Splits the output text into whitespace-delimited tokens and returns
|
|
170
|
-
the distinct set of tokens that resolve to a recognized
|
|
171
|
-
discovery-artifact type via Get-DiscoveryArtifactType. This is a
|
|
172
|
-
lightweight text scan, not a JSON/markdown parser, matching the
|
|
173
|
-
precision needed for a defense-in-depth completion gate.
|
|
174
|
-
#>
|
|
175
|
-
[CmdletBinding()]
|
|
176
|
-
[OutputType([string[]])]
|
|
177
|
-
param(
|
|
178
|
-
[Parameter(Mandatory = $true)]
|
|
179
|
-
[AllowEmptyString()]
|
|
180
|
-
[string] $OutputText
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
if ([string]::IsNullOrWhiteSpace($OutputText)) {
|
|
184
|
-
return [string[]]@()
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
$tokens = $OutputText -split '\s+' | Where-Object { $_ }
|
|
188
|
-
$foundReferences = New-Object System.Collections.Generic.List[string]
|
|
189
|
-
foreach ($token in $tokens) {
|
|
190
|
-
$trimmed = $token.Trim('`', '"', "'", ',', ';', '(', ')', '[', ']')
|
|
191
|
-
if ($trimmed -and (Get-DiscoveryArtifactType -Path $trimmed)) {
|
|
192
|
-
if (-not $foundReferences.Contains($trimmed)) {
|
|
193
|
-
$foundReferences.Add($trimmed)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
return [string[]]$foundReferences
|
|
199
|
-
}
|
|
45
|
+
$script:DiscoveryGateReasonPrefix = 'DISCOVERY_ARTIFACT_GATE_BLOCKED:'
|
|
200
46
|
|
|
201
47
|
function Invoke-DiscoveryArtifactGateValidation {
|
|
202
48
|
<#
|
|
203
49
|
.SYNOPSIS
|
|
204
|
-
Reads the SubagentStop envelope and returns an Ok/Message validation
|
|
205
|
-
|
|
50
|
+
Reads the SubagentStop envelope and returns an Ok/Message validation result for a discovery stop.
|
|
51
|
+
.DESCRIPTION
|
|
52
|
+
Every seam defaults to the real host (platform state roots, protected
|
|
53
|
+
store, workspace bytes) and is injectable so tests run over in-memory
|
|
54
|
+
values. A recorded dependency failure blocks before the envelope is read.
|
|
55
|
+
The result also carries the shared outcome Code for diagnostics.
|
|
206
56
|
#>
|
|
207
57
|
[CmdletBinding()]
|
|
208
58
|
[OutputType([hashtable])]
|
|
209
59
|
param(
|
|
210
60
|
[AllowNull()] [AllowEmptyString()] [string] $InputText,
|
|
211
|
-
|
|
212
|
-
[Parameter(Mandatory = $false)]
|
|
213
|
-
[scriptblock]
|
|
61
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$HostEnvironment = $null,
|
|
62
|
+
[Parameter(Mandatory = $false)][AllowNull()][hashtable]$Store = $null,
|
|
63
|
+
[Parameter(Mandatory = $false)][AllowNull()][scriptblock]$ReadBytes = $null
|
|
214
64
|
)
|
|
215
|
-
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix
|
|
65
|
+
$dependencyDecision = Get-HookDependencyFailureDecision -HookEvent SubagentStop -ReasonPrefix $script:DiscoveryGateReasonPrefix
|
|
216
66
|
if ($null -ne $dependencyDecision) { return $dependencyDecision }
|
|
217
67
|
$envelope = if ($PSBoundParameters.ContainsKey('InputText')) { Read-SubagentStopEnvelope -InputText $InputText } else { Read-SubagentStopEnvelope }
|
|
218
|
-
if (-not $envelope.IsValid) { return @{ Ok = $false; Message = "
|
|
219
|
-
$assistantMessage = [string]$envelope.AssistantText
|
|
68
|
+
if (-not $envelope.IsValid) { return @{ Ok = $false; Message = "$($script:DiscoveryGateReasonPrefix) payload anomaly - $(Get-SubagentStopEnvelopeAnomalyReason -Anomaly $envelope.Anomaly)"; Code = 'ENVELOPE' } }
|
|
220
69
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
70
|
+
# Seams resolve only after the dependency check so a missing module blocks
|
|
71
|
+
# instead of raising while a default is evaluated.
|
|
72
|
+
if ($null -eq $HostEnvironment) { $HostEnvironment = Get-DiscoveryTrustedHostEnvironment }
|
|
73
|
+
if ($null -eq $Store) { $Store = Get-DiscoveryStartStore }
|
|
225
74
|
|
|
226
|
-
$
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
75
|
+
$normalized = ConvertFrom-DiscoveryHostEnvelope -HostName 'claude-code' -Envelope $envelope.Envelope
|
|
76
|
+
$parameters = @{
|
|
77
|
+
Normalized = $normalized; HostEnvironment = $HostEnvironment
|
|
78
|
+
AssistantText = [string]$envelope.AssistantText; StopHookActive = [bool]$envelope.StopHookActive; Store = $Store
|
|
230
79
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
$hasErrorOutput = -not [string]::IsNullOrWhiteSpace($validatorResult['Output'])
|
|
236
|
-
if ($validatorResult['ExitCode'] -ne 0 -or $hasErrorOutput) {
|
|
237
|
-
return @{ Ok = $false; Message = "DISCOVERY_ARTIFACT_GATE_BLOCKED: $($validatorResult['Output'])" }
|
|
238
|
-
}
|
|
80
|
+
if ($null -ne $ReadBytes) { $parameters['ReadBytes'] = $ReadBytes }
|
|
81
|
+
$outcome = Get-DiscoveryStopDecision @parameters
|
|
82
|
+
if ($outcome.Decision -eq 'block') {
|
|
83
|
+
return @{ Ok = $false; Message = "$($script:DiscoveryGateReasonPrefix) $($outcome.Reason)"; Code = $outcome.Code }
|
|
239
84
|
}
|
|
240
|
-
|
|
241
|
-
return @{ Ok = $true; Message = $null }
|
|
85
|
+
return @{ Ok = $true; Message = $null; Code = $outcome.Code }
|
|
242
86
|
}
|
|
243
87
|
|
|
244
88
|
# Guard allows dot-sourcing in tests without executing the entrypoint.
|