0xray 4.0.41 → 4.1.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 (148) hide show
  1. package/.grok-plugin/plugin.json +1 -1
  2. package/.opencode/skills/orchestrator/SKILL.md +12 -0
  3. package/.plugin/plugin.json +1 -1
  4. package/.xray/features.json +5 -5
  5. package/.xray/features.schema.json +1 -1
  6. package/AGENTS-consumer.md +10 -6
  7. package/AGENTS.md +19 -8
  8. package/LICENSE +1 -1
  9. package/README.md +65 -19
  10. package/SKILLS.md +5 -1
  11. package/dist/AGENTS.md +19 -8
  12. package/dist/CHANGELOG.md +85 -0
  13. package/dist/LICENSE +1 -1
  14. package/dist/README.md +65 -19
  15. package/dist/SKILLS.md +5 -1
  16. package/dist/cli/commands/openclaw-install.js +1 -1
  17. package/dist/cli/commands/plugin-commands.d.ts +4 -0
  18. package/dist/cli/commands/plugin-commands.js +84 -41
  19. package/dist/cli/index.js +12 -0
  20. package/dist/core/config-loader.js +4 -4
  21. package/dist/core/features-config.d.ts +1 -1
  22. package/dist/core/features-config.js +3 -3
  23. package/dist/enforcement/index.d.ts +4 -0
  24. package/dist/enforcement/index.js +4 -0
  25. package/dist/enforcement/validators/code-quality-validators.js +6 -4
  26. package/dist/governance/llm-governance-provider.d.ts +7 -1
  27. package/dist/governance/llm-governance-provider.js +72 -14
  28. package/dist/governance/local-confer.d.ts +4 -1
  29. package/dist/governance/local-confer.js +22 -1
  30. package/dist/integrations/cursor/hooks/hooks.json +6 -3
  31. package/dist/integrations/cursor/hooks/pre-tool-use.js +100 -37
  32. package/dist/integrations/cursor/hooks/xray-cloud-hook.sh +9 -1
  33. package/dist/integrations/grok/grok-cli.js +10 -37
  34. package/dist/integrations/grok/hooks/grok-hook-utils.js +8 -1
  35. package/dist/integrations/grok/hooks/pre-tool-use.js +2 -58
  36. package/dist/integrations/hermes-agent/bridge.mjs +14 -1
  37. package/dist/integrations/hooks/confer-hook-runtime.mjs +23 -1
  38. package/dist/integrations/hooks/delegation-gate-runtime.mjs +3 -2
  39. package/dist/integrations/hooks/goggles-mcp.mjs +35 -17
  40. package/dist/integrations/hooks/goggles-pipeline.mjs +46 -1
  41. package/dist/integrations/hooks/goggles-planes.json +11 -7
  42. package/dist/integrations/hooks/pre-tool-speak.mjs +76 -0
  43. package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +21 -4
  44. package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +17 -2
  45. package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  46. package/dist/mcps/architect-tools.server.d.ts +6 -0
  47. package/dist/mcps/architect-tools.server.js +19 -2
  48. package/dist/mcps/config/server-config-registry.js +8 -6
  49. package/dist/mcps/governance.server.d.ts +1 -0
  50. package/dist/mcps/governance.server.js +46 -0
  51. package/dist/mcps/knowledge-skills/code-review.server.js +7 -0
  52. package/dist/mcps/knowledge-skills/security-audit.server.js +5 -3
  53. package/dist/mcps/mcp-client.js +1 -1
  54. package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
  55. package/dist/mcps/researcher.server.js +12 -3
  56. package/dist/monitoring/{nudge-watchdog.d.ts → nudge-monitor.d.ts} +14 -5
  57. package/dist/monitoring/{nudge-watchdog.js → nudge-monitor.js} +42 -17
  58. package/dist/nucleus/autonomy-kernel.d.ts +2 -0
  59. package/dist/nucleus/autonomy-kernel.js +17 -13
  60. package/dist/nucleus/confer-host.d.ts +35 -0
  61. package/dist/nucleus/confer-host.js +55 -0
  62. package/dist/nucleus/confer.d.ts +19 -3
  63. package/dist/nucleus/confer.js +111 -55
  64. package/dist/nucleus/lead-dev-plan-persistence.js +4 -2
  65. package/dist/nucleus/suit-temperament.d.ts +1 -1
  66. package/dist/nucleus/suit-temperament.js +2 -2
  67. package/dist/nucleus/synthesis-consult-receipt.d.ts +7 -1
  68. package/dist/nucleus/synthesis-consult-receipt.js +86 -35
  69. package/dist/plugin/xray-codex-injection.js +18 -0
  70. package/dist/processors/implementations/nudge-processor.d.ts +1 -1
  71. package/dist/processors/implementations/nudge-processor.js +4 -4
  72. package/dist/reporting/framework-reporting-system.js +2 -5
  73. package/dist/reporting/log-parser.d.ts +2 -0
  74. package/dist/reporting/log-parser.js +7 -6
  75. package/dist/skills/orchestrator/SKILL.md +12 -0
  76. package/docs-site/docs/plates/activity-log.md +1 -1
  77. package/docs-site/docs/plates/bifrost.md +48 -0
  78. package/docs-site/docs/plates/boot.md +2 -2
  79. package/docs-site/docs/plates/centrifuge.md +1 -1
  80. package/docs-site/docs/plates/cursor-compact.md +1 -1
  81. package/docs-site/docs/plates/glossary.md +7 -3
  82. package/docs-site/docs/plates/goggles.md +13 -2
  83. package/docs-site/docs/plates/governance.md +1 -1
  84. package/docs-site/docs/plates/grok-compact.md +1 -1
  85. package/docs-site/docs/plates/grokbot.md +3 -1
  86. package/docs-site/docs/plates/host-pack.md +1 -1
  87. package/docs-site/docs/plates/house.md +1 -1
  88. package/docs-site/docs/plates/index.md +4 -2
  89. package/docs-site/docs/plates/inference-files.md +1 -1
  90. package/docs-site/docs/plates/kept-line.md +1 -1
  91. package/docs-site/docs/plates/kits.md +1 -1
  92. package/docs-site/docs/plates/lens-gate.md +3 -1
  93. package/docs-site/docs/plates/lens-page.md +1 -1
  94. package/docs-site/docs/plates/memory-recall.md +1 -1
  95. package/docs-site/docs/plates/notes-page.md +2 -2
  96. package/docs-site/docs/plates/orchestration.md +1 -1
  97. package/docs-site/docs/plates/package-face.md +1 -1
  98. package/docs-site/docs/plates/payload-heat.md +1 -1
  99. package/docs-site/docs/plates/pickup-stamp.md +1 -1
  100. package/docs-site/docs/plates/pre-tool.md +1 -1
  101. package/docs-site/docs/plates/processor.md +1 -1
  102. package/docs-site/docs/plates/record-map.md +1 -1
  103. package/docs-site/docs/plates/reflection-page.md +1 -1
  104. package/docs-site/docs/plates/reporting.md +1 -1
  105. package/docs-site/docs/plates/review.md +1 -1
  106. package/docs-site/docs/plates/routing.md +1 -1
  107. package/docs-site/docs/plates/session-capture.md +1 -1
  108. package/docs-site/docs/plates/site-manual.md +1 -1
  109. package/docs-site/docs/plates/stamp-plate.md +1 -1
  110. package/docs-site/docs/plates/station-card.md +1 -1
  111. package/docs-site/docs/plates/station-heat.md +1 -1
  112. package/docs-site/docs/plates/suit-organs.md +1 -1
  113. package/docs-site/docs/plates/suit-settings.md +1 -1
  114. package/docs-site/docs/plates/suit-wear.md +1 -1
  115. package/docs-site/docs/plates/suit.md +3 -3
  116. package/docs-site/docs/plates/trail-state.md +1 -1
  117. package/docs-site/docs/plates/work-fresh.md +1 -1
  118. package/docs-site/docs/plates/write-home.md +1 -1
  119. package/llms.txt +16 -6
  120. package/package.json +4 -4
  121. package/scripts/foundry/README.md +2 -2
  122. package/scripts/foundry/release-gate.mjs +111 -15
  123. package/scripts/foundry/release.mjs +8 -0
  124. package/scripts/mjs/verify-confer-core.mjs +153 -29
  125. package/scripts/mjs/verify-pipeline-facets.mjs +1 -1
  126. package/scripts/mjs/verify-user-aside-core.mjs +3 -4
  127. package/scripts/node/bridge-mcp-wiring.cjs +236 -5
  128. package/scripts/node/confer-switch.cjs +66 -0
  129. package/scripts/node/install-bridges.cjs +44 -53
  130. package/scripts/node/pack-tmp-suit-proof.mjs +14 -6
  131. package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +17 -2
  132. package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +1 -1
  133. package/src/mcps/architect-tools.server.ts +26 -2
  134. package/src/mcps/config/__tests__/server-config-registry.test.ts +15 -6
  135. package/src/mcps/config/server-config-registry.ts +9 -6
  136. package/src/mcps/governance.server.ts +49 -0
  137. package/src/mcps/knowledge-skills/code-review.server.ts +8 -0
  138. package/src/mcps/knowledge-skills/security-audit.server.ts +11 -12
  139. package/src/mcps/mcp-client.ts +1 -1
  140. package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
  141. package/src/mcps/researcher.server.ts +19 -10
  142. package/src/skills/orchestrator/SKILL.md +12 -0
  143. package/vendor/@0xray/repertoire/README.md +1 -1
  144. package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +5 -51
  145. package/xray/agents_template.md +2 -2
  146. package/xray/features.json +5 -5
  147. package/xray/features.schema.json +1 -1
  148. package/docs-site/docs/plates/live-mesh.md +0 -41
@@ -3,10 +3,12 @@
3
3
  * release-gate.mjs — Single release checkpoint.
4
4
  *
5
5
  * Modes:
6
- * (default) build + test + consumer smoke (fresh + upgrade merge)
6
+ * (default) build + test + docs + consumer smoke (fresh + upgrade merge)
7
7
  * --verify-only git + reconcile + release docs + consumer smoke — after push, before publish
8
8
  * --skip-smoke skip consumer install smoke
9
- * --skip-docs skip release docs validation (not recommended for publish)
9
+ * --prove-published Gate D only: npm lists this version, the annotated tag points at HEAD,
10
+ * and the GitHub Release exists. This command does not publish.
11
+ * --skip-docs refused. Gate C runs on every gate.
10
12
  *
11
13
  * Usage:
12
14
  * npx @0xray/foundry gate
@@ -21,7 +23,7 @@ import { isXrayExoRepo, millScript, readRootPackage, resolveMillRoot } from "./m
21
23
  const rootDir = resolveMillRoot();
22
24
  const verifyOnly = process.argv.includes("--verify-only");
23
25
  const skipSmoke = process.argv.includes("--skip-smoke");
24
- const skipDocs = process.argv.includes("--skip-docs");
26
+ const provePublished = process.argv.includes("--prove-published");
25
27
 
26
28
  function step(label, cmd) {
27
29
  console.log(`\n${"─".repeat(60)}\n🔄 ${label}\n${"─".repeat(60)}\n`);
@@ -32,18 +34,114 @@ function docsCheckCmd() {
32
34
  return `${JSON.stringify(process.execPath)} ${JSON.stringify(millScript("validate-release-docs.mjs"))}`;
33
35
  }
34
36
 
37
+
38
+ /** Gate C is the docs check. A ship gate that skips it is not a pass. */
39
+ export function gateCRefusal(argv = process.argv) {
40
+ if (argv.includes("--skip-docs")) {
41
+ return "Gate C cannot be skipped. Remove --skip-docs. The docs check runs on every gate.";
42
+ }
43
+ return null;
44
+ }
45
+
46
+ /**
47
+ * Gate D facts. listed, tagAnnotated, and tagMatchesHead are booleans.
48
+ * releaseUrl is the GitHub Release page, or empty when that page is missing.
49
+ */
50
+ export function provePublishedRelease(proof) {
51
+ const version = proof.version;
52
+ const errors = [];
53
+ if (proof.listed !== true) errors.push(`npm does not list ${version}`);
54
+ if (proof.tagAnnotated !== true) errors.push(`annotated tag v${version} is missing`);
55
+ if (proof.tagMatchesHead !== true) errors.push(`annotated tag v${version} does not point at HEAD`);
56
+ if (typeof proof.releaseUrl !== "string" || proof.releaseUrl.length === 0) {
57
+ errors.push(`GitHub Release v${version} is missing`);
58
+ }
59
+ return errors;
60
+ }
61
+
62
+ function gitOut(cmd) {
63
+ return execSync(cmd, { cwd: rootDir, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
64
+ }
65
+
66
+ function originSlug() {
67
+ const url = gitOut("git remote get-url origin");
68
+ const match = url.match(/github\.com[:/]([^/]+)\/([^/.]+)(?:\.git)?$/);
69
+ if (!match) throw new Error(`origin is not a GitHub repo: ${url}`);
70
+ return { owner: match[1], repo: match[2] };
71
+ }
72
+
73
+ function collectPublishedProof() {
74
+ const pkg = readRootPackage(rootDir);
75
+ const version = pkg.version;
76
+ const name = pkg.name;
77
+ let listed = false;
78
+ try {
79
+ const view = gitOut(`npm view ${name}@${version} version`);
80
+ listed = view.split(/\s+/).includes(version);
81
+ } catch {
82
+ listed = false;
83
+ }
84
+ let tagAnnotated = false;
85
+ let tagMatchesHead = false;
86
+ try {
87
+ tagAnnotated = gitOut(`git cat-file -t v${version}`) === "tag";
88
+ const tagged = gitOut(`git rev-parse v${version}^{}`);
89
+ const head = gitOut("git rev-parse HEAD");
90
+ tagMatchesHead = tagAnnotated && tagged === head;
91
+ } catch {
92
+ tagAnnotated = false;
93
+ tagMatchesHead = false;
94
+ }
95
+ let releaseUrl = "";
96
+ try {
97
+ const { owner, repo } = originSlug();
98
+ const body = gitOut(
99
+ `curl -fsS -H "Accept: application/vnd.github+json" -H "User-Agent: 0xray-release-gate" https://api.github.com/repos/${owner}/${repo}/releases/tags/v${version}`,
100
+ );
101
+ const parsed = JSON.parse(body);
102
+ releaseUrl = typeof parsed.html_url === "string" ? parsed.html_url : "";
103
+ } catch {
104
+ releaseUrl = "";
105
+ }
106
+ return { version, name, listed, tagAnnotated, tagMatchesHead, releaseUrl };
107
+ }
108
+
109
+ function runProvePublished() {
110
+ const proof = collectPublishedProof();
111
+ const errors = provePublishedRelease(proof);
112
+ process.stdout.write(`\nGate D — ${proof.name}@${proof.version}\n`);
113
+ if (errors.length) {
114
+ for (const error of errors) process.stderr.write(`❌ ${error}\n`);
115
+ process.stderr.write("\n❌ GATE D FAILED — npm listing, annotated tag at HEAD, and GitHub Release are all required\n\n");
116
+ process.exit(1);
117
+ }
118
+ process.stdout.write(`✅ npm lists ${proof.version}\n`);
119
+ process.stdout.write(`✅ annotated tag v${proof.version} points at HEAD\n`);
120
+ process.stdout.write(`✅ GitHub Release ${proof.releaseUrl}\n`);
121
+ process.stdout.write("\n✅ GATE D PROVEN\n\n");
122
+ }
123
+
35
124
  function runLightGate() {
36
125
  const pkg = readRootPackage(rootDir);
37
126
  if (verifyOnly) {
38
- if (!skipDocs) step("1/1 Release docs (light)", docsCheckCmd());
127
+ step("1/1 Release docs (light)", docsCheckCmd());
39
128
  return;
40
129
  }
41
130
  if (pkg.scripts.build) step("1/3 Build", "npm run build");
42
131
  if (pkg.scripts.test) step("2/3 Tests", "npm test");
43
- if (!skipDocs) step("3/3 Release docs (light)", docsCheckCmd());
132
+ step("3/3 Release docs (light)", docsCheckCmd());
44
133
  }
45
134
 
46
135
  function main() {
136
+ const refused = gateCRefusal();
137
+ if (refused) {
138
+ process.stderr.write(`\n❌ ${refused}\n\n`);
139
+ process.exit(1);
140
+ }
141
+ if (provePublished) {
142
+ runProvePublished();
143
+ return;
144
+ }
47
145
  const mode = verifyOnly ? "verify" : "full";
48
146
  console.log("\n╔════════════════════════════════════════════════════════╗");
49
147
  console.log(`║ 🛡️ 0xRay Release Gate (${mode})`.padEnd(57) + "║");
@@ -54,9 +152,7 @@ function main() {
54
152
  runLightGate();
55
153
  } else if (verifyOnly) {
56
154
  step("1/6 Git + reconcile", "node scripts/node/pre-publish-guard.js --verify-only");
57
- if (!skipDocs) {
58
- step("2/6 Release docs", docsCheckCmd());
59
- }
155
+ step("2/6 Release docs", docsCheckCmd());
60
156
  step(
61
157
  "3/6 Plugin infrastructure",
62
158
  "node scripts/test/validate-plugins-e2e.cjs --structural-only",
@@ -75,9 +171,7 @@ function main() {
75
171
  `${JSON.stringify(process.execPath)} ${JSON.stringify(millScript("assert-packed-dist-cli.mjs"))}`,
76
172
  );
77
173
  step("3/8 Tests", "npm run test:comprehensive");
78
- if (!skipDocs) {
79
- step("4/8 Release docs", docsCheckCmd());
80
- }
174
+ step("4/8 Release docs", docsCheckCmd());
81
175
  step(
82
176
  "5/8 Consumer hook verifiers",
83
177
  "npm run verify:pre-commit-diff && npm run verify:pre-push-diff && node scripts/mjs/verify-delegation-gate-core.mjs --host=grok && node scripts/mjs/verify-delegation-gate-core.mjs --host=hermes && node scripts/mjs/verify-delegation-gate-core.mjs --host=opencode && node scripts/mjs/verify-hermes-session-start.mjs && node scripts/mjs/verify-confer-core.mjs && npm run verify:user-aside && npm run build && node scripts/mjs/verify-pipeline-facets.mjs --package-only",
@@ -91,9 +185,11 @@ function main() {
91
185
  }
92
186
  }
93
187
 
94
- console.log("\n╔════════════════════════════════════════════════════════╗");
95
- console.log("║ ✅ RELEASE GATE PASSED ║");
96
- console.log("╚════════════════════════════════════════════════════════╝\n");
188
+ process.stdout.write("\n╔════════════════════════════════════════════════════════╗\n");
189
+ process.stdout.write("║ ✅ GATE A–C LOCAL PASS ║\n");
190
+ process.stdout.write("║ Gate D is not proven by this command. ║\n");
191
+ process.stdout.write("╚════════════════════════════════════════════════════════╝\n");
192
+ process.stdout.write("Prove D after publish: npx @0xray/foundry gate --prove-published\n\n");
97
193
  } catch {
98
194
  console.error("\n❌ RELEASE GATE FAILED — do not tag or publish\n");
99
195
  process.exit(1);
@@ -105,4 +201,4 @@ const isMain =
105
201
 
106
202
  if (isMain) {
107
203
  main();
108
- }
204
+ }
@@ -191,6 +191,8 @@ async function main() {
191
191
  }
192
192
  }
193
193
  run(`git push origin v${version}`, "push tag");
194
+ say("Step 8: Gate D");
195
+ runMill("release-gate.mjs", ["--prove-published"], "gate D");
194
196
  return;
195
197
  }
196
198
 
@@ -281,6 +283,12 @@ async function main() {
281
283
  console.log(` would: git tag -a v${newVersion}`);
282
284
  }
283
285
  run(`git push origin v${newVersion}`, "push tag");
286
+ say("Step 8: Gate D");
287
+ runMill("release-gate.mjs", ["--prove-published"], "gate D");
288
+ if (dryRun) {
289
+ say("Dry run did not prove Gate D.");
290
+ return;
291
+ }
284
292
 
285
293
  console.log("\n╔════════════════════════════════════════════════════════╗");
286
294
  console.log("║ ✅ Release Complete! ║");
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Confer quorum fixture — 3-agent synthesis consult completes via fixture mode.
3
+ * Confer quorum fixture.
4
+ * PASS completes. FAIL and no-LLM UNREVIEWED leave the todo open and the checkpoint due.
5
+ * Temp projects opt into synthesis so a due checkpoint can be observed. The repo default stays off.
4
6
  */
5
- import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from 'node:fs';
7
+ import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
6
8
  import { tmpdir } from 'node:os';
7
9
  import { dirname, join } from 'node:path';
8
10
  import { fileURLToPath } from 'node:url';
@@ -10,10 +12,14 @@ import { fileURLToPath } from 'node:url';
10
12
  const __dirname = dirname(fileURLToPath(import.meta.url));
11
13
  const packageRoot = join(__dirname, '../..');
12
14
 
15
+ // Fixture PASS is refused unless this process is a test. The live orchestrate-task
16
+ // flag and XRAY_CONFER_FIXTURE stay unreachable when NODE_ENV is not test.
17
+ process.env.NODE_ENV = 'test';
18
+
13
19
  const { buildSynthesisCheckpointPlan } = await import(
14
20
  join(packageRoot, 'dist/nucleus/autonomy-kernel.js')
15
21
  );
16
- const { savePersistedLeadDevPlan, areSynthesisConsultTodosComplete } = await import(
22
+ const { savePersistedLeadDevPlan, areSynthesisConsultTodosComplete, loadPersistedLeadDevPlan } = await import(
17
23
  join(packageRoot, 'dist/nucleus/lead-dev-plan-persistence.js')
18
24
  );
19
25
  const { recordExecutionSlice, isSynthesisCheckpointDue } = await import(
@@ -22,46 +28,103 @@ const { recordExecutionSlice, isSynthesisCheckpointDue } = await import(
22
28
  const { runConferQuorum, loadConferCheckpoint, CONFER_AGENTS } = await import(
23
29
  join(packageRoot, 'dist/nucleus/confer.js')
24
30
  );
31
+ const { loadSynthesisConsultReceipt } = await import(
32
+ join(packageRoot, 'dist/nucleus/synthesis-consult-receipt.js')
33
+ );
34
+ const { readConferReviewHint } = await import(
35
+ join(packageRoot, 'src/integrations/hooks/confer-hook-runtime.mjs')
36
+ );
37
+ const { buildSessionBootPayload } = await import(
38
+ join(packageRoot, 'src/integrations/grok/hooks/grok-hook-utils.js')
39
+ );
25
40
 
26
- const sessionId = 'verify-confer-core';
27
41
  let failed = 0;
42
+ let checks = 0;
28
43
  function pass(n) {
44
+ checks++;
29
45
  console.log(`✅ ${n}`);
30
46
  }
31
47
  function fail(n, d = '') {
32
48
  failed++;
49
+ checks++;
33
50
  console.error(`❌ ${n}${d ? ` — ${d}` : ''}`);
34
51
  }
35
52
 
36
- const tmp = mkdtempSync(join(tmpdir(), 'xray-confer-verify-'));
37
- mkdirSync(join(tmp, '.xray', 'state'), { recursive: true });
38
- writeFileSync(
39
- join(tmp, '.xray', 'features.json'),
40
- JSON.stringify({
41
- multi_agent_orchestration: { lead_dev_mode: true, confer_on_synthesis: true },
42
- synthesis: { enabled: true, every_n_gates: 1, every_n_turns: 0, every_n_todos_completed: 0 },
43
- }),
44
- );
53
+ function assertRepoSynthesisStaysOff() {
54
+ const source = readFileSync(join(packageRoot, 'src/nucleus/synthesis.ts'), 'utf8');
55
+ const defaults = source.match(/function defaultSynthesisConfig\(\)[\s\S]*?return \{([\s\S]*?)\n \};/);
56
+ if (defaults && /enabled:\s*false/.test(defaults[1])) pass('repo defaultSynthesisConfig stays enabled: false');
57
+ else fail('repo defaultSynthesisConfig stays enabled: false');
45
58
 
46
- try {
47
- recordExecutionSlice('gate', { projectRoot: tmp, sessionId });
48
- if (!isSynthesisCheckpointDue(tmp, sessionId)) fail('step 1: synthesis due');
49
- else pass('step 1: synthesis checkpoint due');
59
+ for (const rel of ['xray/features.json', '.xray/features.json']) {
60
+ const data = JSON.parse(readFileSync(join(packageRoot, rel), 'utf8'));
61
+ if (data.synthesis?.enabled === false) pass(`${rel} synthesis.enabled stays false`);
62
+ else fail(`${rel} synthesis.enabled stays false`, JSON.stringify(data.synthesis));
63
+ }
64
+ }
50
65
 
66
+ function makeProject() {
67
+ const tmp = mkdtempSync(join(tmpdir(), 'xray-confer-verify-'));
68
+ mkdirSync(join(tmp, '.xray', 'state'), { recursive: true });
69
+ writeFileSync(
70
+ join(tmp, '.xray', 'features.json'),
71
+ JSON.stringify({
72
+ multi_agent_orchestration: { lead_dev_mode: true, confer_on_synthesis: true },
73
+ synthesis: { enabled: true, every_n_gates: 1, every_n_turns: 0, every_n_todos_completed: 0 },
74
+ }),
75
+ );
76
+ return tmp;
77
+ }
78
+
79
+ function seedDuePlan(tmp, sessionId) {
80
+ recordExecutionSlice('gate', { projectRoot: tmp, sessionId });
81
+ const due = isSynthesisCheckpointDue(tmp, sessionId);
51
82
  const plan = buildSynthesisCheckpointPlan('gate threshold (1/1)', tmp);
52
- if (!plan) fail('step 2: synthesis plan');
53
- else {
83
+ if (plan) {
54
84
  savePersistedLeadDevPlan(
55
85
  { ...plan, persistedAt: new Date().toISOString(), sessionId },
56
86
  tmp,
57
87
  );
58
- pass('step 2: synthesis plan persisted');
59
88
  }
89
+ return { due, plan };
90
+ }
91
+
92
+ function blocksCheckpoint(label, tmp, sessionId, result, verdict) {
93
+ const receipt = loadSynthesisConsultReceipt('s.1', tmp);
94
+ if (result.status === 'partial' && result.agents[0]?.verdict === verdict && result.agents[0]?.todoCompleted === false) {
95
+ pass(`${label}: quorum stopped on ${verdict}`);
96
+ } else {
97
+ fail(`${label}: quorum stopped on ${verdict}`, JSON.stringify(result));
98
+ }
99
+ if (receipt?.verdict === verdict) pass(`${label}: receipt verdict ${verdict}`);
100
+ else fail(`${label}: receipt verdict ${verdict}`, JSON.stringify(receipt));
101
+ if (!areSynthesisConsultTodosComplete(loadPersistedLeadDevPlan(tmp))) {
102
+ pass(`${label}: consult todo stays open`);
103
+ } else {
104
+ fail(`${label}: consult todo stays open`);
105
+ }
106
+ if (isSynthesisCheckpointDue(tmp, sessionId)) pass(`${label}: synthesis checkpoint stays due`);
107
+ else fail(`${label}: synthesis checkpoint stays due`);
108
+ const state = loadConferCheckpoint(tmp);
109
+ if (state?.status === 'failed') pass(`${label}: confer checkpoint not cleared`);
110
+ else fail(`${label}: confer checkpoint not cleared`, JSON.stringify(state));
111
+ }
112
+
113
+ assertRepoSynthesisStaysOff();
114
+
115
+ const passRoot = makeProject();
116
+ const passSession = 'verify-confer-core-pass';
117
+ try {
118
+ const seeded = seedDuePlan(passRoot, passSession);
119
+ if (!seeded.due) fail('step 1: synthesis due');
120
+ else pass('step 1: synthesis checkpoint due');
121
+ if (!seeded.plan) fail('step 2: synthesis plan');
122
+ else pass('step 2: synthesis plan persisted');
60
123
 
61
124
  if (CONFER_AGENTS.length !== 3) fail('step 3: confer agent count', String(CONFER_AGENTS.length));
62
125
  else pass('step 3: three confer agents defined');
63
126
 
64
- const result = await runConferQuorum(tmp, sessionId, {
127
+ const result = await runConferQuorum(passRoot, passSession, {
65
128
  collocatedText: 'verify confer fixture context',
66
129
  dueReason: 'gate threshold',
67
130
  fixture: true,
@@ -73,31 +136,92 @@ try {
73
136
  fail('step 4: confer quorum', JSON.stringify(result));
74
137
  }
75
138
 
76
- const state = loadConferCheckpoint(tmp);
139
+ const state = loadConferCheckpoint(passRoot);
77
140
  if (state?.status === 'completed' && state.completedAgents.length === 3) {
78
141
  pass('step 5: confer checkpoint state completed');
79
142
  } else {
80
143
  fail('step 5: confer state', JSON.stringify(state));
81
144
  }
82
145
 
83
- if (areSynthesisConsultTodosComplete(
84
- (await import(join(packageRoot, 'dist/nucleus/lead-dev-plan-persistence.js'))).loadPersistedLeadDevPlan(tmp),
85
- )) {
146
+ if (areSynthesisConsultTodosComplete(loadPersistedLeadDevPlan(passRoot))) {
86
147
  pass('step 6: synthesis consult todos complete after confer');
87
148
  } else {
88
149
  fail('step 6: consult todos incomplete');
89
150
  }
90
151
 
91
- if (!isSynthesisCheckpointDue(tmp, sessionId)) pass('step 7: synthesis checkpoint cleared');
152
+ if (!isSynthesisCheckpointDue(passRoot, passSession)) pass('step 7: synthesis checkpoint cleared');
92
153
  else fail('step 7: checkpoint still due');
93
154
  } finally {
94
- rmSync(tmp, { recursive: true, force: true });
155
+ rmSync(passRoot, { recursive: true, force: true });
156
+ }
157
+
158
+ const failRoot = makeProject();
159
+ const failSession = 'verify-confer-core-fail';
160
+ try {
161
+ seedDuePlan(failRoot, failSession);
162
+ const result = await runConferQuorum(failRoot, failSession, {
163
+ fixture: true,
164
+ fixtureVerdict: 'FAIL',
165
+ });
166
+ blocksCheckpoint('FAIL', failRoot, failSession, result, 'FAIL');
167
+ } finally {
168
+ rmSync(failRoot, { recursive: true, force: true });
169
+ }
170
+
171
+ const unreviewedRoot = makeProject();
172
+ const unreviewedSession = 'verify-confer-core-unreviewed';
173
+ try {
174
+ seedDuePlan(unreviewedRoot, unreviewedSession);
175
+ const result = await runConferQuorum(unreviewedRoot, unreviewedSession, {
176
+ fixture: true,
177
+ fixtureNoLlm: true,
178
+ });
179
+ blocksCheckpoint('no-LLM', unreviewedRoot, unreviewedSession, result, 'UNREVIEWED');
180
+ if (readConferReviewHint(unreviewedRoot) === 'UNREVIEWED') {
181
+ pass('no-LLM: confer review hint is UNREVIEWED');
182
+ } else {
183
+ fail('no-LLM: confer review hint is UNREVIEWED');
184
+ }
185
+ const boot = buildSessionBootPayload(unreviewedRoot, 'verify/session-start');
186
+ if (boot.conferReview === 'UNREVIEWED' && String(boot.conferReviewHint).includes('UNREVIEWED')) {
187
+ pass('no-LLM: session-boot hint records UNREVIEWED');
188
+ } else {
189
+ fail('no-LLM: session-boot hint records UNREVIEWED', JSON.stringify({
190
+ conferReview: boot.conferReview,
191
+ conferReviewHint: boot.conferReviewHint,
192
+ }));
193
+ }
194
+ } finally {
195
+ rmSync(unreviewedRoot, { recursive: true, force: true });
196
+ }
197
+
198
+ const conditionalRoot = makeProject();
199
+ const conditionalSession = 'verify-confer-core-conditional';
200
+ try {
201
+ seedDuePlan(conditionalRoot, conditionalSession);
202
+ const result = await runConferQuorum(conditionalRoot, conditionalSession, {
203
+ fixture: true,
204
+ fixtureVerdict: 'CONDITIONAL',
205
+ });
206
+ const verdicts = result.agents.map((agent) => agent.verdict);
207
+ if (result.status === 'partial' && verdicts[0] === 'CONDITIONAL' && result.agents[0]?.todoCompleted === false) {
208
+ pass('CONDITIONAL: explicit conditional does not complete');
209
+ } else {
210
+ fail('CONDITIONAL: explicit conditional does not complete', JSON.stringify(result));
211
+ }
212
+ if (isSynthesisCheckpointDue(conditionalRoot, conditionalSession)) {
213
+ pass('CONDITIONAL: checkpoint stays due');
214
+ } else {
215
+ fail('CONDITIONAL: checkpoint stays due');
216
+ }
217
+ } finally {
218
+ rmSync(conditionalRoot, { recursive: true, force: true });
95
219
  }
96
220
 
97
221
  console.log(
98
222
  '\n' +
99
223
  (failed === 0
100
- ? '🎉 Confer verify passed (7/7).'
224
+ ? `🎉 Confer verify passed (${checks}/${checks}).`
101
225
  : `⚠️ ${failed} confer check(s) failed.`),
102
226
  );
103
- process.exit(failed === 0 ? 0 : 1);
227
+ process.exit(failed === 0 ? 0 : 1);
@@ -110,7 +110,7 @@ if (packageOnly) {
110
110
  }
111
111
 
112
112
  // P1 — autonomous reporting
113
- if (features?.autonomous_reporting?.enabled === true) {
113
+ if (features?.autonomous_reporting?.enabled === false) {
114
114
  pass('autonomous_reporting.enabled');
115
115
  } else {
116
116
  fail('autonomous_reporting.enabled');
@@ -75,16 +75,15 @@ try {
75
75
  35,
76
76
  tmp,
77
77
  );
78
- if (aside?.plan.phases[0]?.todos[0]?.id !== 'suit-nft.a.1.1') {
79
- fail('step 3: build aside plan', aside?.plan.phases[0]?.todos[0]?.id);
78
+ const todo = aside?.plan.phases.flatMap((phase) => phase.todos)[0];
79
+ if (todo?.id !== 'suit-nft.a.2.1') {
80
+ fail('step 3: build aside plan', todo?.id);
80
81
  } else pass('step 3: namespaced aside todos');
81
82
 
82
83
  saveUserAside(aside, tmp);
83
84
  setActiveAsideId('suit-nft', tmp, 'verify-session');
84
85
  if (getActiveAsideId(tmp, 'verify-session') !== 'suit-nft') fail('step 4: active pointer');
85
86
  else pass('step 4: active aside pointer with session');
86
-
87
- const todo = aside.plan.phases[0].todos[0];
88
87
  const resolved = resolveSpawnPlan({ planTodoId: todo.id }, tmp, 'verify-session');
89
88
  if (resolved.source !== 'aside') fail('step 5: resolve spawn plan', JSON.stringify(resolved));
90
89
  else pass('step 5: spawn plan resolves to aside');