gsdd-cli 0.23.0 → 0.25.0

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.
@@ -7,6 +7,7 @@ const __dirname = dirname(__filename);
7
7
  const DISTILLED_DIR = join(__dirname, '..', '..', 'distilled');
8
8
  const HELPER_LIB_FILES = Object.freeze([
9
9
  'cli-utils.mjs',
10
+ 'closeout-report.mjs',
10
11
  'control-map.mjs',
11
12
  'evidence-contract.mjs',
12
13
  'file-ops.mjs',
@@ -47,19 +48,28 @@ function renderPlanningCliLauncher() {
47
48
 
48
49
  import { cmdFileOp } from './lib/file-ops.mjs';
49
50
  import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
50
- import { cmdPhaseStatus } from './lib/phase.mjs';
51
+ import { cmdPhaseStatus, cmdVerify } from './lib/phase.mjs';
51
52
  import { cmdSessionFingerprint } from './lib/session-fingerprint.mjs';
52
53
  import { cmdUiProof } from './lib/ui-proof.mjs';
53
54
  import { cmdControlMap } from './lib/control-map.mjs';
55
+ import { createCmdCloseoutReport } from './lib/closeout-report.mjs';
54
56
  import { bootstrapHelperWorkspace, consumeWorkspaceRootArg, resolveWorkspaceContext } from './lib/workspace-root.mjs';
55
57
 
58
+ const HELPER_CONTEXT = {
59
+ workflows: [],
60
+ frameworkVersion: 'generated-helper',
61
+ };
62
+ const cmdCloseoutReport = createCmdCloseoutReport(HELPER_CONTEXT);
63
+
56
64
  const COMMANDS = {
57
65
  'file-op': cmdFileOp,
58
66
  'lifecycle-preflight': cmdLifecyclePreflight,
59
67
  'phase-status': cmdPhaseStatus,
68
+ verify: cmdVerify,
60
69
  'session-fingerprint': cmdSessionFingerprint,
61
70
  'ui-proof': cmdUiProof,
62
71
  'control-map': cmdControlMap,
72
+ 'closeout-report': cmdCloseoutReport,
63
73
  };
64
74
 
65
75
  function printHelp() {
@@ -72,6 +82,8 @@ function printHelp() {
72
82
  ' Example: node .planning/bin/gsdd.mjs file-op delete .planning/.continue-here.bak --missing ok',
73
83
  ' phase-status <N> <status> Update ROADMAP.md phase status ([ ] / [-] / [x])',
74
84
  ' Example: node .planning/bin/gsdd.mjs phase-status 1 done',
85
+ ' verify <N> Run direct phase artifact and UI-proof gate checks',
86
+ ' Example: node .planning/bin/gsdd.mjs verify 1',
75
87
  ' lifecycle-preflight <surface> [phase]',
76
88
  ' Inspect lifecycle gate results for a workflow surface',
77
89
  ' Example: node .planning/bin/gsdd.mjs lifecycle-preflight verify 1 --expects-mutation phase-status',
@@ -83,6 +95,8 @@ function printHelp() {
83
95
  ' Compare planned UI proof slots against observed bundles',
84
96
  ' control-map [--json] [--with-ignored] [--annotations <path>]',
85
97
  ' Report computed repo/worktree/planning state and local annotations',
98
+ ' closeout-report [--json] [--phase <N>]',
99
+ ' Replay read-only closeout status from control-map, health, preflight, verify, and UI-proof signals',
86
100
  '',
87
101
  'Advanced option:',
88
102
  ' --workspace-root <path> Override workspace root discovery before or after the subcommand',
@@ -446,6 +446,41 @@ function normalizeObservedBundle(entry) {
446
446
  };
447
447
  }
448
448
 
449
+ function comparisonFixHint(code) {
450
+ const hints = {
451
+ invalid_observed_bundle: 'Fix the observed proof bundle metadata, then rerun ui-proof compare.',
452
+ unsatisfied_observed_claim_status: 'Record a passed observed claim only after the changed UI state has been exercised and evidenced.',
453
+ unsatisfied_observed_comparison_status: 'Set comparison_status_by_slot to satisfied only for slots backed by matching observations and artifacts.',
454
+ missing_required_evidence_kind: 'Add observed evidence for every evidence kind required by the planned slot, or narrow the planned slot before verification.',
455
+ human_evidence_cannot_bypass_required_non_human_evidence: 'Add the missing non-human evidence; human approval may narrow or waive but cannot replace it.',
456
+ route_state_mismatch: 'Capture proof for the exact planned route/state, or update the plan before execution.',
457
+ environment_mismatch: 'Capture proof in the planned environment, or record a narrowed claim limit and rerun comparison.',
458
+ viewport_mismatch: 'Capture proof for the planned viewport, or narrow the viewport claim explicitly.',
459
+ requirement_mismatch: 'Declare the planned requirement id in the observed proof bundle scope.',
460
+ claim_mismatch: 'Keep the planned and observed claims identical so proof maps to the exact UI assertion.',
461
+ observation_claim_mismatch: 'Add a passed observation that supports the exact planned claim.',
462
+ observation_route_state_mismatch: 'Attach observations to the exact planned route/state.',
463
+ missing_supporting_observation_evidence_kind: 'Add passed supporting observations for each required evidence kind.',
464
+ unsatisfied_proof_step: 'Rerun or replace failing proof steps before claiming the slot is satisfied.',
465
+ missing_manual_acceptance_evidence: 'Record human evidence when the planned slot requires manual acceptance.',
466
+ missing_manual_acceptance_observation: 'Add a passed human observation for manual acceptance.',
467
+ unsatisfied_observation_result: 'Resolve failed observations or classify the slot as partial, waived, or deferred.',
468
+ missing_minimum_observation: 'Add observations covering every planned minimum observation.',
469
+ missing_claim_limit: 'Preserve the planned claim limit in the observed proof bundle.',
470
+ missing_expected_artifact_type: 'Attach the planned artifact type, such as screenshot, report, trace, or DOM snapshot.',
471
+ missing_observed_bundle: 'Create an observed UI proof bundle for the planned slot, or explicitly waive/defer the slot with claim narrowing.',
472
+ };
473
+ return hints[code] || 'Fix the proof issue, rerun the comparison, and keep the slot partial until evidence matches the plan.';
474
+ }
475
+
476
+ function decorateComparisonIssue(issue) {
477
+ return {
478
+ severity: issue.severity || 'blocker',
479
+ fix_hint: issue.fix_hint || issue.fix || comparisonFixHint(issue.code),
480
+ ...issue,
481
+ };
482
+ }
483
+
449
484
  function compareSlotToBundle(slot, slotIdValue, observed) {
450
485
  const issues = [];
451
486
  const bundle = observed.bundle;
@@ -648,7 +683,7 @@ function compareSlotToBundle(slot, slotIdValue, observed) {
648
683
  }
649
684
 
650
685
  const status = issues.length === 0 ? 'satisfied' : (bundleStatus === 'missing' ? 'missing' : 'partial');
651
- return { status, issues, source: observed.source };
686
+ return { status, issues: issues.map(decorateComparisonIssue), source: observed.source };
652
687
  }
653
688
 
654
689
  export function compareUiProofSlots(plannedSlots, observedBundles) {
@@ -656,7 +691,7 @@ export function compareUiProofSlots(plannedSlots, observedBundles) {
656
691
  const slotValidation = validateUiProofSlots(slots);
657
692
  const bundles = normalizeArray(observedBundles).map(normalizeObservedBundle);
658
693
  const results = [];
659
- const errors = [...slotValidation.errors];
694
+ const errors = slotValidation.errors.map(decorateComparisonIssue);
660
695
 
661
696
  for (const observed of bundles) {
662
697
  if (!observed.validation.valid) {
@@ -680,7 +715,7 @@ export function compareUiProofSlots(plannedSlots, observedBundles) {
680
715
  code: 'missing_observed_bundle',
681
716
  path: 'scope.slot_ids',
682
717
  message: `No observed UI proof bundle declares planned slot ${slotIdValue}.`,
683
- }],
718
+ }].map(decorateComparisonIssue),
684
719
  });
685
720
  continue;
686
721
  }
@@ -706,7 +741,7 @@ export function compareUiProofSlots(plannedSlots, observedBundles) {
706
741
  ? 'missing'
707
742
  : 'partial';
708
743
 
709
- return { status, slots: results, errors };
744
+ return { status, slots: results, errors: errors.map(decorateComparisonIssue) };
710
745
  }
711
746
 
712
747
  export function validateUiProofBundle(bundle, options = {}) {
@@ -2818,7 +2818,7 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2818
2818
 
2819
2819
  ## D62 - Repo-Native UI Proof Contract
2820
2820
 
2821
- **Decision (2026-04-28; revised 2026-05-08):** UI-sensitive work should carry a compact planned proof-slot contract and, when executed, an observed UI proof bundle that references artifacts by path or link while preserving the existing closure evidence kinds: `code`, `test`, `runtime`, `delivery`, and `human`. For live rendered UI proof, `agent-browser` is the default runtime evidence path for consumers, while existing Playwright tests remain the canonical repeatable browser-regression path when present. The deterministic `ui-proof` validator remains provider-agnostic structural validation, but it now validates planned slot specificity, concise tool provenance, local artifact path existence when validating from files, raw-artifact safety for paths and URLs, and failed/partial proof classification so the workflow cannot degrade back into unstructured "looks good" review.
2821
+ **Decision (2026-04-28; revised 2026-05-09):** UI-sensitive work should carry a compact planned proof-slot contract and, when executed, an observed UI proof bundle that references artifacts by path or link while preserving the existing closure evidence kinds: `code`, `test`, `runtime`, `delivery`, and `human`. For live rendered UI proof, `agent-browser` is the default runtime evidence path for consumers, while existing Playwright tests remain the canonical repeatable browser-regression path when present. The deterministic `ui-proof` validator remains provider-agnostic structural validation, but it now validates planned slot specificity, concise tool provenance, local artifact path existence when validating from files, raw-artifact safety for paths and URLs, and failed/partial proof classification so the workflow cannot degrade back into unstructured "looks good" review. Direct phase verification also treats plan frontmatter as the UI-proof declaration authority and fails closed on missing phase prerequisites, empty `ui_proof_slots: []` without `no_ui_proof_rationale`, and invalid required UI proof.
2822
2822
 
2823
2823
  **Context:**
2824
2824
  - UI proof targets the recurring failure mode where agents claim a UI works or looks good without rendered proof, matched observations, or explicit human judgment.
@@ -2828,6 +2828,9 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2828
2828
 
2829
2829
  **Decision:**
2830
2830
  - Planning must classify UI-sensitive work and require either `ui_proof_slots` or an explicit `no_ui_proof_rationale`.
2831
+ - Direct phase verification must read `ui_proof_slots` and `no_ui_proof_rationale` from plan frontmatter only; body prose, fenced examples, and stale sidecars are not declaration authority.
2832
+ - Direct phase verification must fail nonzero with structured blockers when no matching plan or summary exists, or when `ui_proof_slots: []` lacks a nonblank `no_ui_proof_rationale`.
2833
+ - When an explicit no-UI rationale exists, stale UI-proof sidecars are warning-level cleanup signals, not proof and not blockers.
2831
2834
  - Planned slots record claim, route/state, required evidence kinds, minimum observations, expected artifact types, runnable validation command, environment/viewport, manual-acceptance requirement, claim limit, and requirement IDs.
2832
2835
  - Observed proof bundles record claim, requirement/slot IDs, route/state, environment, viewport, evidence inputs, commands/manual steps, observations, artifacts, privacy metadata, result, and claim limits.
2833
2836
  - Planned slots must be tight enough for the plan checker to reject vague proof: specific route/state, viewport rationale or narrowed claim limit, minimum observations, expected artifact types, runnable validation, and matchability back to the exact UI claim.
@@ -2853,7 +2856,7 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2853
2856
  - `distilled/templates/ui-proof.md`
2854
2857
  - `distilled/workflows/plan.md`, `distilled/workflows/execute.md`, `distilled/workflows/quick.md`, `distilled/workflows/verify.md`
2855
2858
  - `agents/planner.md`, `agents/executor.md`, `agents/verifier.md`, `distilled/templates/delegates/plan-checker.md`
2856
- - `bin/lib/templates.mjs`, `bin/lib/ui-proof.mjs`, `bin/lib/health.mjs`, `bin/lib/rendering.mjs`
2859
+ - `bin/lib/templates.mjs`, `bin/lib/ui-proof.mjs`, `bin/lib/health.mjs`, `bin/lib/phase.mjs`, `bin/lib/rendering.mjs`
2857
2860
  - `tests/phase.test.cjs`, `tests/gsdd.guards.test.cjs`, `tests/gsdd.health.test.cjs`, `tests/gsdd.init.test.cjs`
2858
2861
  - GSD comparison: the upstream planner, executor, and verifier role patterns preserve lifecycle rigor, but they do not define UI proof slots or planned-vs-observed UI proof bundles.
2859
2862
  - OneShot QC source: `https://github.com/oneshot-repo/OneShot/tree/main/skills`
@@ -2875,7 +2878,7 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2875
2878
 
2876
2879
  ## D63 - Computed-First Control Map
2877
2880
 
2878
- **Decision (2026-05-08):** Long-running multi-agent and multi-worktree control uses a computed-first `gsdd control-map` helper rather than a new lifecycle workflow or a vendor session parser. The helper computes repo/worktree/planning truth live and overlays optional local annotations only for intent that git cannot know.
2881
+ **Decision (2026-05-08; revised 2026-05-09):** Long-running multi-agent and multi-worktree control uses a computed-first `gsdd control-map` helper rather than a new lifecycle workflow or a vendor session parser. The helper computes repo/worktree/planning truth live and overlays optional local annotations only for intent that git cannot know.
2879
2882
 
2880
2883
  **Context:**
2881
2884
  - Gap I52 showed that ordinary `git status` can be clean while sibling worktrees, detached runtime worktrees, ignored/generated surfaces, snapshots, dirty local WIP, and cleanup obligations remain unexplained.
@@ -2885,21 +2888,24 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2885
2888
 
2886
2889
  **Decision:**
2887
2890
  - Add `gsdd control-map [--json] [--with-ignored] [--annotations <path>]` to the main CLI and generated `.planning/bin/gsdd.mjs` helper runtime.
2891
+ - Add `gsdd control-map annotate set|clear` as the minimal mutation surface for local annotation intent. `set` creates or updates workspace-local annotation files with live branch/head snapshots, normalized write sets, cleanup state, owner/scope/next-step metadata, and stale-update refusal unless `--refresh` is explicit. `clear` removes an annotation by id or path, including stale or missing-worktree entries, without deleting branches, pruning worktrees, or cleaning files.
2892
+ - Add `gsdd closeout-report [--json] [--phase <N>]` as a read-only replay helper over the same local-state authority. It defaults to the latest completed phase and reports blockers, warnings, next safe action, control-map status, health/preflight status, direct phase verification, and UI-proof status without mutating ROADMAP status, fingerprints, annotations, branches, worktrees, generated surfaces, release state, or report files.
2888
2893
  - Compute authority from live git/worktree state first: canonical checkout, branch, HEAD, upstream divergence when comparable, tracked/untracked dirty buckets, optional ignored-path scans through `--with-ignored`, sibling git worktrees, detached/bare state, invalid git access, planning drift, checkpoint existence, lifecycle state, and repo-local runtime worktree directories.
2889
- - Read optional annotations from `.planning/.local/control-map.annotations.json`. Annotations may record `runtime_owner`, intended scope, write set, cleanup state, proof state, next step, branch, and last known head.
2894
+ - Read optional annotations from `.planning/.local/control-map.annotations.json`. Annotations may record `runtime_owner`, intended scope, write set, cleanup state, next step, branch, last known head, and update timestamp.
2890
2895
  - Treat annotations as stale-checkable intent only. They never outrank repo truth, planning artifacts, or checkpoint reconciliation.
2896
+ - Emit explicit transition-risk semantics from computed truth: concrete annotation write-set overlap, live dirty-path/write-set overlap, upstream divergence, detached candidate worktrees, stale annotation mismatches, and tracked dirty canonical work behind upstream. Only concrete block-level risks should stop owned-write lifecycle transitions; ordinary dirty or detached local state remains warning-level guidance.
2891
2897
  - Keep transcript/session stores out of the helper. Vendor session evidence may support postmortems, but it is not live product truth.
2892
2898
  - Wire the control map into portable workflow behavior by having `progress`, `resume`, `pause`, `quick`, `plan`, and `execute` consult it when available. This is guidance plus deterministic helper output, not a new workflow lane.
2893
2899
 
2894
2900
  **Leverage:**
2895
2901
  - Lost: a pure zero-file model cannot preserve non-computable intent such as owner/runtime, intended scope, and cleanup obligation.
2896
2902
  - Kept: Workspine remains a lightweight repo-native spine; no new lifecycle workflow, no dashboard/control plane, no vendor session authority, and no change to the five evidence kinds.
2897
- - Gained: agents can explain "clean" precisely across tracked, untracked, sibling, detached, stale, and annotated state by default, and across ignored/generated local surfaces when the caller requests the explicit `--with-ignored` scan before planning, execution, resume, cleanup, or milestone continuation.
2903
+ - Gained: agents can explain "clean" precisely across tracked, untracked, sibling, detached, stale, and annotated state by default, and across ignored/generated local surfaces when the caller requests the explicit `--with-ignored` scan before planning, execution, resume, cleanup, or milestone continuation. Owned-write preflight can also consume the same computed risk output, operators can update stale-aware local intent without hand-editing JSON, and closeout replay can join existing verification signals into one typed report without inventing a branch lease, control plane, or cleanup workflow.
2898
2904
 
2899
2905
  **Evidence:**
2900
- - `bin/lib/control-map.mjs`, `bin/gsdd.mjs`, `bin/lib/rendering.mjs`
2906
+ - `bin/lib/control-map.mjs`, `bin/lib/closeout-report.mjs`, `bin/lib/health.mjs`, `bin/lib/phase.mjs`, `bin/lib/init-runtime.mjs`, `bin/lib/lifecycle-preflight.mjs`, `bin/gsdd.mjs`, `bin/lib/rendering.mjs`
2901
2907
  - `distilled/workflows/progress.md`, `resume.md`, `pause.md`, `quick.md`, `plan.md`, `execute.md`
2902
- - `tests/gsdd.control-map.test.cjs`
2908
+ - `tests/gsdd.control-map.test.cjs`, `tests/gsdd.closeout-report.test.cjs`, `tests/gsdd.health.test.cjs`, `tests/phase.test.cjs`, `tests/gsdd.guards.test.cjs`
2903
2909
  - `.internal-research/gaps.md` Gap I52 and Gap I54
2904
2910
  - `.internal-research/lessons-learned.md` entries on multi-worktree registry, clean-vs-editor-visible noise, checkpoint/worktree truth split, and subagent stop conditions
2905
2911
  - GSD comparison: upstream GSD preserves lifecycle rigor but does not define a vendor-agnostic computed worktree/control-map helper.
@@ -2908,8 +2914,10 @@ Posture compatibility is part of that closeout contract: `repo_closeout` and `ru
2908
2914
 
2909
2915
  **Consequences:**
2910
2916
  - Future cleanup, resume, and parallel-worktree work should start from `gsdd control-map --json` rather than repeated ad hoc repo audits; use `--with-ignored` before making a clean-workspace claim that includes ignored or generated surfaces.
2911
- - A future mutation command may update annotations, but the current helper intentionally stays computed/read-first and safe to call from status surfaces.
2912
- - Future health or preflight hardening can consume the same helper output for stricter blocking, but must avoid turning local annotations into product truth.
2917
+ - Annotation mutation is intentionally confined to `control-map annotate`; ordinary `control-map` reads remain computed-first and safe to call from status surfaces.
2918
+ - Lifecycle preflight may consume block-level control-map risks for owned-write transitions, but read-only status surfaces must not turn warning-level local state into blockers.
2919
+ - `closeout-report` is a compact replay/report helper, not `progress`, `verify`, milestone audit, release automation, cleanup, or a dashboard. The source CLI path includes full health diagnostics; the generated helper reports health availability as a typed warning if the full health builder is not present in that helper runtime.
2920
+ - Future health hardening can consume the same helper output for stricter reporting, but must avoid turning local annotations into product truth.
2913
2921
 
2914
2922
  ---
2915
2923
 
@@ -77,6 +77,8 @@ Helper command for long-running sessions:
77
77
 
78
78
  ```
79
79
  npx -y gsdd-cli control-map [--json] [--with-ignored] -> computed repo/worktree/planning state plus local annotations
80
+ npx -y gsdd-cli control-map annotate set|clear -> optional stale-aware local intent maintenance
81
+ npx -y gsdd-cli closeout-report [--json] [--phase <N>] -> read-only replay of closeout blockers, warnings, and next safe action
80
82
  ```
81
83
 
82
84
  ## Brownfield Entry Contract
@@ -109,7 +111,7 @@ Use the same three-way routing everywhere:
109
111
  Architecture notes:
110
112
  - `bin/gsdd.mjs` remains the thin generator entrypoint, while vendor-specific rendering lives in adapter modules.
111
113
  - Codex CLI uses the always-generated `.agents/skills/gsdd-*` surface as its entry path, relies on `.planning/bin/gsdd.mjs` for deterministic helper calls, and can add a native `.codex/agents/gsdd-plan-checker.toml` checker agent.
112
- - `control-map` is a helper command, not a lifecycle workflow: it computes repo/worktree/planning truth first and treats `.planning/.local/` annotations as local intent only.
114
+ - `control-map` is a helper command, not a lifecycle workflow: it computes repo/worktree/planning truth first and treats `.planning/.local/` annotations as local intent only. `control-map annotate` can maintain those annotations, but cannot create ownership, cleanup, or lifecycle authority.
113
115
  - Codex VS Code/app are separate surfaces from Codex CLI; do not claim the CLI proof for them unless they expose compatible skill discovery. Fallback is opening or pasting the generated `SKILL.md`.
114
116
  - `npx -y gsdd-cli health` now compares any installed generated runtime surfaces against current render output and routes repairs back through `npx -y gsdd-cli update`.
115
117
  - Portable lifecycle contracts now align to the roadmap template status grammar: `[ ]`, `[-]`, `[x]`.
@@ -14,6 +14,7 @@ Before starting, read these files:
14
14
  5. From the SUMMARY.md loaded in step 3, if a `<judgment>` section is present - read `<anti_regression>` rules as additional verification targets: confirm that invariants listed there were not broken by execution. Read `<active_constraints>` to calibrate verification scope.
15
15
  6. The relevant codebase files - the code that was actually built
16
16
  7. **Session-boundary fallback:** If the SUMMARY.md loaded in step 3 has no `<judgment>` section, check whether `.planning/.continue-here.bak` exists. If it does, read its `<judgment>` section. Treat `<anti_regression>` rules as additional verification targets and `<active_constraints>` to calibrate verification scope (same usage as step 5). After reading, run `node .planning/bin/gsdd.mjs file-op delete .planning/.continue-here.bak --missing ok` (auto-clean).
17
+ 8. `node .planning/bin/gsdd.mjs control-map --json` to reconcile workflow/lifecycle state and checkpoint presence (`.planning/.continue-here.md`) before deciding pass/fail.
17
18
 
18
19
  Establish your verification basis (must-have sources, requirement scope, previous report status) before beginning code inspection. Do not jump to loose file reading until this basis is explicit.
19
20
 
@@ -129,8 +130,8 @@ Note: this step does NOT replace levels 1–3. An artifact can satisfy the evide
129
130
  </evidence_contract>
130
131
 
131
132
  <ui_proof_comparison>
132
- If the plan defines non-empty `ui_proof_slots`, compare planned UI proof against observed bundles before closure. Prefer `gsdd ui-proof compare <planned-slots-json> [observed-bundle-json ...]` when planned slots are available as JSON or fenced JSON; otherwise perform the same field-by-field comparison and record reduced assurance if no deterministic command could run. If the plan records only `no_ui_proof_rationale`, verify the rationale instead of requiring a bundle. Each observed bundle must include top-level `proof_bundle_version`, `scope`, `route_state`, `environment`, `viewport`, `evidence_inputs`, `commands_or_manual_steps`, `observations`, `artifacts`, `privacy`, `result`, and `claim_limits`.
133
- Classify each slot as exactly one of: `satisfied`, `partial`, `missing`, `waived`, `deferred`, or `not_applicable`. Waiver/deferment narrows the claim; it is not proof. Screenshots, traces, videos, reports, accessibility scans, Gherkin, visual diffs, and manual notes are artifact types or activities mapped onto existing evidence kinds, not new evidence kinds. Artifact count is never proof; each artifact must tie to the slot claim, route/state, observation, artifact path/link, privacy metadata, and claim limit.
133
+ Before closure, direct `gsdd verify <phase>` and this workflow must fail closed when the target phase has no matching PLAN.md or SUMMARY.md; report structured prerequisite blockers instead of treating missing artifacts as an empty success. Read UI proof declaration authority from the plan frontmatter contract only: body prose, fenced examples, stale sidecars, and markdown snippets do not declare UI proof intent. If frontmatter defines non-empty `ui_proof_slots`, compare planned UI proof against observed bundles before closure. Prefer `gsdd ui-proof compare <planned-slots-json> [observed-bundle-json ...]` when planned slots are available as JSON or fenced JSON; otherwise perform the same field-by-field comparison and record reduced assurance if no deterministic command could run. If frontmatter records `ui_proof_slots: []`, it must also contain a nonblank `no_ui_proof_rationale`; otherwise verification blocks. If the plan records only `no_ui_proof_rationale`, verify the rationale instead of requiring a bundle, and treat stale planned/observed sidecars as warnings rather than proof or blockers. Each observed bundle must include top-level `proof_bundle_version`, `scope`, `route_state`, `environment`, `viewport`, `evidence_inputs`, `commands_or_manual_steps`, `observations`, `artifacts`, `privacy`, `result`, and `claim_limits`.
134
+ Classify each slot as exactly one of: `satisfied`, `partial`, `missing`, `waived`, `deferred`, or `not_applicable`. Deterministic comparison issues include `severity` and `fix_hint`; use those as the normal repair feedback loop before closing verification. Waiver/deferment narrows the claim; it is not proof. Screenshots, traces, videos, reports, accessibility scans, Gherkin, visual diffs, and manual notes are artifact types or activities mapped onto existing evidence kinds, not new evidence kinds. Artifact count is never proof; each artifact must tie to the slot claim, route/state, observation, artifact path/link, privacy metadata, and claim limit.
134
135
  For live UI runtime proof, expect `agent-browser` as the default captured tool unless the observed bundle explains a project-native equivalent or an availability constraint. Do not fail solely because another browser tool was used, but downgrade vague proof that lacks exact route/state, planned viewport coverage or rationale, interactive steps/refs where relevant, screenshot/report artifacts, or relevant console/network observations. Existing Playwright tests count as canonical repeatable regression evidence, not a replacement for scoped runtime evidence when the slot requires `runtime`.
135
136
  Artifact privacy metadata must include `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; raw screenshots, traces, videos, DOM snapshots, and reports default to local-only and unsafe unless sanitized. Run `gsdd ui-proof validate <path>` or treat `gsdd health` E10 as blocking; add `--claim <...>` when relying on the bundle for public, tracked, delivery, release, or publication proof. Visual taste, accessibility judgment, baseline acceptance, subjective polish/layout quality, and privacy publication require human evidence or explicit waiver; human approval does not replace required `code`, `test`, `runtime`, or `delivery` evidence. Source annotations, AST/cAST findings, semantic search, comments, and Semble-like retrieval are discovery hints only.
136
137
  </ui_proof_comparison>
@@ -223,7 +223,7 @@ Other CLI commands that remain available outside the first-run path:
223
223
  | Command | Purpose |
224
224
  |---------|---------|
225
225
  | `gsdd find-phase [N]` | Show phase info as JSON (for agent consumption) |
226
- | `gsdd verify <N>` | Run artifact checks for phase N |
226
+ | `gsdd verify <N>` | Run phase artifact and UI-proof closure checks for phase N; exits nonzero when verification is blocked |
227
227
  | `gsdd scaffold phase <N> [name]` | Create a new phase plan file |
228
228
 
229
229
  ### Platform flags for `--tools`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gsdd-cli",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Workspine — a repo-native delivery spine for long-horizon AI-assisted work, with directly validated support for Claude Code, Codex CLI, and OpenCode, published as gsdd-cli.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "test": "npm run test:gsdd",
11
- "test:gsdd": "node tests/gsdd.init.test.cjs && node tests/gsdd.models.test.cjs && node tests/gsdd.consumer-ceremony.test.cjs && node tests/gsdd.manifest.test.cjs && node tests/gsdd.plan.adapters.test.cjs && node tests/gsdd.audit-milestone.test.cjs && node tests/gsdd.invariants.test.cjs && node tests/gsdd.guards.test.cjs && node tests/gsdd.health.test.cjs && node tests/gsdd.scenarios.test.cjs && node tests/gsdd.cross-runtime.test.cjs && node tests/gsdd.control-map.test.cjs && node tests/phase.test.cjs && node tests/session-fingerprint.test.cjs",
11
+ "test:gsdd": "node tests/gsdd.init.test.cjs && node tests/gsdd.models.test.cjs && node tests/gsdd.consumer-ceremony.test.cjs && node tests/gsdd.manifest.test.cjs && node tests/gsdd.plan.adapters.test.cjs && node tests/gsdd.audit-milestone.test.cjs && node tests/gsdd.invariants.test.cjs && node tests/gsdd.guards.test.cjs && node tests/gsdd.health.test.cjs && node tests/gsdd.scenarios.test.cjs && node tests/gsdd.cross-runtime.test.cjs && node tests/gsdd.control-map.test.cjs && node tests/gsdd.closeout-report.test.cjs && node tests/phase.test.cjs && node tests/session-fingerprint.test.cjs",
12
12
  "prepublishOnly": "node -e \"const ok=process.env.GITHUB_ACTIONS==='true'&&process.env.GITHUB_REF_NAME==='main'&&process.env.GITHUB_WORKFLOW==='Release'; if(!ok){console.error('Refusing to publish gsdd-cli outside the GitHub Actions Release workflow on main.'); process.exit(1)}\""
13
13
  },
14
14
  "devDependencies": {