gsdd-cli 0.18.5 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +609 -608
  3. package/agents/DISTILLATION.md +421 -421
  4. package/agents/README.md +62 -62
  5. package/agents/approach-explorer.md +361 -361
  6. package/agents/debugger.md +82 -82
  7. package/agents/executor.md +394 -394
  8. package/agents/integration-checker.md +318 -318
  9. package/agents/mapper.md +103 -103
  10. package/agents/planner.md +313 -313
  11. package/agents/researcher.md +84 -84
  12. package/agents/roadmapper.md +296 -296
  13. package/agents/synthesizer.md +236 -236
  14. package/agents/verifier.md +337 -337
  15. package/bin/adapters/agents.mjs +34 -34
  16. package/bin/adapters/claude.mjs +191 -191
  17. package/bin/adapters/codex.mjs +85 -85
  18. package/bin/adapters/index.mjs +20 -20
  19. package/bin/adapters/opencode.mjs +278 -278
  20. package/bin/gsdd.mjs +123 -116
  21. package/bin/lib/cli-utils.mjs +28 -28
  22. package/bin/lib/evidence-contract.mjs +112 -112
  23. package/bin/lib/file-ops.mjs +186 -144
  24. package/bin/lib/health-truth.mjs +181 -178
  25. package/bin/lib/health.mjs +246 -226
  26. package/bin/lib/init-flow.mjs +247 -231
  27. package/bin/lib/init-prompts.mjs +248 -247
  28. package/bin/lib/init-runtime.mjs +191 -190
  29. package/bin/lib/init.mjs +17 -17
  30. package/bin/lib/lifecycle-preflight.mjs +347 -325
  31. package/bin/lib/lifecycle-state.mjs +351 -267
  32. package/bin/lib/manifest.mjs +116 -114
  33. package/bin/lib/models.mjs +411 -411
  34. package/bin/lib/phase.mjs +360 -358
  35. package/bin/lib/plan-constants.mjs +30 -30
  36. package/bin/lib/provenance.mjs +109 -106
  37. package/bin/lib/rendering.mjs +115 -83
  38. package/bin/lib/runtime-freshness.mjs +214 -214
  39. package/bin/lib/templates.mjs +225 -224
  40. package/bin/lib/workspace-root.mjs +2 -1
  41. package/distilled/DESIGN.md +2333 -2323
  42. package/distilled/EVIDENCE-INDEX.md +394 -392
  43. package/distilled/README.md +196 -193
  44. package/distilled/SKILL.md +86 -85
  45. package/distilled/templates/agents.block.md +21 -21
  46. package/distilled/templates/agents.md +6 -6
  47. package/distilled/templates/approach.md +232 -232
  48. package/distilled/templates/auth-matrix.md +78 -78
  49. package/distilled/templates/brownfield-change/CHANGE.md +99 -0
  50. package/distilled/templates/brownfield-change/HANDOFF.md +38 -0
  51. package/distilled/templates/brownfield-change/VERIFICATION.md +56 -0
  52. package/distilled/templates/codebase/architecture.md +110 -110
  53. package/distilled/templates/codebase/concerns.md +95 -95
  54. package/distilled/templates/codebase/conventions.md +193 -193
  55. package/distilled/templates/codebase/stack.md +96 -96
  56. package/distilled/templates/delegates/approach-explorer.md +25 -25
  57. package/distilled/templates/delegates/mapper-arch.md +26 -26
  58. package/distilled/templates/delegates/mapper-concerns.md +27 -27
  59. package/distilled/templates/delegates/mapper-quality.md +28 -28
  60. package/distilled/templates/delegates/mapper-tech.md +25 -25
  61. package/distilled/templates/delegates/plan-checker.md +68 -68
  62. package/distilled/templates/delegates/researcher-architecture.md +30 -30
  63. package/distilled/templates/delegates/researcher-features.md +30 -30
  64. package/distilled/templates/delegates/researcher-pitfalls.md +30 -30
  65. package/distilled/templates/delegates/researcher-stack.md +30 -30
  66. package/distilled/templates/delegates/researcher-synthesizer.md +31 -31
  67. package/distilled/templates/research/architecture.md +57 -57
  68. package/distilled/templates/research/features.md +23 -23
  69. package/distilled/templates/research/pitfalls.md +46 -46
  70. package/distilled/templates/research/stack.md +45 -45
  71. package/distilled/templates/research/summary.md +67 -67
  72. package/distilled/templates/roadmap.md +74 -62
  73. package/distilled/templates/spec.md +110 -110
  74. package/distilled/workflows/audit-milestone.md +275 -271
  75. package/distilled/workflows/complete-milestone.md +336 -332
  76. package/distilled/workflows/execute.md +454 -449
  77. package/distilled/workflows/map-codebase.md +253 -253
  78. package/distilled/workflows/new-milestone.md +242 -238
  79. package/distilled/workflows/new-project.md +398 -398
  80. package/distilled/workflows/pause.md +160 -156
  81. package/distilled/workflows/plan-milestone-gaps.md +183 -183
  82. package/distilled/workflows/plan.md +451 -447
  83. package/distilled/workflows/progress.md +227 -223
  84. package/distilled/workflows/quick.md +351 -347
  85. package/distilled/workflows/resume.md +220 -212
  86. package/distilled/workflows/verify-work.md +260 -260
  87. package/distilled/workflows/verify.md +431 -429
  88. package/docs/BROWNFIELD-PROOF.md +95 -95
  89. package/docs/RUNTIME-SUPPORT.md +80 -69
  90. package/docs/USER-GUIDE.md +394 -386
  91. package/docs/VERIFICATION-DISCIPLINE.md +59 -59
  92. package/docs/claude/context-monitor.md +98 -98
  93. package/docs/proof/consumer-node-cli/README.md +37 -37
  94. package/docs/proof/consumer-node-cli/ROADMAP.md +14 -14
  95. package/docs/proof/consumer-node-cli/SPEC.md +17 -17
  96. package/docs/proof/consumer-node-cli/brief.md +9 -9
  97. package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-PLAN.md +34 -34
  98. package/docs/proof/consumer-node-cli/phases/01-foundation/01-01-SUMMARY.md +10 -10
  99. package/docs/proof/consumer-node-cli/phases/01-foundation/01-VERIFICATION.md +30 -30
  100. package/package.json +62 -61
package/bin/gsdd.mjs CHANGED
@@ -1,66 +1,64 @@
1
- #!/usr/bin/env node
2
-
3
- // gsdd - Workspine CLI
4
-
1
+ #!/usr/bin/env node
2
+
5
3
  import { realpathSync, readFileSync } from 'fs';
6
- import { join, dirname } from 'path';
7
- import { fileURLToPath } from 'url';
8
- import { createAdapterRegistry } from './adapters/index.mjs';
9
- import {
10
- renderAgentsBoundedBlock,
11
- renderAgentsFileContent,
12
- renderOpenCodeCommandContent,
13
- renderSkillContent,
14
- upsertBoundedBlock,
15
- getDelegateContent,
16
- } from './lib/rendering.mjs';
17
- import { loadProjectModelConfig, getRuntimeModelOverride, resolveRuntimeAgentModel, cmdModels } from './lib/models.mjs';
18
- import { createCmdInit, createCmdUpdate, cmdHelp } from './lib/init.mjs';
19
- import { cmdFindPhase, cmdVerify, cmdScaffold, cmdPhaseStatus } from './lib/phase.mjs';
20
- import { cmdFileOp } from './lib/file-ops.mjs';
21
- import { createCmdHealth } from './lib/health.mjs';
22
- import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
23
-
4
+ import { join, dirname } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { createAdapterRegistry } from './adapters/index.mjs';
7
+ import {
8
+ renderAgentsBoundedBlock,
9
+ renderAgentsFileContent,
10
+ renderOpenCodeCommandContent,
11
+ renderSkillContent,
12
+ upsertBoundedBlock,
13
+ getDelegateContent,
14
+ } from './lib/rendering.mjs';
15
+ import { loadProjectModelConfig, getRuntimeModelOverride, resolveRuntimeAgentModel, cmdModels } from './lib/models.mjs';
16
+ import { createCmdInit, createCmdUpdate, cmdHelp } from './lib/init.mjs';
17
+ import { cmdFindPhase, cmdVerify, cmdScaffold, cmdPhaseStatus } from './lib/phase.mjs';
18
+ import { cmdFileOp } from './lib/file-ops.mjs';
19
+ import { createCmdHealth } from './lib/health.mjs';
20
+ import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
21
+ import { resolveWorkspaceContext } from './lib/workspace-root.mjs';
22
+
24
23
  const __filename = fileURLToPath(import.meta.url);
25
24
  const __dirname = dirname(__filename);
26
25
  const DISTILLED_DIR = join(__dirname, '..', 'distilled');
27
26
  const AGENTS_DIR = join(__dirname, '..', 'agents');
28
27
  const PACKAGE_JSON = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
29
- const CWD = process.cwd();
30
- const IS_MAIN = process.argv[1]
31
- ? realpathSync(process.argv[1]) === realpathSync(__filename)
32
- : false;
33
-
34
- const [,, command, ...args] = process.argv;
35
-
36
- function defineWorkflow({ mutatesArtifacts = true, ...workflow }) {
37
- return {
38
- ...workflow,
39
- mutatesArtifacts,
40
- agent: mutatesArtifacts ? 'Code' : 'Plan',
41
- opencodeType: mutatesArtifacts ? 'edit' : 'plan',
42
- };
43
- }
44
-
45
- const WORKFLOWS = [
46
- defineWorkflow({ name: 'gsdd-new-project', workflow: 'new-project.md', description: 'New project - questioning, codebase audit, research, spec, roadmap' }),
47
- defineWorkflow({ name: 'gsdd-map-codebase', workflow: 'map-codebase.md', description: 'Map or refresh codebase - 4 parallel mappers, staleness check, secrets scan' }),
48
- defineWorkflow({ name: 'gsdd-plan', workflow: 'plan.md', description: 'Plan a phase - research check, backward planning, task creation' }),
49
- defineWorkflow({ name: 'gsdd-execute', workflow: 'execute.md', description: 'Execute a phase plan - implement tasks, verify changes, follow repo git conventions' }),
50
- defineWorkflow({ name: 'gsdd-verify', workflow: 'verify.md', description: 'Verify a completed phase - 3-level checks, anti-pattern scan' }),
51
- defineWorkflow({ name: 'gsdd-verify-work', workflow: 'verify-work.md', description: 'Conversational UAT testing - validate user-facing behavior with structured gap tracking' }),
52
- defineWorkflow({ name: 'gsdd-audit-milestone', workflow: 'audit-milestone.md', description: 'Audit a completed milestone - cross-phase integration, requirements coverage, E2E flows' }),
53
- defineWorkflow({ name: 'gsdd-complete-milestone', workflow: 'complete-milestone.md', description: 'Complete milestone - archive, evolve spec, collapse roadmap' }),
54
- defineWorkflow({ name: 'gsdd-new-milestone', workflow: 'new-milestone.md', description: 'New milestone - gather goals, define requirements, create roadmap phases' }),
55
- defineWorkflow({ name: 'gsdd-plan-milestone-gaps', workflow: 'plan-milestone-gaps.md', description: 'Plan gap closure phases from audit results' }),
56
- defineWorkflow({ name: 'gsdd-quick', workflow: 'quick.md', description: 'Quick task - plan and execute a sub-hour task outside the phase cycle' }),
57
- defineWorkflow({ name: 'gsdd-pause', workflow: 'pause.md', description: 'Pause work - save session context for seamless resumption' }),
58
- defineWorkflow({ name: 'gsdd-resume', workflow: 'resume.md', description: 'Resume work - restore context and route to next action' }),
59
- defineWorkflow({ name: 'gsdd-progress', workflow: 'progress.md', description: 'Check progress - show project status and route to next action', mutatesArtifacts: false }),
60
- ];
61
-
62
- const FRAMEWORK_VERSION = 'v1.4';
63
-
28
+ const IS_MAIN = process.argv[1]
29
+ ? realpathSync(process.argv[1]) === realpathSync(__filename)
30
+ : false;
31
+
32
+ const [,, command, ...args] = process.argv;
33
+
34
+ function defineWorkflow({ mutatesArtifacts = true, ...workflow }) {
35
+ return {
36
+ ...workflow,
37
+ mutatesArtifacts,
38
+ agent: mutatesArtifacts ? 'Code' : 'Plan',
39
+ opencodeType: mutatesArtifacts ? 'edit' : 'plan',
40
+ };
41
+ }
42
+
43
+ const WORKFLOWS = [
44
+ defineWorkflow({ name: 'gsdd-new-project', workflow: 'new-project.md', description: 'New project - questioning, codebase audit, research, spec, roadmap' }),
45
+ defineWorkflow({ name: 'gsdd-map-codebase', workflow: 'map-codebase.md', description: 'Map or refresh codebase - 4 parallel mappers, staleness check, secrets scan' }),
46
+ defineWorkflow({ name: 'gsdd-plan', workflow: 'plan.md', description: 'Plan a phase - research check, backward planning, task creation' }),
47
+ defineWorkflow({ name: 'gsdd-execute', workflow: 'execute.md', description: 'Execute a phase plan - implement tasks, verify changes, follow repo git conventions' }),
48
+ defineWorkflow({ name: 'gsdd-verify', workflow: 'verify.md', description: 'Verify a completed phase - 3-level checks, anti-pattern scan' }),
49
+ defineWorkflow({ name: 'gsdd-verify-work', workflow: 'verify-work.md', description: 'Conversational UAT testing - validate user-facing behavior with structured gap tracking' }),
50
+ defineWorkflow({ name: 'gsdd-audit-milestone', workflow: 'audit-milestone.md', description: 'Audit a completed milestone - cross-phase integration, requirements coverage, E2E flows' }),
51
+ defineWorkflow({ name: 'gsdd-complete-milestone', workflow: 'complete-milestone.md', description: 'Complete milestone - archive, evolve spec, collapse roadmap' }),
52
+ defineWorkflow({ name: 'gsdd-new-milestone', workflow: 'new-milestone.md', description: 'New milestone - gather goals, define requirements, create roadmap phases' }),
53
+ defineWorkflow({ name: 'gsdd-plan-milestone-gaps', workflow: 'plan-milestone-gaps.md', description: 'Plan gap closure phases from audit results' }),
54
+ defineWorkflow({ name: 'gsdd-quick', workflow: 'quick.md', description: 'Quick task - plan and execute a sub-hour task outside the phase cycle' }),
55
+ defineWorkflow({ name: 'gsdd-pause', workflow: 'pause.md', description: 'Pause work - save session context for seamless resumption' }),
56
+ defineWorkflow({ name: 'gsdd-resume', workflow: 'resume.md', description: 'Resume work - restore context and route to next action' }),
57
+ defineWorkflow({ name: 'gsdd-progress', workflow: 'progress.md', description: 'Check progress - show project status and route to next action', mutatesArtifacts: false }),
58
+ ];
59
+
60
+ const FRAMEWORK_VERSION = 'v1.4';
61
+
64
62
  function createCliContext(cwd = process.cwd()) {
65
63
  return {
66
64
  cwd,
@@ -71,62 +69,71 @@ function createCliContext(cwd = process.cwd()) {
71
69
  packageVersion: PACKAGE_JSON.version,
72
70
  workflows: WORKFLOWS,
73
71
  frameworkVersion: FRAMEWORK_VERSION,
74
- adapters: createAdapterRegistry({
75
- cwd,
76
- workflows: WORKFLOWS,
77
- renderAgentsBoundedBlock,
78
- renderAgentsFileContent,
79
- renderOpenCodeCommandContent,
80
- renderSkillContent,
81
- upsertBoundedBlock,
82
- getDelegateContent,
83
- loadProjectModelConfig,
84
- getRuntimeModelOverride,
85
- resolveRuntimeAgentModel,
86
- }),
87
- };
88
- }
89
-
90
- const INIT_CONTEXT = createCliContext(CWD);
91
-
92
- const cmdInit = createCmdInit(INIT_CONTEXT);
93
- const cmdUpdate = createCmdUpdate(INIT_CONTEXT);
94
- const cmdHealth = createCmdHealth(INIT_CONTEXT);
95
-
96
- const COMMANDS = {
97
- init: cmdInit,
98
- update: cmdUpdate,
99
- models: cmdModels,
100
- health: cmdHealth,
101
- 'file-op': cmdFileOp,
102
- 'lifecycle-preflight': cmdLifecyclePreflight,
103
- 'find-phase': cmdFindPhase,
104
- 'phase-status': cmdPhaseStatus,
105
- verify: cmdVerify,
106
- scaffold: cmdScaffold,
107
- help: cmdHelp,
108
- };
109
-
110
- async function runCli(cliCommand = command, ...cliArgs) {
111
- const normalizedArgs = cliArgs.length === 0
112
- ? args
113
- : cliArgs.length === 1 && Array.isArray(cliArgs[0])
114
- ? cliArgs[0]
115
- : cliArgs;
116
-
117
- process.exitCode = 0;
118
-
119
- if (!cliCommand || !COMMANDS[cliCommand]) {
120
- cmdHelp();
121
- if (cliCommand) process.exitCode = 1;
122
- return;
123
- }
124
-
125
- await COMMANDS[cliCommand](...normalizedArgs);
126
- }
127
-
128
- if (IS_MAIN) {
129
- await runCli();
130
- }
131
-
132
- export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
72
+ adapters: createAdapterRegistry({
73
+ cwd,
74
+ workflows: WORKFLOWS,
75
+ renderAgentsBoundedBlock,
76
+ renderAgentsFileContent,
77
+ renderOpenCodeCommandContent,
78
+ renderSkillContent,
79
+ upsertBoundedBlock,
80
+ getDelegateContent,
81
+ loadProjectModelConfig,
82
+ getRuntimeModelOverride,
83
+ resolveRuntimeAgentModel,
84
+ }),
85
+ };
86
+ }
87
+
88
+ const INIT_CONTEXT = createCliContext(process.cwd());
89
+
90
+ const cmdInit = createCmdInit(INIT_CONTEXT);
91
+ const cmdHealth = createCmdHealth(INIT_CONTEXT);
92
+
93
+ const cmdUpdate = (...updateArgs) => {
94
+ const { args: normalizedArgs, workspaceRoot, invalid, error } = resolveWorkspaceContext(updateArgs, { cwd: INIT_CONTEXT.cwd });
95
+ if (invalid) {
96
+ console.error(error);
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ return createCmdUpdate(createCliContext(workspaceRoot))(...normalizedArgs);
101
+ };
102
+
103
+ const COMMANDS = {
104
+ init: cmdInit,
105
+ update: cmdUpdate,
106
+ models: cmdModels,
107
+ health: cmdHealth,
108
+ 'file-op': cmdFileOp,
109
+ 'lifecycle-preflight': cmdLifecyclePreflight,
110
+ 'find-phase': cmdFindPhase,
111
+ 'phase-status': cmdPhaseStatus,
112
+ verify: cmdVerify,
113
+ scaffold: cmdScaffold,
114
+ help: cmdHelp,
115
+ };
116
+
117
+ async function runCli(cliCommand = command, ...cliArgs) {
118
+ const normalizedArgs = cliArgs.length === 0
119
+ ? args
120
+ : cliArgs.length === 1 && Array.isArray(cliArgs[0])
121
+ ? cliArgs[0]
122
+ : cliArgs;
123
+
124
+ process.exitCode = 0;
125
+
126
+ if (!cliCommand || !COMMANDS[cliCommand]) {
127
+ cmdHelp();
128
+ if (cliCommand) process.exitCode = 1;
129
+ return;
130
+ }
131
+
132
+ await COMMANDS[cliCommand](...normalizedArgs);
133
+ }
134
+
135
+ if (IS_MAIN) {
136
+ await runCli();
137
+ }
138
+
139
+ export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
@@ -1,28 +1,28 @@
1
- // cli-utils.mjs — Pure CLI utility functions (no external deps)
2
-
3
- export function parseFlagValue(flagArgs, flagName) {
4
- const idx = flagArgs.indexOf(flagName);
5
- if (idx === -1) return { present: false, value: null, invalid: false };
6
-
7
- const value = flagArgs[idx + 1];
8
- if (!value || value.startsWith('--')) {
9
- return { present: true, value: null, invalid: true };
10
- }
11
-
12
- return { present: true, value, invalid: false };
13
- }
14
-
15
- export function parseToolsFlag(flagArgs) {
16
- const { value } = parseFlagValue(flagArgs, '--tools');
17
- if (!value) return [];
18
- if (value === 'all') return ['claude', 'opencode', 'codex', 'agents', 'cursor', 'copilot', 'gemini'];
19
- return value.split(',').map((v) => v.trim()).filter(Boolean);
20
- }
21
-
22
- export function parseAutoFlag(flagArgs) {
23
- return flagArgs.includes('--auto');
24
- }
25
-
26
- export function output(data) {
27
- console.log(JSON.stringify(data, null, 2));
28
- }
1
+ // cli-utils.mjs — Pure CLI utility functions (no external deps)
2
+
3
+ export function parseFlagValue(flagArgs, flagName) {
4
+ const idx = flagArgs.indexOf(flagName);
5
+ if (idx === -1) return { present: false, value: null, invalid: false };
6
+
7
+ const value = flagArgs[idx + 1];
8
+ if (!value || value.startsWith('--')) {
9
+ return { present: true, value: null, invalid: true };
10
+ }
11
+
12
+ return { present: true, value, invalid: false };
13
+ }
14
+
15
+ export function parseToolsFlag(flagArgs) {
16
+ const { value } = parseFlagValue(flagArgs, '--tools');
17
+ if (!value) return [];
18
+ if (value === 'all') return ['claude', 'opencode', 'codex', 'agents', 'cursor', 'copilot', 'gemini'];
19
+ return value.split(',').map((v) => v.trim()).filter(Boolean);
20
+ }
21
+
22
+ export function parseAutoFlag(flagArgs) {
23
+ return flagArgs.includes('--auto');
24
+ }
25
+
26
+ export function output(data) {
27
+ console.log(JSON.stringify(data, null, 2));
28
+ }
@@ -1,112 +1,112 @@
1
- const EVIDENCE_KINDS = Object.freeze(['code', 'test', 'runtime', 'delivery', 'human']);
2
- const DELIVERY_POSTURES = Object.freeze(['repo_only', 'delivery_sensitive']);
3
- const CLOSURE_SURFACES = Object.freeze(['verify', 'audit-milestone', 'complete-milestone']);
4
-
5
- const LEGACY_EVIDENCE_ALIASES = Object.freeze({
6
- code: 'code',
7
- test: 'test',
8
- runtime: 'runtime',
9
- delivery: 'delivery',
10
- human: 'human',
11
- 'code-evidence': 'code',
12
- 'repo-test': 'test',
13
- 'runtime-check': 'runtime',
14
- 'user-confirmation': 'human',
15
- });
16
-
17
- const EVIDENCE_MATRIX = Object.freeze({
18
- verify: Object.freeze({
19
- repo_only: Object.freeze({
20
- requiredKinds: Object.freeze(['code']),
21
- recommendedKinds: Object.freeze(['test']),
22
- blockedSoloKinds: Object.freeze(['human', 'delivery']),
23
- }),
24
- delivery_sensitive: Object.freeze({
25
- requiredKinds: Object.freeze(['code', 'runtime']),
26
- recommendedKinds: Object.freeze(['test', 'delivery', 'human']),
27
- blockedSoloKinds: Object.freeze(['code', 'human']),
28
- }),
29
- }),
30
- 'audit-milestone': Object.freeze({
31
- repo_only: Object.freeze({
32
- requiredKinds: Object.freeze(['code', 'test']),
33
- recommendedKinds: Object.freeze(['runtime', 'human']),
34
- blockedSoloKinds: Object.freeze(['human', 'delivery']),
35
- }),
36
- delivery_sensitive: Object.freeze({
37
- requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
38
- recommendedKinds: Object.freeze(['human']),
39
- blockedSoloKinds: Object.freeze(['code', 'human']),
40
- }),
41
- }),
42
- 'complete-milestone': Object.freeze({
43
- repo_only: Object.freeze({
44
- requiredKinds: Object.freeze(['code', 'test']),
45
- recommendedKinds: Object.freeze(['runtime']),
46
- blockedSoloKinds: Object.freeze(['human', 'delivery']),
47
- }),
48
- delivery_sensitive: Object.freeze({
49
- requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
50
- recommendedKinds: Object.freeze(['human']),
51
- blockedSoloKinds: Object.freeze(['code', 'human']),
52
- }),
53
- }),
54
- });
55
-
56
- export { CLOSURE_SURFACES, DELIVERY_POSTURES, EVIDENCE_KINDS };
57
-
58
- export function normalizeEvidenceKind(kind) {
59
- if (!kind) {
60
- return null;
61
- }
62
-
63
- return LEGACY_EVIDENCE_ALIASES[kind] ?? null;
64
- }
65
-
66
- export function normalizeEvidenceKinds(kinds = []) {
67
- const normalized = [];
68
- for (const kind of kinds) {
69
- const resolved = normalizeEvidenceKind(kind);
70
- if (resolved && !normalized.includes(resolved)) {
71
- normalized.push(resolved);
72
- }
73
- }
74
- return normalized;
75
- }
76
-
77
- export function isClosureSurface(surface) {
78
- return CLOSURE_SURFACES.includes(surface);
79
- }
80
-
81
- export function getEvidenceContract(surface, deliveryPosture) {
82
- const matrix = EVIDENCE_MATRIX[surface];
83
- if (!matrix) {
84
- throw new Error(`Unsupported closure evidence surface: ${surface}`);
85
- }
86
-
87
- const posture = matrix[deliveryPosture];
88
- if (!posture) {
89
- throw new Error(`Unsupported delivery posture for ${surface}: ${deliveryPosture}`);
90
- }
91
-
92
- return {
93
- surface,
94
- deliveryPosture,
95
- supportedKinds: [...EVIDENCE_KINDS],
96
- requiredKinds: [...posture.requiredKinds],
97
- recommendedKinds: [...posture.recommendedKinds],
98
- blockedSoloKinds: [...posture.blockedSoloKinds],
99
- };
100
- }
101
-
102
- export function describeEvidenceSurface(surface) {
103
- if (!isClosureSurface(surface)) {
104
- return null;
105
- }
106
-
107
- return {
108
- surface,
109
- supportedKinds: [...EVIDENCE_KINDS],
110
- deliveryPostures: DELIVERY_POSTURES.map((deliveryPosture) => getEvidenceContract(surface, deliveryPosture)),
111
- };
112
- }
1
+ const EVIDENCE_KINDS = Object.freeze(['code', 'test', 'runtime', 'delivery', 'human']);
2
+ const DELIVERY_POSTURES = Object.freeze(['repo_only', 'delivery_sensitive']);
3
+ const CLOSURE_SURFACES = Object.freeze(['verify', 'audit-milestone', 'complete-milestone']);
4
+
5
+ const LEGACY_EVIDENCE_ALIASES = Object.freeze({
6
+ code: 'code',
7
+ test: 'test',
8
+ runtime: 'runtime',
9
+ delivery: 'delivery',
10
+ human: 'human',
11
+ 'code-evidence': 'code',
12
+ 'repo-test': 'test',
13
+ 'runtime-check': 'runtime',
14
+ 'user-confirmation': 'human',
15
+ });
16
+
17
+ const EVIDENCE_MATRIX = Object.freeze({
18
+ verify: Object.freeze({
19
+ repo_only: Object.freeze({
20
+ requiredKinds: Object.freeze(['code']),
21
+ recommendedKinds: Object.freeze(['test']),
22
+ blockedSoloKinds: Object.freeze(['human', 'delivery']),
23
+ }),
24
+ delivery_sensitive: Object.freeze({
25
+ requiredKinds: Object.freeze(['code', 'runtime']),
26
+ recommendedKinds: Object.freeze(['test', 'delivery', 'human']),
27
+ blockedSoloKinds: Object.freeze(['code', 'human']),
28
+ }),
29
+ }),
30
+ 'audit-milestone': Object.freeze({
31
+ repo_only: Object.freeze({
32
+ requiredKinds: Object.freeze(['code', 'test']),
33
+ recommendedKinds: Object.freeze(['runtime', 'human']),
34
+ blockedSoloKinds: Object.freeze(['human', 'delivery']),
35
+ }),
36
+ delivery_sensitive: Object.freeze({
37
+ requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
38
+ recommendedKinds: Object.freeze(['human']),
39
+ blockedSoloKinds: Object.freeze(['code', 'human']),
40
+ }),
41
+ }),
42
+ 'complete-milestone': Object.freeze({
43
+ repo_only: Object.freeze({
44
+ requiredKinds: Object.freeze(['code', 'test']),
45
+ recommendedKinds: Object.freeze(['runtime']),
46
+ blockedSoloKinds: Object.freeze(['human', 'delivery']),
47
+ }),
48
+ delivery_sensitive: Object.freeze({
49
+ requiredKinds: Object.freeze(['code', 'test', 'runtime', 'delivery']),
50
+ recommendedKinds: Object.freeze(['human']),
51
+ blockedSoloKinds: Object.freeze(['code', 'human']),
52
+ }),
53
+ }),
54
+ });
55
+
56
+ export { CLOSURE_SURFACES, DELIVERY_POSTURES, EVIDENCE_KINDS };
57
+
58
+ export function normalizeEvidenceKind(kind) {
59
+ if (!kind) {
60
+ return null;
61
+ }
62
+
63
+ return LEGACY_EVIDENCE_ALIASES[kind] ?? null;
64
+ }
65
+
66
+ export function normalizeEvidenceKinds(kinds = []) {
67
+ const normalized = [];
68
+ for (const kind of kinds) {
69
+ const resolved = normalizeEvidenceKind(kind);
70
+ if (resolved && !normalized.includes(resolved)) {
71
+ normalized.push(resolved);
72
+ }
73
+ }
74
+ return normalized;
75
+ }
76
+
77
+ export function isClosureSurface(surface) {
78
+ return CLOSURE_SURFACES.includes(surface);
79
+ }
80
+
81
+ export function getEvidenceContract(surface, deliveryPosture) {
82
+ const matrix = EVIDENCE_MATRIX[surface];
83
+ if (!matrix) {
84
+ throw new Error(`Unsupported closure evidence surface: ${surface}`);
85
+ }
86
+
87
+ const posture = matrix[deliveryPosture];
88
+ if (!posture) {
89
+ throw new Error(`Unsupported delivery posture for ${surface}: ${deliveryPosture}`);
90
+ }
91
+
92
+ return {
93
+ surface,
94
+ deliveryPosture,
95
+ supportedKinds: [...EVIDENCE_KINDS],
96
+ requiredKinds: [...posture.requiredKinds],
97
+ recommendedKinds: [...posture.recommendedKinds],
98
+ blockedSoloKinds: [...posture.blockedSoloKinds],
99
+ };
100
+ }
101
+
102
+ export function describeEvidenceSurface(surface) {
103
+ if (!isClosureSurface(surface)) {
104
+ return null;
105
+ }
106
+
107
+ return {
108
+ surface,
109
+ supportedKinds: [...EVIDENCE_KINDS],
110
+ deliveryPostures: DELIVERY_POSTURES.map((deliveryPosture) => getEvidenceContract(surface, deliveryPosture)),
111
+ };
112
+ }