@devtrack-solution/codesdd 1.2.3 → 1.2.4-rc3

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.
Files changed (139) hide show
  1. package/.sdd/skills/curated/devtrack-api/SKILL.md +12 -5
  2. package/.sdd/skills/curated/devtrack-api/agents/claude-code.yaml +8 -0
  3. package/.sdd/skills/curated/devtrack-api/agents/codex.yaml +8 -0
  4. package/.sdd/skills/curated/devtrack-api/agents/cursor.yaml +8 -0
  5. package/.sdd/skills/curated/devtrack-api/agents/gemini.yaml +8 -0
  6. package/.sdd/skills/curated/devtrack-api/agents/kimi.yaml +8 -0
  7. package/.sdd/skills/curated/devtrack-api/agents/openai.yaml +4 -2
  8. package/.sdd/skills/curated/devtrack-api/agents/opencode.yaml +10 -0
  9. package/.sdd/skills/curated/devtrack-api/references/application-presentation.md +2 -2
  10. package/.sdd/skills/curated/devtrack-api/references/contract-pack.yaml +55 -0
  11. package/.sdd/skills/curated/devtrack-api/references/domain-modeling.md +13 -13
  12. package/.sdd/skills/curated/devtrack-api/references/foundation-layout.md +2 -3
  13. package/.sdd/skills/curated/devtrack-api/references/implementation-checklist.md +1 -1
  14. package/.sdd/skills/curated/devtrack-api/references/portable-agent-contract.md +41 -0
  15. package/.sdd/skills/curated/devtrack-api/references/typeorm-infrastructure.md +7 -9
  16. package/README.md +159 -5
  17. package/dist/applications/sdd/index.d.ts +16 -0
  18. package/dist/applications/sdd/index.js +16 -0
  19. package/dist/commands/config.js +171 -10
  20. package/dist/commands/sdd/execution.js +345 -15
  21. package/dist/commands/sdd/plugin.js +5 -0
  22. package/dist/commands/sdd/shared.d.ts +1 -0
  23. package/dist/commands/sdd/shared.js +10 -0
  24. package/dist/commands/sdd.js +38 -3
  25. package/dist/core/cli/command-matrix.js +9 -0
  26. package/dist/core/cli-command-quality.js +9 -0
  27. package/dist/core/completions/command-registry.js +45 -0
  28. package/dist/core/config-schema.d.ts +18 -1
  29. package/dist/core/config-schema.js +48 -5
  30. package/dist/core/global-config.d.ts +16 -0
  31. package/dist/core/sdd/agent-binding.d.ts +10 -10
  32. package/dist/core/sdd/agent-runtime-contract.d.ts +204 -0
  33. package/dist/core/sdd/agent-runtime-contract.js +200 -0
  34. package/dist/core/sdd/check.d.ts +2 -0
  35. package/dist/core/sdd/check.js +40 -2
  36. package/dist/core/sdd/coordination/coordination-adapters.d.ts +15 -8
  37. package/dist/core/sdd/coordination/coordination-adapters.js +43 -15
  38. package/dist/core/sdd/coordination/index.d.ts +1 -0
  39. package/dist/core/sdd/coordination/index.js +1 -0
  40. package/dist/core/sdd/coordination/redis-runtime.d.ts +131 -0
  41. package/dist/core/sdd/coordination/redis-runtime.js +698 -0
  42. package/dist/core/sdd/deepagent-contracts.d.ts +98 -4
  43. package/dist/core/sdd/deepagent-contracts.js +62 -0
  44. package/dist/core/sdd/default-bootstrap-files.d.ts +2 -2
  45. package/dist/core/sdd/default-bootstrap-files.js +14 -8
  46. package/dist/core/sdd/default-skills.js +108 -4
  47. package/dist/core/sdd/devtrack-api-appliance.d.ts +8 -1
  48. package/dist/core/sdd/devtrack-api-appliance.js +46 -23
  49. package/dist/core/sdd/docs-sync.js +21 -15
  50. package/dist/core/sdd/domain/capability-diff.d.ts +63 -0
  51. package/dist/core/sdd/domain/capability-diff.js +200 -0
  52. package/dist/core/sdd/domain/change-safety-guardrails.d.ts +74 -0
  53. package/dist/core/sdd/domain/change-safety-guardrails.js +333 -0
  54. package/dist/core/sdd/domain/semantic-intent-classifier.d.ts +29 -0
  55. package/dist/core/sdd/domain/semantic-intent-classifier.js +117 -0
  56. package/dist/core/sdd/foundation-artifact-map-validator.d.ts +16 -0
  57. package/dist/core/sdd/foundation-artifact-map-validator.js +71 -0
  58. package/dist/core/sdd/foundation-layer-manifest.d.ts +24 -0
  59. package/dist/core/sdd/foundation-layer-manifest.js +117 -0
  60. package/dist/core/sdd/intent-guard.d.ts +22 -0
  61. package/dist/core/sdd/intent-guard.js +67 -0
  62. package/dist/core/sdd/json-schema.js +9 -1
  63. package/dist/core/sdd/legacy-operations.js +76 -1
  64. package/dist/core/sdd/migrate-workspace.js +39 -0
  65. package/dist/core/sdd/package-security-gates.d.ts +21 -0
  66. package/dist/core/sdd/package-security-gates.js +119 -0
  67. package/dist/core/sdd/package-structure-gate.js +3 -8
  68. package/dist/core/sdd/parallel-feat-automation.d.ts +181 -3
  69. package/dist/core/sdd/parallel-feat-automation.js +212 -0
  70. package/dist/core/sdd/plugin-broker.d.ts +223 -4
  71. package/dist/core/sdd/plugin-broker.js +10 -0
  72. package/dist/core/sdd/plugin-cli.d.ts +30 -0
  73. package/dist/core/sdd/plugin-cli.js +70 -3
  74. package/dist/core/sdd/plugin-evidence.d.ts +73 -0
  75. package/dist/core/sdd/plugin-manifest.d.ts +69 -1
  76. package/dist/core/sdd/plugin-manifest.js +10 -0
  77. package/dist/core/sdd/plugin-policy-pack.d.ts +1 -1
  78. package/dist/core/sdd/plugin-registry.d.ts +141 -5
  79. package/dist/core/sdd/plugin-sdk-contract.d.ts +363 -0
  80. package/dist/core/sdd/plugin-sdk-contract.js +268 -0
  81. package/dist/core/sdd/plugin-skill-binding.d.ts +1 -1
  82. package/dist/core/sdd/quality-validation.d.ts +84 -11
  83. package/dist/core/sdd/release-readiness.d.ts +19 -0
  84. package/dist/core/sdd/release-readiness.js +472 -0
  85. package/dist/core/sdd/runtime-boundary-contract.d.ts +45 -0
  86. package/dist/core/sdd/runtime-boundary-contract.js +90 -0
  87. package/dist/core/sdd/sdk-agent-plugin-quality-gates.d.ts +150 -0
  88. package/dist/core/sdd/sdk-agent-plugin-quality-gates.js +258 -0
  89. package/dist/core/sdd/services/agent-run.service.d.ts +38 -6
  90. package/dist/core/sdd/services/agent-run.service.js +73 -1
  91. package/dist/core/sdd/services/capability-diff.service.d.ts +18 -0
  92. package/dist/core/sdd/services/capability-diff.service.js +26 -0
  93. package/dist/core/sdd/services/change-safety-preflight.service.d.ts +17 -0
  94. package/dist/core/sdd/services/change-safety-preflight.service.js +17 -0
  95. package/dist/core/sdd/services/context.service.d.ts +43 -340
  96. package/dist/core/sdd/services/context.service.js +323 -9
  97. package/dist/core/sdd/services/finalize.service.d.ts +25 -0
  98. package/dist/core/sdd/services/finalize.service.js +178 -16
  99. package/dist/core/sdd/services/frontend-impact.service.d.ts +1 -1
  100. package/dist/core/sdd/services/semantic-intent-classifier.service.d.ts +6 -0
  101. package/dist/core/sdd/services/semantic-intent-classifier.service.js +7 -0
  102. package/dist/core/sdd/state.d.ts +1 -0
  103. package/dist/core/sdd/state.js +251 -29
  104. package/dist/core/sdd/store/sdd-stores.js +2 -2
  105. package/dist/core/sdd/structural-health.d.ts +13 -13
  106. package/dist/core/sdd/types.d.ts +27 -12
  107. package/dist/core/sdd/types.js +4 -0
  108. package/dist/core/sdd/views.js +17 -0
  109. package/dist/core/sdd/workspace-schemas.d.ts +387 -7
  110. package/dist/core/sdd/workspace-schemas.js +196 -64
  111. package/dist/domains/sdd/index.d.ts +6 -0
  112. package/dist/domains/sdd/index.js +6 -0
  113. package/dist/infrastructures/sdd/index.d.ts +7 -0
  114. package/dist/infrastructures/sdd/index.js +6 -0
  115. package/dist/presentations/cli/sdd/index.d.ts +3 -0
  116. package/dist/presentations/cli/sdd/index.js +3 -0
  117. package/dist/shared/sdd/index.d.ts +3 -0
  118. package/dist/shared/sdd/index.js +2 -0
  119. package/package.json +9 -6
  120. package/schemas/sdd/2-plan.schema.json +207 -2
  121. package/schemas/sdd/5-quality.schema.json +281 -25
  122. package/schemas/sdd/agent-runtime-command-plan.schema.json +212 -0
  123. package/schemas/sdd/agent-runtime-opencode-run-evidence.schema.json +270 -0
  124. package/schemas/sdd/codesdd-plugin.schema.json +171 -0
  125. package/schemas/sdd/deepagent-run-request.schema.json +316 -0
  126. package/schemas/sdd/parallel-feat-automation-plan.schema.json +89 -0
  127. package/schemas/sdd/parallel-feat-scheduler-request.schema.json +116 -0
  128. package/schemas/sdd/parallel-feat-scheduler-result.schema.json +404 -0
  129. package/schemas/sdd/plugin-artifact-manifest.schema.json +109 -0
  130. package/schemas/sdd/plugin-artifact-map.schema.json +223 -0
  131. package/schemas/sdd/plugin-evidence-manifest.schema.json +109 -0
  132. package/schemas/sdd/plugin-language-runtime.schema.json +103 -0
  133. package/schemas/sdd/plugin-package-governance.schema.json +74 -0
  134. package/schemas/sdd/plugin-registry.schema.json +171 -0
  135. package/schemas/sdd/plugin-runtime-invocation-plan.schema.json +109 -0
  136. package/schemas/sdd/quality-evidence-bundle.schema.json +109 -0
  137. package/schemas/sdd/sdk-agent-plugin-quality-gate-input.schema.json +168 -0
  138. package/schemas/sdd/sdk-agent-plugin-quality-gate-report.schema.json +160 -0
  139. package/schemas/sdd/workspace-catalog.schema.json +3776 -398
@@ -31,6 +31,16 @@ function upsertMarkedBlock(source, startMarker, endMarker, blockContent) {
31
31
  const next = `${prefix}${replacement}\n`;
32
32
  return { content: next, changed: true, hasMarkers: false };
33
33
  }
34
+ function validateManagedBlock(source, startMarker, endMarker, expectedBlock, label, missingBlocks) {
35
+ if (!source.includes(startMarker) || !source.includes(endMarker)) {
36
+ missingBlocks.push(label);
37
+ return;
38
+ }
39
+ const expected = upsertMarkedBlock(source, startMarker, endMarker, expectedBlock);
40
+ if (expected.changed) {
41
+ missingBlocks.push(`${label}:DRIFT`);
42
+ }
43
+ }
34
44
  function buildReadmeBlock(memoryDir, config) {
35
45
  return `## Onboarding SDD
36
46
 
@@ -41,6 +51,8 @@ Operational authority:
41
51
 
42
52
  Initial operational directives:
43
53
  - CodeSDD is the official planner for any build request; other planners or agent-native plans are secondary execution aids only.
54
+ - In initialized CodeSDD repositories, any user request that implies implementation, file edits, validation, execution, or finalize must be treated as requiring CodeSDD planning unless the user explicitly marks it as read-only or outside CodeSDD.
55
+ - For change requests, agents must bind the work to an active or ready FEAT through \`${CLI_NAME} sdd next\` and \`${CLI_NAME} sdd context <FEAT-ID>\` before implementation; agent-native plans may only decompose execution after that CodeSDD context exists.
44
56
  - For API/backend work, use \`devtrack-api\` by default unless the user or SDD context explicitly selects another skill/profile; Python/Flask API work stays routed to \`api-clean-flask-langgraph\`.
45
57
  - During init, onboard, insight, and debate flows, CodeSDD-managed agent instruction blocks must be inspected and reconfigured when they drift from this contract.
46
58
  - Commit requests must follow Conventional Commits, selective staging, and grouping by modified directory plus change protocol (\`src\`, \`${memoryDir}\`, docs, config, infra, dependencies, or generated files).
@@ -102,6 +114,8 @@ Operational exclusivity:
102
114
 
103
115
  Initial directives:
104
116
  - CodeSDD is the official planner for requested work; model-native plans and other planning tools are subordinate to CodeSDD artifacts.
117
+ - In initialized CodeSDD repositories, implementation, edit, validation, execution, and finalize requests implicitly require CodeSDD planning unless the user explicitly marks the request as read-only or outside CodeSDD.
118
+ - A change request must use the active or ready FEAT returned by \`${CLI_NAME} sdd next\` and must load \`${CLI_NAME} sdd context <FEAT-ID>\` before coding; model-native plans may only refine execution after that context exists.
105
119
  - API/backend work uses \`devtrack-api\` by default unless an explicit skill/profile says otherwise; Python/Flask API work uses \`api-clean-flask-langgraph\`.
106
120
  - CodeSDD-managed blocks in \`AGENTS.md\`, \`AGENT.md\`, \`CLAUDE.md\`, \`GEMINI.md\`, \`.codex\`, \`.opencode\`, \`.ai\`, \`.cloud\`, or equivalent agent files must be inspected and normalized during init/onboard/insight/debate when CodeSDD owns project governance.
107
121
  - Commits must use Conventional Commits, selective staging, and grouping by modified directory plus protocol: source, \`${memoryDir}\`, docs, config, infra, dependencies, generated files, renames, or deletions.`;
@@ -134,6 +148,8 @@ Do not use external context, memory, workflow, backlog, scratchpad, or handoff t
134
148
 
135
149
  Initial directives:
136
150
  - CodeSDD is the official planner. Other planning systems may assist execution only after CodeSDD context exists.
151
+ - In initialized CodeSDD repositories, implementation, edit, validation, execution, and finalize requests implicitly require CodeSDD planning unless the user explicitly marks the request as read-only or outside CodeSDD.
152
+ - Agents must bind each change request to the active or ready FEAT returned by \`${CLI_NAME} sdd next\` and load \`${CLI_NAME} sdd context <FEAT-ID>\` before coding.
137
153
  - API/backend work defaults to \`devtrack-api\` unless an explicit skill/profile overrides it; Python/Flask API work remains a documented exception routed to \`api-clean-flask-langgraph\`.
138
154
  - CodeSDD lifecycle entrypoints must inspect and normalize CodeSDD-managed agent instruction blocks in root and tool-specific agent files.
139
155
  - Commit work must use Conventional Commits, selective staging, and directory/protocol grouping. Source changes, \`${memoryDir}\` governance, docs, config, infra, dependencies, generated files, renames, and deletions should be staged and committed separately unless indivisible.`;
@@ -225,11 +241,9 @@ export async function validateSddGuideDocs(projectRoot, paths, config) {
225
241
  const agentCompatRaw = (await fileExists(agentCompatPath))
226
242
  ? await fs.readFile(agentCompatPath, 'utf-8')
227
243
  : '';
228
- if (!readmeRaw.includes(README_SDD_BLOCK_START) || !readmeRaw.includes(README_SDD_BLOCK_END)) {
229
- missingBlocks.push('README.md::SDD:ONBOARDING');
230
- }
244
+ validateManagedBlock(readmeRaw, README_SDD_BLOCK_START, README_SDD_BLOCK_END, buildReadmeBlock(memoryDirName, config), 'README.md::SDD:ONBOARDING', missingBlocks);
231
245
  if (internalReadmeRaw !==
232
- buildSddInternalReadme(path.relative(projectRoot, paths.memoryRoot) || '.sdd', {
246
+ buildSddInternalReadme(memoryDirName, {
233
247
  discovery: config?.folders.discovery,
234
248
  planning: config?.folders.planning,
235
249
  skills: config?.folders.skills,
@@ -240,17 +254,9 @@ export async function validateSddGuideDocs(projectRoot, paths, config) {
240
254
  })) {
241
255
  missingBlocks.push(`${memoryDirName}/README.md::SDD:INTERNAL`);
242
256
  }
243
- if (!agentRaw.includes(AGENT_SDD_BLOCK_START) || !agentRaw.includes(AGENT_SDD_BLOCK_END)) {
244
- missingBlocks.push(`${memoryDirName}/AGENT.md::SDD:GUIA`);
245
- }
246
- if (!agentsRaw.includes(ROOT_AGENTS_SDD_BLOCK_START) ||
247
- !agentsRaw.includes(ROOT_AGENTS_SDD_BLOCK_END)) {
248
- missingBlocks.push('AGENTS.md::SDD:ROOT-AGENTS');
249
- }
250
- if (!agentCompatRaw.includes(ROOT_AGENTS_SDD_BLOCK_START) ||
251
- !agentCompatRaw.includes(ROOT_AGENTS_SDD_BLOCK_END)) {
252
- missingBlocks.push('AGENT.md::SDD:ROOT-AGENTS');
253
- }
257
+ validateManagedBlock(agentRaw, AGENT_SDD_BLOCK_START, AGENT_SDD_BLOCK_END, buildAgentGuideBlock(memoryDirName, config), `${memoryDirName}/AGENT.md::SDD:GUIA`, missingBlocks);
258
+ validateManagedBlock(agentsRaw, ROOT_AGENTS_SDD_BLOCK_START, ROOT_AGENTS_SDD_BLOCK_END, buildRootAgentsBlock(memoryDirName), 'AGENTS.md::SDD:ROOT-AGENTS', missingBlocks);
259
+ validateManagedBlock(agentCompatRaw, ROOT_AGENTS_SDD_BLOCK_START, ROOT_AGENTS_SDD_BLOCK_END, buildRootAgentsBlock(memoryDirName), 'AGENT.md::SDD:ROOT-AGENTS', missingBlocks);
254
260
  return {
255
261
  documentationSync: missingBlocks.length === 0,
256
262
  missingBlocks,
@@ -0,0 +1,63 @@
1
+ import type { ChangeSafetyEvaluation, PlannedFileChange } from './change-safety-guardrails.js';
2
+ export declare const CAPABILITY_KINDS: readonly ["route", "page", "cli_command", "public_contract", "schema", "event", "core_flow", "governance_state"];
3
+ export declare const CAPABILITY_CHANGE_TYPES: readonly ["added", "removed", "modified", "unchanged"];
4
+ export declare const CAPABILITY_RISK_LEVELS: readonly ["none", "low", "medium", "high", "critical"];
5
+ export type CapabilityKind = (typeof CAPABILITY_KINDS)[number];
6
+ export type CapabilityChangeType = (typeof CAPABILITY_CHANGE_TYPES)[number];
7
+ export type CapabilityRiskLevel = (typeof CAPABILITY_RISK_LEVELS)[number];
8
+ export interface CapabilityInventoryItem {
9
+ kind: CapabilityKind;
10
+ id: string;
11
+ path?: string;
12
+ fingerprint?: string;
13
+ metadata?: Record<string, unknown>;
14
+ }
15
+ export interface CapabilityInventory {
16
+ schema_version: 1;
17
+ contract: 'capability-inventory/v1';
18
+ items: CapabilityInventoryItem[];
19
+ }
20
+ export interface CapabilityDiffEntry {
21
+ kind: CapabilityKind;
22
+ id: string;
23
+ change: CapabilityChangeType;
24
+ before?: CapabilityInventoryItem;
25
+ after?: CapabilityInventoryItem;
26
+ }
27
+ export interface CapabilityDiffCounts {
28
+ added: number;
29
+ removed: number;
30
+ modified: number;
31
+ unchanged: number;
32
+ }
33
+ export interface CapabilityDiffReport {
34
+ schema_version: 1;
35
+ contract: 'capability-diff-report/v1';
36
+ entries: CapabilityDiffEntry[];
37
+ counts: CapabilityDiffCounts;
38
+ }
39
+ export interface CapabilityRiskSignal {
40
+ code: string;
41
+ level: Exclude<CapabilityRiskLevel, 'none'>;
42
+ message: string;
43
+ capability_ref?: string;
44
+ path?: string;
45
+ }
46
+ export interface CapabilityRiskReport {
47
+ schema_version: 1;
48
+ contract: 'deterministic-capability-risk/v1';
49
+ level: CapabilityRiskLevel;
50
+ score: number;
51
+ signals: CapabilityRiskSignal[];
52
+ }
53
+ export interface CapabilityRiskInput {
54
+ diff: CapabilityDiffReport;
55
+ change_safety?: ChangeSafetyEvaluation;
56
+ planned_changes?: PlannedFileChange[];
57
+ required_kinds?: CapabilityKind[];
58
+ }
59
+ export declare function buildCapabilityInventory(items: CapabilityInventoryItem[]): CapabilityInventory;
60
+ export declare function diffCapabilityInventories(before: CapabilityInventory, after: CapabilityInventory): CapabilityDiffReport;
61
+ export declare function scoreCapabilityDiffRisk(input: CapabilityRiskInput): CapabilityRiskReport;
62
+ export declare function capabilityKey(item: Pick<CapabilityInventoryItem, 'kind' | 'id'>): string;
63
+ //# sourceMappingURL=capability-diff.d.ts.map
@@ -0,0 +1,200 @@
1
+ import { createHash } from 'node:crypto';
2
+ export const CAPABILITY_KINDS = [
3
+ 'route',
4
+ 'page',
5
+ 'cli_command',
6
+ 'public_contract',
7
+ 'schema',
8
+ 'event',
9
+ 'core_flow',
10
+ 'governance_state',
11
+ ];
12
+ export const CAPABILITY_CHANGE_TYPES = ['added', 'removed', 'modified', 'unchanged'];
13
+ export const CAPABILITY_RISK_LEVELS = ['none', 'low', 'medium', 'high', 'critical'];
14
+ const PUBLIC_SURFACE_KINDS = new Set([
15
+ 'route',
16
+ 'page',
17
+ 'cli_command',
18
+ 'public_contract',
19
+ 'schema',
20
+ 'event',
21
+ ]);
22
+ const CRITICAL_KIND_WEIGHTS = new Map([
23
+ ['core_flow', 'critical'],
24
+ ['governance_state', 'critical'],
25
+ ]);
26
+ const RISK_SCORE = {
27
+ none: 0,
28
+ low: 25,
29
+ medium: 50,
30
+ high: 75,
31
+ critical: 100,
32
+ };
33
+ export function buildCapabilityInventory(items) {
34
+ return {
35
+ schema_version: 1,
36
+ contract: 'capability-inventory/v1',
37
+ items: normalizeCapabilityItems(items),
38
+ };
39
+ }
40
+ export function diffCapabilityInventories(before, after) {
41
+ const beforeByKey = indexByCapabilityKey(before.items);
42
+ const afterByKey = indexByCapabilityKey(after.items);
43
+ const keys = [...new Set([...beforeByKey.keys(), ...afterByKey.keys()])].sort();
44
+ const entries = keys.map((key) => {
45
+ const beforeItem = beforeByKey.get(key);
46
+ const afterItem = afterByKey.get(key);
47
+ const item = afterItem ?? beforeItem;
48
+ if (!item) {
49
+ throw new Error(`Capability key ${key} resolved without an inventory item.`);
50
+ }
51
+ if (!beforeItem)
52
+ return { kind: item.kind, id: item.id, change: 'added', after: afterItem };
53
+ if (!afterItem)
54
+ return { kind: item.kind, id: item.id, change: 'removed', before: beforeItem };
55
+ if (beforeItem.fingerprint !== afterItem.fingerprint) {
56
+ return { kind: item.kind, id: item.id, change: 'modified', before: beforeItem, after: afterItem };
57
+ }
58
+ return { kind: item.kind, id: item.id, change: 'unchanged', before: beforeItem, after: afterItem };
59
+ });
60
+ return {
61
+ schema_version: 1,
62
+ contract: 'capability-diff-report/v1',
63
+ entries,
64
+ counts: countDiffEntries(entries),
65
+ };
66
+ }
67
+ export function scoreCapabilityDiffRisk(input) {
68
+ const signals = [];
69
+ const presentKinds = new Set(input.diff.entries.map((entry) => entry.kind));
70
+ for (const requiredKind of input.required_kinds ?? []) {
71
+ if (!presentKinds.has(requiredKind)) {
72
+ signals.push({
73
+ code: 'required_capability_inventory_missing',
74
+ level: CRITICAL_KIND_WEIGHTS.get(requiredKind) ?? 'high',
75
+ message: `Required capability inventory kind ${requiredKind} is missing from before/after diff evidence.`,
76
+ capability_ref: requiredKind,
77
+ });
78
+ }
79
+ }
80
+ for (const entry of input.diff.entries) {
81
+ if (entry.change === 'removed') {
82
+ signals.push(riskForRemovedCapability(entry));
83
+ }
84
+ if (entry.change === 'modified' && PUBLIC_SURFACE_KINDS.has(entry.kind)) {
85
+ signals.push({
86
+ code: 'public_capability_modified',
87
+ level: 'medium',
88
+ message: `Public capability ${capabilityRef(entry)} changed.`,
89
+ capability_ref: capabilityRef(entry),
90
+ path: entry.after?.path ?? entry.before?.path,
91
+ });
92
+ }
93
+ if (entry.change === 'added' && PUBLIC_SURFACE_KINDS.has(entry.kind)) {
94
+ signals.push({
95
+ code: 'public_capability_added',
96
+ level: 'low',
97
+ message: `Public capability ${capabilityRef(entry)} was added.`,
98
+ capability_ref: capabilityRef(entry),
99
+ path: entry.after?.path,
100
+ });
101
+ }
102
+ }
103
+ if (input.change_safety?.status === 'blocked') {
104
+ signals.push(...input.change_safety.violations.map((violation) => ({
105
+ code: `change_safety_${violation.code}`,
106
+ level: 'critical',
107
+ message: violation.message,
108
+ path: violation.path,
109
+ })));
110
+ }
111
+ for (const plannedChange of input.planned_changes ?? []) {
112
+ if (plannedChange.operation === 'delete' || plannedChange.operation === 'rename' || plannedChange.operation === 'replace') {
113
+ signals.push({
114
+ code: 'destructive_planned_change',
115
+ level: 'high',
116
+ message: `Planned ${plannedChange.operation} change affects ${plannedChange.path}.`,
117
+ path: plannedChange.path,
118
+ });
119
+ }
120
+ }
121
+ const level = maxRiskLevel(signals.map((signal) => signal.level));
122
+ return {
123
+ schema_version: 1,
124
+ contract: 'deterministic-capability-risk/v1',
125
+ level,
126
+ score: RISK_SCORE[level],
127
+ signals: sortRiskSignals(signals),
128
+ };
129
+ }
130
+ export function capabilityKey(item) {
131
+ return `${item.kind}:${item.id}`;
132
+ }
133
+ function normalizeCapabilityItems(items) {
134
+ const byKey = new Map();
135
+ for (const item of items) {
136
+ const normalized = {
137
+ kind: item.kind,
138
+ id: item.id.trim(),
139
+ path: item.path?.trim(),
140
+ metadata: item.metadata ?? {},
141
+ fingerprint: item.fingerprint ?? fingerprintCapabilityItem(item),
142
+ };
143
+ byKey.set(capabilityKey(normalized), normalized);
144
+ }
145
+ return [...byKey.values()].sort((left, right) => capabilityKey(left).localeCompare(capabilityKey(right)));
146
+ }
147
+ function fingerprintCapabilityItem(item) {
148
+ const stable = stableStringify({
149
+ kind: item.kind,
150
+ id: item.id.trim(),
151
+ path: item.path?.trim() ?? '',
152
+ metadata: item.metadata ?? {},
153
+ });
154
+ return createHash('sha256').update(stable).digest('hex');
155
+ }
156
+ function indexByCapabilityKey(items) {
157
+ return new Map(items.map((item) => [capabilityKey(item), item]));
158
+ }
159
+ function countDiffEntries(entries) {
160
+ return entries.reduce((counts, entry) => {
161
+ counts[entry.change] += 1;
162
+ return counts;
163
+ }, { added: 0, removed: 0, modified: 0, unchanged: 0 });
164
+ }
165
+ function riskForRemovedCapability(entry) {
166
+ const criticalLevel = CRITICAL_KIND_WEIGHTS.get(entry.kind);
167
+ const level = criticalLevel ?? (PUBLIC_SURFACE_KINDS.has(entry.kind) ? 'high' : 'medium');
168
+ return {
169
+ code: 'capability_removed',
170
+ level,
171
+ message: `Capability ${capabilityRef(entry)} was removed.`,
172
+ capability_ref: capabilityRef(entry),
173
+ path: entry.before?.path,
174
+ };
175
+ }
176
+ function capabilityRef(entry) {
177
+ return `${entry.kind}:${entry.id}`;
178
+ }
179
+ function maxRiskLevel(levels) {
180
+ if (levels.length === 0)
181
+ return 'none';
182
+ return levels.reduce((max, level) => (RISK_SCORE[level] > RISK_SCORE[max] ? level : max), 'none');
183
+ }
184
+ function sortRiskSignals(signals) {
185
+ return [...signals].sort((left, right) => RISK_SCORE[right.level] - RISK_SCORE[left.level] ||
186
+ left.code.localeCompare(right.code) ||
187
+ (left.capability_ref ?? '').localeCompare(right.capability_ref ?? '') ||
188
+ (left.path ?? '').localeCompare(right.path ?? ''));
189
+ }
190
+ function stableStringify(value) {
191
+ if (Array.isArray(value)) {
192
+ return `[${value.map((entry) => stableStringify(entry)).join(',')}]`;
193
+ }
194
+ if (value && typeof value === 'object') {
195
+ const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
196
+ return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(',')}}`;
197
+ }
198
+ return JSON.stringify(value);
199
+ }
200
+ //# sourceMappingURL=capability-diff.js.map
@@ -0,0 +1,74 @@
1
+ export declare const CHANGE_SAFETY_OPERATIONS: readonly ["add", "modify", "remove", "replace", "refactor", "optimize"];
2
+ export type ChangeSafetyOperation = (typeof CHANGE_SAFETY_OPERATIONS)[number];
3
+ export type PlannedFileOperation = 'create' | 'modify' | 'delete' | 'rename' | 'replace';
4
+ export interface ExplicitModificationIntent {
5
+ operation?: string;
6
+ }
7
+ export interface ContextLock {
8
+ allowed_paths?: string[];
9
+ forbidden_paths?: string[];
10
+ protected_core?: string[];
11
+ }
12
+ export interface ChangeBudget {
13
+ max_files_changed?: number;
14
+ max_new_files?: number;
15
+ max_deleted_files?: number;
16
+ }
17
+ export interface GovernedOverride {
18
+ feature_id?: string;
19
+ intent?: string;
20
+ rationale?: string;
21
+ write_scope?: string[];
22
+ expected_deletions?: string[];
23
+ rollback_plan?: string;
24
+ compensating_control?: string;
25
+ approver?: string;
26
+ expires_at?: string;
27
+ }
28
+ export interface PlannedFileChange {
29
+ path: string;
30
+ operation: PlannedFileOperation;
31
+ previous_path?: string;
32
+ }
33
+ export interface ChangeSafetyContract {
34
+ explicit_modification_intent?: ExplicitModificationIntent;
35
+ intent?: ExplicitModificationIntent;
36
+ context_lock?: ContextLock;
37
+ change_budget?: ChangeBudget;
38
+ governed_override?: GovernedOverride;
39
+ }
40
+ export type ChangeSafetyViolationCode = 'planned_changes_missing' | 'intent_missing' | 'intent_invalid' | 'add_intent_destructive_change' | 'context_lock_outside_allowed_paths' | 'context_lock_forbidden_path' | 'protected_core_change' | 'change_budget_files_exceeded' | 'change_budget_new_files_exceeded' | 'change_budget_deleted_files_exceeded' | 'governed_override_required' | 'governed_override_field_missing' | 'governed_override_feature_mismatch' | 'governed_override_intent_mismatch' | 'governed_override_expires_at_invalid' | 'governed_override_expired' | 'governed_override_scope_mismatch' | 'governed_override_deletions_mismatch';
41
+ export interface ChangeSafetyViolation {
42
+ code: ChangeSafetyViolationCode;
43
+ message: string;
44
+ path?: string;
45
+ limit?: number;
46
+ actual?: number;
47
+ }
48
+ export interface ChangeSafetyCounts {
49
+ files_changed: number;
50
+ new_files: number;
51
+ deleted_files: number;
52
+ }
53
+ export interface ChangeSafetyEvaluation {
54
+ status: 'allowed' | 'blocked';
55
+ operation: ChangeSafetyOperation | '';
56
+ violations: ChangeSafetyViolation[];
57
+ counts: ChangeSafetyCounts;
58
+ governed_override: GovernedOverrideEvaluation;
59
+ }
60
+ export interface ChangeSafetyEvaluationOptions {
61
+ feature_id?: string;
62
+ now?: Date | string;
63
+ }
64
+ export interface GovernedOverrideEvaluation {
65
+ required: boolean;
66
+ status: 'not_required' | 'valid' | 'invalid';
67
+ violations: ChangeSafetyViolation[];
68
+ }
69
+ export declare function isChangeSafetyOperation(value: string | undefined): value is ChangeSafetyOperation;
70
+ export declare function evaluateChangeSafety(contract: ChangeSafetyContract, plannedChanges: PlannedFileChange[], options?: ChangeSafetyEvaluationOptions): ChangeSafetyEvaluation;
71
+ export declare function countPlannedChanges(plannedChanges: PlannedFileChange[]): ChangeSafetyCounts;
72
+ export declare function normalizeProjectPath(value: string): string;
73
+ export declare function pathMatchesPattern(candidatePath: string, pattern: string): boolean;
74
+ //# sourceMappingURL=change-safety-guardrails.d.ts.map