no-mistakes(review): Harden onboarding projection routing
This commit is contained in:
committed by
Codesmith
parent
a5298c1fc0
commit
2a38ea5331
@@ -212,8 +212,14 @@ function mapFinalStatus(mapReadiness: MapReadiness): string {
|
||||
return 'missing';
|
||||
}
|
||||
|
||||
function planningMissing(requirementsExists: boolean, roadmapExists: boolean, stateExists: boolean): string[] {
|
||||
function planningMissing(
|
||||
projectExists: boolean,
|
||||
requirementsExists: boolean,
|
||||
roadmapExists: boolean,
|
||||
stateExists: boolean,
|
||||
): string[] {
|
||||
const missing: string[] = [];
|
||||
if (!projectExists) missing.push('PROJECT.md');
|
||||
if (!requirementsExists) missing.push('REQUIREMENTS.md');
|
||||
if (!roadmapExists) missing.push('ROADMAP.md');
|
||||
if (!stateExists) missing.push('STATE.md');
|
||||
@@ -228,6 +234,7 @@ function nextAction(params: {
|
||||
projectExists: boolean;
|
||||
mapReadiness: MapReadiness;
|
||||
onboardingSummaryExists: boolean;
|
||||
hasPlanningArtifacts: boolean;
|
||||
missingPlanningFiles: string[];
|
||||
}): OnboardNextAction {
|
||||
if (params.isBrownfield && params.needsCodebaseMap) {
|
||||
@@ -238,6 +245,22 @@ function nextAction(params: {
|
||||
};
|
||||
}
|
||||
|
||||
if (!params.projectExists && params.fastMode && params.mapReadiness === 'fast') {
|
||||
return {
|
||||
kind: 'complete-map-before-new-project',
|
||||
command: '/gsd:map-codebase',
|
||||
reason: 'The fast map is enough for lightweight onboarding, but project setup still requires the complete codebase map.',
|
||||
};
|
||||
}
|
||||
|
||||
if (params.hasPlanningArtifacts && params.missingPlanningFiles.length > 0) {
|
||||
return {
|
||||
kind: 'partial-planning',
|
||||
missing: params.missingPlanningFiles,
|
||||
reason: 'Project planning exists but required planning files are missing.',
|
||||
};
|
||||
}
|
||||
|
||||
if (params.hasDocsCandidates && !params.projectExists) {
|
||||
return {
|
||||
kind: 'ingest-docs',
|
||||
@@ -254,14 +277,6 @@ function nextAction(params: {
|
||||
};
|
||||
}
|
||||
|
||||
if (!params.projectExists && params.fastMode && params.mapReadiness === 'fast') {
|
||||
return {
|
||||
kind: 'complete-map-before-new-project',
|
||||
command: '/gsd:map-codebase',
|
||||
reason: 'The fast map is enough for lightweight onboarding, but project setup still requires the complete codebase map.',
|
||||
};
|
||||
}
|
||||
|
||||
if (!params.projectExists) {
|
||||
return {
|
||||
kind: 'new-project',
|
||||
@@ -270,14 +285,6 @@ function nextAction(params: {
|
||||
};
|
||||
}
|
||||
|
||||
if (params.missingPlanningFiles.length > 0) {
|
||||
return {
|
||||
kind: 'partial-planning',
|
||||
missing: params.missingPlanningFiles,
|
||||
reason: 'Project planning exists but required planning files are missing.',
|
||||
};
|
||||
}
|
||||
|
||||
if (!params.onboardingSummaryExists) {
|
||||
return {
|
||||
kind: 'write-summary',
|
||||
@@ -315,7 +322,13 @@ function buildOnboardProjection(cwd: string, options: BuildOnboardProjectionOpti
|
||||
const roadmapExists = fs.existsSync(path.join(planningDir(cwd), 'ROADMAP.md'));
|
||||
const stateExists = fs.existsSync(path.join(planningDir(cwd), 'STATE.md'));
|
||||
const onboardingSummaryExists = pathExistsInternal(cwd, '.planning/onboarding/SUMMARY.md');
|
||||
const missingPlanningFiles = planningMissing(requirementsExists, roadmapExists, stateExists);
|
||||
const hasPlanningArtifacts = projectExists || requirementsExists || roadmapExists || stateExists;
|
||||
const missingPlanningFiles = planningMissing(
|
||||
projectExists,
|
||||
requirementsExists,
|
||||
roadmapExists,
|
||||
stateExists,
|
||||
);
|
||||
|
||||
return {
|
||||
commit_docs: options.commitDocs,
|
||||
@@ -341,6 +354,7 @@ function buildOnboardProjection(cwd: string, options: BuildOnboardProjectionOpti
|
||||
projectExists,
|
||||
mapReadiness: mapReadinessValue,
|
||||
onboardingSummaryExists,
|
||||
hasPlanningArtifacts,
|
||||
missingPlanningFiles,
|
||||
}),
|
||||
needs_codebase_map: needsCodebaseMap,
|
||||
|
||||
@@ -165,6 +165,37 @@ describe('init onboard public CLI projection', () => {
|
||||
assert.deepStrictEqual(parsed.missing_fast_codebase_map_files, []);
|
||||
});
|
||||
|
||||
test('routes fast mapped repositories with planning docs to complete map before ingest', () => {
|
||||
fs.mkdirSync(path.join(tmpDir, '.planning', 'codebase'), { recursive: true });
|
||||
for (const name of ['STACK', 'INTEGRATIONS', 'ARCHITECTURE', 'STRUCTURE']) {
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'codebase', `${name}.md`), `# ${name}\n`);
|
||||
}
|
||||
fs.writeFileSync(path.join(tmpDir, 'package.json'), '{"name":"fixture"}\n');
|
||||
fs.mkdirSync(path.join(tmpDir, 'docs', 'adr'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpDir, 'docs', 'adr', '0001-runtime.md'), '# ADR: Runtime\n');
|
||||
|
||||
const result = runGsdTools(['init', 'onboard', '--fast', '--raw'], tmpDir, { HOME: tmpDir });
|
||||
assert.ok(result.success, `init onboard should succeed: ${result.error}`);
|
||||
|
||||
const parsed = JSON.parse(result.output);
|
||||
assert.strictEqual(parsed.next_action.kind, 'complete-map-before-new-project');
|
||||
assert.strictEqual(parsed.next_action.command, '/gsd:map-codebase');
|
||||
});
|
||||
|
||||
test('routes planning artifacts without PROJECT.md to partial planning', () => {
|
||||
fs.mkdirSync(path.join(tmpDir, '.planning'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'REQUIREMENTS.md'), '# Requirements\n');
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), '# Roadmap\n');
|
||||
fs.writeFileSync(path.join(tmpDir, '.planning', 'STATE.md'), '# State\n');
|
||||
|
||||
const result = runGsdTools('init onboard --raw', tmpDir, { HOME: tmpDir });
|
||||
assert.ok(result.success, `init onboard should succeed: ${result.error}`);
|
||||
|
||||
const parsed = JSON.parse(result.output);
|
||||
assert.strictEqual(parsed.next_action.kind, 'partial-planning');
|
||||
assert.deepStrictEqual(parsed.next_action.missing, ['PROJECT.md']);
|
||||
});
|
||||
|
||||
test('projects the next action for code, docs, greenfield, partial planning, and summary states', () => {
|
||||
fs.mkdirSync(path.join(tmpDir, 'src'), { recursive: true });
|
||||
fs.writeFileSync(path.join(tmpDir, 'src', 'server.ts'), 'export const server = true;\n');
|
||||
|
||||
Reference in New Issue
Block a user