@xenonbyte/da-vinci-workflow 0.1.13 → 0.1.15

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 +21 -1
  2. package/README.md +23 -1
  3. package/README.zh-CN.md +23 -1
  4. package/SKILL.md +15 -0
  5. package/commands/claude/dv/design.md +2 -0
  6. package/commands/claude/dv/verify.md +2 -0
  7. package/commands/codex/prompts/dv-design.md +2 -0
  8. package/commands/codex/prompts/dv-verify.md +1 -0
  9. package/commands/gemini/dv/design.toml +2 -0
  10. package/commands/gemini/dv/verify.toml +1 -0
  11. package/docs/mcp-aware-gate-implementation.md +291 -0
  12. package/docs/mcp-aware-gate-tests.md +244 -0
  13. package/docs/mcp-aware-gate.md +246 -0
  14. package/docs/mode-use-cases.md +2 -0
  15. package/docs/prompt-presets/README.md +1 -0
  16. package/docs/prompt-presets/desktop-app.md +4 -0
  17. package/docs/prompt-presets/mobile-app.md +4 -0
  18. package/docs/prompt-presets/tablet-app.md +4 -0
  19. package/docs/prompt-presets/web-app.md +4 -0
  20. package/docs/visual-adapters.md +9 -0
  21. package/docs/visual-assist-presets/README.md +4 -2
  22. package/docs/visual-assist-presets/desktop-app.md +2 -0
  23. package/docs/visual-assist-presets/mobile-app.md +2 -0
  24. package/docs/visual-assist-presets/tablet-app.md +2 -0
  25. package/docs/visual-assist-presets/web-app.md +2 -0
  26. package/docs/workflow-examples.md +9 -4
  27. package/docs/zh-CN/mcp-aware-gate-implementation.md +290 -0
  28. package/docs/zh-CN/mcp-aware-gate-tests.md +244 -0
  29. package/docs/zh-CN/mcp-aware-gate.md +249 -0
  30. package/docs/zh-CN/mode-use-cases.md +3 -0
  31. package/docs/zh-CN/prompt-presets/README.md +1 -0
  32. package/docs/zh-CN/prompt-presets/desktop-app.md +4 -0
  33. package/docs/zh-CN/prompt-presets/mobile-app.md +4 -0
  34. package/docs/zh-CN/prompt-presets/tablet-app.md +4 -0
  35. package/docs/zh-CN/prompt-presets/web-app.md +4 -0
  36. package/docs/zh-CN/visual-adapters.md +9 -0
  37. package/docs/zh-CN/visual-assist-presets/README.md +5 -3
  38. package/docs/zh-CN/visual-assist-presets/desktop-app.md +2 -0
  39. package/docs/zh-CN/visual-assist-presets/mobile-app.md +2 -0
  40. package/docs/zh-CN/visual-assist-presets/tablet-app.md +2 -0
  41. package/docs/zh-CN/visual-assist-presets/web-app.md +2 -0
  42. package/docs/zh-CN/workflow-examples.md +9 -4
  43. package/examples/greenfield-spec-markupflow/DA-VINCI.md +1 -0
  44. package/examples/greenfield-spec-markupflow/README.md +3 -0
  45. package/examples/greenfield-spec-markupflow/design-registry.md +3 -0
  46. package/examples/greenfield-spec-markupflow/pencil-design.md +4 -0
  47. package/lib/audit.js +348 -0
  48. package/lib/cli.js +47 -1
  49. package/lib/mcp-runtime-gate.js +342 -0
  50. package/package.json +3 -2
  51. package/references/artifact-templates.md +35 -3
  52. package/references/checkpoints.md +69 -1
  53. package/references/design-inputs.md +9 -1
  54. package/references/layout-hygiene.md +117 -0
  55. package/references/pencil-design-to-code.md +8 -0
  56. package/scripts/test-mcp-runtime-gate.js +199 -0
@@ -0,0 +1,342 @@
1
+ const path = require("path");
2
+
3
+ const PASS = "PASS";
4
+ const WARN = "WARN";
5
+ const BLOCK = "BLOCK";
6
+ const SKIP = "SKIP";
7
+
8
+ function normalizeArray(value) {
9
+ return Array.isArray(value) ? value.filter(Boolean) : [];
10
+ }
11
+
12
+ function normalizeLiveScreens(liveScreens) {
13
+ return normalizeArray(liveScreens).map((screen) => ({
14
+ id: screen && screen.id ? String(screen.id) : "",
15
+ name: screen && screen.name ? String(screen.name) : ""
16
+ }));
17
+ }
18
+
19
+ function unique(values) {
20
+ return [...new Set(values)];
21
+ }
22
+
23
+ function getScreenIds(liveScreens) {
24
+ return unique(normalizeLiveScreens(liveScreens).map((screen) => screen.id).filter(Boolean));
25
+ }
26
+
27
+ function getScreenNames(liveScreens) {
28
+ return unique(normalizeLiveScreens(liveScreens).map((screen) => screen.name).filter(Boolean));
29
+ }
30
+
31
+ function normalizeEditorName(activeEditor) {
32
+ return typeof activeEditor === "string" ? activeEditor.trim() : "";
33
+ }
34
+
35
+ function normalizeRegisteredPath(registeredPenPath) {
36
+ return typeof registeredPenPath === "string" ? registeredPenPath.trim() : "";
37
+ }
38
+
39
+ function resolveProjectPath(projectRoot, targetPath) {
40
+ if (!targetPath) {
41
+ return "";
42
+ }
43
+
44
+ if (path.isAbsolute(targetPath)) {
45
+ return path.normalize(targetPath);
46
+ }
47
+
48
+ if (!projectRoot) {
49
+ return "";
50
+ }
51
+
52
+ return path.normalize(path.resolve(projectRoot, targetPath));
53
+ }
54
+
55
+ function isUnnamedEditor(activeEditor) {
56
+ const normalized = normalizeEditorName(activeEditor).toLowerCase();
57
+ return normalized === "" || normalized === "new";
58
+ }
59
+
60
+ function matchesRegisteredPath(activeEditor, registeredPenPath, projectRoot) {
61
+ const editor = normalizeEditorName(activeEditor);
62
+ const registered = normalizeRegisteredPath(registeredPenPath);
63
+
64
+ if (!editor || !registered) {
65
+ return false;
66
+ }
67
+
68
+ const resolvedEditor = resolveProjectPath(projectRoot, editor);
69
+ const resolvedRegistered = resolveProjectPath(projectRoot, registered);
70
+
71
+ if (resolvedEditor && resolvedRegistered) {
72
+ return resolvedEditor === resolvedRegistered;
73
+ }
74
+
75
+ const editorHasPathSeparators = editor.includes("/") || editor.includes("\\");
76
+ if (editorHasPathSeparators) {
77
+ return false;
78
+ }
79
+
80
+ return path.basename(editor) === path.basename(registered);
81
+ }
82
+
83
+ function missingIds(expectedIds, actualIds) {
84
+ const actualSet = new Set(actualIds);
85
+ return unique(expectedIds).filter((id) => !actualSet.has(id));
86
+ }
87
+
88
+ function derivePhase(snapshot) {
89
+ return snapshot.phase || "completion";
90
+ }
91
+
92
+ function evaluateSourceConvergence(snapshot) {
93
+ const notes = [];
94
+ const activeEditor = normalizeEditorName(snapshot.activeEditor);
95
+ const registeredPenPath = normalizeRegisteredPath(snapshot.registeredPenPath);
96
+ const projectRoot = typeof snapshot.projectRoot === "string" ? snapshot.projectRoot.trim() : "";
97
+ const shellVisiblePenExists = Boolean(snapshot.shellVisiblePenExists);
98
+ const documentedReconciliation = Boolean(snapshot.documentedReconciliation);
99
+ const noNewPencilEditsYet = Boolean(snapshot.noNewPencilEditsYet);
100
+
101
+ if (Boolean(snapshot.mcpAvailable) === false) {
102
+ return {
103
+ status: WARN,
104
+ notes: ["Pencil MCP is unavailable, so runtime source convergence could not be fully checked."]
105
+ };
106
+ }
107
+
108
+ if (isUnnamedEditor(activeEditor)) {
109
+ return {
110
+ status: BLOCK,
111
+ notes: ["Active Pencil editor is still an unnamed live document such as `new`."]
112
+ };
113
+ }
114
+
115
+ if (!registeredPenPath) {
116
+ return {
117
+ status: BLOCK,
118
+ notes: ["No registered project-local `.pen` path was provided for runtime comparison."]
119
+ };
120
+ }
121
+
122
+ if (!shellVisiblePenExists) {
123
+ return {
124
+ status: BLOCK,
125
+ notes: ["The registered project-local `.pen` file is not shell-visible on disk."]
126
+ };
127
+ }
128
+
129
+ if (!matchesRegisteredPath(activeEditor, registeredPenPath, projectRoot)) {
130
+ if (documentedReconciliation) {
131
+ return {
132
+ status: WARN,
133
+ notes: [
134
+ "Active Pencil editor does not match the registered project-local `.pen` path, but a documented reconciliation was provided."
135
+ ]
136
+ };
137
+ }
138
+
139
+ return {
140
+ status: BLOCK,
141
+ notes: ["Active Pencil editor does not match the registered project-local `.pen` path."]
142
+ };
143
+ }
144
+
145
+ if (noNewPencilEditsYet) {
146
+ notes.push("No new Pencil edits were recorded yet; source convergence is only provisionally confirmed.");
147
+ return {
148
+ status: WARN,
149
+ notes
150
+ };
151
+ }
152
+
153
+ return {
154
+ status: PASS,
155
+ notes: ["Active Pencil editor matches the registered project-local `.pen` source and the file exists on disk."]
156
+ };
157
+ }
158
+
159
+ function evaluateScreenPresence(snapshot) {
160
+ const phase = derivePhase(snapshot);
161
+ const claimedAnchorIds = normalizeArray(snapshot.claimedAnchorIds);
162
+ const claimedReviewedScreenIds = normalizeArray(snapshot.claimedReviewedScreenIds);
163
+ const reviewTargets = normalizeArray(snapshot.reviewTargets);
164
+ const liveIds = getScreenIds(snapshot.liveScreens);
165
+
166
+ if (Boolean(snapshot.mcpAvailable) === false) {
167
+ return {
168
+ status: WARN,
169
+ notes: ["Pencil MCP is unavailable, so live screen presence could not be fully checked."]
170
+ };
171
+ }
172
+
173
+ if (phase === "first_write" && claimedAnchorIds.length === 0 && claimedReviewedScreenIds.length === 0 && reviewTargets.length === 0) {
174
+ return {
175
+ status: SKIP,
176
+ notes: ["No anchor or review ids were declared yet, so screen-presence checks were skipped at first-write stage."]
177
+ };
178
+ }
179
+
180
+ const missingAnchorIds = missingIds(claimedAnchorIds, liveIds);
181
+ const missingReviewedIds = missingIds(claimedReviewedScreenIds, liveIds);
182
+ const missingReviewTargets = missingIds(reviewTargets, liveIds);
183
+
184
+ const notes = [];
185
+ if (missingAnchorIds.length > 0) {
186
+ notes.push(`Missing claimed anchor ids in the active editor: ${missingAnchorIds.join(", ")}`);
187
+ }
188
+ if (missingReviewedIds.length > 0) {
189
+ notes.push(`Missing claimed reviewed screen ids in the active editor: ${missingReviewedIds.join(", ")}`);
190
+ }
191
+ if (missingReviewTargets.length > 0) {
192
+ notes.push(`Missing screenshot target ids in the active editor: ${missingReviewTargets.join(", ")}`);
193
+ }
194
+
195
+ if (notes.length > 0) {
196
+ return {
197
+ status: BLOCK,
198
+ notes
199
+ };
200
+ }
201
+
202
+ if (claimedAnchorIds.length === 0 && claimedReviewedScreenIds.length === 0 && reviewTargets.length === 0) {
203
+ return {
204
+ status: WARN,
205
+ notes: ["No claimed anchor, reviewed, or screenshot target ids were provided for runtime verification."]
206
+ };
207
+ }
208
+
209
+ return {
210
+ status: PASS,
211
+ notes: ["Claimed anchor surfaces and review targets resolve in the active live editor."]
212
+ };
213
+ }
214
+
215
+ function evaluateReviewExecution(snapshot) {
216
+ const phase = derivePhase(snapshot);
217
+ const claimedReviewedScreenIds = normalizeArray(snapshot.claimedReviewedScreenIds);
218
+ const reviewTargets = normalizeArray(snapshot.reviewTargets);
219
+ const reviewBlockersIgnored = Boolean(snapshot.reviewBlockersIgnored);
220
+ const broadExpansionRequested = Boolean(snapshot.broadExpansionRequested);
221
+
222
+ if (Boolean(snapshot.mcpAvailable) === false) {
223
+ return {
224
+ status: WARN,
225
+ notes: ["Pencil MCP is unavailable, so runtime review execution could not be fully checked."]
226
+ };
227
+ }
228
+
229
+ if (phase === "first_write") {
230
+ return {
231
+ status: SKIP,
232
+ notes: ["Screenshot review is not required at first-write stage."]
233
+ };
234
+ }
235
+
236
+ if (claimedReviewedScreenIds.length === 0 && reviewTargets.length === 0) {
237
+ if (phase === "completion" || broadExpansionRequested) {
238
+ return {
239
+ status: BLOCK,
240
+ notes: ["No reviewed screen ids or screenshot targets were recorded for a stage that requires runtime review evidence."]
241
+ };
242
+ }
243
+
244
+ return {
245
+ status: WARN,
246
+ notes: ["No reviewed screen ids or screenshot targets were recorded yet."]
247
+ };
248
+ }
249
+
250
+ if (reviewBlockersIgnored) {
251
+ return {
252
+ status: BLOCK,
253
+ notes: ["Screenshot review recorded blocker-level issues that were ignored while the surface was still treated as approved."]
254
+ };
255
+ }
256
+
257
+ return {
258
+ status: PASS,
259
+ notes: ["Runtime review evidence exists for the approved surfaces."]
260
+ };
261
+ }
262
+
263
+ function combineStatuses(statuses) {
264
+ if (statuses.includes(BLOCK)) {
265
+ return BLOCK;
266
+ }
267
+ if (statuses.includes(WARN)) {
268
+ return WARN;
269
+ }
270
+ if (statuses.every((status) => status === SKIP)) {
271
+ return WARN;
272
+ }
273
+ return PASS;
274
+ }
275
+
276
+ function evaluateMcpRuntimeGate(snapshot = {}) {
277
+ const sourceConvergence = evaluateSourceConvergence(snapshot);
278
+ const screenPresence = evaluateScreenPresence(snapshot);
279
+ const reviewExecution = evaluateReviewExecution(snapshot);
280
+
281
+ const finalStatus = combineStatuses([
282
+ sourceConvergence.status,
283
+ screenPresence.status === SKIP ? PASS : screenPresence.status,
284
+ reviewExecution.status === SKIP ? PASS : reviewExecution.status
285
+ ]);
286
+
287
+ return {
288
+ phase: derivePhase(snapshot),
289
+ sourceConvergence,
290
+ screenPresence,
291
+ reviewExecution,
292
+ finalStatus,
293
+ activeEditor: normalizeEditorName(snapshot.activeEditor),
294
+ registeredPenPath:
295
+ typeof snapshot.registeredPenPath === "string" ? snapshot.registeredPenPath.trim() : "",
296
+ shellVisiblePenPath:
297
+ typeof snapshot.shellVisiblePenPath === "string" ? snapshot.shellVisiblePenPath.trim() : "",
298
+ shellVisiblePenExists: Boolean(snapshot.shellVisiblePenExists),
299
+ claimedAnchorIds: normalizeArray(snapshot.claimedAnchorIds),
300
+ claimedReviewedScreenIds: normalizeArray(snapshot.claimedReviewedScreenIds),
301
+ reviewTargets: normalizeArray(snapshot.reviewTargets),
302
+ liveScreenIds: getScreenIds(snapshot.liveScreens),
303
+ liveScreenNames: getScreenNames(snapshot.liveScreens)
304
+ };
305
+ }
306
+
307
+ function formatMcpRuntimeGateSection(snapshot, result, options = {}) {
308
+ const timestamp = options.timestamp || new Date().toISOString();
309
+ const notes = [
310
+ ...result.sourceConvergence.notes,
311
+ ...result.screenPresence.notes,
312
+ ...result.reviewExecution.notes
313
+ ];
314
+
315
+ return [
316
+ "## MCP Runtime Gate",
317
+ `- Time: ${timestamp}`,
318
+ `- Phase: ${result.phase}`,
319
+ `- Active editor: ${result.activeEditor || "(unavailable)"}`,
320
+ `- Registered \`.pen\` path: ${result.registeredPenPath || "(missing)"}`,
321
+ `- Shell-visible \`.pen\` path: ${result.shellVisiblePenPath || "(missing)"}`,
322
+ `- Shell-visible \`.pen\` exists: ${result.shellVisiblePenExists ? "yes" : "no"}`,
323
+ `- Claimed anchor ids: ${result.claimedAnchorIds.length > 0 ? result.claimedAnchorIds.join(", ") : "(none)"}`,
324
+ `- Reviewed screen ids: ${result.claimedReviewedScreenIds.length > 0 ? result.claimedReviewedScreenIds.join(", ") : "(none)"}`,
325
+ `- Screenshot target ids: ${result.reviewTargets.length > 0 ? result.reviewTargets.join(", ") : "(none)"}`,
326
+ `- Live screen ids: ${result.liveScreenIds.length > 0 ? result.liveScreenIds.join(", ") : "(none)"}`,
327
+ `- Source convergence: ${result.sourceConvergence.status}`,
328
+ `- Screen presence: ${result.screenPresence.status}`,
329
+ `- Review execution: ${result.reviewExecution.status}`,
330
+ `- Final runtime gate status: ${result.finalStatus}`,
331
+ `- Notes: ${notes.length > 0 ? notes.join(" | ") : "none"}`
332
+ ].join("\n");
333
+ }
334
+
335
+ module.exports = {
336
+ PASS,
337
+ WARN,
338
+ BLOCK,
339
+ SKIP,
340
+ evaluateMcpRuntimeGate,
341
+ formatMcpRuntimeGateSection
342
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xenonbyte/da-vinci-workflow",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
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"
@@ -21,7 +21,8 @@
21
21
  ],
22
22
  "scripts": {
23
23
  "postinstall": "node scripts/postinstall.js",
24
- "validate-assets": "node scripts/validate-assets.js"
24
+ "validate-assets": "node scripts/validate-assets.js",
25
+ "test:mcp-runtime-gate": "node scripts/test-mcp-runtime-gate.js"
25
26
  },
26
27
  "engines": {
27
28
  "node": ">=18"
@@ -36,6 +36,7 @@ project/
36
36
  ├── pencil-bindings.md
37
37
  ├── tasks.md
38
38
  ├── verification.md
39
+ ├── exports/
39
40
  └── specs/
40
41
  └── <capability>/spec.md
41
42
  ```
@@ -175,8 +176,8 @@ Use this structure:
175
176
 
176
177
  Field meaning:
177
178
 
178
- - `Preferred adapters`: desired local-skill priority order
179
- - `Scope`: allowed presentation-quality influence areas only
179
+ - `Preferred adapters`: desired local-skill priority order using adapter names that actually exist in the current environment
180
+ - `Scope`: allowed presentation-quality influence areas only, including anchor-surface composition when redesign quality matters
180
181
  - `Fallback`: what to do when preferred adapters are unavailable
181
182
  - `Require Adapter`: whether missing adapters should block the workflow
182
183
 
@@ -214,6 +215,11 @@ Use this structure:
214
215
  - workspace density
215
216
  - responsiveness expectations
216
217
 
218
+ ## Layout Hygiene Profile
219
+ - Resolved profile: mobile / tablet / desktop / web
220
+ - Per-surface overrides when mixed product surfaces require them
221
+ - Blocker classes to watch during screenshot review
222
+
217
223
  ## Notes
218
224
  - explicit user preferences
219
225
  - inferred preferences
@@ -243,6 +249,7 @@ Use this structure:
243
249
  - Which `.pen` file is authoritative
244
250
  - Why that file should be preferred over live-only or external sources
245
251
  - whether the active Pencil editor matches that same path
252
+ - whether the active Pencil editor is still an unnamed live document that must be reconciled before completion
246
253
 
247
254
  ## Visual Adapter Resolution
248
255
  - Requested adapters
@@ -483,7 +490,9 @@ Use this structure:
483
490
  - Which 1-3 anchor screens were designed first
484
491
  - Structural-delta summary for each anchor surface
485
492
  - Screenshot review status for each anchor
493
+ - Applied layout-hygiene profile for each reviewed anchor surface
486
494
  - Whether screenshot review found hierarchy, spacing, clarity, or inconsistency issues
495
+ - Whether screenshot review found blocker-level layout-hygiene issues
487
496
  - Whether each anchor was revised after screenshot review
488
497
  - Whether broad multi-screen expansion is approved yet
489
498
 
@@ -504,7 +513,30 @@ Use this structure:
504
513
  - Which states still need design coverage
505
514
 
506
515
  ## Screenshots
507
- - Reference image paths or exported nodes
516
+ - Reference image paths or exported nodes under `.da-vinci/changes/<change-id>/exports/`
517
+
518
+ ## MCP Runtime Gate
519
+ - Time
520
+ - Phase
521
+ - Active editor
522
+ - Registered `.pen` path
523
+ - Shell-visible `.pen` path
524
+ - Shell-visible `.pen` exists
525
+ - Claimed anchor ids
526
+ - Reviewed screen ids
527
+ - Screenshot target ids
528
+ - Live screen ids
529
+ - `Source convergence`
530
+ - `Screen presence`
531
+ - `Review execution`
532
+ - `Final runtime gate status`
533
+ - Notes
534
+
535
+ ## Checkpoint Status
536
+ - `mcp runtime gate`
537
+ - `design-source checkpoint`
538
+ - `design checkpoint`
539
+ - `completion gate`
508
540
 
509
541
  ## Implementation Notes
510
542
  - Important layout or styling constraints to preserve in code
@@ -48,6 +48,7 @@ Check:
48
48
  - the active mode is correct
49
49
  - the starting material is stable enough to write specs
50
50
  - product form factor and visual direction are known, inferred, or explicitly deferred
51
+ - the form factor is specific enough to resolve the active layout-hygiene profile before screenshot review begins
51
52
  - candidate pages or current pages are clear enough to move into `page-map.md`
52
53
  - open questions are explicitly tracked
53
54
  - workflow artifacts are being written to standard locations, especially keeping `.da-vinci/designs/` for `.pen` files rather than markdown notes
@@ -101,6 +102,7 @@ Check:
101
102
  - when a primary adapter is active, the workflow wrote a visual thesis, content plan, and interaction thesis before broad anchor-surface generation
102
103
  - complex redesigns have 1-3 fully composed anchor surfaces reviewed before broad multi-screen expansion
103
104
  - each anchor surface includes a short explanation of how its composition differs structurally from the current layout truth
105
+ - the relevant form-factor-specific layout-hygiene profile was applied to each reviewed anchor surface and any other screen being treated as approval-ready
104
106
  - each page has a clear visual anchor or primary working surface
105
107
  - section hierarchy is readable without relying on decorative chrome
106
108
  - the design does not collapse into generic card-grid or border-heavy filler UI
@@ -118,10 +120,13 @@ Result meanings:
118
120
 
119
121
  Automatic failures:
120
122
 
123
+ - if anchor-surface design starts before the required discovery artifacts and design-source artifacts exist in their standard locations, treat the design checkpoint as `BLOCK`
121
124
  - if broad Pencil generation starts before anchor surfaces are compositionally stable, treat the design checkpoint as `BLOCK`
122
125
  - if more than roughly 20% of a screen's primary content area is unresolved placeholder scaffolding, treat the design checkpoint as `BLOCK`
123
126
  - if multiple screens are effectively the same scaffold with title changes, treat the design checkpoint as `BLOCK`
124
127
  - if screenshot review or image analysis calls out hierarchy, spacing, clarity, inconsistency, or unresolved-placeholder issues and the workflow marks the screen as passed without revision, treat the design checkpoint as `BLOCK`
128
+ - if any blocker-level condition from the active form-factor-specific layout-hygiene profile is present on a reviewed screen, treat the design checkpoint as `BLOCK`
129
+ - if an anchor surface required repeated rolled-back Pencil batches from unsupported properties and the workflow still treats that surface as approved without a clean schema-safe pass, treat the design checkpoint as `BLOCK`
125
130
  - if a redesign screen materially mirrors the current XML grouping with only recolor, spacing tweaks, or minor rearrangement, treat the design checkpoint as `BLOCK`
126
131
 
127
132
  ## `design-source checkpoint`
@@ -133,9 +138,11 @@ Check:
133
138
  - `design-registry.md` records one specific preferred project-local `.pen` path
134
139
  - the preferred `.pen` path is workflow-owned state, not a hand-wavy placeholder
135
140
  - the active Pencil editor path matches the preferred project-local `.pen` path, or the mismatch has been reconciled explicitly
141
+ - an unnamed live editor such as `new` is not being treated as the persisted project-local design source
136
142
  - if the workflow created or edited Pencil work, the preferred project-local `.pen` file exists as a shell-visible file immediately after the first successful Pencil write, not just at workflow close
137
143
  - if Pencil MCP only exposed a live document, the workflow reconstructed and wrote the registered project-local `.pen` file from MCP-readable document data before continuing
138
- - `.da-vinci/designs/` is being used cleanly for project-local `.pen` files rather than mixed with workflow markdown
144
+ - `.da-vinci/designs/` is being used cleanly for project-local `.pen` files rather than mixed with workflow markdown, screenshots, or other exports
145
+ - exported screenshots are stored under `.da-vinci/changes/<change-id>/exports/` and are not being used as a substitute for the `.pen` source
139
146
  - `design-registry.md`, `pencil-design.md`, and `pencil-bindings.md` describe the same active project-local `.pen` source clearly enough to map and implement from
140
147
 
141
148
  Result meanings:
@@ -144,6 +151,36 @@ Result meanings:
144
151
  - `WARN`: the workflow is intentionally staying on an older but still shell-visible baseline, or no new Pencil edits have happened yet
145
152
  - `BLOCK`: the registered `.pen` path, the active Pencil work, and the shell-visible project-local file do not agree well enough to treat the design source as traceable
146
153
 
154
+ ## `mcp runtime gate`
155
+
156
+ Run inside the active design session when Pencil MCP is available:
157
+
158
+ - after the first successful Pencil write
159
+ - before broad expansion beyond approved anchor surfaces
160
+ - before any terminal `design complete` or `workflow complete` claim
161
+
162
+ Check:
163
+
164
+ - the active editor is not still an unnamed live document such as `new`
165
+ - the active editor, registered project-local `.pen` path, and shell-visible `.pen` file are converged strongly enough to trust the runtime source
166
+ - claimed anchor ids exist in the active live editor
167
+ - claimed reviewed screens and screenshot targets exist in the active live editor
168
+ - screenshot-reviewed surfaces were not treated as approved while blocker-level review findings were ignored
169
+ - runtime-gate evidence is recorded in `pencil-design.md`
170
+
171
+ Result meanings:
172
+
173
+ - `PASS`: runtime source and live screen state are trustworthy enough to continue
174
+ - `WARN`: runtime evidence is partial or intentionally deferred, but not yet contradictory
175
+ - `BLOCK`: runtime truth is too weak or contradictory to continue or claim completion
176
+
177
+ Automatic failures:
178
+
179
+ - if the active editor is still `new`, treat the runtime gate as `BLOCK`
180
+ - if live anchor surfaces exist only in the current editor while no shell-visible `.pen` exists, treat the runtime gate as `BLOCK`
181
+ - if claimed anchor ids, reviewed screen ids, or screenshot targets do not resolve in the active editor, treat the runtime gate as `BLOCK`
182
+ - if blocker-level review findings were ignored while the workflow still approved the surface, treat the runtime gate as `BLOCK`
183
+
147
184
  ## `mapping checkpoint`
148
185
 
149
186
  Run after `design-registry.md` and `pencil-bindings.md`.
@@ -154,6 +191,7 @@ Check:
154
191
  - the preferred `.pen` path in `design-registry.md` is workflow-owned and specific, not hand-wavy
155
192
  - the active Pencil editor path matches the preferred project-local `.pen` path, or the project-local file has been reconstructed explicitly
156
193
  - the preferred project-local `.pen` file exists as a shell-visible file when the workflow created or edited Pencil work
194
+ - exported screenshots are treated only as review artifacts, not as page-to-design source of truth
157
195
  - each implementation page has a Pencil page or an explicit exception
158
196
  - shared layouts and shared regions are bound clearly enough to implement from
159
197
  - route names and Pencil names are traceable
@@ -202,9 +240,39 @@ Examples of `BLOCK`:
202
240
  - page-to-Pencil bindings are too weak to know which redesign screen to follow
203
241
  - `design-registry.md` points to a project-local `.pen` path, but the workflow actually edited a different live editor document and did not reconcile the mismatch
204
242
  - the workflow created or edited Pencil pages but no shell-visible `.pen` file exists under the registered project-local path
243
+ - `.da-vinci/designs/` contains workflow markdown or screenshot exports instead of `.pen` files only
205
244
  - required permissions, environment access, or protected files are unavailable
206
245
  - the implementation would overwrite the project baseline in a destructive way without an explicit go-ahead
207
246
 
247
+ ## `completion gate`
248
+
249
+ Apply before reporting `design complete`, `workflow complete`, or any equivalent terminal state.
250
+
251
+ When shell access is available:
252
+
253
+ - use `da-vinci audit --mode integrity <project-path>` as a filesystem-truth sanity check during active work
254
+ - use `da-vinci audit --mode completion --change <change-id> <project-path>` before any terminal completion claim
255
+ - treat an audit failure as `BLOCK`
256
+
257
+ Check:
258
+
259
+ - the artifacts required for the active intent actually exist in their standard locations
260
+ - for `redesign-from-code` with active Pencil work, this normally includes `project-inventory.md`, `page-map.md`, `design-registry.md`, `design-brief.md`, `design.md`, `pencil-design.md`, and `pencil-bindings.md`
261
+ - if Pencil work happened, `design-source checkpoint` is at least `PASS`
262
+ - if design output is being treated as ready, `design checkpoint` is at least `PASS` or an explicitly accepted `WARN`
263
+ - if Pencil MCP is available, `mcp runtime gate` is at least `PASS` or an explicitly accepted `WARN`
264
+ - the registered project-local `.pen` file exists as a shell-visible file
265
+ - the active Pencil editor is not still an unnamed live document such as `new`
266
+ - `.da-vinci/designs/` contains `.pen` files only
267
+ - exported screenshots, if any, live under `.da-vinci/changes/<change-id>/exports/`
268
+ - screenshots are recorded only as review artifacts and not described as the persisted design source
269
+
270
+ Automatic failures:
271
+
272
+ - if the workflow claims the `.pen` source exists only "in memory", treat completion as `BLOCK`
273
+ - if the workflow claims success after exporting PNGs but without a shell-visible `.pen`, treat completion as `BLOCK`
274
+ - if the workflow reports completion without the required standard artifacts for the active stage, treat completion as `BLOCK`
275
+
208
276
  ## `execution checkpoint`
209
277
 
210
278
  Run after each top-level task group during implementation.
@@ -9,7 +9,7 @@ Check for `DA-VINCI.md` first, then check whether the project already has persis
9
9
  - if it exists, treat it as the project visual contract
10
10
  - if `DA-VINCI.md` declares preferred visual adapters, treat them as optional design-assist preferences
11
11
  - if `.da-vinci/designs/*.pen` exists, treat those files as project-local design inputs and record the exact preferred path in `design-registry.md`
12
- - treat non-`.pen` files inside `.da-vinci/designs/` as artifact-placement drift that must be corrected instead of as valid design inputs
12
+ - treat non-`.pen` files inside `.da-vinci/designs/` as artifact-placement drift that must be corrected instead of as valid design inputs; screenshot exports belong under `.da-vinci/changes/<change-id>/exports/`
13
13
  - if it does not exist, generate it from the best stable inputs before broad Pencil page generation
14
14
  - avoid re-deriving the visual language page by page
15
15
 
@@ -37,6 +37,7 @@ If Pencil MCP is currently pointing at a different active editor:
37
37
 
38
38
  - switch to the registered project-local path when possible
39
39
  - otherwise reconstruct the project-local `.pen` file from MCP-readable document data before treating the workflow as traceable
40
+ - do not treat an unnamed live editor such as `new` as the resolved project-local path
40
41
 
41
42
  ## Minimum Inputs
42
43
 
@@ -72,6 +73,11 @@ Collect or infer:
72
73
  - whether adapter use is required or optional
73
74
  - fallback expectation when adapters are unavailable
74
75
 
76
+ 6. layout hygiene profile
77
+ - resolved from the product form factor
78
+ - per-surface override only when the product intentionally mixes different surface classes
79
+ - blocker classes that must fail screenshot review
80
+
75
81
  ## Inference Order
76
82
 
77
83
  Infer in this order:
@@ -97,6 +103,8 @@ Examples:
97
103
 
98
104
  Write stable answers into `design-brief.md`.
99
105
 
106
+ Record the resolved layout-hygiene profile there as well, including any intentional per-surface overrides for mixed products.
107
+
100
108
  If `DA-VINCI.md` did not already exist, generate it from those stable answers and save it as the project visual baseline.
101
109
 
102
110
  If Pencil creates or updates a baseline during the workflow: