diff --git a/openspec/changes/fix-doctor-json-schema-cargo-installer/.openspec.yaml b/openspec/changes/fix-doctor-json-schema-cargo-installer/.openspec.yaml new file mode 100644 index 0000000..ac20efa --- /dev/null +++ b/openspec/changes/fix-doctor-json-schema-cargo-installer/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-05-10 diff --git a/openspec/changes/fix-doctor-json-schema-cargo-installer/proposal.md b/openspec/changes/fix-doctor-json-schema-cargo-installer/proposal.md new file mode 100644 index 0000000..4af571f --- /dev/null +++ b/openspec/changes/fix-doctor-json-schema-cargo-installer/proposal.md @@ -0,0 +1,13 @@ +## Why + +Cargo support added a `cargo` boolean to `quantex doctor --json` under `data.installers`, but the doctor entry in `quantex schema doctor` still described only `brew`, `bun`, `npm`, and `winget`. With `additionalProperties: false`, any consumer validating doctor output against the published schema incorrectly rejects valid payloads. + +## What Changes + +- Extend the doctor `dataSchema.installers` contract to include `cargo` alongside the other managed installer flags. +- Lock the alignment in tests and sync the agent-update spec narrative used for diagnostics contracts. + +## Impact + +- Affected specs: `openspec/specs/agent-update/spec.md`. +- Affected code: `src/commands/schema.ts`, `test/commands/schema.test.ts`. diff --git a/openspec/changes/fix-doctor-json-schema-cargo-installer/specs/agent-update/spec.md b/openspec/changes/fix-doctor-json-schema-cargo-installer/specs/agent-update/spec.md new file mode 100644 index 0000000..d1a6ae0 --- /dev/null +++ b/openspec/changes/fix-doctor-json-schema-cargo-installer/specs/agent-update/spec.md @@ -0,0 +1,12 @@ +## ADDED Requirements + +### Requirement: Doctor JSON schema MUST stay aligned with doctor installer diagnostics + +The machine-readable schema for `quantex doctor` SHALL enumerate every installer availability flag that structured doctor output can emit, so validators using `additionalProperties: false` accept real doctor JSON. + +#### Scenario: Doctor schema includes Cargo alongside other managed installers + +- **GIVEN** the user runs `quantex schema doctor` in JSON mode +- **WHEN** Quantex returns the doctor command `dataSchema` +- **THEN** `dataSchema.properties.installers.properties` includes a `cargo` boolean field +- **AND** `dataSchema.properties.installers.required` includes `cargo` together with the other managed installer keys diff --git a/openspec/changes/fix-doctor-json-schema-cargo-installer/tasks.md b/openspec/changes/fix-doctor-json-schema-cargo-installer/tasks.md new file mode 100644 index 0000000..d02d075 --- /dev/null +++ b/openspec/changes/fix-doctor-json-schema-cargo-installer/tasks.md @@ -0,0 +1,3 @@ +- [x] 1.1 Add `cargo` to doctor JSON schema `installers` properties and `required` list in `src/commands/schema.ts`. +- [x] 1.2 Assert schema parity in `test/commands/schema.test.ts`. +- [x] 1.3 Document the contract in `openspec/specs/agent-update/spec.md`. diff --git a/openspec/specs/agent-update/spec.md b/openspec/specs/agent-update/spec.md index ce2bbd0..868a403 100644 --- a/openspec/specs/agent-update/spec.md +++ b/openspec/specs/agent-update/spec.md @@ -150,6 +150,13 @@ Agent update behavior SHALL be inspectable through user-facing diagnostic comman - AND includes `subject`, `suggestedAction`, and `suggestedCommands` - AND allows an automation layer to distinguish between inspection, self-update, and manual-follow-up paths +#### Scenario: Doctor schema documents every managed installer availability flag + +- GIVEN the user runs `quantex schema doctor` in JSON mode +- WHEN Quantex returns the doctor command `dataSchema` +- THEN the `installers` object lists every managed installer key that `quantex doctor --json` may emit, including `cargo` +- AND strict schema validation of real doctor JSON output does not fail solely because an installer flag is missing from the published schema + #### Scenario: Resolve exposes machine-actionable install guidance - GIVEN the user runs `quantex resolve --json` diff --git a/src/commands/schema.ts b/src/commands/schema.ts index cfd7a83..cc19495 100644 --- a/src/commands/schema.ts +++ b/src/commands/schema.ts @@ -230,10 +230,11 @@ const schemaCatalog: SchemaDocument[] = [ properties: { brew: { type: 'boolean' }, bun: { type: 'boolean' }, + cargo: { type: 'boolean' }, npm: { type: 'boolean' }, winget: { type: 'boolean' }, }, - required: ['brew', 'bun', 'npm', 'winget'], + required: ['brew', 'bun', 'cargo', 'npm', 'winget'], type: 'object', }, issues: { diff --git a/src/self/index.ts b/src/self/index.ts index c0fc04a..29de90f 100644 --- a/src/self/index.ts +++ b/src/self/index.ts @@ -1,20 +1,5 @@ -import type { - SelfInspection, - SelfInstallSource, - SelfPackageMetadata, - SelfUpdateChannel, - SelfUpdateResult, - SelfUpgradePlan, -} from './types' +import type { SelfInspection, SelfInstallSource, SelfUpdateChannel, SelfUpdateResult, SelfUpgradePlan } from './types' import process from 'node:process' -import { - canAutoUpdateSelf, - detectSelfInstallSource, - getSelfVersion, - reconcileSelfInstallSource, - resolveSelfInstallFacts, - resolveSelfPackageMetadata, -} from './facts' import { acquireSelfUpgradeLock } from './lock' import { buildPlanFromInspection, diff --git a/test/commands/schema.test.ts b/test/commands/schema.test.ts index 8417ac9..2ae2e62 100644 --- a/test/commands/schema.test.ts +++ b/test/commands/schema.test.ts @@ -66,6 +66,8 @@ describe('schemaCommand', () => { expect(payload.data.commands[0].name).toBe('doctor') expect(payload.data.commands[0].dataSchema.properties.issues.items.properties.suggestedAction).toBeDefined() expect(payload.data.commands[0].dataSchema.properties.issues.items.properties.suggestedCommands).toBeDefined() + expect(payload.data.commands[0].dataSchema.properties.installers.properties.cargo).toEqual({ type: 'boolean' }) + expect(payload.data.commands[0].dataSchema.properties.installers.required).toContain('cargo') }) it('returns the exec schema in json mode', async () => {