@codyswann/lisa 4.64.1 → 4.64.2
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/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +9 -8
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/lisa/.codex-plugin/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/lisa/.codex-plugin/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
- package/plugins/lisa/rules/reference/design-source-of-truth.md +32 -10
- package/plugins/lisa/scripts/design-source-gate.mjs +35 -13
- package/plugins/lisa/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/lisa/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/lisa/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/lisa/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/lisa/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/design-source-gate.mjs +35 -13
- package/plugins/lisa-agy/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-agy/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/lisa-agy/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/lisa-agy/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/lisa-agy/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +32 -10
- package/plugins/lisa-copilot/scripts/design-source-gate.mjs +35 -13
- package/plugins/lisa-copilot/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-copilot/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/lisa-copilot/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/lisa-copilot/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/lisa-copilot/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +32 -10
- package/plugins/lisa-cursor/scripts/design-source-gate.mjs +35 -13
- package/plugins/lisa-cursor/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-cursor/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/lisa-cursor/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/lisa-cursor/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/lisa-cursor/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/reference/design-source-of-truth.md +32 -10
- package/plugins/src/base/scripts/design-source-gate.mjs +35 -13
- package/plugins/src/base/skills/lisa-design-intake/SKILL.md +1 -1
- package/plugins/src/base/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/src/base/skills/lisa-quality-review/SKILL.md +2 -2
- package/plugins/src/base/skills/lisa-review-local/SKILL.md +9 -3
- package/plugins/src/base/skills/lisa-tdd-implementation/SKILL.md +2 -1
- package/plugins/src/base/skills/lisa-tracker-source-artifacts/SKILL.md +3 -1
|
@@ -18,14 +18,20 @@ One deterministic gate runs ahead of the judgement-based review and is exempt
|
|
|
18
18
|
from the confidence filtering below, because it is decided by a script rather
|
|
19
19
|
than by an agent's opinion.
|
|
20
20
|
|
|
21
|
-
**Design-source gate (`design-source-of-truth` rule).**
|
|
22
|
-
|
|
21
|
+
**Design-source gate (`design-source-of-truth` rule).** First read
|
|
22
|
+
`designSource.enabled` in `.lisa.config.json`. Only boolean `false` opts out:
|
|
23
|
+
omit the design-source review step; do not request DESIGN-SOURCE markers, Figma
|
|
24
|
+
nodes, or Figma access for this obligation. Record `SKIPPED: designSource.enabled=false`
|
|
25
|
+
in the review. Absent, true, or invalid values keep enforcement enabled.
|
|
26
|
+
The separate design-value binding review below still applies.
|
|
27
|
+
|
|
28
|
+
When enabled, run the gate against the branch diff before step 1:
|
|
23
29
|
|
|
24
30
|
```bash
|
|
25
31
|
node "${CLAUDE_PLUGIN_ROOT:-.}/scripts/design-source-gate.mjs" --base=main --head=HEAD
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
Exit 0 = PASS, exit 1 = FAIL. A FAIL is a **blocking** review finding and is
|
|
34
|
+
Exit 0 = PASS or explicit SKIPPED, exit 1 = FAIL. A FAIL is a **blocking** review finding and is
|
|
29
35
|
reported verbatim at the top of the review — it is never scored, never filtered
|
|
30
36
|
by confidence, and never demoted to a nitpick. It qualifies under
|
|
31
37
|
`convergent-review` because it names a concrete failure scenario: the design
|
|
@@ -72,7 +72,8 @@ TDD Cycle:
|
|
|
72
72
|
|
|
73
73
|
- Write the minimum production code to make the test pass
|
|
74
74
|
- Do not optimize, do not add features beyond what the test requires
|
|
75
|
-
-
|
|
75
|
+
- Read `designSource.enabled` in `.lisa.config.json` before preparing design-source instructions. Only boolean `false` opts out: omit the design-source step and do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Absent, true, or invalid values keep enforcement enabled.
|
|
76
|
+
- When enabled, for any UI surface the implementation adds or changes, the `design-source-of-truth` rule requires its design-source declaration to land in the same commit as the surface it describes — `DESIGN-SOURCE: <figma-url>` when the surface is backed by a Figma node (sync it back first if Figma access exists), or the exception marker `DESIGN-SOURCE: none — not in Figma` when it genuinely is not captured at the source. `scripts/design-source-gate.mjs` fails closed on an undeclared surface. Cite the rule; do not restate its marker grammar here.
|
|
76
77
|
- Separately, the `design-value-binding` rule governs where each *value* on that surface came from: in an axis with a published variable collection, bind the variable and use a screenshot only to verify; in an axis with none, measure and record what you derived. A literal in a typed axis is a block, not a TODO. Cite the rule; do not restate its conditions here.
|
|
77
78
|
- The goal is the simplest code that makes the test green
|
|
78
79
|
|
|
@@ -93,7 +93,9 @@ Mocks define visual *intent*, not implementation shortcut. Every UI-touching tic
|
|
|
93
93
|
|
|
94
94
|
If no existing component fits, building a new one is an explicit decision that must be recorded in the ticket (with rationale) before implementation. Lovable-generated components are never the reuse target — always use the project's own components.
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
Before adding the code-side obligation to ticket or teammate instructions, read `designSource.enabled` in `.lisa.config.json`. Only boolean `false` opts out: omit the design-source step; do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Absent, true, or invalid values keep enforcement enabled. Preserve supplied artifacts and component-reuse requirements regardless; `design-value-binding` remains independent.
|
|
97
|
+
|
|
98
|
+
When enabled, the divergence note above covers the **ticket** side of this event. The **code** side is governed by the `design-source-of-truth` rule: a UI surface built with no Figma source behind it is either synced back to Figma and annotated `DESIGN-SOURCE: <figma-url>`, or explicitly marked `DESIGN-SOURCE: none — not in Figma`, and review fails closed if neither happened. Cite the rule for the code obligation rather than restating it here — a ticket comment closes with the ticket, the annotation stays with the surface.
|
|
97
99
|
|
|
98
100
|
## 8. Preservation gate (run after creating tickets)
|
|
99
101
|
|
|
@@ -1,18 +1,41 @@
|
|
|
1
1
|
# Design Source of Truth
|
|
2
2
|
|
|
3
3
|
> Demoted from the always-on eager tier by CodySwannGT/lisa#3992. The
|
|
4
|
-
> section below is the former eager head,
|
|
4
|
+
> section below is the former eager head, maintained with the full
|
|
5
5
|
> contract follows it. Reachable on demand via [the rule index](../eager/00-rule-index.md).
|
|
6
6
|
|
|
7
7
|
## Design Source of Truth (load-bearing)
|
|
8
8
|
|
|
9
|
-
**Figma is the design source of truth, and every UI surface a change touches declares where its design came from.** A changed UI surface that neither cites a Figma node nor carries the designated marker is a contract violation — and so is a surface whose declaration the gate cannot resolve.
|
|
9
|
+
**When enabled, Figma is the design source of truth, and every UI surface a change touches declares where its design came from.** A changed UI surface that neither cites a Figma node nor carries the designated marker is a contract violation — and so is a surface whose declaration the gate cannot resolve.
|
|
10
10
|
|
|
11
11
|
**One vendor-neutral contract, cited by** `lisa-implement`, `lisa-tdd-implementation`, `lisa-review-local`, `lisa-quality-review`, and `lisa-tracker-source-artifacts` (the `leaf-only-lifecycle` / `repo-scope-split` precedent: one shared slug, never divergent per-skill prose).
|
|
12
12
|
|
|
13
|
+
## Explicit project opt-out
|
|
14
|
+
|
|
15
|
+
A project with **no design source at all** may set this in `.lisa.config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{ "designSource": { "enabled": false } }
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Only `designSource.enabled` set to boolean `false` opts out. Absent, true, and
|
|
22
|
+
invalid values retain the default enforcement. The explicit configuration is
|
|
23
|
+
the auditable record; it replaces per-file exception markers for this project.
|
|
24
|
+
The gate exits 0 with `SKIPPED: designSource.enabled=false` before resolving the
|
|
25
|
+
diff. JSON output reports `verdict: "SKIPPED"`, the config key in `reasons`, and
|
|
26
|
+
zero judged surfaces. A skip does not claim that surfaces passed inspection.
|
|
27
|
+
|
|
28
|
+
When opted out, the five consuming skills omit the design-source step from
|
|
29
|
+
plans, tickets, teammate instructions, and review; they do not ask for markers,
|
|
30
|
+
Figma nodes, or Figma access for this obligation. All declaration, sync-back,
|
|
31
|
+
and fail-closed requirements below apply only when enabled. Host design-system
|
|
32
|
+
rules, `design-value-binding`, and `bdd-e2e-coverage` remain independent and
|
|
33
|
+
unchanged. A project that has Figma must still not use `exclude` to hide its UI
|
|
34
|
+
tree from this contract.
|
|
35
|
+
|
|
13
36
|
## Membership
|
|
14
37
|
|
|
15
|
-
Membership is **surface, not repo name or file extension**: a file is in scope the moment a change makes it render something user-observable — a screen, component, layout, style token, visual state, or markup a user reads. Barrels, pure-logic modules, tests, stories, generated output, and vendored code are out. Projects narrow or widen the default detection through `designSource.include` / `designSource.exclude` in `.lisa.config.json`;
|
|
38
|
+
Membership is **surface, not repo name or file extension**: a file is in scope the moment a change makes it render something user-observable — a screen, component, layout, style token, visual state, or markup a user reads. Barrels, pure-logic modules, tests, stories, generated output, and vendored code are out. Projects narrow or widen the default detection through `designSource.include` / `designSource.exclude` in `.lisa.config.json`; those filters never turn the obligation off. Only the explicit project opt-out above does.
|
|
16
39
|
|
|
17
40
|
## The two declarations
|
|
18
41
|
|
|
@@ -39,7 +62,7 @@ Projects that carry their own design-system rules (`figma-design-system`, `desig
|
|
|
39
62
|
|
|
40
63
|
## Bootstrap and degradation
|
|
41
64
|
|
|
42
|
-
Adoption never demands a retroactive backfill: the gate judges **only the surfaces this change touched**. Pre-existing unannotated UI is burndown, recorded and worked down, not this work item's blocker.
|
|
65
|
+
Adoption never demands a retroactive backfill: the gate judges **only the surfaces this change touched**. Pre-existing unannotated UI is burndown, recorded and worked down, not this work item's blocker. A project with no design source may use the explicit project opt-out above; otherwise every changed surface still needs a declaration. Behavior obligations for the same surfaces are unchanged and still governed by `bdd-e2e-coverage`.
|
|
43
66
|
|
|
44
67
|
---
|
|
45
68
|
|
|
@@ -188,7 +211,7 @@ Two consequences worth stating plainly:
|
|
|
188
211
|
node design-source-gate.mjs --base=origin/main [--head=HEAD] [--figma-access] [--json]
|
|
189
212
|
```
|
|
190
213
|
|
|
191
|
-
Exit `0` = PASS, `1` = FAIL, `2` = usage error.
|
|
214
|
+
Exit `0` = PASS or explicit SKIPPED, `1` = FAIL, `2` = usage error. When enabled, it classifies every changed file into one status:
|
|
192
215
|
|
|
193
216
|
| Status | Verdict | Meaning |
|
|
194
217
|
|---|---|---|
|
|
@@ -231,8 +254,7 @@ so a repository with hundreds of unannotated legacy components can adopt the con
|
|
|
231
254
|
and be green on Tuesday. Pre-existing unannotated UI is **burndown**: recorded, worked down
|
|
232
255
|
opportunistically as files are touched, never treated as the current work item's blocker.
|
|
233
256
|
|
|
234
|
-
A project with no
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
BDD scenario to improve coverage: mark it, do not drop it.
|
|
257
|
+
A project with no design source may opt out explicitly using `designSource.enabled: false`.
|
|
258
|
+
Without that explicit opt-out, every changed surface still declares its source. In an enabled
|
|
259
|
+
project, deleting or excluding a surface to make the gate green is a violation of the same kind as
|
|
260
|
+
deleting a BDD scenario to improve coverage: mark it, do not drop it.
|
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
* at the source; it is the exception, not the default, and the gate reports
|
|
20
20
|
* every one of them so review can challenge it.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
22
|
+
* Projects with no design source may explicitly set `designSource.enabled`
|
|
23
|
+
* to boolean false. The gate reports SKIPPED before resolving the diff; all
|
|
24
|
+
* other values retain the default enforcement.
|
|
25
|
+
*
|
|
26
|
+
* **When enabled, the gate fails closed.** Anything it cannot resolve into one of those two
|
|
23
27
|
* declarations is a violation: no annotation, a malformed one, a file that both
|
|
24
28
|
* cites Figma and denies having a source, a changed file it could not read, or
|
|
25
29
|
* a diff it could not compute. A gate that returns PASS when it could not look
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
* to all of it — it asks only whether the design source is declared.
|
|
33
37
|
*
|
|
34
38
|
* Run it: `node design-source-gate.mjs --base=origin/main [--head=HEAD] [--json]`
|
|
35
|
-
* Exit 0 = PASS, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
39
|
+
* Exit 0 = PASS or SKIPPED, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
36
40
|
*/
|
|
37
41
|
import { execFileSync } from "node:child_process";
|
|
38
42
|
import { readFileSync, realpathSync } from "node:fs";
|
|
@@ -338,10 +342,10 @@ export const VIOLATION_STATUSES = new Set([
|
|
|
338
342
|
* files?: readonly { path: string, changeType?: string, content?: string | null }[] | null,
|
|
339
343
|
* diffError?: string | null,
|
|
340
344
|
* figmaAccess?: boolean,
|
|
341
|
-
* config?: { include?: readonly string[], exclude?: readonly string[] }
|
|
345
|
+
* config?: { enabled?: unknown, include?: readonly string[], exclude?: readonly string[] }
|
|
342
346
|
* }} input Change under evaluation.
|
|
343
347
|
* @returns {{
|
|
344
|
-
* verdict: "PASS" | "FAIL",
|
|
348
|
+
* verdict: "PASS" | "FAIL" | "SKIPPED",
|
|
345
349
|
* reasons: string[],
|
|
346
350
|
* violations: object[],
|
|
347
351
|
* exceptions: object[],
|
|
@@ -352,6 +356,21 @@ export const VIOLATION_STATUSES = new Set([
|
|
|
352
356
|
* }} The gate result.
|
|
353
357
|
*/
|
|
354
358
|
export function evaluateDesignSource(input = {}) {
|
|
359
|
+
// Only the explicit boolean opts out: a missing or mistyped setting must
|
|
360
|
+
// never silently remove enforcement from an existing adopter.
|
|
361
|
+
if (input.config?.enabled === false) {
|
|
362
|
+
return {
|
|
363
|
+
verdict: "SKIPPED",
|
|
364
|
+
reasons: ["designSource.enabled=false"],
|
|
365
|
+
violations: [],
|
|
366
|
+
exceptions: [],
|
|
367
|
+
syncBackPreferred: [],
|
|
368
|
+
sealed: [],
|
|
369
|
+
notApplicable: [],
|
|
370
|
+
summary: { judged: 0, sealed: 0, exceptions: 0, violations: 0 },
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
355
374
|
const reasons = [];
|
|
356
375
|
const files = Array.isArray(input.files) ? input.files : null;
|
|
357
376
|
|
|
@@ -452,7 +471,7 @@ export function collectChangedFiles(base, head) {
|
|
|
452
471
|
/**
|
|
453
472
|
* Read the optional `designSource` block from `.lisa.config.json`.
|
|
454
473
|
*
|
|
455
|
-
* @returns {{ include?: string[], exclude?: string[] }} Project overrides, or {}.
|
|
474
|
+
* @returns {{ enabled?: unknown, include?: string[], exclude?: string[] }} Project overrides, or {}.
|
|
456
475
|
*/
|
|
457
476
|
function readProjectConfig() {
|
|
458
477
|
try {
|
|
@@ -471,6 +490,9 @@ function readProjectConfig() {
|
|
|
471
490
|
* @returns {string} Report text.
|
|
472
491
|
*/
|
|
473
492
|
export function renderReport(result) {
|
|
493
|
+
if (result.verdict === "SKIPPED") {
|
|
494
|
+
return "design-source gate: SKIPPED: designSource.enabled=false";
|
|
495
|
+
}
|
|
474
496
|
const lines = [`design-source gate: ${result.verdict}`];
|
|
475
497
|
|
|
476
498
|
if (result.verdict === "PASS") {
|
|
@@ -534,15 +556,15 @@ export function runCli(argv) {
|
|
|
534
556
|
return 2;
|
|
535
557
|
}
|
|
536
558
|
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
559
|
+
const config = readProjectConfig();
|
|
560
|
+
const change =
|
|
561
|
+
config.enabled === false
|
|
562
|
+
? {}
|
|
563
|
+
: collectChangedFiles(base, args.get("head") ?? "HEAD");
|
|
541
564
|
const result = evaluateDesignSource({
|
|
542
|
-
|
|
543
|
-
diffError,
|
|
565
|
+
...change,
|
|
544
566
|
figmaAccess: args.get("figma-access") === "true",
|
|
545
|
-
config
|
|
567
|
+
config,
|
|
546
568
|
});
|
|
547
569
|
|
|
548
570
|
process.stdout.write(
|
|
@@ -550,7 +572,7 @@ export function runCli(argv) {
|
|
|
550
572
|
? `${JSON.stringify(result, null, 2)}\n`
|
|
551
573
|
: `${renderReport(result)}\n`
|
|
552
574
|
);
|
|
553
|
-
return result.verdict === "
|
|
575
|
+
return result.verdict === "FAIL" ? 1 : 0;
|
|
554
576
|
}
|
|
555
577
|
|
|
556
578
|
/**
|
|
@@ -14,7 +14,7 @@ This skill carries the **judgment**. It does not carry the **policy** — that i
|
|
|
14
14
|
|
|
15
15
|
## What this is not
|
|
16
16
|
|
|
17
|
-
`design-source-of-truth` and `scripts/design-source-gate.mjs` already ask whether a changed surface **declares where its design came from**. This asks the orthogonal question: are the **values on it bound**.
|
|
17
|
+
`design-source-of-truth` and `scripts/design-source-gate.mjs` already ask whether a changed surface **declares where its design came from**. This asks the orthogonal question: are the **values on it bound**. Design-source declarations apply unless the project explicitly sets `designSource.enabled` to boolean `false`; that opt-out does not disable this skill or `design-value-binding`. A surface can cite a perfectly valid design node and still paint a literal that no variable backs — that is the case this skill exists for, and it is invisible to the other gate.
|
|
18
18
|
|
|
19
19
|
## Why this gate is executable and not advisory
|
|
20
20
|
|
|
@@ -160,7 +160,9 @@ IF it is a Fix (bug), execute the Reproduce sub-flow FIRST:
|
|
|
160
160
|
|
|
161
161
|
For any Fix flow, and for any Build flow that changes user-visible behavior, regression coverage is a required deliverable at the highest practical observation level for the reported surface. If the project has a browser, device, or end-to-end harness for that platform (for example Playwright, Maestro, Detox, Cypress, or an equivalent runtime), the task plan and definition of done MUST include a deterministic regression spec against the reported surface, using mocked or seeded data where needed. This is alongside unit or integration coverage, not a substitute for it. For **frontend work** the deliverable is defined by the `bdd-e2e-coverage` rule and has two halves, both landing in this PR: the Gherkin scenario (stable ID, required platforms) added or updated in the project's behavior contract, and aligned automation in the project's configured runner for **every** platform that scenario requires — no runner substitutes for another, because they guard different platforms of the same behavior. The coverage gate must pass and the matrix and burndown be regenerated before the item is done. Cite the rule; do not restate its scenario, waiver, or bootstrap mechanics here.
|
|
162
162
|
|
|
163
|
-
|
|
163
|
+
Before preparing any design-source tasks or teammate instructions, read `designSource.enabled` in `.lisa.config.json`. Only boolean `false` opts out: omit the design-source step from the plan and all teammate prompts; do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Absent, true, or invalid values keep enforcement enabled. The separate `design-value-binding` obligation and host design-system rules remain in force.
|
|
164
|
+
|
|
165
|
+
When enabled, for work that adds or changes a **UI surface**, the `design-source-of-truth` rule adds a second non-demotable deliverable landing in this same PR: every UI surface the change touches declares where its design came from. Figma is the source of truth, so **prefer sync-back** — if the surface is not in Figma yet and the tool-access preflight proved Figma access, reflect it there and cite the node with `DESIGN-SOURCE: <figma-url>`. Only when the surface genuinely does not belong in the design source (debug affordance, dev-only playground, internal tooling) does it carry the exception marker `DESIGN-SOURCE: none — not in Figma`, ideally with a trailing reason. `scripts/design-source-gate.mjs` decides this deterministically and fails closed on anything it cannot resolve; a FAIL blocks the item exactly as a failing coverage gate does. Host design-system rules (`figma-design-system`, `design-system`, `use-the-design-library`, or the project's equivalent) stay authoritative about *what* to build — this obligation is only about declaring the source. Cite the rule; do not restate its marker grammar, host-precedence, or bootstrap mechanics here.
|
|
164
166
|
|
|
165
167
|
The `design-value-binding` rule adds a second, orthogonal obligation on the same surfaces: **values come from design variables where a variable system exists.** That contract asks whether the values are *bound*, not whether the source is *declared* — a surface can cite a valid design node and still paint a literal no variable backs. Resolve the regime per axis, block only on the five objectively checkable conditions, and record every value derived in an untyped axis on the work item. `/lisa:design:intake` runs it. Cite the rule; do not restate its conditions, config schema, or comment grammar here.
|
|
166
168
|
|
|
@@ -16,7 +16,7 @@ For each changed file, evaluate:
|
|
|
16
16
|
3. **Test coverage** -- Tests present? Testing behavior, not implementation details? Edge cases covered?
|
|
17
17
|
4. **Documentation** -- JSDoc on new functions explaining "why"? Preambles on new files?
|
|
18
18
|
5. **Code clarity** -- Readable variable names? Unnecessary complexity? Could a new team member understand this?
|
|
19
|
-
6. **Design source** --
|
|
19
|
+
6. **Design source** -- Read `designSource.enabled` in `.lisa.config.json` first. Only boolean `false` opts out: omit the design-source review step; do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Record `SKIPPED: designSource.enabled=false` in the review. Absent, true, or invalid values keep enforcement enabled. When enabled, for UI surfaces, does each changed file say where its design came from? Run the deterministic gate rather than judging by eye:
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
22
|
node "${CLAUDE_PLUGIN_ROOT:-.}/scripts/design-source-gate.mjs" --base=main --head=HEAD
|
|
@@ -24,7 +24,7 @@ For each changed file, evaluate:
|
|
|
24
24
|
|
|
25
25
|
Exit 1 is a **Critical** finding under the `design-source-of-truth` rule -- the change is blocked until every UI surface either cites a Figma node (`DESIGN-SOURCE: <figma-url>`, the preferred fix -- sync it back) or carries the exception marker `DESIGN-SOURCE: none — not in Figma`. The gate fails closed: an unreadable file or an uncomputable diff is a FAIL, not a pass. Host design-system rules (`figma-design-system`, `design-system`, `use-the-design-library`, or the project's equivalent) stay authoritative about what to build; this checks only that the source is declared. If the gate script is absent, say so in the review rather than skipping silently.
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
7. **Design-value binding** -- Independently of the design-source opt-out, review the same surfaces against the `design-value-binding` rule — it asks the orthogonal question of whether each value is *bound* to what the design system publishes, not whether the source is declared. A literal in an axis the project publishes variables for is a **Critical** finding; the identical literal in an axis with no variable collection is correct and must not be flagged. Aesthetic disagreement is never a finding under this rule. Cite the rule; do not restate its conditions here.
|
|
28
28
|
|
|
29
29
|
## Output Format
|
|
30
30
|
|
|
@@ -18,14 +18,20 @@ One deterministic gate runs ahead of the judgement-based review and is exempt
|
|
|
18
18
|
from the confidence filtering below, because it is decided by a script rather
|
|
19
19
|
than by an agent's opinion.
|
|
20
20
|
|
|
21
|
-
**Design-source gate (`design-source-of-truth` rule).**
|
|
22
|
-
|
|
21
|
+
**Design-source gate (`design-source-of-truth` rule).** First read
|
|
22
|
+
`designSource.enabled` in `.lisa.config.json`. Only boolean `false` opts out:
|
|
23
|
+
omit the design-source review step; do not request DESIGN-SOURCE markers, Figma
|
|
24
|
+
nodes, or Figma access for this obligation. Record `SKIPPED: designSource.enabled=false`
|
|
25
|
+
in the review. Absent, true, or invalid values keep enforcement enabled.
|
|
26
|
+
The separate design-value binding review below still applies.
|
|
27
|
+
|
|
28
|
+
When enabled, run the gate against the branch diff before step 1:
|
|
23
29
|
|
|
24
30
|
```bash
|
|
25
31
|
node "${CLAUDE_PLUGIN_ROOT:-.}/scripts/design-source-gate.mjs" --base=main --head=HEAD
|
|
26
32
|
```
|
|
27
33
|
|
|
28
|
-
Exit 0 = PASS, exit 1 = FAIL. A FAIL is a **blocking** review finding and is
|
|
34
|
+
Exit 0 = PASS or explicit SKIPPED, exit 1 = FAIL. A FAIL is a **blocking** review finding and is
|
|
29
35
|
reported verbatim at the top of the review — it is never scored, never filtered
|
|
30
36
|
by confidence, and never demoted to a nitpick. It qualifies under
|
|
31
37
|
`convergent-review` because it names a concrete failure scenario: the design
|
|
@@ -72,7 +72,8 @@ TDD Cycle:
|
|
|
72
72
|
|
|
73
73
|
- Write the minimum production code to make the test pass
|
|
74
74
|
- Do not optimize, do not add features beyond what the test requires
|
|
75
|
-
-
|
|
75
|
+
- Read `designSource.enabled` in `.lisa.config.json` before preparing design-source instructions. Only boolean `false` opts out: omit the design-source step and do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Absent, true, or invalid values keep enforcement enabled.
|
|
76
|
+
- When enabled, for any UI surface the implementation adds or changes, the `design-source-of-truth` rule requires its design-source declaration to land in the same commit as the surface it describes — `DESIGN-SOURCE: <figma-url>` when the surface is backed by a Figma node (sync it back first if Figma access exists), or the exception marker `DESIGN-SOURCE: none — not in Figma` when it genuinely is not captured at the source. `scripts/design-source-gate.mjs` fails closed on an undeclared surface. Cite the rule; do not restate its marker grammar here.
|
|
76
77
|
- Separately, the `design-value-binding` rule governs where each *value* on that surface came from: in an axis with a published variable collection, bind the variable and use a screenshot only to verify; in an axis with none, measure and record what you derived. A literal in a typed axis is a block, not a TODO. Cite the rule; do not restate its conditions here.
|
|
77
78
|
- The goal is the simplest code that makes the test green
|
|
78
79
|
|
|
@@ -93,7 +93,9 @@ Mocks define visual *intent*, not implementation shortcut. Every UI-touching tic
|
|
|
93
93
|
|
|
94
94
|
If no existing component fits, building a new one is an explicit decision that must be recorded in the ticket (with rationale) before implementation. Lovable-generated components are never the reuse target — always use the project's own components.
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
Before adding the code-side obligation to ticket or teammate instructions, read `designSource.enabled` in `.lisa.config.json`. Only boolean `false` opts out: omit the design-source step; do not request DESIGN-SOURCE markers, Figma nodes, or Figma access for this obligation. Absent, true, or invalid values keep enforcement enabled. Preserve supplied artifacts and component-reuse requirements regardless; `design-value-binding` remains independent.
|
|
97
|
+
|
|
98
|
+
When enabled, the divergence note above covers the **ticket** side of this event. The **code** side is governed by the `design-source-of-truth` rule: a UI surface built with no Figma source behind it is either synced back to Figma and annotated `DESIGN-SOURCE: <figma-url>`, or explicitly marked `DESIGN-SOURCE: none — not in Figma`, and review fails closed if neither happened. Cite the rule for the code obligation rather than restating it here — a ticket comment closes with the ticket, the annotation stays with the surface.
|
|
97
99
|
|
|
98
100
|
## 8. Preservation gate (run after creating tickets)
|
|
99
101
|
|
|
@@ -6,18 +6,41 @@ alwaysApply: false
|
|
|
6
6
|
# Design Source of Truth
|
|
7
7
|
|
|
8
8
|
> Demoted from the always-on eager tier by CodySwannGT/lisa#3992. The
|
|
9
|
-
> section below is the former eager head,
|
|
9
|
+
> section below is the former eager head, maintained with the full
|
|
10
10
|
> contract follows it. Reachable on demand via [the rule index](00-rule-index.mdc).
|
|
11
11
|
|
|
12
12
|
## Design Source of Truth (load-bearing)
|
|
13
13
|
|
|
14
|
-
**Figma is the design source of truth, and every UI surface a change touches declares where its design came from.** A changed UI surface that neither cites a Figma node nor carries the designated marker is a contract violation — and so is a surface whose declaration the gate cannot resolve.
|
|
14
|
+
**When enabled, Figma is the design source of truth, and every UI surface a change touches declares where its design came from.** A changed UI surface that neither cites a Figma node nor carries the designated marker is a contract violation — and so is a surface whose declaration the gate cannot resolve.
|
|
15
15
|
|
|
16
16
|
**One vendor-neutral contract, cited by** `lisa-implement`, `lisa-tdd-implementation`, `lisa-review-local`, `lisa-quality-review`, and `lisa-tracker-source-artifacts` (the `leaf-only-lifecycle` / `repo-scope-split` precedent: one shared slug, never divergent per-skill prose).
|
|
17
17
|
|
|
18
|
+
## Explicit project opt-out
|
|
19
|
+
|
|
20
|
+
A project with **no design source at all** may set this in `.lisa.config.json`:
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{ "designSource": { "enabled": false } }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Only `designSource.enabled` set to boolean `false` opts out. Absent, true, and
|
|
27
|
+
invalid values retain the default enforcement. The explicit configuration is
|
|
28
|
+
the auditable record; it replaces per-file exception markers for this project.
|
|
29
|
+
The gate exits 0 with `SKIPPED: designSource.enabled=false` before resolving the
|
|
30
|
+
diff. JSON output reports `verdict: "SKIPPED"`, the config key in `reasons`, and
|
|
31
|
+
zero judged surfaces. A skip does not claim that surfaces passed inspection.
|
|
32
|
+
|
|
33
|
+
When opted out, the five consuming skills omit the design-source step from
|
|
34
|
+
plans, tickets, teammate instructions, and review; they do not ask for markers,
|
|
35
|
+
Figma nodes, or Figma access for this obligation. All declaration, sync-back,
|
|
36
|
+
and fail-closed requirements below apply only when enabled. Host design-system
|
|
37
|
+
rules, `design-value-binding`, and `bdd-e2e-coverage` remain independent and
|
|
38
|
+
unchanged. A project that has Figma must still not use `exclude` to hide its UI
|
|
39
|
+
tree from this contract.
|
|
40
|
+
|
|
18
41
|
## Membership
|
|
19
42
|
|
|
20
|
-
Membership is **surface, not repo name or file extension**: a file is in scope the moment a change makes it render something user-observable — a screen, component, layout, style token, visual state, or markup a user reads. Barrels, pure-logic modules, tests, stories, generated output, and vendored code are out. Projects narrow or widen the default detection through `designSource.include` / `designSource.exclude` in `.lisa.config.json`;
|
|
43
|
+
Membership is **surface, not repo name or file extension**: a file is in scope the moment a change makes it render something user-observable — a screen, component, layout, style token, visual state, or markup a user reads. Barrels, pure-logic modules, tests, stories, generated output, and vendored code are out. Projects narrow or widen the default detection through `designSource.include` / `designSource.exclude` in `.lisa.config.json`; those filters never turn the obligation off. Only the explicit project opt-out above does.
|
|
21
44
|
|
|
22
45
|
## The two declarations
|
|
23
46
|
|
|
@@ -44,7 +67,7 @@ Projects that carry their own design-system rules (`figma-design-system`, `desig
|
|
|
44
67
|
|
|
45
68
|
## Bootstrap and degradation
|
|
46
69
|
|
|
47
|
-
Adoption never demands a retroactive backfill: the gate judges **only the surfaces this change touched**. Pre-existing unannotated UI is burndown, recorded and worked down, not this work item's blocker.
|
|
70
|
+
Adoption never demands a retroactive backfill: the gate judges **only the surfaces this change touched**. Pre-existing unannotated UI is burndown, recorded and worked down, not this work item's blocker. A project with no design source may use the explicit project opt-out above; otherwise every changed surface still needs a declaration. Behavior obligations for the same surfaces are unchanged and still governed by `bdd-e2e-coverage`.
|
|
48
71
|
|
|
49
72
|
---
|
|
50
73
|
|
|
@@ -193,7 +216,7 @@ Two consequences worth stating plainly:
|
|
|
193
216
|
node design-source-gate.mjs --base=origin/main [--head=HEAD] [--figma-access] [--json]
|
|
194
217
|
```
|
|
195
218
|
|
|
196
|
-
Exit `0` = PASS, `1` = FAIL, `2` = usage error.
|
|
219
|
+
Exit `0` = PASS or explicit SKIPPED, `1` = FAIL, `2` = usage error. When enabled, it classifies every changed file into one status:
|
|
197
220
|
|
|
198
221
|
| Status | Verdict | Meaning |
|
|
199
222
|
|---|---|---|
|
|
@@ -236,8 +259,7 @@ so a repository with hundreds of unannotated legacy components can adopt the con
|
|
|
236
259
|
and be green on Tuesday. Pre-existing unannotated UI is **burndown**: recorded, worked down
|
|
237
260
|
opportunistically as files are touched, never treated as the current work item's blocker.
|
|
238
261
|
|
|
239
|
-
A project with no
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
BDD scenario to improve coverage: mark it, do not drop it.
|
|
262
|
+
A project with no design source may opt out explicitly using `designSource.enabled: false`.
|
|
263
|
+
Without that explicit opt-out, every changed surface still declares its source. In an enabled
|
|
264
|
+
project, deleting or excluding a surface to make the gate green is a violation of the same kind as
|
|
265
|
+
deleting a BDD scenario to improve coverage: mark it, do not drop it.
|
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
* at the source; it is the exception, not the default, and the gate reports
|
|
20
20
|
* every one of them so review can challenge it.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
22
|
+
* Projects with no design source may explicitly set `designSource.enabled`
|
|
23
|
+
* to boolean false. The gate reports SKIPPED before resolving the diff; all
|
|
24
|
+
* other values retain the default enforcement.
|
|
25
|
+
*
|
|
26
|
+
* **When enabled, the gate fails closed.** Anything it cannot resolve into one of those two
|
|
23
27
|
* declarations is a violation: no annotation, a malformed one, a file that both
|
|
24
28
|
* cites Figma and denies having a source, a changed file it could not read, or
|
|
25
29
|
* a diff it could not compute. A gate that returns PASS when it could not look
|
|
@@ -32,7 +36,7 @@
|
|
|
32
36
|
* to all of it — it asks only whether the design source is declared.
|
|
33
37
|
*
|
|
34
38
|
* Run it: `node design-source-gate.mjs --base=origin/main [--head=HEAD] [--json]`
|
|
35
|
-
* Exit 0 = PASS, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
39
|
+
* Exit 0 = PASS or SKIPPED, 1 = FAIL (any violation, or anything unresolvable), 2 = usage.
|
|
36
40
|
*/
|
|
37
41
|
import { execFileSync } from "node:child_process";
|
|
38
42
|
import { readFileSync, realpathSync } from "node:fs";
|
|
@@ -338,10 +342,10 @@ export const VIOLATION_STATUSES = new Set([
|
|
|
338
342
|
* files?: readonly { path: string, changeType?: string, content?: string | null }[] | null,
|
|
339
343
|
* diffError?: string | null,
|
|
340
344
|
* figmaAccess?: boolean,
|
|
341
|
-
* config?: { include?: readonly string[], exclude?: readonly string[] }
|
|
345
|
+
* config?: { enabled?: unknown, include?: readonly string[], exclude?: readonly string[] }
|
|
342
346
|
* }} input Change under evaluation.
|
|
343
347
|
* @returns {{
|
|
344
|
-
* verdict: "PASS" | "FAIL",
|
|
348
|
+
* verdict: "PASS" | "FAIL" | "SKIPPED",
|
|
345
349
|
* reasons: string[],
|
|
346
350
|
* violations: object[],
|
|
347
351
|
* exceptions: object[],
|
|
@@ -352,6 +356,21 @@ export const VIOLATION_STATUSES = new Set([
|
|
|
352
356
|
* }} The gate result.
|
|
353
357
|
*/
|
|
354
358
|
export function evaluateDesignSource(input = {}) {
|
|
359
|
+
// Only the explicit boolean opts out: a missing or mistyped setting must
|
|
360
|
+
// never silently remove enforcement from an existing adopter.
|
|
361
|
+
if (input.config?.enabled === false) {
|
|
362
|
+
return {
|
|
363
|
+
verdict: "SKIPPED",
|
|
364
|
+
reasons: ["designSource.enabled=false"],
|
|
365
|
+
violations: [],
|
|
366
|
+
exceptions: [],
|
|
367
|
+
syncBackPreferred: [],
|
|
368
|
+
sealed: [],
|
|
369
|
+
notApplicable: [],
|
|
370
|
+
summary: { judged: 0, sealed: 0, exceptions: 0, violations: 0 },
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
355
374
|
const reasons = [];
|
|
356
375
|
const files = Array.isArray(input.files) ? input.files : null;
|
|
357
376
|
|
|
@@ -452,7 +471,7 @@ export function collectChangedFiles(base, head) {
|
|
|
452
471
|
/**
|
|
453
472
|
* Read the optional `designSource` block from `.lisa.config.json`.
|
|
454
473
|
*
|
|
455
|
-
* @returns {{ include?: string[], exclude?: string[] }} Project overrides, or {}.
|
|
474
|
+
* @returns {{ enabled?: unknown, include?: string[], exclude?: string[] }} Project overrides, or {}.
|
|
456
475
|
*/
|
|
457
476
|
function readProjectConfig() {
|
|
458
477
|
try {
|
|
@@ -471,6 +490,9 @@ function readProjectConfig() {
|
|
|
471
490
|
* @returns {string} Report text.
|
|
472
491
|
*/
|
|
473
492
|
export function renderReport(result) {
|
|
493
|
+
if (result.verdict === "SKIPPED") {
|
|
494
|
+
return "design-source gate: SKIPPED: designSource.enabled=false";
|
|
495
|
+
}
|
|
474
496
|
const lines = [`design-source gate: ${result.verdict}`];
|
|
475
497
|
|
|
476
498
|
if (result.verdict === "PASS") {
|
|
@@ -534,15 +556,15 @@ export function runCli(argv) {
|
|
|
534
556
|
return 2;
|
|
535
557
|
}
|
|
536
558
|
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
559
|
+
const config = readProjectConfig();
|
|
560
|
+
const change =
|
|
561
|
+
config.enabled === false
|
|
562
|
+
? {}
|
|
563
|
+
: collectChangedFiles(base, args.get("head") ?? "HEAD");
|
|
541
564
|
const result = evaluateDesignSource({
|
|
542
|
-
|
|
543
|
-
diffError,
|
|
565
|
+
...change,
|
|
544
566
|
figmaAccess: args.get("figma-access") === "true",
|
|
545
|
-
config
|
|
567
|
+
config,
|
|
546
568
|
});
|
|
547
569
|
|
|
548
570
|
process.stdout.write(
|
|
@@ -550,7 +572,7 @@ export function runCli(argv) {
|
|
|
550
572
|
? `${JSON.stringify(result, null, 2)}\n`
|
|
551
573
|
: `${renderReport(result)}\n`
|
|
552
574
|
);
|
|
553
|
-
return result.verdict === "
|
|
575
|
+
return result.verdict === "FAIL" ? 1 : 0;
|
|
554
576
|
}
|
|
555
577
|
|
|
556
578
|
/**
|
|
@@ -14,7 +14,7 @@ This skill carries the **judgment**. It does not carry the **policy** — that i
|
|
|
14
14
|
|
|
15
15
|
## What this is not
|
|
16
16
|
|
|
17
|
-
`design-source-of-truth` and `scripts/design-source-gate.mjs` already ask whether a changed surface **declares where its design came from**. This asks the orthogonal question: are the **values on it bound**.
|
|
17
|
+
`design-source-of-truth` and `scripts/design-source-gate.mjs` already ask whether a changed surface **declares where its design came from**. This asks the orthogonal question: are the **values on it bound**. Design-source declarations apply unless the project explicitly sets `designSource.enabled` to boolean `false`; that opt-out does not disable this skill or `design-value-binding`. A surface can cite a perfectly valid design node and still paint a literal that no variable backs — that is the case this skill exists for, and it is invisible to the other gate.
|
|
18
18
|
|
|
19
19
|
## Why this gate is executable and not advisory
|
|
20
20
|
|