@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +40 -54
  3. package/README.zh-CN.md +34 -54
  4. package/SKILL.md +4 -0
  5. package/commands/claude/dv/build.md +6 -0
  6. package/commands/claude/dv/continue.md +5 -0
  7. package/commands/codex/prompts/dv-build.md +4 -0
  8. package/commands/codex/prompts/dv-continue.md +5 -0
  9. package/commands/gemini/dv/build.toml +4 -0
  10. package/commands/gemini/dv/continue.toml +5 -0
  11. package/docs/codex-natural-language-usage.md +3 -0
  12. package/docs/dv-command-reference.md +10 -0
  13. package/docs/mode-use-cases.md +2 -0
  14. package/docs/pencil-rendering-workflow.md +16 -0
  15. package/docs/prompt-entrypoints.md +7 -0
  16. package/docs/prompt-presets/README.md +2 -0
  17. package/docs/prompt-presets/desktop-app.md +4 -0
  18. package/docs/prompt-presets/mobile-app.md +4 -0
  19. package/docs/prompt-presets/tablet-app.md +4 -0
  20. package/docs/prompt-presets/web-app.md +4 -0
  21. package/docs/visual-adapters.md +24 -80
  22. package/docs/visual-assist-presets/desktop-app.md +20 -68
  23. package/docs/visual-assist-presets/mobile-app.md +20 -68
  24. package/docs/visual-assist-presets/tablet-app.md +20 -68
  25. package/docs/visual-assist-presets/web-app.md +20 -68
  26. package/docs/workflow-examples.md +2 -0
  27. package/docs/workflow-overview.md +11 -0
  28. package/docs/zh-CN/codex-natural-language-usage.md +3 -0
  29. package/docs/zh-CN/dv-command-reference.md +10 -0
  30. package/docs/zh-CN/mode-use-cases.md +2 -0
  31. package/docs/zh-CN/pencil-rendering-workflow.md +16 -0
  32. package/docs/zh-CN/prompt-entrypoints.md +7 -0
  33. package/docs/zh-CN/prompt-presets/README.md +2 -0
  34. package/docs/zh-CN/prompt-presets/desktop-app.md +3 -0
  35. package/docs/zh-CN/prompt-presets/mobile-app.md +3 -0
  36. package/docs/zh-CN/prompt-presets/tablet-app.md +3 -0
  37. package/docs/zh-CN/prompt-presets/web-app.md +3 -0
  38. package/docs/zh-CN/visual-adapters.md +24 -80
  39. package/docs/zh-CN/visual-assist-presets/desktop-app.md +20 -68
  40. package/docs/zh-CN/visual-assist-presets/mobile-app.md +20 -68
  41. package/docs/zh-CN/visual-assist-presets/tablet-app.md +20 -68
  42. package/docs/zh-CN/visual-assist-presets/web-app.md +20 -68
  43. package/docs/zh-CN/workflow-examples.md +2 -0
  44. package/docs/zh-CN/workflow-overview.md +11 -0
  45. package/examples/greenfield-spec-markupflow/DA-VINCI.md +4 -13
  46. package/lib/audit.js +455 -0
  47. package/lib/cli.js +6 -1
  48. package/lib/pencil-session.js +6 -0
  49. package/package.json +2 -1
  50. package/references/artifact-templates.md +38 -0
  51. package/references/checkpoints.md +16 -0
  52. package/references/prompt-recipes.md +5 -0
  53. package/scripts/test-audit-context-delta.js +446 -0
  54. package/scripts/test-mode-consistency.js +50 -0
  55. package/scripts/test-pencil-session.js +40 -0
  56. 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.19",
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.");