@rsaglobaltech/specgate 0.27.8 → 1.0.0-rc.1

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 (146) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/packages/core/src/application/ValidateChangeUseCase.js +19 -3
  3. package/dist/packages/core/src/application/ValidateChangeUseCase.js.map +1 -1
  4. package/dist/packages/core/src/domain/ApiContract.js +157 -0
  5. package/dist/packages/core/src/domain/ApiContract.js.map +1 -0
  6. package/dist/packages/core/src/domain/Approvals.js +127 -0
  7. package/dist/packages/core/src/domain/Approvals.js.map +1 -0
  8. package/dist/packages/core/src/domain/ChangeLayers.js +281 -0
  9. package/dist/packages/core/src/domain/ChangeLayers.js.map +1 -0
  10. package/dist/packages/core/src/domain/DraftChecklist.js +15 -2
  11. package/dist/packages/core/src/domain/DraftChecklist.js.map +1 -1
  12. package/dist/packages/core/src/domain/HarnessConfig.js.map +1 -1
  13. package/dist/packages/core/src/domain/HarnessGaps.js +182 -0
  14. package/dist/packages/core/src/domain/HarnessGaps.js.map +1 -0
  15. package/dist/packages/core/src/domain/HarnessReport.js +16 -1
  16. package/dist/packages/core/src/domain/HarnessReport.js.map +1 -1
  17. package/dist/packages/core/src/domain/HarnessRun.js.map +1 -1
  18. package/dist/packages/core/src/domain/Principles.js +119 -0
  19. package/dist/packages/core/src/domain/Principles.js.map +1 -0
  20. package/dist/packages/core/src/domain/RequirementGraph.js +12 -1
  21. package/dist/packages/core/src/domain/RequirementGraph.js.map +1 -1
  22. package/dist/packages/core/src/domain/Workspace.js +150 -0
  23. package/dist/packages/core/src/domain/Workspace.js.map +1 -0
  24. package/dist/packages/core/src/index.js +1 -0
  25. package/dist/packages/core/src/index.js.map +1 -1
  26. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js +12 -0
  27. package/dist/packages/core/src/infrastructure/HarnessConfigFile.js.map +1 -1
  28. package/dist/packages/mcp-spec-driven/src/tools.js +18 -0
  29. package/dist/packages/mcp-spec-driven/src/tools.js.map +1 -1
  30. package/dist/scripts/alm/cli.js +45 -4
  31. package/dist/scripts/alm/cli.js.map +1 -1
  32. package/dist/scripts/alm/clients.js +3 -1
  33. package/dist/scripts/alm/clients.js.map +1 -1
  34. package/dist/scripts/alm/phases.js +279 -0
  35. package/dist/scripts/alm/phases.js.map +1 -0
  36. package/dist/scripts/alm/port.js +33 -5
  37. package/dist/scripts/alm/port.js.map +1 -1
  38. package/dist/scripts/alm/providers/azure.js +72 -11
  39. package/dist/scripts/alm/providers/azure.js.map +1 -1
  40. package/dist/scripts/alm/providers/github.js +67 -7
  41. package/dist/scripts/alm/providers/github.js.map +1 -1
  42. package/dist/scripts/alm/providers/index.js +8 -2
  43. package/dist/scripts/alm/providers/index.js.map +1 -1
  44. package/dist/scripts/alm/providers/jira.js +86 -8
  45. package/dist/scripts/alm/providers/jira.js.map +1 -1
  46. package/dist/scripts/alm/providers/linear.js +167 -0
  47. package/dist/scripts/alm/providers/linear.js.map +1 -0
  48. package/dist/scripts/change/artifacts.js +15 -1
  49. package/dist/scripts/change/artifacts.js.map +1 -1
  50. package/dist/scripts/change/instructions.js +39 -5
  51. package/dist/scripts/change/instructions.js.map +1 -1
  52. package/dist/scripts/cli/commands/alm/PhaseCommand.js +153 -0
  53. package/dist/scripts/cli/commands/alm/PhaseCommand.js.map +1 -0
  54. package/dist/scripts/cli/commands/alm/PullCommand.js +33 -2
  55. package/dist/scripts/cli/commands/alm/PullCommand.js.map +1 -1
  56. package/dist/scripts/cli/commands/alm/pull-back.js +104 -0
  57. package/dist/scripts/cli/commands/alm/pull-back.js.map +1 -0
  58. package/dist/scripts/cli/commands/change/ChangeCommand.js +92 -14
  59. package/dist/scripts/cli/commands/change/ChangeCommand.js.map +1 -1
  60. package/dist/scripts/cli/commands/change/TicketCommand.js +20 -7
  61. package/dist/scripts/cli/commands/change/TicketCommand.js.map +1 -1
  62. package/dist/scripts/cli/commands/config/ConfigSetCommand.js +2 -1
  63. package/dist/scripts/cli/commands/config/ConfigSetCommand.js.map +1 -1
  64. package/dist/scripts/cli/commands/harness/RunCommand.js +85 -21
  65. package/dist/scripts/cli/commands/harness/RunCommand.js.map +1 -1
  66. package/dist/scripts/cli/commands/project/AdoptCommand.js +44 -4
  67. package/dist/scripts/cli/commands/project/AdoptCommand.js.map +1 -1
  68. package/dist/scripts/cli/commands/project/MigrateCommand.js +166 -0
  69. package/dist/scripts/cli/commands/project/MigrateCommand.js.map +1 -0
  70. package/dist/scripts/cli/commands/project/OnboardCommand.js +23 -5
  71. package/dist/scripts/cli/commands/project/OnboardCommand.js.map +1 -1
  72. package/dist/scripts/cli/commands/quality/CheckCommand.js +25 -0
  73. package/dist/scripts/cli/commands/quality/CheckCommand.js.map +1 -1
  74. package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js +15 -0
  75. package/dist/scripts/cli/commands/quality/ValidateSpecsCommand.js.map +1 -1
  76. package/dist/scripts/cli/commands/spec/ContractCommand.js +117 -0
  77. package/dist/scripts/cli/commands/spec/ContractCommand.js.map +1 -0
  78. package/dist/scripts/cli/commands/spec/DraftCommand.js +22 -8
  79. package/dist/scripts/cli/commands/spec/DraftCommand.js.map +1 -1
  80. package/dist/scripts/cli/commands/spec/DriftCommand.js +128 -0
  81. package/dist/scripts/cli/commands/spec/DriftCommand.js.map +1 -0
  82. package/dist/scripts/cli/commands/spec/StatusCommand.js +12 -0
  83. package/dist/scripts/cli/commands/spec/StatusCommand.js.map +1 -1
  84. package/dist/scripts/cli/commands/spec/StudioCommand.js +43 -1
  85. package/dist/scripts/cli/commands/spec/StudioCommand.js.map +1 -1
  86. package/dist/scripts/cli/commands/workspace/WorkspaceCommand.js +485 -0
  87. package/dist/scripts/cli/commands/workspace/WorkspaceCommand.js.map +1 -0
  88. package/dist/scripts/contract.js +10 -0
  89. package/dist/scripts/contract.js.map +1 -0
  90. package/dist/scripts/docs/nav.js +16 -1
  91. package/dist/scripts/docs/nav.js.map +1 -1
  92. package/dist/scripts/draft/drafting-guide.js +6 -0
  93. package/dist/scripts/draft/drafting-guide.js.map +1 -1
  94. package/dist/scripts/draft/ticket-guide.js +5 -0
  95. package/dist/scripts/draft/ticket-guide.js.map +1 -1
  96. package/dist/scripts/drift.js +10 -0
  97. package/dist/scripts/drift.js.map +1 -0
  98. package/dist/scripts/harness/gap-evidence.js +149 -0
  99. package/dist/scripts/harness/gap-evidence.js.map +1 -0
  100. package/dist/scripts/harness/prompt.js +5 -1
  101. package/dist/scripts/harness/prompt.js.map +1 -1
  102. package/dist/scripts/harness/report.js +104 -5
  103. package/dist/scripts/harness/report.js.map +1 -1
  104. package/dist/scripts/lib/agent-permission.js +19 -0
  105. package/dist/scripts/lib/agent-permission.js.map +1 -1
  106. package/dist/scripts/lib/approvals.js +243 -0
  107. package/dist/scripts/lib/approvals.js.map +1 -0
  108. package/dist/scripts/lib/change-review.js +19 -11
  109. package/dist/scripts/lib/change-review.js.map +1 -1
  110. package/dist/scripts/lib/contracts.js +211 -0
  111. package/dist/scripts/lib/contracts.js.map +1 -0
  112. package/dist/scripts/lib/drift.js +80 -0
  113. package/dist/scripts/lib/drift.js.map +1 -0
  114. package/dist/scripts/lib/harness-environment.js +118 -0
  115. package/dist/scripts/lib/harness-environment.js.map +1 -0
  116. package/dist/scripts/lib/live-model.js +1 -0
  117. package/dist/scripts/lib/live-model.js.map +1 -1
  118. package/dist/scripts/lib/migrate.js +264 -0
  119. package/dist/scripts/lib/migrate.js.map +1 -0
  120. package/dist/scripts/lib/quality-run.js +3 -1
  121. package/dist/scripts/lib/quality-run.js.map +1 -1
  122. package/dist/scripts/lib/role-packages.js +230 -0
  123. package/dist/scripts/lib/role-packages.js.map +1 -0
  124. package/dist/scripts/lib/steering.js +180 -0
  125. package/dist/scripts/lib/steering.js.map +1 -0
  126. package/dist/scripts/lib/studio-app-page.js +28 -5
  127. package/dist/scripts/lib/studio-app-page.js.map +1 -1
  128. package/dist/scripts/lib/studio-app.js +42 -0
  129. package/dist/scripts/lib/studio-app.js.map +1 -1
  130. package/dist/scripts/lib/studio-route.js +54 -8
  131. package/dist/scripts/lib/studio-route.js.map +1 -1
  132. package/dist/scripts/lib/surface.js +55 -0
  133. package/dist/scripts/lib/surface.js.map +1 -1
  134. package/dist/scripts/lib/workspace-live-page.js +90 -0
  135. package/dist/scripts/lib/workspace-live-page.js.map +1 -0
  136. package/dist/scripts/lib/workspace-live.js +216 -0
  137. package/dist/scripts/lib/workspace-live.js.map +1 -0
  138. package/dist/scripts/lib/workspace.js +406 -0
  139. package/dist/scripts/lib/workspace.js.map +1 -0
  140. package/dist/scripts/migrate.js +10 -0
  141. package/dist/scripts/migrate.js.map +1 -0
  142. package/dist/scripts/schema/registry.js +12 -0
  143. package/dist/scripts/schema/registry.js.map +1 -1
  144. package/dist/scripts/workspace.js +10 -0
  145. package/dist/scripts/workspace.js.map +1 -0
  146. package/package.json +1 -1
@@ -62,6 +62,7 @@ exports.promptInFlight = promptInFlight;
62
62
  exports.setJsonMode = setJsonMode;
63
63
  exports.error = error;
64
64
  exports.parseArgs = parseArgs;
65
+ exports.baselineProblem = baselineProblem;
65
66
  exports.isRegeneratedMatrix = isRegeneratedMatrix;
66
67
  exports.publishBranch = publishBranch;
67
68
  exports.printReport = printReport;
@@ -82,11 +83,19 @@ const prompt_1 = require("../../../harness/prompt");
82
83
  const agent_permission_1 = require("../../../lib/agent-permission");
83
84
  const init_1 = require("../../../harness/init");
84
85
  const in_flight_1 = require("../../../lib/in-flight");
86
+ const approvals_1 = require("../../../lib/approvals");
87
+ const role_packages_1 = require("../../../lib/role-packages");
88
+ /**
89
+ * REQ-317: the role packages each requirement's prompts carried in this run,
90
+ * recorded on its result — the report counts them across runs.
91
+ */
92
+ const packagesUsed = new Map();
85
93
  const harness_events_1 = require("../../../lib/harness-events");
86
94
  const clarification_1 = require("../../../lib/clarification");
87
95
  const screen_requirements_1 = require("../../../lib/screen-requirements");
88
96
  const harness_guard_1 = require("../../../lib/harness-guard");
89
97
  const quality_run_1 = require("../../../lib/quality-run");
98
+ const harness_environment_1 = require("../../../lib/harness-environment");
90
99
  const HarnessEvents_1 = require("../../../../packages/core/src/domain/HarnessEvents");
91
100
  /**
92
101
  * `read` against the project as it will be after its open changes are
@@ -659,6 +668,17 @@ function runGate(worktreeDir, testCmd, timeoutMs, req = {}, settings = {}, repor
659
668
  ...(0, HarnessEvents_1.testCounts)(`${test.stdout || ""}${test.stderr || ""}`),
660
669
  ms: Date.now() - testStart,
661
670
  });
671
+ // REQ-279: a test command that could not reach Docker failed for the
672
+ // machine, not the code; the person starts Docker, the agent cannot.
673
+ const missing = test.status !== 0 ? (0, harness_environment_1.environmentFailure)(`${test.stdout || ""}${test.stderr || ""}`) : null;
674
+ if (missing) {
675
+ return {
676
+ ok: false,
677
+ stage: `test command: ${resolved}`,
678
+ output: `${test.stdout || ""}${test.stderr || ""}`,
679
+ couldNotRun: missing,
680
+ };
681
+ }
662
682
  if (test.status !== 0) {
663
683
  // Name the command. A gate that silently does the wrong thing — running
664
684
  // the whole suite because a filter did not apply, say — produces a
@@ -890,7 +910,10 @@ function agentChecks(worktreeDir, req, settings, timeoutMs, testCmd) {
890
910
  said = runAgentOnce(worktreeDir, command, promptFor(`Review only; change no file. Compare the change below with ${req.requirement}, its ` +
891
911
  "statement and every scenario. Answer with a first line `VERDICT: PASS` when the " +
892
912
  "change does what the requirement says and nothing it forbids, or `VERDICT: FAIL` " +
893
- "followed by each reason as `- path:line — what is wrong`.\n\n```diff\n" +
913
+ "followed by each reason as `- path:line — what is wrong`." +
914
+ // REQ-318: one advice line per role package; it never decides the verdict.
915
+ (0, role_packages_1.reviewAdvice)(judged(worktreeDir, (d) => (0, role_packages_1.packagesFor)(d, String(req.requirement || "")))) +
916
+ "\n\n```diff\n" +
894
917
  diff +
895
918
  "\n```"), timeoutMs, "review");
896
919
  }
@@ -1258,7 +1281,7 @@ function attemptRequirement(req, ctx) {
1258
1281
  let agentMs = 0;
1259
1282
  /** Which roles ran this attempt, in order — the run record's answer to "who did this". */
1260
1283
  const profilesUsed = [];
1261
- const record = (stage) => {
1284
+ const record = (stage, gateStage) => {
1262
1285
  event({
1263
1286
  type: "attempt",
1264
1287
  state: "end",
@@ -1271,6 +1294,8 @@ function attemptRequirement(req, ctx) {
1271
1294
  agentMs,
1272
1295
  totalMs: Date.now() - attemptStart,
1273
1296
  profiles: [...profilesUsed],
1297
+ // REQ-301: which stage rejected it is what says what to strengthen.
1298
+ ...(gateStage ? { gateStage } : {}),
1274
1299
  });
1275
1300
  ledgerAttempts(attemptLog);
1276
1301
  };
@@ -1288,21 +1313,31 @@ function attemptRequirement(req, ctx) {
1288
1313
  // implementing step that follows must see what it said. Building once
1289
1314
  // up front meant findings only ever reached the *next* attempt, which
1290
1315
  // is not what a reviewer is for.
1291
- const prompt = judged(worktreeDir, (dir) => (0, prompt_1.buildPrompt)(req, dir, {
1292
- promptPrefix: settings.promptPrefix,
1293
- hint,
1294
- previousFailure: previousFailure || undefined,
1295
- reviewFindings: step.advisory ? undefined : reviewFindings || undefined,
1296
- attempt,
1297
- maxAttempts: settings.maxAttempts,
1298
- // Read from the worktree, which carries the matrix at the base
1299
- // commit — the precedent must be work already accepted, not a
1300
- // sibling requirement this same run happens to be writing.
1301
- withPrecedents: settings.promptPrecedents === true,
1302
- e2eDir: settings.e2eDir && (0, screen_requirements_1.onScreen)(worktreeDir, req.requirement)
1303
- ? settings.e2eDir
1304
- : undefined,
1305
- }));
1316
+ let stepPackages = [];
1317
+ const prompt = judged(worktreeDir, (dir) => {
1318
+ stepPackages = (0, role_packages_1.packagesFor)(dir, req.requirement).map((p) => p.id);
1319
+ return (0, prompt_1.buildPrompt)(req, dir, {
1320
+ promptPrefix: settings.promptPrefix,
1321
+ hint,
1322
+ previousFailure: previousFailure || undefined,
1323
+ reviewFindings: step.advisory ? undefined : reviewFindings || undefined,
1324
+ attempt,
1325
+ maxAttempts: settings.maxAttempts,
1326
+ // Read from the worktree, which carries the matrix at the base
1327
+ // commit — the precedent must be work already accepted, not a
1328
+ // sibling requirement this same run happens to be writing.
1329
+ withPrecedents: settings.promptPrecedents === true,
1330
+ e2eDir: settings.e2eDir && (0, screen_requirements_1.onScreen)(worktreeDir, req.requirement)
1331
+ ? settings.e2eDir
1332
+ : undefined,
1333
+ });
1334
+ });
1335
+ if (stepPackages.length > 0) {
1336
+ const seen = packagesUsed.get(req.requirement) || new Set();
1337
+ for (const id of stepPackages)
1338
+ seen.add(id);
1339
+ packagesUsed.set(req.requirement, seen);
1340
+ }
1306
1341
  const promptFile = path.join(os.tmpdir(), `specgate-harness-prompt-${req.requirement}-${crypto.randomBytes(4).toString("hex")}.md`);
1307
1342
  fs.writeFileSync(promptFile, prompt, "utf8");
1308
1343
  archivePrompt(worktreeDir, req.requirement, attempt, step, prompt);
@@ -1313,6 +1348,8 @@ function attemptRequirement(req, ctx) {
1313
1348
  role: step.profile || (step.advisory ? "reviewer" : "agent"),
1314
1349
  chars: prompt.length,
1315
1350
  lines: prompt.split("\n").length,
1351
+ // REQ-317: which role packages it carried.
1352
+ ...(stepPackages.length > 0 ? { packages: stepPackages } : {}),
1316
1353
  });
1317
1354
  // D1: a profile chosen by matching this requirement, when one matches.
1318
1355
  // The role ladder still wins — `attempt_profiles` names a profile for
@@ -1461,8 +1498,10 @@ function attemptRequirement(req, ctx) {
1461
1498
  warn(`${req.requirement}: ${gate.couldNotRun}`);
1462
1499
  for (const line of gate.output.trim().split("\n").slice(-5))
1463
1500
  warn(` ${line}`);
1464
- warn(` not retrying: fix the check (harness.config.yaml) and run it again`);
1465
- record("check");
1501
+ warn(gate.stage.startsWith("quality check")
1502
+ ? ` not retrying: fix the check (harness.config.yaml) and run it again`
1503
+ : ` not retrying: the agent cannot fix the machine`);
1504
+ record("check", gate.stage);
1466
1505
  stopRetrying = true;
1467
1506
  break;
1468
1507
  }
@@ -1486,11 +1525,11 @@ function attemptRequirement(req, ctx) {
1486
1525
  previousFailure;
1487
1526
  warn(`${req.requirement}: the failure is in ${specFiles.join(", ")}, which the agent may not edit`);
1488
1527
  warn(` not retrying; fix the specification and run it again`);
1489
- record("spec");
1528
+ record("spec", gate.stage);
1490
1529
  stopRetrying = true;
1491
1530
  break;
1492
1531
  }
1493
- record("gate");
1532
+ record("gate", gate.stage);
1494
1533
  continue;
1495
1534
  }
1496
1535
  // Green — but does the diff contain what the row promised? (A2)
@@ -2053,6 +2092,9 @@ function processRequirement(req, ctx) {
2053
2092
  ledgerWrite();
2054
2093
  }
2055
2094
  const result = processOneRequirement(req, ctx);
2095
+ const used = packagesUsed.get(req.requirement);
2096
+ if (used && used.size > 0)
2097
+ result.packages = [...used];
2056
2098
  if (ledger) {
2057
2099
  ledger.record.results.push(result);
2058
2100
  delete ledger.record.running;
@@ -2074,6 +2116,22 @@ function processOneRequirement(req, ctx) {
2074
2116
  });
2075
2117
  if (matchedProfile)
2076
2118
  info(`${req.requirement}: profile '${matchedProfile}' matched`);
2119
+ // REQ-315: a requirement of an open change waits for its approvals — the 1.0
2120
+ // default for a layered change — before any worktree or agent.
2121
+ const owning = (0, in_flight_1.inFlightRequirements)(projectDir).find((r) => r.id === req.requirement);
2122
+ const unapproved = owning ? (0, approvals_1.missingApprovals)(projectDir, owning.change) : null;
2123
+ if (unapproved) {
2124
+ error(`${req.requirement}: ${unapproved.message} [harness_not_approved]`);
2125
+ warn(` fix: ${unapproved.fix}`);
2126
+ return {
2127
+ requirement: req.requirement,
2128
+ category: req.category,
2129
+ result: "skipped",
2130
+ attempts: 0,
2131
+ branch,
2132
+ error: `harness_not_approved: ${unapproved.message} Fix: ${unapproved.fix}`,
2133
+ };
2134
+ }
2077
2135
  const readiness = readinessOf(projectDir, req);
2078
2136
  const unrunnable = readiness.blockers.find((b) => b.code === "requirement_scenario_unrunnable");
2079
2137
  const hardStop = unrunnable || (ctx.skipNotReady && !readiness.ready);
@@ -2953,6 +3011,12 @@ class RunCommand extends command_1.BaseCommand {
2953
3011
  const identity = gitIdentityProblem(projectDir);
2954
3012
  if (identity)
2955
3013
  throw new Error(identity);
3014
+ // REQ-279: a stopped Docker fails every attempt in the tests or the
3015
+ // checks, and the agent cannot start it (truck-flote S61: three attempts).
3016
+ const needsDocker = (0, harness_environment_1.dockerNeed)(projectDir, settings.quality || null);
3017
+ const noDocker = needsDocker ? (0, quality_run_1.dockerWhyNot)() : null;
3018
+ if (noDocker)
3019
+ throw new Error(`${noDocker} This project needs it: ${needsDocker}.`);
2956
3020
  if (args.chain) {
2957
3021
  if (args.baseBranch) {
2958
3022
  throw new Error("--chain merges into the branch you are on: check that branch out instead of --base-branch.");