ai-delivery-workflow 0.5.0 → 0.6.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.
- package/README.md +5 -6
- package/bin/ai-delivery.mjs +2 -24
- package/docs/CLI-PARAMETER-REFERENCE.zh-CN.md +6 -67
- package/docs/DUAL-REPOSITORY-WORKSPACE.zh-CN.md +1 -1
- package/docs/FILE-REFERENCE.zh-CN.md +6 -28
- package/docs/MAINTENANCE-VERIFICATION.zh-CN.md +2 -2
- package/docs/PROJECT-MANUAL.zh-CN.md +23 -38
- package/docs/STATE-CLI-MAINTENANCE.zh-CN.md +8 -10
- package/docs/STATE-CLI-USER-GUIDE.zh-CN.md +6 -16
- package/docs/agents/workflow-manager-acceptance-matrix.md +9 -15
- package/docs/agents/workflow-manager-current-state.md +12 -15
- package/lib/communication-confirmation.mjs +177 -0
- package/lib/delivery-state.mjs +59 -910
- package/lib/fs-utils.mjs +0 -16
- package/lib/project-bootstrap.mjs +288 -61
- package/lib/project-installer.mjs +49 -181
- package/lib/project-repair.mjs +217 -0
- package/lib/toml-hooks.mjs +2 -4
- package/lib/workflow-manager-governance.mjs +3 -47
- package/lib/workspace.mjs +2 -3
- package/package.json +2 -2
- package/skills/ai-delivery-bootstrap/SKILL.md +5 -1
- package/skills/ai-delivery-bootstrap/references/bootstrap-contract.md +1 -1
- package/skills/ai-delivery-checkpoint-task/SKILL.md +2 -4
- package/skills/ai-delivery-checkpoint-task/references/checkpoint-contract.md +4 -2
- package/skills/ai-delivery-checkpoint-task/scripts/hook-event.mjs +2 -8
- package/skills/ai-delivery-checkpoint-task/scripts/task-state.mjs +26 -46
- package/skills/ai-delivery-close-version/SKILL.md +13 -10
- package/skills/ai-delivery-close-version/references/version-closeout-contract.md +2 -1
- package/skills/ai-delivery-define-product/SKILL.md +6 -3
- package/skills/ai-delivery-design-architecture/SKILL.md +10 -5
- package/skills/ai-delivery-design-architecture/assets/architecture-template/architecture-gate.yaml +2 -0
- package/skills/ai-delivery-design-architecture/assets/architecture-template/prototype-architecture-validation.yaml +2 -0
- package/skills/ai-delivery-design-architecture/references/architecture-contract.md +4 -0
- package/skills/ai-delivery-design-experience/SKILL.md +8 -6
- package/skills/ai-delivery-design-experience/assets/experience-template/product-prototype-reconciliation.yaml +2 -0
- package/skills/ai-delivery-design-experience/assets/experience-template/ui-handoff.yaml +3 -0
- package/skills/ai-delivery-design-experience/references/experience-contract.md +3 -13
- package/skills/ai-delivery-design-experience/references/prototype-management-contract.md +1 -1
- package/skills/ai-delivery-design-tests/SKILL.md +4 -0
- package/skills/ai-delivery-develop-iteration/SKILL.md +6 -1
- package/skills/ai-delivery-develop-iteration/assets/development-template/candidate-manifest.yaml +2 -0
- package/skills/ai-delivery-execute-work-package/SKILL.md +4 -2
- package/skills/ai-delivery-orchestrate/SKILL.md +7 -7
- package/skills/ai-delivery-orchestrate/assets/codebase-template/AGENTS.md +14 -0
- package/skills/ai-delivery-orchestrate/assets/codebase-template/CODEBASE_GUIDE.md +124 -0
- package/skills/ai-delivery-orchestrate/assets/codebase-template/docs/CODEBASE_INDEX.md +87 -0
- package/skills/ai-delivery-orchestrate/assets/communication-template/confirmation-examples.yaml +67 -0
- package/skills/ai-delivery-orchestrate/assets/communication-template/confirmation-summary.yaml +42 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/iterations/ITER-0001/02-solution-design/product-impact-assessment.yaml +42 -0
- package/skills/ai-delivery-orchestrate/assets/project-template/.workflow/tools/hooks/hook-event.mjs +2 -8
- package/skills/ai-delivery-orchestrate/assets/project-template/AGENTS.md +4 -5
- package/skills/ai-delivery-orchestrate/references/codebase-document-contract.md +91 -0
- package/skills/ai-delivery-orchestrate/references/communication-confirmation-contract.md +52 -0
- package/skills/ai-delivery-orchestrate/references/formal-state-contract.md +11 -20
- package/skills/ai-delivery-orchestrate/references/product-impact-assessment-contract.md +87 -0
- package/skills/ai-delivery-orchestrate/references/workflow-model.md +1 -3
- package/skills/ai-delivery-orchestrate/scripts/confirmation-state.mjs +30 -0
- package/skills/ai-delivery-orchestrate-release/SKILL.md +3 -1
- package/skills/ai-delivery-plan-iteration/SKILL.md +6 -1
- package/skills/ai-delivery-prepare-platform/SKILL.md +1 -1
- package/skills/ai-delivery-prepare-release/SKILL.md +2 -0
- package/skills/ai-delivery-prepare-release/assets/release-template/release-manifest.yaml +0 -2
- package/skills/ai-delivery-review-change/SKILL.md +3 -1
- package/skills/ai-delivery-validate-artifacts/SKILL.md +10 -7
- package/skills/ai-delivery-validate-artifacts/references/artifact-contract.md +2 -1
- package/skills/ai-delivery-verify-candidate/SKILL.md +5 -2
- package/skills/ai-delivery-verify-candidate/references/candidate-verification-contract.md +1 -1
- package/docs/PROTOTYPE-MIGRATION.zh-CN.md +0 -164
- package/docs/VIEWER-MAINTENANCE.zh-CN.md +0 -150
- package/docs/VIEWER-USER-GUIDE.zh-CN.md +0 -113
- package/lib/project-migration.mjs +0 -1193
- package/lib/prototype-migration.mjs +0 -713
- package/skills/ai-delivery-design-experience/assets/experience-template/LEGACY-COMPATIBILITY.md +0 -16
- package/skills/ai-delivery-design-experience/assets/experience-template/canvas-catalog.csv +0 -1
- package/skills/ai-delivery-design-experience/assets/experience-template/canvas-pages.csv +0 -1
- package/skills/ai-delivery-design-experience/assets/experience-template/page-catalog.csv +0 -1
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-file-terminals.csv +0 -1
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-files.csv +0 -1
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-manifest.yaml +0 -76
- package/skills/ai-delivery-design-experience/assets/experience-template/prototype-set.yaml +0 -24
package/lib/toml-hooks.mjs
CHANGED
|
@@ -14,7 +14,6 @@ export const HOOK_EVENTS = [
|
|
|
14
14
|
];
|
|
15
15
|
|
|
16
16
|
const HOOK_COMMAND = "node .workflow/tools/hooks/hook-event.mjs";
|
|
17
|
-
const LEGACY_HOOK_COMMAND = "node .ai-delivery/hooks/hook-event.mjs";
|
|
18
17
|
|
|
19
18
|
function hookBlock(event, newline) {
|
|
20
19
|
return [
|
|
@@ -102,9 +101,8 @@ export function mergeHookConfig(existing, { force = false } = {}) {
|
|
|
102
101
|
const newline = existing.includes("\r\n") ? "\r\n" : "\n";
|
|
103
102
|
let text = existing.trimEnd();
|
|
104
103
|
const actions = [];
|
|
105
|
-
if (text.includes(
|
|
106
|
-
|
|
107
|
-
actions.push("migrate AI delivery Hook command into .workflow/tools");
|
|
104
|
+
if (text.includes("node .ai-delivery/hooks/hook-event.mjs")) {
|
|
105
|
+
throw new Error("Unsupported legacy Hook command; remove the .ai-delivery handler before installing the current Hook.");
|
|
108
106
|
}
|
|
109
107
|
if (force) {
|
|
110
108
|
const refreshed = removeDeliveryHandlerBlocks(text);
|
|
@@ -24,7 +24,6 @@ export const WORKFLOW_MANAGER_GOVERNANCE_SCHEMA_VERSION = "workflow-manager.gove
|
|
|
24
24
|
const RELATIONS_FILE = ".workflow/control/relations.yaml";
|
|
25
25
|
const SETTINGS_FILE = ".workflow/config/manager-settings.json";
|
|
26
26
|
const RECEIPTS_ROOT = ".workflow/control/receipts";
|
|
27
|
-
const EVENTS_FILE = ".workflow/control/events/workflow-manager-events.jsonl";
|
|
28
27
|
const SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,191}$/;
|
|
29
28
|
const SAFE_ENTITY_TYPE = /^[a-z][a-z0-9-]{0,63}$/;
|
|
30
29
|
const RELATION_TYPES = new Set([
|
|
@@ -59,18 +58,6 @@ function contained(root, relative) {
|
|
|
59
58
|
return absolute;
|
|
60
59
|
}
|
|
61
60
|
|
|
62
|
-
function atomicWrite(file, content) {
|
|
63
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
64
|
-
const temporary = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
65
|
-
fs.writeFileSync(temporary, content, { encoding: "utf8", flag: "wx" });
|
|
66
|
-
try {
|
|
67
|
-
fs.renameSync(temporary, file);
|
|
68
|
-
} catch (error) {
|
|
69
|
-
fs.rmSync(temporary, { force: true });
|
|
70
|
-
throw error;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
61
|
function requireHuman(actor) {
|
|
75
62
|
if (!/^human:[A-Za-z0-9._@/-]+$/.test(String(actor || ""))) {
|
|
76
63
|
throw new Error("Governed confirmation requires actor human:<identity>");
|
|
@@ -92,16 +79,13 @@ function receiptFiles(root) {
|
|
|
92
79
|
|
|
93
80
|
function replay(root, action, input, subject = null) {
|
|
94
81
|
if (!input.idempotency_key) return null;
|
|
95
|
-
const
|
|
96
|
-
const governedRequestChecksum = workflowManagerRequestChecksum(action, input, subject);
|
|
82
|
+
const expectedRequestChecksum = workflowManagerRequestChecksum(action, input, subject);
|
|
97
83
|
for (const file of receiptFiles(root)) {
|
|
98
84
|
try {
|
|
99
85
|
const receipt = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
100
86
|
if (receipt.action !== action || receipt.idempotency_key !== input.idempotency_key) continue;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
&& (receipt.subject ?? null) === subject;
|
|
104
|
-
if (!legacy && !governed) {
|
|
87
|
+
if (receipt.request_checksum !== expectedRequestChecksum
|
|
88
|
+
|| (receipt.subject ?? null) !== subject) {
|
|
105
89
|
throw new Error("Idempotency key was already used for a different request");
|
|
106
90
|
}
|
|
107
91
|
return receipt;
|
|
@@ -112,34 +96,6 @@ function replay(root, action, input, subject = null) {
|
|
|
112
96
|
return null;
|
|
113
97
|
}
|
|
114
98
|
|
|
115
|
-
function record(root, action, input, detail = {}) {
|
|
116
|
-
const timestamp = new Date().toISOString();
|
|
117
|
-
const receipt = {
|
|
118
|
-
schema_version: 1,
|
|
119
|
-
receipt_id: `WMG-${crypto.randomUUID()}`,
|
|
120
|
-
action,
|
|
121
|
-
actor: input.actor,
|
|
122
|
-
idempotency_key: input.idempotency_key || null,
|
|
123
|
-
request_checksum: checksum({ action, input }),
|
|
124
|
-
applied_at: timestamp,
|
|
125
|
-
...detail,
|
|
126
|
-
};
|
|
127
|
-
receipt.receipt_checksum = checksum(receipt);
|
|
128
|
-
atomicWrite(contained(root, `${RECEIPTS_ROOT}/${receipt.receipt_id}.json`), `${JSON.stringify(receipt, null, 2)}\n`);
|
|
129
|
-
const event = {
|
|
130
|
-
schema_version: 1,
|
|
131
|
-
event_id: `WME-${crypto.randomUUID()}`,
|
|
132
|
-
type: `workflow-manager.${action}`,
|
|
133
|
-
occurred_at: timestamp,
|
|
134
|
-
receipt_id: receipt.receipt_id,
|
|
135
|
-
subject: detail.subject || null,
|
|
136
|
-
};
|
|
137
|
-
const eventFile = contained(root, EVENTS_FILE);
|
|
138
|
-
fs.mkdirSync(path.dirname(eventFile), { recursive: true });
|
|
139
|
-
fs.appendFileSync(eventFile, `${JSON.stringify(event)}\n`, "utf8");
|
|
140
|
-
return { receipt, event };
|
|
141
|
-
}
|
|
142
|
-
|
|
143
99
|
function relationsDocument(root) {
|
|
144
100
|
const file = contained(root, RELATIONS_FILE);
|
|
145
101
|
if (!fs.existsSync(file)) return { file, document: { schema_version: 1, revision: 0, relations: [] }, checksum: null };
|
package/lib/workspace.mjs
CHANGED
|
@@ -4,7 +4,6 @@ import { spawnSync } from "node:child_process";
|
|
|
4
4
|
import { parse as parseYaml, stringify as stringifyYaml } from "./yaml-runtime.mjs";
|
|
5
5
|
|
|
6
6
|
export const WORKSPACE_CONFIG = path.join(".workflow", "config", "workspace.yaml");
|
|
7
|
-
export const LEGACY_WORKSPACE_CONFIG = path.join(".ai-delivery", "workspace.yaml");
|
|
8
7
|
|
|
9
8
|
function toPosix(value) {
|
|
10
9
|
return value.replaceAll("\\", "/");
|
|
@@ -114,7 +113,7 @@ function initializeWorkflowRepository(workspaceRoot, branch, remote, heads, acti
|
|
|
114
113
|
const current = gitBranch(workspaceRoot);
|
|
115
114
|
if (current !== branch) {
|
|
116
115
|
if (gitHasCommit(workspaceRoot)) {
|
|
117
|
-
throw new Error(`Existing workflow repository must already use ${branch}; automatic
|
|
116
|
+
throw new Error(`Existing workflow repository must already use ${branch}; automatic branch changes are not supported.`);
|
|
118
117
|
}
|
|
119
118
|
if (!dryRun) runGit(workspaceRoot, ["symbolic-ref", "HEAD", `refs/heads/${branch}`]);
|
|
120
119
|
}
|
|
@@ -172,7 +171,7 @@ export function validateCodePath(workspaceRoot, codePath = "code") {
|
|
|
172
171
|
if (!normalized || normalized.includes("/") || normalized === "." || normalized === "..") {
|
|
173
172
|
throw new Error("Code path must be a relative direct child directory.");
|
|
174
173
|
}
|
|
175
|
-
if (new Set([".git", ".workflow", ".
|
|
174
|
+
if (new Set([".git", ".workflow", ".agents", ".codex"]).has(normalized)) {
|
|
176
175
|
throw new Error(`Reserved code path: ${normalized}`);
|
|
177
176
|
}
|
|
178
177
|
const absolute = path.resolve(workspaceRoot, normalized);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-delivery-workflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Project-scoped Codex skills and hooks for artifact-driven AI software delivery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"skills"
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
|
-
"test": "node --test verification/*.test.mjs",
|
|
25
|
+
"test": "node --test --test-concurrency=4 verification/*.test.mjs",
|
|
26
26
|
"manager:build": "npm --prefix manager run build",
|
|
27
27
|
"skills:validate": "node bin/validate-skills.mjs",
|
|
28
28
|
"audit:generate": "node audit/generate-all.mjs",
|
|
@@ -44,7 +44,7 @@ The first product question is the safe stopping point. Do not invent the initial
|
|
|
44
44
|
- `codebase-uninitialized`: use packaged `ai-delivery bootstrap`, review the repository baseline, inventory, context index, and adoption assessment, then invoke `$ai-delivery-define-product` to distinguish observed behavior from intended product behavior.
|
|
45
45
|
- `workflow-interrupted`: do not write bootstrap artifacts. If `runtime.next_action_owner` is `user`, return the recorded `next_action` as the single business question and perform no recovery, activation, checkpoint, task, artifact, or Git mutation. If it is `external`, report the recorded wait condition without mutation. Only an `agent`-owned next action may invoke `$ai-delivery-checkpoint-task recover`, reconcile reality, inspect the pending Evolution queue without applying changes mid-task, and continue `recommended_task_id`. When required input arrives, transfer ownership with both `--next-action-owner agent` and a new idempotent `--next-action`.
|
|
46
46
|
- `workflow-ready`: when a queued task is recommended, first apply the same `next_action_owner` boundary; activate it through `$ai-delivery-checkpoint-task` only when the owner is `agent`. Otherwise use the reported specialist skill or `$ai-delivery-orchestrate` to derive the next development node. Treat `release-ready` versions as completed development evidence, not implicit release intent. Route to `$ai-delivery-orchestrate-release` only when the user explicitly requests a release.
|
|
47
|
-
- `workflow-inconsistent`: stop automatic mutation, run the available project/package doctor internally, report exact conflicts, and obtain
|
|
47
|
+
- `workflow-inconsistent`: stop automatic mutation, run the available project/package doctor internally, report exact conflicts, and obtain an explicit repair decision. Use `upgrade --dry-run` for current managed installation drift; malformed current state, missing anchors, archive conflicts, and checksum drift fail closed until repaired through the governed current-state interface. Use `upgrade --force` only when the user explicitly approves replacing the reported managed files.
|
|
48
48
|
|
|
49
49
|
## Brownfield Rules
|
|
50
50
|
|
|
@@ -52,6 +52,10 @@ Treat repository scans as observations, not approved product or architecture tru
|
|
|
52
52
|
|
|
53
53
|
Do not replace existing product, architecture, test, or release baselines. Keep the project-state report and related observations outside the formal artifact registry while they remain working drafts, preserve every timestamped bootstrap run, and update only the `.workflow/delivery/bootstrap/latest.yaml` pointer.
|
|
54
54
|
|
|
55
|
+
### Codebase Handbook Discovery
|
|
56
|
+
|
|
57
|
+
For the configured nested code repository, inspect `AGENTS.md`, `CODEBASE_GUIDE.md`, and `docs/CODEBASE_INDEX.md` as read-only maintainer documents. The report records `observed`, `approved`, or `stale`; missing files are a warning, while malformed, path-invalid, symlink, or sensitive-content findings fail closed. Compare each declared `source_commit` with the code repository HEAD. Never infer an approved rule from the generated inventory, and never overwrite these files during bootstrap or upgrade.
|
|
58
|
+
|
|
55
59
|
## Resume Boundary
|
|
56
60
|
|
|
57
61
|
Codex lifecycle Hooks provide audit and heartbeat data only. Versioned Evolution Hooks may return `pass`, `warn`, or an approved `block`, but they never select or complete tasks and never mutate formal workflow state. A bootstrap report may recommend recovery, but `$ai-delivery-checkpoint-task` remains authoritative for task order, dependency readiness, worktree reconciliation, and idempotent continuation. Route pending feedback and extension evaluation to `$ai-delivery-evolve-workflow` only at a task, version, or explicit review safe point.
|
|
@@ -28,7 +28,7 @@ After installation, `node .workflow/tools/bootstrap/bootstrap.mjs inspect` is th
|
|
|
28
28
|
|
|
29
29
|
`ai-delivery bootstrap <project-root>` may initialize only `empty-uninitialized` and `codebase-uninitialized` projects through the project-scoped installer. Preserve existing code and configuration. On partial or conflicting installation, return `workflow-inconsistent` without writes. `--force` is allowed only after explicit user approval.
|
|
30
30
|
|
|
31
|
-
For an installed
|
|
31
|
+
For an installed or conflicting state, keep Bootstrap read-only and return `workflow-inconsistent` with the failing path and remediation. Use the packaged `repair --invalidate-archive` forward transaction only for an explicitly identified archive integrity defect; it records a human actor, reason, RCA evidence, and recovery evidence without rewriting immutable history.
|
|
32
32
|
|
|
33
33
|
For an uninitialized project, generate repository inventory and context artifacts from the first read-only scan snapshot. Do not let installer-generated `AGENTS.md`, `.gitignore`, Hook, skill, standard, or delivery files contaminate the observed pre-install codebase baseline.
|
|
34
34
|
|
|
@@ -11,10 +11,6 @@ Treat explicit task snapshots as authoritative. Treat Hook events as an audit tr
|
|
|
11
11
|
|
|
12
12
|
Write portable task state to `.workflow/control/tasks/<task-id>.yaml` and `.workflow/control/checkpoints/<task-id>/<checkpoint-id>.yaml`. Keep only PID, heartbeat, temporary locks, raw Hook events, and unshared context under ignored `.workflow/delivery/runtime/`. Keep durable node documents under `.workflow/iterations/<iteration-id>/<node-id>/`; runtime snapshots never replace registered delivery artifacts. Resolve code branch and commit from `.workflow/config/workspace.yaml` and the nested code repository.
|
|
13
13
|
|
|
14
|
-
## Legacy Node Boundary
|
|
15
|
-
|
|
16
|
-
Legacy development nodes are read-only compatibility. `inspect` remains a strictly read-only diagnosis path for historical tasks. `init`, `activate`, `checkpoint`, `finish`, and `archive-version` reject legacy task targets before mutation or Hook dispatch; `recover` refuses to materialize them and `publish` refuses to share them. New tasks use only the `development-seven-node` route, while `R00-release-request` through `R10-release-archive` remain writable.
|
|
17
|
-
|
|
18
14
|
## Start Or Resume
|
|
19
15
|
|
|
20
16
|
1. Locate the project root and shared state root.
|
|
@@ -64,6 +60,8 @@ Checkpoint after every externally meaningful milestone, before a long command, a
|
|
|
64
60
|
|
|
65
61
|
Use shared shards and the newest shared checkpoint as the portable recovery source. If local runtime is absent and `next_action_owner` is `agent`, `recover` restores it from shared state. For `user` or `external`, report the wait state without hydration; after the input arrives, `activate` performs the atomic hydration and owner transfer. If local and shared revisions or semantic checksums differ, stop for reconciliation. Inspect both Git repositories before resuming. Report pending `.workflow/delivery/runtime/evolution/pending/` events, but defer their evaluation until the recovered task reaches a safe point.
|
|
66
62
|
|
|
63
|
+
Confirmation waits persist the summary path, question identity, frontier round, and an idempotent next action. `user` and `external` ownership remains strict zero-mutation wait until explicit input transfer.
|
|
64
|
+
|
|
67
65
|
Generate a compact recovery report from snapshots, checkpoints, Hook events, Git, and workspace state. Return active work and failed tasks in `retryable_task_ids` by default; use `--include-closed` only when completed or abandoned details are required for an explicit audit. For each iteration, report total, completed, closed, remaining, active, retryable, queued, dependency-ready, and waiting tasks plus one deterministic `recommended_task_id`. Prefer an interrupted or active task, then the lowest-sequence failed task requiring `activate --new-attempt --phase repair`, then the lowest-sequence queued task whose dependencies are all `completed`. Resume only idempotent steps. Re-read production and external systems before any deployment recovery; never replay production deployment automatically.
|
|
68
66
|
|
|
69
67
|
## Hook Boundary
|
|
@@ -34,7 +34,7 @@ Keep `.workflow/delivery/runtime/` local and ignored. Persist durable stage outp
|
|
|
34
34
|
|
|
35
35
|
`task-state.mjs` is the only runtime-state writer. Do not directly edit task JSON, checkpoint JSON, active-task markers, recovery output, or archive indexes. Formal workflow and artifact state belong to `.workflow/tools/state/state.mjs`; do not edit its YAML or JSONL streams directly.
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Task contracts use the current `development-seven-node` route or the independent `R00-release-request` through `R10-release-archive` release route. `inspect` is read-only diagnosis; `init`, `activate`, `checkpoint`, `finish`, `recover`, `archive-version`, and `publish` operate only on current task contracts.
|
|
38
38
|
|
|
39
39
|
When the installed Evolution CLI exists, `init`, `activate`, `checkpoint`, `finish`, and `archive-version` emit idempotent schema 1 `task.before`, `task.after`, and `task.failed` events. An approved blocking `task.before` result stops the task command before mutation. Hook dispatch failures otherwise fail open as warnings and never replace checkpoint state as the completion authority.
|
|
40
40
|
|
|
@@ -75,7 +75,9 @@ For an installed dual-repository project, `task-state.mjs` resolves `code_branch
|
|
|
75
75
|
|
|
76
76
|
`blockers` represents current unresolved blockers. A `blocked` update replaces that list; any transition to another status clears it. Historical blocker text remains available in prior checkpoints and events.
|
|
77
77
|
|
|
78
|
-
`next_action_owner` is required in persisted state and has exactly three values: `agent`, `user`, or `external`;
|
|
78
|
+
`next_action_owner` is required in persisted state and has exactly three values: `agent`, `user`, or `external`; explicit null, empty, boolean, numeric, or unknown values are invalid. `user` and `external` are zero-mutation wait states. `recover` may report shared wait state but must not hydrate local task or resume files for it. After the required input arrives, `activate` requires both `--next-action-owner agent` and a new idempotent `--next-action`; it may atomically hydrate a missing local runtime snapshot from the matching shared shard and transfer ownership in the same transition. Same-revision local and shared content must have identical semantic checksums. Evidence arrays are ordered sets: replaying an already recorded `--evidence` value does not append a duplicate.
|
|
79
|
+
|
|
80
|
+
When waiting on a confirmation frontier, persist the summary path, `question_id`, `frontier_round`, and summary checksum in checkpoint evidence. Repeated answers are idempotent; superseding a decision appends a new record and never overwrites prior confirmation.
|
|
79
81
|
|
|
80
82
|
Pass `--state-root` when worktrees must write to one shared primary state directory. Pass `--worktree` during init so the script writes a local `.workflow/delivery/runtime/active-task.json` marker pointing to that state root. Later `checkpoint`, `finish`, and `recover` commands automatically use the marker's shared state root.
|
|
81
83
|
|
|
@@ -144,15 +144,9 @@ function enforceFrontendGuard(projectRoot, input) {
|
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
try {
|
|
147
|
-
const
|
|
148
|
-
const legacyProjectFile = currentProjectFile
|
|
149
|
-
? null
|
|
150
|
-
: findUp(process.cwd(), path.join("delivery", "project.yaml"));
|
|
151
|
-
const projectFile = currentProjectFile || legacyProjectFile;
|
|
147
|
+
const projectFile = findUp(process.cwd(), path.join(".workflow", "delivery", "project.yaml"));
|
|
152
148
|
if (!projectFile) process.exit(0);
|
|
153
|
-
const projectRoot =
|
|
154
|
-
? path.dirname(path.dirname(path.dirname(projectFile)))
|
|
155
|
-
: path.dirname(path.dirname(projectFile));
|
|
149
|
+
const projectRoot = path.dirname(path.dirname(path.dirname(projectFile)));
|
|
156
150
|
const markerFile = path.join(projectRoot, ".workflow", "delivery", "runtime", "active-task.json");
|
|
157
151
|
const marker = fs.existsSync(markerFile) ? JSON.parse(fs.readFileSync(markerFile, "utf8")) : null;
|
|
158
152
|
const raw = await readStdin();
|
|
@@ -42,19 +42,13 @@ const REPEATABLE_ARGS = new Set([
|
|
|
42
42
|
"completed-step", "blocker", "evidence", "depends-on", "acceptance", "finding-json",
|
|
43
43
|
"change-set-json",
|
|
44
44
|
]);
|
|
45
|
-
const
|
|
46
|
-
"01-product-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"07-iteration-planning",
|
|
53
|
-
"08-test-design",
|
|
54
|
-
"09-development",
|
|
55
|
-
"10-change-review",
|
|
56
|
-
"11-candidate-verification",
|
|
57
|
-
"12-version-closeout",
|
|
45
|
+
const VALID_NODE_IDS = new Set([
|
|
46
|
+
"00-bootstrap", "01-product-shaping", "02-solution-design", "03-delivery-readiness",
|
|
47
|
+
"04-implementation", "05-candidate-assurance", "06-version-closeout",
|
|
48
|
+
"R00-release-request", "R01-version-selection", "R02-release-eligibility", "R03-material-aggregation",
|
|
49
|
+
"R04-release-candidate", "R05-release-verification", "R06-release-preparation", "R07-production-approval",
|
|
50
|
+
"R08-production-deployment", "R09-production-verification", "R10-release-archive",
|
|
51
|
+
"development", "implementation", "planning", "test", "review",
|
|
58
52
|
]);
|
|
59
53
|
|
|
60
54
|
function parseArgs(argv) {
|
|
@@ -83,10 +77,8 @@ function requireValue(args, key) {
|
|
|
83
77
|
return value;
|
|
84
78
|
}
|
|
85
79
|
|
|
86
|
-
function
|
|
87
|
-
if (
|
|
88
|
-
throw new Error(`Legacy workflow node is read-only: ${node}`);
|
|
89
|
-
}
|
|
80
|
+
function assertCurrentNode(node) {
|
|
81
|
+
if (!VALID_NODE_IDS.has(node)) throw new Error(`Unsupported workflow node: ${node}`);
|
|
90
82
|
return node;
|
|
91
83
|
}
|
|
92
84
|
|
|
@@ -720,7 +712,7 @@ function repairChangesSinceBaseline(workflowRoot, baseline) {
|
|
|
720
712
|
}
|
|
721
713
|
|
|
722
714
|
function writeSharedTask(runtime, workflowRoot, task) {
|
|
723
|
-
|
|
715
|
+
assertCurrentNode(task.node);
|
|
724
716
|
const sharedFile = sharedTaskFile(workflowRoot, task.task_id);
|
|
725
717
|
let previousRevision = 0;
|
|
726
718
|
if (fs.existsSync(sharedFile)) {
|
|
@@ -786,25 +778,15 @@ function normalizeTask(task) {
|
|
|
786
778
|
task[key] = [...new Set(task[key])];
|
|
787
779
|
}
|
|
788
780
|
task.sequence = parseSequence(task.sequence);
|
|
789
|
-
task.next_action_owner = parseNextActionOwner(task.next_action_owner);
|
|
790
|
-
task.responsibility
|
|
781
|
+
task.next_action_owner = parseNextActionOwner(task.next_action_owner, undefined);
|
|
782
|
+
if (!task.responsibility) throw new Error(`Task ${task.task_id || "unknown"} is missing responsibility.`);
|
|
791
783
|
task.derived_from = task.derived_from || null;
|
|
792
784
|
task.supersedes = task.supersedes || null;
|
|
793
|
-
if (!Array.isArray(task.attempts)) {
|
|
794
|
-
|
|
795
|
-
task.attempts = legacyNumber > 0 && (task.started_at || task.status !== "queued")
|
|
796
|
-
? [normalizeAttempt(task.task_id, {
|
|
797
|
-
number: legacyNumber,
|
|
798
|
-
status: projectedTaskStatus(task.status, "attempt"),
|
|
799
|
-
started_at: task.started_at || task.created_at || null,
|
|
800
|
-
finished_at: CLOSED_STATUS.has(task.status) ? task.finished_at || task.updated_at || null : null,
|
|
801
|
-
}, legacyNumber)]
|
|
802
|
-
: [];
|
|
803
|
-
} else {
|
|
804
|
-
task.attempts = task.attempts.map((attempt, index) => normalizeAttempt(task.task_id, attempt, index + 1));
|
|
785
|
+
if (Object.prototype.hasOwnProperty.call(task, "attempt") || !Array.isArray(task.attempts)) {
|
|
786
|
+
throw new Error(`Task ${task.task_id || "unknown"} must use canonical attempts.`);
|
|
805
787
|
}
|
|
788
|
+
task.attempts = task.attempts.map((attempt, index) => normalizeAttempt(task.task_id, attempt, index + 1));
|
|
806
789
|
task.change_sets = Array.isArray(task.change_sets) ? task.change_sets.map((item) => normalizeChangeSet(item)) : [];
|
|
807
|
-
task.attempt = task.attempts.at(-1)?.number || 0;
|
|
808
790
|
return task;
|
|
809
791
|
}
|
|
810
792
|
|
|
@@ -852,7 +834,6 @@ function startAttempt(task, phase, timestamp) {
|
|
|
852
834
|
time_entries: [],
|
|
853
835
|
}, number);
|
|
854
836
|
task.attempts.push(attempt);
|
|
855
|
-
task.attempt = number;
|
|
856
837
|
return attempt;
|
|
857
838
|
}
|
|
858
839
|
|
|
@@ -1379,7 +1360,7 @@ function summarizeIteration(tasks, iterationId) {
|
|
|
1379
1360
|
function commandInit(args) {
|
|
1380
1361
|
const taskId = sanitizeId(requireValue(args, "task-id"));
|
|
1381
1362
|
const iterationId = sanitizeId(requireValue(args, "iteration-id"));
|
|
1382
|
-
const node =
|
|
1363
|
+
const node = assertCurrentNode(requireValue(args, "node"));
|
|
1383
1364
|
const { projectRoot, stateRoot, workflowRoot, runtime } = statePaths(args);
|
|
1384
1365
|
return withTaskLock(runtime, `version.${iterationId}`, () => withTaskLock(runtime, taskId, () => {
|
|
1385
1366
|
if (fs.existsSync(archivedTaskIndexFile(runtime, taskId))) {
|
|
@@ -1424,6 +1405,7 @@ function commandInit(args) {
|
|
|
1424
1405
|
const candidateContract = normalizeTask({
|
|
1425
1406
|
...(existing || {}),
|
|
1426
1407
|
...contractFields,
|
|
1408
|
+
attempts: existing?.attempts || [],
|
|
1427
1409
|
next_action_owner: existing?.next_action_owner || "agent",
|
|
1428
1410
|
});
|
|
1429
1411
|
if (existing) {
|
|
@@ -1459,7 +1441,6 @@ function commandInit(args) {
|
|
|
1459
1441
|
...contractFields,
|
|
1460
1442
|
status,
|
|
1461
1443
|
sequence: parseSequence(args.sequence ?? existing?.sequence),
|
|
1462
|
-
attempt: 0,
|
|
1463
1444
|
attempts: [],
|
|
1464
1445
|
change_sets: [],
|
|
1465
1446
|
input_artifacts: args["input-artifact"] || existing?.input_artifacts || [],
|
|
@@ -1486,7 +1467,7 @@ function commandInit(args) {
|
|
|
1486
1467
|
clearTaskMarker(task);
|
|
1487
1468
|
appendEvent(runtime, taskId, "task-initialized", {
|
|
1488
1469
|
status: task.status,
|
|
1489
|
-
|
|
1470
|
+
attempt_count: task.attempts.length,
|
|
1490
1471
|
derived_from: task.derived_from,
|
|
1491
1472
|
supersedes: task.supersedes,
|
|
1492
1473
|
});
|
|
@@ -1557,7 +1538,6 @@ function commandActivate(args) {
|
|
|
1557
1538
|
phase.status = "active";
|
|
1558
1539
|
phase.finished_at = null;
|
|
1559
1540
|
}
|
|
1560
|
-
task.attempt = attempt.number;
|
|
1561
1541
|
task.started_at ||= timestamp;
|
|
1562
1542
|
task.updated_at = timestamp;
|
|
1563
1543
|
task.finished_at = null;
|
|
@@ -1573,7 +1553,7 @@ function commandActivate(args) {
|
|
|
1573
1553
|
});
|
|
1574
1554
|
appendEvent(runtime, taskId, "task-activated", {
|
|
1575
1555
|
status,
|
|
1576
|
-
|
|
1556
|
+
attempt_count: task.attempts.length,
|
|
1577
1557
|
attempt_id: attempt.attempt_id,
|
|
1578
1558
|
phase: attempt.phases.at(-1)?.phase || null,
|
|
1579
1559
|
new_attempt: newAttempt,
|
|
@@ -1627,7 +1607,7 @@ function commandUpdate(args, finish = false) {
|
|
|
1627
1607
|
writeResume(runtime, task);
|
|
1628
1608
|
appendEvent(runtime, taskId, finish ? "task-finished" : "task-checkpointed", {
|
|
1629
1609
|
status,
|
|
1630
|
-
|
|
1610
|
+
attempt_number: attempt.number,
|
|
1631
1611
|
attempt_id: attempt.attempt_id,
|
|
1632
1612
|
phase: attempt.phases.at(-1)?.phase || null,
|
|
1633
1613
|
});
|
|
@@ -1696,7 +1676,7 @@ function commandArchiveVersion(args) {
|
|
|
1696
1676
|
.map((name) => normalizeTask(JSON.parse(fs.readFileSync(path.join(tasksDir, name), "utf8"))))
|
|
1697
1677
|
.filter((task) => task.iteration_id === iterationId);
|
|
1698
1678
|
if (!tasks.length) throw new Error(`No tasks found for version: ${iterationId}`);
|
|
1699
|
-
for (const task of tasks)
|
|
1679
|
+
for (const task of tasks) assertCurrentNode(task.node);
|
|
1700
1680
|
const sharedById = new Map(readSharedTasks(workflowRoot, stateRoot).map((task) => [task.task_id, task]));
|
|
1701
1681
|
for (const task of tasks) {
|
|
1702
1682
|
const shared = sharedById.get(task.task_id);
|
|
@@ -1795,7 +1775,7 @@ function commandRecover(args) {
|
|
|
1795
1775
|
const reportableTasks = selectedTasks
|
|
1796
1776
|
.filter((task) => !requested || task.task_id === requested)
|
|
1797
1777
|
.filter((task) => includeClosed || !RECOVERY_COMPLETE_STATUS.has(task.status));
|
|
1798
|
-
for (const task of reportableTasks)
|
|
1778
|
+
for (const task of reportableTasks) assertCurrentNode(task.node);
|
|
1799
1779
|
for (const task of reportableTasks) {
|
|
1800
1780
|
if (missingLocalTaskIds.has(task.task_id)) atomicWrite(taskFile(runtime, task.task_id), task);
|
|
1801
1781
|
}
|
|
@@ -1853,7 +1833,7 @@ function commandPublish(args) {
|
|
|
1853
1833
|
const checkpointDirectory = path.join(workflowRoot, "control", "checkpoints", taskId);
|
|
1854
1834
|
if (!fs.existsSync(sharedFile)) throw new Error(`Shared task state not found: ${taskId}`);
|
|
1855
1835
|
const shared = JSON.parse(fs.readFileSync(sharedFile, "utf8"));
|
|
1856
|
-
|
|
1836
|
+
assertCurrentNode(shared.node);
|
|
1857
1837
|
|
|
1858
1838
|
const repository = gitState(stateRoot);
|
|
1859
1839
|
if (!repository.repository || path.resolve(repository.root).toLowerCase() !== path.resolve(stateRoot).toLowerCase()) {
|
|
@@ -1978,7 +1958,7 @@ function assertWritableEvolutionTarget(args, command) {
|
|
|
1978
1958
|
if (!new Set(["init", "activate", "checkpoint", "finish", "archive-version"]).has(command)) return;
|
|
1979
1959
|
if (command === "init") {
|
|
1980
1960
|
const node = args.node && args.node !== true ? String(args.node) : null;
|
|
1981
|
-
if (node)
|
|
1961
|
+
if (node) assertCurrentNode(node);
|
|
1982
1962
|
return;
|
|
1983
1963
|
}
|
|
1984
1964
|
const { runtime, workflowRoot, stateRoot } = statePaths(args);
|
|
@@ -1990,14 +1970,14 @@ function assertWritableEvolutionTarget(args, command) {
|
|
|
1990
1970
|
if (!iterationId || !fs.existsSync(tasksDir)) return;
|
|
1991
1971
|
for (const name of fs.readdirSync(tasksDir).filter((item) => item.endsWith(".json"))) {
|
|
1992
1972
|
const task = normalizeTask(JSON.parse(fs.readFileSync(path.join(tasksDir, name), "utf8")));
|
|
1993
|
-
if (task.iteration_id === iterationId)
|
|
1973
|
+
if (task.iteration_id === iterationId) assertCurrentNode(task.node);
|
|
1994
1974
|
}
|
|
1995
1975
|
return;
|
|
1996
1976
|
}
|
|
1997
1977
|
const taskId = args["task-id"] && args["task-id"] !== true ? sanitizeId(args["task-id"]) : null;
|
|
1998
1978
|
if (!taskId) return;
|
|
1999
1979
|
const task = taskSources(runtime, workflowRoot, stateRoot, taskId).task;
|
|
2000
|
-
if (task)
|
|
1980
|
+
if (task) assertCurrentNode(task.node);
|
|
2001
1981
|
}
|
|
2002
1982
|
|
|
2003
1983
|
function dispatchTaskEvolution(context, phase, result = null, error = null) {
|
|
@@ -11,24 +11,27 @@ Finish one planned version and stop before release. Never start a release from t
|
|
|
11
11
|
|
|
12
12
|
1. Recover or initialize the `06-version-closeout` task through `$ai-delivery-checkpoint-task`.
|
|
13
13
|
2. Run `node .workflow/tools/state/state.mjs verify --history`.
|
|
14
|
-
3. Require a passing immutable candidate, a completed Candidate Assurance receipt for that same candidate, closed version tasks, complete requirement/test/material traceability, and no unresolved blocking defect.
|
|
14
|
+
3. Require a passing immutable candidate, a completed Candidate Assurance receipt for that same candidate, a resolved or superseded product impact assessment bound to the candidate, closed version tasks, complete requirement/test/material traceability, and no unresolved blocking defect.
|
|
15
15
|
4. Read the preceding version lineage and Git policy. Require the candidate to descend from the current `line/<product-id>` head, except for the first version.
|
|
16
16
|
|
|
17
17
|
## Close The Version
|
|
18
18
|
|
|
19
19
|
1. Read `.workflow/config/workspace.yaml`; verify the candidate in the configured code repository and populate `repo_id`, `code_commit`, `source_path`, and SHA-256.
|
|
20
|
-
2.
|
|
21
|
-
3.
|
|
22
|
-
4.
|
|
23
|
-
5.
|
|
24
|
-
6.
|
|
25
|
-
7.
|
|
26
|
-
8.
|
|
27
|
-
9.
|
|
28
|
-
10.
|
|
20
|
+
2. Validate the candidate's codebase handbook and navigation index at the exact code commit. Record their status, checksums, owner, last review, and any stale/invalid findings in closeout evidence; require repair or explicit maintainer acceptance before marking documentation evidence complete.
|
|
21
|
+
3. Freeze the candidate commit and create code `version-ready/<version-id>/rN`. Never move or replace an existing Tag; increment `rN` only for a newly verified replacement candidate.
|
|
22
|
+
4. Fast-forward code `line/<product-id>` to the tagged commit. Never advance code `main` here.
|
|
23
|
+
5. Copy the closeout assets into `.workflow/iterations/<version-id>/06-version-closeout/`, populate the code Tag identity, and compute the final manifest SHA-256.
|
|
24
|
+
6. Register the immutable closeout semantic revision directly as `release-ready` with the formal state CLI, and complete `06-version-closeout` with that registered artifact as evidence. Do not register a draft and mutate its status in place.
|
|
25
|
+
7. Commit all version workflow materials and create immutable workflow `workflow-ready/<version-id>/rN` at that exact workflow commit. Record the workflow commit, workflow Tag, and manifest checksum in the lineage index without rewriting the tagged manifest.
|
|
26
|
+
8. Verify both Tags and the manifest checksum. Inspect the current development scope revision, then run `state.mjs transition --expected-scope-revision <revision> --event version-closed --iteration-id <version-id> --artifact-id <closeout-artifact-id>` to update the audited cumulative development identity. Never edit `latest_line_version_id` directly.
|
|
27
|
+
9. Run `state.mjs snapshot create --id <version-id> --reason version-boundary`, then `state.mjs verify --history --since-anchor`. The first trusted anchor performs a full-history audit before creation; later anchors validate the suffix from the previous anchor.
|
|
28
|
+
10. Archive tasks with `task-state.mjs archive-version --version-status release-ready --candidate-id <candidate-id> --evidence <closeout-artifact-id>`. The command must first obtain `snapshot references` from the formal-state CLI and fail before writing if the anchor, scope, or candidate is missing. Verify that the version manifest references checksummed task summaries, complete attempt values, scope, candidate, Gate decisions, and the version-boundary anchor; then checkpoint the Git, anchor, and archive evidence and finish the task.
|
|
29
|
+
11. Invoke `$ai-delivery-evolve-workflow evaluate --safe-point version --iteration-id <version-id>`. Record trial results and decisions, but never use an Evolution result as release intent.
|
|
29
30
|
|
|
30
31
|
## Stop Boundary
|
|
31
32
|
|
|
32
33
|
Report the release-ready version, code Tag, workflow Tag, manifest checksum, cumulative line head, archived task count, and next planned version. Stop and wait for either the next version iteration or an explicit user release request. Do not invoke release orchestration implicitly.
|
|
33
34
|
|
|
34
35
|
Read [version-closeout-contract.md](references/version-closeout-contract.md) before writing outputs.
|
|
36
|
+
|
|
37
|
+
Before closeout, validate the confirmation summary and ensure confirmed product, architecture, standard, and risk decisions have authority references and matching checksums. Deferred or open decisions remain visible in closeout evidence. Closing a version does not imply release intent.
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
- planned version ID, product ID, predecessor version, and iteration plan;
|
|
6
6
|
- immutable candidate ID, commit, artifact digest, and passing verification decision;
|
|
7
|
+
- resolved or superseded `product-impact-assessment.yaml` bound to the candidate and the aligned product baseline;
|
|
7
8
|
- complete closed-task summary and unresolved-risk statement;
|
|
8
9
|
- current `line/<product-id>` head and applicable standards baseline.
|
|
9
10
|
|
|
@@ -17,4 +18,4 @@ After Candidate Assurance has completed for the same immutable candidate, the `r
|
|
|
17
18
|
|
|
18
19
|
## Failure rules
|
|
19
20
|
|
|
20
|
-
Block closeout for active tasks, mutable candidates, failed verification, missing materials, Git divergence, an existing tag resolving to another commit, or a candidate that does not include a synchronized production hotfix. Mark affected candidates `stale`; never edit a previously closed version.
|
|
21
|
+
Block closeout for active tasks, mutable candidates, failed verification, missing materials, an unresolved or checksum-drifted product impact assessment, Git divergence, an existing tag resolving to another commit, or a candidate that does not include a synchronized production hotfix. Mark affected candidates `stale`; never edit a previously closed version.
|
|
@@ -24,7 +24,7 @@ This Skill owns `01-product-shaping`. Discovery, product definition, and prototy
|
|
|
24
24
|
|
|
25
25
|
## Preflight
|
|
26
26
|
|
|
27
|
-
Read the project state, artifact registry, applicable standards,
|
|
27
|
+
Read the project state, artifact registry, applicable standards, existing product baseline, and the current `confirmation-summary.yaml`. For a change, identify the affected terms, terminals, features, stories, and acceptance criteria before editing. In prototype-reconciliation mode also read the shared `product-impact-assessment.yaml`, complete adjustment log, requirement change set, formal UI confirmation, exact Prototype revision and checksum, normalized Page and Review Scene catalogs, UI Mapping, and bidirectional product coverage. Facts discovered from the repository remain `observed_fact`; only the business sponsor confirms product intent, scope, terminology, priority, risk acceptance, or Gate decisions.
|
|
28
28
|
|
|
29
29
|
## Run Discovery
|
|
30
30
|
|
|
@@ -34,6 +34,8 @@ Read the project state, artifact registry, applicable standards, and existing pr
|
|
|
34
34
|
4. Produce the discovery baseline and run completeness and contradiction checks.
|
|
35
35
|
5. Submit discovery Gate A for human approval. Do not start product definition while Gate A is rejected or incomplete.
|
|
36
36
|
|
|
37
|
+
After each answer, append a structured confirmation record, recompute the frontier, and persist exactly one idempotent user-owned next action when another decision is required. Before Gate A or Gate B, produce a shared-understanding summary and link every confirmed business decision and domain term to its owning product artifact. Do not save the conversation transcript.
|
|
38
|
+
|
|
37
39
|
## Define The Product
|
|
38
40
|
|
|
39
41
|
1. Define the product specification, capability structure, business flows, user stories, acceptance criteria, non-functional requirements, and business priority.
|
|
@@ -59,6 +61,7 @@ Required outputs:
|
|
|
59
61
|
- `acceptance-criteria.csv`;
|
|
60
62
|
- traceability association CSV files;
|
|
61
63
|
- `product-baseline.yaml` with versions and item-level approval state.
|
|
64
|
+
- `confirmation-summary.yaml` with the current frontier, confirmed/rejected/deferred decisions, authority references, and shared-understanding result.
|
|
62
65
|
|
|
63
66
|
In prototype-reconciliation mode also produce the terminal requirement change set, bidirectional product coverage, product artifact delta, and `product-prototype-reconciliation.yaml`.
|
|
64
67
|
|
|
@@ -68,12 +71,12 @@ Use the schemas and controlled values in [product-contract.md](references/produc
|
|
|
68
71
|
|
|
69
72
|
Run this mode only after the candidate Prototype revision is approved for every visual or interactive Page and Review Scene and all of its adjustments are terminal.
|
|
70
73
|
|
|
71
|
-
1. Review every row in `requirement-change-set.csv`; classify it as approved, rejected, or requiring clarification. Do not approve a requirement merely because the prototype implements it.
|
|
74
|
+
1. Review the shared `product-impact-assessment.yaml` first. Confirm that every `product-update-required` or `clarification-required` finding has a user-owned question, affected stable IDs, and a return reason. Review every row in `requirement-change-set.csv`; classify it as approved, rejected, or requiring clarification. Do not approve a requirement merely because the prototype implements it.
|
|
72
75
|
2. Verify both directions of `prototype-product-coverage.csv`: every prototype behavior must resolve to an approved feature/story/acceptance criterion, and every visual product behavior must resolve to a prototype element or justified `not-applicable` row.
|
|
73
76
|
3. Apply approved added, modified, retired, or superseded requirements to a new product baseline version. Preserve stable IDs for modifications and retire IDs instead of reusing them.
|
|
74
77
|
4. Re-run Gate B for every changed product artifact and record exact approval evidence. When nothing changes, retain the existing baseline and record an `aligned` no-change decision.
|
|
75
78
|
5. Write `product-prototype-reconciliation.yaml` with the input/output product baseline checksums, prototype/formal-UI checksums, terminal and terminology checks, requirement-change closure, stale artifacts, and required prototype revalidation.
|
|
76
|
-
6. Return rejected prototype behavior to experience for removal. Return an updated baseline to experience, mark the affected Page and Review Scene revisions stale, and require their staged re-approval in a new Prototype revision. Repeat until the receipt is `status: valid`, `decision: aligned`,
|
|
79
|
+
6. Return rejected prototype behavior to experience for removal. Return an updated baseline to experience, resolve the shared impact assessment, mark the affected Page and Review Scene revisions stale, and require their staged re-approval in a new Prototype revision. Repeat until the receipt is `status: valid`, `decision: aligned`, every requirement change is terminal, and every product impact assessment is `resolved` or `superseded`.
|
|
77
80
|
|
|
78
81
|
## Handoff
|
|
79
82
|
|
|
@@ -23,28 +23,31 @@ This Skill shares `02-solution-design` with `$ai-delivery-design-experience`. In
|
|
|
23
23
|
|
|
24
24
|
## Preflight
|
|
25
25
|
|
|
26
|
-
Read the approved product baseline, business glossary, terminal matrix, feature catalog, applicable standards, and
|
|
26
|
+
Read the approved product baseline, business glossary, terminal matrix, feature catalog, applicable standards, prior architecture decisions, the current `confirmation-summary.yaml`, and the configured code repository's `AGENTS.md`, `CODEBASE_GUIDE.md`, and relevant `docs/CODEBASE_INDEX.md` entries. Read [product-impact-assessment-contract.md](../ai-delivery-orchestrate/references/product-impact-assessment-contract.md) before classifying a design discovery. Treat handbook content and confirmation summaries as context/traceability only: architecture artifacts and decisions remain the sole authority for boundaries and dependency rules. Reject missing, stale, malformed, or conflicting references instead of guessing product scope; record a draft remediation when documentation is incomplete.
|
|
27
27
|
|
|
28
28
|
## Initial Mode
|
|
29
29
|
|
|
30
|
-
1. Convert non-functional requirements into measurable quality scenarios and budgets.
|
|
30
|
+
1. Convert non-functional requirements into measurable quality scenarios and budgets. If a new budget, constraint, or tradeoff changes product scope, priority, risk acceptance, terminology, terminal coverage, or acceptance, create `product-impact-assessment.yaml` before continuing.
|
|
31
31
|
2. Define system context, application and component boundaries, terminal implementation strategies, data ownership, authentication and authorization, security controls, deployment topology, observability, and operational constraints.
|
|
32
32
|
3. Select technology stacks with exact supported versions, package and build tools, repository layout, dependency policy, and required commands.
|
|
33
33
|
4. Draft APIs, events, data contracts, migration strategy, test seams, and delivery constraints.
|
|
34
34
|
5. Record only decisions that are costly to reverse and based on real tradeoffs.
|
|
35
|
-
6.
|
|
35
|
+
6. Classify each discovery with the shared assessment. `no-impact` and `architecture-only` require evidence; `product-update-required` and `clarification-required` return to `01-product-shaping` and block the architecture handoff until product reconciliation is valid.
|
|
36
|
+
7. Submit major decisions for human approval before experience design proceeds.
|
|
36
37
|
|
|
37
38
|
Major decisions include platforms, paid services, security or privacy boundaries, hard-to-reverse data or infrastructure choices, material cost/performance/schedule tradeoffs, and deviations from approved product scope.
|
|
38
39
|
|
|
39
40
|
## Reconcile Mode
|
|
40
41
|
|
|
41
|
-
1. Read the experience baseline, `ui-handoff.yaml`, both staged Gate receipts (`UX-VS` and `UX-UI`), aligned `product-prototype-reconciliation.yaml` receipt, experience/requirement change sets, interaction contract, design tokens, framework selection, component-state matrix, page-component map, the exact immutable Prototype revision and checksum, its source and review-bundle checksums, the normalized terminal, Page, Review Scene, trigger-condition, route, and UI Mapping catalogs, review/impact records, traceability, and source confirmation. Verify every exact identity/checksum and require the handoff to be complete and free of stale references. Reject a missing or conflicting reference; never infer a relationship from a file name or catalog order.
|
|
42
|
+
1. Read the experience baseline, `ui-handoff.yaml`, both staged Gate receipts (`UX-VS` and `UX-UI`), the aligned `product-prototype-reconciliation.yaml` receipt, the shared `product-impact-assessment.yaml`, experience/requirement change sets, interaction contract, design tokens, framework selection, component-state matrix, page-component map, the exact immutable Prototype revision and checksum, its source and review-bundle checksums, the normalized terminal, Page, Review Scene, trigger-condition, route, and UI Mapping catalogs, review/impact records, traceability, and source confirmation. Verify every exact identity/checksum and require the handoff to be complete and free of stale references. Reject a missing or conflicting reference; never infer a relationship from a file name or catalog order.
|
|
42
43
|
2. Resolve every affected Page, Review Scene, UI component, frontend source, and acceptance ID through the pinned UI Mapping. Verify that the selected UI framework/version is compatible with the architecture stack and dependency policy, and that every mapped interaction, state, permission, query, upload, real-time behavior, failure mode, responsive rule, and accessibility requirement is technically supported. Use stable change, terminal, Page, Review Scene, prototype-element, UI Mapping, component, frontend-source, and acceptance IDs in findings.
|
|
43
44
|
3. Write one `prototype-architecture-validation.yaml` for the Prototype revision with the UI handoff identity/checksum, Prototype revision and UI Mapping checksums, all consumed artifact versions/checksums, exact architecture baseline version/checksum, implementability decision, affected changes/Pages/Review Scenes/mappings/components/acceptance criteria, issues, and return node. An accepted receipt uses `status: valid`; a `changes-required` receipt uses `status: invalid`. Accept the handoff only when the receipt passes, then advance accepted experience changes from `formal-ui-confirmed` to `architecture-accepted` and `ready-for-development` through the state CLI.
|
|
44
|
-
4. Return product
|
|
45
|
+
4. Wrap any product-affecting architecture finding in `product-impact-assessment.yaml`. Return `product-update-required` and `clarification-required` to `01-product-shaping`; return experience defects to their producer. Do not silently weaken approved behavior, edit the frozen prototype, or continue with an unresolved assessment.
|
|
45
46
|
5. Finalize APIs, data access, events, component boundaries, test seams, deployment requirements, and implementation constraints.
|
|
46
47
|
6. Reopen human approval only when reconciliation creates or changes a major decision.
|
|
47
48
|
|
|
49
|
+
For each new architecture decision, append a confirmation record with factual evidence, alternatives, recommendation, user decision, impact, and owning architecture artifact. Ask only frontier decisions that are not answerable from the environment. A confirmed record never substitutes for the architecture Gate.
|
|
50
|
+
|
|
48
51
|
## Outputs
|
|
49
52
|
|
|
50
53
|
Produce one versioned architecture baseline containing:
|
|
@@ -61,6 +64,8 @@ Produce one versioned architecture baseline containing:
|
|
|
61
64
|
- prototype architecture validation receipt in reconcile mode;
|
|
62
65
|
- UI framework/dependency acceptance and exact `ui-handoff.yaml` receipt in reconcile mode;
|
|
63
66
|
- final test seams and component impact map.
|
|
67
|
+
- handbook review evidence: exact code commit, files/sections consulted, stale or missing findings, and maintainer confirmation required for any promoted rule.
|
|
68
|
+
- confirmation summary and decision-to-architecture artifact traceability.
|
|
64
69
|
|
|
65
70
|
Do not require DDD constructs. Use business terms from the product manual and provide explicit mappings for unavoidable technical names.
|
|
66
71
|
|