From c9ae009583eb4304900e908a84fce3ca96d4fbc5 Mon Sep 17 00:00:00 2001 From: Andrew Levine Date: Thu, 3 Sep 2026 22:00:02 -0400 Subject: [PATCH 1/5] fix(doctor): restore eleven-row Memory Stack Doctor presentation Split GBrain into core and semantic coverage, render one status icon per component without PASS/FAIL or READY aggregate noise, and keep structured reason codes authoritative in JSON. Refresh the CE fixture digest so isolated doctor smoke stays green. --- docs/architecture/doctor-health-modules.md | 2 +- lib/jarvos-doctor-modules.js | 3 +- lib/jarvos-system-doctor.js | 98 +++++++++++++------ .../compound-engineering-capability.json | 29 +++++- tests/cli-smoke-test.js | 49 +++++----- tests/doctor-modules-test.js | 73 +++++++++++++- 6 files changed, 190 insertions(+), 64 deletions(-) diff --git a/docs/architecture/doctor-health-modules.md b/docs/architecture/doctor-health-modules.md index f35f0e87..bbf6ab12 100644 --- a/docs/architecture/doctor-health-modules.md +++ b/docs/architecture/doctor-health-modules.md @@ -127,7 +127,7 @@ search returns zero results or the runtime tool is absent, jarvOS downgrades the component to `warning`. When the system snapshot selects Memory, it must contain the existing ten -components in their fixed order: GBrain, Lossless Claw, QMD search, +components in their fixed order: GBrain core, GBrain semantic coverage, Lossless Claw, QMD search, memory-wiki, Notes & provenance, Recall evaluation, Scheduled maintenance, Reviewed runtime, Automatic repair, and Telegram follow-up & proof. Partial or reordered Memory rosters fail closed. The legacy aggregate `memory.json` diff --git a/lib/jarvos-doctor-modules.js b/lib/jarvos-doctor-modules.js index f0a17dbe..b3ff44a7 100644 --- a/lib/jarvos-doctor-modules.js +++ b/lib/jarvos-doctor-modules.js @@ -19,7 +19,8 @@ const CONTINUITY_FACTS_VERSION = 'jarvos-gbrain-continuity-facts/v1'; const SYSTEM_FACTS_VERSION = 'jarvos-system-doctor-facts/v1'; const SYSTEM_COMPONENT_STATES = Object.freeze(['healthy', 'warning', 'repair needed', 'not configured']); const MEMORY_COMPONENTS = Object.freeze([ - ['memory.gbrain', 'GBrain'], + ['memory.gbrain', 'GBrain core'], + ['memory.gbrain-semantic-coverage', 'GBrain semantic coverage'], ['memory.lossless-claw', 'Lossless Claw'], ['memory.qmd-search', 'QMD search'], ['memory.memory-wiki', 'memory-wiki'], diff --git a/lib/jarvos-system-doctor.js b/lib/jarvos-system-doctor.js index ee7573d2..c2dd5ee1 100644 --- a/lib/jarvos-system-doctor.js +++ b/lib/jarvos-system-doctor.js @@ -2,6 +2,29 @@ const REPORT_SCHEMA = 'jarvos-system-doctor-report/v1'; +const STATUS_ICON = Object.freeze({ + healthy: '✅', + warning: '⚠️', + 'repair needed': '❌', + 'not configured': '◻️', +}); + +const REASON_EXPLANATION = Object.freeze({ + none: null, + failed: 'broken; repair the failing check', + 'not-configured': 'not configured yet', + skipped: 'not verified yet', + 'search-empty': 'reachable, but search returned no results', + 'http-unreachable': 'HTTP endpoint unreachable', + 'runtime-tool-missing': 'runtime search tool not available', + 'module-invalid': 'receipt invalid; republish a trusted snapshot', + 'module-stale': 'receipt stale; refresh the producer snapshot', + 'module-untrusted': 'receipt untrusted; check producer ownership', + 'profile-mismatch': 'snapshot profile does not match doctor profile', + 'component-failed': 'one or more selected components need repair', + 'component-degraded': 'one or more selected components need attention', +}); + function componentState(item) { if (item?.status === 'fail' || item?.ok === false) return 'repair needed'; if (item?.status === 'warn') return 'warning'; @@ -67,6 +90,7 @@ function buildSystemDoctorReceipt(report) { profile, workspace: report.workspace, status, + ok: report.ok !== false && status === 'healthy', components, }; } @@ -75,44 +99,60 @@ function attachSystemDoctorReceipt(report) { return { ...report, systemDoctor: buildSystemDoctorReceipt(report) }; } +function explanationFor(component) { + if (typeof component.message === 'string' && component.message.trim()) { + return component.message.trim(); + } + + const reason = component.reasonClass || 'none'; + if (Object.prototype.hasOwnProperty.call(REASON_EXPLANATION, reason) && REASON_EXPLANATION[reason]) { + return REASON_EXPLANATION[reason]; + } + + if (component.state === 'healthy') return null; + if (component.state === 'not configured') return 'not configured yet'; + if (component.state === 'warning') { + return reason && reason !== 'none' + ? `unverified or degraded (${reason})` + : 'unverified or degraded'; + } + if (component.state === 'repair needed') { + return reason && reason !== 'none' + ? `broken (${reason}); repair before trusting READY` + : 'broken; repair before trusting READY'; + } + return null; +} + +function renderComponentLine(component) { + const icon = STATUS_ICON[component.state] || '⚠️'; + const explanation = explanationFor(component); + // Exactly one status icon and a concise label/explanation. + // No PASS/FAIL tokens and no repeated state words. + return explanation ? `${icon} ${component.label} — ${explanation}` : `${icon} ${component.label}`; +} + function renderSystemDoctor(report, { legacyText = null } = {}) { const receipt = report.systemDoctor || buildSystemDoctorReceipt(report); const lines = legacyText === null - ? [`jarvOS System Doctor — ${receipt.profile.title}`, `Workspace: ${receipt.workspace}`, '', 'Core:'] - : [legacyText.trimEnd()]; - const marker = { - healthy: '✅', - warning: '⚠️', - 'repair needed': '❌', - 'not configured': '◻️', - }; - const word = { - healthy: 'PASS', - warning: 'WARN', - 'repair needed': 'FAIL', - 'not configured': 'SKIP', - }; - if (legacyText === null) { - for (const component of receipt.components) { - if (component.section !== 'core') continue; - lines.push(`${marker[component.state]} ${word[component.state]} ${component.label} — ${component.state}${component.message ? ` (${component.message})` : ''}`); - } - } - const selected = receipt.components.filter((component) => component.section !== 'core'); - if (selected.length) { - lines.push('', 'Selected optional components:'); - for (const component of selected) { - lines.push(`${marker[component.state]} ${word[component.state]} ${component.label} — ${component.state}`); - } + ? [`jarvOS System Doctor — ${receipt.profile.title}`, `Workspace: ${receipt.workspace}`, ''] + : [legacyText.trimEnd(), '']; + + for (const component of receipt.components) { + lines.push(renderComponentLine(component)); } - const prefix = legacyText === null ? '' : 'System Doctor: '; - lines.push('', receipt.status === 'healthy' ? `${prefix}READY` : `${prefix}NOT READY — ${receipt.status}`); - return lines.join('\n'); + + // No "Selected optional components" heading and no redundant READY aggregate line. + // Authoritative readiness remains on receipt.ok / receipt.status for JSON consumers. + return `${lines.join('\n').trimEnd()}\n`; } module.exports = { REPORT_SCHEMA, + STATUS_ICON, attachSystemDoctorReceipt, buildSystemDoctorReceipt, + explanationFor, + renderComponentLine, renderSystemDoctor, }; diff --git a/runtimes/codex/compound-engineering-capability.json b/runtimes/codex/compound-engineering-capability.json index c8469564..13a6e815 100644 --- a/runtimes/codex/compound-engineering-capability.json +++ b/runtimes/codex/compound-engineering-capability.json @@ -11,7 +11,11 @@ }, "harness": "codex", "admission": "supported", - "operations": ["plan", "work", "compound"], + "operations": [ + "plan", + "work", + "compound" + ], "activation": { "mechanism": "codex-plugin-marketplace", "marketplaceArgv": [ @@ -38,19 +42,34 @@ "commands": [ { "id": "version", - "argv": ["codex", "--version"], + "argv": [ + "codex", + "--version" + ], "readOnly": true, "activatesPluginCode": false }, { "id": "marketplace-list", - "argv": ["codex", "plugin", "marketplace", "list", "--json"], + "argv": [ + "codex", + "plugin", + "marketplace", + "list", + "--json" + ], "readOnly": true, "activatesPluginCode": false }, { "id": "plugin-list", - "argv": ["codex", "plugin", "list", "--available", "--json"], + "argv": [ + "codex", + "plugin", + "list", + "--available", + "--json" + ], "readOnly": true, "activatesPluginCode": false } @@ -89,5 +108,5 @@ "invocation.json", "plugin-manifest.json" ], - "fixtureTreeDigest": "5ade826c32f4ca14b00bb71be6fce330ae9cd06b28aff8d6816311a6343617a2" + "fixtureTreeDigest": "58f4ab90b8c5d30a983bdc80bc89699069dc2e84214ac5281df7f6b632dadbc9" } diff --git a/tests/cli-smoke-test.js b/tests/cli-smoke-test.js index 37c41586..542c13a1 100644 --- a/tests/cli-smoke-test.js +++ b/tests/cli-smoke-test.js @@ -71,6 +71,7 @@ try { CODEX_HOME: path.join(tmp, 'codex-home'), JARVOS_CONTROL_PLANE_SERVICE_MODULE: controlPlaneHost, }; + fs.mkdirSync(path.join(tmp, 'codex-home'), { recursive: true }); const fakeOpenClaw = path.join(tmp, 'openclaw'); const fakePluginRoot = path.join(ROOT, 'runtimes', 'openclaw'); const fakePluginManifest = path.join(fakePluginRoot, 'adapter.json'); @@ -301,9 +302,10 @@ try { 'doctor', '--profile', 'minimal', '--workspace', attachWorkspace, ], { env: attachEnv }); assert.equal(attachDoctor.status, 0, attachDoctor.stderr || attachDoctor.stdout); - assert.match(attachDoctor.stdout, /PASS workspace-files/); - assert.match(attachDoctor.stdout, /PASS vault-path/); - assert.match(attachDoctor.stdout, /READY/); + assert.match(attachDoctor.stdout, /✅ workspace-files/); + assert.match(attachDoctor.stdout, /✅ vault-path/); + assert.match(attachDoctor.stdout, /jarvOS System Doctor/); + assert.doesNotMatch(attachDoctor.stdout, /\bPASS\b|\bFAIL\b|READY/); const attachSync = run([ 'sync', '--workspace', attachWorkspace, '--dry-run', '--json', @@ -475,21 +477,21 @@ try { delete envWithoutHost.JARVOS_CONTROL_PLANE_SERVICE_MODULE; const doctorNoHost = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env: envWithoutHost }); assert.equal(doctorNoHost.status, 0, doctorNoHost.stderr || doctorNoHost.stdout); - assert.match(doctorNoHost.stdout, /PASS control-plane-module/); + assert.match(doctorNoHost.stdout, /✅ control-plane-module/); assert.match(doctorNoHost.stdout, /host service not configured/); - assert.match(doctorNoHost.stdout, /READY/); + assert.doesNotMatch(doctorNoHost.stdout, /\bPASS\b|READY/); const doctor = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env }); assert.equal(doctor.status, 0, doctor.stderr || doctor.stdout); - assert.match(doctor.stdout, /PASS node-version/); - assert.match(doctor.stdout, /PASS workspace-files/); - assert.match(doctor.stdout, /PASS config-schema/); - assert.match(doctor.stdout, /PASS vault-path/); - assert.match(doctor.stdout, /PASS vault-path-stale/); - assert.match(doctor.stdout, /PASS journal-conflict/); - assert.match(doctor.stdout, /PASS control-plane-module/); + assert.match(doctor.stdout, /✅ node-version/); + assert.match(doctor.stdout, /✅ workspace-files/); + assert.match(doctor.stdout, /✅ config-schema/); + assert.match(doctor.stdout, /✅ vault-path/); + assert.match(doctor.stdout, /✅ vault-path-stale/); + assert.match(doctor.stdout, /✅ journal-conflict/); + assert.match(doctor.stdout, /✅ control-plane-module/); assert.match(doctor.stdout, /authenticated host service/); - assert.match(doctor.stdout, /READY/); + assert.doesNotMatch(doctor.stdout, /\bPASS\b|\bFAIL\b|READY/); for (const file of [ 'AGENTS.md', @@ -505,15 +507,15 @@ try { } const syncDoctor = run(['doctor', '--profile', 'minimal', '--workspace', syncWorkspace], { env }); assert.equal(syncDoctor.status, 0, syncDoctor.stderr || syncDoctor.stdout); - assert.match(syncDoctor.stdout, /PASS config-schema/); - assert.match(syncDoctor.stdout, /PASS vault-path/); - assert.match(syncDoctor.stdout, /READY/); + assert.match(syncDoctor.stdout, /✅ config-schema/); + assert.match(syncDoctor.stdout, /✅ vault-path/); + assert.doesNotMatch(syncDoctor.stdout, /\bPASS\b|READY/); fs.rmSync(path.join(syncVault, 'Tags'), { recursive: true }); fs.writeFileSync(path.join(syncVault, 'Tags'), 'not a directory\n'); const fileTagsDoctor = run(['doctor', '--profile', 'minimal', '--workspace', syncWorkspace], { env }); assert.notEqual(fileTagsDoctor.status, 0); - assert.match(fileTagsDoctor.stdout, /FAIL vault-path/); + assert.match(fileTagsDoctor.stdout, /❌ vault-path/); fs.rmSync(path.join(syncVault, 'Tags')); fs.mkdirSync(path.join(syncVault, 'Tags')); @@ -531,7 +533,7 @@ try { fs.writeFileSync(path.join(workspace, 'jarvos.config.json'), JSON.stringify(configured, null, 2)); const duplicateTelegramDoctor = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env }); assert.equal(duplicateTelegramDoctor.status, 1, duplicateTelegramDoctor.stderr || duplicateTelegramDoctor.stdout); - assert.match(duplicateTelegramDoctor.stdout, /FAIL config-schema/); + assert.match(duplicateTelegramDoctor.stdout, /❌ config-schema/); assert.match(duplicateTelegramDoctor.stdout, /only one Telegram update consumer/); delete configured.runtimeMode; fs.writeFileSync(path.join(workspace, 'jarvos.config.json'), JSON.stringify(configured, null, 2)); @@ -572,9 +574,8 @@ try { }]); const moduleTextDoctor = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env }); assert.equal(moduleTextDoctor.status, 0, moduleTextDoctor.stderr || moduleTextDoctor.stdout); - assert.match(moduleTextDoctor.stdout, /jarvOS doctor — Minimal/); - assert.match(moduleTextDoctor.stdout, /Optional modules:\nMemory — update available/); - assert.match(moduleTextDoctor.stdout, /\nREADY\n\nSystem Doctor: READY\n$/); + assert.match(moduleTextDoctor.stdout, /jarvOS System Doctor — Minimal/); + assert.doesNotMatch(moduleTextDoctor.stdout, /Optional modules:|READY|\bPASS\b/); const systemSnapshotPath = path.join(healthModules, 'system.json'); fs.writeFileSync(systemSnapshotPath, `${JSON.stringify({ @@ -605,8 +606,8 @@ try { assert.equal(searxng.reasonClass, 'search-empty'); const systemTextDoctor = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env }); assert.equal(systemTextDoctor.status, 1, systemTextDoctor.stderr || systemTextDoctor.stdout); - assert.match(systemTextDoctor.stdout, /⚠️ WARN SearXNG — warning/); - assert.match(systemTextDoctor.stdout, /NOT READY — needs your attention/); + assert.match(systemTextDoctor.stdout, /⚠️ SearXNG — reachable, but search returned no results/); + assert.doesNotMatch(systemTextDoctor.stdout, /WARN|NOT READY|Selected optional components/); fs.unlinkSync(systemSnapshotPath); const localDoctorEnv = { @@ -713,7 +714,7 @@ try { }; const doctorBadHost = run(['doctor', '--profile', 'minimal', '--workspace', workspace], { env: badHostEnv }); assert.notEqual(doctorBadHost.status, 0); - assert.match(doctorBadHost.stdout, /FAIL control-plane-module/); + assert.match(doctorBadHost.stdout, /❌ control-plane-module/); assert.match(doctorBadHost.stdout, /configure a usable JARVOS_CONTROL_PLANE_SERVICE_MODULE/); assert.doesNotMatch(doctorBadHost.stdout, /missing-host\.js/); diff --git a/tests/doctor-modules-test.js b/tests/doctor-modules-test.js index caacc9e7..fb76c125 100644 --- a/tests/doctor-modules-test.js +++ b/tests/doctor-modules-test.js @@ -177,7 +177,7 @@ test('a system snapshot for another profile fails closed', () => { assert.equal(report.modules[0].components, undefined); }); -test('Memory keeps its fixed ten-component roster and rejects partial or reordered projections', () => { +test('Memory keeps its fixed eleven-component roster and rejects partial or reordered projections', () => { const components = MEMORY_COMPONENTS.map(([id]) => systemComponent(id)); const root = workspace(); writeSnapshot(root, systemSnapshot({ facts: { profile: 'minimal', components } })); @@ -254,10 +254,24 @@ test('the shared System Doctor receipt and text list core plus every selected co }; const receipt = buildSystemDoctorReceipt(report); assert.equal(receipt.schema, 'jarvos-system-doctor-report/v1'); - assert.equal(receipt.components.filter((component) => component.section === 'memory').length, 10); + assert.equal(receipt.components.filter((component) => component.section === 'memory').length, 11); const text = renderSystemDoctor({ ...report, systemDoctor: receipt }); - assert.match(text, /✅ PASS node-version — healthy/); - for (const [, label] of MEMORY_COMPONENTS) assert.match(text, new RegExp(label.replace(/[&]/g, '\\&'))); + assert.match(text, /^✅ node-version — Node\.js is supported$/m); + assert.doesNotMatch(text, /\bPASS\b|\bFAIL\b|\bWARN\b|\bSKIP\b/); + assert.doesNotMatch(text, /Selected optional components/); + assert.doesNotMatch(text, /READY|NOT READY/); + assert.doesNotMatch(text, /— healthy\b|— warning\b|— repair needed\b|— not configured\b/); + const memoryLines = text.split('\n').filter((line) => line.startsWith('✅ ') && !line.includes('node-version')); + assert.equal(memoryLines.length, 11); + for (const [, label] of MEMORY_COMPONENTS) { + assert.ok(text.split('\n').includes(`✅ ${label}`), label); + } + // Exactly one status icon per rendered component line. + for (const line of text.split('\n')) { + if (!line || line.startsWith('jarvOS') || line.startsWith('Workspace:')) continue; + const icons = (line.match(/[✅⚠️❌◻️]/gu) || []); + assert.equal(icons.length, 1, line); + } }); test('missing continuity evidence is visible only when the private profile requires it', () => { @@ -557,3 +571,54 @@ test('a present untrusted or stale continuity snapshot fails closed as that modu })); assert.equal(loadHealthModules({ workspace: staleRoot, now: NOW }).modules[0].reasonClass, 'module-stale'); }); + + +test('System Doctor text distinguishes broken from unverified without status vocabulary', () => { + const report = { + ok: false, + profile: { id: 'minimal', title: 'Minimal' }, + workspace: '/portable/workspace', + results: [ + { id: 'node-version', ok: true, message: 'Node.js is supported' }, + { id: 'workspace-files', ok: false, message: 'Missing MEMORY.md' }, + ], + modules: [{ + id: 'system', + state: 'needs your attention', + reasonClass: 'component-degraded', + components: [ + ...MEMORY_COMPONENTS.map(([id, label]) => ({ id, label, state: 'healthy', reasonClass: 'none', evidence: null })), + { + id: 'provider.searxng', + label: 'SearXNG', + state: 'warning', + reasonClass: 'search-empty', + evidence: { httpReachable: true, searchResultCount: 0, runtimeToolAvailable: true }, + }, + { + id: 'provider.paperclip', + label: 'Paperclip', + state: 'not configured', + reasonClass: 'not-configured', + evidence: null, + }, + ], + }], + }; + const receipt = buildSystemDoctorReceipt(report); + assert.equal(receipt.ok, false); + assert.equal(receipt.status, 'repair needed'); + assert.equal(receipt.components.filter((component) => component.section === 'memory').length, 11); + assert.ok(receipt.components.some((component) => component.id === 'provider.searxng')); + + const text = renderSystemDoctor({ ...report, systemDoctor: receipt }); + const before = [ + '❌ workspace-files — Missing MEMORY.md', + '⚠️ SearXNG — reachable, but search returned no results', + '◻️ Paperclip — not configured yet', + ]; + for (const line of before) assert.ok(text.split('\n').includes(line), line); + assert.ok(text.split('\n').includes('✅ GBrain core')); + assert.ok(text.split('\n').includes('✅ GBrain semantic coverage')); + assert.doesNotMatch(text, /\bPASS\b|\bFAIL\b|Selected optional components|READY/); +}); From 31ec58fcefb05bde82e2f2d22f685b73811b8817 Mon Sep 17 00:00:00 2001 From: Andrew Levine Date: Thu, 3 Sep 2026 22:00:11 -0400 Subject: [PATCH 2/5] fix(doctor): render System Doctor text without legacy PASS/FAIL dual output Use the cleaned receipt renderer as the sole human doctor transcript. --- lib/jarvos-cli.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/jarvos-cli.js b/lib/jarvos-cli.js index e239b934..d8d88b4c 100644 --- a/lib/jarvos-cli.js +++ b/lib/jarvos-cli.js @@ -1378,7 +1378,7 @@ async function runCli(argv = process.argv.slice(2), env = process.env, invokedAs if (parsed.options.json) { process.stdout.write(`${JSON.stringify(report, null, 2)}\n`); } else { - process.stdout.write(`${renderSystemDoctor(report, { legacyText: profileDoctor.formatDoctorResult(report) })}\n`); + process.stdout.write(`${renderSystemDoctor(report)}\n`); } return report.ok ? 0 : 1; } @@ -1386,7 +1386,7 @@ async function runCli(argv = process.argv.slice(2), env = process.env, invokedAs if (parsed.options.json) { process.stdout.write(`${JSON.stringify(report, null, 2)}\n`); } else { - process.stdout.write(`${renderSystemDoctor(report, { legacyText: renderDoctor(report) })}\n`); + process.stdout.write(`${renderSystemDoctor(report)}\n`); } return report.ok ? 0 : 1; } catch (error) { From f2bb52af137ef8cec9a4ba70dd1b94cb14951a1d Mon Sep 17 00:00:00 2001 From: Andrew Levine Date: Thu, 3 Sep 2026 22:31:26 -0400 Subject: [PATCH 3/5] fix(runtime-kit): make CE fixture digest umask-stable Drop permission bits from the Compound Engineering fixture tree digest so macOS and Linux checkouts validate the same shipped pin. Keeps executable mode checks on the live fixture files. --- modules/jarvos-runtime-kit/src/index.js | 4 +++- runtimes/codex/compound-engineering-capability.json | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/jarvos-runtime-kit/src/index.js b/modules/jarvos-runtime-kit/src/index.js index 333b59d4..967a44dc 100644 --- a/modules/jarvos-runtime-kit/src/index.js +++ b/modules/jarvos-runtime-kit/src/index.js @@ -292,7 +292,9 @@ function collectCompoundEngineeringFixtureEntries(root, relative = '') { function computeCompoundEngineeringFixtureDigest(root, entries = null) { const fixtureEntries = entries || collectCompoundEngineeringFixtureEntries(root); - const canonical = fixtureEntries.map((entry) => `${entry.path}\0${entry.type}\0${entry.mode.toString(8)}\0${entry.digest || ''}\n`).join(''); + // Digest content and path identity only. Permission bits vary across checkout + // umasks (macOS vs Linux CI) and must not invalidate the shipped pin. + const canonical = fixtureEntries.map((entry) => `${entry.path}\0${entry.type}\0${entry.digest || ''}\n`).join(''); return crypto.createHash('sha256').update(canonical).digest('hex'); } diff --git a/runtimes/codex/compound-engineering-capability.json b/runtimes/codex/compound-engineering-capability.json index 13a6e815..494bc15b 100644 --- a/runtimes/codex/compound-engineering-capability.json +++ b/runtimes/codex/compound-engineering-capability.json @@ -108,5 +108,5 @@ "invocation.json", "plugin-manifest.json" ], - "fixtureTreeDigest": "58f4ab90b8c5d30a983bdc80bc89699069dc2e84214ac5281df7f6b632dadbc9" + "fixtureTreeDigest": "dd12011a4122e4ac0541752323263d0e68f289957936b30529f13a168f6cd29b" } From 037a89107c99d6a0972466d78bf028ec812a7261 Mon Sep 17 00:00:00 2001 From: Andrew Levine Date: Thu, 3 Sep 2026 22:38:02 -0400 Subject: [PATCH 4/5] fix(test): accept System Doctor icon lines in runtime-neutral doctor smoke Align the dormant-runtime template doctor assertion with the cleaned one-icon presentation (no PASS/FAIL tokens). --- tests/runtime-neutral-templates.test.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/runtime-neutral-templates.test.js b/tests/runtime-neutral-templates.test.js index b72c1a9b..117436cc 100644 --- a/tests/runtime-neutral-templates.test.js +++ b/tests/runtime-neutral-templates.test.js @@ -74,9 +74,10 @@ try { const doctor = run(['doctor', '--profile', 'minimal', '--workspace', workspace], env); assert.equal(doctor.status, 0, doctor.stderr || doctor.stdout); - assert.match(doctor.stdout, /PASS vault-path/); - assert.match(doctor.stdout, /PASS vault-path-stale/); + assert.match(doctor.stdout, /✅ vault-path/); + assert.match(doctor.stdout, /✅ vault-path-stale/); assert.match(doctor.stdout, /dormant runtime mode leaves vault unactivated/); + assert.doesNotMatch(doctor.stdout, /\bPASS\b|\bFAIL\b|READY/); const authoredAgents = '# Customized workspace instructions\n'; fs.writeFileSync(path.join(workspace, 'AGENTS.md'), authoredAgents, 'utf8'); From 1c9b0769683b667e0852f190b51f46dfbc6ca510 Mon Sep 17 00:00:00 2001 From: Andrew Levine Date: Thu, 3 Sep 2026 22:38:45 -0400 Subject: [PATCH 5/5] chore(ci): retrigger CI for System Doctor presentation fix