@lazyingart/agintiflow 0.20.241 → 0.20.243

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.
@@ -10,6 +10,15 @@ Simple questions should stay on the fast path. A deep-research run spends more
10
10
  queries and model calls only when breadth, verification, and traceability add
11
11
  real value.
12
12
 
13
+ For a request that combines local workspace evidence with web research, the
14
+ outer agent first receives normal inspection tools. After it has read two
15
+ relevant files, or read one file plus inspected/searched the project, the next
16
+ research turn is constrained to `deep_research` and `finish`. This keeps local
17
+ notes authoritative without letting an agent silently replace a requested
18
+ multi-source review with ad hoc browsing. Tool history is scoped to the newest
19
+ genuine user request, so a completed research call from an older task does not
20
+ suppress a later correction or refresh.
21
+
13
22
  ## Architecture
14
23
 
15
24
  The implementation follows the strongest production patterns without making
@@ -35,6 +44,11 @@ every query an unbounded agent swarm:
35
44
  paper set erase the requested source class. Search snippets can guide
36
45
  discovery, but they cannot satisfy verified first-party coverage or enter
37
46
  synthesis as cited evidence.
47
+ Phrases such as “official Temporal docs” retain this requirement even when a
48
+ product name occurs between `official` and `docs`. Product-owned root pages
49
+ and vendor blogs are classified using the named discovery route; unrelated
50
+ third-party pages are not promoted merely because their URL repeats one
51
+ query word.
38
52
  Canonical duplicates found by multiple providers are promoted and retain
39
53
  per-provider rank evidence. Multi-domain corpora receive separate bounded `site:`
40
54
  queries matched to entity-specific subquestions instead of one fragile OR
@@ -99,6 +113,10 @@ every query an unbounded agent swarm:
99
113
  rather than arbitrary page text. Every substantive paragraph and finding
100
114
  cites exact evidence IDs instead of merely naming a source. A failed main
101
115
  synthesis gets one same-provider fast-model fallback.
116
+ A request for practical recommendations becomes a completion obligation:
117
+ every recommendation must cite verified evidence, and the run fails closed
118
+ rather than delivering an unsupported advice section. The renderer uses the
119
+ compact research objective instead of dumping the raw task prompt.
102
120
  9. **Audit**: deterministic code removes unknown or unverified evidence IDs,
103
121
  derives visible source citations from accepted evidence records, removes
104
122
  unsupported synthesis statements, then reports claim, quotation, citation,
@@ -110,6 +128,13 @@ every query an unbounded agent swarm:
110
128
  guarded workspace-relative `outputPath` when the caller requests a durable
111
129
  filename, then sent to the canvas.
112
130
 
131
+ The reader-facing report always includes an explicit limitations section and
132
+ separates quote-verified sources from inspected-but-uncited pages. When the
133
+ original request asks for reproducibility or exact quotations, deterministic
134
+ rendering adds a verification procedure, retrieval timestamps and SHA-256
135
+ digests, and a verified-evidence appendix. These sections come from the
136
+ retrieval/evidence ledger, not model memory.
137
+
113
138
  This combines the orchestrator/worker and separate citation-pass lessons
114
139
  described by [Anthropic's production research
115
140
  system](https://www.anthropic.com/engineering/multi-agent-research-system)
@@ -136,6 +161,8 @@ the authoritative original user goal. A planner may shorten the research
136
161
  question, but cannot silently drop requirements such as “compare at least three
137
162
  independent primary sources,” “read a paper/PDF when available,” or “include
138
163
  negative evidence.” These requirements are fingerprinted and checkpointed.
164
+ The same contract covers practical recommendations, reproducible verification
165
+ methods, and exact-quote evidence appendices.
139
166
 
140
167
  Planning and evidence extraction deliberately use the configured routing model
141
168
  when it belongs to a hosted active provider. Synthesis uses the configured main
@@ -187,7 +214,10 @@ To resume a partial or completed same-query run, pass the returned
187
214
  `refresh=true` is explicit. A transient run that retrieved zero allowed sources
188
215
  is marked failed, preserves its attempts, and retries retrieval on resume
189
216
  instead of caching an empty report as success. Checkpoint schema changes
190
- invalidate old cached runs automatically.
217
+ invalidate old cached runs automatically. The public tool result also carries
218
+ the research schema version; the outer session reuses a completed result only
219
+ when that version matches the installed engine. Versionless or older retained
220
+ results are refreshed instead of being presented as current evidence.
191
221
 
192
222
  `outputPath` is optional and must name a Markdown file inside the active
193
223
  workspace. Repository internals such as `.git`, dependency trees such as
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.241",
3
+ "version": "0.20.243",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -66,6 +66,7 @@
66
66
  "scripts/supervision-ledger.js",
67
67
  "scripts/smoke-supervision-ledger.js",
68
68
  "scripts/smoke-integration-production-mount.js",
69
+ "scripts/smoke-integration-production-runtime-bundle.js",
69
70
  "scripts/smoke-integration-storage-authority.js",
70
71
  "scripts/smoke-integration-retained-durable-common.js",
71
72
  "scripts/smoke-integration-retained-file-lock.js",
@@ -203,6 +204,7 @@
203
204
  "supervision:ledger": "node scripts/supervision-ledger.js",
204
205
  "smoke:supervision-ledger": "node scripts/smoke-supervision-ledger.js",
205
206
  "smoke:integration-production-mount": "node scripts/smoke-integration-production-mount.js",
207
+ "smoke:integration-production-runtime-bundle": "node scripts/smoke-integration-production-runtime-bundle.js",
206
208
  "smoke:integration-storage-authority": "node scripts/smoke-integration-storage-authority.js",
207
209
  "smoke:integration-retained-durable-common": "node scripts/smoke-integration-retained-durable-common.js",
208
210
  "smoke:integration-retained-file-lock": "node scripts/smoke-integration-retained-file-lock.js",
@@ -219,7 +221,7 @@
219
221
  "storage:migrate": "node bin/aginti-cli.js storage migrate",
220
222
  "publish:env": "node scripts/npm-publish-from-env.js publish --access public",
221
223
  "publish:env:whoami": "node scripts/npm-publish-from-env.js whoami",
222
- "test": "npm run check && npm run smoke:integration-production-mount && npm run smoke:integration-storage-authority && npm run smoke:integration-retained-durable-common && npm run smoke:integration-retained-file-lock && npm run smoke:integration-retained-event-ledger && npm run smoke:integration-retained-event-ledger-bundle && npm run smoke:integration-retained-repository-kernel && npm run smoke:integration-retained-session-state-store && npm run smoke:integration-retained-native-session-repository-state && npm run smoke:integration-retained-native-execution-evidence && npm run smoke:integration-retained-runtime-repository-surface && npm run smoke:integration-retained-runtime-repository-phase-b && npm run smoke:integration-runtime-repository-contract && npm run smoke:integration-runtime-authority && npm run smoke:localllm-provider && npm run smoke:localllm-model-tiers && npm run smoke:localllm-code-routing && npm run smoke:local-failure-recovery && npm run smoke:localllm-auto-max && npm run smoke:local-resource-policy && npm run smoke:context-budget-recovery && npm run smoke:session-runtime && npm run smoke:runtime-core && npm run smoke:progressive-tools && npm run smoke:truthful-completion && npm run smoke:document-artifact-quality && npm run smoke:writing-specialist-routing && npm run eval:local-first-agent && npm run eval:provider-attribution && npm run smoke:runtime-compat && npm run smoke:autoupdate && npm run smoke:web-api && npm run smoke:math-rendering && npm run smoke:web-ui && npm run smoke:web-autostart && npm run smoke:webapp-command && npm run smoke:web-port-fallback && npm run smoke:docker-command && npm run smoke:coding-tools && npm run smoke:dynamic-step-budget && npm run smoke:execution-policy && npm run smoke:aaps-adapter && npm run smoke:auxiliary-tools && npm run smoke:perception-research && npm run smoke:deep-research && npm run smoke:public-research && npm run smoke:safe-chat && npm run smoke:auth && npm run smoke:agentlink && npm run smoke:canvas-artifacts && npm run smoke:capabilities && npm run smoke:mcp && npm run smoke:model-roles && npm run smoke:platform && npm run smoke:permission-modes && npm run smoke:skills && npm run smoke:skillmesh && npm run smoke:supervision-ledger && npm run smoke:tmux-tools && npm run smoke:long-jobs && npm run smoke:run-stdin && npm run smoke:cli-chat && npm run smoke:inbox",
224
+ "test": "npm run check && npm run smoke:integration-production-mount && npm run smoke:integration-production-runtime-bundle && npm run smoke:integration-storage-authority && npm run smoke:integration-retained-durable-common && npm run smoke:integration-retained-file-lock && npm run smoke:integration-retained-event-ledger && npm run smoke:integration-retained-event-ledger-bundle && npm run smoke:integration-retained-repository-kernel && npm run smoke:integration-retained-session-state-store && npm run smoke:integration-retained-native-session-repository-state && npm run smoke:integration-retained-native-execution-evidence && npm run smoke:integration-retained-runtime-repository-surface && npm run smoke:integration-retained-runtime-repository-phase-b && npm run smoke:integration-runtime-repository-contract && npm run smoke:integration-runtime-authority && npm run smoke:localllm-provider && npm run smoke:localllm-model-tiers && npm run smoke:localllm-code-routing && npm run smoke:local-failure-recovery && npm run smoke:localllm-auto-max && npm run smoke:local-resource-policy && npm run smoke:context-budget-recovery && npm run smoke:session-runtime && npm run smoke:runtime-core && npm run smoke:progressive-tools && npm run smoke:truthful-completion && npm run smoke:document-artifact-quality && npm run smoke:writing-specialist-routing && npm run eval:local-first-agent && npm run eval:provider-attribution && npm run smoke:runtime-compat && npm run smoke:autoupdate && npm run smoke:web-api && npm run smoke:math-rendering && npm run smoke:web-ui && npm run smoke:web-autostart && npm run smoke:webapp-command && npm run smoke:web-port-fallback && npm run smoke:docker-command && npm run smoke:coding-tools && npm run smoke:dynamic-step-budget && npm run smoke:execution-policy && npm run smoke:aaps-adapter && npm run smoke:auxiliary-tools && npm run smoke:perception-research && npm run smoke:deep-research && npm run smoke:public-research && npm run smoke:safe-chat && npm run smoke:auth && npm run smoke:agentlink && npm run smoke:canvas-artifacts && npm run smoke:capabilities && npm run smoke:mcp && npm run smoke:model-roles && npm run smoke:platform && npm run smoke:permission-modes && npm run smoke:skills && npm run smoke:skillmesh && npm run smoke:supervision-ledger && npm run smoke:tmux-tools && npm run smoke:long-jobs && npm run smoke:run-stdin && npm run smoke:cli-chat && npm run smoke:inbox",
223
225
  "pack:dry-run": "npm pack --dry-run",
224
226
  "smoke:capabilities": "node scripts/smoke-capabilities.js"
225
227
  },
@@ -3,7 +3,7 @@ import fs from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
5
5
 
6
- import { auditResearchSynthesis, deepResearch } from "../src/deep-research.js";
6
+ import { auditResearchSynthesis, deepResearch, RESEARCH_VERSION } from "../src/deep-research.js";
7
7
  import { checkToolUse } from "../src/guardrails.js";
8
8
  import { flushHousekeeping } from "../src/housekeeping.js";
9
9
  import { requestNextStep, toolChoiceForProvider } from "../src/model-client.js";
@@ -59,6 +59,50 @@ async function main() {
59
59
  !shouldStartWithDeepResearch(localEvidenceGoal),
60
60
  "local-source research incorrectly forced deep_research before workspace inspection"
61
61
  );
62
+ const inspectedLocalEvidenceMessages = [
63
+ { role: "user", content: localEvidenceGoal },
64
+ {
65
+ role: "assistant",
66
+ tool_calls: [{ id: "inspect-notes", function: { name: "read_file", arguments: '{"path":"PROJECT_NOTES.md"}' } }],
67
+ },
68
+ {
69
+ role: "assistant",
70
+ tool_calls: [{ id: "inspect-sources", function: { name: "read_file", arguments: '{"path":"sources.json"}' } }],
71
+ },
72
+ ];
73
+ assert(
74
+ shouldStartWithDeepResearch(localEvidenceGoal, inspectedLocalEvidenceMessages),
75
+ "local-source research did not enter bounded deep research after workspace inspection"
76
+ );
77
+ assert(
78
+ !shouldStartWithDeepResearch(localEvidenceGoal, [
79
+ ...inspectedLocalEvidenceMessages,
80
+ {
81
+ role: "assistant",
82
+ tool_calls: [{ id: "current-research", function: { name: "deep_research", arguments: "{}" } }],
83
+ },
84
+ ]),
85
+ "the current request repeated deep research after already requesting it"
86
+ );
87
+ assert(
88
+ shouldStartWithDeepResearch(localEvidenceGoal, [
89
+ ...inspectedLocalEvidenceMessages,
90
+ {
91
+ role: "assistant",
92
+ tool_calls: [{ id: "old-research", function: { name: "deep_research", arguments: "{}" } }],
93
+ },
94
+ { role: "user", content: "Refresh this evidence review because the current report quality is not acceptable." },
95
+ {
96
+ role: "assistant",
97
+ tool_calls: [{ id: "refresh-report", function: { name: "read_file", arguments: '{"path":"agent-reliability-evidence-review.md"}' } }],
98
+ },
99
+ {
100
+ role: "assistant",
101
+ tool_calls: [{ id: "refresh-sources", function: { name: "read_file", arguments: '{"path":"sources.json"}' } }],
102
+ },
103
+ ]),
104
+ "a completed research call from an older user intent suppressed a fresh bounded research pass"
105
+ );
62
106
  assert(
63
107
  shouldStartWithDeepResearch("Write a deep web research report comparing three primary papers."),
64
108
  "standalone deep research no longer starts with the bounded research workflow"
@@ -441,6 +485,7 @@ async function main() {
441
485
  ],
442
486
  }],
443
487
  keyFindings: [{ claim: "Claims retain exact evidence IDs.", evidenceIds: ["S1-C1", "S2-C1"], confidence: "high" }],
488
+ recommendations: [],
444
489
  contradictions: [],
445
490
  uncertainties: [],
446
491
  nextQuestions: [],
@@ -508,6 +553,7 @@ async function main() {
508
553
  },
509
554
  store
510
555
  );
556
+ assert(research.version === RESEARCH_VERSION, "deep research did not expose its result-schema version");
511
557
  assert(research.ok && research.sourceCount === 2, `deep research failed: ${research.error || "unknown"}`);
512
558
  assert(
513
559
  researchSearchProviders.length === 2 && researchSearchProviders.every((provider) => provider === "multi"),
@@ -601,6 +647,7 @@ async function main() {
601
647
  executiveSummaryEvidenceIds: ["S1-C1"],
602
648
  sections: [{ heading: "Claim", paragraphs: [{ text: "The gain was measured.", evidenceIds: ["S1-C1"] }] }],
603
649
  keyFindings: [],
650
+ recommendations: [],
604
651
  contradictions: [],
605
652
  uncertainties: ["The exact source was inaccessible."],
606
653
  nextQuestions: [],
@@ -734,6 +781,7 @@ async function main() {
734
781
  { claim: "A second independent source corroborates the measurement.", evidenceIds: ["S2-C1"], confidence: "high" },
735
782
  { claim: "A third independent source supplies separate evidence.", evidenceIds: ["S3-C1"], confidence: "high" },
736
783
  ],
784
+ recommendations: [],
737
785
  contradictions: [],
738
786
  uncertainties: ["Benchmark scope remains limited."],
739
787
  nextQuestions: [],
@@ -1004,6 +1052,95 @@ async function main() {
1004
1052
  "a bounded official PDF was still constrained by the generic 2 MiB page limit"
1005
1053
  );
1006
1054
 
1055
+ const namedOfficialResearch = await deepResearch(
1056
+ {
1057
+ query: "Compare official Temporal docs and official LangGraph docs for durable agent execution.",
1058
+ depth: "quick",
1059
+ sourcePolicy: "primary",
1060
+ maxQueries: 1,
1061
+ maxSources: 2,
1062
+ gapPasses: 0,
1063
+ researchId: "named-official-products-smoke",
1064
+ outputPath: "reports/named-official-products.md",
1065
+ dryRun: true,
1066
+ },
1067
+ {
1068
+ provider: "mock",
1069
+ model: "mock-agent",
1070
+ commandCwd: researchWorkspace,
1071
+ webSearchImpl: async ({ query }) => ({
1072
+ ok: true,
1073
+ toolName: "web_search",
1074
+ provider: "test",
1075
+ query,
1076
+ results: /official system card engineering blog architecture/i.test(query)
1077
+ ? [
1078
+ {
1079
+ rank: 1,
1080
+ title: "Durable Execution Solutions",
1081
+ url: "https://temporal.io/blog/durable-execution-solutions",
1082
+ canonicalUrl: "https://temporal.io/blog/durable-execution-solutions",
1083
+ domain: "temporal.io",
1084
+ snippet: "Temporal explains durable execution and workflow recovery.",
1085
+ provider: "test",
1086
+ },
1087
+ {
1088
+ rank: 2,
1089
+ title: "Third-party retry commentary",
1090
+ url: "https://appscale.example.org/blog/retry-commentary",
1091
+ canonicalUrl: "https://appscale.example.org/blog/retry-commentary",
1092
+ domain: "appscale.example.org",
1093
+ snippet: "A secondary opinion about retry behavior.",
1094
+ provider: "test",
1095
+ },
1096
+ ]
1097
+ : [
1098
+ {
1099
+ rank: 1,
1100
+ title: "LangGraph",
1101
+ url: "https://www.langchain.com/langgraph",
1102
+ canonicalUrl: "https://www.langchain.com/langgraph",
1103
+ domain: "langchain.com",
1104
+ snippet: "LangGraph provides durable execution for long-running stateful agents.",
1105
+ provider: "test",
1106
+ },
1107
+ {
1108
+ rank: 2,
1109
+ title: "Generic durable systems survey",
1110
+ url: "https://link.springer.com/article/generic-durable-systems",
1111
+ canonicalUrl: "https://link.springer.com/article/generic-durable-systems",
1112
+ domain: "link.springer.com",
1113
+ snippet: "A broad survey with little agent-specific implementation detail.",
1114
+ provider: "test",
1115
+ },
1116
+ ],
1117
+ }),
1118
+ webPageReaderImpl: async ({ url }) => ({
1119
+ ok: true,
1120
+ toolName: "read_web_page",
1121
+ url,
1122
+ title: url.includes("temporal.io") ? "Temporal Durable Execution" : "LangGraph",
1123
+ readable: true,
1124
+ contentType: "text/html",
1125
+ retrievedAt: "2026-08-25T00:00:00.000Z",
1126
+ sha256: (url.includes("temporal.io") ? "1" : "2").repeat(64),
1127
+ content: "The official product page documents durable execution, checkpointing, and recovery behavior.",
1128
+ passages: ["The official product page documents durable execution, checkpointing, and recovery behavior."],
1129
+ }),
1130
+ },
1131
+ new SessionStore(path.join(tempRoot, "sessions"), "named-official-products-smoke")
1132
+ );
1133
+ assert(namedOfficialResearch.ok, `named official product research failed: ${namedOfficialResearch.error || "unknown"}`);
1134
+ assert(namedOfficialResearch.requirements.officialDiscovery, "'official Temporal docs' did not preserve first-party discovery intent");
1135
+ assert(
1136
+ namedOfficialResearch.sources.map((source) => source.domain).sort().join(",") === "langchain.com,temporal.io",
1137
+ `named first-party product pages were displaced by weaker filler: ${namedOfficialResearch.sources.map((source) => source.domain).join(", ")}`
1138
+ );
1139
+ assert(namedOfficialResearch.sources.every((source) => source.firstParty), "a named official product root was not classified as first-party");
1140
+ const namedOfficialReport = await fs.readFile(namedOfficialResearch.reportPath, "utf8");
1141
+ assert(namedOfficialReport.includes("## Limitations, Uncertainties, And Coverage Gaps"), "research report omitted an explicit limitations section");
1142
+ assert(namedOfficialReport.includes("## Sources Inspected But Not Cited"), "dry-run report hid the uncited-source boundary");
1143
+
1007
1144
  const scholarlyGapCalls = [];
1008
1145
  const scholarlyGapResearch = await deepResearch(
1009
1146
  {
@@ -1070,6 +1207,7 @@ async function main() {
1070
1207
  paragraphs: [{ text: "Two primary sources support the result.", evidenceIds: ["S1-C1", "S2-C1"] }],
1071
1208
  }],
1072
1209
  keyFindings: [{ claim: "Independent evidence was recovered.", evidenceIds: ["S1-C1", "S2-C1"], confidence: "high" }],
1210
+ recommendations: [],
1073
1211
  contradictions: [],
1074
1212
  uncertainties: [],
1075
1213
  nextQuestions: [],
@@ -1209,6 +1347,7 @@ async function main() {
1209
1347
  evidenceIds: ["S1-C1", "S2-C1", "S3-C1"],
1210
1348
  confidence: "high",
1211
1349
  }],
1350
+ recommendations: [],
1212
1351
  contradictions: [],
1213
1352
  uncertainties: ["Real throughput depends on local hardware."],
1214
1353
  nextQuestions: [],
@@ -4,6 +4,7 @@ import os from "node:os";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { runAgent } from "../src/agent-runner.js";
7
+ import { RESEARCH_VERSION } from "../src/deep-research.js";
7
8
  import { resolveRuntimeConfig } from "../src/config.js";
8
9
  import { classifyCommand, evaluateCommandPolicy } from "../src/command-policy.js";
9
10
  import {
@@ -4338,6 +4339,7 @@ try {
4338
4339
  {
4339
4340
  ok: true,
4340
4341
  toolName: "deep_research",
4342
+ version: RESEARCH_VERSION,
4341
4343
  researchId: "research-one",
4342
4344
  status: "completed",
4343
4345
  reportPath: path.join(workspace, "report.md"),
@@ -4354,6 +4356,16 @@ try {
4354
4356
  reusedResearch?.duplicateSuppressed && reusedResearch.reportPath === path.join(workspace, "report.md"),
4355
4357
  "same-goal deep research did not reuse an already completed exact report"
4356
4358
  );
4359
+ completedResearchState.meta.completedDeepResearch[0].result.version = RESEARCH_VERSION - 1;
4360
+ assert(
4361
+ completedDeepResearchReuse(
4362
+ completedResearchState,
4363
+ { query: "A model-expanded query", outputPath: "report.md", refresh: true },
4364
+ { commandCwd: workspace }
4365
+ ) === null,
4366
+ "a stale deep-research engine result was reused after the report contract changed"
4367
+ );
4368
+ completedResearchState.meta.completedDeepResearch[0].result.version = RESEARCH_VERSION;
4357
4369
  completedResearchState.meta.goalContract = { revision: 2, currentHash: "goal-two" };
4358
4370
  assert(
4359
4371
  completedDeepResearchReuse(
@@ -547,6 +547,7 @@ async function verifyPackagedBinAndScriptClosure() {
547
547
  "scripts/eval-provider-attribution.js",
548
548
  "scripts/smoke-context-budget-recovery.js",
549
549
  "scripts/smoke-integration-production-mount.js",
550
+ "scripts/smoke-integration-production-runtime-bundle.js",
550
551
  ]) {
551
552
  assert.equal(packageJson.files.includes(requiredFile), true);
552
553
  }
@@ -1087,6 +1088,38 @@ async function main() {
1087
1088
  "INTEGRATION_CREDENTIAL_SOURCE_FORBIDDEN"
1088
1089
  );
1089
1090
 
1091
+ let cliCheckOutput = "";
1092
+ await withCanonicalCredentialFixture(async () => {
1093
+ const summary = await integrationCliMain(["check", "--config", configPath], {
1094
+ env: { CREDENTIALS_DIRECTORY: INTEGRATION_SYSTEMD_CREDENTIALS_DIRECTORY },
1095
+ stdout: { write(chunk) { cliCheckOutput += String(chunk); } },
1096
+ });
1097
+ assert.equal(summary.status, "checked-disabled");
1098
+ assert.equal(summary.capability?.enabled, false);
1099
+ assert.equal(summary.implementationReady, false);
1100
+ assert.equal(typeof summary.runtimeBundle?.healthy, "boolean");
1101
+ assert.equal(summary.runtimeBundle?.implementationReady, false);
1102
+ assert.equal(summary.runtimeBundle?.capabilityEnabled, false);
1103
+ assert.equal(summary.runtimeBundle?.httpServingEnabled, false);
1104
+ if (summary.runtimeBundle.healthy) {
1105
+ assert.equal(summary.runtimeBundle.firstBlocker?.component, "idempotencyStore");
1106
+ assert.equal(
1107
+ summary.runtimeBundle.firstBlocker?.code,
1108
+ "INTEGRATION_DESCRIPTOR_BOUND_IDEMPOTENCY_UNAVAILABLE"
1109
+ );
1110
+ } else {
1111
+ assert.equal(summary.runtimeBundle.firstBlocker?.component, "storageAuthority");
1112
+ assert.match(
1113
+ summary.runtimeBundle.firstBlocker?.code || "",
1114
+ /^INTEGRATION_STORAGE_/u
1115
+ );
1116
+ }
1117
+ assert.deepEqual(
1118
+ JSON.parse(cliCheckOutput.trim()),
1119
+ JSON.parse(JSON.stringify(summary))
1120
+ );
1121
+ });
1122
+
1090
1123
  const cliServePort = await unusedLoopbackPort();
1091
1124
  const cliServeConfigPath = path.join(tempRoot, "integration-serve.json");
1092
1125
  await fs.writeFile(