feat: add experimental wealth-ledger-sdd-lab OpenSpec schema (#61)
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
#!/usr/bin/env node
|
||||
// Deterministic checks for wealth-ledger-sdd-lab changes. OpenSpec CLI 1.13.1 has no conditional
|
||||
// artifacts, gate records or archive policy, so this file covers only what the CLI cannot.
|
||||
// It is the single source for profile, ordering, gate and readiness rules; schema.yaml points here.
|
||||
// Semantic quality (contradictions, invented facts, design fit) stays with reviewers.
|
||||
//
|
||||
// Usage: node check.cjs <plan|apply|archive> <change-name> [--root <openspec-root>]
|
||||
// plan — artifact consistency while planning; missing gates are notes, not errors.
|
||||
// apply — plan + every apply blocker is an error.
|
||||
// archive — apply + all tasks done, G4 approved, lab retrospective.
|
||||
// Exit: 0 ok, 1 violations, 2 invocation/environment error.
|
||||
"use strict";
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const SA_MODULES = ["data-mapping", "failure-model", "nfr", "observability"];
|
||||
// Primary file of each conditional artifact, relative to the change directory.
|
||||
const PRIMARY = {
|
||||
research: "research.md",
|
||||
"ux-design": "ux-design.md",
|
||||
"system-analysis": "system-analysis/system-analysis.md",
|
||||
"data-mapping": "system-analysis/data-mapping.md",
|
||||
"failure-model": "system-analysis/failure-model.md",
|
||||
nfr: "system-analysis/nfr.md",
|
||||
observability: "system-analysis/observability.md",
|
||||
"security-analysis": "security-analysis.md",
|
||||
"test-cases": "test-cases",
|
||||
"docs-impact": "docs-impact.md",
|
||||
};
|
||||
const CONDITIONAL = Object.keys(PRIMARY);
|
||||
// A selected conditional input must exist before any of these files is written.
|
||||
const BEFORE_SOLUTION = ["design.md", "qa-analysis.md", "tasks.md"];
|
||||
const DOWNSTREAM = {
|
||||
research: ["specs", ...BEFORE_SOLUTION],
|
||||
"ux-design": BEFORE_SOLUTION,
|
||||
"system-analysis": BEFORE_SOLUTION,
|
||||
...Object.fromEntries(SA_MODULES.map((id) => [id, BEFORE_SOLUTION])),
|
||||
"security-analysis": BEFORE_SOLUTION,
|
||||
"test-cases": ["tasks.md"],
|
||||
"docs-impact": ["tasks.md"],
|
||||
};
|
||||
// Gate that may approve each artifact. Complex changes approve system analysis at G2 (contract-first).
|
||||
const SA_IDS = ["system-analysis", ...SA_MODULES];
|
||||
const allowedGates = (id, complex, hasG2) => {
|
||||
if (id === "proposal") return ["G1"];
|
||||
if (id === "change-profile") return ["G1", "G2", "G3"]; // later profile changes need a recorded decision
|
||||
if (id === "specs") return hasG2 ? ["G2"] : ["G3"];
|
||||
if (SA_IDS.includes(id)) return complex ? ["G2"] : hasG2 ? ["G2", "G3"] : ["G3"];
|
||||
return ["G3"];
|
||||
};
|
||||
const NOT_APPROVED = new Set(["research", "process-record"]); // input context / the log itself
|
||||
const REF = /`([a-z0-9][a-z0-9/-]*)`\s*[—–-]\s*`([^`]+)`/g;
|
||||
|
||||
const fail = (msg) => { console.error(msg); process.exit(2); };
|
||||
const args = process.argv.slice(2);
|
||||
const [mode, changeName] = args;
|
||||
if (!["plan", "apply", "archive"].includes(mode) || !changeName) {
|
||||
fail("Usage: node check.cjs <plan|apply|archive> <change-name> [--root <openspec-root>]");
|
||||
}
|
||||
const rootIdx = args.indexOf("--root");
|
||||
if (rootIdx > 0 && !args[rootIdx + 1]) fail("--root needs a path");
|
||||
const root = path.resolve(rootIdx > 0 ? args[rootIdx + 1] : path.join(__dirname, "..", ".."));
|
||||
const changeDir = path.join(root, "changes", changeName);
|
||||
if (!fs.existsSync(changeDir)) fail(`Change directory not found: ${changeDir}`);
|
||||
|
||||
const errors = [];
|
||||
const warnings = [];
|
||||
const notes = [];
|
||||
const rel = (p) => path.relative(changeDir, p);
|
||||
const read = (p) => fs.readFileSync(p, "utf8");
|
||||
const at = (p) => path.join(changeDir, p);
|
||||
const walk = (dir) => fs.existsSync(dir)
|
||||
? fs.readdirSync(dir, { withFileTypes: true }).flatMap((e) =>
|
||||
e.isDirectory() ? walk(path.join(dir, e.name)) : [path.join(dir, e.name)])
|
||||
: [];
|
||||
const present = (p) => p === "test-cases" || p === "specs"
|
||||
? walk(at(p)).some((f) => f.endsWith(".md"))
|
||||
: fs.existsSync(at(p));
|
||||
const mdFiles = walk(changeDir).filter((f) => f.endsWith(".md"));
|
||||
const strip = (s) => (s ?? "").replace(/`/g, "").trim();
|
||||
// Columns: fixed count, the last cell keeps any `|` it contains.
|
||||
const tableRows = (text, heading, columns) => {
|
||||
const section = text.split(/^## /m).find((s) => s.startsWith(heading));
|
||||
if (!section) return null;
|
||||
return section.split("\n").filter((l) => /^\|/.test(l)).slice(2).map((l) => {
|
||||
const parts = l.replace(/^\|/, "").replace(/\|\s*$/, "").split("|");
|
||||
return [...parts.slice(0, columns - 1), parts.slice(columns - 1).join("|")].map((c) => c.trim());
|
||||
});
|
||||
};
|
||||
|
||||
finishIfMissing();
|
||||
const record = read(at("process-record.md"));
|
||||
|
||||
// 1. Unfilled templates.
|
||||
for (const f of mdFiles) {
|
||||
if (read(f).includes("<!-- guide:")) errors.push(`${rel(f)}: unfilled template guide comment remains`);
|
||||
}
|
||||
|
||||
// 2. Mode, class, Change Profile.
|
||||
const labMode = (record.match(/\*\*Mode:\*\*\s*(lab|delivery)\b/i) || [])[1]?.toLowerCase();
|
||||
if (!labMode) errors.push("process-record.md: **Mode:** must be `lab` or `delivery`");
|
||||
const klass = (record.match(/\*\*Class:\*\*\s*(standard|complex)\b/i) || [])[1]?.toLowerCase();
|
||||
if (!klass) errors.push("process-record.md: **Class:** must be `standard` or `complex`");
|
||||
const complex = klass === "complex";
|
||||
const hasG2 = labMode === "lab" || complex;
|
||||
|
||||
const profile = new Map();
|
||||
for (const [rawId, selected, reason] of tableRows(record, "Change Profile", 3) ?? []) {
|
||||
const id = strip(rawId);
|
||||
if (!CONDITIONAL.includes(id)) { errors.push(`Change Profile: unknown artifact '${id}'`); continue; }
|
||||
if (!/^(yes|no)$/i.test(strip(selected))) errors.push(`Change Profile: '${id}' Selected must be yes|no`);
|
||||
if (!reason) errors.push(`Change Profile: '${id}' needs a trigger or reason`);
|
||||
profile.set(id, /^yes$/i.test(strip(selected)));
|
||||
}
|
||||
const pending = [];
|
||||
for (const id of CONDITIONAL) {
|
||||
if (!profile.has(id)) { errors.push(`Change Profile: no decision for '${id}'`); continue; }
|
||||
const has = present(PRIMARY[id]);
|
||||
if (profile.get(id) && !has) {
|
||||
const consumer = DOWNSTREAM[id].find(present);
|
||||
if (consumer) errors.push(`'${id}' is selected but ${PRIMARY[id]} does not exist while ${consumer} was already written`);
|
||||
else pending.push(id);
|
||||
}
|
||||
if (!profile.get(id) && has) errors.push(`'${id}' is not selected but ${PRIMARY[id]} exists; select it through a gate decision or remove the file`);
|
||||
}
|
||||
for (const id of SA_MODULES) {
|
||||
if (profile.get(id) && !profile.get("system-analysis")) errors.push(`'${id}' requires system-analysis to be selected`);
|
||||
}
|
||||
if (fs.existsSync(at("system-analysis")) && !present(PRIMARY["system-analysis"])) {
|
||||
errors.push("system-analysis/ exists without system-analysis/system-analysis.md");
|
||||
}
|
||||
|
||||
// 3. Requirement references resolve; delta requirements are covered.
|
||||
const skipSpecs = present(".openspec.yaml") && /^skip_specs:\s*true/m.test(read(at(".openspec.yaml")));
|
||||
if (skipSpecs && present("specs")) errors.push("skip_specs: true but specs/ contains delta files");
|
||||
const deltaReqs = [];
|
||||
const known = new Map();
|
||||
const removed = new Set();
|
||||
const addKnown = (cap, h) => (known.get(cap) ?? known.set(cap, new Set()).get(cap)).add(h);
|
||||
const key = (cap, req) => `${cap}\u0000${req}`;
|
||||
for (const f of walk(at("specs")).filter((x) => x.endsWith("spec.md"))) {
|
||||
const cap = path.relative(at("specs"), path.dirname(f)).split(path.sep).join("/");
|
||||
let op = null;
|
||||
const seen = new Set();
|
||||
for (const line of read(f).split("\n")) {
|
||||
op = (line.match(/^## (ADDED|MODIFIED|REMOVED|RENAMED) Requirements/) || [])[1] ?? op;
|
||||
const req = (line.match(/^### Requirement:\s*(.+?)\s*$/) || [])[1];
|
||||
if (req) {
|
||||
if (seen.has(req)) errors.push(`specs/${cap}/spec.md: duplicate Requirement '${req}'`);
|
||||
seen.add(req);
|
||||
if (op === "REMOVED") removed.add(key(cap, req));
|
||||
else addKnown(cap, req);
|
||||
if (op === "ADDED" || op === "MODIFIED") deltaReqs.push(key(cap, req));
|
||||
}
|
||||
const to = (line.match(/^-?\s*TO:\s*`?###\s*Requirement:\s*(.+?)`?\s*$/) || [])[1];
|
||||
if (to) addKnown(cap, to);
|
||||
}
|
||||
}
|
||||
for (const f of walk(path.join(root, "specs")).filter((x) => x.endsWith("spec.md"))) {
|
||||
const cap = path.relative(path.join(root, "specs"), path.dirname(f)).split(path.sep).join("/");
|
||||
for (const m of read(f).matchAll(/^### Requirement:\s*(.+?)\s*$/gm)) {
|
||||
if (!removed.has(key(cap, m[1]))) addKnown(cap, m[1]);
|
||||
}
|
||||
}
|
||||
const refs = (text) => [...text.matchAll(REF)].map((m) => ({ cap: m[1], req: m[2] }));
|
||||
for (const f of mdFiles.filter((x) => !rel(x).startsWith(`specs${path.sep}`))) {
|
||||
for (const { cap, req } of refs(read(f))) {
|
||||
if (!known.get(cap)?.has(req)) errors.push(`${rel(f)}: unknown requirement reference \`${cap}\` — \`${req}\``);
|
||||
}
|
||||
}
|
||||
const tasksPath = at("tasks.md");
|
||||
const tasksText = fs.existsSync(tasksPath) ? read(tasksPath) : "";
|
||||
const coversLines = tasksText.split("\n").filter((l) => /\*\*Covers:\*\*/.test(l)).join("\n");
|
||||
const taskCover = new Set(refs(coversLines).map((r) => key(r.cap, r.req)));
|
||||
const qaText = [at("qa-analysis.md"), ...walk(at("test-cases"))].filter(fs.existsSync).map(read).join("\n");
|
||||
const qaCover = new Set(refs(qaText).map((r) => key(r.cap, r.req)));
|
||||
for (const k of deltaReqs) {
|
||||
const label = k.replace("\u0000", "` — `");
|
||||
if (tasksText && !taskCover.has(k)) errors.push(`tasks.md: delta requirement \`${label}\` has no task Covers`);
|
||||
if (present("qa-analysis.md") && !qaCover.has(k)) warnings.push(`qa-analysis: delta requirement \`${label}\` has no verification reference (allowed only with a stated risk reason)`);
|
||||
}
|
||||
if (!skipSpecs && present("specs") && deltaReqs.length === 0) warnings.push("no ADDED/MODIFIED requirements found in delta specs");
|
||||
|
||||
// 4. Test case identity and traceability.
|
||||
const tcIds = new Set();
|
||||
for (const f of walk(at("test-cases")).filter((x) => x.endsWith(".md"))) {
|
||||
for (const block of read(f).split(/^###\s+(?=TC-)/m).slice(1)) {
|
||||
const id = block.split(/\s/)[0];
|
||||
if (tcIds.has(id)) errors.push(`${rel(f)}: duplicate test case id ${id}`);
|
||||
tcIds.add(id);
|
||||
if (!refs(block).length) errors.push(`${rel(f)}: test case ${id} has no requirement reference`);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Contracts and diagrams are referenced, JSON parses, required task kinds exist.
|
||||
const saText = walk(at("system-analysis")).filter((f) => f.endsWith(".md")).map(read).join("\n");
|
||||
const contracts = walk(at("system-analysis/contracts"));
|
||||
for (const f of [...contracts, ...walk(at("system-analysis/diagrams"))]) {
|
||||
if (!saText.includes(path.basename(f))) errors.push(`${rel(f)}: not referenced from any system-analysis/*.md`);
|
||||
if (f.endsWith(".json")) {
|
||||
try { JSON.parse(read(f)); } catch (e) { errors.push(`${rel(f)}: invalid JSON (${e.message})`); }
|
||||
}
|
||||
}
|
||||
const taskLines = tasksText.split("\n").filter((l) => /^\s*[-*+]\s*\[.?\]/.test(l));
|
||||
if (tasksText) {
|
||||
if (!taskLines.some((l) => /Independent Review:/.test(l))) errors.push("tasks.md: no `Independent Review:` task");
|
||||
if (contracts.length && !taskLines.some((l) => /Contract Parity:/.test(l))) errors.push("tasks.md: contracts exist but no `Contract Parity:` task");
|
||||
if (profile.get("docs-impact") === false && !/^## Docs Impact/m.test(tasksText)) {
|
||||
errors.push("tasks.md: docs-impact not selected, so a `## Docs Impact` section (changes or no-change reason) is required");
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Gate Log: chronological; invalidating Gn withdraws Gn and every later gate.
|
||||
const gates = new Map();
|
||||
const order = [];
|
||||
for (const [rawGate, , scope, validation, , decision] of tableRows(record, "Gate Log", 6) ?? []) {
|
||||
const id = (strip(rawGate).match(/^G[1-4]\b/) || [])[0];
|
||||
if (!id) continue;
|
||||
if (/^invalidated\b/i.test(decision)) {
|
||||
for (const g of [...gates.keys()]) if (g >= id) gates.delete(g);
|
||||
continue;
|
||||
}
|
||||
if (!/^approved\b/i.test(decision)) continue;
|
||||
if (!/"[^"]+"|«[^»]+»/.test(decision)) errors.push(`Gate ${id}: approval must quote the Change Owner decision`);
|
||||
if (!validation) errors.push(`Gate ${id}: approval has no validation evidence`);
|
||||
const prior = ["G1", "G2", "G3", "G4"].filter((g) => g < id && (g !== "G2" || hasG2));
|
||||
if (prior.some((g) => !gates.has(g))) errors.push(`Gate ${id}: approved before ${prior.filter((g) => !gates.has(g)).join(", ")}`);
|
||||
const ids = strip(scope).split(/[,\s]+/).filter(Boolean);
|
||||
for (const a of ids) {
|
||||
if (id !== "G4" && !allowedGates(a, complex, hasG2).includes(id)) errors.push(`Gate ${id}: '${a}' must be approved at ${allowedGates(a, complex, hasG2).join(" or ")}`);
|
||||
}
|
||||
gates.set(id, ids);
|
||||
order.push(id);
|
||||
}
|
||||
if (gates.has("G1") && !gates.get("G1").includes("change-profile")) errors.push("Gate G1: scope must include change-profile");
|
||||
|
||||
// 7. Readiness.
|
||||
const artifactPaths = [
|
||||
["proposal", "proposal.md"], ["specs", "specs"], ["design", "design.md"],
|
||||
["qa-analysis", "qa-analysis.md"], ["tasks", "tasks.md"],
|
||||
...CONDITIONAL.map((id) => [id, PRIMARY[id]]),
|
||||
];
|
||||
const approvedScope = new Set([...gates.values()].flat());
|
||||
const required = hasG2 ? ["G1", "G2", "G3"] : ["G1", "G3"];
|
||||
const missingGates = required.filter((g) => !gates.has(g));
|
||||
const unapproved = artifactPaths.filter(([id, p]) => !NOT_APPROVED.has(id) && present(p) && !approvedScope.has(id)).map(([id]) => id);
|
||||
const blockers = [
|
||||
...(tasksText ? [] : ["tasks.md missing"]),
|
||||
...(missingGates.length ? [`missing gates: ${missingGates.join(", ")}`] : []),
|
||||
...(unapproved.length ? [`not in any approved gate scope: ${unapproved.join(", ")}`] : []),
|
||||
...(pending.length ? [`selected but missing: ${pending.join(", ")}`] : []),
|
||||
];
|
||||
notes.push(`apply-ready: ${blockers.length || errors.length ? `no (${[...blockers, ...(errors.length ? ["errors"] : [])].join("; ")})` : "yes"}`);
|
||||
if (mode !== "plan") blockers.forEach((b) => errors.push(`apply blocker: ${b}`));
|
||||
|
||||
const sequence = ["proposal", "process-record", "research", "specs", "ux-design", "system-analysis",
|
||||
...SA_MODULES, "security-analysis", "design", "qa-analysis", "test-cases", "docs-impact", "tasks"];
|
||||
const pathOf = Object.fromEntries([...artifactPaths, ["process-record", "process-record.md"]]);
|
||||
const next = sequence.find((id) => {
|
||||
if (CONDITIONAL.includes(id) && !profile.get(id)) return false;
|
||||
if (id === "specs" && skipSpecs) return false;
|
||||
return !present(pathOf[id]);
|
||||
});
|
||||
notes.push(`next artifact: ${next ?? "none (planning complete for this profile)"}`);
|
||||
|
||||
// 8. Archive readiness. Native archive treats any non-[x] marker as open, so descoped work is
|
||||
// removed from tasks.md by a gate decision and recorded in "Descoped Work".
|
||||
if (mode === "archive") {
|
||||
for (const l of taskLines) if (!/\[x\]/i.test(l)) errors.push(`tasks.md: open task: ${l.trim()}`);
|
||||
for (const [task, reason, gate] of tableRows(record, "Descoped Work", 3) ?? []) {
|
||||
if (task && (!reason || !/^G[1-4]$/.test(strip(gate)))) errors.push(`Descoped Work '${task}': needs reason and approving gate`);
|
||||
}
|
||||
if (!gates.has("G4")) errors.push("Gate G4 Delivery Acceptance is not approved");
|
||||
if (labMode === "lab") {
|
||||
const retro = record.split(/^## /m).find((s) => s.startsWith("Retrospective")) ?? "";
|
||||
if (!retro.replace(/^Retrospective.*\n/, "").trim()) errors.push("process-record.md: Retrospective is empty (lab mode)");
|
||||
if ((tableRows(record, "Lab Journal", 9) ?? []).length < gates.size) warnings.push("Lab Journal has fewer rows than approved gates");
|
||||
}
|
||||
}
|
||||
finish();
|
||||
|
||||
function finishIfMissing() {
|
||||
if (fs.existsSync(at("process-record.md"))) return;
|
||||
errors.push("process-record.md is missing: Change Profile and Gate Log are required");
|
||||
finish();
|
||||
}
|
||||
|
||||
function finish() {
|
||||
for (const n of notes) console.log(`note: ${n}`);
|
||||
for (const w of warnings) console.log(`warning: ${w}`);
|
||||
for (const e of errors) console.log(`error: ${e}`);
|
||||
console.log(errors.length ? `FAIL ${mode} ${changeName}: ${errors.length} error(s)` : `OK ${mode} ${changeName}`);
|
||||
process.exit(errors.length ? 1 : 0);
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
name: wealth-ledger-sdd-lab
|
||||
version: 1
|
||||
description: Experimental Engineering Lab workflow - proposal + change profile → specs → selected analysis modules → design ∥ qa-analysis → tasks → apply, with 4 decision gates
|
||||
|
||||
# CLI contract (OpenSpec 1.13.1): an artifact is complete when its `generates` path exists;
|
||||
# `requires` is a hard edge; there is no conditional artifact. Conditional artifacts below are
|
||||
# therefore never required by a mandatory artifact or by apply. Selection, ordering of selected
|
||||
# artifacts, gates and archive readiness are checked by `check.cjs` in this schema directory.
|
||||
|
||||
artifacts:
|
||||
- id: proposal
|
||||
generates: proposal.md
|
||||
description: Change Owner intent, scope, capabilities, evidence and open decisions
|
||||
template: proposal.md
|
||||
instruction: |
|
||||
Owner: Change Owner; draft — product-analyst. Gate: G1 Product Decision.
|
||||
|
||||
Purpose:
|
||||
Proposal фиксирует, зачем нужно изменение, какой результат ожидается, где
|
||||
проходит scope и какие решения ещё не приняты. Это не requirements, не system
|
||||
analysis и не design.
|
||||
|
||||
Start of the lab lifecycle (обязательно до записи):
|
||||
- Change создаётся явно: `openspec new change <name> --schema wealth-ledger-sdd-lab
|
||||
--store wealth-ledger-specs`. Schema не становится default и не применяется к
|
||||
существующим changes.
|
||||
- Small (локальный fix, известное behavior) не идёт в OpenSpec: правка canonical spec
|
||||
в том же Issue. Lab schema принимает только Standard и Complex.
|
||||
- Если существует research (`research.md` в change, Issue, внешний отчёт), прочитай
|
||||
его выводы; Proposal ссылается на research в **Evidence**, а не копирует его.
|
||||
Research может закончиться решением не делать change — тогда change не создаётся.
|
||||
- Общий протокол (Change Profile, gates, делегирование сабагентам, `check.cjs`) —
|
||||
instruction artifact `process-record`; он действует на каждой стадии.
|
||||
|
||||
Read First:
|
||||
- Релевантные canonical specs из `specs/openspec/specs/` и AS-IS pages `docs/`
|
||||
(`overview.md`, `architecture/`, `domains/`, `integrations/`, `adr/`, `design/`).
|
||||
- Code-level реализацию не исследуй глубже, чем нужно для scope/impact.
|
||||
|
||||
Critical Rules:
|
||||
- Один Proposal = одно связное намерение; независимо поставляемое разделяй.
|
||||
- Capabilities перечисляют каждую новую/изменяемую behavior spec точным path.
|
||||
Если observable behavior не меняется — `.openspec.yaml: skip_specs: true`.
|
||||
- Breaking observable behavior помечай **BREAKING**.
|
||||
- Evidence разделяет факты (с источником) и гипотезы.
|
||||
- Open Decisions: вопрос, кто решает, что блокирует. Вопрос, меняющий scope или
|
||||
capabilities, решается до G1.
|
||||
|
||||
MUST NOT Include:
|
||||
- files/classes/functions/tables/ORM entities; libraries/frameworks/transport;
|
||||
endpoint/payload/error-code contracts; diagrams; test plans; tasks/PR plan;
|
||||
пиксельные UI-детали.
|
||||
|
||||
Feedback Routing: research gap → research; всё остальное возвращается сюда.
|
||||
|
||||
Validation:
|
||||
- `openspec validate <change> --store wealth-ledger-specs` (Why/What Changes);
|
||||
structural success не является approval.
|
||||
- Затем создай `process-record.md` (Change Profile) и предъяви G1 оба файла вместе.
|
||||
requires: []
|
||||
|
||||
- id: research
|
||||
generates: research.md
|
||||
description: Optional product research used as input context; never approved as a requirement source
|
||||
template: research.md
|
||||
instruction: |
|
||||
Owner: product-researcher. Conditional: создавай только если Change Profile выбрал
|
||||
`research`. Не требуется ни одним artifact и не блокирует apply. Не входит в gates:
|
||||
это входной контекст, не утверждаемый artifact.
|
||||
|
||||
Trigger: новый продуктовый функционал, незнакомая предметная область, конкуренты и
|
||||
альтернативы, проверка гипотезы, высокая продуктовая неопределённость.
|
||||
Если исследование уже существует вне change (Issue, `audit-results/`, отчёт),
|
||||
не копируй его: Proposal ссылается на источник, Change Profile ставит `no` + ссылку.
|
||||
Исследование, начатое до решения о change, живёт вне OpenSpec до G1.
|
||||
|
||||
Critical Rules:
|
||||
- Каждое утверждение: [F] факт с источником, [I] интерпретация или [H] гипотеза.
|
||||
- Не выдумывай источники, цифры и пользователей; нет данных — так и напиши.
|
||||
- Recommendation допускает «не делать» и «сузить scope».
|
||||
|
||||
MUST NOT Include: окончательные requirements, обязательные архитектурные решения,
|
||||
contracts, tasks.
|
||||
|
||||
Feedback Routing: выводы потребляет Proposal (Evidence, Scope, Open Decisions).
|
||||
requires: []
|
||||
|
||||
- id: process-record
|
||||
generates: process-record.md
|
||||
description: Change Profile, gate decisions, descoped work and lab journal for the change
|
||||
template: process-record.md
|
||||
instruction: |
|
||||
Owner: основной агент (оркестратор). Change Profile утверждает Change Owner на G1.
|
||||
Это журнал процесса, а не planning authority: он не содержит requirements,
|
||||
contracts или design.
|
||||
|
||||
## Общий протокол lab schema (действует на каждой стадии)
|
||||
|
||||
Modes and Classes:
|
||||
- **Mode** `lab` — целенаправленная практика: G2 обязателен, независимая проверка
|
||||
на каждом gate, Lab Journal после каждой стадии, Retrospective перед archive,
|
||||
условные artifacts можно выбирать ради названной практики.
|
||||
- **Mode** `delivery` — минимально достаточный процесс: artifacts только по
|
||||
risk-триггеру, qa-analysis компактный, Lab Journal необязателен.
|
||||
- **Class** `standard` | `complex`. Complex: межсистемно, деньги/синхронизация/
|
||||
данные, необратимые миграции или высокая неопределённость. Mode и Class
|
||||
независимы.
|
||||
|
||||
Change Profile (обязательная таблица, все 10 строк):
|
||||
- `yes` только при конкретном trigger из instruction artifact; в lab допустим
|
||||
`yes` с названной практикой («lab: data mapping practice»).
|
||||
- `no` с конкретной причиной. Пустой документ с «N/A» вместо `no` запрещён.
|
||||
- Profile меняется только решением Change Owner, записанным строкой Gate Log
|
||||
со scope `change-profile`; уже утверждённые gates при этом инвалидируются.
|
||||
- Выбранный условный input пишется до artifact, который его потребляет
|
||||
(research, ux-design, system-analysis и modules, security-analysis — до design,
|
||||
qa-analysis и tasks; test-cases, docs-impact — до tasks).
|
||||
|
||||
Deterministic checks — `check.cjs` (из `specs/`):
|
||||
`node openspec/schemas/wealth-ledger-sdd-lab/check.cjs <plan|apply|archive> <change>`.
|
||||
Он единственный владелец правил profile/порядка/gates/readiness; не дублируй их
|
||||
проверку вручную, а читай его вывод. `plan` — после каждого artifact; `apply` —
|
||||
перед apply; `archive` — перед native archive. Exit 1 = нарушение artifact,
|
||||
exit 2 = ошибка вызова/окружения (не исправляй artifact из-за неё).
|
||||
|
||||
Next artifact:
|
||||
- `openspec status` показывает невыбранные условные artifacts как `ready`, а
|
||||
`isPlanningComplete` остаётся `false`, пока они не созданы. Это ограничение CLI:
|
||||
не создавай artifact только потому, что он `ready`.
|
||||
- Следующий artifact = `note: next artifact` из `check.cjs plan`.
|
||||
|
||||
Decision Gates (Gate Log, append-only):
|
||||
| Gate | Scope | Когда |
|
||||
| --- | --- | --- |
|
||||
| G1 Product Decision | proposal, change-profile | всегда |
|
||||
| G2 Requirements Baseline | specs (+ system-analysis и модули для complex) | lab или complex |
|
||||
| G3 Solution Approval | всё остальное planning, включая tasks | всегда |
|
||||
| G4 Delivery Acceptance | implementation, review, QA, parity, docs | перед archive |
|
||||
- Без G2 (delivery standard) specs входят в scope G3.
|
||||
- Complex: system-analysis и выбранные модули входят в G2, чтобы системные
|
||||
обязательства были согласованы до design (contract-first).
|
||||
- Решение gate явно разрешает draft следующего пакета artifacts. Approval
|
||||
перечисляет каждый artifact id в Scope и дословно цитирует слова Change Owner
|
||||
из текущей сессии или комментария Issue (укажи ссылку). Никогда не записывай
|
||||
решение, которого владелец не давал; существование файла или строки Gate Log
|
||||
не является approval — `check.cjs` проверяет только форму записи.
|
||||
- Каждый gate различает: Artifact Validation (CLI + `check.cjs`), Independent
|
||||
Review (findings) и Decision Approval (владелец). Validation и Findings
|
||||
заполняются до запроса решения.
|
||||
- Семантическое изменение утверждённого artifact: строка `invalidated: <reason>`
|
||||
для gate, покрывающего самый ранний затронутый artifact (это снимает и все
|
||||
последующие gates), затем повторное approval по порядку. Механические правки
|
||||
(опечатка, формат) не инвалидируют.
|
||||
- Release Approval находится вне OpenSpec (release-it, Gitea); G4 его не заменяет.
|
||||
|
||||
Independent Review (lab — на каждом gate; delivery — минимум G4):
|
||||
- G1: product-analyst проверяет проблему/scope на противоречия и скрытые решения.
|
||||
- G2: qa-engineer — testability; independent-reviewer — противоречия с canonical
|
||||
specs и пропущенные error/boundary cases.
|
||||
- G3: independent-reviewer — согласованность specs ↔ system-analysis ↔ design ↔
|
||||
qa-analysis ↔ tasks; security-reviewer, если выбран security-analysis.
|
||||
- G4: independent-reviewer — код против approved artifacts; qa-engineer — system
|
||||
verification по qa-analysis.
|
||||
- Reviewer не исправляет artifact; findings маршрутизируются по Feedback Routing.
|
||||
|
||||
Delegation to subagents:
|
||||
- Сабагент — самостоятельный профессионал: не знает OpenSpec, gates и других
|
||||
сабагентов. Основной агент выбирает роль, пишет Task Brief, получает результат,
|
||||
размещает его в artifact, проверяет согласованность и выносит вопросы человеку.
|
||||
- Task Brief: профессиональная цель («спроектируй межсистемные взаимодействия
|
||||
для …», не «создай artifact system-analysis»); точные входные файлы/разделы;
|
||||
ограничения из MUST NOT Include artifact, сформулированные профессионально;
|
||||
ожидаемые разделы ответа; правило «неизвестное — вернуть вопросом, не
|
||||
выдумывать».
|
||||
- Сабагент не принимает решений за другие роли; конфликт с upstream возвращается
|
||||
как finding.
|
||||
|
||||
Lab Journal (lab): строка после каждой стадии — уникальные находки (что нашла
|
||||
только эта стадия), решения, риски, проблемы передачи контекста, skills, стоимость
|
||||
(вызовы, токены/время), что переносимо на крупные проекты. Не пиши ожидаемые
|
||||
результаты заранее.
|
||||
requires:
|
||||
- proposal
|
||||
|
||||
- id: specs
|
||||
generates: "specs/**/*.md"
|
||||
description: Normative black-box behavioral deltas, business rules and invariants
|
||||
template: spec.md
|
||||
instruction: |
|
||||
Owner: product-analyst (requirements engineering). Gate: G2 (lab/complex) или G3.
|
||||
Reviewers: qa-engineer (testability), independent-reviewer (consistency).
|
||||
|
||||
Purpose:
|
||||
Delta Specs — нормативный black-box contract: что система обязана делать для
|
||||
пользователя или внешнего наблюдателя. После archive становятся canonical specs.
|
||||
|
||||
Preconditions:
|
||||
- G1 approved; используются только capabilities из Proposal.
|
||||
- Для existing capability прочитай canonical spec целиком.
|
||||
- `skip_specs: true` — spec files не создаются.
|
||||
|
||||
Critical Rules:
|
||||
- Один Requirement = одно устойчивое observable behavior/invariant.
|
||||
- BCP 14 по policy `config.yaml`: uppercase SHALL/MUST только для обязательств.
|
||||
- Каждый Requirement имеет ≥1 `#### Scenario:` с конкретными WHEN/THEN.
|
||||
- Бизнес-правила, инварианты (например, сохранение суммы, однократный учёт денег,
|
||||
знак и точка округления) и граничные случаи — явные Requirements/Scenarios.
|
||||
- Допущение не оформляется как факт: неизвестное правило → вопрос в Proposal
|
||||
Open Decisions, а не выдуманный Requirement.
|
||||
- Не дели Requirements по repositories; system names/transport/endpoints —
|
||||
System Analysis, если сама их identity не является внешним обязательством.
|
||||
|
||||
Delta Operations:
|
||||
- `ADDED`; `MODIFIED` — ПОЛНЫЙ existing block со всеми scenarios, heading точно;
|
||||
`REMOVED` — **Reason** и **Migration**; `RENAMED` — `FROM:`/`TO:`.
|
||||
- Новая capability: `## Purpose` 1–2 предложения (≥50 символов).
|
||||
- Не оставляй пустые operation sections.
|
||||
|
||||
Reference Format (используется всеми downstream artifacts и `check.cjs`):
|
||||
`` `capability-path` — `Requirement heading` `` — точный heading.
|
||||
|
||||
MUST NOT Include: implementation details, поведение вне Proposal, «корректно»/
|
||||
«быстро»/«удобно» без критерия, противоречия canonical specs.
|
||||
|
||||
Feedback Routing: intent/scope/capabilities → Proposal; systems/contracts/
|
||||
mappings → позже System Analysis; interaction details → UX Design.
|
||||
|
||||
Validation: `openspec validate <change> --strict --store wealth-ledger-specs`.
|
||||
requires:
|
||||
- process-record
|
||||
|
||||
- id: ux-design
|
||||
generates: ux-design.md
|
||||
description: Optional interaction design of approved behavior; part of the Design package
|
||||
template: ux-design.md
|
||||
instruction: |
|
||||
Owner: ux-designer. Conditional: только если Change Profile выбрал `ux-design`.
|
||||
Gate: G3 вместе с design (единый Design package, отдельного UX approval нет).
|
||||
|
||||
Trigger: новые экраны, существенное изменение пользовательского сценария,
|
||||
редизайн, сложные формы, многосостоянийный интерфейс. Иначе UI описывается в
|
||||
разделе UI Implementation `design.md` (reuse или N/A с причиной).
|
||||
|
||||
Authority:
|
||||
- ux-design.md — UX-часть единого Design package (не отдельный planning
|
||||
authority и не отдельный approval): внутри пакета он один владеет flows, IA,
|
||||
состояниями, feedback, responsive и a11y. design.md ссылается на него и
|
||||
фиксирует только инженерную реализацию UI.
|
||||
- Observable behavior остаётся в Specs; UX не вводит новое behavior. Состояние или
|
||||
ошибка, которых нет в Specs, — finding → Specs.
|
||||
|
||||
Critical Rules:
|
||||
- Ссылайся на Requirements, не пересказывай их.
|
||||
- UI States покрывает loading/empty/error/success/partial только там, где они
|
||||
реально возможны.
|
||||
- Visual materials следуют правилу Visual Package из instruction `design`.
|
||||
- Используй существующую design system (`docs/design/`, `frontend` UI kit) прежде
|
||||
нового паттерна; отклонение обоснуй.
|
||||
|
||||
MUST NOT Include: серверная архитектура, contracts, component tree, state
|
||||
management, data fetching.
|
||||
|
||||
Feedback Routing: behavior → Specs; реализуемость → Design; данные/ошибки
|
||||
интеграции → System Analysis.
|
||||
requires:
|
||||
- specs
|
||||
|
||||
- id: system-analysis
|
||||
generates: system-analysis/system-analysis.md
|
||||
description: Optional hub of cross-system context, boundaries, flows, data ownership and contracts
|
||||
template: system-analysis.md
|
||||
instruction: |
|
||||
Owner: system-analyst. Conditional: только если Change Profile выбрал
|
||||
`system-analysis`. Gate: G2 для complex, иначе G3.
|
||||
|
||||
Trigger: новый/изменённый межсистемный contract (HTTP API, внешняя интеграция,
|
||||
event), изменение data ownership, несколько систем в одном flow, сложная
|
||||
миграция/coexistence. Изменение внутри одного repo без contract — не trigger.
|
||||
|
||||
Structure (hub + modules; каждый module — отдельный выбор Change Profile):
|
||||
- `system-analysis/system-analysis.md` — context, boundaries, As-Is/To-Be, impact,
|
||||
responsibilities, data ownership, flows overview, contract semantics, error
|
||||
semantics на границах, compatibility, ссылки на modules.
|
||||
- `system-analysis/contracts/` — machine-readable target contracts
|
||||
(OpenAPI/AsyncAPI/JSON Schema/Proto). Не отдельный artifact: принадлежит hub.
|
||||
- `system-analysis/diagrams/*.mmd` — Mermaid sequence/state/data-flow, только
|
||||
если помогают понять поведение. Каждый файл упоминается в hub или module.
|
||||
- Modules: `data-mapping.md`, `failure-model.md`, `nfr.md`, `observability.md`.
|
||||
- Расширения (audit, fraud, feature toggles, CMS, внешние системы) добавляются
|
||||
новым module только при реальном requirement; schema их не предопределяет.
|
||||
|
||||
Contract Authority (сохранено из v2):
|
||||
- Новый/изменённый contract определяется в `contracts/` до implementation.
|
||||
- Backend-generated OpenAPI остаётся executable/runtime source после реализации
|
||||
и MUST быть semantic-compatible с approved target contract до G4.
|
||||
- Не создавай второй вечный canonical OpenAPI в `specs/`; target contract остаётся
|
||||
в archived change. Mismatch generated ↔ target возвращает change сюда.
|
||||
- Для existing HTTP API прочитай текущий backend-generated OpenAPI
|
||||
(`frontend/src/shared/api/spec/openapi.json` — опубликованный snapshot).
|
||||
- Каждый contract помечает compatibility: additive | breaking (+ migration).
|
||||
|
||||
Critical Rules:
|
||||
- Не вводи observable behavior молча: gap → Specs и повторный G2/G3.
|
||||
- Hub не копирует содержимое modules; module не копирует hub.
|
||||
- Нет internal classes/modules/DB tables/developer tests.
|
||||
|
||||
Feedback Routing: behavior → Specs; internal implementation → Design;
|
||||
verification → QA Analysis.
|
||||
requires:
|
||||
- specs
|
||||
|
||||
- id: data-mapping
|
||||
generates: system-analysis/data-mapping.md
|
||||
description: Optional field-level mapping, transformations and conservation invariants between systems
|
||||
template: data-mapping.md
|
||||
instruction: |
|
||||
Owner: system-analyst; reviewer — database-specialist при изменении хранения.
|
||||
Conditional: только если выбран `data-mapping` (требует `system-analysis`).
|
||||
|
||||
Trigger: преобразование данных между системами или моделями (внешний API →
|
||||
domain, domain → API, агрегаты), денежные суммы, валюты, знаки, агрегаты,
|
||||
классификация записей по группам.
|
||||
|
||||
Critical Rules:
|
||||
- Каждое target-поле: source, transformation, unit/currency/scale, nullability,
|
||||
default, validation, поведение при ошибке.
|
||||
- Invariants: правила сохранения (сумма частей = итог, каждая денежная единица
|
||||
учитывается ровно в одном агрегате), знаковые соглашения, точка округления —
|
||||
со ссылкой на защищаемый Requirement. Нет Requirement — finding → Specs.
|
||||
- Double-counting: каждый тип исходной записи, который может попасть в два
|
||||
агрегата, и правило, относящее его ровно к одному.
|
||||
- Большой mapping — machine-checkable файл в `contracts/` со ссылкой отсюда.
|
||||
|
||||
MUST NOT Include: ORM/SQL/код mappers, retry/idempotency (failure-model).
|
||||
|
||||
Feedback Routing: инвариант без Requirement → Specs; ownership → hub;
|
||||
реализация → Design.
|
||||
requires:
|
||||
- system-analysis
|
||||
|
||||
- id: failure-model
|
||||
generates: system-analysis/failure-model.md
|
||||
description: Optional boundary failure semantics - timeouts, retries, idempotency, partial failure and recovery
|
||||
template: failure-model.md
|
||||
instruction: |
|
||||
Owner: system-analyst; reviewer — reliability-specialist.
|
||||
Conditional: только если выбран `failure-model` (требует `system-analysis`).
|
||||
|
||||
Trigger: внешняя интеграция, фоновая синхронизация, повторяемые операции,
|
||||
многошаговая запись, возможны дубликаты/out-of-order/частичный отказ.
|
||||
|
||||
Critical Rules:
|
||||
- Каждый failure scenario: граница, отказ, обнаружение, требуемое поведение
|
||||
системы, observable результат, Requirement.
|
||||
- Idempotency: ключ, scope, срок хранения, результат повторного запроса/события.
|
||||
- Partial failure: что остаётся согласованным, compensation или recovery.
|
||||
- Обязательства формулируются на границе систем; механизм (lock, queue,
|
||||
transaction) — Design.
|
||||
|
||||
MUST NOT Include: численные SLO (nfr), выбор библиотек, код.
|
||||
|
||||
Feedback Routing: новое user-visible поведение при отказе → Specs; механизм →
|
||||
Design; проверка → QA Analysis.
|
||||
requires:
|
||||
- system-analysis
|
||||
|
||||
- id: nfr
|
||||
generates: system-analysis/nfr.md
|
||||
description: Optional measurable non-functional requirements with thresholds and evidence
|
||||
template: nfr.md
|
||||
instruction: |
|
||||
Owner: system-analyst; reviewer — reliability-specialist.
|
||||
Conditional: только если выбран `nfr` (требует `system-analysis`).
|
||||
|
||||
Trigger: значимые performance/availability/capacity/retention/security
|
||||
constraints, которые меняют design или verification.
|
||||
|
||||
Critical Rules:
|
||||
- Каждый NFR: id, threshold, способ измерения, rationale/источник.
|
||||
- Без threshold — раздел Constraints Without Thresholds с владельцем решения;
|
||||
не выдумывай числа.
|
||||
- Security-NFR живут здесь; security-analysis ссылается на них по id.
|
||||
|
||||
MUST NOT Include: механизмы достижения (Design), failure semantics
|
||||
(failure-model), события наблюдаемости (observability).
|
||||
requires:
|
||||
- system-analysis
|
||||
|
||||
- id: observability
|
||||
generates: system-analysis/observability.md
|
||||
description: Optional semantic observability obligations - events, signals, correlation, SLI and alerts
|
||||
template: observability.md
|
||||
instruction: |
|
||||
Owner: system-analyst; reviewer — reliability-specialist.
|
||||
Conditional: только если выбран `observability` (требует `system-analysis`).
|
||||
|
||||
Trigger: фоновые/асинхронные процессы, финансовые расчёты или синхронизация,
|
||||
где оператор должен отличать успех, частичный успех и отказ; новые SLI.
|
||||
|
||||
Critical Rules:
|
||||
- Semantic events с trigger и обязательными атрибутами (например,
|
||||
`code=1 → NO_MONEY`); correlation через границы систем.
|
||||
- Diagnostic scenarios: «когда X, оператор определяет Y по Z».
|
||||
- SLI/alerts — только с определением и целевым значением; цель из nfr — ссылкой.
|
||||
|
||||
MUST NOT Include: SDK/exporter/logger/инфраструктура (Design), секреты и
|
||||
персональные данные в атрибутах.
|
||||
requires:
|
||||
- system-analysis
|
||||
|
||||
- id: security-analysis
|
||||
generates: security-analysis.md
|
||||
description: Optional change-scoped threat model with mitigations and residual risks
|
||||
template: security-analysis.md
|
||||
instruction: |
|
||||
Owner: security-reviewer. Conditional: только если выбран `security-analysis`.
|
||||
Gate: G3; validation requirements проверяются на G4.
|
||||
|
||||
Trigger: authentication/authorization, токены и секреты, новая trust boundary,
|
||||
sensitive/financial personal data, внешняя интеграция, изменение модели доступа.
|
||||
Не создавай для изменений без этих признаков.
|
||||
|
||||
Inputs: Specs; system-analysis (hub, nfr) если выбран; существующие ADR и
|
||||
`docs/architecture/cross-cutting/`.
|
||||
|
||||
Critical Rules:
|
||||
- Threat model только этого change (STRIDE как способ поиска, не как чек-лист).
|
||||
- Каждая mitigation назначена artifact-владельцу: observable требование → Specs,
|
||||
межсистемное обязательство → System Analysis, механизм → Design.
|
||||
- Security-NFR не дублируй: ссылайся на id из `nfr.md`.
|
||||
- Residual risks явно принимает Change Owner на G3.
|
||||
|
||||
MUST NOT Include: универсальный security checklist, эксплуатация внешних систем,
|
||||
секреты.
|
||||
requires:
|
||||
- specs
|
||||
|
||||
- id: design
|
||||
generates: design.md
|
||||
description: Engineering design of how affected repositories implement approved behavior and system obligations
|
||||
template: design.md
|
||||
instruction: |
|
||||
Owner: solution-architect; reviewers — affected frontend/backend engineers,
|
||||
database-specialist при миграциях. Gate: G3.
|
||||
|
||||
Purpose:
|
||||
Как affected repositories реализуют свою сторону approved Specs и выбранных
|
||||
system-analysis/ux-design/security-analysis. Не повторный system analysis.
|
||||
|
||||
Preconditions:
|
||||
- Все выбранные research, ux-design, system-analysis и modules,
|
||||
security-analysis уже существуют (`check.cjs plan` без errors). Complex:
|
||||
system-analysis утверждён на G2.
|
||||
- Upstream contracts/sequences/mappings — входные ограничения.
|
||||
|
||||
Critical Rules:
|
||||
- Не добавляй observable behavior; не меняй system contracts. Нереализуемый
|
||||
contract → System Analysis, а не private contract здесь.
|
||||
- Каждое существенное решение ссылается на driver: Requirement, NFR id, failure
|
||||
id, threat id или constraint. Новая технология/компонент без driver запрещены.
|
||||
- UI: при ux-design.md — только инженерная реализация (composition, state, data
|
||||
fetching, производство каждого UI state); без ux-design.md — раздел UI
|
||||
Implementation даёт new/changed/reuse/N/A с причиной и нужные экраны/состояния.
|
||||
Неизменяемый UI и N/A не требуют макетов.
|
||||
- Visual Package (единые правила для ux-design.md и UI Implementation): версия
|
||||
пакета; для reuse — immutable locator (store ID + path от OpenSpec root),
|
||||
применимая часть и отличия; локальные PNG/SVG под `visuals/` с relative path,
|
||||
purpose и SHA-256; SVG самодостаточен (без scripts, handlers, внешних
|
||||
fonts/assets); mutable внешняя ссылка не является утверждённой версией.
|
||||
ux-design.md и design.md — один Design package с одним approval на G3.
|
||||
- Solution Assessment обязателен для нового auth, security, storage, external
|
||||
integration, observability, caching, concurrency, shared tooling или иного
|
||||
дорогого необратимого решения; иначе N/A + reason.
|
||||
- Rollback contract обязателен для security, destructive migration, public
|
||||
contract и труднообратимых решений.
|
||||
- Developer verification определяют implementation owners; QA matrix не копируй.
|
||||
- ADR Candidates: только долгоживущие архитектурные решения с alternatives.
|
||||
|
||||
MUST NOT Include: approved sequences/contracts/mappings (ссылки, не копии);
|
||||
UX flows/states при наличии ux-design.md; QA coverage; docs plan; tasks/PR plan;
|
||||
длинный production code.
|
||||
|
||||
Feedback Routing: intent → Proposal; behavior → Specs; interaction → UX Design;
|
||||
contracts/mappings/failure semantics/semantic observability → System Analysis;
|
||||
threats → Security Analysis.
|
||||
requires:
|
||||
- specs
|
||||
|
||||
- id: qa-analysis
|
||||
generates: qa-analysis.md
|
||||
description: Risk-based system verification strategy independent from developer-owned tests
|
||||
template: qa-analysis.md
|
||||
instruction: |
|
||||
Owner: qa-engineer. Gate: G3. Может выполняться параллельно с design.
|
||||
|
||||
Purpose:
|
||||
Что нужно проверить на уровне системы, чтобы доказать соответствие Specs и
|
||||
выбранным system-analysis modules, и с какой глубиной — по риску.
|
||||
|
||||
Depth (условные секции внутри обязательного artifact):
|
||||
- Всегда: Risk Assessment, Coverage Matrix (строка на каждый delta Requirement),
|
||||
Gaps / Blockers.
|
||||
- Delivery standard: остальные разделы только при наличии содержания; удаляй
|
||||
пустые разделы, не пиши N/A.
|
||||
- Lab или complex: все разделы; Cross-system Verification обязателен при
|
||||
выбранном system-analysis, failure-model или data-mapping (каждый failure id
|
||||
и invariant имеет проверку или обоснованный risk-based отказ).
|
||||
|
||||
Critical Rules:
|
||||
- QA проверяет system behavior, не устройство кода; не предписывай unit/component
|
||||
tests, mocks, coverage percentage.
|
||||
- Не создавай behavior: неопределённый expected result → gap в Specs;
|
||||
неопределённый flow/error/contract → gap в System Analysis.
|
||||
- Ссылайся на Scenarios, не переписывай их. Отдельные test cases — только через
|
||||
artifact `test-cases`.
|
||||
- Планы проверок отделены от результатов: результаты фиксируются на G4, не здесь.
|
||||
- Automation: black-box API/E2E кандидаты; QA repo пока нет — `deferred until QA
|
||||
repo exists`.
|
||||
|
||||
Feedback Routing: behavior → Specs; contracts/failures → System Analysis;
|
||||
testability hooks → Design (как need, без проектирования).
|
||||
requires:
|
||||
- specs
|
||||
|
||||
- id: test-cases
|
||||
generates: "test-cases/*.md"
|
||||
description: Optional explicit test design for high-risk scenarios that need concrete data, steps or oracles
|
||||
template: test-cases.md
|
||||
instruction: |
|
||||
Owner: qa-engineer. Conditional: только если выбран `test-cases`. Gate: G3.
|
||||
|
||||
Trigger: финансовые расчёты, сложные бизнес-сценарии, значимые интеграции,
|
||||
много ошибок и граничных случаев, критичное пользовательское поведение — когда
|
||||
проверка требует конкретных данных, шагов или oracle, которых нет в Scenario.
|
||||
|
||||
Critical Rules:
|
||||
- Один файл на область: `test-cases/<area>.md`; id `TC-<AREA>-<NNN>` уникален.
|
||||
- Каждый case: Verifies (reference format), Risk/Priority, Preconditions, Test
|
||||
Data, Steps, Expected Results, Automation Candidate.
|
||||
- Case добавляет информацию сверх Scenario (числа, комбинации, порядок событий,
|
||||
расчётный oracle). Если не добавляет — не пиши case; coverage matrix ссылается
|
||||
на Scenario.
|
||||
- Не копируй acceptance criteria дословно; expected result выводится из
|
||||
Requirement, а не придумывается. Неопределённость → gap в Specs.
|
||||
- qa-analysis Coverage Matrix ссылается на TC ids.
|
||||
requires:
|
||||
- qa-analysis
|
||||
|
||||
- id: docs-impact
|
||||
generates: docs-impact.md
|
||||
description: Optional promotion plan from change knowledge to canonical AS-IS documentation
|
||||
template: docs-impact.md
|
||||
instruction: |
|
||||
Owner: documentation-engineer. Conditional: только если выбран `docs-impact`.
|
||||
Gate: G3.
|
||||
|
||||
Trigger: несколько docs targets, новый ADR, перенос diagrams, изменение
|
||||
architecture/integration pages, lab-практика Documentation Impact Analysis.
|
||||
Иначе — раздел `## Docs Impact` в tasks.md (targets или конкретная no-change
|
||||
причина).
|
||||
|
||||
Canonical Documentation Model: `docs/` — AS-IS (`overview.md`, `glossary.md`,
|
||||
`architecture/`, `architecture/cross-cutting/`, `domains/`, `integrations/`,
|
||||
`adr/`, `design/`). Accepted ADR не переписывается.
|
||||
|
||||
Critical Rules:
|
||||
- Promote только знание, полезное после завершения change; без migration diary.
|
||||
- Не копируй machine-readable contract в docs как второй source of truth.
|
||||
- Каждая entry: Action, exact Target (существующий path проверен), Category,
|
||||
Resulting AS-IS, Source, Verification.
|
||||
- Diagram promotion по умолчанию — нет.
|
||||
- docs-impact не редактирует `docs/`; Tasks создаёт `[docs]` items.
|
||||
requires:
|
||||
- design
|
||||
|
||||
- id: tasks
|
||||
generates: tasks.md
|
||||
description: Dependency-ordered, repository-owned delivery checklist with verification, review and parity tasks
|
||||
template: tasks.md
|
||||
instruction: |
|
||||
Owner: основной агент (delivery coordination); reviewers — affected engineers.
|
||||
Gate: G3.
|
||||
|
||||
Preconditions:
|
||||
- design и qa-analysis существуют; все выбранные условные artifacts существуют
|
||||
(`check.cjs plan` без errors).
|
||||
- Для complex/lab: G2 approved до записи tasks.
|
||||
|
||||
Task Format:
|
||||
`- [ ] X.Y [main|frontend|backend|docs|specs] <Kind>: <action + outcome>`
|
||||
с полями **Covers**, **Source**, **Verification**, **Depends on**.
|
||||
Kinds: Implementation, Migration, Automated Testing, Contract Parity, Docs,
|
||||
Independent Review, QA Verification, Verification.
|
||||
|
||||
Required Tasks (только релевантные; `check.cjs` проверяет отмеченные *):
|
||||
- Implementation/Automated Testing per repository по Design.
|
||||
- Migration: при изменении хранения — backup/rollback и проверка на копии данных.
|
||||
- * Contract Parity: при наличии `system-analysis/contracts/` — сравнение
|
||||
backend-generated OpenAPI/runtime с target contract.
|
||||
- Docs: из docs-impact или раздела `## Docs Impact`.
|
||||
- * Independent Review: read-only review реализации против approved artifacts.
|
||||
- QA Verification: system checks по qa-analysis (и test-cases).
|
||||
- Security: проверки из security-analysis Validation Requirements, если выбран.
|
||||
- Native sync/archive не является task; canonical specs не правятся task'ом.
|
||||
|
||||
Critical Rules:
|
||||
- Одна task = один repository + один independently reviewable outcome.
|
||||
- * Каждый ADDED/MODIFIED Requirement появляется в Covers хотя бы одной task.
|
||||
- Covers использует reference format; неизвестный heading — ошибка `check.cjs`.
|
||||
- `[qa]` запрещён, пока QA repo не существует.
|
||||
- Не создавай ceremonial tasks; нерелевантная Kind не нужна.
|
||||
- Descope после G3: удали task из tasks.md и запиши в process-record
|
||||
`Descoped Work` с причиной и gate решения владельца.
|
||||
|
||||
MUST NOT Include: новое behavior/contract/design/QA/docs decision (→ upstream
|
||||
artifact), commits/branches, будущие результаты.
|
||||
|
||||
Feedback Routing: semantic change → самый ранний затронутый artifact,
|
||||
инвалидируя его gate и последующие.
|
||||
requires:
|
||||
- design
|
||||
- qa-analysis
|
||||
|
||||
apply:
|
||||
requires:
|
||||
- tasks
|
||||
tracks: tasks.md
|
||||
instruction: |
|
||||
Apply реализует approved plan и не переоткрывает upstream decisions без feedback cycle.
|
||||
|
||||
Preconditions (CLI проверяет только наличие tasks.md, остальное — `check.cjs`):
|
||||
- `check.cjs apply <change>` = OK (G1, G2 для lab/complex, G3; каждый
|
||||
существующий artifact утверждён на своём gate; выбранные artifacts существуют).
|
||||
- Перед зависимой UI-работой проверь наличие и SHA-256 материалов из таблицы
|
||||
Materials (ux-design.md или UI Implementation design.md).
|
||||
- Store `wealth-ledger-specs`; protocol — instruction `process-record`.
|
||||
|
||||
Context Loading: `contextFiles` из apply instructions, затем `AGENTS.md` только
|
||||
affected repositories, затем relevant upstream sections для каждой task.
|
||||
|
||||
Execution:
|
||||
- Pending tasks по dependency order; один repository на task; delegate по роли
|
||||
(frontend-engineer, backend-engineer, database-specialist) с Task Brief.
|
||||
- Checkbox отмечается только после observed success Verification.
|
||||
- Contract Parity: backend-generated OpenAPI semantic-compatible с target contract.
|
||||
- Independent Review выполняет independent-reviewer (read-only) по полному diff
|
||||
против approved artifacts; Major findings исправляются или возвращаются в gate.
|
||||
- QA Verification выполняет qa-engineer по qa-analysis; результаты — в Gate Log G4.
|
||||
- Lab: строка Lab Journal после implementation, review и QA.
|
||||
|
||||
Before archive (G4 Delivery Acceptance):
|
||||
- Все tasks `[x]`; descoped — только через `Descoped Work`.
|
||||
- Validation G4: developer checks, parity, review verdict, QA results, docs.
|
||||
- Lab: Retrospective заполнен.
|
||||
- `check.cjs archive <change>` = OK (включает все apply-проверки), затем `openspec archive <change>
|
||||
--store wealth-ledger-specs`. Никогда `--no-validate`. `--yes` подавляет и
|
||||
подтверждение spec updates, и предупреждение о незакрытых tasks, поэтому
|
||||
допустим только сразу после успешного `check.cjs archive` (в non-TTY агентской
|
||||
среде без него archive не выполняется).
|
||||
|
||||
Sync / Archive Semantics: native archive обновляет canonical specs;
|
||||
system-analysis, contracts и process-record остаются в archived change; `docs/`
|
||||
меняются только `[docs]` tasks; значимые решения — immutable ADR.
|
||||
|
||||
Feedback Routing:
|
||||
- intent/scope → Proposal; behavior/invariants → Specs; interaction → UX Design;
|
||||
systems/contracts/mappings/failures/NFR/semantic observability → System Analysis
|
||||
и modules; threats → Security Analysis; internal implementation → Design;
|
||||
verification → QA Analysis/Test Cases; docs → Docs Impact; decomposition → Tasks.
|
||||
- При semantic conflict останови downstream work, сообщи evidence, инвалидируй
|
||||
gates от самого раннего затронутого artifact.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Data Mapping
|
||||
|
||||
<!-- guide: Field-level transformation between systems. Large mappings go to a
|
||||
machine-checkable file in contracts/ and are referenced here. Remove guides. -->
|
||||
|
||||
## Source and Target
|
||||
|
||||
| Mapping | Source (owner) | Target (owner) | Direction | Trigger |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
## Field Mapping
|
||||
|
||||
| Target field | Source field(s) | Transformation | Unit / currency / scale | Nullability | Default | Validation | On failure |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Invariants
|
||||
|
||||
<!-- guide: Conservation rules that must hold after mapping, e.g. "total = sum of
|
||||
positions + cash; each money unit counted once", sign conventions, rounding
|
||||
point. Each invariant references the spec requirement it protects. -->
|
||||
|
||||
## Double-counting and Classification Risks
|
||||
|
||||
<!-- guide: Every source record type that could fall into two target aggregates,
|
||||
and the rule that assigns it to exactly one. -->
|
||||
|
||||
## Transformation Errors
|
||||
|
||||
## Open Questions
|
||||
@@ -0,0 +1,58 @@
|
||||
# Engineering Design
|
||||
|
||||
<!-- guide: How affected repositories implement approved specs and system
|
||||
obligations. Reference upstream ids; do not restate them. Remove guides. -->
|
||||
|
||||
## Inputs
|
||||
|
||||
<!-- guide: Exact upstream artifacts this design implements (specs, selected
|
||||
system-analysis modules, ux-design, security-analysis). -->
|
||||
|
||||
## Architecture Drivers
|
||||
|
||||
<!-- guide: Requirements, NFR ids, constraints and risks that force decisions. -->
|
||||
|
||||
## Technical Goals / Non-Goals
|
||||
|
||||
## Implementation Impact Map
|
||||
|
||||
| Area | Affected | Outcome or N/A reason |
|
||||
| --- | --- | --- |
|
||||
| main | | |
|
||||
| frontend | | |
|
||||
| backend | | |
|
||||
|
||||
## Decisions
|
||||
|
||||
<!-- guide: Per decision: context, chosen option, rejected alternatives, driver it
|
||||
satisfies. Group by repository when that helps. -->
|
||||
|
||||
## Components and Responsibilities
|
||||
|
||||
## Data / Storage Changes
|
||||
|
||||
## Contract Implementation
|
||||
|
||||
<!-- guide: How each contract is produced/consumed and how published OpenAPI is
|
||||
compared with the target contract. N/A when no contracts changed. -->
|
||||
|
||||
## Cross-cutting Implementation
|
||||
|
||||
## UI Implementation
|
||||
|
||||
<!-- guide: With ux-design.md: component composition, state, data fetching, how
|
||||
each UI state is produced — no restated UX. Without ux-design.md: state
|
||||
new/changed, reuse or N/A with reason, plus the needed screen/state detail. -->
|
||||
|
||||
## Developer Verification Strategy
|
||||
|
||||
## Migration / Rollout / Rollback
|
||||
|
||||
## Solution Assessment
|
||||
|
||||
<!-- guide: Required for new auth, security, storage, integration, observability,
|
||||
caching, concurrency or shared tooling; otherwise N/A with reason. -->
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
## ADR Candidates
|
||||
@@ -0,0 +1,18 @@
|
||||
# Documentation Impact
|
||||
|
||||
<!-- guide: Plan only; docs/ is edited by [docs] tasks. Remove guides. -->
|
||||
|
||||
## Summary
|
||||
|
||||
## Documentation Changes
|
||||
|
||||
| Action | Target | Category | Resulting AS-IS | Source | Verification |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Diagram Promotion
|
||||
|
||||
## ADR Decision
|
||||
|
||||
## Glossary / Navigation Impact
|
||||
|
||||
## No-Change Rationale
|
||||
@@ -0,0 +1,26 @@
|
||||
# Failure Model
|
||||
|
||||
<!-- guide: Boundary-level failure semantics. Implementation of mechanisms (queues,
|
||||
locks, libraries) belongs to design.md. Remove guides before G3. -->
|
||||
|
||||
## Failure Scenarios
|
||||
|
||||
| ID | Boundary / step | Failure | Detection | Required system behavior | Observable result | Requirement |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Timeouts and Retries
|
||||
|
||||
## Idempotency and Duplicate Handling
|
||||
|
||||
<!-- guide: Idempotency key, scope, retention; what a duplicate request/event
|
||||
yields. -->
|
||||
|
||||
## Ordering and Concurrency
|
||||
|
||||
## Partial Failure and Compensation
|
||||
|
||||
## Recovery Behavior
|
||||
|
||||
## Compatibility During Failure
|
||||
|
||||
## Open Questions
|
||||
@@ -0,0 +1,14 @@
|
||||
# Non-Functional Requirements
|
||||
|
||||
<!-- guide: Only measurable constraints that change design or verification.
|
||||
Each row needs a threshold and a way to measure it. Remove guides. -->
|
||||
|
||||
| ID | Category | Requirement | Threshold | Measurement / evidence | Rationale / source |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Constraints Without Thresholds
|
||||
|
||||
<!-- guide: Constraints that are real but not measurable yet; state why and who
|
||||
decides the threshold. -->
|
||||
|
||||
## Open Questions
|
||||
@@ -0,0 +1,24 @@
|
||||
# Observability
|
||||
|
||||
<!-- guide: What must be observable and why; not which SDK, exporter or logger
|
||||
(design.md). Remove guides before G3. -->
|
||||
|
||||
## Semantic Events
|
||||
|
||||
| Event | Trigger | Required attributes | Consumer / purpose |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
## Logs, Metrics and Traces
|
||||
|
||||
## Correlation
|
||||
|
||||
## SLI and Alert Conditions
|
||||
|
||||
| SLI | Definition | Target | Alert condition |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
## Diagnostic Scenarios
|
||||
|
||||
<!-- guide: "When X happens, an operator can determine Y from Z." -->
|
||||
|
||||
## Open Questions
|
||||
@@ -0,0 +1,57 @@
|
||||
# Process Record
|
||||
|
||||
**Mode:** <!-- guide: lab | delivery -->
|
||||
**Class:** <!-- guide: standard | complex -->
|
||||
**Issue:** <!-- guide: Gitea Issue link -->
|
||||
|
||||
## Change Profile
|
||||
|
||||
<!-- guide: One row per conditional artifact, all ten rows required. Selected =
|
||||
yes|no. Reason cites the concrete trigger from the instruction table or why
|
||||
it does not apply; "lab practice" is a valid reason only in lab mode and
|
||||
must name the practice. -->
|
||||
|
||||
| Artifact | Selected | Reason |
|
||||
| --- | --- | --- |
|
||||
| research | | |
|
||||
| ux-design | | |
|
||||
| system-analysis | | |
|
||||
| data-mapping | | |
|
||||
| failure-model | | |
|
||||
| nfr | | |
|
||||
| observability | | |
|
||||
| security-analysis | | |
|
||||
| test-cases | | |
|
||||
| docs-impact | | |
|
||||
|
||||
## Gate Log
|
||||
|
||||
<!-- guide: Append-only, chronological. Scope = artifact ids covered by the
|
||||
decision. Validation = commands run and their results, review verdicts.
|
||||
Decision = `approved "<quoted owner words>"`, `rejected`, `changes requested`
|
||||
or `invalidated: <reason>`. Never write a decision the owner did not give. -->
|
||||
|
||||
| Gate | Date | Scope | Validation | Findings | Decision |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Descoped Work
|
||||
|
||||
<!-- guide: Tasks removed from tasks.md after G3. Reason and approving gate are
|
||||
required. Leave the header row only when nothing was descoped. -->
|
||||
|
||||
| Task | Reason | Gate |
|
||||
| --- | --- | --- |
|
||||
|
||||
## Lab Journal
|
||||
|
||||
<!-- guide: lab mode: one row per completed stage, written right after it.
|
||||
Unique findings = what this stage found that no other stage did.
|
||||
Cost = subagent calls, approximate tokens or time. delivery mode: optional. -->
|
||||
|
||||
| Stage | Role / subagent | Unique findings | Decisions | Risks found / excluded | Handoff issues | Skills | Cost | Transferable |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Retrospective
|
||||
|
||||
<!-- guide: Written after G4. Which stages paid off, which were redundant for this
|
||||
class of change, what to change in the schema. Facts first, then opinion. -->
|
||||
@@ -0,0 +1,36 @@
|
||||
# Proposal
|
||||
|
||||
<!-- guide: Language of the Change Owner. No files, APIs, tables, libraries,
|
||||
diagrams or test plans. Remove every guide comment before G1. -->
|
||||
|
||||
## Why
|
||||
|
||||
## What Changes
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
### Out of Scope / Non-Goals
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
## Impact
|
||||
|
||||
## Success Criteria
|
||||
|
||||
## Evidence
|
||||
|
||||
<!-- guide: Facts that justify the change, each with a source: Issue, research
|
||||
(link or `research.md`), incident, measurement. Mark hypotheses as such. -->
|
||||
|
||||
## Assumptions / Dependencies
|
||||
|
||||
## Open Decisions
|
||||
|
||||
<!-- guide: Decisions not yet taken that may change scope. Each item: question,
|
||||
who decides, what blocks until it is answered. Empty only if none exist. -->
|
||||
@@ -0,0 +1,34 @@
|
||||
# QA Analysis
|
||||
|
||||
<!-- guide: Risk-based system verification strategy. Reference scenarios; do not
|
||||
restate them. No developer unit/component test plans. Remove guides. -->
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
| Risk | Affected requirements | Likelihood | Impact | Verification depth |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
## Coverage Matrix
|
||||
|
||||
<!-- guide: One row per delta requirement. Check = system-level way of proving
|
||||
it; test case ids when test-cases is selected; or "not verified: <risk
|
||||
reason>". -->
|
||||
|
||||
| Requirement | Check | Level | Test cases |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
## Negative and Boundary Focus
|
||||
|
||||
## Cross-system Verification
|
||||
|
||||
## Test Data and Environment Needs
|
||||
|
||||
## Manual / Exploratory Scope
|
||||
|
||||
## Automation Candidates
|
||||
|
||||
## Regression Impact
|
||||
|
||||
## Gaps / Blockers
|
||||
|
||||
<!-- guide: Each gap names its routing destination artifact. -->
|
||||
@@ -0,0 +1,28 @@
|
||||
# Product Research
|
||||
|
||||
<!-- guide: Input context, not a requirement source. Every claim is marked
|
||||
[F] fact with source, [I] interpretation or [H] hypothesis. Remove guides. -->
|
||||
|
||||
## Problem Statement
|
||||
|
||||
## Target Audience
|
||||
|
||||
## Research Questions
|
||||
|
||||
## Existing Solutions and Alternatives
|
||||
|
||||
| Option | What it does | Strengths | Weaknesses | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
## Evidence & Sources
|
||||
|
||||
## Assumptions
|
||||
|
||||
## Risks
|
||||
|
||||
## Conclusions
|
||||
|
||||
## Recommendation
|
||||
|
||||
<!-- guide: build / do not build / narrow scope / research more, with reasons.
|
||||
"Do not build" is a valid outcome. -->
|
||||
@@ -0,0 +1,26 @@
|
||||
# Security Analysis
|
||||
|
||||
<!-- guide: Threat model of this change only. Reference security NFR rows by id;
|
||||
do not restate them. No generic checklist. Remove guides before G3. -->
|
||||
|
||||
## Scope
|
||||
|
||||
## Assets
|
||||
|
||||
## Trust Boundaries
|
||||
|
||||
## Threats
|
||||
|
||||
| ID | Threat (STRIDE) | Attack scenario | Asset / boundary | Existing control | Likelihood / impact |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Recommended Mitigations
|
||||
|
||||
| Threat | Mitigation | Owner artifact (specs / system-analysis / design) |
|
||||
| --- | --- | --- |
|
||||
|
||||
## Residual Risks
|
||||
|
||||
## Validation Requirements
|
||||
|
||||
<!-- guide: Evidence needed before G4: review focus, negative tests, tooling. -->
|
||||
@@ -0,0 +1,18 @@
|
||||
<!--
|
||||
Choose only the sections this delta needs; delete this guide before approval.
|
||||
|
||||
New capability only: add `## Purpose` with 1–2 sentences (50+ characters).
|
||||
Existing capability: do not add Purpose.
|
||||
|
||||
Supported operations:
|
||||
- `## ADDED Requirements`: new complete Requirement blocks.
|
||||
- `## MODIFIED Requirements`: full existing Requirement blocks with every
|
||||
surviving Scenario, then edited behavior; heading matches exactly.
|
||||
- `## REMOVED Requirements`: Requirement heading plus **Reason** and **Migration**.
|
||||
- `## RENAMED Requirements`: `FROM:` and `TO:` heading pairs only.
|
||||
|
||||
Every normative Requirement uses BCP 14 (RFC 2119 + RFC 8174) uppercase
|
||||
SHALL/MUST deliberately, and at least one `#### Scenario:` with `- **WHEN**`
|
||||
and `- **THEN**`. Lowercase must/should/may are ordinary language.
|
||||
Do not leave empty operation sections or a sample Requirement.
|
||||
-->
|
||||
@@ -0,0 +1,50 @@
|
||||
# System Analysis
|
||||
|
||||
<!-- guide: Hub document. Owns context, boundaries, flows overview and contract
|
||||
semantics; details live in selected modules and are referenced, not copied.
|
||||
Remove guides before G3. -->
|
||||
|
||||
## Requirement Coverage
|
||||
|
||||
| Requirement | Flow / contract | Module |
|
||||
| --- | --- | --- |
|
||||
|
||||
## System Context and Boundaries
|
||||
|
||||
## As-Is / To-Be
|
||||
|
||||
## Impact Analysis
|
||||
|
||||
## Systems and Responsibilities
|
||||
|
||||
## Data Ownership
|
||||
|
||||
| Data | Source of truth | Writers | Readers |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
## Interaction Flows
|
||||
|
||||
<!-- guide: Reference diagrams/*.mmd; text only for what a diagram cannot carry. -->
|
||||
|
||||
## Contracts
|
||||
|
||||
<!-- guide: Per contract: producer/consumer, operation/event, version, file in
|
||||
contracts/, compatibility class (additive / breaking), published source it
|
||||
must match after implementation. -->
|
||||
|
||||
| Contract | Producer → Consumer | File | Compatibility | Published source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
|
||||
## Error Semantics
|
||||
|
||||
<!-- guide: Business vs technical failures at boundaries. Detailed retry/
|
||||
idempotency/recovery belongs to failure-model.md when selected. -->
|
||||
|
||||
## Compatibility / Migration
|
||||
|
||||
## Detailed Modules
|
||||
|
||||
<!-- guide: Link each selected module (data-mapping, failure-model, nfr,
|
||||
observability) with one line on what it decides. -->
|
||||
|
||||
## Open Questions
|
||||
@@ -0,0 +1,18 @@
|
||||
# Tasks
|
||||
|
||||
<!-- guide: Task line format:
|
||||
- [ ] X.Y [main|frontend|backend|docs|specs] <Kind>: <action + outcome>
|
||||
- **Covers:** `capability` — `Requirement heading` pairs, or `N/A` — <reason>
|
||||
- **Source:** exact upstream artifact section / contract / docs-impact entry
|
||||
- **Verification:** owner-controlled command, observable check or artifact
|
||||
- **Depends on:** task ids or none
|
||||
Kinds: Implementation, Migration, Automated Testing, Contract Parity, Docs,
|
||||
Independent Review, QA Verification, Verification. Remove guides before G3. -->
|
||||
|
||||
## 1. <!-- guide: delivery phase -->
|
||||
|
||||
## Docs Impact
|
||||
|
||||
<!-- guide: Only when docs-impact is not selected: list docs/ targets with
|
||||
resulting AS-IS, or one concrete no-change reason. Delete when docs-impact.md
|
||||
exists. -->
|
||||
@@ -0,0 +1,16 @@
|
||||
# Test Cases — <!-- guide: area -->
|
||||
|
||||
<!-- guide: One file per area under test-cases/. A case adds concrete data, steps
|
||||
or an oracle that the scenario does not already state; otherwise reference the
|
||||
scenario from qa-analysis instead of writing a case. Remove guides. -->
|
||||
|
||||
### TC-<!-- guide: AREA-NNN --> <!-- guide: title -->
|
||||
|
||||
- **Verifies:** `capability` — `Requirement heading` / Scenario
|
||||
- **Risk / Priority:**
|
||||
- **Preconditions:**
|
||||
- **Test Data:**
|
||||
- **Steps:**
|
||||
1.
|
||||
- **Expected Results:**
|
||||
- **Automation Candidate:** <!-- guide: yes (level) | no (reason) -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# UX Design
|
||||
|
||||
<!-- guide: Interaction design of observable behavior from Delta Specs. Reference
|
||||
requirements as `capability` — `Requirement heading`; do not restate them.
|
||||
No server architecture, contracts or component/state-management choices.
|
||||
Remove guides before G3. -->
|
||||
|
||||
## User Goals
|
||||
|
||||
## User Flows
|
||||
|
||||
<!-- guide: Mermaid flowchart or numbered steps per flow, with entry and exit points. -->
|
||||
|
||||
## Information Architecture and Screen Structure
|
||||
|
||||
## Interaction Behavior
|
||||
|
||||
## UI States
|
||||
|
||||
| Screen / region | Loading | Empty | Error | Success | Partial / stale |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
|
||||
## Validation Feedback
|
||||
|
||||
## Responsive Behavior
|
||||
|
||||
## Accessibility
|
||||
|
||||
<!-- guide: Keyboard path, focus order, names/roles, contrast, non-color cues. -->
|
||||
|
||||
## Design System Reuse
|
||||
|
||||
## Materials
|
||||
|
||||
<!-- guide: Inline Markdown by default; local files follow the Visual Package rule. -->
|
||||
|
||||
| Material ID | Relative path / reference | Screen/state and purpose | SHA-256 |
|
||||
| --- | --- | --- | --- |
|
||||
|
||||
## Open UX Questions
|
||||
Reference in New Issue
Block a user