fix(state): always run disk→DB reconciliation when DB is available (#2631)

When DB was available but empty, deriveState skipped deriveStateFromDb
entirely, bypassing the disk→DB sync logic. Milestones created outside
the DB write path were never discovered.
This commit is contained in:
Jeremy 2026-03-31 17:34:05 -05:00
parent 36b03890da
commit 0e978d4565

View file

@ -228,19 +228,15 @@ export async function deriveState(basePath: string): Promise<GSDState> {
const stopTimer = debugTime("derive-state-impl");
let result: GSDState;
// Dual-path: try DB-backed derivation first when hierarchy tables are populated
// Dual-path: try DB-backed derivation when DB is available.
// Always go through deriveStateFromDb when DB is open — even if hierarchy
// tables are empty — because it contains disk→DB reconciliation logic that
// discovers milestones created outside the DB write path (#2631).
if (isDbAvailable()) {
const dbMilestones = getAllMilestones();
if (dbMilestones.length > 0) {
const stopDbTimer = debugTime("derive-state-db");
result = await deriveStateFromDb(basePath);
stopDbTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
_telemetry.dbDeriveCount++;
} else {
// DB open but empty hierarchy tables — pre-migration project, use filesystem
result = await _deriveStateImpl(basePath);
_telemetry.markdownDeriveCount++;
}
const stopDbTimer = debugTime("derive-state-db");
result = await deriveStateFromDb(basePath);
stopDbTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
_telemetry.dbDeriveCount++;
} else {
result = await _deriveStateImpl(basePath);
_telemetry.markdownDeriveCount++;