mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-12 06:06:37 +03:00
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:
+14
-23
@@ -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,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 }));
|
||||||
|
|||||||
Reference in New Issue
Block a user