@opengsd/gsd-pi 1.1.1-dev.9f86580 → 1.1.1-dev.b2556262
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/headless-recover.js +56 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/browser-tools/index.js +39 -22
- package/dist/resources/extensions/browser-tools/state.js +12 -0
- package/dist/resources/extensions/browser-tools/tools/session.js +3 -2
- package/dist/resources/extensions/browser-tools/utils.js +3 -3
- package/dist/resources/extensions/gsd/auto/loop.js +4 -2
- package/dist/resources/extensions/gsd/auto/phases.js +43 -10
- package/dist/resources/extensions/gsd/auto/session.js +20 -1
- package/dist/resources/extensions/gsd/auto/workflow-kernel.js +1 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +72 -12
- package/dist/resources/extensions/gsd/auto-model-selection.js +128 -9
- package/dist/resources/extensions/gsd/auto-post-unit.js +19 -2
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -19
- package/dist/resources/extensions/gsd/auto-recovery.js +4 -2
- package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +1 -1
- package/dist/resources/extensions/gsd/auto.js +14 -11
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +3 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -65
- package/dist/resources/extensions/gsd/closeout-wizard.js +32 -9
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -9
- package/dist/resources/extensions/gsd/commands-maintenance.js +93 -15
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +2 -2
- package/dist/resources/extensions/gsd/db-writer.js +35 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/dist/resources/extensions/gsd/gsd-db.js +480 -172
- package/dist/resources/extensions/gsd/markdown-renderer.js +37 -53
- package/dist/resources/extensions/gsd/md-importer.js +38 -3
- package/dist/resources/extensions/gsd/migration-auto-check.js +126 -31
- package/dist/resources/extensions/gsd/parsers-legacy.js +23 -0
- package/dist/resources/extensions/gsd/planning-path-scope.js +22 -4
- package/dist/resources/extensions/gsd/pre-execution-checks.js +10 -2
- package/dist/resources/extensions/gsd/preferences-models.js +110 -43
- package/dist/resources/extensions/gsd/preferences-types.js +13 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +68 -3
- package/dist/resources/extensions/gsd/preferences.js +4 -1
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/dist/resources/extensions/gsd/roadmap-slices.js +5 -1
- package/dist/resources/extensions/gsd/safety/content-validator.js +6 -4
- package/dist/resources/extensions/gsd/source-observations.js +306 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +15 -8
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +33 -5
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +34 -13
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +39 -14
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +4 -4
- package/dist/resources/extensions/gsd/state.js +7 -3
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tool-presentation-plan.js +1 -9
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -6
- package/dist/resources/extensions/gsd/tools/plan-slice.js +42 -11
- package/dist/resources/extensions/gsd/tools/plan-task.js +7 -1
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +57 -429
- package/dist/resources/extensions/gsd/uat-policy.js +130 -0
- package/dist/resources/extensions/gsd/uat-run.js +414 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +3 -4
- package/dist/resources/extensions/gsd/verdict-parser.js +3 -8
- package/dist/resources/extensions/gsd/workflow-manifest.js +132 -5
- package/dist/resources/extensions/gsd/workflow-projections.js +8 -0
- package/dist/resources/extensions/gsd/worktree-state-projection.js +18 -17
- package/dist/resources/extensions/subagent/agents.js +1 -0
- package/dist/resources/extensions/subagent/index.js +27 -12
- package/dist/resources/extensions/subagent/launch.js +7 -2
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
- package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/node_modules/@gsd/native/dist/native.js +22 -0
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/package.json +4 -4
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +21 -23
- package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +25 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +66 -12
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +18 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +16 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/dist/native.js +22 -0
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
- package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/image-models.generated.js +30 -0
- package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +23 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +25 -24
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js +1 -1
- package/packages/pi-coding-agent/dist/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/dist/utils.d.ts +11 -0
- package/packages/pi-tui/dist/utils.d.ts.map +1 -1
- package/packages/pi-tui/dist/utils.js +119 -6
- package/packages/pi-tui/dist/utils.js.map +1 -1
- package/packages/pi-tui/package.json +2 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/theme/themes.js +1 -1
- package/pkg/dist/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/index.ts +39 -22
- package/src/resources/extensions/browser-tools/state.ts +13 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +57 -0
- package/src/resources/extensions/browser-tools/tools/session.ts +4 -2
- package/src/resources/extensions/browser-tools/utils.ts +3 -3
- package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -0
- package/src/resources/extensions/gsd/auto/loop.ts +4 -2
- package/src/resources/extensions/gsd/auto/phases.ts +42 -10
- package/src/resources/extensions/gsd/auto/session.ts +22 -1
- package/src/resources/extensions/gsd/auto/workflow-kernel.ts +1 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +85 -12
- package/src/resources/extensions/gsd/auto-model-selection.ts +164 -12
- package/src/resources/extensions/gsd/auto-post-unit.ts +20 -2
- package/src/resources/extensions/gsd/auto-prompts.ts +23 -20
- package/src/resources/extensions/gsd/auto-recovery.ts +22 -3
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +1 -1
- package/src/resources/extensions/gsd/auto.ts +13 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +3 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +225 -72
- package/src/resources/extensions/gsd/closeout-wizard.ts +47 -13
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -17
- package/src/resources/extensions/gsd/commands-maintenance.ts +124 -13
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +2 -2
- package/src/resources/extensions/gsd/db-writer.ts +38 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +50 -1
- package/src/resources/extensions/gsd/gsd-db.ts +564 -186
- package/src/resources/extensions/gsd/markdown-renderer.ts +44 -66
- package/src/resources/extensions/gsd/md-importer.ts +49 -2
- package/src/resources/extensions/gsd/migration-auto-check.ts +154 -34
- package/src/resources/extensions/gsd/parsers-legacy.ts +20 -0
- package/src/resources/extensions/gsd/planning-path-scope.ts +22 -4
- package/src/resources/extensions/gsd/pre-execution-checks.ts +9 -2
- package/src/resources/extensions/gsd/preferences-models.ts +112 -43
- package/src/resources/extensions/gsd/preferences-types.ts +39 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +76 -2
- package/src/resources/extensions/gsd/preferences.ts +5 -0
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
- package/src/resources/extensions/gsd/roadmap-slices.ts +6 -1
- package/src/resources/extensions/gsd/safety/content-validator.ts +8 -5
- package/src/resources/extensions/gsd/source-observations.ts +402 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +20 -8
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +44 -5
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +39 -11
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +45 -15
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +4 -4
- package/src/resources/extensions/gsd/state.ts +7 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +299 -1
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +75 -3
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +22 -1
- package/src/resources/extensions/gsd/tests/before-provider-context-management.test.ts +145 -0
- package/src/resources/extensions/gsd/tests/closeout-wizard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/content-validator.test.ts +74 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +16 -2
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +1 -11
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +62 -1
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/plan-slice.test.ts +99 -2
- package/src/resources/extensions/gsd/tests/plan-task.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +101 -1
- package/src/resources/extensions/gsd/tests/repository-registry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/schema-v21-sequence.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +162 -18
- package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +8 -0
- package/src/resources/extensions/gsd/tests/source-observations.test.ts +275 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +43 -0
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +76 -21
- package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +203 -0
- package/src/resources/extensions/gsd/tests/uat-policy.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +306 -1
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +73 -6
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +511 -1
- package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +44 -0
- package/src/resources/extensions/gsd/tool-contract.ts +28 -0
- package/src/resources/extensions/gsd/tool-presentation-plan.ts +1 -11
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -6
- package/src/resources/extensions/gsd/tools/plan-slice.ts +54 -12
- package/src/resources/extensions/gsd/tools/plan-task.ts +8 -1
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +66 -526
- package/src/resources/extensions/gsd/types.ts +1 -0
- package/src/resources/extensions/gsd/uat-policy.ts +191 -0
- package/src/resources/extensions/gsd/uat-run.ts +550 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +3 -4
- package/src/resources/extensions/gsd/verdict-parser.ts +3 -10
- package/src/resources/extensions/gsd/workflow-manifest.ts +193 -7
- package/src/resources/extensions/gsd/workflow-projections.ts +9 -0
- package/src/resources/extensions/gsd/worktree-state-projection.ts +22 -22
- package/src/resources/extensions/shared/tests/format-utils.test.ts +8 -3
- package/src/resources/extensions/subagent/agents.ts +4 -0
- package/src/resources/extensions/subagent/index.ts +28 -3
- package/src/resources/extensions/subagent/launch.ts +8 -0
- package/src/resources/extensions/subagent/tests/model-override.test.ts +31 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{zzYMrKpPGfRQRxSFO32Jr → tJOKQbQRO-9MiFDO8DIDS}/_ssgManifest.js +0 -0
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { createRequire } from "node:module";
|
|
26
26
|
import { createHash } from "node:crypto";
|
|
27
27
|
import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
|
|
28
|
-
import { dirname } from "node:path";
|
|
28
|
+
import { dirname, join } from "node:path";
|
|
29
29
|
import type { Decision, Requirement, GateRow, GateId, GateScope, GateStatus, GateVerdict } from "./types.js";
|
|
30
30
|
import { GSDError, GSD_STALE_STATE } from "./errors.js";
|
|
31
31
|
import type { GsdWorkspace, MilestoneScope } from "./workspace.js";
|
|
@@ -760,6 +760,28 @@ export function checkpointDatabase(): void {
|
|
|
760
760
|
} catch (e) { logWarning("db", `WAL checkpoint failed: ${(e as Error).message}`); }
|
|
761
761
|
}
|
|
762
762
|
|
|
763
|
+
/**
|
|
764
|
+
* Copy the live database file to `.gsd/backups/<label>-<timestamp>.db` so a
|
|
765
|
+
* destructive operation (e.g. recover, which clears the hierarchy tables) is
|
|
766
|
+
* reversible. Checkpoints the WAL first so the snapshot is complete. Returns
|
|
767
|
+
* the backup path, or null if no DB is open or the copy failed.
|
|
768
|
+
*/
|
|
769
|
+
export function backupDatabaseSnapshot(label: string): string | null {
|
|
770
|
+
if (!currentPath) return null;
|
|
771
|
+
try {
|
|
772
|
+
checkpointDatabase();
|
|
773
|
+
const backupsDir = join(dirname(currentPath), "backups");
|
|
774
|
+
mkdirSync(backupsDir, { recursive: true });
|
|
775
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
776
|
+
const dest = join(backupsDir, `${label}-${stamp}.db`);
|
|
777
|
+
copyFileSync(currentPath, dest);
|
|
778
|
+
return dest;
|
|
779
|
+
} catch (e) {
|
|
780
|
+
logWarning("db", `database snapshot failed: ${(e as Error).message}`);
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
|
|
763
785
|
const _transactionRunner = createDbTransactionRunner();
|
|
764
786
|
|
|
765
787
|
function createTransactionControls(db: DbAdapter) {
|
|
@@ -1260,14 +1282,14 @@ export function insertTask(t: {
|
|
|
1260
1282
|
milestone_id, slice_id, id, title, status, one_liner, narrative,
|
|
1261
1283
|
verification_result, duration, completed_at, blocker_discovered,
|
|
1262
1284
|
deviations, known_issues, key_files, key_decisions, full_summary_md,
|
|
1263
|
-
description, estimate, files, verify, inputs, expected_output,
|
|
1264
|
-
, target_repositories
|
|
1285
|
+
description, estimate, files, verify, inputs, expected_output,
|
|
1286
|
+
observability_impact, full_plan_md, target_repositories, sequence
|
|
1265
1287
|
) VALUES (
|
|
1266
1288
|
:milestone_id, :slice_id, :id, :title, :status, :one_liner, :narrative,
|
|
1267
1289
|
:verification_result, :duration, :completed_at, :blocker_discovered,
|
|
1268
1290
|
:deviations, :known_issues, :key_files, :key_decisions, :full_summary_md,
|
|
1269
|
-
:description, :estimate, :files, :verify, :inputs, :expected_output,
|
|
1270
|
-
, :target_repositories
|
|
1291
|
+
:description, :estimate, :files, :verify, :inputs, :expected_output,
|
|
1292
|
+
:observability_impact, :full_plan_md, :target_repositories, :sequence
|
|
1271
1293
|
)
|
|
1272
1294
|
ON CONFLICT(milestone_id, slice_id, id) DO UPDATE SET
|
|
1273
1295
|
title = CASE WHEN NULLIF(:title, '') IS NOT NULL THEN :title ELSE tasks.title END,
|
|
@@ -1290,6 +1312,7 @@ export function insertTask(t: {
|
|
|
1290
1312
|
inputs = CASE WHEN NULLIF(:inputs, '[]') IS NOT NULL THEN :inputs ELSE tasks.inputs END,
|
|
1291
1313
|
expected_output = CASE WHEN NULLIF(:expected_output, '[]') IS NOT NULL THEN :expected_output ELSE tasks.expected_output END,
|
|
1292
1314
|
observability_impact = CASE WHEN NULLIF(:observability_impact, '') IS NOT NULL THEN :observability_impact ELSE tasks.observability_impact END,
|
|
1315
|
+
full_plan_md = CASE WHEN NULLIF(:full_plan_md, '') IS NOT NULL THEN :full_plan_md ELSE tasks.full_plan_md END,
|
|
1293
1316
|
sequence = :sequence,
|
|
1294
1317
|
target_repositories = CASE
|
|
1295
1318
|
WHEN :raw_target_repositories IS NOT NULL THEN :target_repositories
|
|
@@ -1319,6 +1342,7 @@ export function insertTask(t: {
|
|
|
1319
1342
|
":inputs": JSON.stringify(t.planning?.inputs ?? []),
|
|
1320
1343
|
":expected_output": JSON.stringify(t.planning?.expectedOutput ?? []),
|
|
1321
1344
|
":observability_impact": t.planning?.observabilityImpact ?? "",
|
|
1345
|
+
":full_plan_md": t.planning?.fullPlanMd ?? "",
|
|
1322
1346
|
":sequence": t.sequence ?? 0,
|
|
1323
1347
|
":target_repositories": JSON.stringify(t.planning?.targetRepositories ?? []),
|
|
1324
1348
|
":raw_target_repositories":
|
|
@@ -1855,7 +1879,13 @@ export interface ReconcileResult {
|
|
|
1855
1879
|
slices: number;
|
|
1856
1880
|
tasks: number;
|
|
1857
1881
|
memories: number;
|
|
1882
|
+
replan_history: number;
|
|
1883
|
+
assessments: number;
|
|
1884
|
+
quality_gates: number;
|
|
1885
|
+
slice_dependencies: number;
|
|
1858
1886
|
verification_evidence: number;
|
|
1887
|
+
gate_runs: number;
|
|
1888
|
+
milestone_commit_attributions: number;
|
|
1859
1889
|
conflicts: string[];
|
|
1860
1890
|
}
|
|
1861
1891
|
|
|
@@ -1863,7 +1893,23 @@ export function reconcileWorktreeDb(
|
|
|
1863
1893
|
mainDbPath: string,
|
|
1864
1894
|
worktreeDbPath: string,
|
|
1865
1895
|
): ReconcileResult {
|
|
1866
|
-
const zero: ReconcileResult = {
|
|
1896
|
+
const zero: ReconcileResult = {
|
|
1897
|
+
decisions: 0,
|
|
1898
|
+
requirements: 0,
|
|
1899
|
+
artifacts: 0,
|
|
1900
|
+
milestones: 0,
|
|
1901
|
+
slices: 0,
|
|
1902
|
+
tasks: 0,
|
|
1903
|
+
memories: 0,
|
|
1904
|
+
replan_history: 0,
|
|
1905
|
+
assessments: 0,
|
|
1906
|
+
quality_gates: 0,
|
|
1907
|
+
slice_dependencies: 0,
|
|
1908
|
+
verification_evidence: 0,
|
|
1909
|
+
gate_runs: 0,
|
|
1910
|
+
milestone_commit_attributions: 0,
|
|
1911
|
+
conflicts: [],
|
|
1912
|
+
};
|
|
1867
1913
|
if (!existsSync(worktreeDbPath)) return zero;
|
|
1868
1914
|
// Guard: bail when both paths resolve to the same physical file.
|
|
1869
1915
|
// ATTACHing a WAL-mode DB to itself corrupts the WAL (#2823).
|
|
@@ -1889,224 +1935,398 @@ export function reconcileWorktreeDb(
|
|
|
1889
1935
|
try {
|
|
1890
1936
|
adapter.exec(`ATTACH DATABASE '${worktreeDbPath}' AS wt`);
|
|
1891
1937
|
try {
|
|
1892
|
-
|
|
1938
|
+
function countChanges(result: unknown): number {
|
|
1939
|
+
return typeof result === "object" && result !== null ? ((result as { changes?: number }).changes ?? 0) : 0;
|
|
1940
|
+
}
|
|
1941
|
+
|
|
1942
|
+
function wtTableInfo(tableName: string): Array<Record<string, unknown>> {
|
|
1943
|
+
return adapter.prepare(`PRAGMA wt.table_info('${tableName}')`).all() as Array<Record<string, unknown>>;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
const wtInfo = wtTableInfo("decisions");
|
|
1947
|
+
const hasWtDecisions = wtInfo.length > 0;
|
|
1893
1948
|
const hasMadeBy = wtInfo.some((col) => col["name"] === "made_by");
|
|
1894
1949
|
// ADR-011: worktree may predate schema v16/v17. For missing columns we
|
|
1895
1950
|
// fall through to the main DB's existing value (not a literal default)
|
|
1896
1951
|
// so reconcile never silently clears state the main tree has recorded.
|
|
1897
1952
|
const hasDecisionSource = wtInfo.some((col) => col["name"] === "source");
|
|
1898
|
-
const
|
|
1953
|
+
const wtRequirementInfo = wtTableInfo("requirements");
|
|
1954
|
+
const hasWtRequirements = wtRequirementInfo.length > 0;
|
|
1955
|
+
const wtMilestoneInfo = wtTableInfo("milestones");
|
|
1956
|
+
const hasWtMilestones = wtMilestoneInfo.length > 0;
|
|
1899
1957
|
const hasMilestoneSequence = wtMilestoneInfo.some((col) => col["name"] === "sequence");
|
|
1900
|
-
const wtSliceInfo =
|
|
1958
|
+
const wtSliceInfo = wtTableInfo("slices");
|
|
1959
|
+
const hasWtSlices = wtSliceInfo.length > 0;
|
|
1901
1960
|
const hasIsSketch = wtSliceInfo.some((col) => col["name"] === "is_sketch");
|
|
1902
1961
|
const hasSketchScope = wtSliceInfo.some((col) => col["name"] === "sketch_scope");
|
|
1903
1962
|
const hasSliceTargetRepositories = wtSliceInfo.some((col) => col["name"] === "target_repositories");
|
|
1904
|
-
const wtTaskInfo =
|
|
1963
|
+
const wtTaskInfo = wtTableInfo("tasks");
|
|
1964
|
+
const hasWtTasks = wtTaskInfo.length > 0;
|
|
1905
1965
|
const hasTaskTargetRepositories = wtTaskInfo.some((col) => col["name"] === "target_repositories");
|
|
1906
1966
|
const hasBlockerSource = wtTaskInfo.some((col) => col["name"] === "blocker_source");
|
|
1907
1967
|
const hasEscalationPending = wtTaskInfo.some((col) => col["name"] === "escalation_pending");
|
|
1908
1968
|
const hasEscalationAwaiting = wtTaskInfo.some((col) => col["name"] === "escalation_awaiting_review");
|
|
1909
1969
|
const hasEscalationArtifact = wtTaskInfo.some((col) => col["name"] === "escalation_artifact_path");
|
|
1910
1970
|
const hasEscalationOverride = wtTaskInfo.some((col) => col["name"] === "escalation_override_applied_at");
|
|
1911
|
-
const wtArtifactInfo =
|
|
1912
|
-
const
|
|
1913
|
-
const wtMemoryInfo =
|
|
1971
|
+
const wtArtifactInfo = wtTableInfo("artifacts");
|
|
1972
|
+
const hasWtArtifacts = wtArtifactInfo.length > 0;
|
|
1973
|
+
const wtMemoryInfo = wtTableInfo("memories");
|
|
1974
|
+
const hasWtMemories = wtMemoryInfo.length > 0;
|
|
1914
1975
|
const hasMemoryScope = wtMemoryInfo.some((col) => col["name"] === "scope");
|
|
1915
1976
|
const hasMemoryTags = wtMemoryInfo.some((col) => col["name"] === "tags");
|
|
1916
1977
|
const hasMemoryStructuredFields = wtMemoryInfo.some((col) => col["name"] === "structured_fields");
|
|
1917
1978
|
const hasMemoryLastHitAt = wtMemoryInfo.some((col) => col["name"] === "last_hit_at");
|
|
1979
|
+
const hasWtReplanHistory = wtTableInfo("replan_history").length > 0;
|
|
1980
|
+
const hasWtAssessments = wtTableInfo("assessments").length > 0;
|
|
1981
|
+
const hasWtQualityGates = wtTableInfo("quality_gates").length > 0;
|
|
1982
|
+
const hasWtSliceDependencies = wtTableInfo("slice_dependencies").length > 0;
|
|
1983
|
+
const hasWtVerificationEvidence = wtTableInfo("verification_evidence").length > 0;
|
|
1984
|
+
const hasWtGateRuns = wtTableInfo("gate_runs").length > 0;
|
|
1985
|
+
const hasWtMilestoneCommitAttributions = wtTableInfo("milestone_commit_attributions").length > 0;
|
|
1986
|
+
|
|
1987
|
+
if (hasWtDecisions) {
|
|
1988
|
+
const decConf = adapter.prepare(
|
|
1989
|
+
`SELECT m.id FROM decisions m INNER JOIN wt.decisions w ON m.id = w.id WHERE m.decision != w.decision OR m.choice != w.choice OR m.rationale != w.rationale OR ${
|
|
1990
|
+
hasMadeBy ? "m.made_by != w.made_by" : "'agent' != 'agent'"
|
|
1991
|
+
} OR m.superseded_by IS NOT w.superseded_by`,
|
|
1992
|
+
).all();
|
|
1993
|
+
for (const row of decConf) conflicts.push(`decision ${(row as Record<string, unknown>)["id"]}: modified in both`);
|
|
1994
|
+
}
|
|
1918
1995
|
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
for (const row of decConf) conflicts.push(`decision ${(row as Record<string, unknown>)["id"]}: modified in both`);
|
|
1925
|
-
|
|
1926
|
-
const reqConf = adapter.prepare(
|
|
1927
|
-
`SELECT m.id FROM requirements m INNER JOIN wt.requirements w ON m.id = w.id WHERE m.description != w.description OR m.status != w.status OR m.notes != w.notes OR m.superseded_by IS NOT w.superseded_by`,
|
|
1928
|
-
).all();
|
|
1929
|
-
for (const row of reqConf) conflicts.push(`requirement ${(row as Record<string, unknown>)["id"]}: modified in both`);
|
|
1930
|
-
|
|
1931
|
-
const merged: Omit<ReconcileResult, "conflicts"> = { decisions: 0, requirements: 0, artifacts: 0, milestones: 0, slices: 0, tasks: 0, memories: 0, verification_evidence: 0 };
|
|
1932
|
-
|
|
1933
|
-
function countChanges(result: unknown): number {
|
|
1934
|
-
return typeof result === "object" && result !== null ? ((result as { changes?: number }).changes ?? 0) : 0;
|
|
1996
|
+
if (hasWtRequirements) {
|
|
1997
|
+
const reqConf = adapter.prepare(
|
|
1998
|
+
`SELECT m.id FROM requirements m INNER JOIN wt.requirements w ON m.id = w.id WHERE m.description != w.description OR m.status != w.status OR m.notes != w.notes OR m.superseded_by IS NOT w.superseded_by`,
|
|
1999
|
+
).all();
|
|
2000
|
+
for (const row of reqConf) conflicts.push(`requirement ${(row as Record<string, unknown>)["id"]}: modified in both`);
|
|
1935
2001
|
}
|
|
1936
2002
|
|
|
2003
|
+
const merged: Omit<ReconcileResult, "conflicts"> = {
|
|
2004
|
+
decisions: 0,
|
|
2005
|
+
requirements: 0,
|
|
2006
|
+
artifacts: 0,
|
|
2007
|
+
milestones: 0,
|
|
2008
|
+
slices: 0,
|
|
2009
|
+
tasks: 0,
|
|
2010
|
+
memories: 0,
|
|
2011
|
+
replan_history: 0,
|
|
2012
|
+
assessments: 0,
|
|
2013
|
+
quality_gates: 0,
|
|
2014
|
+
slice_dependencies: 0,
|
|
2015
|
+
verification_evidence: 0,
|
|
2016
|
+
gate_runs: 0,
|
|
2017
|
+
milestone_commit_attributions: 0,
|
|
2018
|
+
};
|
|
2019
|
+
const sliceTargetRepositoriesSql = hasSliceTargetRepositories
|
|
2020
|
+
? `CASE
|
|
2021
|
+
WHEN w.target_repositories = '[]' AND COALESCE(m.target_repositories, '[]') <> '[]'
|
|
2022
|
+
THEN m.target_repositories
|
|
2023
|
+
ELSE COALESCE(w.target_repositories, m.target_repositories, '[]')
|
|
2024
|
+
END`
|
|
2025
|
+
: "COALESCE(m.target_repositories, '[]')";
|
|
2026
|
+
const taskTargetRepositoriesSql = hasTaskTargetRepositories
|
|
2027
|
+
? `CASE
|
|
2028
|
+
WHEN w.target_repositories = '[]' AND COALESCE(m.target_repositories, '[]') <> '[]'
|
|
2029
|
+
THEN m.target_repositories
|
|
2030
|
+
ELSE COALESCE(w.target_repositories, m.target_repositories, '[]')
|
|
2031
|
+
END`
|
|
2032
|
+
: "COALESCE(m.target_repositories, '[]')";
|
|
2033
|
+
|
|
1937
2034
|
adapter.exec("BEGIN");
|
|
1938
2035
|
try {
|
|
1939
2036
|
// Join the target decisions so we can prefer an existing main.source
|
|
1940
2037
|
// when the worktree predates v16 — otherwise a write-through reconcile
|
|
1941
2038
|
// would clobber 'escalation'-sourced decisions with the literal default.
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
2039
|
+
if (hasWtDecisions) {
|
|
2040
|
+
merged.decisions = countChanges(adapter.prepare(`
|
|
2041
|
+
INSERT INTO decisions (
|
|
2042
|
+
id, when_context, scope, decision, choice, rationale, revisable, made_by, source, superseded_by
|
|
2043
|
+
)
|
|
2044
|
+
SELECT w.id, w.when_context, w.scope, w.decision, w.choice, w.rationale, w.revisable, ${
|
|
2045
|
+
hasMadeBy ? "w.made_by" : "COALESCE(m.made_by, 'agent')"
|
|
2046
|
+
}, ${
|
|
2047
|
+
hasDecisionSource ? "w.source" : "COALESCE(m.source, 'discussion')"
|
|
2048
|
+
}, w.superseded_by
|
|
2049
|
+
FROM wt.decisions w
|
|
2050
|
+
LEFT JOIN decisions m ON m.id = w.id
|
|
2051
|
+
WHERE true
|
|
2052
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
2053
|
+
when_context = excluded.when_context,
|
|
2054
|
+
scope = excluded.scope,
|
|
2055
|
+
decision = excluded.decision,
|
|
2056
|
+
choice = excluded.choice,
|
|
2057
|
+
rationale = excluded.rationale,
|
|
2058
|
+
revisable = excluded.revisable,
|
|
2059
|
+
made_by = excluded.made_by,
|
|
2060
|
+
source = excluded.source,
|
|
2061
|
+
superseded_by = excluded.superseded_by
|
|
2062
|
+
`).run());
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
if (hasWtRequirements) {
|
|
2066
|
+
merged.requirements = countChanges(adapter.prepare(`
|
|
2067
|
+
INSERT OR REPLACE INTO requirements (
|
|
2068
|
+
id, class, status, description, why, source, primary_owner,
|
|
2069
|
+
supporting_slices, validation, notes, full_content, superseded_by
|
|
2070
|
+
)
|
|
2071
|
+
SELECT id, class, status, description, why, source, primary_owner,
|
|
2072
|
+
supporting_slices, validation, notes, full_content, superseded_by
|
|
2073
|
+
FROM wt.requirements
|
|
2074
|
+
`).run());
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
// Always recompute artifact hashes from the content being merged. Older
|
|
2078
|
+
// worktree DBs may not have content_hash at all, and migrated old DBs can
|
|
2079
|
+
// carry stale default/null hashes after their content changed.
|
|
2080
|
+
if (hasWtArtifacts) {
|
|
2081
|
+
const artifactRows = adapter.prepare(`
|
|
2082
|
+
SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
|
|
2083
|
+
FROM wt.artifacts
|
|
2084
|
+
`).all() as Array<Record<string, unknown>>;
|
|
2085
|
+
const artifactStmt = adapter.prepare(`
|
|
2086
|
+
INSERT OR REPLACE INTO artifacts (
|
|
2087
|
+
path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash
|
|
2088
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
2089
|
+
`);
|
|
2090
|
+
for (const row of artifactRows) {
|
|
2091
|
+
const fullContent = String(row["full_content"] ?? "");
|
|
2092
|
+
merged.artifacts += countChanges(artifactStmt.run(
|
|
2093
|
+
row["path"],
|
|
2094
|
+
row["artifact_type"],
|
|
2095
|
+
row["milestone_id"] ?? null,
|
|
2096
|
+
row["slice_id"] ?? null,
|
|
2097
|
+
row["task_id"] ?? null,
|
|
2098
|
+
fullContent,
|
|
2099
|
+
row["imported_at"],
|
|
2100
|
+
createHash("sha256").update(fullContent).digest("hex"),
|
|
2101
|
+
));
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
1977
2104
|
|
|
1978
2105
|
// Merge milestones — worktree may have updated status/planning fields.
|
|
1979
2106
|
// Never downgrade status: complete > active > pre-planning (#4372).
|
|
1980
2107
|
// A stale worktree may carry an older 'active' status for a milestone
|
|
1981
2108
|
// that the main DB has already marked 'complete'; preserve the higher status.
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2109
|
+
if (hasWtMilestones) {
|
|
2110
|
+
merged.milestones = countChanges(adapter.prepare(`
|
|
2111
|
+
INSERT OR REPLACE INTO milestones (
|
|
2112
|
+
id, title, status, depends_on, created_at, completed_at,
|
|
2113
|
+
vision, success_criteria, key_risks, proof_strategy,
|
|
2114
|
+
verification_contract, verification_integration, verification_operational, verification_uat,
|
|
2115
|
+
definition_of_done, requirement_coverage, boundary_map_markdown, sequence
|
|
2116
|
+
)
|
|
2117
|
+
SELECT w.id, w.title,
|
|
2118
|
+
CASE
|
|
2119
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2120
|
+
THEN m.status ELSE w.status
|
|
2121
|
+
END,
|
|
2122
|
+
w.depends_on,
|
|
2123
|
+
CASE
|
|
2124
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2125
|
+
THEN m.created_at ELSE w.created_at
|
|
2126
|
+
END,
|
|
2127
|
+
CASE
|
|
2128
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2129
|
+
THEN m.completed_at ELSE w.completed_at
|
|
2130
|
+
END,
|
|
2131
|
+
w.vision, w.success_criteria, w.key_risks, w.proof_strategy,
|
|
2132
|
+
w.verification_contract, w.verification_integration, w.verification_operational, w.verification_uat,
|
|
2133
|
+
w.definition_of_done, w.requirement_coverage, w.boundary_map_markdown,
|
|
2134
|
+
${hasMilestoneSequence ? "COALESCE(w.sequence, 0)" : "COALESCE(m.sequence, 0)"}
|
|
2135
|
+
FROM wt.milestones w
|
|
2136
|
+
LEFT JOIN milestones m ON m.id = w.id
|
|
2137
|
+
`).run());
|
|
2138
|
+
}
|
|
2010
2139
|
|
|
2011
2140
|
// Merge slices — preserve worktree progress but never downgrade completed status (#2558).
|
|
2012
2141
|
// ADR-011 Phase 1: carry is_sketch + sketch_scope so reconcile doesn't
|
|
2013
2142
|
// silently clear sketch metadata. When the worktree predates v16,
|
|
2014
2143
|
// fall back to the main DB's existing value rather than a literal 0/''.
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2144
|
+
if (hasWtSlices) {
|
|
2145
|
+
merged.slices = countChanges(adapter.prepare(`
|
|
2146
|
+
INSERT OR REPLACE INTO slices (
|
|
2147
|
+
milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
|
|
2148
|
+
full_summary_md, full_uat_md, goal, success_criteria, proof_level,
|
|
2149
|
+
integration_closure, observability_impact, target_repositories, sequence, replan_triggered_at,
|
|
2150
|
+
is_sketch, sketch_scope
|
|
2151
|
+
)
|
|
2152
|
+
SELECT w.milestone_id, w.id, w.title,
|
|
2153
|
+
CASE
|
|
2154
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2155
|
+
THEN m.status ELSE w.status
|
|
2156
|
+
END,
|
|
2157
|
+
w.risk, w.depends, w.demo, w.created_at,
|
|
2158
|
+
CASE
|
|
2159
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2160
|
+
THEN m.completed_at ELSE w.completed_at
|
|
2161
|
+
END,
|
|
2162
|
+
w.full_summary_md, w.full_uat_md, w.goal, w.success_criteria, w.proof_level,
|
|
2163
|
+
w.integration_closure, w.observability_impact,
|
|
2164
|
+
${sliceTargetRepositoriesSql},
|
|
2165
|
+
w.sequence, w.replan_triggered_at,
|
|
2166
|
+
${hasIsSketch ? "w.is_sketch" : "COALESCE(m.is_sketch, 0)"},
|
|
2167
|
+
${hasSketchScope ? "w.sketch_scope" : "COALESCE(m.sketch_scope, '')"}
|
|
2168
|
+
FROM wt.slices w
|
|
2169
|
+
LEFT JOIN slices m ON m.milestone_id = w.milestone_id AND m.id = w.id
|
|
2170
|
+
`).run());
|
|
2171
|
+
}
|
|
2041
2172
|
|
|
2042
2173
|
// Merge tasks — preserve execution results, never downgrade completed status (#2558).
|
|
2043
2174
|
// ADR-011 P2: carry blocker_source + escalation_* columns so worktree reconcile
|
|
2044
2175
|
// doesn't silently clear escalation state back to defaults.
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2176
|
+
if (hasWtTasks) {
|
|
2177
|
+
merged.tasks = countChanges(adapter.prepare(`
|
|
2178
|
+
INSERT OR REPLACE INTO tasks (
|
|
2179
|
+
milestone_id, slice_id, id, title, status, one_liner, narrative,
|
|
2180
|
+
verification_result, duration, completed_at, blocker_discovered,
|
|
2181
|
+
deviations, known_issues, key_files, key_decisions, full_summary_md,
|
|
2182
|
+
description, estimate, files, verify, inputs, expected_output,
|
|
2183
|
+
observability_impact, full_plan_md, target_repositories, sequence,
|
|
2184
|
+
blocker_source, escalation_pending, escalation_awaiting_review,
|
|
2185
|
+
escalation_artifact_path, escalation_override_applied_at
|
|
2186
|
+
)
|
|
2187
|
+
SELECT w.milestone_id, w.slice_id, w.id, w.title,
|
|
2188
|
+
CASE
|
|
2189
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2190
|
+
THEN m.status ELSE w.status
|
|
2191
|
+
END,
|
|
2192
|
+
w.one_liner, w.narrative,
|
|
2193
|
+
w.verification_result, w.duration,
|
|
2194
|
+
CASE
|
|
2195
|
+
WHEN m.status IN (${TERMINAL_STATUS_SQL}) AND w.status NOT IN (${TERMINAL_STATUS_SQL})
|
|
2196
|
+
THEN m.completed_at ELSE w.completed_at
|
|
2197
|
+
END,
|
|
2198
|
+
w.blocker_discovered,
|
|
2199
|
+
w.deviations, w.known_issues, w.key_files, w.key_decisions, w.full_summary_md,
|
|
2200
|
+
w.description, w.estimate, w.files, w.verify, w.inputs, w.expected_output,
|
|
2201
|
+
w.observability_impact, w.full_plan_md,
|
|
2202
|
+
${taskTargetRepositoriesSql},
|
|
2203
|
+
w.sequence,
|
|
2204
|
+
${hasBlockerSource ? "w.blocker_source" : "COALESCE(m.blocker_source, '')"},
|
|
2205
|
+
${hasEscalationPending ? "w.escalation_pending" : "COALESCE(m.escalation_pending, 0)"},
|
|
2206
|
+
${hasEscalationAwaiting ? "w.escalation_awaiting_review" : "COALESCE(m.escalation_awaiting_review, 0)"},
|
|
2207
|
+
${hasEscalationArtifact ? "w.escalation_artifact_path" : "m.escalation_artifact_path"},
|
|
2208
|
+
${hasEscalationOverride ? "w.escalation_override_applied_at" : "m.escalation_override_applied_at"}
|
|
2209
|
+
FROM wt.tasks w
|
|
2210
|
+
LEFT JOIN tasks m ON m.milestone_id = w.milestone_id AND m.slice_id = w.slice_id AND m.id = w.id
|
|
2211
|
+
`).run());
|
|
2212
|
+
}
|
|
2080
2213
|
|
|
2081
2214
|
// Merge memories — keep worktree-learned insights.
|
|
2082
2215
|
// V18 (scope, tags), V21 (structured_fields), V28 (last_hit_at): for each
|
|
2083
2216
|
// column the wt may not yet have (older worktree DB), fall back to the
|
|
2084
2217
|
// main DB's existing value via LEFT JOIN so reconcile never silently
|
|
2085
2218
|
// resets these fields to defaults on rows that already had them.
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2219
|
+
if (hasWtMemories) {
|
|
2220
|
+
merged.memories = countChanges(adapter.prepare(`
|
|
2221
|
+
INSERT OR REPLACE INTO memories (
|
|
2222
|
+
seq, id, category, content, confidence, source_unit_type, source_unit_id,
|
|
2223
|
+
created_at, updated_at, superseded_by, hit_count,
|
|
2224
|
+
scope, tags, structured_fields, last_hit_at
|
|
2225
|
+
)
|
|
2226
|
+
SELECT w.seq, w.id, w.category, w.content, w.confidence, w.source_unit_type, w.source_unit_id,
|
|
2227
|
+
w.created_at, w.updated_at, w.superseded_by, w.hit_count,
|
|
2228
|
+
${hasMemoryScope ? "w.scope" : "COALESCE(m.scope, 'project')"},
|
|
2229
|
+
${hasMemoryTags ? "w.tags" : "COALESCE(m.tags, '[]')"},
|
|
2230
|
+
${hasMemoryStructuredFields ? "w.structured_fields" : "m.structured_fields"},
|
|
2231
|
+
${hasMemoryLastHitAt ? "w.last_hit_at" : "m.last_hit_at"}
|
|
2232
|
+
FROM wt.memories w
|
|
2233
|
+
LEFT JOIN memories m ON m.id = w.id
|
|
2234
|
+
`).run());
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
if (hasWtReplanHistory) {
|
|
2238
|
+
merged.replan_history = countChanges(adapter.prepare(`
|
|
2239
|
+
INSERT INTO replan_history (
|
|
2240
|
+
milestone_id, slice_id, task_id, summary, previous_artifact_path, replacement_artifact_path, created_at
|
|
2241
|
+
)
|
|
2242
|
+
SELECT w.milestone_id, w.slice_id, w.task_id, w.summary, w.previous_artifact_path, w.replacement_artifact_path, w.created_at
|
|
2243
|
+
FROM wt.replan_history w
|
|
2244
|
+
WHERE EXISTS (SELECT 1 FROM milestones m WHERE m.id = w.milestone_id)
|
|
2245
|
+
AND NOT EXISTS (
|
|
2246
|
+
SELECT 1 FROM replan_history m
|
|
2247
|
+
WHERE m.milestone_id = w.milestone_id
|
|
2248
|
+
AND m.slice_id IS w.slice_id
|
|
2249
|
+
AND m.task_id IS w.task_id
|
|
2250
|
+
AND m.summary = w.summary
|
|
2251
|
+
AND m.previous_artifact_path IS w.previous_artifact_path
|
|
2252
|
+
AND m.replacement_artifact_path IS w.replacement_artifact_path
|
|
2253
|
+
)
|
|
2254
|
+
`).run());
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
if (hasWtAssessments) {
|
|
2258
|
+
merged.assessments = countChanges(adapter.prepare(`
|
|
2259
|
+
INSERT OR REPLACE INTO assessments (
|
|
2260
|
+
path, milestone_id, slice_id, task_id, status, scope, full_content, created_at
|
|
2261
|
+
)
|
|
2262
|
+
SELECT w.path, w.milestone_id, w.slice_id, w.task_id, w.status, w.scope, w.full_content, w.created_at
|
|
2263
|
+
FROM wt.assessments w
|
|
2264
|
+
WHERE EXISTS (SELECT 1 FROM milestones m WHERE m.id = w.milestone_id)
|
|
2265
|
+
`).run());
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
if (hasWtQualityGates) {
|
|
2269
|
+
merged.quality_gates = countChanges(adapter.prepare(`
|
|
2270
|
+
INSERT OR REPLACE INTO quality_gates (
|
|
2271
|
+
milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at
|
|
2272
|
+
)
|
|
2273
|
+
SELECT w.milestone_id, w.slice_id, w.gate_id, w.scope, COALESCE(w.task_id, ''), w.status, w.verdict, w.rationale, w.findings, w.evaluated_at
|
|
2274
|
+
FROM wt.quality_gates w
|
|
2275
|
+
WHERE EXISTS (SELECT 1 FROM slices s WHERE s.milestone_id = w.milestone_id AND s.id = w.slice_id)
|
|
2276
|
+
`).run());
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
if (hasWtSliceDependencies) {
|
|
2280
|
+
merged.slice_dependencies = countChanges(adapter.prepare(`
|
|
2281
|
+
INSERT OR IGNORE INTO slice_dependencies (milestone_id, slice_id, depends_on_slice_id)
|
|
2282
|
+
SELECT w.milestone_id, w.slice_id, w.depends_on_slice_id
|
|
2283
|
+
FROM wt.slice_dependencies w
|
|
2284
|
+
WHERE EXISTS (SELECT 1 FROM slices s WHERE s.milestone_id = w.milestone_id AND s.id = w.slice_id)
|
|
2285
|
+
AND EXISTS (SELECT 1 FROM slices d WHERE d.milestone_id = w.milestone_id AND d.id = w.depends_on_slice_id)
|
|
2286
|
+
`).run());
|
|
2287
|
+
}
|
|
2101
2288
|
|
|
2102
2289
|
// Merge verification evidence — append-only, use INSERT OR IGNORE to avoid duplicates
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2290
|
+
if (hasWtVerificationEvidence) {
|
|
2291
|
+
merged.verification_evidence = countChanges(adapter.prepare(`
|
|
2292
|
+
INSERT OR IGNORE INTO verification_evidence (
|
|
2293
|
+
task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
|
|
2294
|
+
)
|
|
2295
|
+
SELECT task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
|
|
2296
|
+
FROM wt.verification_evidence
|
|
2297
|
+
`).run());
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
if (hasWtGateRuns) {
|
|
2301
|
+
merged.gate_runs = countChanges(adapter.prepare(`
|
|
2302
|
+
INSERT INTO gate_runs (
|
|
2303
|
+
trace_id, turn_id, gate_id, gate_type, unit_type, unit_id, milestone_id, slice_id, task_id,
|
|
2304
|
+
outcome, failure_class, rationale, findings, attempt, max_attempts, retryable, evaluated_at
|
|
2305
|
+
)
|
|
2306
|
+
SELECT w.trace_id, w.turn_id, w.gate_id, w.gate_type, w.unit_type, w.unit_id, w.milestone_id, w.slice_id, w.task_id,
|
|
2307
|
+
w.outcome, w.failure_class, w.rationale, w.findings, w.attempt, w.max_attempts, w.retryable, w.evaluated_at
|
|
2308
|
+
FROM wt.gate_runs w
|
|
2309
|
+
WHERE NOT EXISTS (
|
|
2310
|
+
SELECT 1 FROM gate_runs m
|
|
2311
|
+
WHERE m.trace_id = w.trace_id
|
|
2312
|
+
AND m.turn_id = w.turn_id
|
|
2313
|
+
AND m.gate_id = w.gate_id
|
|
2314
|
+
AND m.attempt = w.attempt
|
|
2315
|
+
AND m.evaluated_at = w.evaluated_at
|
|
2316
|
+
)
|
|
2317
|
+
`).run());
|
|
2318
|
+
}
|
|
2319
|
+
|
|
2320
|
+
if (hasWtMilestoneCommitAttributions) {
|
|
2321
|
+
merged.milestone_commit_attributions = countChanges(adapter.prepare(`
|
|
2322
|
+
INSERT OR REPLACE INTO milestone_commit_attributions (
|
|
2323
|
+
commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
|
|
2324
|
+
)
|
|
2325
|
+
SELECT w.commit_sha, w.milestone_id, w.slice_id, w.task_id, w.source, w.confidence, w.files_json, w.created_at
|
|
2326
|
+
FROM wt.milestone_commit_attributions w
|
|
2327
|
+
WHERE EXISTS (SELECT 1 FROM milestones m WHERE m.id = w.milestone_id)
|
|
2328
|
+
`).run());
|
|
2329
|
+
}
|
|
2110
2330
|
|
|
2111
2331
|
adapter.exec("COMMIT");
|
|
2112
2332
|
} catch (txErr) {
|
|
@@ -2364,12 +2584,13 @@ export function saveGateResult(g: {
|
|
|
2364
2584
|
findings: string;
|
|
2365
2585
|
}): void {
|
|
2366
2586
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
2367
|
-
|
|
2587
|
+
const evaluatedAt = new Date().toISOString();
|
|
2588
|
+
const result = currentDb.prepare(
|
|
2368
2589
|
`UPDATE quality_gates
|
|
2369
2590
|
SET status = 'complete', verdict = :verdict, rationale = :rationale,
|
|
2370
2591
|
findings = :findings, evaluated_at = :evaluated_at
|
|
2371
2592
|
WHERE milestone_id = :mid AND slice_id = :sid AND gate_id = :gid
|
|
2372
|
-
AND task_id = :tid`,
|
|
2593
|
+
AND (task_id = :tid OR (:tid = '' AND task_id IS NULL))`,
|
|
2373
2594
|
).run({
|
|
2374
2595
|
":mid": g.milestoneId,
|
|
2375
2596
|
":sid": g.sliceId,
|
|
@@ -2378,8 +2599,15 @@ export function saveGateResult(g: {
|
|
|
2378
2599
|
":verdict": g.verdict,
|
|
2379
2600
|
":rationale": g.rationale,
|
|
2380
2601
|
":findings": g.findings,
|
|
2381
|
-
":evaluated_at":
|
|
2382
|
-
});
|
|
2602
|
+
":evaluated_at": evaluatedAt,
|
|
2603
|
+
}) as { changes?: number };
|
|
2604
|
+
|
|
2605
|
+
if ((result.changes ?? 0) === 0) {
|
|
2606
|
+
throw new GSDError(
|
|
2607
|
+
GSD_STALE_STATE,
|
|
2608
|
+
`quality gate row not found for ${g.milestoneId}/${g.sliceId}/${g.gateId}${g.taskId ? `/${g.taskId}` : ""}`,
|
|
2609
|
+
);
|
|
2610
|
+
}
|
|
2383
2611
|
|
|
2384
2612
|
const outcome =
|
|
2385
2613
|
g.verdict === "pass"
|
|
@@ -2402,7 +2630,7 @@ export function saveGateResult(g: {
|
|
|
2402
2630
|
attempt: 1,
|
|
2403
2631
|
maxAttempts: 1,
|
|
2404
2632
|
retryable: false,
|
|
2405
|
-
evaluatedAt
|
|
2633
|
+
evaluatedAt,
|
|
2406
2634
|
});
|
|
2407
2635
|
}
|
|
2408
2636
|
|
|
@@ -2438,6 +2666,30 @@ export function markAllGatesOmitted(milestoneId: string, sliceId: string): void
|
|
|
2438
2666
|
});
|
|
2439
2667
|
}
|
|
2440
2668
|
|
|
2669
|
+
export function markPendingGatesOmittedForTurn(
|
|
2670
|
+
milestoneId: string,
|
|
2671
|
+
sliceId: string,
|
|
2672
|
+
turn: OwnerTurn,
|
|
2673
|
+
): void {
|
|
2674
|
+
if (!currentDb) return;
|
|
2675
|
+
const gateIds = [...getGateIdsForTurn(turn)];
|
|
2676
|
+
if (gateIds.length === 0) return;
|
|
2677
|
+
const placeholders = gateIds.map((_, i) => `:gid${i}`).join(",");
|
|
2678
|
+
const params: Record<string, unknown> = {
|
|
2679
|
+
":mid": milestoneId,
|
|
2680
|
+
":sid": sliceId,
|
|
2681
|
+
":now": new Date().toISOString(),
|
|
2682
|
+
};
|
|
2683
|
+
gateIds.forEach((id, index) => {
|
|
2684
|
+
params[`:gid${index}`] = id;
|
|
2685
|
+
});
|
|
2686
|
+
currentDb.prepare(
|
|
2687
|
+
`UPDATE quality_gates SET status = 'complete', verdict = 'omitted', evaluated_at = :now
|
|
2688
|
+
WHERE milestone_id = :mid AND slice_id = :sid AND status = 'pending'
|
|
2689
|
+
AND gate_id IN (${placeholders})`,
|
|
2690
|
+
).run(params);
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2441
2693
|
export function getPendingSliceGateCount(milestoneId: string, sliceId: string): number {
|
|
2442
2694
|
if (!currentDb) return 0;
|
|
2443
2695
|
const row = currentDb.prepare(
|
|
@@ -2858,21 +3110,75 @@ export function upsertQualityGate(g: {
|
|
|
2858
3110
|
|
|
2859
3111
|
/**
|
|
2860
3112
|
* Atomically replace all workflow state from a manifest. Lifted verbatim from
|
|
2861
|
-
* workflow-manifest.ts so the single-writer invariant holds.
|
|
2862
|
-
*
|
|
3113
|
+
* workflow-manifest.ts so the single-writer invariant holds. Restores
|
|
3114
|
+
* correctness-bearing workflow tables; runtime soft state and append-only audit
|
|
3115
|
+
* streams stay outside this recovery path.
|
|
2863
3116
|
*/
|
|
2864
3117
|
export function restoreManifest(manifest: StateManifest): void {
|
|
2865
3118
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
2866
3119
|
const db = currentDb;
|
|
2867
3120
|
|
|
2868
3121
|
transaction(() => {
|
|
2869
|
-
|
|
3122
|
+
const restoredMilestoneIds = new Set(manifest.milestones.map((m) => m.id));
|
|
3123
|
+
const restoredSliceKeys = new Set(manifest.slices.map((s) => JSON.stringify([s.milestone_id, s.id])));
|
|
3124
|
+
const preservedReplanHistory = manifest.replan_history === undefined
|
|
3125
|
+
? db.prepare("SELECT * FROM replan_history ORDER BY id").all() as unknown as NonNullable<StateManifest["replan_history"]>
|
|
3126
|
+
: [];
|
|
3127
|
+
const preservedAssessments = manifest.assessments === undefined
|
|
3128
|
+
? db.prepare("SELECT * FROM assessments ORDER BY path").all() as unknown as NonNullable<StateManifest["assessments"]>
|
|
3129
|
+
: [];
|
|
3130
|
+
const preservedQualityGates = manifest.quality_gates === undefined
|
|
3131
|
+
? db.prepare("SELECT * FROM quality_gates ORDER BY milestone_id, slice_id, gate_id, task_id").all() as unknown as NonNullable<StateManifest["quality_gates"]>
|
|
3132
|
+
: [];
|
|
3133
|
+
const preservedCommitAttributions = manifest.milestone_commit_attributions === undefined
|
|
3134
|
+
? db.prepare("SELECT * FROM milestone_commit_attributions ORDER BY milestone_id, commit_sha").all() as unknown as NonNullable<StateManifest["milestone_commit_attributions"]>
|
|
3135
|
+
: [];
|
|
3136
|
+
|
|
3137
|
+
// Clear workflow tables in dependency order.
|
|
2870
3138
|
db.exec("DELETE FROM verification_evidence");
|
|
3139
|
+
db.exec("DELETE FROM quality_gates");
|
|
3140
|
+
db.exec("DELETE FROM slice_dependencies");
|
|
3141
|
+
db.exec("DELETE FROM assessments");
|
|
3142
|
+
db.exec("DELETE FROM replan_history");
|
|
3143
|
+
db.exec("DELETE FROM milestone_commit_attributions");
|
|
2871
3144
|
db.exec("DELETE FROM tasks");
|
|
2872
3145
|
db.exec("DELETE FROM slices");
|
|
2873
3146
|
db.exec("DELETE FROM milestone_leases");
|
|
2874
3147
|
db.exec("DELETE FROM milestones");
|
|
2875
3148
|
db.exec("DELETE FROM decisions WHERE 1=1");
|
|
3149
|
+
db.exec(`DELETE FROM memories WHERE category = 'architecture' AND structured_fields LIKE '%"sourceDecisionId":"%'`);
|
|
3150
|
+
if (manifest.artifacts !== undefined) db.exec("DELETE FROM artifacts");
|
|
3151
|
+
if (manifest.requirements !== undefined) db.exec("DELETE FROM requirements");
|
|
3152
|
+
|
|
3153
|
+
if (manifest.requirements !== undefined) {
|
|
3154
|
+
const reqStmt = db.prepare(
|
|
3155
|
+
`INSERT INTO requirements (
|
|
3156
|
+
id, class, status, description, why, source, primary_owner,
|
|
3157
|
+
supporting_slices, validation, notes, full_content, superseded_by
|
|
3158
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3159
|
+
);
|
|
3160
|
+
for (const r of manifest.requirements) {
|
|
3161
|
+
reqStmt.run(
|
|
3162
|
+
r.id, r.class, r.status, r.description, r.why, r.source, r.primary_owner,
|
|
3163
|
+
r.supporting_slices, r.validation, r.notes, r.full_content, r.superseded_by,
|
|
3164
|
+
);
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
if (manifest.artifacts !== undefined) {
|
|
3169
|
+
const artStmt = db.prepare(
|
|
3170
|
+
`INSERT INTO artifacts (
|
|
3171
|
+
path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash
|
|
3172
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3173
|
+
);
|
|
3174
|
+
for (const a of manifest.artifacts) {
|
|
3175
|
+
const fullContent = a.full_content ?? "";
|
|
3176
|
+
artStmt.run(
|
|
3177
|
+
a.path, a.artifact_type, a.milestone_id, a.slice_id, a.task_id,
|
|
3178
|
+
fullContent, a.imported_at, a.content_hash ?? createHash("sha256").update(fullContent).digest("hex"),
|
|
3179
|
+
);
|
|
3180
|
+
}
|
|
3181
|
+
}
|
|
2876
3182
|
|
|
2877
3183
|
// Restore milestones
|
|
2878
3184
|
const msStmt = db.prepare(
|
|
@@ -2914,16 +3220,25 @@ export function restoreManifest(manifest: StateManifest): void {
|
|
|
2914
3220
|
);
|
|
2915
3221
|
}
|
|
2916
3222
|
|
|
3223
|
+
const depStmt = db.prepare(
|
|
3224
|
+
"INSERT OR IGNORE INTO slice_dependencies (milestone_id, slice_id, depends_on_slice_id) VALUES (?, ?, ?)",
|
|
3225
|
+
);
|
|
3226
|
+
for (const s of manifest.slices) {
|
|
3227
|
+
for (const dep of s.depends ?? []) {
|
|
3228
|
+
depStmt.run(s.milestone_id, s.id, dep);
|
|
3229
|
+
}
|
|
3230
|
+
}
|
|
3231
|
+
|
|
2917
3232
|
// Restore tasks (ADR-011 P2: includes blocker_source + escalation_* columns)
|
|
2918
3233
|
const tkStmt = db.prepare(
|
|
2919
3234
|
`INSERT INTO tasks (milestone_id, slice_id, id, title, status,
|
|
2920
3235
|
one_liner, narrative, verification_result, duration, completed_at,
|
|
2921
3236
|
blocker_discovered, deviations, known_issues, key_files, key_decisions,
|
|
2922
3237
|
full_summary_md, description, estimate, files, verify,
|
|
2923
|
-
inputs, expected_output, observability_impact, target_repositories, sequence,
|
|
3238
|
+
inputs, expected_output, observability_impact, full_plan_md, target_repositories, sequence,
|
|
2924
3239
|
blocker_source, escalation_pending, escalation_awaiting_review,
|
|
2925
3240
|
escalation_artifact_path, escalation_override_applied_at)
|
|
2926
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3241
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2927
3242
|
);
|
|
2928
3243
|
for (const t of manifest.tasks) {
|
|
2929
3244
|
tkStmt.run(
|
|
@@ -2933,7 +3248,7 @@ export function restoreManifest(manifest: StateManifest): void {
|
|
|
2933
3248
|
JSON.stringify(t.key_files), JSON.stringify(t.key_decisions),
|
|
2934
3249
|
t.full_summary_md, t.description, t.estimate, JSON.stringify(t.files), t.verify,
|
|
2935
3250
|
JSON.stringify(t.inputs), JSON.stringify(t.expected_output),
|
|
2936
|
-
t.observability_impact, JSON.stringify(t.target_repositories ?? []), t.sequence,
|
|
3251
|
+
t.observability_impact, t.full_plan_md ?? "", JSON.stringify(t.target_repositories ?? []), t.sequence,
|
|
2937
3252
|
t.blocker_source ?? "",
|
|
2938
3253
|
t.escalation_pending ?? 0,
|
|
2939
3254
|
t.escalation_awaiting_review ?? 0,
|
|
@@ -2951,6 +3266,69 @@ export function restoreManifest(manifest: StateManifest): void {
|
|
|
2951
3266
|
dcStmt.run(d.seq, d.id, d.when_context, d.scope, d.decision, d.choice, d.rationale, d.revisable, d.made_by, d.source ?? "discussion", d.superseded_by);
|
|
2952
3267
|
}
|
|
2953
3268
|
|
|
3269
|
+
const replanHistoryRows = manifest.replan_history ?? preservedReplanHistory.filter((r) => restoredMilestoneIds.has(r.milestone_id));
|
|
3270
|
+
if (replanHistoryRows.length > 0) {
|
|
3271
|
+
const replStmt = db.prepare(
|
|
3272
|
+
`INSERT INTO replan_history (
|
|
3273
|
+
id, milestone_id, slice_id, task_id, summary, previous_artifact_path, replacement_artifact_path, created_at
|
|
3274
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3275
|
+
);
|
|
3276
|
+
for (const r of replanHistoryRows) {
|
|
3277
|
+
replStmt.run(
|
|
3278
|
+
r.id, r.milestone_id, r.slice_id, r.task_id, r.summary,
|
|
3279
|
+
r.previous_artifact_path, r.replacement_artifact_path, r.created_at,
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
|
|
3284
|
+
const assessmentRows = manifest.assessments ?? preservedAssessments.filter((a) => restoredMilestoneIds.has(a.milestone_id));
|
|
3285
|
+
if (assessmentRows.length > 0) {
|
|
3286
|
+
const assessStmt = db.prepare(
|
|
3287
|
+
`INSERT INTO assessments (
|
|
3288
|
+
path, milestone_id, slice_id, task_id, status, scope, full_content, created_at
|
|
3289
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3290
|
+
);
|
|
3291
|
+
for (const a of assessmentRows) {
|
|
3292
|
+
assessStmt.run(
|
|
3293
|
+
a.path, a.milestone_id, a.slice_id, a.task_id,
|
|
3294
|
+
a.status, a.scope, a.full_content, a.created_at,
|
|
3295
|
+
);
|
|
3296
|
+
}
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
const qualityGateRows = manifest.quality_gates ?? preservedQualityGates.filter((g) => (
|
|
3300
|
+
restoredSliceKeys.has(JSON.stringify([g.milestone_id, g.slice_id]))
|
|
3301
|
+
));
|
|
3302
|
+
if (qualityGateRows.length > 0) {
|
|
3303
|
+
const gateStmt = db.prepare(
|
|
3304
|
+
`INSERT INTO quality_gates (
|
|
3305
|
+
milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at
|
|
3306
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3307
|
+
);
|
|
3308
|
+
for (const g of qualityGateRows) {
|
|
3309
|
+
gateStmt.run(
|
|
3310
|
+
g.milestone_id, g.slice_id, g.gate_id, g.scope, g.task_id,
|
|
3311
|
+
g.status, g.verdict ?? "", g.rationale, g.findings, g.evaluated_at,
|
|
3312
|
+
);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
|
|
3316
|
+
const commitAttributionRows = manifest.milestone_commit_attributions ??
|
|
3317
|
+
preservedCommitAttributions.filter((a) => restoredMilestoneIds.has(a.milestone_id));
|
|
3318
|
+
if (commitAttributionRows.length > 0) {
|
|
3319
|
+
const attrStmt = db.prepare(
|
|
3320
|
+
`INSERT OR REPLACE INTO milestone_commit_attributions (
|
|
3321
|
+
commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
|
|
3322
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3323
|
+
);
|
|
3324
|
+
for (const a of commitAttributionRows) {
|
|
3325
|
+
attrStmt.run(
|
|
3326
|
+
a.commit_sha, a.milestone_id, a.slice_id, a.task_id,
|
|
3327
|
+
a.source, a.confidence, a.files_json, a.created_at,
|
|
3328
|
+
);
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
|
|
2954
3332
|
// Restore verification evidence
|
|
2955
3333
|
const evStmt = db.prepare(
|
|
2956
3334
|
`INSERT INTO verification_evidence (task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at)
|