@codyswann/lisa 3.3.0 → 3.4.0
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/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +25 -5
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/package.json +1 -1
- 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-implement/SKILL.md +3 -1
- package/plugins/lisa/.codex-plugin/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/lisa/.codex-plugin/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
- package/plugins/lisa/rules/eager/design-source-of-truth.md +38 -0
- package/plugins/lisa/rules/reference/design-source-of-truth.md +195 -0
- package/plugins/lisa/scripts/design-source-gate.mjs +530 -0
- package/plugins/lisa/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/lisa/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/lisa/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/lisa/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-agy/scripts/design-source-gate.mjs +530 -0
- package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-agy/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/lisa-agy/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/lisa-agy/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/lisa-agy/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
- 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/eager/design-source-of-truth.md +38 -0
- package/plugins/lisa-copilot/rules/reference/design-source-of-truth.md +195 -0
- package/plugins/lisa-copilot/scripts/design-source-gate.mjs +530 -0
- package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-copilot/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/lisa-copilot/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/lisa-copilot/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/lisa-copilot/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/rules/design-source-of-truth-reference.mdc +200 -0
- package/plugins/lisa-cursor/rules/design-source-of-truth.mdc +43 -0
- package/plugins/lisa-cursor/scripts/design-source-gate.mjs +530 -0
- package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/lisa-cursor/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/lisa-cursor/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/lisa-cursor/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/lisa-cursor/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
- 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/eager/design-source-of-truth.md +38 -0
- package/plugins/src/base/rules/reference/design-source-of-truth.md +195 -0
- package/plugins/src/base/scripts/design-source-gate.mjs +530 -0
- package/plugins/src/base/skills/lisa-implement/SKILL.md +3 -1
- package/plugins/src/base/skills/lisa-quality-review/SKILL.md +7 -0
- package/plugins/src/base/skills/lisa-review-local/SKILL.md +27 -0
- package/plugins/src/base/skills/lisa-tdd-implementation/SKILL.md +1 -0
- package/plugins/src/base/skills/lisa-tracker-source-artifacts/SKILL.md +2 -0
package/package.json
CHANGED
|
@@ -120,7 +120,7 @@
|
|
|
120
120
|
}
|
|
121
121
|
},
|
|
122
122
|
"name": "@codyswann/lisa",
|
|
123
|
-
"version": "3.
|
|
123
|
+
"version": "3.4.0",
|
|
124
124
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
125
125
|
"main": "dist/index.js",
|
|
126
126
|
"exports": {
|
|
@@ -155,7 +155,9 @@ IF it is a Fix (bug), execute the Reproduce sub-flow FIRST:
|
|
|
155
155
|
|
|
156
156
|
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.
|
|
157
157
|
|
|
158
|
-
For work that adds or changes **
|
|
158
|
+
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.
|
|
159
|
+
|
|
160
|
+
For work that adds or changes **persistent state**, the `reset-seed-coverage` rule adds a third non-demotable deliverable landing in this same PR: every entity the item introduces or changes is classified in the project's state contract (`fixture-owned` / `preserve` / `derived-rebuild` / `forbidden`) with a reason and an owner, anything `fixture-owned` declares its ownership predicate and is actually swept, and the state-classification check passes. Writing a flow that creates a record and deletes it only on its happy path does NOT satisfy this — that is the leak, not the coverage. Cite the rule; do not restate its policy, waiver, or bootstrap mechanics here.
|
|
159
161
|
|
|
160
162
|
The team lead may not waive, defer, demote, or phrase this regression spec as "optional", "if cheap", "nice to have", or equivalent. The only permitted exits are:
|
|
161
163
|
|
|
@@ -16,6 +16,13 @@ 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** -- For UI surfaces, does each changed file say where its design came from? Run the deterministic gate rather than judging by eye:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node "${CLAUDE_PLUGIN_ROOT:-.}/scripts/design-source-gate.mjs" --base=main --head=HEAD
|
|
23
|
+
```
|
|
24
|
+
|
|
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.
|
|
19
26
|
|
|
20
27
|
## Output Format
|
|
21
28
|
|
|
@@ -14,6 +14,33 @@ maintainability feedback are non-blocking unless a repository rule or work item
|
|
|
14
14
|
explicitly makes them release criteria. A blocking finding without a concrete
|
|
15
15
|
failure scenario is malformed and must be filtered out.
|
|
16
16
|
|
|
17
|
+
One deterministic gate runs ahead of the judgement-based review and is exempt
|
|
18
|
+
from the confidence filtering below, because it is decided by a script rather
|
|
19
|
+
than by an agent's opinion.
|
|
20
|
+
|
|
21
|
+
**Design-source gate (`design-source-of-truth` rule).** Run it against the
|
|
22
|
+
branch diff before step 1:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
node "${CLAUDE_PLUGIN_ROOT:-.}/scripts/design-source-gate.mjs" --base=main --head=HEAD
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Exit 0 = PASS, exit 1 = FAIL. A FAIL is a **blocking** review finding and is
|
|
29
|
+
reported verbatim at the top of the review — it is never scored, never filtered
|
|
30
|
+
by confidence, and never demoted to a nitpick. It qualifies under
|
|
31
|
+
`convergent-review` because it names a concrete failure scenario: the design
|
|
32
|
+
source silently diverges from the shipped product and nobody can tell which one
|
|
33
|
+
is authoritative. The gate fails closed, so an unresolvable diff or an unreadable
|
|
34
|
+
file is a FAIL too. Each violation is fixed one of two ways, sync-back first:
|
|
35
|
+
reflect the surface in Figma and cite the node with `DESIGN-SOURCE: <figma-url>`,
|
|
36
|
+
or — only when the surface genuinely does not belong in the design source — mark
|
|
37
|
+
it `DESIGN-SOURCE: none — not in Figma`. Host design-system rules
|
|
38
|
+
(`figma-design-system`, `design-system`, `use-the-design-library`, or the
|
|
39
|
+
project's equivalent) remain authoritative about what to build; this gate only
|
|
40
|
+
asks whether the source is declared. If the gate script is not present (the
|
|
41
|
+
project predates the plugin version that ships it), say so explicitly in the
|
|
42
|
+
review — a silent skip is not one of the exits.
|
|
43
|
+
|
|
17
44
|
To do this, follow these steps precisely:
|
|
18
45
|
|
|
19
46
|
1. Use a Haiku agent to check the current git state:
|
|
@@ -71,6 +71,7 @@ TDD Cycle:
|
|
|
71
71
|
|
|
72
72
|
- Write the minimum production code to make the test pass
|
|
73
73
|
- Do not optimize, do not add features beyond what the test requires
|
|
74
|
+
- 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.
|
|
74
75
|
- The goal is the simplest code that makes the test green
|
|
75
76
|
|
|
76
77
|
### REFACTOR Phase
|
|
@@ -93,6 +93,8 @@ 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
|
+
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
|
+
|
|
96
98
|
## 8. Preservation gate (run after creating tickets)
|
|
97
99
|
|
|
98
100
|
Before declaring done, verify every extracted artifact is reachable from the created tickets.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Design Source of Truth (load-bearing)
|
|
2
|
+
|
|
3
|
+
**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.
|
|
4
|
+
|
|
5
|
+
**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).
|
|
6
|
+
|
|
7
|
+
## Membership
|
|
8
|
+
|
|
9
|
+
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`; they never turn the obligation off.
|
|
10
|
+
|
|
11
|
+
## The two declarations
|
|
12
|
+
|
|
13
|
+
Exactly one of these, written as an ordinary comment in whatever syntax the file uses:
|
|
14
|
+
|
|
15
|
+
| Form | Means |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `DESIGN-SOURCE: <figma-url>` | The surface is backed by a Figma node — it already existed there, or it was synced back. |
|
|
18
|
+
| `DESIGN-SOURCE: none — not in Figma` | The surface is deliberately not captured at the design source. |
|
|
19
|
+
|
|
20
|
+
The marker's spelling is fixed and load-bearing; a drifted spelling silently disarms the gate. An optional trailing ` — <reason>` records why. Only a `figma.com` URL seals a surface: a link to a screenshot, a Slack thread, or any other mock is **malformed**, not proof.
|
|
21
|
+
|
|
22
|
+
## Sync-back is the default; the marker is the exception, not the default
|
|
23
|
+
|
|
24
|
+
When the flow has proven Figma access (the `tool-access-gate` probe), reflecting the surface in Figma and citing the node is the expected outcome. Reach for the marker only when the surface genuinely does not belong in the design source — a debug affordance, a dev-only playground, a throwaway internal tool. The gate reports every marked exception so review can challenge it, and reports a reasonless exception separately when Figma access was available.
|
|
25
|
+
|
|
26
|
+
## Host design-system rules stay authoritative
|
|
27
|
+
|
|
28
|
+
Projects that carry their own design-system rules (`figma-design-system`, `design-system`, `use-the-design-library`, or an equivalent) keep them. This contract never restates component hierarchy, token vocabulary, or reuse policy, and never overrides them. It asks one orthogonal question the host rules do not: is the design source declared?
|
|
29
|
+
|
|
30
|
+
## The gate fails closed
|
|
31
|
+
|
|
32
|
+
`scripts/design-source-gate.mjs` decides the change deterministically. It fails on an undeclared surface, a malformed annotation, a file that both cites Figma and denies having a source, a changed file it could not read, and a diff it could not compute. **A design-source violation is a blocking review finding, never a warning** — it is not demoted to "optional", "if cheap", or a follow-up. A gate that passes on what it could not read proves nothing, so it never does.
|
|
33
|
+
|
|
34
|
+
## Bootstrap and degradation
|
|
35
|
+
|
|
36
|
+
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. If a project has no Figma at all, that is not an exemption — every changed surface carries the marker, and the resulting exception list is the honest record of how much of the product lives outside its design source. Behavior obligations for the same surfaces are unchanged and still governed by `bdd-e2e-coverage`.
|
|
37
|
+
|
|
38
|
+
Full contract (marker grammar, gate semantics, host-rule precedence, bootstrap procedure): [reference/design-source-of-truth.md](../reference/design-source-of-truth.md).
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Design Source of Truth
|
|
2
|
+
|
|
3
|
+
Design has always leaked in one direction. A ticket arrives with a Figma frame, the frame gets
|
|
4
|
+
built, and then — during implementation, during a bug fix, during a "quick" empty state nobody
|
|
5
|
+
specified — new UI gets invented directly in code. Nothing ever carries it back. A year later the
|
|
6
|
+
Figma file describes a product that no longer exists, and the only way to answer "what is this
|
|
7
|
+
screen supposed to look like?" is to read the code, which is precisely the question the design
|
|
8
|
+
source was supposed to answer.
|
|
9
|
+
|
|
10
|
+
Lisa had every design obligation conditioned on a design artifact *already existing*. Ticket gate
|
|
11
|
+
S12 fires only `when artifacts_attached = true`. `work-item-definition-of-ready` requires
|
|
12
|
+
design-source precedence "when artifacts exist". `lisa-implement` treats a linked Figma file as a
|
|
13
|
+
required tool and hard-stops when access to it fails. The nearest adjacent behavior —
|
|
14
|
+
`lisa-tracker-source-artifacts` asking UI tickets to flag design-vs-code divergence — files that
|
|
15
|
+
divergence as a *ticket comment*, which closes with the ticket.
|
|
16
|
+
|
|
17
|
+
Every one of those is about UI that has a source. **None of them govern UI that has none.** That is
|
|
18
|
+
the gap this contract closes, and it closes it on the code side, where the invented UI actually
|
|
19
|
+
lives.
|
|
20
|
+
|
|
21
|
+
## What the contract asks
|
|
22
|
+
|
|
23
|
+
One question, per UI surface a change touches: **where did this design come from?**
|
|
24
|
+
|
|
25
|
+
Not "is it pretty", not "does it use the right token", not "should this component exist" — those are
|
|
26
|
+
the host design system's questions, and it answers them far better than a vendor-neutral contract
|
|
27
|
+
could. This contract asks only whether the answer to the provenance question is written down.
|
|
28
|
+
|
|
29
|
+
## Membership
|
|
30
|
+
|
|
31
|
+
A file is a UI surface when a change makes it render something user-observable: a screen,
|
|
32
|
+
component, layout, style token, visual state, or markup a user reads. The gate's default detection
|
|
33
|
+
is two-tier, and the split is deliberate:
|
|
34
|
+
|
|
35
|
+
- **Extensions that always render** — `.tsx`, `.jsx`, `.vue`, `.svelte` — count wherever they live.
|
|
36
|
+
- **Markup and style extensions** — `.css`, `.scss`, `.sass`, `.less`, `.styl`, `.html`, `.erb`,
|
|
37
|
+
`.haml`, `.slim`, `.swift`, `.kt`, `.dart`, `.xml` — count only inside a rendering directory
|
|
38
|
+
(`components`, `screens`, `views`, `pages`, `ui`, `widgets`, `layouts`, `templates`, `atoms`,
|
|
39
|
+
`molecules`, `organisms`).
|
|
40
|
+
|
|
41
|
+
The second tier is why a `.ts` barrel under `components/` is out: `src/components/atoms/index.ts`
|
|
42
|
+
re-exports and renders nothing, so demanding a design source from it would be noise, and noise is
|
|
43
|
+
how a gate earns its way into an ignore list. Tests, specs, stories, snapshots, `.d.ts` declarations,
|
|
44
|
+
`node_modules`, and build output are excluded for the same reason.
|
|
45
|
+
|
|
46
|
+
Projects tune this in `.lisa.config.json`:
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"designSource": {
|
|
51
|
+
"include": ["**/*.mjml"],
|
|
52
|
+
"exclude": ["src/legacy/**"]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`include` widens the surface; `exclude` narrows it. Neither turns the obligation off — a project that
|
|
58
|
+
excluded its whole UI tree would be declaring it has no UI, which review can see.
|
|
59
|
+
|
|
60
|
+
## The marker grammar
|
|
61
|
+
|
|
62
|
+
Exactly one declaration per file, written as an ordinary comment in whatever syntax the file already
|
|
63
|
+
uses. The gate reads the annotation, not the comment characters around it, so all of these are the
|
|
64
|
+
same declaration:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
// DESIGN-SOURCE: https://www.figma.com/design/AbC123/Checkout?node-id=412-1187
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```css
|
|
71
|
+
/* DESIGN-SOURCE: none — not in Figma */
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```svelte
|
|
75
|
+
<!-- DESIGN-SOURCE: none — not in Figma — internal-only debug affordance -->
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `DESIGN-SOURCE: <figma-url>` — sealed
|
|
79
|
+
|
|
80
|
+
The surface is backed by a design node. Only a `figma.com` URL counts. A screenshot link, a Slack
|
|
81
|
+
permalink, a Jira attachment, or a path to a PNG in the repo is **malformed**, not proof: those are
|
|
82
|
+
copies of a design, and a copy cannot be updated when the design changes. Prefer a URL carrying a
|
|
83
|
+
`node-id` so the citation resolves to the frame rather than the file.
|
|
84
|
+
|
|
85
|
+
### `DESIGN-SOURCE: none — not in Figma` — the recorded exception
|
|
86
|
+
|
|
87
|
+
The spelling is fixed, including the em dash, and it is load-bearing: the gate, the rule, the review
|
|
88
|
+
path, and the implement path all cite the same string, so a drifted spelling silently disarms the
|
|
89
|
+
gate rather than failing loudly. An optional trailing ` — <reason>` records why the surface is not
|
|
90
|
+
captured at the source, and the gate surfaces reasonless markers separately (below).
|
|
91
|
+
|
|
92
|
+
### Everything else
|
|
93
|
+
|
|
94
|
+
`DESIGN-SOURCE:` followed by anything that is neither form is **malformed** and fails. This is not
|
|
95
|
+
pedantry — it is what stops the annotation from degrading into a comment that says "design source:
|
|
96
|
+
ask Priya" and passes. **Silence is a violation, never a pass.**
|
|
97
|
+
|
|
98
|
+
A file that carries both a Figma URL and the none-marker is **conflicting** and fails. It is
|
|
99
|
+
asserting two contradictory things about the same surface, and the gate does not pick a winner.
|
|
100
|
+
|
|
101
|
+
## Sync-back is the default
|
|
102
|
+
|
|
103
|
+
The order of preference is not decorative:
|
|
104
|
+
|
|
105
|
+
1. **The surface already exists in Figma.** Cite the node. Nothing else to do.
|
|
106
|
+
2. **Figma access is available and the surface belongs in the design source.** Reflect it in Figma,
|
|
107
|
+
then cite the node. This is the expected outcome for real product UI, and the whole reason the
|
|
108
|
+
`tool-access-gate` probe enumerates Figma as a required tool when the work item links one.
|
|
109
|
+
3. **The surface genuinely does not belong in the design source.** Mark it. Debug affordances,
|
|
110
|
+
dev-only playgrounds, internal tooling, and diagnostics live here.
|
|
111
|
+
|
|
112
|
+
The marker is the exception, not the default. When Figma access has been proven and a marked
|
|
113
|
+
exception records no reason, the gate reports it under `syncBackPreferred` — non-blocking, because
|
|
114
|
+
turning a preference into a second hard gate would make the honest exception more expensive than a
|
|
115
|
+
copy-pasted Figma link, which is exactly the wrong incentive. It is a review prompt: *you could have
|
|
116
|
+
synced this back — why didn't you?*
|
|
117
|
+
|
|
118
|
+
## Host design-system rules stay authoritative
|
|
119
|
+
|
|
120
|
+
Several Lisa host projects already carry a design-system rule of their own —
|
|
121
|
+
`figma-design-system.md`, `design-system.md`, `use-the-design-library.md`. Those files are
|
|
122
|
+
**host-owned**. They define the component hierarchy, the closed token vocabulary, the atom layer,
|
|
123
|
+
the escape hatches, and the lint manifest that enforces all of it, and they are specific to a product
|
|
124
|
+
in ways no shared contract can or should be.
|
|
125
|
+
|
|
126
|
+
**This contract governs whether the design source is declared, never what to build.** It adds one
|
|
127
|
+
orthogonal obligation on top of whatever the host rule already says. Where a host rule already
|
|
128
|
+
mandates a Figma mapping, this contract is satisfied by that mapping — cite the node and move on.
|
|
129
|
+
|
|
130
|
+
Two consequences worth stating plainly:
|
|
131
|
+
|
|
132
|
+
- **Do not duplicate host content into this contract, and do not rewrite host rules to restate this
|
|
133
|
+
one.** Wire them: the host rule points at this slug for the provenance obligation, this contract
|
|
134
|
+
points at the host rule for everything else.
|
|
135
|
+
- **Several host design-system rules are generated artifacts** carrying a "generated from
|
|
136
|
+
`docs/design-system-rfc.md` — do not edit this file directly" provenance header. Respect it:
|
|
137
|
+
**amend the RFC and regenerate.** A hand-edit to a generated rule is lost on the next
|
|
138
|
+
regeneration, which is worse than not making the change at all, because it looks like it shipped.
|
|
139
|
+
|
|
140
|
+
## Gate semantics
|
|
141
|
+
|
|
142
|
+
`scripts/design-source-gate.mjs` is the executable arm of this contract, and it **fails closed**.
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
node design-source-gate.mjs --base=origin/main [--head=HEAD] [--figma-access] [--json]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Exit `0` = PASS, `1` = FAIL, `2` = usage error. It classifies every changed file into one status:
|
|
149
|
+
|
|
150
|
+
| Status | Verdict | Meaning |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| `figma-source` | pass | Sealed by a Figma node. |
|
|
153
|
+
| `marked-exception` | pass | Explicitly declared as not captured at the source. |
|
|
154
|
+
| `not-applicable` | pass | Not a UI surface, or a deletion — nothing to declare. |
|
|
155
|
+
| `undeclared` | **fail** | A UI surface with no annotation at all. |
|
|
156
|
+
| `malformed` | **fail** | An annotation whose value is neither form. |
|
|
157
|
+
| `conflicting` | **fail** | Cites Figma *and* denies having a source. |
|
|
158
|
+
| `unreadable` | **fail** | The changed file could not be read. |
|
|
159
|
+
|
|
160
|
+
Plus two change-level failures that exist purely so the gate cannot pass on ignorance:
|
|
161
|
+
`changed-files-unresolved` (the file list never materialized) and `diff-unresolved` (git could not
|
|
162
|
+
compute the range). **A gate that returns PASS when it could not look proves nothing.** This is the
|
|
163
|
+
same discipline `claim-evidence-mapping` applies to verification evidence and `bdd-e2e-coverage`
|
|
164
|
+
applies to a missing runner: the absence of a check is never a passing check.
|
|
165
|
+
|
|
166
|
+
The gate aggregates — it reports every violating file, not the first one — so a single run tells the
|
|
167
|
+
implementer everything they need to fix.
|
|
168
|
+
|
|
169
|
+
## Where it is enforced
|
|
170
|
+
|
|
171
|
+
- **`lisa-implement`** — building or changing a UI surface includes declaring its design source, and
|
|
172
|
+
the sync-back preference applies while the work is being done, when reflecting the surface in Figma
|
|
173
|
+
is cheap. The `tool-access-gate` probe already establishes whether Figma access exists.
|
|
174
|
+
- **`lisa-tdd-implementation`** — the declaration lands with the implementation, in the same commit
|
|
175
|
+
as the surface it describes.
|
|
176
|
+
- **`lisa-review-local` and `lisa-quality-review`** — the gate runs on the branch diff, and a FAIL is
|
|
177
|
+
a **blocking** finding. It qualifies under `convergent-review` because it names a concrete failure
|
|
178
|
+
scenario: the design source silently diverges from the shipped product, and nobody can tell which
|
|
179
|
+
one is authoritative.
|
|
180
|
+
- **`lisa-tracker-source-artifacts`** — its existing design-vs-code divergence note covers the
|
|
181
|
+
*ticket* side of the same event. It points here for the code side, so the two are one behavior
|
|
182
|
+
rather than two half-behaviors.
|
|
183
|
+
|
|
184
|
+
## Bootstrap and degradation
|
|
185
|
+
|
|
186
|
+
Adoption is never a backfill project. The gate judges only the surfaces the current change touched,
|
|
187
|
+
so a repository with hundreds of unannotated legacy components can adopt the contract on a Tuesday
|
|
188
|
+
and be green on Tuesday. Pre-existing unannotated UI is **burndown**: recorded, worked down
|
|
189
|
+
opportunistically as files are touched, never treated as the current work item's blocker.
|
|
190
|
+
|
|
191
|
+
A project with no Figma at all is not exempt. Every changed surface carries the marker, and the
|
|
192
|
+
resulting exception list is the honest, mounting record of how much of the product lives outside its
|
|
193
|
+
design source — which is far more useful than an exemption flag that makes the question disappear.
|
|
194
|
+
Deleting or excluding a surface to make the gate green is a violation of the same kind as deleting a
|
|
195
|
+
BDD scenario to improve coverage: mark it, do not drop it.
|