@jstn-sdk/ma 0.1.12 → 0.14.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 (198) hide show
  1. package/.codex/agents/Architect.toml +1 -2
  2. package/.codex/agents/Auditor.toml +1 -2
  3. package/.codex/agents/Builder.toml +1 -2
  4. package/.codex/agents/Flow.toml +1 -2
  5. package/.codex/agents/Sage.toml +1 -2
  6. package/.codex/agents/Vibe.toml +1 -2
  7. package/.codex/hooks.json +24 -13
  8. package/.codex/prompts/enforcement.md +4 -0
  9. package/.codex/prompts/onboarding.md +6 -1
  10. package/.codex/prompts/release-rules.md +0 -0
  11. package/.codex/prompts/skill-contract.md +4 -0
  12. package/COVERAGE.md +211 -0
  13. package/DEMO.md +274 -0
  14. package/LICENSE +0 -0
  15. package/README.md +132 -656
  16. package/bin/ma.js +748 -55
  17. package/data/clone-data.ledger.json +41 -0
  18. package/data/clone-data.proof.json +50 -0
  19. package/data/clone-data.rvf +37 -0
  20. package/docs/README.md +10 -1
  21. package/docs/autonomous-tasks.md +46 -0
  22. package/docs/codex-integration.md +16 -0
  23. package/docs/getting-started.md +62 -22
  24. package/docs/mcp-setup.md +64 -0
  25. package/docs/qa/release-issue-gates-0.14.0.json +644 -0
  26. package/docs/qa/release-readiness-0.1.5.md +1 -1
  27. package/docs/qa/{release-readiness-0.1.12.md → release-readiness-0.14.0.md} +25 -9
  28. package/docs/quality.md +24 -0
  29. package/docs/reference/native-security-playbooks.md +6 -0
  30. package/docs/reference/native-source-selection.md +6 -0
  31. package/docs/release-spec.md +39 -10
  32. package/docs/skills.md +14 -1
  33. package/index.js +295 -2
  34. package/mcp/collections.json +23 -6
  35. package/mcp/fallback.json +0 -0
  36. package/mcp/local/code-intel.js +179 -41
  37. package/mcp/local/context.js +180 -0
  38. package/mcp/local/memory.js +17 -6
  39. package/mcp/local/quality.js +39 -0
  40. package/mcp/local/state.js +7 -3
  41. package/mcp/local/team-run.js +56 -4
  42. package/mcp/local-capabilities.json +9 -0
  43. package/mcp/servers.json +24 -0
  44. package/package.json +29 -4
  45. package/plugins/meta-architect/.app.json +1 -1
  46. package/plugins/meta-architect/.codex-plugin/plugin.json +1 -1
  47. package/plugins/meta-architect/.mcp.json +1 -1
  48. package/plugins/meta-architect/README.md +8 -1
  49. package/plugins/meta-architect/obsidian/main.js +534 -0
  50. package/plugins/meta-architect/obsidian/manifest.json +9 -0
  51. package/plugins/meta-architect/obsidian/styles.css +7 -0
  52. package/plugins/meta-architect/skills/arch/SKILL.md +2 -0
  53. package/plugins/meta-architect/skills/build/SKILL.md +3 -0
  54. package/plugins/meta-architect/skills/flow/SKILL.md +2 -0
  55. package/plugins/meta-architect/skills/sage/SKILL.md +2 -0
  56. package/plugins/meta-architect/skills/sage/references/source-selection.md +8 -0
  57. package/plugins/meta-architect/skills/vet/SKILL.md +2 -0
  58. package/plugins/meta-architect/skills/vet/references/security-playbooks.md +7 -0
  59. package/plugins/meta-architect/skills/vibe/SKILL.md +2 -0
  60. package/schemas/autonomous-task-queue.schema.json +56 -0
  61. package/schemas/handoff-packet.schema.json +36 -0
  62. package/schemas/setup-receipt.schema.json +28 -0
  63. package/schemas/skill-frontmatter.schema.json +20 -0
  64. package/schemas/support-bundle.schema.json +37 -0
  65. package/schemas/task-contract.schema.json +31 -0
  66. package/scripts/active-autonomy-hook.mjs +226 -0
  67. package/scripts/build-linux-packages.mjs +7 -3
  68. package/scripts/cleanup-test-fixtures.sh +55 -0
  69. package/scripts/context-hydration-hook.mjs +89 -0
  70. package/scripts/demo-smoke.js +285 -0
  71. package/scripts/doctor.js +27 -12
  72. package/scripts/install.sh +57 -0
  73. package/scripts/install.sh.sha256 +1 -0
  74. package/scripts/linux-package-smoke.mjs +2 -2
  75. package/scripts/package-size-check.mjs +26 -0
  76. package/scripts/plugin-sync.js +83 -17
  77. package/scripts/postinstall.js +17 -10
  78. package/scripts/prepack.js +9 -0
  79. package/scripts/ralph/prompt.md +35 -0
  80. package/scripts/release-sync.js +72 -7
  81. package/scripts/release-verify.js +260 -2
  82. package/scripts/setup-npmrc.js +48 -23
  83. package/scripts/skills-install.js +9 -2
  84. package/scripts/skills-manifest.js +2 -21
  85. package/scripts/skills-pack.js +2 -2
  86. package/scripts/skills-validate.js +5 -55
  87. package/skills/arch/SKILL.md +2 -0
  88. package/skills/build/SKILL.md +3 -0
  89. package/skills/flow/SKILL.md +2 -0
  90. package/skills/index.json +0 -0
  91. package/skills/sage/SKILL.md +2 -0
  92. package/skills/sage/references/source-selection.md +8 -0
  93. package/skills/vet/SKILL.md +2 -0
  94. package/skills/vet/references/security-playbooks.md +7 -0
  95. package/skills/vibe/SKILL.md +2 -0
  96. package/sprint/00-idea.md +0 -0
  97. package/sprint/01-architecture.md +0 -0
  98. package/sprint/02-oss-evidence.md +0 -0
  99. package/sprint/03-logic.md +0 -0
  100. package/sprint/04-security.md +0 -0
  101. package/sprint/05-dx-ux.md +0 -0
  102. package/sprint/06-build-plan.md +0 -0
  103. package/sprint/07-release.md +0 -0
  104. package/src/agents.js +279 -0
  105. package/src/bootstrap.js +268 -62
  106. package/src/build-gate.js +2 -2
  107. package/src/codex-app-server.js +291 -0
  108. package/src/decision-log.js +0 -0
  109. package/src/fs-utils.js +175 -4
  110. package/src/launcher.js +28 -21
  111. package/src/mcp-config.js +9 -1
  112. package/src/mcp-live-client.js +422 -3
  113. package/src/paths.js +10 -1
  114. package/src/policy.js +3 -3
  115. package/src/prelaunch.js +189 -0
  116. package/src/quality/ai-quality-orchestrator.js +328 -0
  117. package/src/release-issue-gates.js +252 -0
  118. package/src/release-operations.js +62 -0
  119. package/src/release-state.js +0 -0
  120. package/src/runtime/active-autonomy-core.js +208 -0
  121. package/src/runtime/agent-compat.js +31 -0
  122. package/src/runtime/alignment-sentinel.js +165 -0
  123. package/src/runtime/architect-review.js +326 -0
  124. package/src/runtime/autonomous-tasks.js +408 -0
  125. package/src/runtime/build-readiness.js +28 -4
  126. package/src/runtime/code-graph-rehearse.js +113 -0
  127. package/src/runtime/codeburn-core.js +112 -0
  128. package/src/runtime/context-authority.js +40 -0
  129. package/src/runtime/context-economy-core.js +316 -0
  130. package/src/runtime/continuity-graph.js +201 -0
  131. package/src/runtime/continuity-notes.js +71 -26
  132. package/src/runtime/core-source-ingest.js +379 -0
  133. package/src/runtime/detached-provider.js +142 -0
  134. package/src/runtime/doctor-report.js +18 -0
  135. package/src/runtime/environment-awareness-core.js +460 -0
  136. package/src/runtime/exposure-catalog.js +276 -0
  137. package/src/runtime/graphify-core.js +167 -0
  138. package/src/runtime/guidance-stack.js +9 -2
  139. package/src/runtime/handoff-packets.js +92 -0
  140. package/src/runtime/headroom-core.js +104 -0
  141. package/src/runtime/helper-orchestration-core.js +307 -0
  142. package/src/runtime/hook-profiles.js +20 -0
  143. package/src/runtime/learning-loop-core.js +344 -0
  144. package/src/runtime/live-agent-verification.js +122 -0
  145. package/src/runtime/maestro-events.js +18 -0
  146. package/src/runtime/maestro-manager.js +19 -0
  147. package/src/runtime/maestro-output.js +58 -0
  148. package/src/runtime/maestro-state.js +125 -0
  149. package/src/runtime/managed-markdown.js +29 -0
  150. package/src/runtime/mcp-authority.js +147 -0
  151. package/src/runtime/mcp-policy.js +192 -0
  152. package/src/runtime/obsidian-integration-core.js +1089 -0
  153. package/src/runtime/obsidian-plugin-bridge.js +1045 -0
  154. package/src/runtime/pi-maestro-core.js +89 -0
  155. package/src/runtime/preferences.js +79 -0
  156. package/src/runtime/project-context.js +636 -0
  157. package/src/runtime/prompt-strategy-core.js +230 -0
  158. package/src/runtime/quorum-review.js +90 -0
  159. package/src/runtime/ralph-execution-core.js +217 -0
  160. package/src/runtime/redaction-gateway.js +373 -0
  161. package/src/runtime/runtime-state.js +935 -2
  162. package/src/runtime/schema-migrations.js +162 -0
  163. package/src/runtime/semantic-recording-core.js +147 -0
  164. package/src/runtime/signal-hooks.js +28 -0
  165. package/src/runtime/skills-registry-export.js +754 -0
  166. package/src/runtime/task-contracts.js +83 -0
  167. package/src/runtime/universal-plugin-broker-core.js +898 -0
  168. package/src/runtime/workspace-intelligence-runtime.js +674 -0
  169. package/src/runtime/workspace-virtualizer.js +102 -0
  170. package/src/runtime-artifacts.js +225 -62
  171. package/src/setup-lifecycle.js +359 -0
  172. package/src/skill-frontmatter.js +78 -0
  173. package/src/skill-installer.js +226 -71
  174. package/src/skills.js +1166 -96
  175. package/src/state-sync.js +0 -0
  176. package/src/test-fixtures.js +543 -0
  177. package/src/tui/grid.js +67 -0
  178. package/src/tui/status-grid.js +23 -0
  179. package/support-bundle.json +114 -0
  180. package/templates/AGENTS.md +6 -2
  181. package/templates/catalog-manifest.json +0 -0
  182. package/templates/model-instructions/core.md +0 -0
  183. package/templates/model-instructions/release.md +0 -0
  184. package/templates/model-instructions/security.md +0 -0
  185. package/templates/quality/ai-quality-rules.yml +37 -0
  186. package/docs/assets/image/Screenshot(1).png +0 -0
  187. package/docs/assets/image/Screenshot(2).png +0 -0
  188. package/docs/assets/image/Screenshot(3).png +0 -0
  189. package/docs/assets/image/Screenshot(4).png +0 -0
  190. package/docs/assets/image/Screenshot(5).png +0 -0
  191. package/docs/assets/image/Screenshot(6).png +0 -0
  192. package/docs/assets/image/Screenshot(7).png +0 -0
  193. package/docs/assets/image/Screenshot(8).png +0 -0
  194. package/docs/assets/image/Screenshot(9).png +0 -0
  195. package/docs/assets/meta-architect-logo.png +0 -0
  196. package/docs/assets/meta-architect-logo.svg +0 -8
  197. package/docs/onboarding.md +0 -65
  198. package/docs/skills-publishing.md +0 -255
package/src/skills.js CHANGED
@@ -1,11 +1,29 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { appendDecision } from "./decision-log.js";
4
- import { readJson, writeFileIfMissing, writeJson } from "./fs-utils.js";
4
+ import { readJson, writeFileIfMissing, writeJson, writeTextAtomically } from "./fs-utils.js";
5
5
  import { validateMcpServers } from "./mcp-config.js";
6
- import { McpSseClient } from "./mcp-live-client.js";
6
+ import { createMcpLiveClient, hasConfiguredMcpRemoteBridge } from "./mcp-live-client.js";
7
7
  import { getRepoRoot, getRuntimeReadPath, getRuntimeWritePath, packageRoot } from "./paths.js";
8
+ import { resolveReleaseIssueGates, resolveReleaseReadiness } from "./release-issue-gates.js";
9
+ import {
10
+ evaluateAlignmentDrift,
11
+ saveAlignmentSentinelReport,
12
+ } from "./runtime/alignment-sentinel.js";
8
13
  import { evaluateRuntimeBuildReadiness } from "./runtime/build-readiness.js";
14
+ import {
15
+ findIngestedCoreSourceForRepo,
16
+ loadCoreSourceIngest,
17
+ } from "./runtime/core-source-ingest.js";
18
+ import { launchDetachedTrack } from "./runtime/detached-provider.js";
19
+ import {
20
+ scanLockfilePackageExposure,
21
+ validateMcpPolicyExposure,
22
+ } from "./runtime/exposure-catalog.js";
23
+ import { getMergedGuidancePath } from "./runtime/guidance-stack.js";
24
+ import { createHandoffPacket, writeHandoffPacket } from "./runtime/handoff-packets.js";
25
+ import { createHelperReceipt } from "./runtime/helper-orchestration-core.js";
26
+ import { appendMaestroEvent } from "./runtime/maestro-events.js";
9
27
  import {
10
28
  buildHelperFailureMatrix,
11
29
  chooseMaestroManagerAction,
@@ -14,12 +32,30 @@ import {
14
32
  loadManagerRunRegistry,
15
33
  saveManagerRunRegistry,
16
34
  } from "./runtime/maestro-manager.js";
35
+ import {
36
+ beginMaestroOrchestration,
37
+ loadMaestroStateOrDefault,
38
+ saveMaestroState,
39
+ } from "./runtime/maestro-state.js";
40
+ import { embedProjectContext } from "./runtime/obsidian-integration-core.js";
17
41
  import { submitTask } from "./runtime/orchestrator.js";
42
+ import { seedPreferences } from "./runtime/preferences.js";
43
+ import { refreshProjectIndex } from "./runtime/project-context.js";
44
+ import {
45
+ createQuorumReviewReceipt,
46
+ evaluateQuorumVotes,
47
+ quorumDecisions,
48
+ } from "./runtime/quorum-review.js";
49
+ import { writeRalphExecutionContract } from "./runtime/ralph-execution-core.js";
50
+ import { redactProviderBoundText, seedRedactionVault } from "./runtime/redaction-gateway.js";
18
51
  import {
19
52
  assertLeaderAuthority,
20
53
  createRuntimeSummary,
21
54
  loadRuntimeSnapshot,
55
+ repairRuntimeScratchpadArtifacts,
22
56
  } from "./runtime/runtime-state.js";
57
+ import { migrateSchemas } from "./runtime/schema-migrations.js";
58
+ import { createTaskContract, writeTaskContract } from "./runtime/task-contracts.js";
23
59
  import {
24
60
  seedRuntimeArtifacts,
25
61
  writeArchitectureArtifacts,
@@ -31,9 +67,29 @@ import {
31
67
  writeProjectContext,
32
68
  writeSecuritySpec,
33
69
  } from "./runtime-artifacts.js";
70
+ import {
71
+ assertNoSymlinkComponents,
72
+ assertSetupReceiptHealthy,
73
+ compactRuntimeState,
74
+ listManagedArtifacts,
75
+ withSetupLock,
76
+ writeSetupReceipt,
77
+ } from "./setup-lifecycle.js";
34
78
  import { syncStatusUpdates } from "./state-sync.js";
35
79
 
36
- const skillNames = ["$maestro", "$arch", "$sage", "$flow", "$vet", "$vibe", "$build"];
80
+ const skillNames = [
81
+ "$maestro",
82
+ "$arch",
83
+ "$sage",
84
+ "$flow",
85
+ "$vet",
86
+ "$vibe",
87
+ "$build",
88
+ "$align",
89
+ "$diagnose",
90
+ "$tdd",
91
+ "$cleanup",
92
+ ];
37
93
  const maestroWorkflowSequence = ["$arch", "$sage", "$flow", "$vet", "$vibe", "$build"];
38
94
  const workflowTemplates = {
39
95
  "maestro.skill.md":
@@ -181,6 +237,35 @@ function chooseMaestroRecommendation(releaseState, idea, buildReadiness = null)
181
237
  };
182
238
  }
183
239
 
240
+ if (releaseState.build_status === "READY") {
241
+ return {
242
+ nextStep: "Start the bounded build execution substep.",
243
+ why: "The build lane has prepared a narrow slice and verification plan, and the next safe move is to begin that bounded substep.",
244
+ primaryLane: "$build",
245
+ supportLane: "implementation",
246
+ assignments: [
247
+ "Run $build again to move the bounded build slice into active execution.",
248
+ "Keep the slice reversible and lane-owned.",
249
+ ],
250
+ avoid: ["Do not merge or release before the bounded build slice is complete."],
251
+ nextTrigger: "`$build`",
252
+ };
253
+ }
254
+
255
+ if (releaseState.build_status === "RUNNING") {
256
+ return {
257
+ nextStep: "Finalize the bounded build execution substep.",
258
+ why: "The build lane is already running its bounded slice and now needs completion evidence before downstream promotion.",
259
+ primaryLane: "$build",
260
+ supportLane: "verification",
261
+ assignments: [
262
+ "Run $build again to finalize the bounded build substep and persist completion evidence.",
263
+ ],
264
+ avoid: ["Do not merge or release before the build lane records DONE."],
265
+ nextTrigger: "`$build`",
266
+ };
267
+ }
268
+
184
269
  if (releaseState.merge_status !== "MERGED_TO_DEVELOPMENT") {
185
270
  return {
186
271
  nextStep: "Finish the implementation slice and merge it into development.",
@@ -255,7 +340,144 @@ function stripBackticks(value) {
255
340
  return value.replaceAll("`", "");
256
341
  }
257
342
 
258
- export async function runBuildLane({ actor = null } = {}) {
343
+ function isGitMcpDocumentationTool(tool, action) {
344
+ if (!tool || typeof tool.name !== "string") {
345
+ return false;
346
+ }
347
+ if (!tool.name.startsWith(`${action}_`)) {
348
+ return false;
349
+ }
350
+ if (tool.name === "fetch_generic_url_content") {
351
+ return false;
352
+ }
353
+
354
+ const lowerName = tool.name.toLowerCase();
355
+ return (
356
+ lowerName.includes("_documentation") ||
357
+ lowerName.includes("_docs") ||
358
+ `${tool.description ?? ""}`.toLowerCase().includes("documentation")
359
+ );
360
+ }
361
+
362
+ function createBoundedBuildSlice() {
363
+ return [
364
+ "Create or confirm the bounded implementation and verification slice for the current release-ready state.",
365
+ "Keep the slice reversible and owned by the $build lane.",
366
+ ];
367
+ }
368
+
369
+ function createBuildVerificationPlan(nextTrigger = "$build") {
370
+ return [
371
+ "Confirm release gates and runtime control-plane artifacts are still green.",
372
+ `Use ${nextTrigger} as the bounded verification loop trigger for the current build slice.`,
373
+ ];
374
+ }
375
+
376
+ function createBuildRepairPath() {
377
+ return [
378
+ "If the bounded build slice becomes invalid without upstream gate regression, return to READY and rerun `$build`.",
379
+ "If runtime or upstream gates regress, fail closed and repair those blockers before resuming.",
380
+ ];
381
+ }
382
+
383
+ async function updateMaestroLedgerForBuild({
384
+ buildStatus,
385
+ runtimeSummary,
386
+ blockers,
387
+ nextTriggers,
388
+ gateState,
389
+ trackStatus,
390
+ completionEvidence = [],
391
+ }) {
392
+ let maestroState = await loadMaestroStateOrDefault();
393
+ maestroState = beginMaestroOrchestration(maestroState, {
394
+ globalStatus: gateState,
395
+ });
396
+ maestroState.runtime_tracks.track_0_sync = {
397
+ active_gate: "$build",
398
+ status: trackStatus,
399
+ pid: null,
400
+ execution_pane: null,
401
+ exit_code: trackStatus === "COMPLETED" ? 0 : null,
402
+ blockers,
403
+ next_triggers: nextTriggers,
404
+ completion_evidence: completionEvidence,
405
+ build_status: buildStatus,
406
+ updated_at: new Date().toISOString(),
407
+ runtime_summary: {
408
+ pendingMailboxCount: runtimeSummary.pendingMailboxCount,
409
+ invalidArtifacts: runtimeSummary.invalidArtifacts,
410
+ missingArtifacts: runtimeSummary.missingArtifacts,
411
+ },
412
+ };
413
+ maestroState.downstream_lock_table.$build = {
414
+ is_locked: buildStatus !== "DONE",
415
+ locked_by: buildStatus === "DONE" ? [] : ["$build"],
416
+ unlock_criteria: "build_status == 'DONE'",
417
+ };
418
+ maestroState.timestamp = new Date().toISOString();
419
+ maestroState.global_status = gateState;
420
+ await saveMaestroState(maestroState);
421
+ await appendMaestroEvent({
422
+ record_type: "runtime:track_status",
423
+ gate: "$build",
424
+ global_status: gateState,
425
+ track_status: trackStatus,
426
+ build_status: buildStatus,
427
+ next_triggers: nextTriggers,
428
+ blockers,
429
+ });
430
+ await appendMaestroEvent({
431
+ record_type: "lock:downstream_circuit_breaker",
432
+ target_gate: "$build",
433
+ is_locked: buildStatus !== "DONE",
434
+ locked_by: buildStatus === "DONE" ? [] : ["$build"],
435
+ unlock_criteria: "build_status == 'DONE'",
436
+ });
437
+ }
438
+
439
+ async function updateScratchpadTrackForLane({
440
+ gate,
441
+ trackStatus,
442
+ globalStatus,
443
+ blockers = [],
444
+ nextTriggers = [],
445
+ detached = null,
446
+ details = {},
447
+ }) {
448
+ let maestroState = await loadMaestroStateOrDefault();
449
+ maestroState = beginMaestroOrchestration(maestroState, {
450
+ globalStatus,
451
+ });
452
+ const trackKey = `track_${gate.replaceAll("$", "")}_sync`;
453
+ maestroState.runtime_tracks[trackKey] = {
454
+ active_gate: gate,
455
+ status: trackStatus,
456
+ pid: null,
457
+ execution_pane: detached?.executionPane ?? null,
458
+ provider: detached?.provider ?? "none",
459
+ log_path: detached?.logPath ?? null,
460
+ exit_code: trackStatus === "COMPLETED" ? 0 : null,
461
+ blockers,
462
+ next_triggers: nextTriggers,
463
+ updated_at: new Date().toISOString(),
464
+ ...details,
465
+ };
466
+ maestroState.timestamp = new Date().toISOString();
467
+ maestroState.global_status = globalStatus;
468
+ await saveMaestroState(maestroState);
469
+ await appendMaestroEvent({
470
+ record_type: "runtime:track_status",
471
+ gate,
472
+ global_status: globalStatus,
473
+ track_status: trackStatus,
474
+ next_triggers: nextTriggers,
475
+ blockers,
476
+ provider: detached?.provider ?? "none",
477
+ });
478
+ }
479
+
480
+ export async function runBuildLane({ actor = null, reviewMode = null, quorumVotes = [] } = {}) {
259
481
  const authority = await assertLeaderAuthority(actor);
260
482
  const runtimeSnapshot = await loadRuntimeSnapshot();
261
483
  const runtimeSummary = createRuntimeSummary(runtimeSnapshot);
@@ -268,10 +490,22 @@ export async function runBuildLane({ actor = null } = {}) {
268
490
  if (!evaluation.allowed) {
269
491
  await writeBuildPlanArtifact({
270
492
  allowed: false,
493
+ gateState: "LOCKED",
271
494
  blockers: evaluation.blockers,
272
495
  nextTriggers: evaluation.nextTriggers,
496
+ buildSlice: createBoundedBuildSlice(),
497
+ verificationPlan: createBuildVerificationPlan("`$build`"),
498
+ repairPath: createBuildRepairPath(),
273
499
  runtimeSummary,
274
500
  });
501
+ await updateMaestroLedgerForBuild({
502
+ buildStatus: runtimeSnapshot.release.build_status,
503
+ runtimeSummary,
504
+ blockers: evaluation.blockers,
505
+ nextTriggers: evaluation.nextTriggers,
506
+ gateState: "LOCKED",
507
+ trackStatus: "BLOCKED",
508
+ });
275
509
  await appendDecision({
276
510
  actor: authority.leaderActor,
277
511
  kind: "skill",
@@ -290,30 +524,205 @@ export async function runBuildLane({ actor = null } = {}) {
290
524
  }
291
525
 
292
526
  const suggestedBranches = ["feature/implementation", "feature/verification"];
527
+ const buildSlice = createBoundedBuildSlice();
528
+ const verificationPlan = createBuildVerificationPlan("`$build`");
529
+ const repairPath = createBuildRepairPath();
530
+ const ralphContract = await writeRalphExecutionContract({
531
+ buildSlice,
532
+ verificationPlan,
533
+ runtimeSummary,
534
+ });
535
+
536
+ if (runtimeSnapshot.release.build_status === "LOCKED") {
537
+ await writeBuildPlanArtifact({
538
+ allowed: true,
539
+ gateState: "READY",
540
+ blockers: [],
541
+ nextTriggers: ["$build"],
542
+ suggestedBranches,
543
+ buildSlice,
544
+ verificationPlan,
545
+ repairPath,
546
+ runtimeSummary,
547
+ });
548
+ await appendDecision({
549
+ actor: authority.leaderActor,
550
+ kind: "skill",
551
+ skill: "$build",
552
+ decision: "Build gate ready",
553
+ status: "READY",
554
+ evidence: [
555
+ { kind: "runtime-summary", value: runtimeSummary },
556
+ { kind: "branches", value: suggestedBranches },
557
+ { kind: "build-slice", value: buildSlice },
558
+ { kind: "ralph-prd", value: ralphContract.prdPath },
559
+ ],
560
+ blockers: [],
561
+ next_allowed_triggers: ["$build"],
562
+ });
563
+ await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
564
+ await updateMaestroLedgerForBuild({
565
+ buildStatus: "READY",
566
+ runtimeSummary,
567
+ blockers: [],
568
+ nextTriggers: ["$build"],
569
+ gateState: "READY",
570
+ trackStatus: "READY",
571
+ });
572
+ return {
573
+ status: "READY",
574
+ nextTrigger: "$build",
575
+ blockers: [],
576
+ suggestedBranches,
577
+ };
578
+ }
579
+
580
+ if (runtimeSnapshot.release.build_status === "READY") {
581
+ await writeBuildPlanArtifact({
582
+ allowed: true,
583
+ gateState: "RUNNING",
584
+ blockers: [],
585
+ nextTriggers: ["$build"],
586
+ suggestedBranches,
587
+ buildSlice,
588
+ verificationPlan,
589
+ repairPath,
590
+ runtimeSummary,
591
+ });
592
+ await appendDecision({
593
+ actor: authority.leaderActor,
594
+ kind: "skill",
595
+ skill: "$build",
596
+ decision: "Started the bounded build execution substep",
597
+ status: "RUNNING",
598
+ evidence: [
599
+ { kind: "runtime-summary", value: runtimeSummary },
600
+ { kind: "build-slice", value: buildSlice },
601
+ { kind: "verification-plan", value: verificationPlan },
602
+ { kind: "ralph-prd", value: ralphContract.prdPath },
603
+ ],
604
+ blockers: [],
605
+ next_allowed_triggers: ["$build"],
606
+ });
607
+ await syncStatusUpdates({ build_status: "RUNNING" }, { actor: authority.leaderActor });
608
+ await updateMaestroLedgerForBuild({
609
+ buildStatus: "RUNNING",
610
+ runtimeSummary,
611
+ blockers: [],
612
+ nextTriggers: ["$build"],
613
+ gateState: "RUNNING",
614
+ trackStatus: "RUNNING",
615
+ });
616
+ return {
617
+ status: "RUNNING",
618
+ nextTrigger: "$build",
619
+ blockers: [],
620
+ suggestedBranches,
621
+ };
622
+ }
623
+
624
+ const completionEvidence = [
625
+ "Build slice remained release-ready through the bounded verification substep.",
626
+ "Runtime control-plane artifacts remained valid at completion.",
627
+ ];
628
+ if (reviewMode === "quorum") {
629
+ const quorum = evaluateQuorumVotes(quorumVotes);
630
+ const quorumReceipt = createQuorumReviewReceipt({ votes: quorumVotes, evaluation: quorum });
631
+ if (quorum.decision !== quorumDecisions.APPROVED) {
632
+ await writeBuildPlanArtifact({
633
+ allowed: true,
634
+ gateState: "READY",
635
+ blockers: quorum.blockers,
636
+ nextTriggers: ["$build"],
637
+ suggestedBranches,
638
+ buildSlice,
639
+ verificationPlan: [
640
+ ...verificationPlan,
641
+ "Resolve quorum disagreement or provide a compatible majority fingerprint before promotion.",
642
+ ],
643
+ repairPath,
644
+ runtimeSummary,
645
+ });
646
+ await appendDecision({
647
+ actor: authority.leaderActor,
648
+ kind: "skill",
649
+ skill: "$build",
650
+ decision: "Quorum review did not approve the current bounded build slice",
651
+ status: "READY",
652
+ evidence: [
653
+ { kind: "runtime-summary", value: runtimeSummary },
654
+ { kind: "quorum-votes", value: quorumVotes },
655
+ { kind: "quorum-decision", value: quorum },
656
+ { kind: "quorum-receipt", value: quorumReceipt },
657
+ { kind: "ralph-prd", value: ralphContract.prdPath },
658
+ ],
659
+ blockers: quorum.blockers,
660
+ next_allowed_triggers: ["$build"],
661
+ });
662
+ await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
663
+ await updateMaestroLedgerForBuild({
664
+ buildStatus: "READY",
665
+ runtimeSummary,
666
+ blockers: quorum.blockers,
667
+ nextTriggers: ["$build"],
668
+ gateState: "READY",
669
+ trackStatus: "BLOCKED",
670
+ completionEvidence: ["Quorum review returned INDETERMINATE or non-approval."],
671
+ });
672
+ return {
673
+ status: "READY",
674
+ nextTrigger: "$build",
675
+ blockers: quorum.blockers,
676
+ suggestedBranches,
677
+ };
678
+ }
679
+ completionEvidence.push(
680
+ "Quorum review approved the bounded build slice with a majority-compatible fingerprint.",
681
+ );
682
+ completionEvidence.push(
683
+ `Quorum confidence receipt recorded with ${quorumReceipt.reviewer_count} reviewers.`,
684
+ );
685
+ }
293
686
  await writeBuildPlanArtifact({
294
687
  allowed: true,
688
+ gateState: "DONE",
295
689
  blockers: [],
296
- nextTriggers: ["$build"],
690
+ nextTriggers: ["ma merge <feature/*> development"],
297
691
  suggestedBranches,
692
+ buildSlice,
693
+ verificationPlan,
694
+ repairPath,
695
+ completionEvidence,
298
696
  runtimeSummary,
299
697
  });
300
698
  await appendDecision({
301
699
  actor: authority.leaderActor,
302
700
  kind: "skill",
303
701
  skill: "$build",
304
- decision: "Build gate ready",
305
- status: "READY",
702
+ decision: "Completed the bounded build execution substep",
703
+ status: "DONE",
306
704
  evidence: [
307
705
  { kind: "runtime-summary", value: runtimeSummary },
308
706
  { kind: "branches", value: suggestedBranches },
707
+ { kind: "completion-evidence", value: completionEvidence },
708
+ { kind: "ralph-prd", value: ralphContract.prdPath },
309
709
  ],
310
710
  blockers: [],
311
- next_allowed_triggers: ["$build"],
711
+ next_allowed_triggers: ["ma merge <feature/*> development"],
712
+ });
713
+ await syncStatusUpdates({ build_status: "DONE" }, { actor: authority.leaderActor });
714
+ await updateMaestroLedgerForBuild({
715
+ buildStatus: "DONE",
716
+ runtimeSummary,
717
+ blockers: [],
718
+ nextTriggers: ["ma merge <feature/*> development"],
719
+ gateState: "COMPLETED",
720
+ trackStatus: "COMPLETED",
721
+ completionEvidence,
312
722
  });
313
- await syncStatusUpdates({ build_status: "READY" }, { actor: authority.leaderActor });
314
723
  return {
315
- status: "READY",
316
- nextTrigger: "$build",
724
+ status: "DONE",
725
+ nextTrigger: "ma merge <feature/*> development",
317
726
  blockers: [],
318
727
  suggestedBranches,
319
728
  };
@@ -396,10 +805,23 @@ function buildManagerDecisionBlockers(managerRun, runtimeSummary, buildReadiness
396
805
  }
397
806
 
398
807
  function executeManagerHelper(helper, { releaseState, runtimeSummary, recommendation }) {
808
+ const baseReceipt = ({ observedContext, result, nextTrigger }) => ({
809
+ helperId: helper.id,
810
+ ...createHelperReceipt({
811
+ skill: helper.skill,
812
+ objective: helper.objective,
813
+ observedContext,
814
+ result,
815
+ nextTrigger: nextTrigger ?? recommendation.nextTrigger ?? "$maestro",
816
+ }),
817
+ });
818
+
399
819
  if (helper.skill === "$align") {
400
820
  return {
401
- helperId: helper.id,
402
- kind: "alignment",
821
+ ...baseReceipt({
822
+ observedContext: `build_status=${releaseState.build_status}; next=${recommendation.nextTrigger}`,
823
+ result: "Normalized the manager handoff around the current lane sequence and next trigger.",
824
+ }),
403
825
  workflowSequence: maestroWorkflowSequence,
404
826
  currentBuildStatus: releaseState.build_status,
405
827
  recommendedNextTrigger: recommendation.nextTrigger,
@@ -408,8 +830,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
408
830
 
409
831
  if (helper.skill === "$diagnose") {
410
832
  return {
411
- helperId: helper.id,
412
- kind: "diagnostic",
833
+ ...baseReceipt({
834
+ observedContext: `pending_mailbox=${runtimeSummary.pendingMailboxCount}; invalid_artifacts=${runtimeSummary.invalidArtifacts.length}; missing_artifacts=${runtimeSummary.missingArtifacts.length}`,
835
+ result: "Captured the smallest blocker slices before the manager resumes gated work.",
836
+ }),
413
837
  pendingMailboxCount: runtimeSummary.pendingMailboxCount,
414
838
  invalidArtifacts: runtimeSummary.invalidArtifacts,
415
839
  missingArtifacts: runtimeSummary.missingArtifacts,
@@ -418,8 +842,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
418
842
 
419
843
  if (helper.skill === "$tdd") {
420
844
  return {
421
- helperId: helper.id,
422
- kind: "test-first",
845
+ ...baseReceipt({
846
+ observedContext: `build_status=${releaseState.build_status}; next=${recommendation.nextTrigger}`,
847
+ result: "Defined the regression-first boundary for the owning implementation lane.",
848
+ }),
423
849
  buildStatus: releaseState.build_status,
424
850
  nextTrigger: recommendation.nextTrigger,
425
851
  };
@@ -427,8 +853,10 @@ function executeManagerHelper(helper, { releaseState, runtimeSummary, recommenda
427
853
 
428
854
  if (helper.skill === "$cleanup") {
429
855
  return {
430
- helperId: helper.id,
431
- kind: "cleanup",
856
+ ...baseReceipt({
857
+ observedContext: `merge_status=${releaseState.merge_status}; release_status=${releaseState.release_status}`,
858
+ result: "Prepared contract-preserving simplification without changing release authority.",
859
+ }),
432
860
  mergeStatus: releaseState.merge_status,
433
861
  releaseStatus: releaseState.release_status,
434
862
  };
@@ -589,9 +1017,35 @@ export async function runArch() {
589
1017
  throw new Error("Cannot run $arch before ma idea captures a project brief");
590
1018
  }
591
1019
 
1020
+ const guidance = await readJson(getMergedGuidancePath()).catch(() => ({
1021
+ sources: [],
1022
+ content: "",
1023
+ }));
1024
+ const advisoryGuidance = guidance.sources
1025
+ .map((source) => `${source.label ?? source.id ?? "Guidance"}: ${source.content ?? ""}`)
1026
+ .filter(Boolean)
1027
+ .join(" ");
1028
+
592
1029
  const blueprint = {
593
- summary: `Blueprint derived from idea: ${idea}. Runtime shell currently exposes ${runtimeSummary.workerCount} workers, ${runtimeSummary.workspaceCount} workspaces, and ${runtimeSummary.guidanceSourceCount} guidance sources.`,
1030
+ decision: "Approve the first bounded architecture direction.",
1031
+ status: "APPROVED",
1032
+ summary: `Blueprint derived from idea: ${idea}. Runtime shell currently exposes ${runtimeSummary.workerCount} workers, ${runtimeSummary.workspaceCount} workspaces, and ${runtimeSummary.guidanceSourceCount} guidance sources. Advisory guidance: ${advisoryGuidance}`,
594
1033
  suggestedStack: ["Node.js", "MCP", "GitMCP", "Git worktree", "File-backed runtime state"],
1034
+ workloadAssumptions: [
1035
+ "single-repo operator workflow",
1036
+ "gate-driven release discipline",
1037
+ "file-backed runtime state",
1038
+ ],
1039
+ rejectedAlternatives: [
1040
+ "Standalone second umbrella runtime surface because it would weaken Meta-Architect ownership.",
1041
+ ],
1042
+ evidence: [
1043
+ `Workers detected: ${runtimeSummary.workerCount}`,
1044
+ `Workspaces detected: ${runtimeSummary.workspaceCount}`,
1045
+ `Guidance sources detected: ${runtimeSummary.guidanceSourceCount}`,
1046
+ ],
1047
+ blockers: [],
1048
+ nextAllowedTriggers: ["`$sage`"],
595
1049
  outcome: "Produce a gated architecture and implementation plan backed by runtime state.",
596
1050
  };
597
1051
 
@@ -608,6 +1062,16 @@ export async function runArch() {
608
1062
  });
609
1063
 
610
1064
  await syncStatusUpdates({ architecture_status: "APPROVED" });
1065
+ await updateScratchpadTrackForLane({
1066
+ gate: "$arch",
1067
+ trackStatus: "COMPLETED",
1068
+ globalStatus: "COMPLETED",
1069
+ nextTriggers: ["$sage"],
1070
+ details: {
1071
+ decision: blueprint.decision,
1072
+ rejected_alternatives: blueprint.rejectedAlternatives,
1073
+ },
1074
+ });
611
1075
  }
612
1076
 
613
1077
  export async function runSage() {
@@ -615,17 +1079,49 @@ export async function runSage() {
615
1079
  const config = await validateMcpServers();
616
1080
  const runtimeSummary = await readRuntimeSummary();
617
1081
  assertControlPlaneReady(runtimeSummary);
1082
+ await seedRedactionVault();
1083
+ await seedPreferences();
1084
+ const disableLiveProbe = process.env.MA_DISABLE_LIVE_MCP === "1";
618
1085
  const sourceEntries = config.servers.map((server) => ({
619
1086
  repo: server.repo,
620
1087
  endpoint: server.endpoint,
621
1088
  category: server.category,
1089
+ exactUpstreamMapping: server.repo,
1090
+ evidenceGrade: disableLiveProbe ? "PARTIAL" : "MISSING",
622
1091
  }));
623
1092
  const blockers = [];
624
1093
  const idea = (await readIdeaText()) ?? "software architecture";
625
- const disableLiveProbe = process.env.MA_DISABLE_LIVE_MCP === "1";
626
- let liveSuccessCount = 0;
1094
+ let verificationSuccessCount = 0;
1095
+ let coreSourceIngest = null;
1096
+ try {
1097
+ coreSourceIngest = await loadCoreSourceIngest();
1098
+ } catch {
1099
+ coreSourceIngest = null;
1100
+ }
627
1101
 
628
1102
  for (const source of sourceEntries) {
1103
+ const ingestedSource = findIngestedCoreSourceForRepo(coreSourceIngest, source.repo);
1104
+ if (ingestedSource) {
1105
+ source.localSourceSnapshot = {
1106
+ status: ingestedSource.status,
1107
+ localPath: ingestedSource.local_path,
1108
+ capability: ingestedSource.capability,
1109
+ semanticRole: ingestedSource.semantic_role,
1110
+ fileCount: ingestedSource.file_count,
1111
+ contentSha256: ingestedSource.content_sha256,
1112
+ gitCommit: ingestedSource.git_commit,
1113
+ sampledFiles: ingestedSource.sampled_files,
1114
+ };
1115
+ source.liveProbe = {
1116
+ transport: "local-core-source-ingest",
1117
+ queryMode: "local-snapshot",
1118
+ sampleText: ingestedSource.sample_text?.slice(0, 400) ?? null,
1119
+ };
1120
+ source.evidenceGrade = "VERIFIED";
1121
+ verificationSuccessCount += 1;
1122
+ continue;
1123
+ }
1124
+
629
1125
  if (disableLiveProbe) {
630
1126
  source.liveProbe = {
631
1127
  skipped: true,
@@ -634,43 +1130,76 @@ export async function runSage() {
634
1130
  continue;
635
1131
  }
636
1132
 
637
- const client = new McpSseClient(source.endpoint);
1133
+ const client = createMcpLiveClient(source.endpoint);
638
1134
  try {
639
1135
  const init = await client.connect();
640
1136
  const tools = await client.request("tools/list", {});
641
- const searchTool = tools.tools?.find(
642
- (tool) => tool.name.includes("search_") && tool.name.endsWith("_documentation"),
643
- );
644
- const fetchTool = tools.tools?.find(
645
- (tool) => tool.name.includes("fetch_") && tool.name.endsWith("_documentation"),
646
- );
1137
+ const searchTool = tools.tools?.find((tool) => isGitMcpDocumentationTool(tool, "search"));
1138
+ const fetchTool = tools.tools?.find((tool) => isGitMcpDocumentationTool(tool, "fetch"));
647
1139
 
648
1140
  let evidence = null;
649
- if (searchTool) {
650
- evidence = await client.request("tools/call", {
651
- name: searchTool.name,
652
- arguments: { query: idea },
653
- });
654
- } else if (fetchTool) {
655
- evidence = await client.request("tools/call", {
656
- name: fetchTool.name,
657
- arguments: {},
1141
+ let queryMode = "list-only";
1142
+ const callFailures = [];
1143
+ if (fetchTool) {
1144
+ try {
1145
+ evidence = await client.request("tools/call", {
1146
+ name: fetchTool.name,
1147
+ arguments: {},
1148
+ });
1149
+ queryMode = "fetch";
1150
+ } catch (error) {
1151
+ callFailures.push({
1152
+ tool: fetchTool.name,
1153
+ error: error.message,
1154
+ });
1155
+ }
1156
+ }
1157
+ if (!evidence && searchTool) {
1158
+ const redactedQuery = await redactProviderBoundText(idea, {
1159
+ kind: "sage-live-query",
1160
+ repo: source.repo,
658
1161
  });
1162
+ try {
1163
+ evidence = await client.request("tools/call", {
1164
+ name: searchTool.name,
1165
+ arguments: { query: redactedQuery.sanitizedText },
1166
+ });
1167
+ queryMode = "search";
1168
+ } catch (error) {
1169
+ callFailures.push({
1170
+ tool: searchTool.name,
1171
+ error: error.message,
1172
+ });
1173
+ }
1174
+ }
1175
+ if ((fetchTool || searchTool) && !evidence) {
1176
+ throw new Error(
1177
+ `No GitMCP documentation call succeeded: ${callFailures
1178
+ .map((failure) => `${failure.tool}: ${failure.error}`)
1179
+ .join("; ")}`,
1180
+ );
659
1181
  }
660
1182
 
661
1183
  source.liveProbe = {
1184
+ transport: hasConfiguredMcpRemoteBridge() ? "stdio-bridge" : "direct-sse",
662
1185
  serverName: init.serverInfo?.name ?? "unknown",
663
1186
  serverVersion: init.serverInfo?.version ?? "unknown",
664
1187
  toolsCount: tools.tools?.length ?? 0,
665
- queryMode: searchTool ? "search" : fetchTool ? "fetch" : "list-only",
1188
+ queryMode,
1189
+ callFailures,
666
1190
  sampleText:
667
1191
  evidence?.content?.find((item) => item.type === "text")?.text?.slice(0, 400) ?? null,
668
1192
  };
669
- liveSuccessCount += 1;
1193
+ source.evidenceGrade = "VERIFIED";
1194
+ source.exactUpstreamMapping = source.repo;
1195
+ verificationSuccessCount += 1;
670
1196
  } catch (error) {
671
1197
  source.liveProbe = {
1198
+ transport: hasConfiguredMcpRemoteBridge() ? "stdio-bridge" : "direct-sse",
672
1199
  error: error.message,
673
1200
  };
1201
+ source.evidenceGrade = "PARTIAL";
1202
+ source.exactUpstreamMapping = source.repo;
674
1203
  blockers.push(`Live MCP query failed for ${source.repo}: ${error.message}`);
675
1204
  } finally {
676
1205
  await client.close().catch(() => {});
@@ -681,8 +1210,7 @@ export async function runSage() {
681
1210
  existing.items = sourceEntries;
682
1211
  await writeJson(getRuntimeWritePath("evidence", "sources.json"), existing);
683
1212
 
684
- const verified =
685
- sourceEntries.length > 0 && !disableLiveProbe && liveSuccessCount === sourceEntries.length;
1213
+ const verified = sourceEntries.length > 0 && verificationSuccessCount === sourceEntries.length;
686
1214
  if (sourceEntries.length > 0 && !verified && blockers.length === 0) {
687
1215
  blockers.push(
688
1216
  disableLiveProbe
@@ -694,7 +1222,8 @@ export async function runSage() {
694
1222
  await appendDecision({
695
1223
  kind: "skill",
696
1224
  skill: "$sage",
697
- decision: "Bound architectural choices to approved GitMCP sources using live MCP queries",
1225
+ decision:
1226
+ "Bound architectural choices to approved sources using local core-source snapshots first, with GitMCP only as refresh/provenance fallback",
698
1227
  status: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
699
1228
  evidence: sourceEntries,
700
1229
  blockers: sourceEntries.length > 0 ? blockers : ["No approved GitMCP sources configured"],
@@ -704,6 +1233,17 @@ export async function runSage() {
704
1233
  await syncStatusUpdates({
705
1234
  evidence_status: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
706
1235
  });
1236
+ await updateScratchpadTrackForLane({
1237
+ gate: "$sage",
1238
+ trackStatus: verified ? "COMPLETED" : "BLOCKED",
1239
+ globalStatus: verified ? "COMPLETED" : "LOCKED",
1240
+ blockers: sourceEntries.length > 0 ? blockers : ["No approved GitMCP sources configured"],
1241
+ nextTriggers: verified ? ["$flow"] : ["$sage"],
1242
+ details: {
1243
+ evidence_grade: verified ? "VERIFIED" : sourceEntries.length > 0 ? "PARTIAL" : "MISSING",
1244
+ exact_upstream_mapping: sourceEntries.map((source) => source.repo),
1245
+ },
1246
+ });
707
1247
  }
708
1248
 
709
1249
  export async function runFlow() {
@@ -729,12 +1269,32 @@ export async function runFlow() {
729
1269
  if (runtimeSummary.workerCount > 0 && runtimeSummary.workspaceCount === 0) {
730
1270
  blockers.push("Workers exist without registered workspaces.");
731
1271
  }
1272
+ const actors = ["leader", "worker", "guidance_stack", "hook_dispatcher", "workspace_manager"];
732
1273
  const logicMap = {
733
- actors: ["leader", "worker", "guidance_stack", "hook_dispatcher", "workspace_manager"],
1274
+ actors,
1275
+ decision:
1276
+ blockers.length === 0
1277
+ ? "Approve the current behavioral model for downstream review."
1278
+ : "Behavioral model remains blocked until the identified logic/runtime issues are resolved.",
1279
+ status: blockers.length === 0 ? "GREEN" : "RED",
734
1280
  states: ["idea", "architecture", "evidence", "logic", "security", "experience", "build"],
1281
+ stateMap: [
1282
+ "idea -> architecture -> evidence -> logic -> security -> experience -> build",
1283
+ "logic review must stop if runtime artifacts are invalid or worker/workspace integrity breaks",
1284
+ ],
1285
+ failureFlows:
1286
+ blockers.length > 0
1287
+ ? blockers
1288
+ : ["No blocking failure flow detected in the current runtime snapshot."],
1289
+ evidence: [
1290
+ `actors observed: ${actors.length}`,
1291
+ `pending mailbox proposals: ${runtimeSummary.pendingMailboxCount}`,
1292
+ `registered workspaces: ${runtimeSummary.workspaceCount}`,
1293
+ ],
735
1294
  runtimeSummary,
736
1295
  blockers,
737
1296
  nextTrigger: blockers.length === 0 ? "`$vet`" : "`$flow`",
1297
+ nextAllowedTriggers: blockers.length === 0 ? ["`$vet`"] : ["`$flow`"],
738
1298
  };
739
1299
  const status = blockers.length === 0 ? "GREEN" : "RED";
740
1300
  const nextAllowedTriggers = blockers.length === 0 ? ["$vet"] : ["$flow"];
@@ -752,6 +1312,18 @@ export async function runFlow() {
752
1312
  });
753
1313
 
754
1314
  await syncStatusUpdates({ logic_status: status });
1315
+ await updateScratchpadTrackForLane({
1316
+ gate: "$flow",
1317
+ trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
1318
+ globalStatus: status === "GREEN" ? "COMPLETED" : "LOCKED",
1319
+ blockers,
1320
+ nextTriggers: nextAllowedTriggers,
1321
+ details: {
1322
+ failure_flows: logicMap.failureFlows,
1323
+ state_map: logicMap.stateMap,
1324
+ hardening_mode: runtimeSummary.pendingMailboxCount > 0 ? "STRICT" : "STANDARD",
1325
+ },
1326
+ });
755
1327
  }
756
1328
 
757
1329
  export async function runVet() {
@@ -760,36 +1332,103 @@ export async function runVet() {
760
1332
  assertControlPlaneReady(runtimeSummary);
761
1333
  const auditLog = await readJson(getRuntimeWritePath("evidence", "audits.json"));
762
1334
  const cveLog = await readJson(getRuntimeWritePath("evidence", "cves.json"));
1335
+ const packageExposureFindings = await scanLockfilePackageExposure();
1336
+ const policyFindings = await validateMcpPolicyExposure();
1337
+ const criticalPackageExposure = packageExposureFindings.filter(
1338
+ (finding) => finding.severity === "critical",
1339
+ );
1340
+ const blockingPolicyFindings = policyFindings.filter((finding) =>
1341
+ ["critical", "high"].includes(`${finding.severity}`.toLowerCase()),
1342
+ );
763
1343
  const reviewApproved =
764
1344
  auditLog.items.some((item) => item.source === "review" || item.approved === true) ||
765
1345
  cveLog.items.some((item) => item.source === "review" || item.approved === true);
766
- const finding = {
767
- severity: "INFO",
768
- source: "placeholder",
769
- summary: `Placeholder security review recorded; explicit security approval is still required after reviewing ${runtimeSummary.compatibilityHookCount} compatibility hooks and ${runtimeSummary.runtimeHookCount} runtime events.`,
770
- unresolved: true,
771
- };
772
- auditLog.items.push(finding);
1346
+ const scanApproved = criticalPackageExposure.length === 0 && blockingPolicyFindings.length === 0;
1347
+ const finding =
1348
+ criticalPackageExposure.length > 0
1349
+ ? {
1350
+ severity: criticalPackageExposure[0].severity.toUpperCase(),
1351
+ source: "package-exposure-scan",
1352
+ summary: criticalPackageExposure
1353
+ .map(
1354
+ (item) =>
1355
+ `${item.package_name}@${item.package_version}: ${item.diagnostic} (${item.advisory_reference})`,
1356
+ )
1357
+ .join(" "),
1358
+ unresolved: true,
1359
+ trustBoundaries: [
1360
+ "lockfile metadata vs provider-bound or build-unlocking execution",
1361
+ "repo-owned MCP config vs runtime-local scratchpad state",
1362
+ "published docs vs private `.ma` execution state",
1363
+ ],
1364
+ acceptedRisks: ["No accepted risk: blocking package exposure must be remediated."],
1365
+ }
1366
+ : {
1367
+ severity: policyFindings.length > 0 ? "WARNING" : "INFO",
1368
+ source: policyFindings.length > 0 ? "mcp-policy-validation" : "runtime-review",
1369
+ summary:
1370
+ policyFindings.length > 0
1371
+ ? policyFindings.map((item) => item.diagnostic).join(" ")
1372
+ : `No blocking package exposure was detected in the current bounded scan. Review still remains required after checking ${runtimeSummary.compatibilityHookCount} compatibility hooks and ${runtimeSummary.runtimeHookCount} runtime events.`,
1373
+ unresolved: !reviewApproved && !scanApproved,
1374
+ trustBoundaries: [
1375
+ "leader vs worker mutation authority",
1376
+ "repo-owned MCP config vs runtime-local scratchpad state",
1377
+ "published docs vs private `.ma` execution state",
1378
+ ],
1379
+ acceptedRisks: scanApproved
1380
+ ? ["No material unresolved risk remains for the current bounded step."]
1381
+ : [
1382
+ "Security evidence still requires explicit approval or remediation before promotion.",
1383
+ ],
1384
+ };
1385
+ auditLog.items.push(finding, ...packageExposureFindings, ...policyFindings);
773
1386
  await writeJson(getRuntimeWritePath("evidence", "audits.json"), auditLog);
774
- cveLog.items.push({
775
- id: "baseline-review",
776
- source: "placeholder",
777
- severity: "INFO",
778
- unresolved: true,
779
- });
1387
+ cveLog.items.push(
1388
+ ...packageExposureFindings.map((item) => ({
1389
+ id: item.advisory_reference ?? `${item.package_name}-${item.package_version}`,
1390
+ source: "package-exposure-scan",
1391
+ severity: item.severity.toUpperCase(),
1392
+ unresolved: true,
1393
+ package_name: item.package_name,
1394
+ package_version: item.package_version,
1395
+ })),
1396
+ {
1397
+ id: "baseline-review",
1398
+ source: packageExposureFindings.length > 0 ? "package-exposure-scan" : "runtime-review",
1399
+ severity: packageExposureFindings.length > 0 ? "CRITICAL" : "INFO",
1400
+ unresolved: !reviewApproved && !scanApproved,
1401
+ },
1402
+ );
780
1403
  await writeJson(getRuntimeWritePath("evidence", "cves.json"), cveLog);
1404
+ for (const exposureFinding of packageExposureFindings) {
1405
+ await appendMaestroEvent(exposureFinding);
1406
+ }
1407
+ for (const policyFinding of policyFindings) {
1408
+ await appendMaestroEvent(policyFinding);
1409
+ }
781
1410
  await writeSecuritySpec({
782
1411
  finding,
783
1412
  auditCount: auditLog.items.length,
784
1413
  cveCount: cveLog.items.length,
785
1414
  runtimeSummary,
786
- nextTrigger: reviewApproved ? "`$vibe`" : "`$vet`",
1415
+ nextTrigger: scanApproved ? "`$vibe`" : "`$vet`",
787
1416
  });
788
- const status = reviewApproved ? "GREEN" : "PENDING";
789
- const blockers = reviewApproved
790
- ? []
791
- : ["Security review evidence has not been explicitly approved yet."];
792
- const nextAllowedTriggers = reviewApproved ? ["$vibe"] : ["$vet"];
1417
+ const status = scanApproved ? "GREEN" : criticalPackageExposure.length > 0 ? "RED" : "PENDING";
1418
+ const blockers =
1419
+ criticalPackageExposure.length > 0
1420
+ ? criticalPackageExposure.map(
1421
+ (item) =>
1422
+ `${item.package_name}@${item.package_version}: ${item.diagnostic} (${item.advisory_reference})`,
1423
+ )
1424
+ : reviewApproved
1425
+ ? []
1426
+ : blockingPolicyFindings.map((finding) => finding.diagnostic);
1427
+ const nextAllowedTriggers = scanApproved
1428
+ ? ["$vibe"]
1429
+ : criticalPackageExposure.length > 0
1430
+ ? ["$vet"]
1431
+ : ["$vet"];
793
1432
 
794
1433
  await appendDecision({
795
1434
  kind: "skill",
@@ -802,6 +1441,25 @@ export async function runVet() {
802
1441
  });
803
1442
 
804
1443
  await syncStatusUpdates({ security_status: status });
1444
+ await updateScratchpadTrackForLane({
1445
+ gate: "$vet",
1446
+ trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
1447
+ globalStatus:
1448
+ status === "GREEN" ? "COMPLETED" : status === "RED" ? "LOCKED" : "DEGRADED_HEALING",
1449
+ blockers,
1450
+ nextTriggers: nextAllowedTriggers,
1451
+ details: {
1452
+ trust_boundaries: finding.trustBoundaries,
1453
+ accepted_risks: finding.acceptedRisks,
1454
+ healing_ledger: reviewApproved
1455
+ ? null
1456
+ : {
1457
+ current_attempt: 0,
1458
+ strategy_assigned: "BOUNDED_DIAGNOSTIC_REVIEW",
1459
+ status: "PENDING_OPERATOR_APPROVAL",
1460
+ },
1461
+ },
1462
+ });
805
1463
  }
806
1464
 
807
1465
  export async function runVibe() {
@@ -810,25 +1468,66 @@ export async function runVibe() {
810
1468
  assertControlPlaneReady(runtimeSummary);
811
1469
  const outcomes = await readJson(getRuntimeWritePath("evidence", "outcomes.json"));
812
1470
  const reviewApproved = outcomes.items.some(
813
- (item) => item.source === "review" || item.approved === true,
1471
+ (item) =>
1472
+ ["review", "vibe-review", "dx-ux-review"].includes(item.source) && item.approved === true,
814
1473
  );
1474
+ const automatedReviewChecks = [
1475
+ {
1476
+ name: "no_pending_mailbox_proposals",
1477
+ passed: runtimeSummary.pendingMailboxCount === 0,
1478
+ evidence: `${runtimeSummary.pendingMailboxCount} pending mailbox proposals`,
1479
+ },
1480
+ {
1481
+ name: "runtime_artifacts_valid",
1482
+ passed: runtimeSummary.invalidArtifacts.length === 0,
1483
+ evidence: `${runtimeSummary.invalidArtifacts.length} invalid runtime artifacts`,
1484
+ },
1485
+ {
1486
+ name: "runtime_artifacts_present",
1487
+ passed: runtimeSummary.missingArtifacts.length === 0,
1488
+ evidence: `${runtimeSummary.missingArtifacts.length} missing runtime artifacts`,
1489
+ },
1490
+ {
1491
+ name: "workspace_context_available",
1492
+ passed: runtimeSummary.workspaceCount > 0,
1493
+ evidence: `${runtimeSummary.workspaceCount} workspace context entries`,
1494
+ },
1495
+ ];
1496
+ const runtimeApproved = automatedReviewChecks.every((check) => check.passed);
1497
+ const failedAutomatedReviewChecks = automatedReviewChecks
1498
+ .filter((check) => !check.passed)
1499
+ .map((check) => `${check.name}: ${check.evidence}`);
815
1500
  const note = {
816
1501
  area: "developer-experience",
817
- source: "placeholder",
818
- summary: `Placeholder DX/UX review recorded; explicit workflow approval is still required while the runtime tracks ${runtimeSummary.taskCount} tasks and ${runtimeSummary.workspaceCount} workspaces.`,
1502
+ source: "runtime-vibe-review",
1503
+ summary: `Runtime DX/UX review recorded from current coordination state: ${runtimeSummary.taskCount} tasks, ${runtimeSummary.workspaceCount} workspaces, and ${runtimeSummary.pendingMailboxCount} pending mailbox proposals.`,
1504
+ automatedReviewChecks,
1505
+ operatorFriction: [
1506
+ runtimeSummary.pendingMailboxCount > 0
1507
+ ? "Pending mailbox proposals increase operator coordination overhead."
1508
+ : "Operator flow is bounded and clear in the current runtime state.",
1509
+ ],
1510
+ userFriction: [
1511
+ "The gated sequence is explicit, but users still need clearer build-loop feedback once execution starts.",
1512
+ ],
1513
+ approved: reviewApproved || runtimeApproved,
819
1514
  };
820
1515
  outcomes.items.push(note);
821
1516
  await writeJson(getRuntimeWritePath("evidence", "outcomes.json"), outcomes);
822
- const status = reviewApproved ? "GREEN" : "PENDING";
823
- const blockers = reviewApproved
824
- ? []
825
- : ["DX/UX review evidence has not been explicitly approved yet."];
826
- const nextAllowedTriggers = reviewApproved ? ["$build"] : ["$vibe"];
1517
+ const status = reviewApproved || runtimeApproved ? "GREEN" : "PENDING";
1518
+ const blockers =
1519
+ status === "GREEN"
1520
+ ? []
1521
+ : [
1522
+ "Automated DX/UX review must pass all runtime evidence checks or receive explicit review approval.",
1523
+ ...failedAutomatedReviewChecks,
1524
+ ];
1525
+ const nextAllowedTriggers = status === "GREEN" ? ["$build"] : ["$vibe"];
827
1526
  await writeExperienceSpec({
828
1527
  note,
829
1528
  outcomeCount: outcomes.items.length,
830
1529
  runtimeSummary,
831
- nextTrigger: reviewApproved ? "`$build`" : "`$vibe`",
1530
+ nextTrigger: status === "GREEN" ? "`$build`" : "`$vibe`",
832
1531
  });
833
1532
 
834
1533
  await appendDecision({
@@ -842,10 +1541,65 @@ export async function runVibe() {
842
1541
  });
843
1542
 
844
1543
  await syncStatusUpdates({ experience_status: status });
1544
+ await updateScratchpadTrackForLane({
1545
+ gate: "$vibe",
1546
+ trackStatus: status === "GREEN" ? "COMPLETED" : "BLOCKED",
1547
+ globalStatus: status === "GREEN" ? "COMPLETED" : "LOCKED",
1548
+ blockers,
1549
+ nextTriggers: nextAllowedTriggers,
1550
+ details: {
1551
+ operator_friction: note.operatorFriction,
1552
+ user_friction: note.userFriction,
1553
+ },
1554
+ });
845
1555
  }
846
1556
 
847
- export async function runMaestro() {
1557
+ export async function runMaestro({
1558
+ autoHeal = false,
1559
+ parallel = false,
1560
+ taskContract = {},
1561
+ handoff = {},
1562
+ } = {}) {
848
1563
  await assertLeaderAuthority();
1564
+ const intakeContract = createTaskContract({
1565
+ goal: taskContract.goal ?? "Execute the next eligible Meta-Architect workflow step",
1566
+ contextUsed: taskContract.contextUsed ?? [
1567
+ ".ma/context/project-index.json",
1568
+ ".ma/context/agent-brief.md",
1569
+ ],
1570
+ assumptions: taskContract.assumptions ?? [
1571
+ "Source files and fresh verification output outrank generated context",
1572
+ ],
1573
+ constraints: taskContract.constraints ?? [
1574
+ "Do not mutate release state outside the owning lane",
1575
+ ],
1576
+ risk: taskContract.risk ?? "medium",
1577
+ verification: taskContract.verification ?? ["ma doctor", "focused tests"],
1578
+ stopCondition:
1579
+ taskContract.stopCondition ??
1580
+ "Stop when the selected lane is complete, blocked, or requires review",
1581
+ persist: taskContract.persist !== false,
1582
+ });
1583
+ if (intakeContract.persist) {
1584
+ await writeTaskContract(`maestro-${Date.now()}`, intakeContract);
1585
+ }
1586
+ if (handoff.persist !== false) {
1587
+ await writeHandoffPacket(
1588
+ `maestro-${Date.now()}`,
1589
+ createHandoffPacket({
1590
+ goal: intakeContract.goal,
1591
+ currentState: "Manager intake accepted",
1592
+ contextUsed: intakeContract.context_used,
1593
+ decisions: handoff.decisions ?? [],
1594
+ blockers: handoff.blockers ?? [],
1595
+ risks: handoff.risks ?? [],
1596
+ changedFiles: handoff.changedFiles ?? [],
1597
+ verification: intakeContract.verification,
1598
+ nextAction: handoff.nextAction ?? "Continue the selected bounded workflow lane",
1599
+ status: handoff.status ?? "active",
1600
+ }),
1601
+ );
1602
+ }
849
1603
  let runtimeSnapshot = await loadRuntimeSnapshot();
850
1604
  let releaseState = runtimeSnapshot.release;
851
1605
  let runtimeSummary = createRuntimeSummary(runtimeSnapshot);
@@ -854,6 +1608,133 @@ export async function runMaestro() {
854
1608
  let buildReadiness = evaluateRuntimeBuildReadiness(releaseState, runtimeSummary);
855
1609
  let recommendation = chooseMaestroRecommendation(releaseState, idea, buildReadiness);
856
1610
  const helperFailureMatrix = buildHelperFailureMatrix();
1611
+ const alignmentReport = {
1612
+ ...evaluateAlignmentDrift({
1613
+ releaseState,
1614
+ decisionLog: runtimeSnapshot.decisions,
1615
+ }),
1616
+ lastRunAt: new Date().toISOString(),
1617
+ baselineArtifacts: [
1618
+ ".ma/release.json",
1619
+ ".ma/decisions.json",
1620
+ ".ma/state/manager-runs.json",
1621
+ ".ma/state/maestro-state.json",
1622
+ ],
1623
+ };
1624
+ await saveAlignmentSentinelReport(alignmentReport);
1625
+ if (alignmentReport.driftStatus === "DRIFTED") {
1626
+ await updateScratchpadTrackForLane({
1627
+ gate: "$maestro",
1628
+ trackStatus: "BLOCKED",
1629
+ globalStatus: "LOCKED",
1630
+ blockers: alignmentReport.findings.map(
1631
+ (finding) =>
1632
+ `${finding.skill} expects ${finding.releaseField} to remain in ${finding.expectedReleaseValues.join(" or ")}, but the current value is ${finding.actualReleaseValue}.`,
1633
+ ),
1634
+ nextTriggers: ["$maestro"],
1635
+ details: {
1636
+ drift_status: alignmentReport.driftStatus,
1637
+ reboot_planned: alignmentReport.rebootPlanned,
1638
+ resume_trigger: alignmentReport.resumeTrigger,
1639
+ },
1640
+ });
1641
+ await appendMaestroEvent({
1642
+ record_type: "alignment:drift_detected",
1643
+ gate: "$maestro",
1644
+ findings: alignmentReport.findings,
1645
+ reboot_planned: alignmentReport.rebootPlanned,
1646
+ resume_trigger: alignmentReport.resumeTrigger,
1647
+ });
1648
+ const driftRecommendation = {
1649
+ nextStep: "Resolve alignment drift before manager dispatch continues.",
1650
+ why: alignmentReport.rebootReason,
1651
+ primaryLane: "$maestro",
1652
+ supportLane: "none",
1653
+ assignments: [
1654
+ "Review the persisted alignment report and conflicting lane-owned decisions.",
1655
+ "Rehydrate the next manager run from baseline `.ma/` artifacts after the conflicting state is repaired.",
1656
+ ],
1657
+ avoid: [
1658
+ "Do not continue autonomous dispatch while release state contradicts approved lane decisions.",
1659
+ ],
1660
+ nextTrigger: "`$maestro`",
1661
+ };
1662
+ await writeMaestroPlan({
1663
+ releaseState,
1664
+ recommendation: driftRecommendation,
1665
+ runtimeSummary,
1666
+ workflowSequence: maestroWorkflowSequence,
1667
+ managerRun: null,
1668
+ });
1669
+ await appendDecision({
1670
+ kind: "skill",
1671
+ skill: "$maestro",
1672
+ decision:
1673
+ "Alignment Sentinel blocked manager execution and requested a fresh worker rehydration path.",
1674
+ status: "BLOCKED",
1675
+ evidence: [alignmentReport],
1676
+ blockers: alignmentReport.findings.map(
1677
+ (finding) =>
1678
+ `${finding.skill} approved ${finding.expectedDecisionStatus}, but ${finding.releaseField} regressed to ${finding.actualReleaseValue}.`,
1679
+ ),
1680
+ next_allowed_triggers: ["$maestro"],
1681
+ });
1682
+ return;
1683
+ }
1684
+ if (
1685
+ autoHeal &&
1686
+ buildReadiness.releaseBlockers.length === 0 &&
1687
+ buildReadiness.nextTriggers.includes("repair runtime artifacts")
1688
+ ) {
1689
+ const repairedArtifacts = await repairRuntimeScratchpadArtifacts([
1690
+ ...runtimeSummary.invalidArtifacts,
1691
+ ...runtimeSummary.missingArtifacts,
1692
+ ]);
1693
+ if (repairedArtifacts.length > 0) {
1694
+ const detached = await launchDetachedTrack({
1695
+ trackId: "heal-sync",
1696
+ title: "Meta-Architect bounded diagnostic sidecar",
1697
+ command: "/bin/sh",
1698
+ args: [
1699
+ "-lc",
1700
+ `printf '%s\n' "Repaired scratchpad artifacts: ${repairedArtifacts.join(", ")}"`,
1701
+ ],
1702
+ });
1703
+ let maestroState = await loadMaestroStateOrDefault();
1704
+ maestroState = beginMaestroOrchestration(maestroState, {
1705
+ globalStatus: "DEGRADED_HEALING",
1706
+ configuration: {
1707
+ auto_heal: true,
1708
+ concurrency_limit: parallel ? 4 : 1,
1709
+ },
1710
+ });
1711
+ maestroState.runtime_tracks.track_heal_sync = {
1712
+ active_gate: "$maestro",
1713
+ status: "COMPLETED",
1714
+ pid: null,
1715
+ execution_pane: detached.executionPane,
1716
+ provider: detached.provider,
1717
+ log_path: detached.logPath,
1718
+ exit_code: 0,
1719
+ repaired_artifacts: repairedArtifacts,
1720
+ updated_at: new Date().toISOString(),
1721
+ };
1722
+ await saveMaestroState(maestroState);
1723
+ await appendMaestroEvent({
1724
+ record_type: "healing:attempt",
1725
+ gate: "$maestro",
1726
+ global_status: "DEGRADED_HEALING",
1727
+ track_status: "COMPLETED",
1728
+ repaired_artifacts: repairedArtifacts,
1729
+ repaired_count: repairedArtifacts.length,
1730
+ });
1731
+ runtimeSnapshot = await loadRuntimeSnapshot();
1732
+ releaseState = runtimeSnapshot.release;
1733
+ runtimeSummary = createRuntimeSummary(runtimeSnapshot);
1734
+ buildReadiness = evaluateRuntimeBuildReadiness(releaseState, runtimeSummary);
1735
+ recommendation = chooseMaestroRecommendation(releaseState, idea, buildReadiness);
1736
+ }
1737
+ }
857
1738
  const registry = await loadManagerRunRegistry();
858
1739
  const activeRun = getActiveManagerRun(registry);
859
1740
  const managerAction = chooseMaestroManagerAction({
@@ -927,9 +1808,28 @@ export async function runMaestro() {
927
1808
  continue;
928
1809
  }
929
1810
 
1811
+ const detached =
1812
+ parallel && ["$flow", "$vet", "$vibe", "$build"].includes(gate.skill)
1813
+ ? await launchDetachedTrack({
1814
+ trackId: `${managerRun.id}-${gate.skill.replaceAll("$", "")}`,
1815
+ title: `Meta-Architect detached track ${gate.skill}`,
1816
+ command: "/bin/sh",
1817
+ args: ["-lc", `printf '%s\n' "Detached scratchpad track for ${gate.skill}"`],
1818
+ })
1819
+ : null;
930
1820
  gate.status = "running";
931
1821
  updateManagerRunTimestamps(managerRun, { state: "running" });
932
1822
  await saveManagerRunRegistry(registry);
1823
+ await updateScratchpadTrackForLane({
1824
+ gate: gate.skill,
1825
+ trackStatus: "RUNNING",
1826
+ globalStatus: "RUNNING",
1827
+ nextTriggers: [gate.skill],
1828
+ detached,
1829
+ details: {
1830
+ objective: gate.objective,
1831
+ },
1832
+ });
933
1833
  await runner();
934
1834
  gate.status = "completed";
935
1835
  await saveManagerRunRegistry(registry);
@@ -964,18 +1864,6 @@ export async function runMaestro() {
964
1864
  await saveManagerRunRegistry(registry);
965
1865
  }
966
1866
 
967
- if (
968
- buildReadiness.nextTriggers.includes("$build") ||
969
- buildReadiness.nextTriggers.includes("repair runtime artifacts")
970
- ) {
971
- await writeBuildPlanArtifact({
972
- allowed: buildReadiness.allowed,
973
- blockers: buildReadiness.blockers,
974
- nextTriggers: buildReadiness.nextTriggers,
975
- runtimeSummary,
976
- });
977
- }
978
-
979
1867
  await writeMaestroPlan({
980
1868
  releaseState,
981
1869
  recommendation,
@@ -995,8 +1883,18 @@ export async function runMaestro() {
995
1883
  });
996
1884
  }
997
1885
 
998
- export async function runInit() {
999
- const created = [];
1886
+ async function runInitUnlocked({
1887
+ refresh = false,
1888
+ obsidianVault = process.env.MA_OBSIDIAN_VAULT,
1889
+ } = {}) {
1890
+ const repoRoot = getRepoRoot();
1891
+ const migrations = await migrateSchemas(repoRoot);
1892
+ const managedBefore = await listManagedArtifacts(repoRoot);
1893
+ const report = {
1894
+ directories: [],
1895
+ files: [],
1896
+ migrations,
1897
+ };
1000
1898
  const targets = [
1001
1899
  ".codex/agents",
1002
1900
  ".codex/prompts",
@@ -1011,6 +1909,7 @@ export async function runInit() {
1011
1909
  ".ma/context",
1012
1910
  ".ma/specs",
1013
1911
  ".ma/plans",
1912
+ "scripts",
1014
1913
  "mcp",
1015
1914
  "docs",
1016
1915
  "docs/qa",
@@ -1019,8 +1918,14 @@ export async function runInit() {
1019
1918
 
1020
1919
  for (const relative of targets) {
1021
1920
  const target = path.join(getRepoRoot(), relative);
1921
+ const existed = await pathExists(target);
1922
+ await assertNoSymlinkComponents(getRepoRoot(), target);
1022
1923
  await fs.mkdir(target, { recursive: true });
1023
- created.push(relative);
1924
+ report.directories.push({
1925
+ path: relative,
1926
+ kind: "directory",
1927
+ status: existed ? "existing" : "created",
1928
+ });
1024
1929
  }
1025
1930
 
1026
1931
  const templateCopies = [
@@ -1068,6 +1973,14 @@ export async function runInit() {
1068
1973
  path.join(packageRoot, ".codex", "prompts", "onboarding.md"),
1069
1974
  path.join(getRepoRoot(), ".codex", "prompts", "onboarding.md"),
1070
1975
  ],
1976
+ [
1977
+ path.join(packageRoot, "scripts", "active-autonomy-hook.mjs"),
1978
+ path.join(getRepoRoot(), "scripts", "active-autonomy-hook.mjs"),
1979
+ ],
1980
+ [
1981
+ path.join(packageRoot, "scripts", "context-hydration-hook.mjs"),
1982
+ path.join(getRepoRoot(), "scripts", "context-hydration-hook.mjs"),
1983
+ ],
1071
1984
  [path.join(packageRoot, "docs", "README.md"), path.join(getRepoRoot(), "docs", "README.md")],
1072
1985
  [
1073
1986
  path.join(packageRoot, "docs", "getting-started.md"),
@@ -1083,8 +1996,16 @@ export async function runInit() {
1083
1996
  path.join(getRepoRoot(), "docs", "release-spec.md"),
1084
1997
  ],
1085
1998
  [
1086
- path.join(packageRoot, "docs", "qa", "release-readiness-0.1.12.md"),
1087
- path.join(getRepoRoot(), "docs", "qa", "release-readiness-0.1.12.md"),
1999
+ resolveReleaseReadiness(packageRoot)?.path ??
2000
+ path.join(packageRoot, "docs", "qa", "release-readiness-missing.md"),
2001
+ resolveReleaseReadiness(getRepoRoot())?.path ??
2002
+ path.join(getRepoRoot(), "docs", "qa", "release-readiness-missing.md"),
2003
+ ],
2004
+ [
2005
+ resolveReleaseIssueGates(packageRoot)?.path ??
2006
+ path.join(packageRoot, "docs", "qa", "release-issue-gates-missing.json"),
2007
+ resolveReleaseIssueGates(getRepoRoot())?.path ??
2008
+ path.join(getRepoRoot(), "docs", "qa", "release-issue-gates-missing.json"),
1088
2009
  ],
1089
2010
  ];
1090
2011
 
@@ -1119,14 +2040,46 @@ export async function runInit() {
1119
2040
  }
1120
2041
 
1121
2042
  for (const [src, dest] of templateCopies) {
1122
- try {
1123
- await fs.access(dest);
1124
- } catch {
1125
- await fs.copyFile(src, dest);
1126
- }
2043
+ report.files.push(await syncTemplateFile(src, dest, { refresh }));
1127
2044
  }
1128
2045
 
1129
2046
  await seedRuntimeArtifacts();
2047
+ const projectIndex = await refreshProjectIndex(repoRoot);
2048
+ report.context = {
2049
+ path: path.relative(repoRoot, getRuntimeWritePath("context", "project-index.json")),
2050
+ status: projectIndex.quality.confidence,
2051
+ completeness: projectIndex.quality.completeness,
2052
+ detected: {
2053
+ languages: projectIndex.languages,
2054
+ frameworks: projectIndex.frameworks,
2055
+ packageManager: projectIndex.packageManager,
2056
+ commands: projectIndex.commands,
2057
+ entrypoints: projectIndex.entrypoints,
2058
+ importantDocs: projectIndex.importantDocs,
2059
+ vendorIntegrations: projectIndex.vendorIntegrations,
2060
+ },
2061
+ unknown: projectIndex.quality.gaps,
2062
+ };
2063
+
2064
+ if (obsidianVault) {
2065
+ const embedded = await embedProjectContext({
2066
+ vaultPath: obsidianVault,
2067
+ projectIndex,
2068
+ });
2069
+ report.integrations = report.integrations ?? [];
2070
+ report.integrations.push({
2071
+ kind: "obsidian",
2072
+ status: embedded.noteStatus,
2073
+ vaultPath: embedded.vaultPath,
2074
+ notePath: embedded.notePath,
2075
+ indexPath: path.relative(
2076
+ repoRoot,
2077
+ getRuntimeWritePath("context", "obsidian-vault-index.json"),
2078
+ ),
2079
+ records_as: "vault_context",
2080
+ build_evidence: false,
2081
+ });
2082
+ }
1130
2083
 
1131
2084
  await writeFileIfMissing(
1132
2085
  getRuntimeWritePath("decisions.json"),
@@ -1251,5 +2204,122 @@ export async function runInit() {
1251
2204
  "# Onboarding\n\nMeta-Architect initializes the core scaffold, MCP config, and canonical .ma runtime files.\n",
1252
2205
  );
1253
2206
 
1254
- return created;
2207
+ const reported = new Set([
2208
+ ...report.directories.map((entry) => entry.path),
2209
+ ...report.files.map((entry) => entry.path),
2210
+ ]);
2211
+ const managedAfter = await listManagedArtifacts(repoRoot);
2212
+ for (const [relative, kind] of managedAfter) {
2213
+ if (!managedBefore.has(relative) && !reported.has(relative)) {
2214
+ report.files.push({ path: relative, kind, status: "created" });
2215
+ }
2216
+ }
2217
+
2218
+ report.onboarding = {
2219
+ context: ".ma/context/project-index.json",
2220
+ future_agents_read: [
2221
+ ".ma/context/agent-brief.md",
2222
+ ".ma/context/project-index.json",
2223
+ "AGENTS.md",
2224
+ ],
2225
+ integrations: {
2226
+ obsidian: report.integrations?.[0]?.status ?? "not configured",
2227
+ mcp: "local read-only context resources",
2228
+ hooks: ".codex/hooks.json",
2229
+ },
2230
+ freshness: report.context?.status ?? "unknown",
2231
+ next: ["ma doctor", "ma context refresh", "ma setup --rollback"],
2232
+ };
2233
+
2234
+ return report;
2235
+ }
2236
+
2237
+ export async function runInit(options = {}) {
2238
+ const repoRoot = getRepoRoot();
2239
+ return withSetupLock(repoRoot, async () => {
2240
+ await assertSetupReceiptHealthy(repoRoot);
2241
+ const managedBefore = await listManagedArtifacts(repoRoot);
2242
+ let report;
2243
+ try {
2244
+ report = await runInitUnlocked(options);
2245
+ } catch (error) {
2246
+ const managedAfter = await listManagedArtifacts(repoRoot);
2247
+ const partialFiles = [...managedAfter]
2248
+ .filter(([relative]) => !managedBefore.has(relative))
2249
+ .map(([relative, kind]) => ({
2250
+ path: relative,
2251
+ kind,
2252
+ status: "created",
2253
+ }));
2254
+ try {
2255
+ await writeSetupReceipt(repoRoot, { files: partialFiles });
2256
+ } catch (receiptError) {
2257
+ error.message = `${error.message}; failed to persist partial setup receipt: ${receiptError.message}`;
2258
+ }
2259
+ throw error;
2260
+ }
2261
+ const receipt = await writeSetupReceipt(repoRoot, report);
2262
+ await compactRuntimeState(repoRoot);
2263
+ report.files.push({ ...receipt, kind: "file", status: "refreshed" });
2264
+ return report;
2265
+ });
2266
+ }
2267
+
2268
+ async function syncTemplateFile(src, dest, { refresh = false } = {}) {
2269
+ const relativePath = path.relative(getRepoRoot(), dest);
2270
+ try {
2271
+ const [sourceContent, destContent] = await Promise.all([
2272
+ fs.readFile(src, "utf8"),
2273
+ fs.readFile(dest, "utf8").catch((error) => {
2274
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
2275
+ return null;
2276
+ }
2277
+ throw error;
2278
+ }),
2279
+ ]);
2280
+
2281
+ if (destContent === null) {
2282
+ await writeTextAtomically(dest, sourceContent);
2283
+ return {
2284
+ path: relativePath,
2285
+ kind: "file",
2286
+ status: "created",
2287
+ };
2288
+ }
2289
+
2290
+ if (destContent !== sourceContent && refresh) {
2291
+ await writeTextAtomically(dest, sourceContent);
2292
+ return {
2293
+ path: relativePath,
2294
+ kind: "file",
2295
+ status: "refreshed",
2296
+ };
2297
+ }
2298
+
2299
+ if (destContent !== sourceContent) {
2300
+ return {
2301
+ path: relativePath,
2302
+ kind: "file",
2303
+ status: "skipped",
2304
+ warning: "existing file differs; rerun with --refresh to update it",
2305
+ };
2306
+ }
2307
+
2308
+ return {
2309
+ path: relativePath,
2310
+ kind: "file",
2311
+ status: "existing",
2312
+ };
2313
+ } catch (error) {
2314
+ throw new Error(`Unable to sync managed template ${relativePath}`, { cause: error });
2315
+ }
2316
+ }
2317
+
2318
+ async function pathExists(target) {
2319
+ try {
2320
+ await fs.access(target);
2321
+ return true;
2322
+ } catch {
2323
+ return false;
2324
+ }
1255
2325
  }