gsd-pi 2.49.0-dev.de3d9f6 → 2.50.0-dev.9476db8
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-ui.js +12 -2
- package/dist/headless.js +29 -13
- package/dist/resources/extensions/gsd/auto/infra-errors.js +1 -0
- package/dist/resources/extensions/gsd/auto/phases.js +11 -11
- package/dist/resources/extensions/gsd/auto/resolve.js +2 -2
- package/dist/resources/extensions/gsd/auto/run-unit.js +2 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +8 -10
- package/dist/resources/extensions/gsd/auto-dashboard.js +6 -3
- package/dist/resources/extensions/gsd/auto-dispatch.js +33 -21
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -24
- package/dist/resources/extensions/gsd/auto-prompts.js +102 -21
- package/dist/resources/extensions/gsd/auto-recovery.js +62 -184
- package/dist/resources/extensions/gsd/auto-start.js +4 -31
- package/dist/resources/extensions/gsd/auto-timers.js +2 -2
- package/dist/resources/extensions/gsd/auto-verification.js +4 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +257 -113
- package/dist/resources/extensions/gsd/auto.js +7 -5
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +89 -0
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -1
- package/dist/resources/extensions/gsd/branch-patterns.js +13 -0
- package/dist/resources/extensions/gsd/doctor-checks.js +5 -1234
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +168 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +28 -7
- package/dist/resources/extensions/gsd/doctor-git-checks.js +405 -0
- package/dist/resources/extensions/gsd/doctor-global-checks.js +74 -0
- package/dist/resources/extensions/gsd/doctor-runtime-checks.js +600 -0
- package/dist/resources/extensions/gsd/doctor.js +9 -1
- package/dist/resources/extensions/gsd/extension-manifest.json +1 -1
- package/dist/resources/extensions/gsd/git-service.js +9 -10
- package/dist/resources/extensions/gsd/gsd-db.js +124 -1
- package/dist/resources/extensions/gsd/guided-flow-queue.js +10 -11
- package/dist/resources/extensions/gsd/markdown-renderer.js +33 -5
- package/dist/resources/extensions/gsd/preferences-types.js +2 -1
- package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/dist/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/dist/resources/extensions/gsd/repo-identity.js +29 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +2 -2
- package/dist/resources/extensions/gsd/session-forensics.js +6 -11
- package/dist/resources/extensions/gsd/session-lock.js +67 -56
- package/dist/resources/extensions/gsd/state.js +34 -7
- package/dist/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/dist/resources/extensions/gsd/templates/plan.md +16 -0
- package/dist/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/dist/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/dist/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -1
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -3
- package/dist/resources/extensions/gsd/verdict-parser.js +84 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +24 -0
- package/dist/resources/extensions/gsd/worktree.js +3 -2
- package/dist/resources/extensions/remote-questions/config.js +3 -5
- package/dist/resources/extensions/search-the-web/native-search.js +8 -3
- package/dist/resources/extensions/search-the-web/tool-search.js +19 -2
- package/dist/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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 +15 -15
- package/dist/web/standalone/.next/server/chunks/229.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.7c75ac378de0f2b5.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-0a4cd455ec4197d2.js → webpack-2473ce2c3879fff4.js} +1 -1
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +4 -1
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/src/agent-loop.ts +4 -1
- package/packages/pi-ai/dist/providers/openai-codex-responses.js +39 -10
- package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-codex-responses.ts +39 -8
- package/packages/pi-coding-agent/dist/core/blob-store.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/blob-store.js +8 -3
- package/packages/pi-coding-agent/dist/core/blob-store.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/discovery-cache.js +9 -2
- package/packages/pi-coding-agent/dist/core/discovery-cache.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -32
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js +5 -0
- package/packages/pi-coding-agent/dist/modes/rpc/jsonl.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +0 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/blob-store.ts +6 -3
- package/packages/pi-coding-agent/src/core/discovery-cache.ts +9 -2
- package/packages/pi-coding-agent/src/core/retry-handler.ts +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +7 -32
- package/packages/pi-coding-agent/src/modes/rpc/jsonl.ts +6 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -2
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/infra-errors.ts +1 -0
- package/src/resources/extensions/gsd/auto/phases.ts +10 -11
- package/src/resources/extensions/gsd/auto/resolve.ts +3 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +2 -2
- package/src/resources/extensions/gsd/auto/session.ts +5 -0
- package/src/resources/extensions/gsd/auto/types.ts +13 -0
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +19 -21
- package/src/resources/extensions/gsd/auto-dashboard.ts +5 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +39 -21
- package/src/resources/extensions/gsd/auto-loop.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +18 -28
- package/src/resources/extensions/gsd/auto-prompts.ts +113 -19
- package/src/resources/extensions/gsd/auto-recovery.ts +65 -199
- package/src/resources/extensions/gsd/auto-start.ts +7 -27
- package/src/resources/extensions/gsd/auto-timers.ts +2 -2
- package/src/resources/extensions/gsd/auto-verification.ts +4 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +305 -108
- package/src/resources/extensions/gsd/auto.ts +11 -10
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +93 -0
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
- package/src/resources/extensions/gsd/branch-patterns.ts +16 -0
- package/src/resources/extensions/gsd/doctor-checks.ts +5 -1291
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +182 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +30 -7
- package/src/resources/extensions/gsd/doctor-git-checks.ts +415 -0
- package/src/resources/extensions/gsd/doctor-global-checks.ts +84 -0
- package/src/resources/extensions/gsd/doctor-runtime-checks.ts +626 -0
- package/src/resources/extensions/gsd/doctor.ts +9 -1
- package/src/resources/extensions/gsd/extension-manifest.json +1 -1
- package/src/resources/extensions/gsd/git-service.ts +7 -15
- package/src/resources/extensions/gsd/gsd-db.ts +150 -2
- package/src/resources/extensions/gsd/guided-flow-queue.ts +11 -12
- package/src/resources/extensions/gsd/markdown-renderer.ts +37 -4
- package/src/resources/extensions/gsd/preferences-types.ts +5 -1
- package/src/resources/extensions/gsd/preferences-validation.ts +37 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +27 -8
- package/src/resources/extensions/gsd/prompts/complete-slice.md +9 -8
- package/src/resources/extensions/gsd/prompts/execute-task.md +16 -13
- package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
- package/src/resources/extensions/gsd/prompts/gate-evaluate.md +32 -0
- package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
- package/src/resources/extensions/gsd/prompts/plan-slice.md +8 -3
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +3 -0
- package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
- package/src/resources/extensions/gsd/repo-identity.ts +28 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +2 -2
- package/src/resources/extensions/gsd/session-forensics.ts +6 -11
- package/src/resources/extensions/gsd/session-lock.ts +92 -64
- package/src/resources/extensions/gsd/state.ts +38 -5
- package/src/resources/extensions/gsd/templates/milestone-summary.md +8 -0
- package/src/resources/extensions/gsd/templates/plan.md +16 -0
- package/src/resources/extensions/gsd/templates/roadmap.md +13 -0
- package/src/resources/extensions/gsd/templates/slice-summary.md +9 -0
- package/src/resources/extensions/gsd/templates/task-plan.md +24 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +35 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +1 -81
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +9 -12
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +115 -1
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +65 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +50 -0
- package/src/resources/extensions/gsd/tests/gate-dispatch.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +156 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/quality-gates.test.ts +347 -0
- package/src/resources/extensions/gsd/tests/queue-completed-milestone-perf.test.ts +155 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +20 -16
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +44 -4
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/verification-gate.test.ts +0 -16
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +204 -0
- package/src/resources/extensions/gsd/tools/plan-slice.ts +16 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +3 -3
- package/src/resources/extensions/gsd/types.ts +30 -0
- package/src/resources/extensions/gsd/verdict-parser.ts +95 -0
- package/src/resources/extensions/gsd/verification-gate.ts +0 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +31 -0
- package/src/resources/extensions/gsd/worktree.ts +3 -2
- package/src/resources/extensions/remote-questions/config.ts +3 -5
- package/src/resources/extensions/search-the-web/native-search.ts +8 -3
- package/src/resources/extensions/search-the-web/tool-search.ts +22 -2
- package/src/resources/skills/github-workflows/references/gh/SKILL.md +22 -1
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -191
- package/dist/resources/extensions/gsd/resource-version.js +0 -97
- package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +0 -9
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -234
- package/src/resources/extensions/gsd/resource-version.ts +0 -101
- /package/dist/web/standalone/.next/static/{ceckLbAMjhzHaQ3RPtJnT → MkE9kzqUGny3-cSE0GNnm}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{ceckLbAMjhzHaQ3RPtJnT → MkE9kzqUGny3-cSE0GNnm}/_ssgManifest.js +0 -0
|
@@ -450,7 +450,15 @@ export async function runGSDDoctor(basePath, options) {
|
|
|
450
450
|
}));
|
|
451
451
|
}
|
|
452
452
|
else {
|
|
453
|
-
|
|
453
|
+
const activeMilestoneId = state.activeMilestone?.id;
|
|
454
|
+
const activeSliceId = state.activeSlice?.id;
|
|
455
|
+
slices = parseLegacyRoadmap(roadmapContent).slices.map(s => ({
|
|
456
|
+
...s,
|
|
457
|
+
// Legacy roadmaps only encode done vs not-done. For doctor's
|
|
458
|
+
// missing-directory checks, treat every undone slice except the
|
|
459
|
+
// current active slice as effectively pending/unstarted.
|
|
460
|
+
pending: !s.done && (milestoneId !== activeMilestoneId || s.id !== activeSliceId),
|
|
461
|
+
}));
|
|
454
462
|
}
|
|
455
463
|
// Wrap in Roadmap-compatible shape for detectCircularDependencies
|
|
456
464
|
const roadmap = { slices };
|
|
@@ -13,7 +13,8 @@ import { join } from "node:path";
|
|
|
13
13
|
import { gsdRoot } from "./paths.js";
|
|
14
14
|
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
|
15
15
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
16
|
-
import { detectWorktreeName,
|
|
16
|
+
import { detectWorktreeName, } from "./worktree.js";
|
|
17
|
+
import { SLICE_BRANCH_RE, QUICK_BRANCH_RE, WORKFLOW_BRANCH_RE } from "./branch-patterns.js";
|
|
17
18
|
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchExists, nativeHasChanges, nativeAddAllWithExclusions, nativeHasStagedChanges, nativeCommit, nativeRmCached, nativeUpdateRef, } from "./native-git-bridge.js";
|
|
18
19
|
import { GSDError, GSD_MERGE_CONFLICT, GSD_GIT_ERROR } from "./errors.js";
|
|
19
20
|
import { getErrorMessage } from "./error-utils.js";
|
|
@@ -133,8 +134,8 @@ export function readIntegrationBranch(basePath, milestoneId) {
|
|
|
133
134
|
*
|
|
134
135
|
* The file is committed immediately so the metadata is persisted in git.
|
|
135
136
|
*/
|
|
136
|
-
/**
|
|
137
|
-
export
|
|
137
|
+
/** Re-export for backward compatibility — canonical definitions in branch-patterns.ts */
|
|
138
|
+
export { QUICK_BRANCH_RE, WORKFLOW_BRANCH_RE } from "./branch-patterns.js";
|
|
138
139
|
export function writeIntegrationBranch(basePath, milestoneId, branch) {
|
|
139
140
|
// Don't record slice branches as the integration target
|
|
140
141
|
if (SLICE_BRANCH_RE.test(branch))
|
|
@@ -144,6 +145,11 @@ export function writeIntegrationBranch(basePath, milestoneId, branch) {
|
|
|
144
145
|
// target causes milestone merges to land on the wrong branch (#1293).
|
|
145
146
|
if (QUICK_BRANCH_RE.test(branch))
|
|
146
147
|
return;
|
|
148
|
+
// Don't record workflow-template branches (hotfix, bugfix, spike, etc.) —
|
|
149
|
+
// same root cause as quick-task branches (#2498). All templates create
|
|
150
|
+
// gsd/<templateId>/<slug> branches that are ephemeral.
|
|
151
|
+
if (WORKFLOW_BRANCH_RE.test(branch))
|
|
152
|
+
return;
|
|
147
153
|
// Validate
|
|
148
154
|
if (!VALID_BRANCH_NAME.test(branch))
|
|
149
155
|
return;
|
|
@@ -299,10 +305,6 @@ export class GitServiceImpl {
|
|
|
299
305
|
setMilestoneId(milestoneId) {
|
|
300
306
|
this._milestoneId = milestoneId;
|
|
301
307
|
}
|
|
302
|
-
/** Convenience wrapper: run git in this repo's basePath. */
|
|
303
|
-
git(args, options = {}) {
|
|
304
|
-
return runGit(this.basePath, args, options);
|
|
305
|
-
}
|
|
306
308
|
/**
|
|
307
309
|
* Smart staging: `git add -A` excluding GSD runtime paths via pathspec.
|
|
308
310
|
* Falls back to plain `git add -A` if the exclusion pathspec fails.
|
|
@@ -442,9 +444,6 @@ export class GitServiceImpl {
|
|
|
442
444
|
getCurrentBranch() {
|
|
443
445
|
return nativeGetCurrentBranch(this.basePath);
|
|
444
446
|
}
|
|
445
|
-
/** True if currently on a GSD slice branch. */
|
|
446
|
-
// ─── Branch Lifecycle ──────────────────────────────────────────────────
|
|
447
|
-
// ─── S05 Features ─────────────────────────────────────────────────────
|
|
448
447
|
/**
|
|
449
448
|
* Create a snapshot ref for the given label (typically a slice branch name).
|
|
450
449
|
* Gated on prefs.snapshots === true. Ref path: refs/gsd/snapshots/<label>/<timestamp>
|
|
@@ -109,7 +109,7 @@ function openRawDb(path) {
|
|
|
109
109
|
const Database = providerModule;
|
|
110
110
|
return new Database(path);
|
|
111
111
|
}
|
|
112
|
-
const SCHEMA_VERSION =
|
|
112
|
+
const SCHEMA_VERSION = 12;
|
|
113
113
|
function initSchema(db, fileBacked) {
|
|
114
114
|
if (fileBacked)
|
|
115
115
|
db.exec("PRAGMA journal_mode=WAL");
|
|
@@ -302,6 +302,22 @@ function initSchema(db, fileBacked) {
|
|
|
302
302
|
created_at TEXT NOT NULL DEFAULT '',
|
|
303
303
|
FOREIGN KEY (milestone_id) REFERENCES milestones(id)
|
|
304
304
|
)
|
|
305
|
+
`);
|
|
306
|
+
db.exec(`
|
|
307
|
+
CREATE TABLE IF NOT EXISTS quality_gates (
|
|
308
|
+
milestone_id TEXT NOT NULL,
|
|
309
|
+
slice_id TEXT NOT NULL,
|
|
310
|
+
gate_id TEXT NOT NULL,
|
|
311
|
+
scope TEXT NOT NULL DEFAULT 'slice',
|
|
312
|
+
task_id TEXT NOT NULL DEFAULT '',
|
|
313
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
314
|
+
verdict TEXT NOT NULL DEFAULT '',
|
|
315
|
+
rationale TEXT NOT NULL DEFAULT '',
|
|
316
|
+
findings TEXT NOT NULL DEFAULT '',
|
|
317
|
+
evaluated_at TEXT DEFAULT NULL,
|
|
318
|
+
PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
|
|
319
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
320
|
+
)
|
|
305
321
|
`);
|
|
306
322
|
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
|
|
307
323
|
db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
|
|
@@ -561,6 +577,28 @@ function migrateSchema(db) {
|
|
|
561
577
|
":applied_at": new Date().toISOString(),
|
|
562
578
|
});
|
|
563
579
|
}
|
|
580
|
+
if (currentVersion < 12) {
|
|
581
|
+
db.exec(`
|
|
582
|
+
CREATE TABLE IF NOT EXISTS quality_gates (
|
|
583
|
+
milestone_id TEXT NOT NULL,
|
|
584
|
+
slice_id TEXT NOT NULL,
|
|
585
|
+
gate_id TEXT NOT NULL,
|
|
586
|
+
scope TEXT NOT NULL DEFAULT 'slice',
|
|
587
|
+
task_id TEXT DEFAULT NULL,
|
|
588
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
589
|
+
verdict TEXT NOT NULL DEFAULT '',
|
|
590
|
+
rationale TEXT NOT NULL DEFAULT '',
|
|
591
|
+
findings TEXT NOT NULL DEFAULT '',
|
|
592
|
+
evaluated_at TEXT DEFAULT NULL,
|
|
593
|
+
PRIMARY KEY (milestone_id, slice_id, gate_id, COALESCE(task_id, '')),
|
|
594
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
595
|
+
)
|
|
596
|
+
`);
|
|
597
|
+
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
|
|
598
|
+
":version": 12,
|
|
599
|
+
":applied_at": new Date().toISOString(),
|
|
600
|
+
});
|
|
601
|
+
}
|
|
564
602
|
db.exec("COMMIT");
|
|
565
603
|
}
|
|
566
604
|
catch (err) {
|
|
@@ -1396,3 +1434,88 @@ export function getAssessment(path) {
|
|
|
1396
1434
|
const row = currentDb.prepare(`SELECT * FROM assessments WHERE path = :path`).get({ ":path": path });
|
|
1397
1435
|
return row ?? null;
|
|
1398
1436
|
}
|
|
1437
|
+
// ─── Quality Gates ───────────────────────────────────────────────────────
|
|
1438
|
+
function rowToGate(row) {
|
|
1439
|
+
return {
|
|
1440
|
+
milestone_id: row["milestone_id"],
|
|
1441
|
+
slice_id: row["slice_id"],
|
|
1442
|
+
gate_id: row["gate_id"],
|
|
1443
|
+
scope: row["scope"],
|
|
1444
|
+
task_id: row["task_id"] ?? "",
|
|
1445
|
+
status: row["status"],
|
|
1446
|
+
verdict: row["verdict"] || "",
|
|
1447
|
+
rationale: row["rationale"] || "",
|
|
1448
|
+
findings: row["findings"] || "",
|
|
1449
|
+
evaluated_at: row["evaluated_at"] ?? null,
|
|
1450
|
+
};
|
|
1451
|
+
}
|
|
1452
|
+
export function insertGateRow(g) {
|
|
1453
|
+
if (!currentDb)
|
|
1454
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1455
|
+
currentDb.prepare(`INSERT OR IGNORE INTO quality_gates (milestone_id, slice_id, gate_id, scope, task_id, status)
|
|
1456
|
+
VALUES (:mid, :sid, :gid, :scope, :tid, :status)`).run({
|
|
1457
|
+
":mid": g.milestoneId,
|
|
1458
|
+
":sid": g.sliceId,
|
|
1459
|
+
":gid": g.gateId,
|
|
1460
|
+
":scope": g.scope,
|
|
1461
|
+
":tid": g.taskId ?? "",
|
|
1462
|
+
":status": g.status ?? "pending",
|
|
1463
|
+
});
|
|
1464
|
+
}
|
|
1465
|
+
export function saveGateResult(g) {
|
|
1466
|
+
if (!currentDb)
|
|
1467
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1468
|
+
currentDb.prepare(`UPDATE quality_gates
|
|
1469
|
+
SET status = 'complete', verdict = :verdict, rationale = :rationale,
|
|
1470
|
+
findings = :findings, evaluated_at = :evaluated_at
|
|
1471
|
+
WHERE milestone_id = :mid AND slice_id = :sid AND gate_id = :gid
|
|
1472
|
+
AND task_id = :tid`).run({
|
|
1473
|
+
":mid": g.milestoneId,
|
|
1474
|
+
":sid": g.sliceId,
|
|
1475
|
+
":gid": g.gateId,
|
|
1476
|
+
":tid": g.taskId ?? "",
|
|
1477
|
+
":verdict": g.verdict,
|
|
1478
|
+
":rationale": g.rationale,
|
|
1479
|
+
":findings": g.findings,
|
|
1480
|
+
":evaluated_at": new Date().toISOString(),
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
export function getPendingGates(milestoneId, sliceId, scope) {
|
|
1484
|
+
if (!currentDb)
|
|
1485
|
+
return [];
|
|
1486
|
+
const sql = scope
|
|
1487
|
+
? `SELECT * FROM quality_gates WHERE milestone_id = :mid AND slice_id = :sid AND scope = :scope AND status = 'pending'`
|
|
1488
|
+
: `SELECT * FROM quality_gates WHERE milestone_id = :mid AND slice_id = :sid AND status = 'pending'`;
|
|
1489
|
+
const params = { ":mid": milestoneId, ":sid": sliceId };
|
|
1490
|
+
if (scope)
|
|
1491
|
+
params[":scope"] = scope;
|
|
1492
|
+
return currentDb.prepare(sql).all(params).map(rowToGate);
|
|
1493
|
+
}
|
|
1494
|
+
export function getGateResults(milestoneId, sliceId, scope) {
|
|
1495
|
+
if (!currentDb)
|
|
1496
|
+
return [];
|
|
1497
|
+
const sql = scope
|
|
1498
|
+
? `SELECT * FROM quality_gates WHERE milestone_id = :mid AND slice_id = :sid AND scope = :scope`
|
|
1499
|
+
: `SELECT * FROM quality_gates WHERE milestone_id = :mid AND slice_id = :sid`;
|
|
1500
|
+
const params = { ":mid": milestoneId, ":sid": sliceId };
|
|
1501
|
+
if (scope)
|
|
1502
|
+
params[":scope"] = scope;
|
|
1503
|
+
return currentDb.prepare(sql).all(params).map(rowToGate);
|
|
1504
|
+
}
|
|
1505
|
+
export function markAllGatesOmitted(milestoneId, sliceId) {
|
|
1506
|
+
if (!currentDb)
|
|
1507
|
+
return;
|
|
1508
|
+
currentDb.prepare(`UPDATE quality_gates SET status = 'omitted', verdict = 'omitted', evaluated_at = :now
|
|
1509
|
+
WHERE milestone_id = :mid AND slice_id = :sid AND status = 'pending'`).run({
|
|
1510
|
+
":mid": milestoneId,
|
|
1511
|
+
":sid": sliceId,
|
|
1512
|
+
":now": new Date().toISOString(),
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
export function getPendingSliceGateCount(milestoneId, sliceId) {
|
|
1516
|
+
if (!currentDb)
|
|
1517
|
+
return 0;
|
|
1518
|
+
const row = currentDb.prepare(`SELECT COUNT(*) as cnt FROM quality_gates
|
|
1519
|
+
WHERE milestone_id = :mid AND slice_id = :sid AND scope = 'slice' AND status = 'pending'`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
1520
|
+
return row ? row["cnt"] : 0;
|
|
1521
|
+
}
|
|
@@ -186,11 +186,20 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
186
186
|
sections.push(`### Decisions Register\nSource: \`${relGsdRootFile("DECISIONS")}\`\n\n${decisionsContent.trim()}`);
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
|
-
// For each milestone, include context and status
|
|
189
|
+
// For each milestone, include context and status.
|
|
190
|
+
// Completed milestones get a compact summary line only — loading their full
|
|
191
|
+
// CONTEXT.md + SUMMARY.md files is expensive and triggers 429 rate limits on
|
|
192
|
+
// projects with many completed milestones (#2379).
|
|
190
193
|
for (const mid of milestoneIds) {
|
|
191
194
|
const registryEntry = state.registry.find(m => m.id === mid);
|
|
192
195
|
const status = registryEntry?.status ?? "unknown";
|
|
193
196
|
const title = registryEntry?.title ?? mid;
|
|
197
|
+
// Completed milestones: emit a one-liner — the LLM only needs to know
|
|
198
|
+
// they exist for dedup/dependency purposes, not their full content.
|
|
199
|
+
if (status === "complete") {
|
|
200
|
+
sections.push(`### ${mid}: ${title}\n**Status:** complete`);
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
194
203
|
const parts = [];
|
|
195
204
|
parts.push(`### ${mid}: ${title}\n**Status:** ${status}`);
|
|
196
205
|
// Include context file — this is the primary content for understanding scope
|
|
@@ -211,16 +220,6 @@ export async function buildExistingMilestonesContext(basePath, milestoneIds, sta
|
|
|
211
220
|
}
|
|
212
221
|
}
|
|
213
222
|
}
|
|
214
|
-
// For completed milestones, include the summary if it exists
|
|
215
|
-
if (status === "complete") {
|
|
216
|
-
const summaryFile = resolveMilestoneFile(basePath, mid, "SUMMARY");
|
|
217
|
-
if (summaryFile) {
|
|
218
|
-
const content = await loadFile(summaryFile);
|
|
219
|
-
if (content) {
|
|
220
|
-
parts.push(`\n**Summary:**\n${content.trim()}`);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
223
|
// For active/pending/parked milestones, include the roadmap if it exists
|
|
225
224
|
// (shows what's planned but not yet built)
|
|
226
225
|
if (status === "active" || status === "pending" || status === "parked") {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
11
11
|
import { join, relative } from "node:path";
|
|
12
12
|
import { createRequire } from "node:module";
|
|
13
|
-
import { getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getTask, getSlice, getArtifact, insertArtifact, } from "./gsd-db.js";
|
|
13
|
+
import { getAllMilestones, getMilestone, getMilestoneSlices, getSliceTasks, getTask, getSlice, getArtifact, insertArtifact, getGateResults, } from "./gsd-db.js";
|
|
14
14
|
import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, gsdRoot, buildTaskFileName, buildSliceFileName, } from "./paths.js";
|
|
15
15
|
import { saveFile, clearParseCache } from "./files.js";
|
|
16
16
|
import { invalidateStateCache } from "./state.js";
|
|
@@ -127,7 +127,7 @@ function renderRoadmapMarkdown(milestone, slices) {
|
|
|
127
127
|
}
|
|
128
128
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
129
129
|
}
|
|
130
|
-
function renderTaskPlanMarkdown(task) {
|
|
130
|
+
function renderTaskPlanMarkdown(task, taskGates = []) {
|
|
131
131
|
const estimatedSteps = Math.max(1, task.description.trim().split(/\n+/).filter(Boolean).length || 1);
|
|
132
132
|
const estimatedFiles = task.files.length > 0
|
|
133
133
|
? task.files.length
|
|
@@ -186,9 +186,20 @@ function renderTaskPlanMarkdown(task) {
|
|
|
186
186
|
lines.push(task.observability_impact.trim());
|
|
187
187
|
lines.push("");
|
|
188
188
|
}
|
|
189
|
+
// ── Quality Gate Sections (Q5/Q6/Q7) ──────────────────────────────────
|
|
190
|
+
const gateLabels = { Q5: "Failure Modes", Q6: "Load Profile", Q7: "Negative Tests" };
|
|
191
|
+
for (const [gid, label] of Object.entries(gateLabels)) {
|
|
192
|
+
const gate = taskGates.find(g => g.gate_id === gid && g.status === "complete");
|
|
193
|
+
if (gate && gate.verdict !== "omitted") {
|
|
194
|
+
lines.push(`## ${label}`);
|
|
195
|
+
lines.push("");
|
|
196
|
+
lines.push(gate.findings.trim() || `- **Verdict:** ${gate.verdict}\n- **Rationale:** ${gate.rationale}`);
|
|
197
|
+
lines.push("");
|
|
198
|
+
}
|
|
199
|
+
}
|
|
189
200
|
return `${lines.join("\n").trimEnd()}\n`;
|
|
190
201
|
}
|
|
191
|
-
function renderSlicePlanMarkdown(slice, tasks) {
|
|
202
|
+
function renderSlicePlanMarkdown(slice, tasks, gates = []) {
|
|
192
203
|
const lines = [];
|
|
193
204
|
lines.push(`# ${slice.id}: ${slice.title || slice.id}`);
|
|
194
205
|
lines.push("");
|
|
@@ -206,6 +217,21 @@ function renderSlicePlanMarkdown(slice, tasks) {
|
|
|
206
217
|
lines.push("- Complete the planned slice outcomes.");
|
|
207
218
|
}
|
|
208
219
|
lines.push("");
|
|
220
|
+
// ── Quality Gate Sections (Q3/Q4) ────────────────────────────────────
|
|
221
|
+
const q3 = gates.find(g => g.gate_id === "Q3" && g.status === "complete");
|
|
222
|
+
if (q3 && q3.verdict !== "omitted") {
|
|
223
|
+
lines.push("## Threat Surface");
|
|
224
|
+
lines.push("");
|
|
225
|
+
lines.push(q3.findings.trim() || `- **Verdict:** ${q3.verdict}\n- **Rationale:** ${q3.rationale}`);
|
|
226
|
+
lines.push("");
|
|
227
|
+
}
|
|
228
|
+
const q4 = gates.find(g => g.gate_id === "Q4" && g.status === "complete");
|
|
229
|
+
if (q4 && q4.verdict !== "omitted") {
|
|
230
|
+
lines.push("## Requirement Impact");
|
|
231
|
+
lines.push("");
|
|
232
|
+
lines.push(q4.findings.trim() || `- **Verdict:** ${q4.verdict}\n- **Rationale:** ${q4.rationale}`);
|
|
233
|
+
lines.push("");
|
|
234
|
+
}
|
|
209
235
|
if (slice.proof_level.trim()) {
|
|
210
236
|
lines.push("## Proof Level");
|
|
211
237
|
lines.push("");
|
|
@@ -275,7 +301,8 @@ export async function renderPlanFromDb(basePath, milestoneId, sliceId) {
|
|
|
275
301
|
const absPath = resolveSliceFile(basePath, milestoneId, sliceId, "PLAN")
|
|
276
302
|
?? join(slicePath, `${sliceId}-PLAN.md`);
|
|
277
303
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
278
|
-
const
|
|
304
|
+
const sliceGates = getGateResults(milestoneId, sliceId, "slice");
|
|
305
|
+
const content = renderSlicePlanMarkdown(slice, tasks, sliceGates);
|
|
279
306
|
await writeAndStore(absPath, artifactPath, content, {
|
|
280
307
|
artifact_type: "PLAN",
|
|
281
308
|
milestone_id: milestoneId,
|
|
@@ -298,7 +325,8 @@ export async function renderTaskPlanFromDb(basePath, milestoneId, sliceId, taskI
|
|
|
298
325
|
mkdirSync(tasksDir, { recursive: true });
|
|
299
326
|
const absPath = join(tasksDir, buildTaskFileName(taskId, "PLAN"));
|
|
300
327
|
const artifactPath = toArtifactPath(absPath, basePath);
|
|
301
|
-
const
|
|
328
|
+
const taskGates = getGateResults(milestoneId, sliceId, "task").filter(g => g.task_id === taskId);
|
|
329
|
+
const content = task.full_plan_md.trim() ? task.full_plan_md : renderTaskPlanMarkdown(task, taskGates);
|
|
302
330
|
await writeAndStore(absPath, artifactPath, content, {
|
|
303
331
|
artifact_type: "PLAN",
|
|
304
332
|
milestone_id: milestoneId,
|
|
@@ -65,6 +65,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
65
65
|
"context_selection",
|
|
66
66
|
"widget_mode",
|
|
67
67
|
"reactive_execution",
|
|
68
|
+
"gate_evaluation",
|
|
68
69
|
"github",
|
|
69
70
|
"service_tier",
|
|
70
71
|
"forensics_dedup",
|
|
@@ -73,7 +74,7 @@ export const KNOWN_PREFERENCE_KEYS = new Set([
|
|
|
73
74
|
/** Canonical list of all dispatch unit types. */
|
|
74
75
|
export const KNOWN_UNIT_TYPES = [
|
|
75
76
|
"research-milestone", "plan-milestone", "research-slice", "plan-slice",
|
|
76
|
-
"execute-task", "reactive-execute", "complete-slice", "replan-slice", "reassess-roadmap",
|
|
77
|
+
"execute-task", "reactive-execute", "gate-evaluate", "complete-slice", "replan-slice", "reassess-roadmap",
|
|
77
78
|
"run-uat", "complete-milestone",
|
|
78
79
|
];
|
|
79
80
|
export const SKILL_ACTIONS = new Set(["use", "prefer", "avoid"]);
|
|
@@ -542,6 +542,45 @@ export function validatePreferences(preferences) {
|
|
|
542
542
|
errors.push("reactive_execution must be an object");
|
|
543
543
|
}
|
|
544
544
|
}
|
|
545
|
+
// ─── Gate Evaluation ─────────────────────────────────────────────────────
|
|
546
|
+
if (preferences.gate_evaluation !== undefined) {
|
|
547
|
+
if (typeof preferences.gate_evaluation === "object" && preferences.gate_evaluation !== null) {
|
|
548
|
+
const ge = preferences.gate_evaluation;
|
|
549
|
+
const validGe = {};
|
|
550
|
+
if (ge.enabled !== undefined) {
|
|
551
|
+
if (typeof ge.enabled === "boolean")
|
|
552
|
+
validGe.enabled = ge.enabled;
|
|
553
|
+
else
|
|
554
|
+
errors.push("gate_evaluation.enabled must be a boolean");
|
|
555
|
+
}
|
|
556
|
+
if (ge.slice_gates !== undefined) {
|
|
557
|
+
if (Array.isArray(ge.slice_gates) && ge.slice_gates.every((g) => typeof g === "string")) {
|
|
558
|
+
validGe.slice_gates = ge.slice_gates;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
errors.push("gate_evaluation.slice_gates must be an array of strings");
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
if (ge.task_gates !== undefined) {
|
|
565
|
+
if (typeof ge.task_gates === "boolean")
|
|
566
|
+
validGe.task_gates = ge.task_gates;
|
|
567
|
+
else
|
|
568
|
+
errors.push("gate_evaluation.task_gates must be a boolean");
|
|
569
|
+
}
|
|
570
|
+
const knownGeKeys = new Set(["enabled", "slice_gates", "task_gates"]);
|
|
571
|
+
for (const key of Object.keys(ge)) {
|
|
572
|
+
if (!knownGeKeys.has(key)) {
|
|
573
|
+
warnings.push(`unknown gate_evaluation key "${key}" — ignored`);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (Object.keys(validGe).length > 0) {
|
|
577
|
+
validated.gate_evaluation = validGe;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
else {
|
|
581
|
+
errors.push("gate_evaluation must be an object");
|
|
582
|
+
}
|
|
583
|
+
}
|
|
545
584
|
// ─── Verification Preferences ───────────────────────────────────────────
|
|
546
585
|
if (preferences.verification_commands !== undefined) {
|
|
547
586
|
if (Array.isArray(preferences.verification_commands)) {
|
|
@@ -20,11 +20,13 @@ Then:
|
|
|
20
20
|
3. **Verify code changes exist.** Run `git diff --stat HEAD $(git merge-base HEAD main) -- ':!.gsd/'` (or the equivalent for the integration branch). If no non-`.gsd/` files appear in the diff, the milestone produced only planning artifacts and no actual code. Record this as a **verification failure**.
|
|
21
21
|
4. Verify each **success criterion** from the milestone definition in `{{roadmapPath}}`. For each criterion, confirm it was met with specific evidence from slice summaries, test results, or observable behavior. Record any criterion that was NOT met as a **verification failure**.
|
|
22
22
|
5. Verify the milestone's **definition of done** — all slices are `[x]`, all slice summaries exist, and any cross-slice integration points work correctly. Record any unmet items as a **verification failure**.
|
|
23
|
-
6.
|
|
23
|
+
6. If the roadmap includes a **Horizontal Checklist**, verify each item was addressed during the milestone. Note unchecked items in the milestone summary.
|
|
24
|
+
7. Fill the **Decision Re-evaluation** table in the milestone summary. For each key decision from `.gsd/DECISIONS.md` made during this milestone, evaluate whether it is still valid given what was actually built. Flag decisions that should be revisited next milestone.
|
|
25
|
+
8. Validate **requirement status transitions**. For each requirement that changed status during this milestone, confirm the transition is supported by evidence. Requirements can move between Active, Validated, Deferred, Blocked, or Out of Scope — but only with proof.
|
|
24
26
|
|
|
25
27
|
### Verification Gate — STOP if verification failed
|
|
26
28
|
|
|
27
|
-
**If ANY verification failure was recorded in steps 3, 4, or 5, you MUST follow the failure path below. Do NOT proceed to step
|
|
29
|
+
**If ANY verification failure was recorded in steps 3, 4, or 5, you MUST follow the failure path below. Do NOT proceed to step 9.**
|
|
28
30
|
|
|
29
31
|
**Failure path** (verification failed):
|
|
30
32
|
- Do NOT call `gsd_complete_milestone` — the milestone must not be marked as complete.
|
|
@@ -33,13 +35,30 @@ Then:
|
|
|
33
35
|
- Write a clear summary of what failed and why to help the next attempt.
|
|
34
36
|
- Say: "Milestone {{milestoneId}} verification FAILED — not complete." and stop.
|
|
35
37
|
|
|
36
|
-
**Success path** (all verifications passed — continue with steps
|
|
38
|
+
**Success path** (all verifications passed — continue with steps 9–13):
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
9. **Persist completion through `gsd_complete_milestone`.** Call it with the parameters below. The tool updates the milestone status in the DB, renders `{{milestoneSummaryPath}}`, and validates all slices are complete before proceeding.
|
|
41
|
+
|
|
42
|
+
**Required parameters:**
|
|
43
|
+
- `milestoneId` (string) — Milestone ID (e.g. M001)
|
|
44
|
+
- `title` (string) — Milestone title
|
|
45
|
+
- `oneLiner` (string) — One-sentence summary of what the milestone achieved
|
|
46
|
+
- `narrative` (string) — Detailed narrative of what happened during the milestone
|
|
47
|
+
- `successCriteriaResults` (string) — Markdown detailing how each success criterion was met or not met
|
|
48
|
+
- `definitionOfDoneResults` (string) — Markdown detailing how each definition-of-done item was met
|
|
49
|
+
- `requirementOutcomes` (string) — Markdown detailing requirement status transitions with evidence
|
|
50
|
+
- `keyDecisions` (array of strings) — Key architectural/pattern decisions made during the milestone
|
|
51
|
+
- `keyFiles` (array of strings) — Key files created or modified during the milestone
|
|
52
|
+
- `lessonsLearned` (array of strings) — Lessons learned during the milestone
|
|
53
|
+
- `verificationPassed` (boolean) — Must be `true` — confirms that code change verification, success criteria, and definition of done checks all passed before completion
|
|
54
|
+
|
|
55
|
+
**Optional parameters:**
|
|
56
|
+
- `followUps` (string) — Follow-up items for future milestones
|
|
57
|
+
- `deviations` (string) — Deviations from the original plan
|
|
58
|
+
10. For each requirement whose status changed in step 8, call `gsd_requirement_update` with the requirement ID and updated `status` and `validation` fields — the tool regenerates `.gsd/REQUIREMENTS.md` automatically.
|
|
59
|
+
11. Update `.gsd/PROJECT.md` to reflect milestone completion and current project state.
|
|
60
|
+
12. Review all slice summaries for cross-cutting lessons, patterns, or gotchas that emerged during this milestone. Append any non-obvious, reusable insights to `.gsd/KNOWLEDGE.md`.
|
|
61
|
+
13. Do not commit manually — the system auto-commits your changes after this unit completes.
|
|
43
62
|
- Say: "Milestone {{milestoneId}} complete."
|
|
44
63
|
|
|
45
64
|
**Important:** Do NOT skip the code change verification, success criteria, or definition of done verification (steps 3-5). The milestone summary must reflect actual verified outcomes, not assumed success. Verification failures BLOCK completion — there is no override. The milestone stays in its current state until issues are resolved and verification is re-run.
|
|
@@ -23,14 +23,15 @@ Then:
|
|
|
23
23
|
2. {{skillActivation}}
|
|
24
24
|
3. Run all slice-level verification checks defined in the slice plan. All must pass before marking the slice done. If any fail, fix them first.
|
|
25
25
|
4. If the slice plan includes observability/diagnostic surfaces, confirm they work. Skip this for simple slices that don't have observability sections.
|
|
26
|
-
5. If
|
|
27
|
-
6.
|
|
28
|
-
7. Write `{{
|
|
29
|
-
8.
|
|
30
|
-
9. Review task summaries for
|
|
31
|
-
10.
|
|
32
|
-
11. Do
|
|
33
|
-
12.
|
|
26
|
+
5. If the slice involved runtime behavior, fill the **Operational Readiness** section (Q8) in the slice summary: health signal, failure signal, recovery procedure, and monitoring gaps. Omit entirely for simple slices with no runtime concerns.
|
|
27
|
+
6. If this slice produced evidence that a requirement changed status (Active → Validated, Active → Deferred, etc.), call `gsd_save_decision` with scope="requirement", decision="{requirement-id}", choice="{new-status}", rationale="{evidence}". Do NOT write `.gsd/REQUIREMENTS.md` directly — the engine renders it from the database.
|
|
28
|
+
7. Write `{{sliceSummaryPath}}` (compress all task summaries).
|
|
29
|
+
8. Write `{{sliceUatPath}}` — a concrete UAT script with real test cases derived from the slice plan and task summaries. Include preconditions, numbered steps with expected outcomes, and edge cases. This must NOT be a placeholder or generic template — tailor every test case to what this slice actually built.
|
|
30
|
+
9. Review task summaries for `key_decisions`. Append any significant decisions to `.gsd/DECISIONS.md` if missing.
|
|
31
|
+
10. Review task summaries for patterns, gotchas, or non-obvious lessons learned. If any would save future agents from repeating investigation or hitting the same issues, append them to `.gsd/KNOWLEDGE.md`. Only add entries that are genuinely useful — don't pad with obvious observations.
|
|
32
|
+
11. Call `gsd_complete_slice` with milestone_id, slice_id, the slice summary, and the UAT result. Do NOT manually mark the roadmap checkbox — the tool writes to the DB and renders the ROADMAP.md projection automatically.
|
|
33
|
+
12. Do not run git commands — the system commits your changes and handles any merge after this unit succeeds.
|
|
34
|
+
13. Update `.gsd/PROJECT.md` if it exists — refresh current state if needed.
|
|
34
35
|
|
|
35
36
|
**You MUST call `gsd_complete_slice` with the slice summary and UAT content before finishing. The tool persists to both DB and disk and renders `{{sliceSummaryPath}}` and `{{sliceUatPath}}` automatically.**
|
|
36
37
|
|
|
@@ -38,18 +38,21 @@ Then:
|
|
|
38
38
|
- Correct: `command > /dev/null 2>&1 &` or `nohup command > /dev/null 2>&1 &`
|
|
39
39
|
- Example: `python -m http.server 8080 > /dev/null 2>&1 &` (NOT `python -m http.server 8080 &`)
|
|
40
40
|
- Preferred: use the `bg_shell` tool if available — it manages process lifecycle correctly without stream-inheritance issues
|
|
41
|
-
6.
|
|
42
|
-
7.
|
|
43
|
-
8.
|
|
44
|
-
9.
|
|
41
|
+
6. If the task plan includes a **Failure Modes** section (Q5), implement the error/timeout/malformed handling specified. Verify each dependency's failure path is handled. Skip if the section is absent.
|
|
42
|
+
7. If the task plan includes a **Load Profile** section (Q6), implement protections for the identified 10x breakpoint (connection pooling, rate limiting, pagination, etc.). Skip if absent.
|
|
43
|
+
8. If the task plan includes a **Negative Tests** section (Q7), write the specified negative test cases alongside the happy-path tests — malformed inputs, error paths, and boundary conditions. Skip if absent.
|
|
44
|
+
9. Verify must-haves are met by running concrete checks (tests, commands, observable behaviors)
|
|
45
|
+
10. Run the slice-level verification checks defined in the slice plan's Verification section. Track which pass. On the final task of the slice, all must pass before marking done. On intermediate tasks, partial passes are expected — note which ones pass in the summary.
|
|
46
|
+
11. After the verification gate runs (you'll see gate results in stderr/notify output), populate the `## Verification Evidence` table in your task summary with the check results. Use the `formatEvidenceTable` format: one row per check with command, exit code, verdict (✅ pass / ❌ fail), and duration. If no verification commands were discovered, note that in the section.
|
|
47
|
+
12. If the task touches UI, browser flows, DOM behavior, or user-visible web state:
|
|
45
48
|
- exercise the real flow in the browser
|
|
46
49
|
- prefer `browser_batch` when the next few actions are obvious and sequential
|
|
47
50
|
- prefer `browser_assert` for explicit pass/fail verification of the intended outcome
|
|
48
51
|
- use `browser_diff` when an action's effect is ambiguous
|
|
49
52
|
- use console/network/dialog diagnostics when validating async, stateful, or failure-prone UI
|
|
50
53
|
- record verification in terms of explicit checks passed/failed, not only prose interpretation
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
13. If the task plan includes an Observability Impact section, verify those signals directly. Skip this step if the task plan omits the section.
|
|
55
|
+
14. **If execution is running long or verification fails:**
|
|
53
56
|
|
|
54
57
|
**Context budget:** You have approximately **{{verificationBudget}}** reserved for verification context. If you've used most of your context and haven't finished all steps, stop implementing and prioritize writing the task summary with clear notes on what's done and what remains. A partial summary that enables clean resumption is more valuable than one more half-finished step with no documentation. Never sacrifice summary quality for one more implementation step.
|
|
55
58
|
|
|
@@ -60,13 +63,13 @@ Then:
|
|
|
60
63
|
- Distinguish "I know" from "I assume." Observable facts (the error says X) are strong evidence. Assumptions (this library should work this way) need verification.
|
|
61
64
|
- Know when to stop. If you've tried 3+ fixes without progress, your mental model is probably wrong. Stop. List what you know for certain. List what you've ruled out. Form fresh hypotheses from there.
|
|
62
65
|
- Don't fix symptoms. Understand *why* something fails before changing code. A test that passes after a change you don't understand is luck, not a fix.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
15. **Blocker discovery:** If execution reveals that the remaining slice plan is fundamentally invalid — not just a bug or minor deviation, but a plan-invalidating finding like a wrong API, missing capability, or architectural mismatch — set `blocker_discovered: true` in the task summary frontmatter and describe the blocker clearly in the summary narrative. Do NOT set `blocker_discovered: true` for ordinary debugging, minor deviations, or issues that can be fixed within the current task or the remaining plan. This flag triggers an automatic replan of the slice.
|
|
67
|
+
16. If you made an architectural, pattern, library, or observability decision during this task that downstream work should know about, append it to `.gsd/DECISIONS.md` (read the template at `~/.gsd/agent/extensions/gsd/templates/decisions.md` if the file doesn't exist yet). Not every task produces decisions — only append when a meaningful choice was made.
|
|
68
|
+
17. If you discover a non-obvious rule, recurring gotcha, or useful pattern during execution, append it to `.gsd/KNOWLEDGE.md`. Only add entries that would save future agents from repeating your investigation. Don't add obvious things.
|
|
69
|
+
18. Read the template at `~/.gsd/agent/extensions/gsd/templates/task-summary.md`
|
|
70
|
+
19. Write `{{taskSummaryPath}}`
|
|
71
|
+
20. Call `gsd_complete_task` with milestone_id, slice_id, task_id, and a summary of what was accomplished. This is your final required step — do NOT manually edit PLAN.md checkboxes. The tool marks the task complete, updates the DB, and renders PLAN.md automatically.
|
|
72
|
+
21. Do not run git commands — the system reads your task summary after completion and creates a meaningful commit from it (type inferred from title, message from your one-liner, key files from frontmatter). Write a clear, specific one-liner in the summary — it becomes the commit message.
|
|
70
73
|
|
|
71
74
|
All work stays in your working directory: `{{workingDirectory}}`.
|
|
72
75
|
|
|
@@ -16,7 +16,7 @@ GSD extension source code is at: `{{gsdSourceDir}}`
|
|
|
16
16
|
|
|
17
17
|
| Domain | Files |
|
|
18
18
|
|--------|-------|
|
|
19
|
-
| **Auto-mode engine** | `auto.ts` `auto-loop.ts` `auto-dispatch.ts` `auto-start.ts` `auto-supervisor.ts` `auto-timers.ts` `auto-timeout-recovery.ts` `auto-unit-closeout.ts` `auto-post-unit.ts` `auto-verification.ts` `auto-recovery.ts` `auto-worktree.ts` `auto-
|
|
19
|
+
| **Auto-mode engine** | `auto.ts` `auto-loop.ts` `auto-dispatch.ts` `auto-start.ts` `auto-supervisor.ts` `auto-timers.ts` `auto-timeout-recovery.ts` `auto-unit-closeout.ts` `auto-post-unit.ts` `auto-verification.ts` `auto-recovery.ts` `auto-worktree.ts` `auto-model-selection.ts` `auto-budget.ts` `dispatch-guard.ts` |
|
|
20
20
|
| **State & persistence** | `state.ts` `types.ts` `files.ts` `paths.ts` `json-persistence.ts` `atomic-write.ts` |
|
|
21
21
|
| **Forensics & recovery** | `forensics.ts` `session-forensics.ts` `crash-recovery.ts` `session-lock.ts` |
|
|
22
22
|
| **Metrics & telemetry** | `metrics.ts` `skill-telemetry.ts` `token-counter.ts` |
|
|
@@ -46,7 +46,7 @@ GSD extension source code is at: `{{gsdSourceDir}}`
|
|
|
46
46
|
├── milestones/{ID}/ — milestone artifacts
|
|
47
47
|
│ ├── {ID}-ROADMAP.md, {ID}-RESEARCH.md, {ID}-CONTEXT.md, {ID}-SUMMARY.md
|
|
48
48
|
│ └── slices/{SID}/ — slice artifacts
|
|
49
|
-
│ ├── {SID}-PLAN.md, {SID}-RESEARCH.md, {SID}-UAT
|
|
49
|
+
│ ├── {SID}-PLAN.md, {SID}-RESEARCH.md, {SID}-UAT.md, {SID}-SUMMARY.md
|
|
50
50
|
│ └── tasks/{TID}-PLAN.md, {TID}-SUMMARY.md
|
|
51
51
|
└── worktrees/{milestoneId}/ — per-milestone worktree with replicated .gsd/
|
|
52
52
|
```
|
|
@@ -142,9 +142,10 @@ Then **offer GitHub issue creation**: "Would you like me to create a GitHub issu
|
|
|
142
142
|
If yes, create using the `bash` tool:
|
|
143
143
|
|
|
144
144
|
```bash
|
|
145
|
-
|
|
145
|
+
# Step 1: Create issue (use labels for metadata, NOT for classification — type is set via GraphQL)
|
|
146
|
+
ISSUE_URL=$(gh issue create --repo gsd-build/gsd-2 \
|
|
146
147
|
--title "..." \
|
|
147
|
-
--label "
|
|
148
|
+
--label "auto-generated" \
|
|
148
149
|
--body "$(cat <<'EOF'
|
|
149
150
|
## Problem
|
|
150
151
|
[1-2 sentence summary]
|
|
@@ -169,7 +170,13 @@ gh issue create --repo gsd-build/gsd-2 \
|
|
|
169
170
|
---
|
|
170
171
|
*Auto-generated by `/gsd forensics`*
|
|
171
172
|
EOF
|
|
172
|
-
)"
|
|
173
|
+
)")
|
|
174
|
+
|
|
175
|
+
# Step 2: Set issue type via GraphQL (gh issue create has no --type flag)
|
|
176
|
+
ISSUE_NUM=$(echo "$ISSUE_URL" | grep -oE '[0-9]+$')
|
|
177
|
+
ISSUE_ID=$(gh api graphql -f query='{ repository(owner:"gsd-build",name:"gsd-2") { issue(number:'"$ISSUE_NUM"') { id } } }' --jq '.data.repository.issue.id')
|
|
178
|
+
TYPE_ID=$(gh api graphql -f query='{ repository(owner:"gsd-build",name:"gsd-2") { issueTypes(first:20) { nodes { id name } } } }' --jq '.data.repository.issueTypes.nodes[] | select(.name=="Bug") | .id')
|
|
179
|
+
gh api graphql -f query='mutation { updateIssue(input:{id:"'"$ISSUE_ID"'",issueTypeId:"'"$TYPE_ID"'"}) { issue { number } } }'
|
|
173
180
|
```
|
|
174
181
|
|
|
175
182
|
### Redaction Rules (CRITICAL)
|