Share doctor boot finding policy

Centralize the shared boot artifact checks so doctor adds only its deep checks while preserving the existing finding order and CLI contracts.

AI-assisted: prepared by Codex under maintainer pbakaus scheduled-refactor authorization.
This commit is contained in:
Paul Bakaus
2026-08-22 11:58:26 -07:00
parent 56f44523f7
commit 809976638d
3 changed files with 55 additions and 39 deletions
+14 -23
View File
@@ -33,13 +33,8 @@ import {
stampProductSchema, stampProductSchema,
} from './lib/artifact-schema.mjs'; } from './lib/artifact-schema.mjs';
import { import {
checkBuildPathUnset, collectBootFindingGroups,
checkConfig,
checkDesignSidecar,
checkNativePlatformEvidence, checkNativePlatformEvidence,
checkProduct,
checkProjectRoots,
checkSurfaceBriefs,
designSidecarCandidatesFor, designSidecarCandidatesFor,
} from './lib/staleness.mjs'; } from './lib/staleness.mjs';
import { import {
@@ -106,34 +101,30 @@ async function collect(cwd, targetOptions) {
extractPlatform, extractPlatform,
readFile: safeRead, readFile: safeRead,
}); });
const bootFindings = collectBootFindingGroups(ctx, {
absDesignPath,
sidecarCandidates,
projectRootPatterns: readProjectRootPatterns(ctx.repoRoot),
targetCandidates: workspaceCandidates,
});
const findings = [ const findings = [
...checkProduct(ctx.product, ctx.productPath || 'PRODUCT.md'), ...bootFindings.product,
...(ctx.product ...bootFindings.nativePlatform,
? checkNativePlatformEvidence({ ...bootFindings.designSidecar,
projectRoot,
platform: ctx.platform,
product: ctx.product,
productPath: ctx.productPath,
})
: []),
...checkDesignSidecar({ designPath: absDesignPath, sidecarCandidates, projectRoot }),
...checkDesignDrift({ designPath: absDesignPath, projectRoot }), ...checkDesignDrift({ designPath: absDesignPath, projectRoot }),
...checkDesignCoverage({ design: ctx.design, designPath: ctx.designPath, parseDesignMd }), ...checkDesignCoverage({ design: ctx.design, designPath: ctx.designPath, parseDesignMd }),
...checkConfig({ projectRoot, repoRoot: ctx.repoRoot }), ...bootFindings.config,
...checkBuildPathUnset({ projectRoot, repoRoot: ctx.repoRoot, product: ctx.product }), ...bootFindings.buildPath,
...checkDetectorIgnores({ projectRoot, knownRuleIds }), ...checkDetectorIgnores({ projectRoot, knownRuleIds }),
...checkSurfaceBriefs({ candidates: ctx.surfaceBriefCandidates, projectRoot }), ...bootFindings.surfaceBriefs,
...checkHookInstallation({ ...checkHookInstallation({
projectRoot, projectRoot,
repoRoot: ctx.repoRoot, repoRoot: ctx.repoRoot,
providerId: IMPECCABLE_PROVIDER_ID, providerId: IMPECCABLE_PROVIDER_ID,
}), }),
...checkLegacyLiveState({ projectRoot }), ...checkLegacyLiveState({ projectRoot }),
...checkProjectRoots({ ...bootFindings.projectRoots,
patterns: readProjectRootPatterns(ctx.repoRoot),
candidates: workspaceCandidates,
}),
...workspaceResult.findings, ...workspaceResult.findings,
]; ];
+21 -16
View File
@@ -488,41 +488,46 @@ export function describeWorkspaceContext(candidates = []) {
// ─── Tier 1 orchestration ────────────────────────────────────────────────── // ─── Tier 1 orchestration ──────────────────────────────────────────────────
/** /**
* Everything a boot can afford. `ctx` is the loadContext result; `extras` * Everything a boot can afford, grouped by artifact so deeper reports can
* carries values the caller already computed so nothing is recomputed here. * interleave their own checks without rebuilding this policy. `ctx` is the
* loadContext result; `extras` carries values the caller already computed so
* nothing is recomputed here.
*/ */
export function collectBootFindings(ctx, extras = {}) { export function collectBootFindingGroups(ctx, extras = {}) {
if (!ctx) return []; if (!ctx) return {};
const projectRoot = ctx.projectRoot || process.cwd(); const projectRoot = ctx.projectRoot || process.cwd();
const absProductPath = extras.absProductPath || null;
const absDesignPath = extras.absDesignPath || null; const absDesignPath = extras.absDesignPath || null;
return [ return {
...checkProduct(ctx.product, ctx.productPath || 'PRODUCT.md'), product: checkProduct(ctx.product, ctx.productPath || 'PRODUCT.md'),
// Only checked once a PRODUCT.md exists. Without one the boot already // Only checked once a PRODUCT.md exists. Without one the boot already
// emits NO_PRODUCT_MD and routes into init, which asks for the platform // emits NO_PRODUCT_MD and routes into init, which asks for the platform
// directly; a second signal saying the same thing is noise. // directly; a second signal saying the same thing is noise.
...(ctx.product nativePlatform: ctx.product
? checkNativePlatformEvidence({ ? checkNativePlatformEvidence({
projectRoot, projectRoot,
platform: ctx.platform, platform: ctx.platform,
product: ctx.product, product: ctx.product,
productPath: ctx.productPath, productPath: ctx.productPath,
}) })
: []), : [],
...checkDesignSidecar({ designSidecar: checkDesignSidecar({
designPath: absDesignPath, designPath: absDesignPath,
sidecarCandidates: extras.sidecarCandidates || [], sidecarCandidates: extras.sidecarCandidates || [],
projectRoot, projectRoot,
}), }),
...checkConfig({ projectRoot, repoRoot: ctx.repoRoot }), config: checkConfig({ projectRoot, repoRoot: ctx.repoRoot }),
...checkBuildPathUnset({ projectRoot, repoRoot: ctx.repoRoot, product: ctx.product }), buildPath: checkBuildPathUnset({ projectRoot, repoRoot: ctx.repoRoot, product: ctx.product }),
...checkSurfaceBriefs({ candidates: ctx.surfaceBriefCandidates, projectRoot }), surfaceBriefs: checkSurfaceBriefs({ candidates: ctx.surfaceBriefCandidates, projectRoot }),
...(extras.projectRootPatterns projectRoots: extras.projectRootPatterns
? checkProjectRoots({ ? checkProjectRoots({
patterns: extras.projectRootPatterns, patterns: extras.projectRootPatterns,
candidates: extras.targetCandidates || [], candidates: extras.targetCandidates || [],
}) })
: []), : [],
]; };
}
export function collectBootFindings(ctx, extras = {}) {
return Object.values(collectBootFindingGroups(ctx, extras)).flat();
} }
+20
View File
@@ -634,6 +634,26 @@ describe('doctor CLI', () => {
assert.equal(report.ruleRegistryAvailable, true); assert.equal(report.ruleRegistryAvailable, true);
}); });
it('keeps boot and deep findings in their established artifact order', () => {
write('PRODUCT.md', '# Product\n\n## Register\n\nbrand\n\n## Users\nDesigners.\n');
write('DESIGN.md', '---\nname: Example\n---\n\n# Design System: Example\n');
write('.impeccable/design.json', JSON.stringify({ schemaVersion: 1 }));
write('.impeccable/config.json', JSON.stringify({ unknownSetting: true }));
const res = run(['--json']);
assert.equal(res.status, 0, res.stderr);
assert.deepEqual(
JSON.parse(res.stdout).findings.map((entry) => entry.id),
[
'product-deprecated-register',
'product-schema-legacy',
'design-sidecar-schema-outdated',
'design-md-coverage',
'config-unknown-keys',
],
);
});
it('applies only the automatic migrations under --fix', () => { it('applies only the automatic migrations under --fix', () => {
write('PRODUCT.md', CURRENT_PRODUCT.replace('<!-- impeccable:product-schema 1 -->\n\n', '')); write('PRODUCT.md', CURRENT_PRODUCT.replace('<!-- impeccable:product-schema 1 -->\n\n', ''));
write('DESIGN.json', JSON.stringify({ schemaVersion: 2 })); write('DESIGN.json', JSON.stringify({ schemaVersion: 2 }));