@xenonbyte/da-vinci-workflow 0.1.19 → 0.1.21
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/CHANGELOG.md +24 -0
- package/README.md +40 -54
- package/README.zh-CN.md +34 -54
- package/SKILL.md +4 -0
- package/commands/claude/dv/build.md +6 -0
- package/commands/claude/dv/continue.md +5 -0
- package/commands/codex/prompts/dv-build.md +4 -0
- package/commands/codex/prompts/dv-continue.md +5 -0
- package/commands/gemini/dv/build.toml +4 -0
- package/commands/gemini/dv/continue.toml +5 -0
- package/docs/codex-natural-language-usage.md +3 -0
- package/docs/dv-command-reference.md +10 -0
- package/docs/mode-use-cases.md +2 -0
- package/docs/pencil-rendering-workflow.md +16 -0
- package/docs/prompt-entrypoints.md +7 -0
- package/docs/prompt-presets/README.md +2 -0
- package/docs/prompt-presets/desktop-app.md +4 -0
- package/docs/prompt-presets/mobile-app.md +4 -0
- package/docs/prompt-presets/tablet-app.md +4 -0
- package/docs/prompt-presets/web-app.md +4 -0
- package/docs/visual-adapters.md +24 -80
- package/docs/visual-assist-presets/desktop-app.md +20 -68
- package/docs/visual-assist-presets/mobile-app.md +20 -68
- package/docs/visual-assist-presets/tablet-app.md +20 -68
- package/docs/visual-assist-presets/web-app.md +20 -68
- package/docs/workflow-examples.md +2 -0
- package/docs/workflow-overview.md +11 -0
- package/docs/zh-CN/codex-natural-language-usage.md +3 -0
- package/docs/zh-CN/dv-command-reference.md +10 -0
- package/docs/zh-CN/mode-use-cases.md +2 -0
- package/docs/zh-CN/pencil-rendering-workflow.md +16 -0
- package/docs/zh-CN/prompt-entrypoints.md +7 -0
- package/docs/zh-CN/prompt-presets/README.md +2 -0
- package/docs/zh-CN/prompt-presets/desktop-app.md +3 -0
- package/docs/zh-CN/prompt-presets/mobile-app.md +3 -0
- package/docs/zh-CN/prompt-presets/tablet-app.md +3 -0
- package/docs/zh-CN/prompt-presets/web-app.md +3 -0
- package/docs/zh-CN/visual-adapters.md +24 -80
- package/docs/zh-CN/visual-assist-presets/desktop-app.md +20 -68
- package/docs/zh-CN/visual-assist-presets/mobile-app.md +20 -68
- package/docs/zh-CN/visual-assist-presets/tablet-app.md +20 -68
- package/docs/zh-CN/visual-assist-presets/web-app.md +20 -68
- package/docs/zh-CN/workflow-examples.md +2 -0
- package/docs/zh-CN/workflow-overview.md +11 -0
- package/examples/greenfield-spec-markupflow/DA-VINCI.md +4 -13
- package/lib/audit.js +455 -0
- package/lib/cli.js +6 -1
- package/lib/pencil-session.js +6 -0
- package/package.json +2 -1
- package/references/artifact-templates.md +38 -0
- package/references/checkpoints.md +16 -0
- package/references/prompt-recipes.md +5 -0
- package/scripts/test-audit-context-delta.js +446 -0
- package/scripts/test-mode-consistency.js +50 -0
- package/scripts/test-pencil-session.js +40 -0
- package/scripts/test-persistence-flows.js +31 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xenonbyte/da-vinci-workflow",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Requirement-to-design-to-code workflow skill for Codex, Claude, and Gemini",
|
|
5
5
|
"bin": {
|
|
6
6
|
"da-vinci": "bin/da-vinci.js"
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"postinstall": "node scripts/postinstall.js",
|
|
24
24
|
"validate-assets": "node scripts/validate-assets.js",
|
|
25
|
+
"test:audit-context-delta": "node scripts/test-audit-context-delta.js",
|
|
25
26
|
"test:audit-design-supervisor": "node scripts/test-audit-design-supervisor.js",
|
|
26
27
|
"test:pencil-lock": "node scripts/test-pencil-lock.js",
|
|
27
28
|
"test:mode-consistency": "node scripts/test-mode-consistency.js",
|
|
@@ -592,6 +592,26 @@ Use this structure:
|
|
|
592
592
|
- `Final runtime gate status`
|
|
593
593
|
- Notes
|
|
594
594
|
|
|
595
|
+
## Context Delta
|
|
596
|
+
- One concise entry per checkpoint-adjacent event
|
|
597
|
+
- Required fields:
|
|
598
|
+
- `time`
|
|
599
|
+
- `checkpoint_type`
|
|
600
|
+
- `goal`
|
|
601
|
+
- `decision`
|
|
602
|
+
- `constraints`
|
|
603
|
+
- `impact`
|
|
604
|
+
- `status`
|
|
605
|
+
- `next_action`
|
|
606
|
+
- Optional field:
|
|
607
|
+
- `supersedes`
|
|
608
|
+
- `supersedes` should reference an earlier entry in the same artifact by `time`, or by `checkpoint_type@time`
|
|
609
|
+
- Parseable timestamp format differences are tolerated during audit (for example: `2026-03-28T12:00:00.000Z` and `2026-03-28 12:00:00Z`)
|
|
610
|
+
- Keep entries as delta summaries, not transcript copies
|
|
611
|
+
- Use this section as auxiliary recovery context only; it is not the phase source of truth
|
|
612
|
+
- Context-delta expectation checks run automatically when this artifact includes `## Checkpoint Status` or `## MCP Runtime Gate`
|
|
613
|
+
- If this artifact should be checked without those headings, add `- Context Delta Required: true` (accepted truthy values: `true`, `yes`, `on`, `1`)
|
|
614
|
+
|
|
595
615
|
## Checkpoint Status
|
|
596
616
|
- `mcp runtime gate`
|
|
597
617
|
- `design-source checkpoint`
|
|
@@ -630,6 +650,15 @@ Use this structure:
|
|
|
630
650
|
## 5. Verification
|
|
631
651
|
- [ ] Check requirement coverage
|
|
632
652
|
- [ ] Check Pencil coverage
|
|
653
|
+
|
|
654
|
+
## Context Delta
|
|
655
|
+
- Add concise checkpoint-adjacent entries when `task checkpoint` or execution planning decisions change
|
|
656
|
+
- Required fields: `time`, `checkpoint_type`, `goal`, `decision`, `constraints`, `impact`, `status`, `next_action`
|
|
657
|
+
- Optional field: `supersedes`
|
|
658
|
+
- `supersedes` should reference an earlier entry in the same artifact by `time`, or by `checkpoint_type@time`
|
|
659
|
+
- Parseable timestamp format differences are tolerated during audit
|
|
660
|
+
- Keep this section auxiliary; route and phase decisions still come from artifact and checkpoint truth
|
|
661
|
+
- If this artifact has no `## Checkpoint Status` or `## MCP Runtime Gate`, add `- Context Delta Required: true` (accepted truthy values: `true`, `yes`, `on`, `1`) when you still want audit expectation checks
|
|
633
662
|
```
|
|
634
663
|
|
|
635
664
|
Prefer top-level task groups. They are required for execution checkpoints.
|
|
@@ -697,6 +726,15 @@ Use this structure:
|
|
|
697
726
|
## Outcome
|
|
698
727
|
- PASS / WARN / BLOCK
|
|
699
728
|
- Next action
|
|
729
|
+
|
|
730
|
+
## Context Delta
|
|
731
|
+
- Add concise entries after each `execution checkpoint`
|
|
732
|
+
- Required fields: `time`, `checkpoint_type`, `goal`, `decision`, `constraints`, `impact`, `status`, `next_action`
|
|
733
|
+
- Optional field: `supersedes`
|
|
734
|
+
- `supersedes` should reference an earlier entry in the same artifact by `time`, or by `checkpoint_type@time`
|
|
735
|
+
- Parseable timestamp format differences are tolerated during audit
|
|
736
|
+
- Use entries to preserve short-horizon execution context; do not treat them as completion-gate truth
|
|
737
|
+
- `## Outcome` alone does not enable context-delta expectation checks; add `- Context Delta Required: true` (or `yes` / `on` / `1`) when needed
|
|
700
738
|
```
|
|
701
739
|
|
|
702
740
|
Recommended path:
|
|
@@ -23,6 +23,15 @@ Resume rule:
|
|
|
23
23
|
|
|
24
24
|
- when artifacts already exist and the workflow was paused, `continue` should resume from the current artifact truth instead of restarting discovery
|
|
25
25
|
|
|
26
|
+
Context-delta rule:
|
|
27
|
+
|
|
28
|
+
- context deltas are auxiliary recovery notes, not authoritative phase truth
|
|
29
|
+
- write context deltas only at existing checkpoint-adjacent boundaries
|
|
30
|
+
- when context deltas conflict with current artifacts or checkpoint results, ignore those deltas for routing and continue from artifact truth
|
|
31
|
+
- context-delta expectation checks auto-apply to artifacts that include `## Checkpoint Status` or `## MCP Runtime Gate`
|
|
32
|
+
- when an artifact should opt in without those headings, add `- Context Delta Required: true` (accepted truthy values: `true`, `yes`, `on`, `1`)
|
|
33
|
+
- when `supersedes` references parseable timestamps in different textual formats, treat them as the same point-in-time reference
|
|
34
|
+
|
|
26
35
|
## Visual Contract Rule
|
|
27
36
|
|
|
28
37
|
Before broad Pencil page generation:
|
|
@@ -310,6 +319,7 @@ Automatic failures:
|
|
|
310
319
|
- if the workflow claims the `.pen` source exists only "in memory", treat completion as `BLOCK`
|
|
311
320
|
- if the workflow claims success after exporting PNGs but without a shell-visible `.pen`, treat completion as `BLOCK`
|
|
312
321
|
- if the workflow reports completion without the required standard artifacts for the active stage, treat completion as `BLOCK`
|
|
322
|
+
- missing or stale context-delta notes alone are `WARN`, not `BLOCK`
|
|
313
323
|
|
|
314
324
|
## `execution checkpoint`
|
|
315
325
|
|
|
@@ -350,3 +360,9 @@ Use this reporting shape:
|
|
|
350
360
|
```
|
|
351
361
|
|
|
352
362
|
Do not create separate review artifacts unless the project explicitly requires them.
|
|
363
|
+
|
|
364
|
+
Context-delta reporting notes:
|
|
365
|
+
|
|
366
|
+
- keep entries concise and checkpoint-adjacent
|
|
367
|
+
- do not dump full dialogue transcripts into workflow artifacts
|
|
368
|
+
- do not create a separate top-level context ledger for this; use existing change artifacts
|
|
@@ -18,6 +18,9 @@ Keep these rules fixed:
|
|
|
18
18
|
- do not default `intake` or `continue` into `build`
|
|
19
19
|
- use `build` directly only when tasks, design bindings, and implementation readiness are already clear
|
|
20
20
|
- continuation prompts should preserve existing artifact truth instead of restarting discovery
|
|
21
|
+
- continuation routing should be decided from artifact and checkpoint truth before consulting any contextual delta notes
|
|
22
|
+
- contextual delta notes are auxiliary recovery signals; they can enrich continuation wording but should not override phase routing
|
|
23
|
+
- when contextual delta notes conflict with current artifacts, ignore those notes for routing and call out the conflict
|
|
21
24
|
- when design artifacts exist but `tasks.md` does not, continuation should usually target `tasks`, not `build`
|
|
22
25
|
- when tasks already exist and the task checkpoint is healthy, continuation should usually target `build`
|
|
23
26
|
|
|
@@ -96,6 +99,8 @@ Then output:
|
|
|
96
99
|
|
|
97
100
|
- detected workflow state
|
|
98
101
|
- missing or weak artifacts
|
|
102
|
+
- latest contextual deltas that are still consistent with current artifact truth, when available
|
|
103
|
+
- stale or conflicting contextual deltas, when detected
|
|
99
104
|
- one executable continuation prompt
|
|
100
105
|
- one more conservative continuation prompt when useful
|
|
101
106
|
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
const assert = require("assert/strict");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const os = require("os");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { spawnSync } = require("child_process");
|
|
6
|
+
|
|
7
|
+
const { auditProject } = require("../lib/audit");
|
|
8
|
+
|
|
9
|
+
const repo = path.resolve(__dirname, "..");
|
|
10
|
+
const cli = path.join(repo, "bin", "da-vinci.js");
|
|
11
|
+
const fixture = JSON.parse(
|
|
12
|
+
fs.readFileSync(path.join(__dirname, "fixtures", "complex-sample.pen"), "utf8")
|
|
13
|
+
);
|
|
14
|
+
const changeId = "redesign-001";
|
|
15
|
+
|
|
16
|
+
function runTest(name, fn) {
|
|
17
|
+
try {
|
|
18
|
+
fn();
|
|
19
|
+
console.log(`PASS ${name}`);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(`FAIL ${name}`);
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function assertFixtureShape() {
|
|
27
|
+
assert.equal(typeof fixture.version, "string", "fixture.version must be a string");
|
|
28
|
+
assert.ok(fixture.version.length > 0, "fixture.version must be non-empty");
|
|
29
|
+
assert.ok(Array.isArray(fixture.children), "fixture.children must be an array");
|
|
30
|
+
assert.ok(fixture.children.length > 0, "fixture.children must include at least one top-level node");
|
|
31
|
+
assert.equal(typeof fixture.variables, "object", "fixture.variables must be an object");
|
|
32
|
+
assert.ok(fixture.variables && Object.keys(fixture.variables).length > 0, "fixture.variables must be non-empty");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function createHarness() {
|
|
36
|
+
const base = fs.mkdtempSync(path.join(os.tmpdir(), "da-vinci-audit-context-"));
|
|
37
|
+
return {
|
|
38
|
+
base,
|
|
39
|
+
home: path.join(base, "home")
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function runCli(harness, args) {
|
|
44
|
+
const [command, ...rest] = args;
|
|
45
|
+
const result = spawnSync(process.execPath, [cli, command, "--home", harness.home, ...rest], {
|
|
46
|
+
cwd: repo,
|
|
47
|
+
encoding: "utf8",
|
|
48
|
+
maxBuffer: 8 * 1024 * 1024
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
code: result.status,
|
|
53
|
+
stdout: (result.stdout || "").trim(),
|
|
54
|
+
stderr: (result.stderr || "").trim()
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function expectOk(step, result) {
|
|
59
|
+
assert.equal(result.code, 0, `${step} failed:\n${result.stderr || result.stdout}`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function writeJson(filePath, payload) {
|
|
63
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
64
|
+
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function writeText(filePath, text) {
|
|
68
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
69
|
+
fs.writeFileSync(filePath, text);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function setupProject(harness, name, pencilDesignBody) {
|
|
73
|
+
const root = path.join(harness.base, name);
|
|
74
|
+
const daVinciDir = path.join(root, ".da-vinci");
|
|
75
|
+
const changeDir = path.join(daVinciDir, "changes", changeId);
|
|
76
|
+
const penPath = path.join(daVinciDir, "designs", `${name}.pen`);
|
|
77
|
+
const nodesFile = path.join(root, `${name}-nodes.json`);
|
|
78
|
+
const variablesFile = path.join(root, `${name}-variables.json`);
|
|
79
|
+
|
|
80
|
+
writeText(path.join(root, "DA-VINCI.md"), "# DA-VINCI\n");
|
|
81
|
+
writeText(path.join(daVinciDir, "project-inventory.md"), "# Inventory\n");
|
|
82
|
+
writeText(path.join(daVinciDir, "page-map.md"), "# Page Map\n");
|
|
83
|
+
writeText(
|
|
84
|
+
path.join(daVinciDir, "design-registry.md"),
|
|
85
|
+
`# Registry\n- Preferred .pen: .da-vinci/designs/${name}.pen\n`
|
|
86
|
+
);
|
|
87
|
+
writeText(path.join(changeDir, "design-brief.md"), "# Brief\n");
|
|
88
|
+
writeText(path.join(changeDir, "design.md"), "# Design\n");
|
|
89
|
+
writeText(path.join(changeDir, "pencil-bindings.md"), "# Bindings\n");
|
|
90
|
+
writeText(path.join(changeDir, "pencil-design.md"), pencilDesignBody);
|
|
91
|
+
|
|
92
|
+
writeJson(nodesFile, { nodes: fixture.children });
|
|
93
|
+
writeJson(variablesFile, { variables: fixture.variables });
|
|
94
|
+
|
|
95
|
+
expectOk(
|
|
96
|
+
`${name} begin`,
|
|
97
|
+
runCli(harness, ["pencil-session", "begin", "--project", root, "--pen", penPath])
|
|
98
|
+
);
|
|
99
|
+
expectOk(
|
|
100
|
+
`${name} persist`,
|
|
101
|
+
runCli(harness, [
|
|
102
|
+
"pencil-session",
|
|
103
|
+
"persist",
|
|
104
|
+
"--project",
|
|
105
|
+
root,
|
|
106
|
+
"--pen",
|
|
107
|
+
penPath,
|
|
108
|
+
"--nodes-file",
|
|
109
|
+
nodesFile,
|
|
110
|
+
"--variables-file",
|
|
111
|
+
variablesFile,
|
|
112
|
+
"--version",
|
|
113
|
+
fixture.version
|
|
114
|
+
])
|
|
115
|
+
);
|
|
116
|
+
expectOk(
|
|
117
|
+
`${name} end`,
|
|
118
|
+
runCli(harness, [
|
|
119
|
+
"pencil-session",
|
|
120
|
+
"end",
|
|
121
|
+
"--project",
|
|
122
|
+
root,
|
|
123
|
+
"--pen",
|
|
124
|
+
penPath,
|
|
125
|
+
"--nodes-file",
|
|
126
|
+
nodesFile,
|
|
127
|
+
"--variables-file",
|
|
128
|
+
variablesFile,
|
|
129
|
+
"--version",
|
|
130
|
+
fixture.version
|
|
131
|
+
])
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
root
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
assertFixtureShape();
|
|
140
|
+
|
|
141
|
+
runTest("completion audit warns when checkpoint-bearing artifacts have no concrete context delta", () => {
|
|
142
|
+
const harness = createHarness();
|
|
143
|
+
const project = setupProject(
|
|
144
|
+
harness,
|
|
145
|
+
"missing-context-delta",
|
|
146
|
+
[
|
|
147
|
+
"# Pencil Design",
|
|
148
|
+
"",
|
|
149
|
+
"## MCP Runtime Gate",
|
|
150
|
+
"- Final runtime gate status: PASS",
|
|
151
|
+
"",
|
|
152
|
+
"## Checkpoint Status",
|
|
153
|
+
"- `design checkpoint`: PASS",
|
|
154
|
+
"- `completion gate`: PASS",
|
|
155
|
+
""
|
|
156
|
+
].join("\n")
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
const result = auditProject(project.root, {
|
|
160
|
+
mode: "completion",
|
|
161
|
+
changeId
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
assert.equal(result.status, "WARN");
|
|
165
|
+
assert.equal(result.failures.length, 0);
|
|
166
|
+
assert.match(result.warnings.join("\n"), /Context Delta/i);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
runTest("completion audit treats Context Delta Required truthy values as expectation signals", () => {
|
|
170
|
+
const harness = createHarness();
|
|
171
|
+
const project = setupProject(
|
|
172
|
+
harness,
|
|
173
|
+
"context-delta-required-yes",
|
|
174
|
+
[
|
|
175
|
+
"# Pencil Design",
|
|
176
|
+
"",
|
|
177
|
+
"- `Context Delta Required`: yes",
|
|
178
|
+
"",
|
|
179
|
+
"## Notes",
|
|
180
|
+
"- Explicit opt-in without checkpoint headings.",
|
|
181
|
+
""
|
|
182
|
+
].join("\n")
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
const result = auditProject(project.root, {
|
|
186
|
+
mode: "completion",
|
|
187
|
+
changeId
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
assert.equal(result.status, "WARN");
|
|
191
|
+
assert.equal(result.failures.length, 0);
|
|
192
|
+
assert.match(result.warnings.join("\n"), /Context Delta/i);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
runTest("completion audit warns for context-delta and checkpoint status mismatches", () => {
|
|
196
|
+
const harness = createHarness();
|
|
197
|
+
const project = setupProject(
|
|
198
|
+
harness,
|
|
199
|
+
"stale-context-delta",
|
|
200
|
+
[
|
|
201
|
+
"# Pencil Design",
|
|
202
|
+
"",
|
|
203
|
+
"## MCP Runtime Gate",
|
|
204
|
+
"- Final runtime gate status: PASS",
|
|
205
|
+
"",
|
|
206
|
+
"## Checkpoint Status",
|
|
207
|
+
"- `design checkpoint`: PASS",
|
|
208
|
+
"",
|
|
209
|
+
"## Context Delta",
|
|
210
|
+
"- time: 2026-03-28T10:00:00.000Z",
|
|
211
|
+
"- checkpoint_type: design checkpoint",
|
|
212
|
+
"- goal: stabilize anchors",
|
|
213
|
+
"- decision: continue to mapping",
|
|
214
|
+
"- constraints: preserve behavior truth",
|
|
215
|
+
"- impact: keeps design pipeline moving",
|
|
216
|
+
"- status: WARN",
|
|
217
|
+
"- next_action: run mapping checkpoint",
|
|
218
|
+
""
|
|
219
|
+
].join("\n")
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const result = auditProject(project.root, {
|
|
223
|
+
mode: "completion",
|
|
224
|
+
changeId
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
assert.equal(result.status, "WARN");
|
|
228
|
+
assert.equal(result.failures.length, 0);
|
|
229
|
+
assert.match(result.warnings.join("\n"), /status mismatch/i);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
runTest("completion audit passes when context-delta and checkpoint status are aligned", () => {
|
|
233
|
+
const harness = createHarness();
|
|
234
|
+
const project = setupProject(
|
|
235
|
+
harness,
|
|
236
|
+
"healthy-context-delta",
|
|
237
|
+
[
|
|
238
|
+
"# Pencil Design",
|
|
239
|
+
"",
|
|
240
|
+
"## MCP Runtime Gate",
|
|
241
|
+
"- Final runtime gate status: PASS",
|
|
242
|
+
"",
|
|
243
|
+
"## Checkpoint Status",
|
|
244
|
+
"- `design checkpoint`: PASS",
|
|
245
|
+
"",
|
|
246
|
+
"## Context Delta",
|
|
247
|
+
"- time: 2026-03-28T11:00:00.000Z",
|
|
248
|
+
"- checkpoint_type: design checkpoint",
|
|
249
|
+
"- goal: stabilize anchors",
|
|
250
|
+
"- decision: continue to mapping",
|
|
251
|
+
"- constraints: preserve behavior truth",
|
|
252
|
+
"- impact: keeps design pipeline moving",
|
|
253
|
+
"- status: PASS",
|
|
254
|
+
"- next_action: run mapping checkpoint",
|
|
255
|
+
""
|
|
256
|
+
].join("\n")
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const result = auditProject(project.root, {
|
|
260
|
+
mode: "completion",
|
|
261
|
+
changeId
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
assert.equal(result.status, "PASS");
|
|
265
|
+
assert.equal(result.failures.length, 0);
|
|
266
|
+
assert.equal(result.warnings.length, 0);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
runTest("completion audit ignores verification outcome-only artifacts for context-delta expectations", () => {
|
|
270
|
+
const harness = createHarness();
|
|
271
|
+
const project = setupProject(
|
|
272
|
+
harness,
|
|
273
|
+
"outcome-only-verification",
|
|
274
|
+
[
|
|
275
|
+
"# Pencil Design",
|
|
276
|
+
"",
|
|
277
|
+
"## Notes",
|
|
278
|
+
"- No checkpoint headings in this artifact.",
|
|
279
|
+
""
|
|
280
|
+
].join("\n")
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
writeText(
|
|
284
|
+
path.join(project.root, ".da-vinci", "changes", changeId, "verification.md"),
|
|
285
|
+
[
|
|
286
|
+
"# Verification",
|
|
287
|
+
"",
|
|
288
|
+
"## Outcome",
|
|
289
|
+
"- PASS",
|
|
290
|
+
"- Next action: none",
|
|
291
|
+
""
|
|
292
|
+
].join("\n")
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
const result = auditProject(project.root, {
|
|
296
|
+
mode: "completion",
|
|
297
|
+
changeId
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
assert.equal(result.status, "PASS");
|
|
301
|
+
assert.equal(result.failures.length, 0);
|
|
302
|
+
assert.equal(result.warnings.length, 0);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
runTest("completion audit warns when supersedes references missing context-delta entries", () => {
|
|
306
|
+
const harness = createHarness();
|
|
307
|
+
const project = setupProject(
|
|
308
|
+
harness,
|
|
309
|
+
"invalid-supersedes",
|
|
310
|
+
[
|
|
311
|
+
"# Pencil Design",
|
|
312
|
+
"",
|
|
313
|
+
"## MCP Runtime Gate",
|
|
314
|
+
"- Final runtime gate status: PASS",
|
|
315
|
+
"",
|
|
316
|
+
"## Checkpoint Status",
|
|
317
|
+
"- `design checkpoint`: PASS",
|
|
318
|
+
"",
|
|
319
|
+
"## Context Delta",
|
|
320
|
+
"- time: 2026-03-28T12:00:00.000Z",
|
|
321
|
+
"- checkpoint_type: design checkpoint",
|
|
322
|
+
"- goal: stabilize anchors",
|
|
323
|
+
"- decision: finish current anchor pass",
|
|
324
|
+
"- constraints: preserve behavior truth",
|
|
325
|
+
"- impact: keeps mapping handoff stable",
|
|
326
|
+
"- status: PASS",
|
|
327
|
+
"- next_action: prepare mapping checkpoint",
|
|
328
|
+
"",
|
|
329
|
+
"- time: 2026-03-28T13:00:00.000Z",
|
|
330
|
+
"- checkpoint_type: design checkpoint",
|
|
331
|
+
"- goal: finalize status consistency",
|
|
332
|
+
"- decision: retain PASS and continue",
|
|
333
|
+
"- constraints: keep traceability",
|
|
334
|
+
"- impact: no gating change",
|
|
335
|
+
"- status: PASS",
|
|
336
|
+
"- supersedes: 2026-03-28T09:00:00.000Z",
|
|
337
|
+
"- next_action: close design phase",
|
|
338
|
+
""
|
|
339
|
+
].join("\n")
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
const result = auditProject(project.root, {
|
|
343
|
+
mode: "completion",
|
|
344
|
+
changeId
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
assert.equal(result.status, "WARN");
|
|
348
|
+
assert.equal(result.failures.length, 0);
|
|
349
|
+
assert.match(result.warnings.join("\n"), /supersed/i);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
runTest("completion audit accepts valid supersedes references to earlier context-delta entries", () => {
|
|
353
|
+
const harness = createHarness();
|
|
354
|
+
const project = setupProject(
|
|
355
|
+
harness,
|
|
356
|
+
"valid-supersedes",
|
|
357
|
+
[
|
|
358
|
+
"# Pencil Design",
|
|
359
|
+
"",
|
|
360
|
+
"## MCP Runtime Gate",
|
|
361
|
+
"- Final runtime gate status: PASS",
|
|
362
|
+
"",
|
|
363
|
+
"## Checkpoint Status",
|
|
364
|
+
"- `design checkpoint`: PASS",
|
|
365
|
+
"",
|
|
366
|
+
"## Context Delta",
|
|
367
|
+
"- time: 2026-03-28T12:00:00.000Z",
|
|
368
|
+
"- checkpoint_type: design checkpoint",
|
|
369
|
+
"- goal: stabilize anchors",
|
|
370
|
+
"- decision: finish current anchor pass",
|
|
371
|
+
"- constraints: preserve behavior truth",
|
|
372
|
+
"- impact: keeps mapping handoff stable",
|
|
373
|
+
"- status: PASS",
|
|
374
|
+
"- next_action: prepare mapping checkpoint",
|
|
375
|
+
"",
|
|
376
|
+
"- time: 2026-03-28T13:00:00.000Z",
|
|
377
|
+
"- checkpoint_type: design checkpoint",
|
|
378
|
+
"- goal: finalize status consistency",
|
|
379
|
+
"- decision: retain PASS and continue",
|
|
380
|
+
"- constraints: keep traceability",
|
|
381
|
+
"- impact: no gating change",
|
|
382
|
+
"- status: PASS",
|
|
383
|
+
"- supersedes: 2026-03-28T12:00:00.000Z",
|
|
384
|
+
"- next_action: close design phase",
|
|
385
|
+
""
|
|
386
|
+
].join("\n")
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const result = auditProject(project.root, {
|
|
390
|
+
mode: "completion",
|
|
391
|
+
changeId
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
assert.equal(result.status, "PASS");
|
|
395
|
+
assert.equal(result.failures.length, 0);
|
|
396
|
+
assert.equal(result.warnings.length, 0);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
runTest("completion audit accepts supersedes when timestamp formats differ but normalize to same time", () => {
|
|
400
|
+
const harness = createHarness();
|
|
401
|
+
const project = setupProject(
|
|
402
|
+
harness,
|
|
403
|
+
"normalized-time-supersedes",
|
|
404
|
+
[
|
|
405
|
+
"# Pencil Design",
|
|
406
|
+
"",
|
|
407
|
+
"## MCP Runtime Gate",
|
|
408
|
+
"- Final runtime gate status: PASS",
|
|
409
|
+
"",
|
|
410
|
+
"## Checkpoint Status",
|
|
411
|
+
"- `design checkpoint`: PASS",
|
|
412
|
+
"",
|
|
413
|
+
"## Context Delta",
|
|
414
|
+
"- time: 2026-03-28T12:00:00.000Z",
|
|
415
|
+
"- checkpoint_type: design checkpoint",
|
|
416
|
+
"- goal: stabilize anchors",
|
|
417
|
+
"- decision: pass design checkpoint",
|
|
418
|
+
"- constraints: preserve behavior truth",
|
|
419
|
+
"- impact: ready for mapping",
|
|
420
|
+
"- status: PASS",
|
|
421
|
+
"- next_action: run mapping checkpoint",
|
|
422
|
+
"",
|
|
423
|
+
"- time: 2026-03-28T13:00:00.000Z",
|
|
424
|
+
"- checkpoint_type: design checkpoint",
|
|
425
|
+
"- goal: retain continuity",
|
|
426
|
+
"- decision: keep status stable",
|
|
427
|
+
"- constraints: no regressions",
|
|
428
|
+
"- impact: no gate changes",
|
|
429
|
+
"- status: PASS",
|
|
430
|
+
"- supersedes: design checkpoint@2026-03-28 12:00:00Z",
|
|
431
|
+
"- next_action: continue implementation prep",
|
|
432
|
+
""
|
|
433
|
+
].join("\n")
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
const result = auditProject(project.root, {
|
|
437
|
+
mode: "completion",
|
|
438
|
+
changeId
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
assert.equal(result.status, "PASS");
|
|
442
|
+
assert.equal(result.failures.length, 0);
|
|
443
|
+
assert.equal(result.warnings.length, 0);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
console.log("All audit context-delta tests passed.");
|
|
@@ -286,4 +286,54 @@ runTest("design-supervisor review stays distinct from preferred adapters and is
|
|
|
286
286
|
}
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
+
runTest("build prompts require completion audit and do not treat compile success as workflow completion", () => {
|
|
290
|
+
const buildPrompts = [
|
|
291
|
+
"commands/claude/dv/build.md",
|
|
292
|
+
"commands/codex/prompts/dv-build.md",
|
|
293
|
+
"commands/gemini/dv/build.toml"
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
for (const file of buildPrompts) {
|
|
297
|
+
const content = read(file);
|
|
298
|
+
assert.match(content, /BUILD SUCCESSFUL/, `${file} should explicitly treat build success as compile-only evidence`);
|
|
299
|
+
assert.match(
|
|
300
|
+
content,
|
|
301
|
+
/da-vinci audit --mode completion --change <change-id> <project-path>/,
|
|
302
|
+
`${file} should require completion audit before terminal completion claims`
|
|
303
|
+
);
|
|
304
|
+
assert.match(
|
|
305
|
+
content,
|
|
306
|
+
/do not report `design complete` or `workflow complete`/i,
|
|
307
|
+
`${file} should prevent terminal completion claims while in-scope tasks remain`
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
runTest("continue prompts keep build routing blocked while design gates are unresolved", () => {
|
|
313
|
+
const continuePrompts = [
|
|
314
|
+
"commands/claude/dv/continue.md",
|
|
315
|
+
"commands/codex/prompts/dv-continue.md",
|
|
316
|
+
"commands/gemini/dv/continue.toml"
|
|
317
|
+
];
|
|
318
|
+
|
|
319
|
+
for (const file of continuePrompts) {
|
|
320
|
+
const content = read(file);
|
|
321
|
+
assert.match(
|
|
322
|
+
content,
|
|
323
|
+
/missing shell-visible project-local `.pen`/,
|
|
324
|
+
`${file} should block build routing when project-local .pen persistence is unresolved`
|
|
325
|
+
);
|
|
326
|
+
assert.match(
|
|
327
|
+
content,
|
|
328
|
+
/active\/unclosed Pencil session/,
|
|
329
|
+
`${file} should block build routing when Pencil session is still active`
|
|
330
|
+
);
|
|
331
|
+
assert.match(
|
|
332
|
+
content,
|
|
333
|
+
/design-supervisor review still BLOCK\/unaccepted/,
|
|
334
|
+
`${file} should block build routing when required design-supervisor review has not cleared`
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
|
|
289
339
|
console.log("All mode consistency tests passed.");
|
|
@@ -149,4 +149,44 @@ runTest("pencil-session end fails when live payload is stale", () => {
|
|
|
149
149
|
});
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
+
runTest("pencil-session end requires live payload unless force is used", () => {
|
|
153
|
+
const fixture = JSON.parse(fs.readFileSync(fixturePath, "utf8"));
|
|
154
|
+
const tempDir = createTempDir();
|
|
155
|
+
const projectRoot = path.join(tempDir, "project");
|
|
156
|
+
const homeDir = path.join(tempDir, "home");
|
|
157
|
+
const penPath = path.join(projectRoot, ".da-vinci", "designs", "cipher.pen");
|
|
158
|
+
const { nodesFile, variablesFile } = writePayloadFiles(tempDir, fixture);
|
|
159
|
+
|
|
160
|
+
beginPencilSession({
|
|
161
|
+
projectPath: projectRoot,
|
|
162
|
+
penPath,
|
|
163
|
+
homeDir
|
|
164
|
+
});
|
|
165
|
+
persistPencilSession({
|
|
166
|
+
projectPath: projectRoot,
|
|
167
|
+
penPath,
|
|
168
|
+
nodesFile,
|
|
169
|
+
variablesFile,
|
|
170
|
+
version: fixture.version,
|
|
171
|
+
homeDir
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
assert.throws(
|
|
175
|
+
() =>
|
|
176
|
+
endPencilSession({
|
|
177
|
+
projectPath: projectRoot,
|
|
178
|
+
penPath,
|
|
179
|
+
homeDir
|
|
180
|
+
}),
|
|
181
|
+
/without a live MCP snapshot/i
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
endPencilSession({
|
|
185
|
+
projectPath: projectRoot,
|
|
186
|
+
penPath,
|
|
187
|
+
homeDir,
|
|
188
|
+
force: true
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
|
|
152
192
|
console.log("All Pencil session tests passed.");
|