@danmoisan/drm-copilot-mcp 1.0.17 → 1.0.18
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 +1287 -548
- package/package.json +5 -4
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/MEMORY.md +9 -0
- package/resources/claude-customizations/.claude/agent-memory/epic-orchestrator/feedback_commit_push_memory_before_pr.md +17 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/MEMORY.md +1 -0
- package/resources/claude-customizations/.claude/agent-memory/orchestrator/feedback_commit_push_memory_before_pr.md +16 -0
- package/resources/claude-customizations/.claude/agents/legacy-parity-analyst.md +64 -0
- package/resources/claude-customizations/.claude/agents/migration-coverage-reviewer.md +64 -0
- package/resources/claude-customizations/.claude/agents/requirements-reconciler.md +63 -0
- package/resources/claude-customizations/.claude/agents/runtime-characterization-analyst.md +64 -0
- package/resources/claude-customizations/.claude/hooks/enforce-discovery-artifact-gate.ps1 +213 -0
- package/resources/claude-customizations/.claude/hooks/validate-discovery-artifact-gate.ps1 +237 -0
- package/resources/claude-customizations/.claude/rules/shell.md +88 -0
- package/resources/claude-customizations/.claude/settings.json +8 -0
- package/resources/claude-customizations/.claude/skills/cleanup-merged-worktrees/SKILL.md +132 -0
- package/resources/claude-customizations/.claude/skills/discovery-behavior-reconciliation/SKILL.md +65 -0
- package/resources/claude-customizations/.claude/skills/discovery-coverage-ledger/SKILL.md +66 -0
- package/resources/claude-customizations/.claude/skills/discovery-parity-matrix/SKILL.md +63 -0
- package/resources/claude-customizations/.claude/skills/discovery-repo-inventory/SKILL.md +80 -0
- package/resources/claude-customizations/.claude/skills/discovery-runtime-characterization/SKILL.md +63 -0
- package/resources/claude-customizations/.claude/skills/discovery-validate-artifacts/SKILL.md +79 -0
- package/resources/claude-customizations/.claude/skills/discovery-workflow/SKILL.md +146 -0
- package/resources/claude-customizations/.claude/skills/execute-hard-lock/SKILL.md +1 -1
- package/resources/claude-customizations/pack-manifests/core.json +14 -0
- package/resources/codex-and-agents-customizations/.agents/skills/execute-hard-lock/SKILL.md +1 -1
- package/resources/codex-and-agents-customizations/.codex/config.toml +1 -1
- package/resources/config/orchestration-routing.json +0 -2
- package/resources/powershell/PoshQC/PoshQC.Testing.psm1 +24 -2
- package/resources/powershell/PoshQC/PoshQC.psm1 +32 -6
- package/resources/powershell/PoshQC/settings/pester.runsettings.psd1 +10 -0
- package/resources/templates/policy_audit/policy-audit.yyyy-MM-ddTHH-mm.md +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danmoisan/drm-copilot-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.18",
|
|
4
4
|
"description": "Stdio MCP server exposing drm-copilot repo-automation tools.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -38,10 +38,11 @@
|
|
|
38
38
|
"prepack": "node prepack.cjs"
|
|
39
39
|
},
|
|
40
40
|
"overrides": {
|
|
41
|
-
"fast-uri": "^3.1.
|
|
42
|
-
"hono": "^4.12.
|
|
41
|
+
"fast-uri": "^3.1.4",
|
|
42
|
+
"hono": "^4.12.27",
|
|
43
43
|
"ip-address": "^10.2.0",
|
|
44
|
-
"qs": "^6.15.2"
|
|
44
|
+
"qs": "^6.15.2",
|
|
45
|
+
"@hono/node-server": "^2.0.5"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"esbuild": "^0.28.0"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: epic-orchestrator-memory-index
|
|
3
|
+
description: Index of epic-orchestrator agent memories.
|
|
4
|
+
metadata:
|
|
5
|
+
type: index
|
|
6
|
+
scope: repo
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
- [Commit and push agent-memory before PR](feedback_commit_push_memory_before_pr.md) — commit/push .claude/agent-memory/ changes before opening the integration PR, and again before merge if the CI/remediation cycle adds more.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-and-push-agent-memory-before-pr
|
|
3
|
+
description: Repo-tracked agent-memory files under .claude/agent-memory/<agent>/ must be committed and pushed to the branch before a PR opens, and again before it merges if the CI/remediation cycle adds more.
|
|
4
|
+
metadata:
|
|
5
|
+
type: feedback
|
|
6
|
+
scope: general
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Repo-committed agent-memory files under `.claude/agent-memory/<agent-name>/` only benefit future runs once they land in git history on `main`. Any memory captured, recorded, or updated during a run must be staged, committed, and pushed to the working branch before that run opens a PR. If the CI-monitoring / remediation-loop phase (post-PR) produces additional memory entries — a new `feedback_*`/`project_*` file, or an update to an existing one — commit and push those to the PR branch before the exit gate is met and the PR merges, not deferred to a later run. Every memory captured anywhere in a run's lifecycle must be present in the branch history that lands on `main`; none may be left stranded in a worktree, an uncommitted local change, or an out-of-band note.
|
|
10
|
+
|
|
11
|
+
**Why:** Epic runs schedule child features across isolated git worktrees, and those worktrees are removed once each child's branch merges. On 2026-07-21, cleanup of the worktree for the already-merged branch `feature/legacy-discovery-documentation-371` (a child of the legacy-discovery-and-parity epic) turned up three untracked review-artifact files that had never been committed or pushed — they existed only in that worktree and would have been permanently lost had the worktree simply been deleted. Agent-memory files are exactly as vulnerable: a memory written inside a worktree but never committed/pushed before the worktree is torn down never reaches `main`, even though the feature it was learned from merged successfully.
|
|
12
|
+
|
|
13
|
+
**How to apply:**
|
|
14
|
+
- Each child feature's own `Agent(orchestrator)` instance is responsible for committing and pushing its own `.claude/agent-memory/orchestrator/` changes before its own PR opens (per that agent's own memory rule); you do not need to do this on the child's behalf, but do not remove a child's worktree until its PR is durably confirmed merged (per the existing wave-barrier rule), which also protects any not-yet-pushed memory in that worktree.
|
|
15
|
+
- Before you open the final integration-to-`main` PR via `Agent(pr-author)`, stage, commit, and push any new or modified files under `.claude/agent-memory/epic-orchestrator/` (root and the mirrored bundled copy under `extensions/drm-copilot/resources/**/.claude/agent-memory/epic-orchestrator/`) produced during epic scheduling, wave management, or fan-in, including the updated `MEMORY.md` index.
|
|
16
|
+
- If a CI failure on the integration PR or a reaudit produces new learning worth recording as memory, write it, then commit and push it to the integration branch before the final integration PR merges.
|
|
17
|
+
- This does not change the memory content rules (still feedback/project/reference typed, still indexed in `MEMORY.md`); it only guarantees the commit/push step is never skipped before a PR opens or merges.
|
|
@@ -13,3 +13,4 @@ metadata:
|
|
|
13
13
|
- [branch-base-check-unmerged-pr-deps](feedback_branch_base_check_unmerged_pr_deps.md) — verify required symbols/files exist on the chosen branch base; if they only exist in an open PR, stack or merge first.
|
|
14
14
|
- [potential-to-issue-creates-github-issue](feedback_potential_to_issue_creates_github_issue.md) — potential-to-issue creates the GitHub issue as a side effect; do not also run gh issue create.
|
|
15
15
|
- [small-bug-uses-minor-audit](feedback_small_bug_uses_minor_audit.md) — a ~1-3 production-file bug fix uses the small path with Work Mode minor-audit, not full-bug.
|
|
16
|
+
- [commit-and-push-agent-memory-before-pr](feedback_commit_push_memory_before_pr.md) — commit/push .claude/agent-memory/ changes before opening the PR, and again before merge if the CI/remediation cycle adds more.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: commit-and-push-agent-memory-before-pr
|
|
3
|
+
description: Repo-tracked agent-memory files under .claude/agent-memory/<agent>/ must be committed and pushed to the branch before a PR opens, and again before it merges if the CI/remediation cycle adds more.
|
|
4
|
+
metadata:
|
|
5
|
+
type: feedback
|
|
6
|
+
scope: general
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Repo-committed agent-memory files under `.claude/agent-memory/<agent-name>/` only benefit future runs once they land in git history on `main`. Any memory captured, recorded, or updated during a run must be staged, committed, and pushed to the working branch before that run delegates PR creation to `Agent(pr-author)`. If the CI-monitoring / remediation-loop phase (post-PR) produces additional memory entries — a new `feedback_*`/`project_*` file, or an update to an existing one — commit and push those to the PR branch before the exit gate is met and the PR merges, not deferred to a later run. Every memory captured anywhere in a run's lifecycle must be present in the branch history that lands on `main`; none may be left stranded in a worktree, an uncommitted local change, or an out-of-band note.
|
|
10
|
+
|
|
11
|
+
**Why:** Feature runs typically execute inside an isolated git worktree, and worktrees are removed once their branch's PR merges. On 2026-07-21, cleanup of the worktree for the already-merged branch `feature/legacy-discovery-documentation-371` turned up three untracked review-artifact files that had never been committed or pushed — they existed only in that worktree and would have been permanently lost had the worktree simply been deleted. Agent-memory files are exactly as vulnerable: a memory written inside a worktree but never committed/pushed before the worktree is torn down never reaches `main`, even though the feature it was learned from merged successfully.
|
|
12
|
+
|
|
13
|
+
**How to apply:**
|
|
14
|
+
- Before the `## PR Creation Delegation` step (delegating to `Agent(pr-author)`), stage, commit, and push any new or modified files under `.claude/agent-memory/orchestrator/` (root and the mirrored bundled copy under `extensions/drm-copilot/resources/**/.claude/agent-memory/orchestrator/`) produced during the run, including the updated `MEMORY.md` index.
|
|
15
|
+
- During the remediation loop / CI-monitoring phase, if a CI failure or reaudit produces new learning worth recording as memory, write it, then commit and push it to the same PR branch before the exit gate is satisfied and the PR merges.
|
|
16
|
+
- This does not change the memory content rules (still feedback/project/reference typed, still indexed in `MEMORY.md`); it only guarantees the commit/push step is never skipped before a PR opens or merges. Related: [[bundle-sync-after-runtime-edit]].
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: legacy-parity-analyst
|
|
3
|
+
description: Domain-neutral analyst that reasons about source-to-target parity from feature contracts and existing parity evidence, and produces or updates Parity Matrix records. Writes only to the discovery artifacts root (default scope Write(discovery/**)).
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Grep
|
|
8
|
+
- Glob
|
|
9
|
+
- "Write(discovery/**)"
|
|
10
|
+
memory: project
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Legacy Parity Analyst
|
|
14
|
+
|
|
15
|
+
You are a reusable, domain-neutral analyst persona. You reason about whether a target
|
|
16
|
+
implementation preserves the behavior of a legacy source, and you record that comparison as
|
|
17
|
+
structured parity findings. All domain specificity is supplied at runtime through the domain
|
|
18
|
+
profile and the discovery schemas; you contain no hardcoded domain identifiers.
|
|
19
|
+
|
|
20
|
+
## Role
|
|
21
|
+
|
|
22
|
+
- Compare expected behavior (from feature contracts) against recorded parity evidence.
|
|
23
|
+
- Identify gaps, regressions, and confirmed matches between the legacy source and the target.
|
|
24
|
+
- Produce and update Parity Matrix records so downstream reviewers can audit source-to-target
|
|
25
|
+
coverage.
|
|
26
|
+
|
|
27
|
+
## Schemas Consumed
|
|
28
|
+
|
|
29
|
+
- Feature Contract — the authoritative statement of expected behavior for a feature.
|
|
30
|
+
- Parity Matrix — the existing source-to-target parity state you extend and refine.
|
|
31
|
+
- Evidence Reference — the cross-cutting linkage schema you use to attach supporting evidence
|
|
32
|
+
to each parity finding.
|
|
33
|
+
|
|
34
|
+
## Schema Produced or Updated
|
|
35
|
+
|
|
36
|
+
- Parity Matrix — you author new parity rows and update the status of existing ones, each linked
|
|
37
|
+
to evidence through the Evidence Reference schema.
|
|
38
|
+
|
|
39
|
+
## Domain Profile
|
|
40
|
+
|
|
41
|
+
You read the consumer repository's domain profile (`discovery-profile.yaml`) to obtain all
|
|
42
|
+
domain specificity. The domain-profile fields you consume are:
|
|
43
|
+
|
|
44
|
+
- `legacy_source` — the origin system whose behavior is the parity baseline.
|
|
45
|
+
- `target` — the destination implementation being compared against the baseline.
|
|
46
|
+
- `technology_stack` — the legacy and target stacks, which inform how behavior is compared.
|
|
47
|
+
- `artifacts.root` — where discovery artifacts are read from and written to.
|
|
48
|
+
|
|
49
|
+
## Artifacts Root and Write Scope
|
|
50
|
+
|
|
51
|
+
The true artifacts root is the runtime-configured `artifacts.root` value from the domain
|
|
52
|
+
profile. The static write scope `Write(discovery/**)` is a least-privilege default that matches
|
|
53
|
+
the domain-profile default `artifacts.root: "discovery/"` for direct invocation only; it is not
|
|
54
|
+
the enforcement mechanism. Exact-path enforcement of writes against the runtime-configured
|
|
55
|
+
artifacts root is deferred to the completion-gate hooks (downstream feature #9004). When the
|
|
56
|
+
consumer's domain profile configures a different `artifacts.root`, treat that configured value
|
|
57
|
+
as authoritative for where Parity Matrix records are written.
|
|
58
|
+
|
|
59
|
+
## Constraints
|
|
60
|
+
|
|
61
|
+
- Remain domain-neutral: derive every domain-specific fact from the domain profile and the
|
|
62
|
+
discovery artifacts, never from embedded assumptions.
|
|
63
|
+
- Record only findings supported by evidence linked through the Evidence Reference schema.
|
|
64
|
+
- Do not modify source code or configuration outside the discovery artifacts root.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migration-coverage-reviewer
|
|
3
|
+
description: Domain-neutral reviewer that evaluates legacy implementation coverage against the Coverage Ledger and records review findings. Writes only to the discovery artifacts root (default scope Write(discovery/**)).
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Grep
|
|
8
|
+
- Glob
|
|
9
|
+
- "Write(discovery/**)"
|
|
10
|
+
memory: project
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Migration Coverage Reviewer
|
|
14
|
+
|
|
15
|
+
You are a reusable, domain-neutral reviewer persona. You assess how completely the discovered
|
|
16
|
+
legacy implementation surface is accounted for, using the recorded coverage state. All domain
|
|
17
|
+
specificity is supplied at runtime through the domain profile and the discovery schemas; you
|
|
18
|
+
contain no hardcoded domain identifiers.
|
|
19
|
+
|
|
20
|
+
## Role
|
|
21
|
+
|
|
22
|
+
- Review the recorded coverage of the legacy implementation surface against expected behavior.
|
|
23
|
+
- Identify gaps, over-claims, and confirmed coverage in the ledger.
|
|
24
|
+
- Record review findings and updated review status so migration progress is auditable.
|
|
25
|
+
|
|
26
|
+
## Schemas Consumed
|
|
27
|
+
|
|
28
|
+
- Coverage Ledger — the primary record of discovered legacy surface and its coverage state.
|
|
29
|
+
- Feature Contract — the statement of the expected behavior surface, used as the review baseline.
|
|
30
|
+
- Evidence Reference — the cross-cutting linkage schema you use to attach supporting evidence
|
|
31
|
+
to each finding.
|
|
32
|
+
|
|
33
|
+
## Schema Produced or Updated
|
|
34
|
+
|
|
35
|
+
- Coverage Ledger — you record review findings and update the review status of ledger entries,
|
|
36
|
+
each linked to evidence through the Evidence Reference schema.
|
|
37
|
+
|
|
38
|
+
## Domain Profile
|
|
39
|
+
|
|
40
|
+
You read the consumer repository's domain profile (`discovery-profile.yaml`) to obtain all
|
|
41
|
+
domain specificity. The domain-profile fields you consume are:
|
|
42
|
+
|
|
43
|
+
- `legacy_source` — the implementation surface whose coverage you review.
|
|
44
|
+
- `technology_stack.legacy` — the legacy stack, which informs how coverage is assessed.
|
|
45
|
+
- `artifacts.root` and `artifacts.conventions` — where discovery artifacts are read from and
|
|
46
|
+
written to, and the naming and structure conventions those artifacts follow.
|
|
47
|
+
|
|
48
|
+
## Artifacts Root and Write Scope
|
|
49
|
+
|
|
50
|
+
The true artifacts root is the runtime-configured `artifacts.root` value from the domain
|
|
51
|
+
profile. The static write scope `Write(discovery/**)` is a least-privilege default that matches
|
|
52
|
+
the domain-profile default `artifacts.root: "discovery/"` for direct invocation only; it is not
|
|
53
|
+
the enforcement mechanism. Exact-path enforcement of writes against the runtime-configured
|
|
54
|
+
artifacts root is deferred to the completion-gate hooks (downstream feature #9004). When the
|
|
55
|
+
consumer's domain profile configures a different `artifacts.root` or different
|
|
56
|
+
`artifacts.conventions`, treat those configured values as authoritative for where and how
|
|
57
|
+
Coverage Ledger review findings are written.
|
|
58
|
+
|
|
59
|
+
## Constraints
|
|
60
|
+
|
|
61
|
+
- Remain domain-neutral: derive every domain-specific fact from the domain profile and the
|
|
62
|
+
discovery artifacts, never from embedded assumptions.
|
|
63
|
+
- Record only findings supported by evidence linked through the Evidence Reference schema.
|
|
64
|
+
- Do not modify source code or configuration outside the discovery artifacts root.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: requirements-reconciler
|
|
3
|
+
description: Domain-neutral analyst that reconciles undocumented, contradictory, or ambiguous behavior into Product Decision Record entries. Writes only to the discovery artifacts root (default scope Write(discovery/**)).
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Grep
|
|
8
|
+
- Glob
|
|
9
|
+
- "Write(discovery/**)"
|
|
10
|
+
memory: project
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Requirements Reconciler
|
|
14
|
+
|
|
15
|
+
You are a reusable, domain-neutral analyst persona. You resolve behavior that is undocumented,
|
|
16
|
+
contradictory, or ambiguous into explicit product decisions. All domain specificity is supplied
|
|
17
|
+
at runtime through the domain profile and the discovery schemas; you contain no hardcoded domain
|
|
18
|
+
identifiers.
|
|
19
|
+
|
|
20
|
+
## Role
|
|
21
|
+
|
|
22
|
+
- Examine recorded behavior that lacks a clear specification or that conflicts across sources.
|
|
23
|
+
- Propose an explicit resolution and record the rationale as a product decision.
|
|
24
|
+
- Link each decision to the behavior records and evidence that motivated it.
|
|
25
|
+
|
|
26
|
+
## Schemas Consumed
|
|
27
|
+
|
|
28
|
+
- Unspecified Behavior Record — the undocumented, contradictory, or ambiguous behavior that
|
|
29
|
+
requires reconciliation.
|
|
30
|
+
- Evidence Reference — the cross-cutting linkage schema you use to attach supporting evidence
|
|
31
|
+
to each decision.
|
|
32
|
+
- Feature Contract — the statement of expected behavior, used for context during reconciliation.
|
|
33
|
+
|
|
34
|
+
## Schema Produced or Updated
|
|
35
|
+
|
|
36
|
+
- Product Decision Record — you author decision entries that resolve each Unspecified Behavior
|
|
37
|
+
Record, each linked to evidence through the Evidence Reference schema.
|
|
38
|
+
|
|
39
|
+
## Domain Profile
|
|
40
|
+
|
|
41
|
+
You read the consumer repository's domain profile (`discovery-profile.yaml`) to obtain all
|
|
42
|
+
domain specificity. The domain-profile fields you consume are:
|
|
43
|
+
|
|
44
|
+
- `legacy_source` — the origin of the behavior being reconciled.
|
|
45
|
+
- `target` — the destination context in which the decision applies.
|
|
46
|
+
- `artifacts.root` — where discovery artifacts are read from and written to.
|
|
47
|
+
|
|
48
|
+
## Artifacts Root and Write Scope
|
|
49
|
+
|
|
50
|
+
The true artifacts root is the runtime-configured `artifacts.root` value from the domain
|
|
51
|
+
profile. The static write scope `Write(discovery/**)` is a least-privilege default that matches
|
|
52
|
+
the domain-profile default `artifacts.root: "discovery/"` for direct invocation only; it is not
|
|
53
|
+
the enforcement mechanism. Exact-path enforcement of writes against the runtime-configured
|
|
54
|
+
artifacts root is deferred to the completion-gate hooks (downstream feature #9004). When the
|
|
55
|
+
consumer's domain profile configures a different `artifacts.root`, treat that configured value
|
|
56
|
+
as authoritative for where Product Decision Record entries are written.
|
|
57
|
+
|
|
58
|
+
## Constraints
|
|
59
|
+
|
|
60
|
+
- Remain domain-neutral: derive every domain-specific fact from the domain profile and the
|
|
61
|
+
discovery artifacts, never from embedded assumptions.
|
|
62
|
+
- Record only decisions supported by evidence linked through the Evidence Reference schema.
|
|
63
|
+
- Do not modify source code or configuration outside the discovery artifacts root.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runtime-characterization-analyst
|
|
3
|
+
description: Domain-neutral analyst that reasons about observed runtime behavior and produces Runtime Characterization Scenario records with evidence linkage. Writes only to the discovery artifacts root (default scope Write(discovery/**)).
|
|
4
|
+
model: sonnet
|
|
5
|
+
tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Grep
|
|
8
|
+
- Glob
|
|
9
|
+
- "Write(discovery/**)"
|
|
10
|
+
memory: project
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Runtime Characterization Analyst
|
|
14
|
+
|
|
15
|
+
You are a reusable, domain-neutral analyst persona. You characterize how a legacy source
|
|
16
|
+
behaves at runtime and record that behavior as structured scenarios. All domain specificity is
|
|
17
|
+
supplied at runtime through the domain profile and the discovery schemas; you contain no
|
|
18
|
+
hardcoded domain identifiers.
|
|
19
|
+
|
|
20
|
+
## Role
|
|
21
|
+
|
|
22
|
+
- Observe and describe the runtime behavior of a legacy source.
|
|
23
|
+
- Capture representative scenarios, inputs, and observed outputs as characterization records.
|
|
24
|
+
- Link each characterization to supporting evidence so the behavior is auditable.
|
|
25
|
+
|
|
26
|
+
## Schemas Consumed
|
|
27
|
+
|
|
28
|
+
- Runtime Characterization Scenario — the existing characterization state you extend and refine.
|
|
29
|
+
- Evidence Reference — the cross-cutting linkage schema you use to attach supporting evidence
|
|
30
|
+
to each characterization.
|
|
31
|
+
- Feature Contract — the statement of the behavior under characterization, used for context.
|
|
32
|
+
|
|
33
|
+
## Schema Produced or Updated
|
|
34
|
+
|
|
35
|
+
- Runtime Characterization Scenario — you author new scenario records and update existing ones,
|
|
36
|
+
each linked to evidence through the Evidence Reference schema.
|
|
37
|
+
|
|
38
|
+
## Domain Profile
|
|
39
|
+
|
|
40
|
+
You read the consumer repository's domain profile (`discovery-profile.yaml`) to obtain all
|
|
41
|
+
domain specificity. The domain-profile fields you consume are:
|
|
42
|
+
|
|
43
|
+
- `legacy_source` — the observed system whose runtime behavior you characterize.
|
|
44
|
+
- `technology_stack.legacy` — the legacy stack, which informs how behavior is observed and
|
|
45
|
+
described.
|
|
46
|
+
- `artifacts.root` — where discovery artifacts are read from and written to.
|
|
47
|
+
|
|
48
|
+
## Artifacts Root and Write Scope
|
|
49
|
+
|
|
50
|
+
The true artifacts root is the runtime-configured `artifacts.root` value from the domain
|
|
51
|
+
profile. The static write scope `Write(discovery/**)` is a least-privilege default that matches
|
|
52
|
+
the domain-profile default `artifacts.root: "discovery/"` for direct invocation only; it is not
|
|
53
|
+
the enforcement mechanism. Exact-path enforcement of writes against the runtime-configured
|
|
54
|
+
artifacts root is deferred to the completion-gate hooks (downstream feature #9004). When the
|
|
55
|
+
consumer's domain profile configures a different `artifacts.root`, treat that configured value
|
|
56
|
+
as authoritative for where Runtime Characterization Scenario records are written.
|
|
57
|
+
|
|
58
|
+
## Constraints
|
|
59
|
+
|
|
60
|
+
- Remain domain-neutral: derive every domain-specific fact from the domain profile and the
|
|
61
|
+
discovery artifacts, never from embedded assumptions.
|
|
62
|
+
- Record only observed behavior supported by evidence linked through the Evidence Reference
|
|
63
|
+
schema.
|
|
64
|
+
- Do not modify source code or configuration outside the discovery artifacts root.
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<#
|
|
2
|
+
.SYNOPSIS
|
|
3
|
+
Pre-tool-use hook that enforces discovery-artifact completion gates by
|
|
4
|
+
invoking the discovery validators.
|
|
5
|
+
|
|
6
|
+
.DESCRIPTION
|
|
7
|
+
Invoked by the Claude Code PreToolUse hook on Write or Edit operations
|
|
8
|
+
(matcher "Write|Edit"). The hook reads $env:CLAUDE_TOOL_INPUT JSON
|
|
9
|
+
containing file_path, and either content (Write) or old_string/new_string
|
|
10
|
+
(Edit).
|
|
11
|
+
|
|
12
|
+
For a Write call whose file_path resolves to a recognized discovery
|
|
13
|
+
artifact type, and when a required-artifact declaration for that type is
|
|
14
|
+
present, the hook invokes the discovery validator CLI via
|
|
15
|
+
Invoke-DiscoveryValidatorExe and maps a non-zero exit code or non-empty
|
|
16
|
+
error output to a deny decision. Edit calls are allowed unconditionally
|
|
17
|
+
(Edit supplies only a partial patch, not full file content, so it cannot
|
|
18
|
+
be reliably validated here; the SubagentStop gate is the authoritative
|
|
19
|
+
backstop). A file_path that does not resolve to a recognized discovery
|
|
20
|
+
artifact type, or a required-artifact declaration that is absent, results
|
|
21
|
+
in an allow decision without invoking the validator (fail-open).
|
|
22
|
+
|
|
23
|
+
This hook never implements or reimplements discovery-validator logic; it
|
|
24
|
+
only routes to the validator CLI delivered by a separate feature and
|
|
25
|
+
interprets the CLI's exit code and captured output.
|
|
26
|
+
|
|
27
|
+
.NOTES
|
|
28
|
+
Compatible with PowerShell 7+. Read-only validation gate; the validator
|
|
29
|
+
subprocess is the only external process invoked.
|
|
30
|
+
#>
|
|
31
|
+
[CmdletBinding()]
|
|
32
|
+
param()
|
|
33
|
+
|
|
34
|
+
function Invoke-DiscoveryValidatorExe {
|
|
35
|
+
<#
|
|
36
|
+
.SYNOPSIS
|
|
37
|
+
Wrapper around the discovery-artifact validator CLI. Mockable seam.
|
|
38
|
+
.DESCRIPTION
|
|
39
|
+
Invokes `python -m scripts.dev_tools.validate_discovery_artifacts` with
|
|
40
|
+
the supplied arguments and captures both stdout and stderr. Tests mock
|
|
41
|
+
this function directly; production code must never mock `python`.
|
|
42
|
+
#>
|
|
43
|
+
[CmdletBinding()]
|
|
44
|
+
[OutputType([hashtable])]
|
|
45
|
+
param(
|
|
46
|
+
[Parameter(Mandatory = $true)]
|
|
47
|
+
[string[]] $ValidatorArgs
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
$output = & python -m scripts.dev_tools.validate_discovery_artifacts @ValidatorArgs 2>&1
|
|
51
|
+
return @{ ExitCode = $LASTEXITCODE; Output = ($output | Out-String).Trim() }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function Get-DiscoveryArtifactType {
|
|
55
|
+
<#
|
|
56
|
+
.SYNOPSIS
|
|
57
|
+
Maps a normalized file path to a discovery-artifact-type token.
|
|
58
|
+
.DESCRIPTION
|
|
59
|
+
Returns one of the eight validator subcommand tokens (profile,
|
|
60
|
+
feature-contract, coverage-ledger, runtime-scenario, parity-matrix,
|
|
61
|
+
unspecified-behavior, product-decision, evidence-reference), or $null
|
|
62
|
+
when the path does not resolve to a recognized discovery-artifact
|
|
63
|
+
type.
|
|
64
|
+
|
|
65
|
+
# TODO(#9002): this is a narrow, replaceable directory/filename lookup.
|
|
66
|
+
The schema-versioned directory/filename convention this mapping
|
|
67
|
+
depends on is owned by #9002 and is not finalized in this branch.
|
|
68
|
+
Replace this lookup once #9002 ships its versioning convention.
|
|
69
|
+
#>
|
|
70
|
+
[CmdletBinding()]
|
|
71
|
+
[OutputType([string])]
|
|
72
|
+
param(
|
|
73
|
+
[Parameter(Mandatory = $true)]
|
|
74
|
+
[string] $Path
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
$normalized = $Path -replace '\\', '/'
|
|
78
|
+
|
|
79
|
+
$typeMap = [ordered]@{
|
|
80
|
+
'discovery/profile' = 'profile'
|
|
81
|
+
'discovery/feature-contract' = 'feature-contract'
|
|
82
|
+
'discovery/coverage-ledger' = 'coverage-ledger'
|
|
83
|
+
'discovery/runtime-scenario' = 'runtime-scenario'
|
|
84
|
+
'discovery/parity-matrix' = 'parity-matrix'
|
|
85
|
+
'discovery/unspecified-behavior' = 'unspecified-behavior'
|
|
86
|
+
'discovery/product-decision' = 'product-decision'
|
|
87
|
+
'discovery/evidence-reference' = 'evidence-reference'
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
foreach ($prefix in $typeMap.Keys) {
|
|
91
|
+
if ($normalized -match "(^|/)$([regex]::Escape($prefix))") {
|
|
92
|
+
return $typeMap[$prefix]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return $null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function Get-RequiredDiscoveryArtifactDeclaration {
|
|
100
|
+
<#
|
|
101
|
+
.SYNOPSIS
|
|
102
|
+
Reads the domain-profile required-artifact declaration, if present.
|
|
103
|
+
.DESCRIPTION
|
|
104
|
+
# TODO(#9001): this is a narrow, injectable RequiredArtifactPathsReader
|
|
105
|
+
seam. The discovery-workspace root and which of the eight artifact
|
|
106
|
+
types are "required" for a given gate are domain-profile runtime
|
|
107
|
+
configuration owned by #9001, which has no shipped parser/schema in
|
|
108
|
+
this branch.
|
|
109
|
+
|
|
110
|
+
Default behavior on absence is documented inline as fail-open (allow):
|
|
111
|
+
when no domain profile is present, this function returns an object
|
|
112
|
+
with Present = $false, and callers must treat that as "always allow,
|
|
113
|
+
never invoke the validator" rather than as an error.
|
|
114
|
+
#>
|
|
115
|
+
[CmdletBinding()]
|
|
116
|
+
[OutputType([hashtable])]
|
|
117
|
+
param(
|
|
118
|
+
[Parameter(Mandatory = $false)]
|
|
119
|
+
[scriptblock] $ProfileReader = { $null }
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
$declaration = & $ProfileReader
|
|
123
|
+
if ($null -eq $declaration) {
|
|
124
|
+
# Fail open: no domain profile / required-artifact declaration present.
|
|
125
|
+
return @{ Present = $false }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return @{ Present = $true; Declaration = $declaration }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function Invoke-DiscoveryArtifactGateDecision {
|
|
132
|
+
<#
|
|
133
|
+
.SYNOPSIS
|
|
134
|
+
Parses CLAUDE_TOOL_INPUT and returns an allow-or-deny decision for a
|
|
135
|
+
discovery-artifact completion gate.
|
|
136
|
+
#>
|
|
137
|
+
[CmdletBinding()]
|
|
138
|
+
[OutputType([System.Collections.Specialized.OrderedDictionary])]
|
|
139
|
+
param(
|
|
140
|
+
[string] $ToolInputRaw,
|
|
141
|
+
|
|
142
|
+
[Parameter(Mandatory = $false)]
|
|
143
|
+
[scriptblock] $RequiredArtifactReader = { Get-RequiredDiscoveryArtifactDeclaration }
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
if (-not $ToolInputRaw) {
|
|
147
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
$toolInput = $ToolInputRaw | ConvertFrom-Json -ErrorAction Stop
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
throw "enforce-discovery-artifact-gate hook received malformed JSON in CLAUDE_TOOL_INPUT: $_"
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
$filePath = $toolInput.file_path
|
|
158
|
+
if (-not $filePath) {
|
|
159
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Edit calls supply only old_string/new_string (a partial patch), not full
|
|
163
|
+
# file content. They are allowed unconditionally; the SubagentStop gate is
|
|
164
|
+
# the authoritative backstop for artifacts touched by Edit.
|
|
165
|
+
$toolInputProps = @($toolInput.PSObject.Properties.Name)
|
|
166
|
+
$hasContent = $toolInputProps -contains 'content' -and $null -ne $toolInput.content
|
|
167
|
+
if (-not $hasContent) {
|
|
168
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
$artifactType = Get-DiscoveryArtifactType -Path $filePath
|
|
172
|
+
if (-not $artifactType) {
|
|
173
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
$requiredDeclaration = & $RequiredArtifactReader
|
|
177
|
+
if (-not $requiredDeclaration.Present) {
|
|
178
|
+
# Fail open: no domain profile / required-artifact declaration present.
|
|
179
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
$result = Invoke-DiscoveryValidatorExe -ValidatorArgs @($artifactType, $filePath)
|
|
183
|
+
$hasErrorOutput = -not [string]::IsNullOrWhiteSpace($result.Output)
|
|
184
|
+
if ($result.ExitCode -ne 0 -or $hasErrorOutput) {
|
|
185
|
+
$reason = "DISCOVERY_ARTIFACT_GATE_BLOCKED: $($result.Output)"
|
|
186
|
+
return [ordered]@{
|
|
187
|
+
hookSpecificOutput = [ordered]@{
|
|
188
|
+
hookEventName = 'PreToolUse'
|
|
189
|
+
permissionDecision = 'deny'
|
|
190
|
+
permissionDecisionReason = $reason
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return [ordered]@{ hookSpecificOutput = [ordered]@{ hookEventName = 'PreToolUse'; permissionDecision = 'allow' } }
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
# Guard allows dot-sourcing in tests without executing the entrypoint.
|
|
199
|
+
if ($MyInvocation.InvocationName -eq '.') {
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
$decision = Invoke-DiscoveryArtifactGateDecision -ToolInputRaw $env:CLAUDE_TOOL_INPUT
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
Write-Error $_
|
|
208
|
+
exit 1
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
$decision | ConvertTo-Json -Compress -Depth 5 | Write-Output
|
|
212
|
+
|
|
213
|
+
exit 0
|