@veewo/gitnexus 1.5.7 → 1.5.9

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 (77) hide show
  1. package/dist/cli/ai-context.js +1 -7
  2. package/dist/cli/analyze-options.d.ts +4 -0
  3. package/dist/cli/analyze-options.js +14 -1
  4. package/dist/cli/analyze-options.test.js +23 -0
  5. package/dist/cli/analyze-runtime-summary.js +0 -1
  6. package/dist/cli/analyze-runtime-summary.test.js +0 -2
  7. package/dist/cli/analyze-summary.d.ts +0 -2
  8. package/dist/cli/analyze-summary.js +0 -24
  9. package/dist/cli/analyze-summary.test.js +1 -65
  10. package/dist/cli/analyze.d.ts +1 -0
  11. package/dist/cli/analyze.js +26 -18
  12. package/dist/cli/clean.js +23 -2
  13. package/dist/cli/index.js +3 -3
  14. package/dist/cli/repo-manager-alias.test.js +2 -0
  15. package/dist/core/ingestion/pipeline.js +0 -43
  16. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -1
  17. package/dist/core/ingestion/tree-sitter-queries.js +3 -3
  18. package/dist/mcp/local/agent-safe-response.js +1 -1
  19. package/dist/mcp/local/local-backend.d.ts +0 -23
  20. package/dist/mcp/local/local-backend.js +69 -248
  21. package/dist/mcp/local/runtime-chain-verify.test.js +0 -49
  22. package/dist/mcp/local/runtime-claim-rule-registry.d.ts +0 -11
  23. package/dist/mcp/local/runtime-claim-rule-registry.js +0 -159
  24. package/dist/mcp/local/runtime-claim-rule-registry.test.js +67 -214
  25. package/dist/mcp/tools.js +0 -70
  26. package/dist/storage/repo-manager.d.ts +1 -0
  27. package/dist/types/pipeline.d.ts +0 -3
  28. package/package.json +4 -4
  29. package/skills/gitnexus-cli.md +5 -2
  30. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.d.ts +0 -60
  31. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.js +0 -395
  32. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.d.ts +0 -1
  33. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.js +0 -41
  34. package/dist/cli/rule-lab.d.ts +0 -38
  35. package/dist/cli/rule-lab.js +0 -148
  36. package/dist/cli/rule-lab.test.d.ts +0 -1
  37. package/dist/cli/rule-lab.test.js +0 -31
  38. package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +0 -26
  39. package/dist/core/ingestion/unity-runtime-binding-rules.js +0 -408
  40. package/dist/rule-lab/analyze.d.ts +0 -13
  41. package/dist/rule-lab/analyze.js +0 -125
  42. package/dist/rule-lab/analyze.test.d.ts +0 -1
  43. package/dist/rule-lab/analyze.test.js +0 -246
  44. package/dist/rule-lab/compile.d.ts +0 -5
  45. package/dist/rule-lab/compile.js +0 -51
  46. package/dist/rule-lab/compiled-bundles.d.ts +0 -30
  47. package/dist/rule-lab/compiled-bundles.js +0 -36
  48. package/dist/rule-lab/curate.d.ts +0 -33
  49. package/dist/rule-lab/curate.js +0 -155
  50. package/dist/rule-lab/curate.test.d.ts +0 -1
  51. package/dist/rule-lab/curate.test.js +0 -137
  52. package/dist/rule-lab/curation-input-builder.d.ts +0 -45
  53. package/dist/rule-lab/curation-input-builder.js +0 -133
  54. package/dist/rule-lab/discover.d.ts +0 -13
  55. package/dist/rule-lab/discover.js +0 -74
  56. package/dist/rule-lab/discover.test.d.ts +0 -1
  57. package/dist/rule-lab/discover.test.js +0 -42
  58. package/dist/rule-lab/paths.d.ts +0 -21
  59. package/dist/rule-lab/paths.js +0 -37
  60. package/dist/rule-lab/paths.test.d.ts +0 -1
  61. package/dist/rule-lab/paths.test.js +0 -46
  62. package/dist/rule-lab/promote.d.ts +0 -26
  63. package/dist/rule-lab/promote.js +0 -387
  64. package/dist/rule-lab/promote.test.d.ts +0 -1
  65. package/dist/rule-lab/promote.test.js +0 -314
  66. package/dist/rule-lab/regress.d.ts +0 -60
  67. package/dist/rule-lab/regress.js +0 -122
  68. package/dist/rule-lab/regress.test.d.ts +0 -1
  69. package/dist/rule-lab/regress.test.js +0 -68
  70. package/dist/rule-lab/review-pack.d.ts +0 -34
  71. package/dist/rule-lab/review-pack.js +0 -165
  72. package/dist/rule-lab/review-pack.test.d.ts +0 -1
  73. package/dist/rule-lab/review-pack.test.js +0 -116
  74. package/dist/rule-lab/types.d.ts +0 -135
  75. package/dist/rule-lab/types.js +0 -1
  76. package/skills/_shared/unity-rule-authoring-contract.md +0 -64
  77. package/skills/gitnexus-unity-rule-gen.md +0 -107
@@ -1,60 +0,0 @@
1
- export interface Phase5StageCoverageRow {
2
- stage: 'analyze' | 'review-pack' | 'curate' | 'promote' | 'regress';
3
- command: string;
4
- status: 'passed' | 'failed';
5
- retry_hint?: string;
6
- error?: string;
7
- }
8
- export interface Phase5FailureClassification {
9
- code: string;
10
- retry_hint: string;
11
- repro_command: string;
12
- }
13
- export interface Phase5RuleLabAcceptanceReport {
14
- generated_at: string;
15
- repo_alias: string;
16
- repo_path: string;
17
- run_id: string;
18
- stage_coverage: Phase5StageCoverageRow[];
19
- metrics: {
20
- precision: number;
21
- coverage: number;
22
- probe_pass_rate: number;
23
- token_budget: number;
24
- };
25
- authenticity_checks: {
26
- static_no_hardcoded_reload: {
27
- pass: boolean;
28
- blocked_symbols: string[];
29
- };
30
- dsl_lint_pass: boolean;
31
- };
32
- failure_classifications: Phase5FailureClassification[];
33
- artifact_paths: {
34
- manifest: string;
35
- candidates: string;
36
- review_cards: string;
37
- curation_input: string;
38
- curated: string;
39
- catalog: string;
40
- promoted_files: string[];
41
- regress_report?: string;
42
- };
43
- }
44
- export interface BuildPhase5RuleLabAcceptanceInput {
45
- repoAlias: string;
46
- repoPath?: string;
47
- seed?: string;
48
- }
49
- export declare function buildPhase5RuleLabAcceptanceReport(input: BuildPhase5RuleLabAcceptanceInput): Promise<Phase5RuleLabAcceptanceReport>;
50
- export declare function runPhase5RuleLabGate(input: {
51
- reportPath: string;
52
- }): Promise<{
53
- pass: boolean;
54
- reason?: string;
55
- }>;
56
- export declare function writePhase5RuleLabAcceptanceArtifacts(input: {
57
- report: Phase5RuleLabAcceptanceReport;
58
- jsonPath: string;
59
- mdPath: string;
60
- }): Promise<void>;
@@ -1,395 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { analyzeRuleLabSlice } from '../../rule-lab/analyze.js';
4
- import { buildReviewPack } from '../../rule-lab/review-pack.js';
5
- import { curateRuleLabSlice } from '../../rule-lab/curate.js';
6
- import { promoteCuratedRules } from '../../rule-lab/promote.js';
7
- import { runRuleLabRegress } from '../../rule-lab/regress.js';
8
- function commandFor(stage, input) {
9
- switch (stage) {
10
- case 'analyze':
11
- return `gitnexus rule-lab analyze --run-id ${input.runId} --slice-id ${input.sliceId}`;
12
- case 'review-pack':
13
- return `gitnexus rule-lab review-pack --run-id ${input.runId} --slice-id ${input.sliceId} --max-tokens 6000`;
14
- case 'curate':
15
- return `gitnexus rule-lab curate --run-id ${input.runId} --slice-id ${input.sliceId} --input-path ${input.curationInputPath}`;
16
- case 'promote':
17
- return `gitnexus rule-lab promote --run-id ${input.runId} --slice-id ${input.sliceId}`;
18
- case 'regress':
19
- return `gitnexus rule-lab regress --precision 0.93 --coverage 0.85 --run-id ${input.runId}`;
20
- default:
21
- return 'gitnexus rule-lab <unknown>';
22
- }
23
- }
24
- async function mustExist(filePath) {
25
- await fs.access(filePath);
26
- }
27
- async function bootstrapReducedRuleLabRun(input) {
28
- const normalizedSeed = String(input.seed || Date.now())
29
- .replace(/[^a-zA-Z0-9]+/g, '-')
30
- .toLowerCase();
31
- const runId = `phase5-${normalizedSeed}-${Date.now()}`;
32
- const sliceId = 'slice-startup-exact-pair';
33
- const runRoot = path.join(input.repoPath, '.gitnexus', 'rules', 'lab', 'runs', runId);
34
- const sliceRoot = path.join(runRoot, 'slices', sliceId);
35
- const manifestPath = path.join(runRoot, 'manifest.json');
36
- const slicePath = path.join(sliceRoot, 'slice.json');
37
- await fs.mkdir(sliceRoot, { recursive: true });
38
- await fs.writeFile(manifestPath, `${JSON.stringify({
39
- run_id: runId,
40
- repo_path: input.repoPath,
41
- scope: 'full',
42
- generated_at: new Date().toISOString(),
43
- slices: [
44
- {
45
- id: sliceId,
46
- trigger_family: 'startup',
47
- resource_types: ['asset'],
48
- host_base_type: ['StartupNode'],
49
- required_hops: ['resource', 'code_runtime'],
50
- },
51
- ],
52
- stages: ['analyze'],
53
- next_actions: [`gitnexus rule-lab analyze --run-id ${runId} --slice-id ${sliceId}`],
54
- }, null, 2)}\n`, 'utf-8');
55
- await fs.writeFile(slicePath, `${JSON.stringify({
56
- id: sliceId,
57
- trigger_family: 'startup',
58
- resource_types: ['asset'],
59
- host_base_type: ['StartupNode'],
60
- required_hops: ['resource', 'code_runtime'],
61
- exact_pairs: [
62
- {
63
- id: 'pair-startup-1',
64
- binding_kind: 'method_triggers_method',
65
- draft_rule_id: 'demo.startup.v1',
66
- source_anchor: {
67
- file: 'Assets/Rules/startup.asset',
68
- line: 1,
69
- symbol: 'StartupNode.Initialize',
70
- },
71
- target_anchor: {
72
- file: 'Assets/Rules/startup.asset',
73
- line: 1,
74
- symbol: 'StartupNode.Bootstrap',
75
- },
76
- },
77
- ],
78
- }, null, 2)}\n`, 'utf-8');
79
- return {
80
- runId,
81
- sliceId,
82
- manifestPath,
83
- };
84
- }
85
- function buildFailureTaxonomy(runId) {
86
- return [
87
- {
88
- code: 'rule_not_matched',
89
- retry_hint: 'confirm trigger_family tokens and rerun analyze/promote',
90
- repro_command: `gitnexus rule-lab analyze --run-id ${runId} --slice-id <slice_id>`,
91
- },
92
- {
93
- code: 'rule_matched_but_evidence_missing',
94
- retry_hint: 'add stronger confirmed_chain anchors in curation input and promote again',
95
- repro_command: `gitnexus rule-lab curate --run-id ${runId} --slice-id <slice_id> --input-path <curation-input.json>`,
96
- },
97
- {
98
- code: 'precision_below_threshold',
99
- retry_hint: 'trim noisy rules or tighten curation semantics before regress',
100
- repro_command: `gitnexus rule-lab regress --precision 0.85 --coverage 0.92 --run-id ${runId}`,
101
- },
102
- {
103
- code: 'coverage_below_threshold',
104
- retry_hint: 'add additional approved rules/slices and rerun regress',
105
- repro_command: `gitnexus rule-lab regress --precision 0.95 --coverage 0.70 --run-id ${runId}`,
106
- },
107
- {
108
- code: 'probe_pass_rate_below_threshold',
109
- retry_hint: 're-run regress with refreshed probes and inspect replay commands',
110
- repro_command: `gitnexus rule-lab regress --precision 0.95 --coverage 0.90 --run-id ${runId}`,
111
- },
112
- {
113
- code: 'static_hardcode_detected',
114
- retry_hint: 'remove project-specific reload fallback constants/branches from runtime verifier',
115
- repro_command: 'rg -n "RESOURCE_ASSET_PATH|GRAPH_ASSET_PATH|RELOAD_GUID|shouldVerifyReloadChain|verifyReloadRuntimeChain" gitnexus/src/mcp/local/runtime-chain-verify.ts',
116
- },
117
- {
118
- code: 'dsl_lint_failed',
119
- retry_hint: 'fix promoted DSL placeholders and rerun promote/regress',
120
- repro_command: `gitnexus rule-lab promote --run-id ${runId} --slice-id <slice_id>`,
121
- },
122
- ];
123
- }
124
- function hasDslPlaceholders(text) {
125
- return /(^|\s)(unknown|todo|tbd)(\s|$)|<[^>]+>/i.test(text);
126
- }
127
- async function buildAuthenticityChecks(input) {
128
- const verifierPathCandidates = [
129
- path.join(input.repoPath, 'gitnexus', 'src', 'mcp', 'local', 'runtime-chain-verify.ts'),
130
- path.join(input.repoPath, 'src', 'mcp', 'local', 'runtime-chain-verify.ts'),
131
- ];
132
- let verifierPath = verifierPathCandidates[0];
133
- for (const candidate of verifierPathCandidates) {
134
- try {
135
- await fs.access(candidate);
136
- verifierPath = candidate;
137
- break;
138
- }
139
- catch {
140
- }
141
- }
142
- const verifierRaw = await fs.readFile(verifierPath, 'utf-8');
143
- const blockedSymbols = [
144
- 'RESOURCE_ASSET_PATH',
145
- 'GRAPH_ASSET_PATH',
146
- 'RELOAD_GUID',
147
- 'shouldVerifyReloadChain',
148
- 'verifyReloadRuntimeChain',
149
- ].filter((token) => verifierRaw.includes(token));
150
- let dslLintPass = true;
151
- for (const promotedPath of input.promotedFiles) {
152
- const raw = await fs.readFile(promotedPath, 'utf-8');
153
- if (hasDslPlaceholders(raw)) {
154
- dslLintPass = false;
155
- break;
156
- }
157
- }
158
- return {
159
- static_no_hardcoded_reload: {
160
- pass: blockedSymbols.length === 0,
161
- blocked_symbols: blockedSymbols,
162
- },
163
- dsl_lint_pass: dslLintPass,
164
- };
165
- }
166
- export async function buildPhase5RuleLabAcceptanceReport(input) {
167
- const repoPath = path.resolve(input.repoPath || process.cwd());
168
- const stageCoverage = [];
169
- const bootstrapped = await bootstrapReducedRuleLabRun({
170
- repoPath,
171
- seed: input.seed || 'phase5-acceptance',
172
- });
173
- const sliceId = bootstrapped.sliceId;
174
- const runId = bootstrapped.runId;
175
- const analyze = await analyzeRuleLabSlice({ repoPath, runId, sliceId });
176
- stageCoverage.push({
177
- stage: 'analyze',
178
- command: commandFor('analyze', { runId, sliceId }),
179
- status: 'passed',
180
- });
181
- const reviewPack = await buildReviewPack({ repoPath, runId, sliceId, maxTokens: 6000 });
182
- stageCoverage.push({
183
- stage: 'review-pack',
184
- command: commandFor('review-pack', { runId, sliceId }),
185
- status: 'passed',
186
- });
187
- const firstCandidate = analyze.candidates[0];
188
- const promotedRuleId = `demo.startup.${runId}.v1`;
189
- const curationInputPath = path.join(repoPath, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'curation-input.json');
190
- await fs.writeFile(curationInputPath, `${JSON.stringify({
191
- run_id: runId,
192
- slice_id: sliceId,
193
- curated: [
194
- {
195
- id: firstCandidate.id,
196
- rule_id: promotedRuleId,
197
- title: 'startup startup graph',
198
- match: {
199
- trigger_tokens: ['startup'],
200
- },
201
- topology: Array.isArray(firstCandidate.topology) && firstCandidate.topology.length > 0
202
- ? firstCandidate.topology
203
- : firstCandidate.evidence.hops.map((hop) => ({
204
- hop: hop.hop_type,
205
- from: { entity: 'resource' },
206
- to: { entity: 'script' },
207
- edge: { kind: 'binds_script' },
208
- })),
209
- closure: {
210
- required_hops: Array.isArray(firstCandidate.topology) && firstCandidate.topology.length > 0
211
- ? firstCandidate.topology.map((hop) => hop.hop)
212
- : ['code_runtime'],
213
- failure_map: {
214
- missing_evidence: 'rule_matched_but_evidence_missing',
215
- },
216
- },
217
- claims: {
218
- guarantees: ['startup trigger matching is confirmed'],
219
- non_guarantees: ['does not prove full runtime ordering'],
220
- next_action: 'gitnexus query "Startup Graph Trigger"',
221
- },
222
- confirmed_chain: {
223
- steps: firstCandidate.evidence.hops.map((hop) => ({ ...hop, hop_type: 'code_runtime' })),
224
- },
225
- guarantees: ['startup trigger matching is confirmed'],
226
- non_guarantees: ['does not prove full runtime ordering'],
227
- },
228
- ],
229
- }, null, 2)}\n`, 'utf-8');
230
- const curated = await curateRuleLabSlice({ repoPath, runId, sliceId, inputPath: curationInputPath });
231
- stageCoverage.push({
232
- stage: 'curate',
233
- command: commandFor('curate', { runId, sliceId, curationInputPath }),
234
- status: 'passed',
235
- });
236
- const promoted = await promoteCuratedRules({ repoPath, runId, sliceId, version: '1.0.0' });
237
- stageCoverage.push({
238
- stage: 'promote',
239
- command: commandFor('promote', { runId, sliceId }),
240
- status: 'passed',
241
- });
242
- const regress = await runRuleLabRegress({
243
- precision: 0.93,
244
- coverage: 0.85,
245
- probes: [
246
- {
247
- id: 'probe-startup-trigger',
248
- pass: true,
249
- replay_command: 'gitnexus query "Startup Graph Trigger" --runtime-chain-verify on-demand',
250
- },
251
- ],
252
- repoPath,
253
- runId,
254
- });
255
- stageCoverage.push({
256
- stage: 'regress',
257
- command: commandFor('regress', { runId, sliceId }),
258
- status: regress.pass ? 'passed' : 'failed',
259
- retry_hint: regress.pass ? undefined : regress.failures.join(','),
260
- });
261
- const artifactPaths = {
262
- manifest: bootstrapped.manifestPath,
263
- candidates: analyze.paths.candidatesPath,
264
- review_cards: reviewPack.paths.reviewCardsPath,
265
- curation_input: curationInputPath,
266
- curated: curated.paths.curatedPath,
267
- catalog: path.join(promoted.paths.rulesRoot, 'catalog.json'),
268
- promoted_files: promoted.promotedFiles,
269
- regress_report: regress.reportPath,
270
- };
271
- await mustExist(artifactPaths.manifest);
272
- await mustExist(artifactPaths.candidates);
273
- await mustExist(artifactPaths.review_cards);
274
- await mustExist(artifactPaths.curation_input);
275
- await mustExist(artifactPaths.curated);
276
- await mustExist(artifactPaths.catalog);
277
- await Promise.all(artifactPaths.promoted_files.map((filePath) => mustExist(filePath)));
278
- if (artifactPaths.regress_report) {
279
- await mustExist(artifactPaths.regress_report);
280
- }
281
- const authenticityChecks = await buildAuthenticityChecks({
282
- repoPath,
283
- promotedFiles: artifactPaths.promoted_files,
284
- });
285
- return {
286
- generated_at: new Date().toISOString(),
287
- repo_alias: input.repoAlias,
288
- repo_path: repoPath,
289
- run_id: runId,
290
- stage_coverage: stageCoverage,
291
- metrics: {
292
- precision: regress.metrics.precision,
293
- coverage: regress.metrics.coverage,
294
- probe_pass_rate: regress.metrics.probe_pass_rate,
295
- token_budget: reviewPack.meta.token_budget_estimate,
296
- },
297
- authenticity_checks: authenticityChecks,
298
- failure_classifications: buildFailureTaxonomy(runId),
299
- artifact_paths: artifactPaths,
300
- };
301
- }
302
- export async function runPhase5RuleLabGate(input) {
303
- const reportPath = path.resolve(input.reportPath);
304
- try {
305
- const raw = await fs.readFile(reportPath, 'utf-8');
306
- const report = JSON.parse(raw);
307
- if (!Array.isArray(report.stage_coverage) || report.stage_coverage.length !== 5) {
308
- return { pass: false, reason: 'stage_coverage_incomplete' };
309
- }
310
- if (typeof report.metrics?.precision !== 'number' || typeof report.metrics?.coverage !== 'number') {
311
- return { pass: false, reason: 'metrics_missing' };
312
- }
313
- if (!report.authenticity_checks?.static_no_hardcoded_reload?.pass) {
314
- return { pass: false, reason: 'static_hardcode_detected' };
315
- }
316
- if (!report.authenticity_checks?.dsl_lint_pass) {
317
- return { pass: false, reason: 'dsl_lint_failed' };
318
- }
319
- if (Number(report.metrics?.probe_pass_rate) < 0.85) {
320
- return { pass: false, reason: 'probe_pass_rate_below_threshold' };
321
- }
322
- return { pass: true };
323
- }
324
- catch {
325
- return { pass: false, reason: 'acceptance_report_missing' };
326
- }
327
- }
328
- export async function writePhase5RuleLabAcceptanceArtifacts(input) {
329
- const jsonPath = path.resolve(input.jsonPath);
330
- const mdPath = path.resolve(input.mdPath);
331
- await fs.mkdir(path.dirname(jsonPath), { recursive: true });
332
- await fs.writeFile(jsonPath, `${JSON.stringify(input.report, null, 2)}\n`, 'utf-8');
333
- const markdown = [
334
- '# Phase 5 Rule Lab Acceptance',
335
- '',
336
- `- generated_at: ${input.report.generated_at}`,
337
- `- repo_alias: ${input.report.repo_alias}`,
338
- `- run_id: ${input.report.run_id}`,
339
- '',
340
- '## Stage Coverage',
341
- ...input.report.stage_coverage.map((stage) => `- ${stage.stage}: ${stage.status} (${stage.command})`),
342
- '',
343
- '## Metrics',
344
- `- precision: ${input.report.metrics.precision}`,
345
- `- coverage: ${input.report.metrics.coverage}`,
346
- `- probe_pass_rate: ${input.report.metrics.probe_pass_rate}`,
347
- `- token_budget: ${input.report.metrics.token_budget}`,
348
- '',
349
- '## Authenticity Checks',
350
- `- static_no_hardcoded_reload.pass: ${input.report.authenticity_checks.static_no_hardcoded_reload.pass}`,
351
- `- static_no_hardcoded_reload.blocked_symbols: ${input.report.authenticity_checks.static_no_hardcoded_reload.blocked_symbols.join(', ') || 'none'}`,
352
- `- dsl_lint_pass: ${input.report.authenticity_checks.dsl_lint_pass}`,
353
- '',
354
- '## Failure Classifications',
355
- ...input.report.failure_classifications.map((failure) => `- ${failure.code}: ${failure.retry_hint} | repro: ${failure.repro_command}`),
356
- '',
357
- '## Artifact Paths',
358
- `- manifest: ${input.report.artifact_paths.manifest}`,
359
- `- candidates: ${input.report.artifact_paths.candidates}`,
360
- `- review_cards: ${input.report.artifact_paths.review_cards}`,
361
- `- curation_input: ${input.report.artifact_paths.curation_input}`,
362
- `- curated: ${input.report.artifact_paths.curated}`,
363
- `- catalog: ${input.report.artifact_paths.catalog}`,
364
- `- promoted_files: ${input.report.artifact_paths.promoted_files.join(', ')}`,
365
- `- regress_report: ${input.report.artifact_paths.regress_report || 'n/a'}`,
366
- '',
367
- ].join('\n');
368
- await fs.mkdir(path.dirname(mdPath), { recursive: true });
369
- await fs.writeFile(mdPath, markdown, 'utf-8');
370
- }
371
- async function main(argv) {
372
- const repoArgIndex = argv.indexOf('--repo-path');
373
- const repoPath = repoArgIndex >= 0 ? argv[repoArgIndex + 1] : process.cwd();
374
- const outJsonIndex = argv.indexOf('--out-json');
375
- const outMdIndex = argv.indexOf('--out-md');
376
- const outJson = outJsonIndex >= 0
377
- ? argv[outJsonIndex + 1]
378
- : path.resolve('docs/reports/2026-04-02-phase5-rule-lab-acceptance.json');
379
- const outMd = outMdIndex >= 0
380
- ? argv[outMdIndex + 1]
381
- : path.resolve('docs/reports/2026-04-02-phase5-rule-lab-acceptance.md');
382
- const report = await buildPhase5RuleLabAcceptanceReport({
383
- repoAlias: 'GitNexus',
384
- repoPath,
385
- seed: 'phase5-acceptance-main',
386
- });
387
- await writePhase5RuleLabAcceptanceArtifacts({ report, jsonPath: outJson, mdPath: outMd });
388
- process.stdout.write(`${JSON.stringify({ outJson, outMd, run_id: report.run_id }, null, 2)}\n`);
389
- }
390
- if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname)) {
391
- main(process.argv.slice(2)).catch((error) => {
392
- console.error(error instanceof Error ? error.message : String(error));
393
- process.exit(1);
394
- });
395
- }
@@ -1,41 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import fs from 'node:fs/promises';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { buildPhase5RuleLabAcceptanceReport, runPhase5RuleLabGate } from './phase5-rule-lab-acceptance-runner.js';
6
- const { test: rawTest } = process.env.VITEST
7
- ? await import('vitest')
8
- : await import('node:test');
9
- const test = rawTest;
10
- test('phase5 rule-lab acceptance runner emits complete stage coverage', async () => {
11
- const report = await buildPhase5RuleLabAcceptanceReport({ repoAlias: 'GitNexus' });
12
- assert.equal(report.stage_coverage.length, 5);
13
- assert.equal(typeof report.metrics.precision, 'number');
14
- });
15
- test('phase5 gate fails when required artifacts are missing', async () => {
16
- const gate = await runPhase5RuleLabGate({ reportPath: '/tmp/missing.json' });
17
- assert.equal(gate.pass, false);
18
- assert.equal(gate.reason, 'acceptance_report_missing');
19
- });
20
- test('phase5 gate fails when anti-hardcode scan or dsl lint fails', async () => {
21
- const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'phase5-gate-'));
22
- const reportPath = path.join(tmpDir, 'report.json');
23
- await fs.writeFile(reportPath, JSON.stringify({
24
- stage_coverage: [
25
- { stage: 'analyze', status: 'passed' },
26
- { stage: 'review-pack', status: 'passed' },
27
- { stage: 'curate', status: 'passed' },
28
- { stage: 'promote', status: 'passed' },
29
- { stage: 'regress', status: 'passed' },
30
- ],
31
- metrics: { precision: 0.93, coverage: 0.9, probe_pass_rate: 0.9 },
32
- authenticity_checks: {
33
- static_no_hardcoded_reload: { pass: false },
34
- dsl_lint_pass: false,
35
- },
36
- }), 'utf-8');
37
- const gate = await runPhase5RuleLabGate({ reportPath });
38
- assert.equal(gate.pass, false);
39
- assert.ok(['static_hardcode_detected', 'dsl_lint_failed'].includes(String(gate.reason)));
40
- await fs.rm(tmpDir, { recursive: true, force: true });
41
- });
@@ -1,38 +0,0 @@
1
- import type { Command } from 'commander';
2
- declare const RULE_LAB_COMMANDS: readonly ["analyze", "review-pack", "curate", "promote", "regress"];
3
- type RuleLabHandlerName = 'ruleLabAnalyzeCommand' | 'ruleLabReviewPackCommand' | 'ruleLabCurateCommand' | 'ruleLabPromoteCommand' | 'ruleLabRegressCommand';
4
- type LazyFactory = (handlerName: RuleLabHandlerName) => (...args: any[]) => void | Promise<void>;
5
- export declare function getRuleLabCommandNames(program: Command): string[];
6
- export declare function attachRuleLabCommands(program: Command, lazyFactory?: LazyFactory): void;
7
- export declare function ruleLabAnalyzeCommand(options: {
8
- repoPath?: string;
9
- runId: string;
10
- sliceId: string;
11
- }): Promise<void>;
12
- export declare function ruleLabReviewPackCommand(options: {
13
- repoPath?: string;
14
- runId: string;
15
- sliceId: string;
16
- maxTokens?: string | number;
17
- }): Promise<void>;
18
- export declare function ruleLabCurateCommand(options: {
19
- repoPath?: string;
20
- runId: string;
21
- sliceId: string;
22
- inputPath: string;
23
- }): Promise<void>;
24
- export declare function ruleLabPromoteCommand(options: {
25
- repoPath?: string;
26
- runId: string;
27
- sliceId: string;
28
- ruleVersion?: string;
29
- version?: string;
30
- }): Promise<void>;
31
- export declare function ruleLabRegressCommand(options: {
32
- precision: string | number;
33
- coverage: string | number;
34
- repoPath?: string;
35
- runId?: string;
36
- probesPath?: string;
37
- }): Promise<void>;
38
- export { RULE_LAB_COMMANDS };