Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ Workflows are agent skills or commands, not plain shell utilities. How you invok
| `npx -y gsdd-cli init [--tools <platform>]` | Set up `.planning/`, generate skills/adapters |
| `npx -y gsdd-cli update [--tools <platform>] [--templates]` | Regenerate skills/adapters and refresh the repo-local helper runtime; `--templates` refreshes `.planning/templates/` and role contracts |
| `npx -y gsdd-cli health [--json]` | Check workspace integrity and generated-surface freshness (healthy/degraded/broken) |
| `npx -y gsdd-cli ui-proof validate <path> [--claim <public\|publication\|tracked\|delivery\|release>]` | Validate UI proof bundle metadata without requiring browser tooling; use `--claim` only when validating that stronger proof use |
| `npx -y gsdd-cli file-op <copy\|delete\|regex-sub>` | Run deterministic workspace-confined file copy, delete, and regex substitution |
| `npx -y gsdd-cli find-phase [N]` | Show phase info as JSON (for agent consumption) |
| `npx -y gsdd-cli phase-status <N> <status>` | Update a single ROADMAP phase status through the status-aware helper |
Expand Down
3 changes: 3 additions & 0 deletions agents/executor.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ Before reporting a task complete:
- if a UI change is involved, verify the relevant rendering path
- if an API change is involved, hit the endpoint or targeted integration path
- A task is not complete because code was written. It is complete when the intended verification path actually passes.

### UI Proof Execution
If the plan defines UI proof slots, record observed proof against the exact claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit before claiming task completion. Artifact metadata must include `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; raw screenshots, traces, videos, DOM snapshots, and reports are local-only/unsafe by default and cannot back public, tracked, delivery, release, or publication proof claims. Use `gsdd ui-proof validate <path>` or `gsdd health` when a bundle exists. Artifact count, source comments, AST/cAST findings, semantic search, and Semble-like retrieval are not proof. Missing or weakly linked evidence must be recorded as proof debt, waiver, deferment, or reduced claim language rather than satisfied proof.
</execution_loop>

<checkpoint_protocol>
Expand Down
12 changes: 11 additions & 1 deletion agents/planner.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,14 @@ Any checkpoint must be justified by the task itself, not by planner caution or h
Any plan containing `checkpoint:*` must set `autonomous: false`.
</task_contract>

<ui_proof_planning>
For UI-sensitive work, plan proof slots that can later be matched exactly to claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit. Use only the stable evidence kinds `code`, `test`, `runtime`, `delivery`, and `human`.

Require observed artifacts to carry `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; when a planned slot is meant to support public, publication, tracked, delivery, or release proof, say to validate the observed bundle with `gsdd ui-proof validate <path> --claim <...>`. `gsdd ui-proof validate`/`gsdd health` must catch invalid bundle metadata when present.

Do not let source annotations, AST/cAST findings, semantic search, comments, or Semble-like retrieval satisfy proof slots; they are discovery hints only. Human acceptance can narrow or waive a claim and record proof debt, but it must not turn missing or mismatched non-human evidence into `satisfied` proof.
</ui_proof_planning>

<dependency_graph_example>
Example dependency graph:

Expand Down Expand Up @@ -184,7 +192,7 @@ Wave rule:
Write one or more `PLAN.md` files to the phase directory.

Keep the current GSDD schema exactly:
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `runtime`, `assurance`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `non_goals`, `hard_boundaries`, `escalation_triggers`, `approval_gates`, `anti_regression_targets`, `known_unknowns`, `high_leverage_surfaces`, `second_pass_required`, `closure_claim_limit`, `parallelism_budget`, `leverage`, `must_haves`
- frontmatter keys: `phase`, `plan`, `type`, `wave`, `runtime`, `assurance`, `depends_on`, `files-modified`, `autonomous`, `requirements`, `non_goals`, `hard_boundaries`, `escalation_triggers`, `approval_gates`, `anti_regression_targets`, `known_unknowns`, `ui_proof_slots`, `no_ui_proof_rationale`, `high_leverage_surfaces`, `second_pass_required`, `closure_claim_limit`, `parallelism_budget`, `leverage`, `must_haves`
- typed tasks with `files`, `action`, `verify`, and `done`

Typed frontmatter example:
Expand Down Expand Up @@ -215,6 +223,8 @@ anti_regression_targets:
- Existing session middleware behavior remains unchanged for already-supported routes.
known_unknowns:
- Exact copy wording for auth errors may still need product confirmation.
ui_proof_slots: []
no_ui_proof_rationale: Not UI-sensitive; scoped work does not claim a visible UI outcome.
high_leverage_surfaces: []
second_pass_required: false
closure_claim_limit: Do not claim phase completion until verification satisfies the evidence contract for the scoped truths.
Expand Down
2 changes: 2 additions & 0 deletions agents/verifier.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ Do not return a flat symptom list when the same underlying breakage explains mul

Visual correctness, live interaction quality, and some external integrations still need explicit human checks.

For UI proof slots, fail closed unless observed proof is matched to the exact claim, route/state, observation, evidence kind, artifact path or manual step, privacy metadata, result, and claim limit. Artifact metadata must include `visibility`, `retention`, `sensitivity`, and `safe_to_publish`; local-only or unsafe artifacts cannot back public, tracked, delivery, release, or publication proof claims, and `gsdd ui-proof validate`/`gsdd health` metadata failures block the stronger proof claim. Screenshots, traces, reports, Gherkin, a11y scans, E2E outputs, manual notes, source annotations, AST/cAST findings, semantic search, comments, and Semble-like retrieval do not satisfy proof by existence alone. Human acceptance records risk, waiver, deferment, proof debt, or a narrowed claim; it does not upgrade missing or mismatched non-human proof to `satisfied`.

## Step 9: Determine overall status

- `passed` when all programmatic checks pass and no human-only checks remain
Expand Down
9 changes: 4 additions & 5 deletions bin/gsdd.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { cmdFileOp } from './lib/file-ops.mjs';
import { createCmdHealth } from './lib/health.mjs';
import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
import { cmdSessionFingerprint } from './lib/session-fingerprint.mjs';
import { cmdUiProof } from './lib/ui-proof.mjs';
import { resolveWorkspaceContext } from './lib/workspace-root.mjs';

const __filename = fileURLToPath(import.meta.url);
Expand Down Expand Up @@ -107,6 +108,7 @@ const COMMANDS = {
'file-op': cmdFileOp,
'lifecycle-preflight': cmdLifecyclePreflight,
'session-fingerprint': cmdSessionFingerprint,
'ui-proof': cmdUiProof,
'find-phase': cmdFindPhase,
'phase-status': cmdPhaseStatus,
verify: cmdVerify,
Expand All @@ -132,8 +134,5 @@ async function runCli(cliCommand = command, ...cliArgs) {
await COMMANDS[cliCommand](...normalizedArgs);
}

if (IS_MAIN) {
await runCli();
}

export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdSessionFingerprint, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
if (IS_MAIN) await runCli();
export { cmdHelp, cmdInit, cmdUpdate, cmdModels, cmdHealth, cmdFileOp, cmdLifecyclePreflight, cmdSessionFingerprint, cmdUiProof, cmdFindPhase, cmdPhaseStatus, cmdVerify, cmdScaffold, runCli, FRAMEWORK_VERSION, createCliContext };
24 changes: 21 additions & 3 deletions bin/lib/health.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@
// evaluate once, so CWD must be computed inside function bodies.

import { existsSync, readFileSync, readdirSync } from 'fs';
import { join } from 'path';
import { join, relative } from 'path';
import { readManifest, detectModifications } from './manifest.mjs';
import { output } from './cli-utils.mjs';
import { runTruthChecks, TRUTH_CHECK_IDS } from './health-truth.mjs';
import { evaluateLifecycleState } from './lifecycle-state.mjs';
import { evaluateRuntimeFreshness } from './runtime-freshness.mjs';
import { findUiProofBundleFiles, readUiProofBundleFile, validateUiProofBundle } from './ui-proof.mjs';
import { resolveWorkspaceContext } from './workspace-root.mjs';

/**
Expand All @@ -31,7 +32,7 @@ export function createCmdHealth(ctx) {
}
const cwd = workspaceRoot;
const frameworkSourceMode = isFrameworkSourceRepo(cwd);
const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];
const healthCheckIds = ['E1', 'E2', 'E3', 'E4', 'E5', 'E6', 'E7', 'E8', 'E9', 'E10', 'W1', 'W2', 'W3', 'W4', 'W5', 'W6', ...TRUTH_CHECK_IDS, 'I1', 'I2', 'I3'];

// Pre-init guard
if (!existsSync(join(planningDir, 'config.json'))) {
Expand Down Expand Up @@ -123,7 +124,7 @@ export function createCmdHealth(ctx) {
}

// E8: critical root template files missing
const requiredRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md'];
const requiredRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md', 'ui-proof.md'];
const missingRoot = requiredRootFiles.filter((f) => !existsSync(join(templatesDir, f)));
if (missingRoot.length > 0) {
errors.push({ id: 'E8', severity: 'ERROR', message: `.planning/templates/ missing critical root files: ${missingRoot.join(', ')}`, fix: 'Run `npx -y gsdd-cli update --templates`' });
Expand All @@ -140,6 +141,23 @@ export function createCmdHealth(ctx) {
}
}

// E10: known UI proof bundles must satisfy deterministic metadata/privacy validation.
for (const bundlePath of findUiProofBundleFiles(planningDir)) {
const relativePath = relative(cwd, bundlePath).replace(/\\/g, '/');
const parsed = readUiProofBundleFile(bundlePath);
const validation = parsed.errors.length > 0
? { valid: false, errors: parsed.errors }
: validateUiProofBundle(parsed.bundle);
if (!validation.valid) {
errors.push({
id: 'E10',
severity: 'ERROR',
message: `${relativePath} has invalid UI proof metadata (${validation.errors.map((entry) => entry.code).join(', ')})`,
fix: 'Run `gsdd ui-proof validate <path>` and add required privacy metadata, claim limits, fixed evidence kinds, observation artifact references, and safe-to-publish handling.',
});
}
}

// --- WARNING checks ---

// W1: generation-manifest.json missing
Expand Down
3 changes: 3 additions & 0 deletions bin/lib/init-runtime.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ Commands:
lifecycle-preflight <surface> [phase]
Inspect deterministic lifecycle gate results for a workflow surface
session-fingerprint write Rebaseline planning-state drift after reviewing changed planning files
ui-proof validate <path> [--claim <public|publication|tracked|delivery|release>]
Validate UI proof metadata; use --claim for stronger proof uses
help Show this summary

Platforms (for --tools):
Expand Down Expand Up @@ -257,6 +259,7 @@ Advanced/internal helpers (kept available, but not the primary first-run user st
lifecycle-preflight Inspect deterministic lifecycle gate results for a workflow surface
session-fingerprint Rebaseline the local planning-state fingerprint after review
phase-status Update ROADMAP.md phase status through the local helper surface
ui-proof Validate UI proof metadata; use --claim for stronger proof uses
file-op Deterministic workspace-confined file copy/delete/text mutation
`;
}
2 changes: 1 addition & 1 deletion bin/lib/lifecycle-state.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const BROWNFIELD_CHANGE_DIR = 'brownfield-change';
const PHASE_LINE_RE = /^\s*[-*]\s*\[([ x-])\]\s*\*\*Phase\s+(\d+(?:\.\d+)*[a-z]?):\s*(.+?)\*\*(?:\s+—\s+\[([^\]]+)])?/i;
const PHASE_DETAIL_HEADING_RE = /^(#{3,})\s+Phase\s+(\d+(?:\.\d+)*[a-z]?)(?::|\b)/i;
const PHASE_DETAIL_STATUS_RE = /^\s*\*\*Status\*\*:\s*\[([ x-])\]/i;
const ACTIVE_MILESTONE_HEADING_RE = /^###\s+(v[^\s]+)\s+(.+)$/im;
const ACTIVE_MILESTONE_HEADING_RE = /^#{2,3}\s+(v[^\s]+)\s+(.+)$/im;
const MILESTONE_LEDGER_HEADING_RE = /^##\s+(?:✅\s+)?(v[^\s]+)\s*(?:—|-)?\s*(.*)$/i;
const DETAILS_OPEN_RE = /<details\b/i;
const DETAILS_CLOSE_RE = /<\/details>/i;
Expand Down
5 changes: 5 additions & 0 deletions bin/lib/rendering.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const HELPER_LIB_FILES = Object.freeze([
'lifecycle-state.mjs',
'phase.mjs',
'session-fingerprint.mjs',
'ui-proof.mjs',
'workspace-root.mjs',
]);

Expand Down Expand Up @@ -47,13 +48,15 @@ import { cmdFileOp } from './lib/file-ops.mjs';
import { cmdLifecyclePreflight } from './lib/lifecycle-preflight.mjs';
import { cmdPhaseStatus } from './lib/phase.mjs';
import { cmdSessionFingerprint } from './lib/session-fingerprint.mjs';
import { cmdUiProof } from './lib/ui-proof.mjs';
import { bootstrapHelperWorkspace, consumeWorkspaceRootArg, resolveWorkspaceContext } from './lib/workspace-root.mjs';

const COMMANDS = {
'file-op': cmdFileOp,
'lifecycle-preflight': cmdLifecyclePreflight,
'phase-status': cmdPhaseStatus,
'session-fingerprint': cmdSessionFingerprint,
'ui-proof': cmdUiProof,
};

function printHelp() {
Expand All @@ -71,6 +74,8 @@ function printHelp() {
' Example: node .planning/bin/gsdd.mjs lifecycle-preflight verify 1 --expects-mutation phase-status',
' session-fingerprint write',
' Rebaseline planning-state drift after reviewing changed planning files',
' ui-proof validate <path> [--claim <public|publication|tracked|delivery|release>]',
' Validate UI proof metadata; use --claim for stronger proof uses',
'',
'Advanced option:',
' --workspace-root <path> Override workspace root discovery before or after the subcommand',
Expand Down
2 changes: 1 addition & 1 deletion bin/lib/templates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function installProjectTemplates({ planningDir, distilledDir, agentsDir }
console.log(` - WARN: missing expected template subdir: ${subdir}/`);
}
}
const expectedRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md'];
const expectedRootFiles = ['spec.md', 'roadmap.md', 'auth-matrix.md', 'ui-proof.md'];
for (const file of expectedRootFiles) {
if (!existsSync(join(localTemplatesDir, file))) {
console.log(` - WARN: missing expected root template file: ${file}`);
Expand Down
Loading