cool-workflow 0.2.0 → 0.2.2

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 (141) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/README.md +7 -5
  4. package/apps/architecture-review/app.json +2 -2
  5. package/apps/architecture-review/workflow.js +12 -12
  6. package/apps/architecture-review-fast/app.json +1 -1
  7. package/apps/end-to-end-golden-path/app.json +1 -1
  8. package/apps/pr-review-fix-ci/app.json +1 -1
  9. package/apps/release-cut/app.json +1 -1
  10. package/apps/research-synthesis/app.json +1 -1
  11. package/dist/cli/dispatch.js +20 -88
  12. package/dist/cli/parseargv.js +6 -3
  13. package/dist/core/capability-data.js +270 -0
  14. package/dist/core/capability-table.js +15 -3519
  15. package/dist/core/format/help.js +30 -7
  16. package/dist/core/hash.js +1 -1
  17. package/dist/core/multi-agent/candidate-scoring.js +1 -1
  18. package/dist/core/multi-agent/collaboration.js +3 -2
  19. package/dist/core/multi-agent/coordinator.js +4 -3
  20. package/dist/core/multi-agent/eval-replay.js +1 -1
  21. package/dist/core/multi-agent/runtime.js +2 -2
  22. package/dist/core/multi-agent/trust-policy.js +1 -1
  23. package/dist/core/pipeline/commit-gate.js +2 -1
  24. package/dist/core/pipeline/contract.js +1 -1
  25. package/dist/core/pipeline/drive-decide.js +1 -1
  26. package/dist/core/state/contract-migration.js +1 -1
  27. package/dist/core/state/migrations.js +2 -2
  28. package/dist/core/state/node-snapshot.js +1 -1
  29. package/dist/core/state/state-explosion/digest.js +3 -2
  30. package/dist/core/state/state-explosion/graph.js +13 -12
  31. package/dist/core/state/state-explosion/helpers.js +5 -4
  32. package/dist/core/state/state-explosion/report.js +1 -1
  33. package/dist/core/state/state-explosion/size.js +1 -1
  34. package/dist/core/state/state-node.js +2 -2
  35. package/dist/core/state/types.js +1 -1
  36. package/dist/core/trust/ledger.js +3 -2
  37. package/dist/core/trust/telemetry-attestation.js +3 -3
  38. package/dist/core/trust/telemetry-ledger.js +2 -2
  39. package/dist/core/types/execution-backend.js +18 -0
  40. package/dist/core/types/observability.js +7 -0
  41. package/dist/core/util/collate.js +23 -0
  42. package/dist/core/version.js +1 -1
  43. package/dist/core/workflow-apps/app-schema.js +1 -1
  44. package/dist/mcp/dispatch.js +1 -1
  45. package/dist/mcp/server.js +1 -1
  46. package/dist/shell/agent-config.js +1 -1
  47. package/dist/shell/audit-cli.js +46 -2
  48. package/dist/shell/commit-summary.js +2 -1
  49. package/dist/shell/doctor.js +17 -4
  50. package/dist/shell/drive.js +47 -19
  51. package/dist/shell/evidence-reasoning.js +4 -3
  52. package/dist/shell/execution-backend/agent.js +42 -10
  53. package/dist/shell/execution-backend/ci.js +1 -1
  54. package/dist/shell/execution-backend/container.js +1 -1
  55. package/dist/shell/execution-backend/envelopes.js +1 -1
  56. package/dist/shell/execution-backend/local.js +1 -1
  57. package/dist/shell/execution-backend/probes.js +1 -1
  58. package/dist/shell/execution-backend/registry.js +3 -2
  59. package/dist/shell/execution-backend/remote.js +1 -1
  60. package/dist/shell/execution-backend/types.js +0 -9
  61. package/dist/shell/fs-atomic.js +15 -2
  62. package/dist/shell/ledger-io.js +1 -1
  63. package/dist/shell/metrics-cli.js +4 -2
  64. package/dist/shell/multi-agent-host.js +1 -1
  65. package/dist/shell/multi-agent-operator-ux.js +4 -3
  66. package/dist/shell/observability.js +12 -11
  67. package/dist/shell/onramp.js +17 -1
  68. package/dist/shell/operator-ux-text.js +2 -1
  69. package/dist/shell/operator-ux.js +7 -6
  70. package/dist/shell/pipeline-cli.js +82 -72
  71. package/dist/shell/reclamation-io.js +3 -2
  72. package/dist/shell/registry-cli.js +15 -0
  73. package/dist/shell/report.js +2 -1
  74. package/dist/shell/run-registry-io.js +1 -1
  75. package/dist/shell/run-store.js +17 -0
  76. package/dist/shell/sandbox-profile.js +1 -1
  77. package/dist/shell/scheduler-io.js +46 -37
  78. package/dist/shell/scheduling-io.js +32 -22
  79. package/dist/shell/state-explosion-cli.js +2 -1
  80. package/dist/shell/telemetry-ledger-io.js +1 -1
  81. package/dist/shell/term.js +1 -1
  82. package/dist/shell/topology-io.js +2 -1
  83. package/dist/shell/trust-audit.js +45 -5
  84. package/dist/shell/workbench-host.js +9 -1
  85. package/dist/shell/workbench.js +6 -11
  86. package/dist/shell/worker-cli.js +9 -1
  87. package/dist/shell/worker-isolation.js +34 -9
  88. package/dist/shell/workflow-app-loader.js +3 -2
  89. package/dist/wiring/capability-table/basics.js +66 -0
  90. package/dist/wiring/capability-table/exec-backend.js +162 -0
  91. package/dist/wiring/capability-table/index.js +42 -0
  92. package/dist/wiring/capability-table/multi-agent.js +623 -0
  93. package/dist/wiring/capability-table/parity.js +466 -0
  94. package/dist/wiring/capability-table/pipeline.js +280 -0
  95. package/dist/wiring/capability-table/registry-core.js +189 -0
  96. package/dist/wiring/capability-table/reporting.js +394 -0
  97. package/dist/wiring/capability-table/scheduling-registry.js +558 -0
  98. package/dist/wiring/capability-table/state.js +173 -0
  99. package/dist/wiring/capability-table/trust-ledger.js +134 -0
  100. package/dist/wiring/capability-table/workflow-apps.js +366 -0
  101. package/docs/agent-delegation-drive.7.md +4 -0
  102. package/docs/cli-mcp-parity.7.md +9 -2
  103. package/docs/contract-migration-tooling.7.md +4 -0
  104. package/docs/control-plane-scheduling.7.md +4 -0
  105. package/docs/durable-state-and-locking.7.md +24 -0
  106. package/docs/evidence-adoption-reasoning-chain.7.md +4 -0
  107. package/docs/execution-backends.7.md +4 -0
  108. package/docs/index.md +1 -0
  109. package/docs/multi-agent-cli-mcp-surface.7.md +4 -0
  110. package/docs/multi-agent-eval-replay-harness.7.md +4 -0
  111. package/docs/multi-agent-operator-ux.7.md +4 -0
  112. package/docs/node-snapshot-diff-replay.7.md +4 -0
  113. package/docs/observability-cost-accounting.7.md +6 -1
  114. package/docs/project-index.md +30 -5
  115. package/docs/real-execution-backends.7.md +4 -0
  116. package/docs/release-and-migration.7.md +4 -0
  117. package/docs/release-tooling.7.md +4 -0
  118. package/docs/remote-source-review.7.md +4 -4
  119. package/docs/report-verifiable-bundle.7.md +1 -1
  120. package/docs/run-registry-control-plane.7.md +4 -0
  121. package/docs/run-retention-reclamation.7.md +4 -0
  122. package/docs/security-trust-hardening.7.md +33 -1
  123. package/docs/state-explosion-management.7.md +4 -0
  124. package/docs/team-collaboration.7.md +4 -0
  125. package/docs/trust-audit-anchor.7.md +69 -0
  126. package/docs/web-desktop-workbench.7.md +15 -1
  127. package/manifest/plugin.manifest.json +1 -1
  128. package/package.json +3 -1
  129. package/scripts/agents/agent-adapter-core.js +22 -2
  130. package/scripts/agents/claude-p-agent.js +8 -3
  131. package/scripts/agents/gemini-agent.js +5 -1
  132. package/scripts/agents/opencode-agent.js +5 -1
  133. package/scripts/bump-version.js +24 -2
  134. package/scripts/canonical-apps.js +4 -4
  135. package/scripts/dogfood-release.js +1 -1
  136. package/scripts/golden-path.js +4 -4
  137. package/scripts/purity-baseline.json +68 -0
  138. package/scripts/purity-gate.js +239 -0
  139. package/scripts/release-check.js +8 -1
  140. package/scripts/version-sync-check.js +33 -12
  141. package/workflows/README.md +19 -0
@@ -5,7 +5,7 @@
5
5
  // src/orchestrator.ts:899-1007 in the old build (formatHelp,
6
6
  // formatCommandHelp) plus the color helpers `bold`/`dim` keyed off stdout.
7
7
  //
8
- // LOAD-BEARING LAYOUT (v2/PLAN.md byte-compat item 14 — do not "clean up"):
8
+ // LOAD-BEARING LAYOUT (docs/rebuild/PLAN.md byte-compat item 14 — do not "clean up"):
9
9
  // - The command-line rows under "Cool Workflow" and the `cw <path...>`
10
10
  // rows in formatCommandHelp use a 2-space indent. The CLI/MCP parity
11
11
  // help-token checker parses ONLY 2-space lines as command tokens.
@@ -21,16 +21,20 @@
21
21
  // milestone 5) are dropped from the literal table below and read from the
22
22
  // capability table instead, via `cliCommandHelpRows()`; every other verb
23
23
  // stays literal here until its own milestone lands. This satisfies
24
- // v2/PLAN.md milestone 2's own "done when": a CLI `--help` walk and an MCP
24
+ // docs/rebuild/PLAN.md milestone 2's own "done when": a CLI `--help` walk and an MCP
25
25
  // `tools/list` round-trip read the SAME table rows for any capability
26
26
  // wired into both.
27
27
  Object.defineProperty(exports, "__esModule", { value: true });
28
28
  exports.formatHelp = formatHelp;
29
29
  exports.formatCommandHelp = formatCommandHelp;
30
30
  exports.formatInfo = formatInfo;
31
+ exports.formatSearchResults = formatSearchResults;
31
32
  const capability_table_1 = require("../capability-table");
32
- /** src/orchestrator.ts:934-951 — the exact "More commands" token set, in
33
- * this exact order (space-joined in the source, pipe-joined for display). */
33
+ /** src/orchestrator.ts:934-951 — the "More commands" token set, in the old
34
+ * build's order (space-joined in the source, pipe-joined for display).
35
+ * One change from the old capture: `update` is gone. The verb had no code
36
+ * behind it in this build (`cw update` said "Unknown command"), so the
37
+ * help must not offer it. See parseargv.ts KNOWN_COMMANDS. */
34
38
  const MORE_COMMANDS_TOKENS = [
35
39
  "list", "search", "info", "init", "plan", "status", "next", "dispatch",
36
40
  "result", "state", "commit", "report", "app", "sandbox", "backend",
@@ -40,7 +44,7 @@ const MORE_COMMANDS_TOKENS = [
40
44
  "summary", "blackboard", "coordinator", "metrics", "operator", "sched",
41
45
  "gc", "telemetry", "migration", "demo", "workbench", "approve", "reject",
42
46
  "comment", "handoff", "ledger", "graph", "eval", "man", "version",
43
- "update", "fix",
47
+ "fix",
44
48
  ];
45
49
  const MORE_COMMANDS_WRAP_WIDTH = 76;
46
50
  /** src/orchestrator.ts:940-951 — greedily pack pipe-joined tokens into
@@ -205,7 +209,9 @@ const COMMAND_HELP_ROWS = {
205
209
  /** src/orchestrator.ts:899-933 — the top-level `cw help` text. Color is
206
210
  * intentionally NOT applied here (this milestone's conformance runs pipe
207
211
  * stdout, so NO_COLOR/non-TTY always wins); byte content matches the
208
- * plain-text capture at SPEC/cli-help/_root.txt exactly. */
212
+ * plain-text capture at SPEC/cli-help/_root.txt, but for the dead
213
+ * `update` lines, which were taken out on purpose (no code was behind
214
+ * the verb — see MORE_COMMANDS_TOKENS note above). */
209
215
  function formatHelp() {
210
216
  const moreCommandsLines = wrapPipeJoined(MORE_COMMANDS_TOKENS, MORE_COMMANDS_WRAP_WIDTH);
211
217
  const lines = [
@@ -214,7 +220,6 @@ function formatHelp() {
214
220
  ' -q "question" [-claude|-codex|-gemini|-deepseek] Ask a question, get a report',
215
221
  ' -q "question" --link <url> Review a remote repo by URL',
216
222
  " version Show version",
217
- " update Update to latest release",
218
223
  " doctor Check setup",
219
224
  " fix Show fix commands for setup issues",
220
225
  "",
@@ -312,3 +317,21 @@ function formatInfo(appId, data) {
312
317
  lines.push(` Run: cw quickstart ${appId} --repo . --question "..."`);
313
318
  return lines.join("\n");
314
319
  }
320
+ /** `cw search <keyword>`'s human text — byte-exact to the milestone-1
321
+ * carry-over's own formatSearchResults (moved here from cli/dispatch.ts
322
+ * so the search capability-table row, which lives in core/, can render
323
+ * its own text without core importing from cli/). */
324
+ function formatSearchResults(keyword, results) {
325
+ if (results.length === 0) {
326
+ return `No workflows matched "${keyword}".\n Tip: cw list for all available workflows.`;
327
+ }
328
+ const lines = [`${results.length} workflow${results.length === 1 ? "" : "s"} matching "${keyword}"`];
329
+ for (const r of results) {
330
+ lines.push(` ${r.id} — ${r.title}`);
331
+ const cut = r.summary.length > 120 ? `${r.summary.slice(0, 119)}…` : r.summary;
332
+ lines.push(` ${cut}`);
333
+ }
334
+ lines.push("");
335
+ lines.push("Use cw info <id> for full details.");
336
+ return lines.join("\n");
337
+ }
package/dist/core/hash.js CHANGED
@@ -6,7 +6,7 @@
6
6
  // content object, a list of strings) still comes in as a plain function
7
7
  // argument here.
8
8
  //
9
- // Per v2/PLAN.md's byte-compat section ("Hash dedup — three shapes, not one
9
+ // Per docs/rebuild/PLAN.md's byte-compat section ("Hash dedup — three shapes, not one
10
10
  // edge case"), this file must keep THREE things separate, each with its own
11
11
  // name, never collapsed into a single flagged helper:
12
12
  //
@@ -164,7 +164,7 @@ function stateNodeError(code, message, options = {}, now) {
164
164
  /** Byte-exact port of selectCandidate's own gate ordering: not-selectable
165
165
  * -> verifier-missing/no-evidence/empty-capture -> score-below-threshold.
166
166
  * Review-gate errors are NOT included here; the caller appends them
167
- * (v2/PLAN.md byte-compat / rebuild risk 8: append-only stacking, never
167
+ * (docs/rebuild/PLAN.md byte-compat / rebuild risk 8: append-only stacking, never
168
168
  * replacing a verifier error). */
169
169
  function selectionGateFailures(input, now) {
170
170
  const failures = [];
@@ -36,6 +36,7 @@ exports.listComments = listComments;
36
36
  exports.distinctTargets = distinctTargets;
37
37
  exports.formatReviewStatus = formatReviewStatus;
38
38
  exports.formatCommentList = formatCommentList;
39
+ const collate_1 = require("../util/collate");
39
40
  exports.COLLABORATION_SCHEMA_VERSION = 1;
40
41
  /** The single, honest stand-in for an absent identity. */
41
42
  exports.UNATTRIBUTED_ACTOR = {
@@ -213,7 +214,7 @@ function matchesAnyTarget(target, related) {
213
214
  return related.some((entry) => sameTarget(target, entry));
214
215
  }
215
216
  function compareByCreated(left, right) {
216
- return left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id);
217
+ return (0, collate_1.stableCompare)(left.createdAt, right.createdAt) || (0, collate_1.stableCompare)(left.id, right.id);
217
218
  }
218
219
  function disqualify(record, policy, selfIds) {
219
220
  const actor = record.actor;
@@ -453,7 +454,7 @@ function distinctTargets(state) {
453
454
  seen.set(targetKey(record.target), record.target);
454
455
  for (const record of state.handoffs)
455
456
  seen.set(targetKey(record.target), record.target);
456
- return [...seen.values()].sort((left, right) => targetKey(left).localeCompare(targetKey(right)));
457
+ return [...seen.values()].sort((left, right) => (0, collate_1.stableCompare)(targetKey(left), targetKey(right)));
457
458
  }
458
459
  function formatReviewStatus(report) {
459
460
  const lines = [];
@@ -47,6 +47,7 @@ exports.summarizeBlackboard = summarizeBlackboard;
47
47
  exports.listBlackboardMessages = listBlackboardMessages;
48
48
  exports.listBlackboardArtifacts = listBlackboardArtifacts;
49
49
  exports.buildBlackboardGraph = buildBlackboardGraph;
50
+ const collate_1 = require("../util/collate");
50
51
  exports.BLACKBOARD_SCHEMA_VERSION = 1;
51
52
  /** Dedup, SORTS. Coordinator-side sorting `unique` — byte-identical
52
53
  * behavior to core/multi-agent/runtime.ts's own copy, kept as a
@@ -420,7 +421,7 @@ function summarizeBlackboard(runId, state, blackboardId, defaultIndexPath) {
420
421
  ].sort();
421
422
  const readyForFanin = Boolean(board && !openQuestions.length && !conflicts.length && artifacts.length > 0 && missingEvidence.length === 0);
422
423
  const latestSnapshot = scoped(state.snapshots)
423
- .sort((left, right) => left.createdAt.localeCompare(right.createdAt))
424
+ .sort((left, right) => (0, collate_1.stableCompare)(left.createdAt, right.createdAt))
424
425
  .at(-1);
425
426
  return {
426
427
  runId,
@@ -454,12 +455,12 @@ function nextAction(runId, board, openQuestions, conflicts, artifacts) {
454
455
  function listBlackboardMessages(state, options = {}) {
455
456
  return state.messages
456
457
  .filter((message) => (!options.blackboardId || message.blackboardId === options.blackboardId) && (!options.topicId || message.topicId === options.topicId))
457
- .sort((left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
458
+ .sort((left, right) => (0, collate_1.stableCompare)(left.createdAt, right.createdAt) || (0, collate_1.stableCompare)(left.id, right.id));
458
459
  }
459
460
  function listBlackboardArtifacts(state, options = {}) {
460
461
  return state.artifacts
461
462
  .filter((artifact) => (!options.blackboardId || artifact.blackboardId === options.blackboardId) && (!options.topicId || artifact.topicId === options.topicId))
462
- .sort((left, right) => left.id.localeCompare(right.id));
463
+ .sort((left, right) => (0, collate_1.stableCompare)(left.id, right.id));
463
464
  }
464
465
  function buildBlackboardGraph(runId, state, recordPath, messagesPath) {
465
466
  const nodes = [];
@@ -17,7 +17,7 @@
17
17
  // `failures`/`evidenceAdoption` from the multi-agent/topology/blackboard/
18
18
  // trust state actually built in this milestone (runtime.ts/topology.ts/
19
19
  // coordinator.ts/candidate-scoring.ts), NOT from the full operator-ux
20
- // module (out of this milestone's scope per v2/PLAN.md's build-order
20
+ // module (out of this milestone's scope per docs/rebuild/PLAN.md's build-order
21
21
  // list). The 9 optional v0.1.25/v0.1.26 sections (summaryFreshness
22
22
  // through reasoningUnexplained) default to `[]`, which SPEC/multi-
23
23
  // agent.md's own edge-case list says is valid for snapshots that predate
@@ -22,7 +22,7 @@
22
22
  // core/multi-agent/topology.ts, candidate-scoring.ts, and the host/step
23
23
  // layer have their OWN separate `unique` that does NOT sort (insertion-
24
24
  // order only) — never merge the two. See uniquedual-role-vs-candidate-
25
- // order.case.js and v2/PLAN.md byte-compat item 3.
25
+ // order.case.js and docs/rebuild/PLAN.md byte-compat item 3.
26
26
  //
27
27
  // Evidence: SPEC/multi-agent.md sections A ("Multi-agent kernel"), the
28
28
  // "Kernel error strings" and "Fanin blocked-reason strings" Exact-outputs
@@ -106,7 +106,7 @@ function pluralKind(kind) {
106
106
  }
107
107
  /** Status -> StateNodeStatus, kernel side (default `pending`). Kept
108
108
  * distinct from coordinator/classify.ts's own table (default
109
- * `completed`) per v2/PLAN.md byte-compat / rebuild risk 7 — collapsing
109
+ * `completed`) per docs/rebuild/PLAN.md byte-compat / rebuild risk 7 — collapsing
110
110
  * the two tables changes graph output and eval dependency_parity. */
111
111
  function statusToNodeStatus(status) {
112
112
  switch (status) {
@@ -25,7 +25,7 @@ function unique(values) {
25
25
  }
26
26
  /** Chair detection: lowercased `metadata.topologyRoleId` (or title)
27
27
  * contains "chair", "reducer", or "synthesizer". Judge detection:
28
- * contains "judge". Renaming a role changes its authority (v2/PLAN.md
28
+ * contains "judge". Renaming a role changes its authority (docs/rebuild/PLAN.md
29
29
  * byte-compat / rebuild risk 4 — substring match, not a flag). */
30
30
  function policyForRole(role) {
31
31
  const topologyRole = String(role.metadata?.topologyRoleId || role.title || "").toLowerCase();
@@ -20,6 +20,7 @@ exports.formatCommitId = formatCommitId;
20
20
  exports.gateFailureSeq = gateFailureSeq;
21
21
  const evidence_grounding_1 = require("../trust/evidence-grounding");
22
22
  const result_normalize_1 = require("./result-normalize");
23
+ const collate_1 = require("../util/collate");
23
24
  /** The sandbox profile that accepted a candidate's worker output — the
24
25
  * worker's own profile when present, else the backing task's. Pure port of
25
26
  * the old build's src/gates.ts sandboxProfileForCandidate. */
@@ -97,7 +98,7 @@ function findSelectionNode(run, selectionId) {
97
98
  function latestSelectionForCandidate(run, candidateId) {
98
99
  return [...(run.candidateSelections || [])]
99
100
  .filter((s) => s.candidateId === candidateId)
100
- .sort((a, b) => (b.selectedAt || "").localeCompare(a.selectedAt || ""))[0];
101
+ .sort((a, b) => (0, collate_1.stableCompare)(b.selectedAt || "", a.selectedAt || ""))[0];
101
102
  }
102
103
  function evidenceLocatorString(entry) {
103
104
  const ref = entry.locator || entry.path || entry.summary || entry.id;
@@ -2,7 +2,7 @@
2
2
  // core/pipeline/contract.ts — DEFAULT_PIPELINE_CONTRACT_ID,
3
3
  // createDefaultPipelineContract.
4
4
  //
5
- // MILESTONE 6+7 (combined; see v2/PLAN.md Open risk 10). Byte-exact port
5
+ // MILESTONE 6+7 (combined; see docs/rebuild/PLAN.md Open risk 10). Byte-exact port
6
6
  // of the old build's src/pipeline-contract.ts. Pure data.
7
7
  //
8
8
  // Evidence: SPEC/pipeline-run.md "Default contract — src/pipeline-
@@ -3,7 +3,7 @@
3
3
  // decision core: task selection, terminal/gate logic, token-budget check,
4
4
  // retry/park math, cache-key formulas.
5
5
  //
6
- // MILESTONE 6+7 (combined; the big one — see v2/PLAN.md Open risk 9).
6
+ // MILESTONE 6+7 (combined; the big one — see docs/rebuild/PLAN.md Open risk 9).
7
7
  // Every branch here is a pure function of already-loaded run state; it
8
8
  // does not itself spawn a process or touch disk. shell/drive.ts is the
9
9
  // thin imperative loop that calls these functions once per step and
@@ -2,7 +2,7 @@
2
2
  // core/state/contract-migration.ts — declared migration registry + prover.
3
3
  //
4
4
  // MILESTONE 3. Byte-exact port of the old build's src/contract-migration.ts
5
- // (renamed target per v2/PLAN.md's module layout note — listed there as
5
+ // (renamed target per docs/rebuild/PLAN.md's module layout note — listed there as
6
6
  // `pipeline/contract-migration.ts`, kept here under state/ since every
7
7
  // symbol it needs — RUN_STATE_MIGRATIONS, migrateRunState,
8
8
  // findMigrationPath — is this milestone's own state kernel and nothing in
@@ -10,7 +10,7 @@
10
10
  //
11
11
  // Evidence: SPEC/state-core.md "src/state-migrations.ts — run-state
12
12
  // migration", "Migration pipeline (migrateRunState)", "Normalization
13
- // defaults" (v2/PLAN.md byte-compat item 4).
13
+ // defaults" (docs/rebuild/PLAN.md byte-compat item 4).
14
14
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
15
  if (k2 === undefined) k2 = k;
16
16
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -232,7 +232,7 @@ function reverseRunState(input, targetSchemaVersion, options = {}) {
232
232
  return { run: state, report };
233
233
  }
234
234
  /** Fill in every WorkflowRun default, each recorded as a StateMigrationChange.
235
- * Pinned defaults (v2/PLAN.md byte-compat item 4): epoch-0 ISO timestamps,
235
+ * Pinned defaults (docs/rebuild/PLAN.md byte-compat item 4): epoch-0 ISO timestamps,
236
236
  * cwd = three dirs above the run dir else process.cwd(), workflow.limits =
237
237
  * { maxAgents: 8, maxConcurrentAgents: 4 }, loopStage = "interpret" (any
238
238
  * unknown value overwritten). */
@@ -9,7 +9,7 @@
9
9
  // given `(run, clock)` — no direct fs/Date calls; `now` is always an
10
10
  // explicit parameter, `persist` is always a caller-supplied callback.
11
11
  //
12
- // RAW vs NORMALIZED fingerprints [v2/PLAN.md byte-compat item 8 — do not
12
+ // RAW vs NORMALIZED fingerprints [docs/rebuild/PLAN.md byte-compat item 8 — do not
13
13
  // merge these two code paths]:
14
14
  // - `sourceFingerprint` is RAW: built from the node's raw id/status/
15
15
  // updatedAt plus raw artifact/evidence id+path strings. ANY transition
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
29
29
  exports.summarizeBlackboardDigest = summarizeBlackboardDigest;
30
30
  const hash_1 = require("../../hash");
31
31
  const helpers_1 = require("./helpers");
32
+ const collate_1 = require("../../util/collate");
32
33
  /** Deterministic structural summary of one (or the default) blackboard.
33
34
  * Every list is sorted by id (`byId`); `recentChanges` is the last 10 by
34
35
  * `updatedAt` desc, THEN re-sorted by id for the final list (matching the
@@ -63,7 +64,7 @@ function summarizeBlackboardDigest(run, blackboardId, now) {
63
64
  .map((topic) => {
64
65
  const topicMessages = messages
65
66
  .filter((m) => m.topicId === topic.id)
66
- .sort((a, b) => a.createdAt.localeCompare(b.createdAt) || a.id.localeCompare(b.id));
67
+ .sort((a, b) => (0, collate_1.stableCompare)(a.createdAt, b.createdAt) || (0, collate_1.stableCompare)(a.id, b.id));
67
68
  const last = topicMessages[topicMessages.length - 1];
68
69
  return {
69
70
  id: `thread:${topic.id}`,
@@ -181,7 +182,7 @@ function summarizeBlackboardDigest(run, blackboardId, now) {
181
182
  updatedAt: record.updatedAt,
182
183
  status: record.status,
183
184
  }))
184
- .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id))
185
+ .sort((a, b) => (0, collate_1.stableCompare)(b.updatedAt, a.updatedAt) || (0, collate_1.stableCompare)(a.id, b.id))
185
186
  .slice(0, 10)
186
187
  .map((record) => ({
187
188
  id: `recent:${record.id}`,
@@ -26,7 +26,7 @@
26
26
  // file's collapse-rule machinery changing at all.
27
27
  //
28
28
  // Evidence: SPEC/state-core.md "buildCompactGraph(...)", "State-explosion
29
- // collapse rules"; v2/PLAN.md byte-compat item 9;
29
+ // collapse rules"; docs/rebuild/PLAN.md byte-compat item 9;
30
30
  // src/multi-agent-operator-ux.ts:153-227 (buildMultiAgentOperatorGraph).
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
32
  exports.byId = exports.GRAPH_VIEWS = void 0;
@@ -37,6 +37,7 @@ exports.buildCompactGraphFromView = buildCompactGraphFromView;
37
37
  const size_1 = require("./size");
38
38
  const helpers_1 = require("./helpers");
39
39
  Object.defineProperty(exports, "byId", { enumerable: true, get: function () { return helpers_1.byId; } });
40
+ const collate_1 = require("../../util/collate");
40
41
  const runtime_1 = require("../../multi-agent/runtime");
41
42
  const coordinator_1 = require("../../multi-agent/coordinator");
42
43
  const topology_1 = require("../../multi-agent/topology");
@@ -144,8 +145,8 @@ function runToGraphView(run) {
144
145
  return true;
145
146
  });
146
147
  return {
147
- nodes: [...nodes.values()].sort((a, b) => a.kind.localeCompare(b.kind) || a.id.localeCompare(b.id)),
148
- edges: dedupedEdges.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to) || (a.label || "").localeCompare(b.label || "")),
148
+ nodes: [...nodes.values()].sort((a, b) => (0, collate_1.stableCompare)(a.kind, b.kind) || (0, collate_1.stableCompare)(a.id, b.id)),
149
+ edges: dedupedEdges.sort((a, b) => (0, collate_1.stableCompare)(a.from, b.from) || (0, collate_1.stableCompare)(a.to, b.to) || (0, collate_1.stableCompare)(a.label || "", b.label || "")),
149
150
  };
150
151
  }
151
152
  /** `buildCompactGraph(run, view, options)` — builds the graph view via
@@ -192,8 +193,8 @@ function runToGraphViewFromWorkflowRun(run) {
192
193
  edges.push(edge);
193
194
  }
194
195
  return {
195
- nodes: [...nodes.values()].sort((a, b) => a.kind.localeCompare(b.kind) || a.id.localeCompare(b.id)),
196
- edges: edges.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to) || (a.label || "").localeCompare(b.label || "")),
196
+ nodes: [...nodes.values()].sort((a, b) => (0, collate_1.stableCompare)(a.kind, b.kind) || (0, collate_1.stableCompare)(a.id, b.id)),
197
+ edges: edges.sort((a, b) => (0, collate_1.stableCompare)(a.from, b.from) || (0, collate_1.stableCompare)(a.to, b.to) || (0, collate_1.stableCompare)(a.label || "", b.label || "")),
197
198
  };
198
199
  }
199
200
  function collapseRuleFor() {
@@ -220,7 +221,7 @@ function collapseRuleFor() {
220
221
  },
221
222
  };
222
223
  }
223
- /** Collapsible kinds ONLY (v2/PLAN.md byte-compat item 9): high-volume,
224
+ /** Collapsible kinds ONLY (docs/rebuild/PLAN.md byte-compat item 9): high-volume,
224
225
  * low-individual-signal. `decisions, artifacts, fanins, candidates,
225
226
  * selections, commits, feedback` are NEVER collapsed so failures,
226
227
  * evidence, policy, and judge rationale stay visible. */
@@ -414,7 +415,7 @@ function buildCompactGraphFromView(runId, full, view = "compact", options = {})
414
415
  protectedIds.add(node.id);
415
416
  }
416
417
  // Reasoning-critical nodes are on the critical path and must never be
417
- // collapsed into a synthetic summary node (v2/PLAN.md byte-compat item 9).
418
+ // collapsed into a synthetic summary node (docs/rebuild/PLAN.md byte-compat item 9).
418
419
  for (const id of options.reasoningCriticalIds || [])
419
420
  protectedIds.add(id);
420
421
  const parents = (0, helpers_1.parentMap)(full.edges);
@@ -467,10 +468,10 @@ function buildCompactGraphFromView(runId, full, view = "compact", options = {})
467
468
  buckets.set(bucketKey, [...(buckets.get(bucketKey) || []), node.id]);
468
469
  }
469
470
  // Buckets smaller than the collapse threshold stay expanded (unless
470
- // critical-path — v2/PLAN.md byte-compat item 9).
471
+ // critical-path — docs/rebuild/PLAN.md byte-compat item 9).
471
472
  const synthetic = [];
472
473
  const collapsedNodeIds = new Map(); // sourceNodeId -> syntheticId
473
- for (const [bucketKey, ids] of [...buckets.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
474
+ for (const [bucketKey, ids] of [...buckets.entries()].sort((a, b) => (0, collate_1.stableCompare)(a[0], b[0]))) {
474
475
  if (view !== "critical-path" && ids.length < thresholds.collapseBucket) {
475
476
  for (const id of ids)
476
477
  keep.add(id);
@@ -519,9 +520,9 @@ function buildCompactGraphFromView(runId, full, view = "compact", options = {})
519
520
  edges.push({ from, to, label: edge.label });
520
521
  }
521
522
  return finalizeGraphRecord(runId, view, options, full, {
522
- nodes: nodes.sort((a, b) => a.kind.localeCompare(b.kind) || a.id.localeCompare(b.id)),
523
- edges: edges.sort((a, b) => a.from.localeCompare(b.from) || a.to.localeCompare(b.to) || (a.label || "").localeCompare(b.label || "")),
524
- syntheticNodes: synthetic.sort((a, b) => a.id.localeCompare(b.id)),
523
+ nodes: nodes.sort((a, b) => (0, collate_1.stableCompare)(a.kind, b.kind) || (0, collate_1.stableCompare)(a.id, b.id)),
524
+ edges: edges.sort((a, b) => (0, collate_1.stableCompare)(a.from, b.from) || (0, collate_1.stableCompare)(a.to, b.to) || (0, collate_1.stableCompare)(a.label || "", b.label || "")),
525
+ syntheticNodes: synthetic.sort((a, b) => (0, collate_1.stableCompare)(a.id, b.id)),
525
526
  critical,
526
527
  });
527
528
  }
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // MILESTONE 4. Byte-exact port of the old build's
6
6
  // src/state-explosion/helpers.ts. `fingerprintStrings`/`fingerprintRecords`
7
- // live in core/hash.ts (the one hash module, per v2/PLAN.md's byte-compat
7
+ // live in core/hash.ts (the one hash module, per docs/rebuild/PLAN.md's byte-compat
8
8
  // item 2) and are re-exported here so every importer of this file keeps
9
9
  // the same surface the old build had.
10
10
  //
@@ -13,7 +13,7 @@
13
13
  // a later milestone's topology/candidate/host-decide code has its OWN
14
14
  // separate `unique` (dedup-only, unsorted) that must NEVER be merged with
15
15
  // this one; collapsing them changes persisted record order and eval
16
- // parity (v2/PLAN.md byte-compat item 3, Open risk 2). See
16
+ // parity (docs/rebuild/PLAN.md byte-compat item 3, Open risk 2). See
17
17
  // core/state/state-node.ts's own local `unique` for the sibling that must
18
18
  // stay separate.
19
19
  //
@@ -33,8 +33,9 @@ exports.slug = slug;
33
33
  const hash_1 = require("../../hash");
34
34
  Object.defineProperty(exports, "fingerprintRecords", { enumerable: true, get: function () { return hash_1.fingerprintRecords; } });
35
35
  Object.defineProperty(exports, "fingerprintStrings", { enumerable: true, get: function () { return hash_1.fingerprintStrings; } });
36
+ const collate_1 = require("../../util/collate");
36
37
  /** True for `failed`, `blocked`, `rejected`, `conflicting` — the never-
37
- * collapse status set (v2/PLAN.md byte-compat item 9). */
38
+ * collapse status set (docs/rebuild/PLAN.md byte-compat item 9). */
38
39
  function isProtectedStatus(status) {
39
40
  return ["failed", "blocked", "rejected", "conflicting"].includes(status);
40
41
  }
@@ -83,7 +84,7 @@ function unique(values) {
83
84
  return Array.from(new Set(values.filter(Boolean))).sort();
84
85
  }
85
86
  function byId(a, b) {
86
- return a.id.localeCompare(b.id);
87
+ return (0, collate_1.stableCompare)(a.id, b.id);
87
88
  }
88
89
  /** Whitespace-collapsed; over 80 chars becomes the first 77 chars + `...`. */
89
90
  function truncate(value) {
@@ -6,7 +6,7 @@
6
6
  // Report`/`buildOperatorDigestWithContext` (src/state-explosion.ts) minus
7
7
  // the disk I/O — persistence (`refreshStateExplosionSummaries`'s writes,
8
8
  // `loadStateExplosionSummaryIndex`'s read) is shell/state-explosion-
9
- // cli.ts's job per v2/PLAN.md's core/shell split. This file only builds
9
+ // cli.ts's job per docs/rebuild/PLAN.md's core/shell split. This file only builds
10
10
  // the report VALUE from an in-memory run + an already-loaded index.
11
11
  //
12
12
  // See size.ts/graph.ts/digest.ts's own header notes on why `operatorDigest`
@@ -2,7 +2,7 @@
2
2
  // core/state/state-explosion/size.ts — computeStateSizeWithGraph,
3
3
  // DEFAULT_STATE_EXPLOSION_THRESHOLDS.
4
4
  //
5
- // MILESTONE 4 (v2/PLAN.md build order, step 4). Byte-exact port of the old
5
+ // MILESTONE 4 (docs/rebuild/PLAN.md build order, step 4). Byte-exact port of the old
6
6
  // build's src/state-explosion/size.ts. The counts are the same 12
7
7
  // categories the old build reads off `run.multiAgent`/`run.blackboard`
8
8
  // (loose `unknown[]`-typed record arrays at this milestone — see core/
@@ -11,7 +11,7 @@
11
11
  //
12
12
  // Evidence: SPEC/state-core.md "src/state-node.ts — StateNode lifecycle and
13
13
  // contract gates", "StateNode transition matrix", "Deterministic id
14
- // fallback", "Contract gates" (v2/PLAN.md byte-compat item 7 — the double
14
+ // fallback", "Contract gates" (docs/rebuild/PLAN.md byte-compat item 7 — the double
15
15
  // commit gate).
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.PipelineContractError = exports.PIPELINE_CONTRACT_SCHEMA_VERSION = exports.STATE_NODE_SCHEMA_VERSION = void 0;
@@ -115,7 +115,7 @@ function validatePipelineContract(contract) {
115
115
  * check against; every real caller (shell/) passes `fs.existsSync` so the
116
116
  * `missing-artifact-path` gate behaves exactly like the old build. Kept as
117
117
  * an explicit parameter (never a top-level `require("node:fs")`) so this
118
- * stays a pure core/ module per v2/PLAN.md's core/shell split. */
118
+ * stays a pure core/ module per docs/rebuild/PLAN.md's core/shell split. */
119
119
  function assertNodeSatisfiesContract(node, contract, stageId, pathExists = () => true) {
120
120
  validatePipelineContract(contract);
121
121
  const stage = contract.stages.find((candidate) => candidate.id === stageId);
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // core/state/types.ts — the state-kernel's own type set.
3
3
  //
4
- // MILESTONE 3 (v2/PLAN.md build order, step 3). Scoped to exactly what
4
+ // MILESTONE 3 (docs/rebuild/PLAN.md build order, step 3). Scoped to exactly what
5
5
  // state-core.md's public surface needs: WorkflowRun and everything it
6
6
  // carries, StateNode + its snapshot/replay/diff family, the pipeline
7
7
  // contract shape, and the small persisted-record shapes validation.ts
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // core/trust/ledger.ts — the cross-agent handoff ledger kernel.
3
3
  //
4
- // MILESTONE 8 (v2/PLAN.md build order, step 8; SPEC/ledger-trust.md in
4
+ // MILESTONE 8 (docs/rebuild/PLAN.md build order, step 8; SPEC/ledger-trust.md in
5
5
  // full). Pure: computeLedgerDigest, buildLedgerProposal/Review,
6
6
  // verifyLedgerEntry, applyLedgerProposal. Directory reads
7
7
  // (listLedgerEntries/unionLedgerEntries) live in shell/ledger-io.ts, NOT
@@ -22,6 +22,7 @@ exports.verifyLedgerEntry = verifyLedgerEntry;
22
22
  exports.applyLedgerProposal = applyLedgerProposal;
23
23
  exports.resolveLedgerInbox = resolveLedgerInbox;
24
24
  const hash_1 = require("../hash");
25
+ const collate_1 = require("../util/collate");
25
26
  /** sha256 over the canonical content (every field except `id` and
26
27
  * `digest`, which are derived FROM it). Returns the full `sha256:<hex>`
27
28
  * form — the same prefixed spelling every other hash chain uses. */
@@ -187,7 +188,7 @@ function resolveLedgerInbox(entries) {
187
188
  reviews: answering.map((r) => r.id).sort(),
188
189
  };
189
190
  })
190
- .sort((a, b) => a.id.localeCompare(b.id));
191
+ .sort((a, b) => (0, collate_1.stableCompare)(a.id, b.id));
191
192
  const tally = (s) => proposals.filter((p) => p.resolution === s).length;
192
193
  return {
193
194
  proposals,
@@ -6,7 +6,7 @@
6
6
  // node:crypto's built-in ed25519 sign/verify (no npm dependency).
7
7
  //
8
8
  // `crypto.verify`/`crypto.createPublicKey` are allowed here per
9
- // v2/PLAN.md's lint carve-out for this exact file (Target shape,
9
+ // docs/rebuild/PLAN.md's lint carve-out for this exact file (Target shape,
10
10
  // core/trust/telemetry-attestation.ts comment) — this remains otherwise
11
11
  // pure (no fs, no process.env, no clock; `resolveTrustPublicKey`'s lazy
12
12
  // `require("node:fs")` is the one exception, ported byte-identically
@@ -62,7 +62,7 @@ const crypto = __importStar(require("node:crypto"));
62
62
  * recursively, AND maps a top-level `undefined` input to the literal
63
63
  * string `"null"`. Divergent from `core/hash.ts`'s
64
64
  * `ledgerStableStringify` exactly at the top-level-undefined edge (see
65
- * v2/PLAN.md byte-compat item 2). Re-exported under this file's own
65
+ * docs/rebuild/PLAN.md byte-compat item 2). Re-exported under this file's own
66
66
  * name (rather than importing `telemetryStableStringify` from
67
67
  * core/hash.ts) because SPEC/ledger-trust.md's "Exported functions"
68
68
  * list names `stableStringify` as a real export of THIS module — the
@@ -118,7 +118,7 @@ function normalizeReportedUsage(usage) {
118
118
  };
119
119
  }
120
120
  /** Verify the agent's signed usage against the operator-provisioned
121
- * public key. Two-arm check (v2/PLAN.md byte-compat item 11): try the
121
+ * public key. Two-arm check (docs/rebuild/PLAN.md byte-compat item 11): try the
122
122
  * 5-field payload (with resultDigest) first; on a miss, retry the
123
123
  * 4-field payload (old signers still verify). `coversResult` is set
124
124
  * ONLY on a first-arm match — a 4-field fallback match never covers the
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // MILESTONE 8. Byte-exact port of the old build's src/telemetry-ledger.ts
9
9
  // verify-side logic. Uses core/hash.ts's `sha256`/`telemetryStableStringify`
10
- // (see v2/PLAN.md byte-compat item 2's key-omission-vs-null rule).
10
+ // (see docs/rebuild/PLAN.md byte-compat item 2's key-omission-vs-null rule).
11
11
  //
12
12
  // Evidence: SPEC/ledger-trust.md "Telemetry ledger record", byte-compat
13
13
  // items 2 and 12; plugins/cool-workflow/src/telemetry-ledger.ts:1-224.
@@ -43,7 +43,7 @@ function genesisPrevHash(runId) {
43
43
  * recordHash itself. `reportedUsage`/`resultDigest` are OMITTED (not
44
44
  * `null`) when absent, so a usage-only record's hash is byte-identical
45
45
  * to a pre-result-coverage one (back-compat with old ledgers) — see
46
- * v2/PLAN.md byte-compat item 2. */
46
+ * docs/rebuild/PLAN.md byte-compat item 2. */
47
47
  function recordHashInput(record) {
48
48
  return (0, hash_1.telemetryStableStringify)({
49
49
  schemaVersion: record.schemaVersion,
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ // core/types/execution-backend.ts — plain data shapes for the driver layer.
3
+ //
4
+ // MILESTONE 5 (docs/rebuild/PLAN.md build order, step 5). Byte-exact port of the shapes
5
+ // in the old build's src/types/execution-backend.ts and the sandbox slice of
6
+ // src/types/sandbox.ts that this subsystem needs. Types only — no logic —
7
+ // so this file lives in core/ (moved here from shell/execution-backend/
8
+ // types.ts, which now re-exports it for its 7 existing importers): the
9
+ // executor-boundary welds in core/types/boundary.ts need ResultEnvelope
10
+ // and ExecutionResultEnvelope, and neither can be cherry-picked out of
11
+ // this file alone without also carrying their whole dependency graph
12
+ // (ExecutionProvenance, SandboxAttestation, BackendLocality/BackendKind,
13
+ // BackendExecutionHandle, ...) — so the file moves as one piece, matching
14
+ // its own original header's claim that it was "safe to import from both
15
+ // shell/ (impure) and any future core/ caller."
16
+ //
17
+ // Evidence: SPEC/execution-backend.md.
18
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ // core/types/observability.ts — the one type shell/observability.ts's
3
+ // executor-boundary weld (core/types/boundary.ts) needs, moved here since
4
+ // it is plain data with no dependency on that (impure) file's logic.
5
+ // shell/observability.ts re-exports it so its own existing exports stay
6
+ // unchanged.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.stableCompare = stableCompare;
4
+ // core/util/collate.ts — THE one string-ordering comparator for anything
5
+ // whose order feeds a hash, a cache key, or a byte-pinned output.
6
+ //
7
+ // Pure. No fs, no child_process, no net, no process.env, no Date.now(), no
8
+ // Math.random().
9
+ //
10
+ // A bare `a.localeCompare(b)` reads the HOST's default locale (LANG/LC_ALL),
11
+ // which is not part of CW's replay-determinism story: two machines with
12
+ // different locales sorting the SAME string set can walk it in a different
13
+ // order, so anything that hashes that order (a cache key) drifts silently
14
+ // across hosts, and anything that hashes CONTENT built from that order (an
15
+ // eval snapshot) can misreport a determinism regression that is really just
16
+ // a locale difference. `stableCompare` pins the locale explicitly to "en" —
17
+ // this is the SAME bytes Node's full-ICU build already produces under the
18
+ // ICU root locale (which is what a locale-stripped environment, e.g. this
19
+ // repo's own conformance harness, always runs under), so switching a bare
20
+ // `localeCompare` call to this one changes NO existing output.
21
+ function stableCompare(a, b) {
22
+ return a.localeCompare(b, "en");
23
+ }
@@ -7,7 +7,7 @@ exports.MIN_SUPPORTED_RUN_STATE_SCHEMA_VERSION = exports.LEGACY_RUN_STATE_SCHEMA
7
7
  // `cw version` output does not change bytes just because the code under it
8
8
  // was rebuilt. See SPEC/cli-surface.md "Exact outputs > Version" and
9
9
  // conformance/cases/version-basic.case.js (regex `/^\d+\.\d+\.\d+\n$/`).
10
- exports.CURRENT_COOL_WORKFLOW_VERSION = "0.2.0";
10
+ exports.CURRENT_COOL_WORKFLOW_VERSION = "0.2.2";
11
11
  // State-kernel schema version constants (SPEC/state-core.md "Version
12
12
  // constants"). Pinned to the old build's src/version.ts byte-for-byte.
13
13
  exports.WORKFLOW_APP_SCHEMA_VERSION = 1;
@@ -4,7 +4,7 @@
4
4
  // `agent`, `artifact`, `subWorkflow`, `input`), and full manifest
5
5
  // validation (`validateWorkflowApp`).
6
6
  //
7
- // MILESTONE 12 (v2/PLAN.md build order; workflow-apps.md). Milestone 6+7
7
+ // MILESTONE 12 (docs/rebuild/PLAN.md build order; workflow-apps.md). Milestone 6+7
8
8
  // built the minimal real subset needed to load ONE app and drive it
9
9
  // end to end (see git history / the old header note this replaces).
10
10
  // This milestone adds, on top of that, WITHOUT changing any existing