@relipa/ai-flow-kit 0.1.5 → 0.1.6

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/bin/aiflow.js CHANGED
@@ -20,6 +20,7 @@ const checkpointCommand = require('../scripts/checkpoint');
20
20
  const { record } = require('../scripts/telemetry/record');
21
21
  const { updateTaskGateState } = require('../scripts/task');
22
22
  const scaffoldPlaywrightCommand = require('../scripts/scaffold-playwright');
23
+ const docsBranchCommand = require('../scripts/docs-branch');
23
24
  const semver = require('semver');
24
25
  const { execSync: execSyncChild, spawnSync } = require('child_process');
25
26
 
@@ -390,6 +391,39 @@ memCmd
390
391
  .description('Clear all memories')
391
392
  .action(() => { memoryCommand('clear'); });
392
393
 
394
+ // ── docs (branch + Merge Request workflow for AK-Docs/Shared-Docs) ─────
395
+ // See docs/internal/Docs-Management-Flow.md — PM reviews & merges `main`;
396
+ // every other role updates docs on feature/<functionId>/<taskId> from main.
397
+ const docsCmd = program.command('docs').description('Branch & Merge Request workflow for AK-Docs/Shared-Docs (see Docs-Management-Flow.md)');
398
+
399
+ docsCmd
400
+ .command('branch <functionId> <taskId>')
401
+ .description('Pull latest main, then create (or checkout) feature/<functionId>/<taskId>')
402
+ .option('-r, --repo <name>', 'AK-Docs | Shared-Docs', 'AK-Docs')
403
+ .option('-b, --base <branch>', 'base branch to branch from', 'main')
404
+ .option('-y, --yes', 'skip the interactive confirm — only pass this after the user has approved the plan in chat')
405
+ .action((functionId, taskId, options) => {
406
+ docsBranchCommand.createBranch({
407
+ functionId, taskId,
408
+ repo: options.repo, base: options.base, yes: options.yes,
409
+ });
410
+ });
411
+
412
+ docsCmd
413
+ .command('submit')
414
+ .description('Commit + push the current docs branch and open a Merge Request against main')
415
+ .requiredOption('-t, --title <title>', 'commit message / MR title')
416
+ .option('-d, --description <text>', 'MR description', '')
417
+ .option('-r, --repo <name>', 'AK-Docs | Shared-Docs', 'AK-Docs')
418
+ .option('-b, --base <branch>', 'target branch', 'main')
419
+ .option('-y, --yes', 'skip the interactive confirm — only pass this after the user has approved the plan in chat')
420
+ .action((options) => {
421
+ docsBranchCommand.submitDocs({
422
+ title: options.title, description: options.description,
423
+ repo: options.repo, base: options.base, yes: options.yes,
424
+ });
425
+ });
426
+
393
427
  // ── guide ─────────────────────────────────────────────────────
394
428
  program
395
429
  .command('guide')
@@ -7,14 +7,16 @@
7
7
 
8
8
  ## ML Plan Output Paths
9
9
 
10
+ ML tickets share the **same** `AK-Docs/04.Coding/` folders as the standard Dev workflow (see `project-conventions.md`) — no separate ML section:
11
+
10
12
  | Output | Path | Note |
11
13
  |--------|------|------|
12
- | ML problem doc | `plan/[ticket-id]/ml-problem.md` | Gate 1 output |
13
- | Experiment plan | `plan/[ticket-id]/experiment-plan.md` | Gate 2 output — **NOT** `docs/superpowers/plans/` |
14
- | Evaluation report | `plan/[ticket-id]/eval-report.md` | Gate 4 output |
14
+ | ML problem doc | `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md` | Gate 1 output |
15
+ | Experiment plan | `AK-Docs/04.Coding/02.Plans/[functionId]/[ticketId].md` | Gate 2 output — **NOT** `docs/superpowers/plans/`, **NOT** `plan/` |
16
+ | Evaluation report + model card | `AK-Docs/04.Coding/04.Reviews/[functionId]/[ticketId].md` | Gate 4 output — include the model card draft in the same file, under its own section |
15
17
 
16
- > The `[ticket-id]` comes from `.aiflow/context/current.json`.
17
- > If no ticket context exists, use a descriptive slug: `plan/<feature-name>/ml-problem.md`.
18
+ > `[functionId]` `[ticketId]` được xác định theo đúng quy tắc "functionId & ticketId" trong `project-conventions.md` — **BẮT BUỘC xác định ở Gate 1 trước khi ghi file đầu tiên.**
19
+ > `plan/[ticket-id]/...` (đường dẫn cũ) đã **DEPRECATED** không được ghi output mới vào `plan/`. Chỉ code/notebook/model artifact thật (Gate 3 training) mới nằm ngoài `AK-Docs`, theo mục "Data & Model Versioning" bên dưới.
18
20
 
19
21
  ---
20
22
 
@@ -74,9 +76,10 @@ These rules are non-negotiable and override any convenience shortcut:
74
76
 
75
77
  Before saving any ML plan, experiment plan, or eval report, verify:
76
78
 
77
- - [ ] Output path follows the table above — NOT the skill's default path
78
- - [ ] `[ticket-id]` is read from `.aiflow/context/current.json`
79
- - [ ] Directory `plan/[ticket-id]/` exists or will be created
79
+ - [ ] Output path follows the table above — NOT the skill's default path, NOT the legacy `plan/` folder
80
+ - [ ] `functionId` đã được xác định/xác nhận ở Gate 1 (xem `project-conventions.md`)
81
+ - [ ] `[ticketId]` is read from `.aiflow/context/current.json`
82
+ - [ ] Directory `AK-Docs/04.Coding/<section>/[functionId]/` exists or will be created
80
83
  - [ ] Announced path in the handoff message matches the actual saved path
81
84
 
82
85
  ---
@@ -7,7 +7,11 @@
7
7
 
8
8
  ## DEV Workflow Output Paths (`AK-Docs/04.Coding/`)
9
9
 
10
- Áp dụng cho taskType: `feature` · `bug-fix` · `refactor` · `investigation` · `documentation`.
10
+ Áp dụng cho taskType: `feature` · `bug-fix` · `refactor` · `investigation` · `documentation` · `gen-doc` · các taskType ML (xem `ml-conventions.md`).
11
+
12
+ > `gen-doc` (2-gate, ad-hoc document generation) và các ticket ML đều dùng **chung** bộ thư mục `AK-Docs/04.Coding/` bên dưới — không có section riêng. Chỉ khác số Gate được dùng (gen-doc chỉ dùng Gate 1–2, ML dùng đủ Gate 1–5).
13
+
14
+ ### Standard tasks (feature, bug-fix, refactor, investigation, documentation, gen-doc, ML)
11
15
 
12
16
  | Output | Path | Note |
13
17
  |--------|------|------|
@@ -30,7 +34,19 @@
30
34
 
31
35
  ### Legacy
32
36
 
33
- - ❌ Đường dẫn cũ `plan/[ticket-id]/requirement.md`, `plan/[ticket-id]/plan.md`, `plan/[ticket-id]/summary.md` đã **DEPRECATED** — không được ghi output mới vào `plan/`.
37
+ - ❌ Đường dẫn cũ `plan/[ticket-id]/requirement.md`, `plan/[ticket-id]/plan.md`, `plan/[ticket-id]/summary.md`, `plan/[ticket-id]/output.md`, `plan/[ticket-id]/task-summary.md`, `plan/[ticket-id]/ml-problem.md`, `plan/[ticket-id]/experiment-plan.md`, `plan/[ticket-id]/eval-report.md` đã **DEPRECATED** cho MỌI taskType (kể cả `gen-doc` và ML) — không được ghi output mới vào `plan/`. Chỉ code/artifact thật sự thuộc source repo (hoặc cache thiết kế Figma — xem `read-study-requirement` skill) mới ở ngoài `AK-Docs`.
38
+
39
+ ### gen-doc tasks (2-gate flow — NO `plan.md`, dùng chung thư mục Coding)
40
+
41
+ | Output | Path | Note |
42
+ |--------|------|------|
43
+ | Requirement doc | `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md` | Gate 1 output — document outline |
44
+ | Document output | `AK-Docs/04.Coding/02.Plans/[functionId]/[ticketId].md` | Gate 2 output — the generated document (or custom path/format — e.g. Excel — noted in the requirement doc; still record the path used in this file) |
45
+ | Task summary | `AK-Docs/04.Coding/02.Plans/[functionId]/[ticketId]-summary.md` | Auto-generated after Gate 2 |
46
+
47
+ > For gen-doc tasks: **do NOT create `plan.md`**. Gate 2 generates the output document directly.
48
+ > If the requirement specifies an Excel output or a custom path, generate it at that path, but still write a short pointer + summary into the Gate 2 output doc above so the tracker/AK-Docs history stays complete.
49
+ > `functionId` vẫn **BẮT BUỘC xác định ở Gate 1** theo đúng quy tắc "functionId & ticketId" ở trên — với gen-doc không suy ra được từ input thì hỏi trực tiếp người yêu cầu (ví dụ dùng ticketId rút gọn hoặc mã chủ đề báo cáo, ví dụ `AD-HOC` nếu task không gắn với chức năng cụ thể nào).
34
50
 
35
51
  ---
36
52
 
@@ -71,7 +71,7 @@ An open-ended experiment loop with no stopping rule is out of scope for a gated
71
71
 
72
72
  ### 7. Output the experiment plan
73
73
 
74
- Write all of the above to `plan/[ticket-id]/experiment-plan.md`. The document must be self-contained: a developer who did not attend the framing discussion should be able to reproduce the full experiment sequence from the plan alone.
74
+ Write all of the above to `AK-Docs/04.Coding/02.Plans/[functionId]/[ticketId].md` (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path). The document must be self-contained: a developer who did not attend the framing discussion should be able to reproduce the full experiment sequence from the plan alone.
75
75
 
76
76
  ---
77
77
 
@@ -85,4 +85,4 @@ Write all of the above to `plan/[ticket-id]/experiment-plan.md`. The document mu
85
85
  - [ ] Experiment tracking configured (params, metrics, seed, data version, git commit)
86
86
  - [ ] Run-naming convention agreed and follows `ml-conventions.md`
87
87
  - [ ] Stopping and decision rule stated (metric, threshold, experiment budget)
88
- - [ ] Full plan written to `plan/[ticket-id]/experiment-plan.md`
88
+ - [ ] Full plan written to `AK-Docs/04.Coding/02.Plans/[functionId]/[ticketId].md` (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path)
@@ -74,7 +74,7 @@ Re-run the final eval using only the logged seed, the pinned config, and the reg
74
74
 
75
75
  ### 8. Write the eval report and model card
76
76
 
77
- Output `plan/[ticket-id]/eval-report.md` containing: the metric table (baseline, threshold, achieved), error analysis findings, overfitting gap, leakage check results, and robustness notes.
77
+ Output `AK-Docs/04.Coding/04.Reviews/[functionId]/[ticketId].md` (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path) containing: the metric table (baseline, threshold, achieved), error analysis findings, overfitting gap, leakage check results, and robustness notes.
78
78
 
79
79
  Draft a model card covering: intended use, training data description, evaluation metrics and their context, known limitations, and owner/contact.
80
80
 
@@ -89,5 +89,5 @@ Draft a model card covering: intended use, training data description, evaluation
89
89
  - [ ] All three leakage types re-checked and documented (target, contamination, temporal)
90
90
  - [ ] Robustness assessed under noise, edge cases, and sensitive slices
91
91
  - [ ] Result reproduced from logged seed and config — numbers match
92
- - [ ] `plan/[ticket-id]/eval-report.md` written
92
+ - [ ] `AK-Docs/04.Coding/04.Reviews/[functionId]/[ticketId].md` (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path) written
93
93
  - [ ] Model card drafted (intended use, data, metrics, limitations, owner)
@@ -84,4 +84,4 @@ Write the EDA results into the `ml-problem.md` file created by `frame-ml-problem
84
84
  - [ ] **Temporal leakage** checked and documented (chronological integrity verified if applicable)
85
85
  - [ ] Data-quality issues listed (units, label noise, sampling bias, drift)
86
86
  - [ ] Required cleaning steps noted
87
- - [ ] All findings written into `plan/[ticket-id]/ml-problem.md` data report section
87
+ - [ ] All findings written into `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md` data report section (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path)
@@ -14,6 +14,22 @@ keywords: figma, design, component, ui, generate, react, nextjs, nextjs-app-rout
14
14
 
15
15
  ---
16
16
 
17
+ ## Gate mode (called from Gate 3 of the gate workflow)
18
+
19
+ When invoked by Gate 3 and `plan/[ticket-id]/design/nodes.json` exists:
20
+
21
+ - **Skip Step 0, Step 1, Step 2, Step 2.5** — the design was already read and images already
22
+ exported during Gate 1. Do NOT call Figma MCP again.
23
+ - Load the cached design from `plan/[ticket-id]/design/nodes.json` and the image mapping from
24
+ `plan/[ticket-id]/design/design-context.md` (section "Image Map").
25
+ - **Copy images** from `plan/[ticket-id]/design/images/` to `public/assets/figma/` before
26
+ generating components, so the `src` paths in the generated code resolve.
27
+ - Continue from **Step 3** (detect CSS tooling) onward.
28
+
29
+ When invoked standalone (no `design/nodes.json`): run the full Process from Step 0.
30
+
31
+ ---
32
+
17
33
  ## Step 0: Verify Figma MCP is available
18
34
 
19
35
  Before doing anything, confirm the Figma MCP server is connected in this session:
@@ -53,6 +69,19 @@ Use Figma MCP tools to fetch design information:
53
69
  Note: `get_figma_data` returns layout, fills, strokes, typography, and component
54
70
  definitions in a single response. No separate style or component fetch is needed.
55
71
 
72
+ **Tier 1 call budget (MANDATORY).** Since 2025-11-17 Figma rate-limits by endpoint tier:
73
+ `get_figma_data` (file/nodes) and image *renders* share the same **Tier 1** bucket —
74
+ only **10-20 calls/min** on a Dev/Full seat, and **~6 calls/MONTH** on a View/Collab seat.
75
+ Every exploratory call burns the same budget as an image export, so:
76
+
77
+ - **ALWAYS pass `nodeId`** — never fetch the whole file.
78
+ - Start with the lowest `depth` that can answer the question; do NOT probe depth 1→2→3.
79
+ - Max **2 `get_figma_data` calls per design**. If the tree is truncated, make ONE targeted
80
+ follow-up on the specific child nodeId — not a re-read of the parent.
81
+ - Keep total Tier 1 calls (metadata + renders) **≤ 8 per minute**; space calls 5-10s apart.
82
+ - **Check the cache BEFORE any MCP call** — Gate mode reads `plan/[ticket-id]/design/nodes.json`;
83
+ standalone: if a `plan/*/design/nodes.json` exists for the same fileKey+nodeId, reuse it.
84
+
56
85
  Analyze the output to extract:
57
86
  - **Layout**: flexbox direction, gap, padding, alignment
58
87
  - **Sizing**: width/height (fixed vs fill vs hug)
@@ -73,33 +102,148 @@ After receiving node data from Step 2, scan the entire node tree to detect image
73
102
  - Node is a frame/group containing many complex layers (icon, illustration, banner) that cannot be recreated with CSS → needs image export
74
103
  - Node has `type === "VECTOR"` or `type === "BOOLEAN_OPERATION"` → always export as SVG/PNG
75
104
 
76
- **Export images via MCP:**
77
-
78
- For each detected image node, call MCP tool `download_figma_images`:
79
-
80
- ```
81
- download_figma_images({
82
- fileKey: "<fileKey>",
83
- nodes: [
84
- { nodeId: "<nodeId>", fileName: "<layerName-nodeId>.png" }
85
- ],
86
- localPath: "public/assets/figma/"
87
- })
105
+ **Naming convention (single source of truth):**
106
+
107
+ Every exported/provided image is keyed to its node through a manifest so matching never
108
+ relies on guessing layer names (which repeat in real designs):
109
+
110
+ - **File name** — the manifest below is authoritative, so any stable name works. Two accepted forms:
111
+ - `<imageRef>.png` — the full 40-char imageRef hash (e.g. `a1f7af10c49119532fa5e95ccceef6adcac9e86c.png`).
112
+ This is what `download_figma_images` and manual API exports produce by default — **keep it,
113
+ no renaming needed**. Collision-proof. Recommended for manual/bulk download.
114
+ - `<layer-slug>-<imageRef first 8 chars>.png` — human-readable variant (e.g. `top-phase1-554b0901.png`).
115
+ Use when you want readable asset names; you must rename after download.
116
+ - Vector / rendered nodes have no imageRef → `<layer-slug>-<nodeId>.png` (or `<nodeId>.png`).
117
+ - Pick ONE form per project and keep the manifest consistent with the files on disk.
118
+ - **Manifest file — one PER DESIGN, not one global file.** Maps **nodeId → file**; several
119
+ nodeIds may map to the same file (reused image). This is authoritative. Location:
120
+ - **Gate mode (a ticket):** `plan/[ticket-id]/design/figma-manifest.json` (next to
121
+ `design-context.md` / `nodes.json`).
122
+ - **Standalone (no ticket):** `public/assets/figma/figma-manifest.<fileKey>.json`.
123
+ - Do NOT share one `figma-manifest.json` across multiple tickets: a `nodeId` is only unique
124
+ within one Figma file, so a global manifest mixes designs and maps the wrong image. The
125
+ **images** stay shared in `public/assets/figma/` (dedup by `imageRef` keeps them unique);
126
+ only the per-design manifest is scoped.
127
+
128
+ ```json
129
+ // plan/PROJ-42/design/figma-manifest.json
130
+ {
131
+ "11362:27220": "top-phase1-554b0901.png",
132
+ "11362:27219": "livebg-1b-red-fc490ecb.png",
133
+ "I11362:27226;3523:5331;1668:8479": "light-6c5e42a8.png"
134
+ }
88
135
  ```
89
136
 
90
- - `localPath` defaults to `public/assets/figma/` (relative to the project root)
91
- - `fileName` follows the pattern: `<layer name in lowercase, spaces replaced with ->-<nodeId>.png`
92
- - Example: layer "Banner Top" with nodeId "123-456" → `banner-top-123-456.png`
93
- - If MCP does not support `download_figma_images`, get the image URL via `get_figma_data`, then notify DEV to download manually and place in `public/assets/figma/`
137
+ **Mode: DEV-provided images (manual download).** When the DEV exports images themselves
138
+ and drops them in `public/assets/figma/`:
139
+
140
+ 1. The DEV names each file per the pattern above (use the download list this skill prints
141
+ see Step 2.5 output — which gives the exact filename for each node).
142
+ 2. Ensure the design's manifest (per-design path above) maps each relevant nodeId to its file.
143
+ If the manifest is missing, build it by matching `<layer-slug>` (+ `imageRef`/`nodeId`) to
144
+ the files on disk.
145
+ 3. **Match order for every image node:** (a) manifest entry → (b) a file on disk matching the
146
+ convention → (c) only if neither, download via MCP. Never re-download what is already there.
147
+ 4. If a node has no manifest entry and no matching file → list it for the DEV (do NOT fake it).
148
+
149
+ **0. Reference render (always, first):** render the target frame itself to
150
+ `public/assets/figma/_reference-<nodeId>.png` via `download_figma_images` (pass the
151
+ frame's own `nodeId`). This is the visual ground truth — keep it open and compare the
152
+ generated UI against it before finishing. Never reproduce a layout from node data alone.
153
+
154
+ **Export images — the anti-429 strategy (standard, follow exactly):**
155
+
156
+ > **What triggers 429 is the number of Figma API CALLS, not the number of images.**
157
+ > Downloading the image *bytes* from the returned AWS S3 URLs does NOT count against the
158
+ > Figma rate limit. So: make as FEW Figma calls as possible (ideally 2 total), each
159
+ > requesting MANY images, then pull all the bytes from S3. Never loop one-call-per-image.
160
+ >
161
+ > Rate limits are **tiered per seat** (since 2025-11-17): the render endpoint is Tier 1
162
+ > (10-20/min on Dev/Full seats, ~6/MONTH on View/Collab seats) and shares its bucket with
163
+ > `get_figma_data`. The fills map is Tier 2 (cheaper) — always prefer it.
164
+
165
+ Figma exposes images through two endpoints — use both, each in a single batched call:
166
+
167
+ | Source | Endpoint / MCP | Cost |
168
+ |--------|----------------|------|
169
+ | **Image fills** (raster fills, `fills[].type==="IMAGE"`) | `GET /v1/files/:key/images` → returns ALL `imageRef → S3 url` in **one** call | **Tier 2** — cheap, rarely 429 |
170
+ | **Render-only** (VECTOR/BOOLEAN, or image-fill refs missing from the fills map) | `GET /v1/images/:key?ids=<id1,id2,…all…>` → **one** call for ALL ids at once | **Tier 1** — shared bucket with `get_figma_data`; one batched call is fine |
171
+
172
+ Steps:
173
+
174
+ 1. **Collect & dedupe by `imageRef`.** The same `imageRef` on many nodes = the SAME picture —
175
+ resolve it once. (Typically cuts 140 nodes → a few dozen unique images.) Name files by ref
176
+ so reuse and re-runs are stable: image fill → `<imageRef>.png` (or `<layer-slug>-<ref8>.png`
177
+ for readability); render-only node → `<layer-slug>-<nodeId>.png`.
178
+ 2. **Skip what already exists** in `public/assets/figma/` — reuse it, don't re-download. Only
179
+ fetch the missing set. Re-runs become incremental and nearly free.
180
+ 3. **One call for fills:** hit the fills map once → map of `imageRef → S3 url`. Download the
181
+ missing ones' bytes from S3.
182
+ 4. **One call for the rest:** VECTOR/render nodes are gathered into a **single** render call:
183
+ `…/images/:key?ids=` with ALL their nodeIds comma-joined. Download the returned S3 URLs.
184
+ (Via MCP: one `download_figma_images` call with all the nodes in its `nodes` array — not one
185
+ call per node.)
186
+
187
+ **How one MCP call maps to REST** (verified against `figma-developer-mcp` v0.13.2 source —
188
+ `downloadImages()` makes at most 3 REST calls no matter how many nodes you pass):
189
+ - nodes with `imageRef`/`gifRef` → **1×** fills-map call (Tier 2; skipped if none)
190
+ - nodes with `nodeId` + `.png` filename → **1×** render call, all ids joined (Tier 1)
191
+ - nodes with `nodeId` + `.svg` filename → **1×** SEPARATE render call (Tier 1)
192
+ So: (a) pass EVERYTHING in one MCP call; (b) prefer ONE format for render-only nodes
193
+ (default `.png`) — mixing `.svg` + `.png` filenames doubles the Tier 1 render calls;
194
+ (c) the tool dedupes identical `imageRef`s within a call, but it does NOT skip files
195
+ already on disk and does NOT retry — skip-existing and 429 policy are YOUR job.
196
+
197
+ 4b. **Refs missing from the fills map are dropped SILENTLY.** If a node's `imageRef` isn't in
198
+ the fills map, the MCP returns no file for it — no error. After the call, diff the files on
199
+ disk against what you requested; re-request the missing ones in ONE follow-up call as render
200
+ nodes (`nodeId` only, no `imageRef`). Only nodes still missing after that go to the DEV.
201
+ 5. **On `429 Rate limit exceeded`:** read the `Retry-After` header first — it tells you which
202
+ limit you hit:
203
+ - **`Retry-After` ≤ 60s** → per-minute leaky bucket. Wait exactly that many seconds, then
204
+ retry **once**. If the retry also 429s, stop and report (below). Never retry more than once.
205
+ - **`Retry-After` > 60s (or absent), or `X-Figma-Rate-Limit-Type: low`** → seat/plan quota
206
+ (a View/Collab seat gets only ~6 Tier 1 calls per MONTH). Do NOT retry. **STOP and report
207
+ to the DEV:**
208
+ > ⚠️ Figma 429 while exporting images (got X/Y). retry-after ≈ <n>. This is the per-seat
209
+ > quota — a new token on the SAME account won't help. Options: use a token from a Dev/Full
210
+ > seat, switch to `aiflow init -a figma-desktop` (no REST quota), or export manually.
211
+ > Missing refs/nodeIds: …
212
+ 6. **A node may render to `null`** (deeply-nested instance Figma can't render standalone) — this
213
+ is NOT a rate-limit error. Report that one ref for manual export; don't fake it.
214
+ 7. **Prioritise** if large: backgrounds / hero / full-bleed first, then logos/icons, then art.
215
+
216
+ - **Verify on disk:** list `public/assets/figma/` and confirm a file exists for every unique
217
+ `imageRef`/`nodeId`. Re-running is cheap (existing files skipped).
218
+
219
+ **Large / art-heavy design (image nodes > 30):** tell the DEV up front
220
+ (`This frame has N image assets; exporting may take several batched calls`). Do NOT skip
221
+ the export to save time — the real images ARE the design. If the volume is impractical
222
+ in one pass, export backgrounds + key assets, then list the remaining nodeIds for the DEV
223
+ instead of approximating them.
224
+
225
+ **FAIL LOUD — never approximate.** If `download_figma_images` is unavailable, or images
226
+ fail to export (e.g. 429), **STOP**. Report which refs/nodes could not be exported and ask
227
+ the DEV how to proceed. Do NOT substitute CSS gradients / solid colours for an image node
228
+ and present the result as done — that is the #1 cause of "doesn't match the design".
229
+
230
+ - Fallback when the MCP tool itself is missing: get image URLs via `get_figma_data`,
231
+ give the DEV the URL→filename list, and pause until the files are placed in
232
+ `public/assets/figma/`.
94
233
 
95
234
  **Record the result:**
96
235
 
97
- After export, save the mapping for use in Step 4:
236
+ After export, persist the mapping to the per-design manifest (`plan/[ticket-id]/design/figma-manifest.json`
237
+ in Gate mode, else `public/assets/figma/figma-manifest.<fileKey>.json`) and load it as
238
+ `imageMap` for Step 4. Key by `nodeId`; **several nodeIds may point to the same file** when
239
+ they share an `imageRef` (reused image — downloaded once). This manifest is the same one the
240
+ DEV-provided-images mode reads, so manual and automatic exports converge on one source of truth:
98
241
 
99
242
  ```
100
243
  imageMap = {
101
- "123-456": "public/assets/figma/banner-top-123-456.png",
102
- "789-012": "public/assets/figma/icon-star-789-012.png"
244
+ "123-456": "public/assets/figma/banner-top-554b0901.png",
245
+ "777-888": "public/assets/figma/banner-top-554b0901.png", // same imageRef → same file, NOT re-downloaded
246
+ "789-012": "public/assets/figma/icon-star-9731a243.png"
103
247
  }
104
248
  ```
105
249
 
@@ -127,6 +271,43 @@ Type: 12→text-xs · 14→text-sm · 16→text-base · 18→text-lg · 20→
127
271
  400→font-normal · 500→font-medium · 600→font-semibold · 700→font-bold
128
272
  ```
129
273
 
274
+ ### Step 3.7: Build faithfully from the node tree (MANDATORY — do not summarize)
275
+
276
+ The #1 cause of "doesn't match the design" is generating a *re-interpretation* (a few labels +
277
+ a hand-picked subset of images in a generic centered/flow layout) instead of reproducing the
278
+ **actual node tree**. Follow these rules — they are not optional:
279
+
280
+ 1. **Reconstruct region by region from real child nodes.** Identify the design's regions from
281
+ the top-level containers (e.g. header frame, the form/panel frame, content sections, footer
282
+ frame). For EACH region, build its component from its OWN child nodes — every image, text,
283
+ and button that lives under that region node — placed in the same arrangement the node tree
284
+ has. Do NOT invent a structure or move elements between regions. "Header has its logo + nav +
285
+ buttons; the panel has its inputs + buttons; the footer has its logos + links" — keep each
286
+ asset in the region Figma puts it in.
287
+
288
+ 2. **Pick the background by PAINT ORDER, never by guessing.** Children are painted in array
289
+ order — a LATER sibling paints ON TOP of an earlier one. The visible full-bleed background is
290
+ the last opaque full-bleed layer, not the first one you find. Check sibling order + `opacity`
291
+ + `visible` before choosing which background image to render. (Classic bug: rendering an early
292
+ red layer when a later blue layer actually covers it.)
293
+
294
+ 3. **No-fabricate / no-omit.** The set of elements you render MUST equal the set of nodes in the
295
+ frame. Build a quick checklist from the node tree before coding:
296
+ - Every TEXT string in the frame appears in the UI (don't drop labels; don't translate).
297
+ - Every image node (from the manifest) is placed in its region (don't omit backgrounds, logos,
298
+ icons, decorative art).
299
+ - You add NOTHING that isn't in the frame (no buttons/sections from memory or another frame —
300
+ e.g. do not add an "Apple" button if only Google/Facebook exist in THIS node).
301
+ Diff your planned element list against the node tree; reconcile before generating code.
302
+
303
+ 4. **Match each region's container style to the node**, not to a default: background colour/image,
304
+ light vs dark, logo-as-image vs text, button shape (pill/outline/solid), spacing. Read the
305
+ node's `fills`, sizes and positions — don't assume a dark card or a text logo.
306
+
307
+ For a fixed-size, absolutely-positioned design (game UI, marketing LP), prefer reproducing each
308
+ region's internal arrangement closely (relative positions of its children) over forcing a generic
309
+ responsive flow; add responsiveness on top without losing the composition.
310
+
130
311
  ### Step 4: Generate component
131
312
 
132
313
  **Framework detection** — check in this order:
@@ -334,8 +515,20 @@ const variantClasses = {
334
515
 
335
516
  ### Step 6: Verify and output
336
517
 
518
+ **MANDATORY reference comparison (do this before claiming done — not optional):**
519
+ Open `public/assets/figma/_reference-<nodeId>.png` (the rendered frame from Step 2.5) and the
520
+ generated UI side by side, region by region. For each region (header / panel / sections / footer)
521
+ confirm: same background, same logo (image vs text), same buttons, same text, images in the right
522
+ place. **List every visible difference**, fix it, and re-compare. Do not finish while a region is
523
+ visibly wrong. If you cannot view the reference, say so and ask the DEV to eyeball it — do not
524
+ silently declare a match.
525
+
337
526
  After generation, verify:
338
527
 
528
+ - [ ] **Reference compare done**: generated UI matches `_reference-<nodeId>.png` region by region; differences fixed
529
+ - [ ] **No-fabricate**: nothing rendered that isn't in the node tree (no buttons/sections from memory/other frames)
530
+ - [ ] **No-omit**: every TEXT string + every manifest image is present in the right region
531
+ - [ ] **Background** is the correct paint-order layer (the one that actually covers the frame)
339
532
  - [ ] Layout matches Figma (flex direction, alignment, gap)
340
533
  - [ ] Colors mapping correct (project tokens, or arbitrary values if no match)
341
534
  - [ ] Typography correct (size, weight, line-height)
@@ -346,6 +539,8 @@ After generation, verify:
346
539
  - [ ] Props typed with TypeScript interface
347
540
  - [ ] Image nodes use `<img>` / `<Image>` (do not use CSS `background-image`)
348
541
  - [ ] Image files exist in `public/assets/figma/` before submitting code
542
+ - [ ] Compared the rendered result against `_reference-<nodeId>.png` — they look alike
543
+ - [ ] No image node was approximated with a CSS gradient/colour; any node that could not be exported is reported to the DEV, not faked
349
544
 
350
545
  ---
351
546
 
@@ -365,12 +560,17 @@ Always output in order:
365
560
 
366
561
  ## Rules
367
562
 
563
+ - **Build from the node tree, region by region** — reproduce each region (header/panel/sections/footer) from its real child nodes; do NOT re-interpret into a generic centered/flow layout. (Step 3.7)
564
+ - **Background by paint order** — the visible full-bleed background is the LAST opaque layer, not the first; check sibling order + opacity before choosing.
565
+ - **No-fabricate / no-omit** — rendered elements must equal the node set: every text + every manifest image placed; nothing added from memory or another frame.
566
+ - **Reference compare is mandatory** — compare the result against `_reference-<nodeId>.png` region by region and fix every difference before claiming done.
368
567
  - **Detect styling tooling first** — do not assume Tailwind; honour CSS Modules / styled-components / vanilla CSS when detected
369
568
  - **Prefer design tokens** — map Figma Styles/Variables to project tokens; only hardcode a value when no token matches
370
569
  - **Always use** the project's class-merge helper (`cn()` = clsx + twMerge for Tailwind)
371
570
  - **Responsive** — if Figma only has 1 breakpoint, default to mobile-first design
372
571
  - **Accessibility** — add `aria-label`, `role`, `alt` for interactive and image elements
373
- - **Image** — detect image fills in Figma node data, export via `download_figma_images` MCP, save to `public/assets/figma/`. Use `<Image>` (Next.js) or `<img>` (React/Vue) with `src` pointing to the exported file. Do NOT use CSS `background-image` for image nodes.
572
+ - **Image** — detect image fills in Figma node data, export via `download_figma_images` MCP: **ONE call with ALL nodes** in its `nodes` array (split only if huge — ~50 ids/call, 5-10s apart). On 429 follow the Retry-After policy in Step 2.5 (≤60s → wait + retry once; larger → report to DEV and stop). Save to `public/assets/figma/`. Use `<Image>` (Next.js) or `<img>` (React/Vue) with `src` pointing to the exported file. Do NOT use CSS `background-image` for image nodes.
573
+ - **Never fake an image** — if export fails or the MCP image tool is missing, STOP and report the failed nodeIds. Do NOT approximate a raster/art node with CSS gradients or solid colours and call it done. Always render the frame to `_reference-<nodeId>.png` first and compare against it.
374
574
  - **Icon** — if Figma uses SVG icons, extract SVG or map to lucide-react / heroicons
375
575
 
376
576
  ---
@@ -385,6 +585,8 @@ Always output in order:
385
585
  | `404` on node | Wrong `fileKey`/`nodeId` | Re-copy the frame URL; node-id uses `-` in URL but `:` in API |
386
586
  | Empty fills / no styles | Node is a component instance | Fetch the main component, or increase `depth` |
387
587
  | `download_figma_images` unsupported | Older MCP preset | Get image URL via `get_figma_data`, download manually to `public/assets/figma/` |
588
+ | `429 Rate limit exceeded` on images | Too many Tier 1 CALLS (metadata probes + per-node loops), or token from a View/Collab seat (~6 calls/MONTH) | Batch ALL ids into one call (Step 2.5). Check `Retry-After`: ≤60s → wait + retry once; hours/days or `X-Figma-Rate-Limit-Type: low` → seat quota — use a Dev/Full-seat token or `figma-desktop` adapter; new token on same account won't help |
589
+ | UI rendered but no images / wrong look | Export skipped or failed; layout faked with CSS | Render `_reference-<nodeId>.png`, export real image nodes (batched), replace CSS approximations with `<img>`/`<Image>` |
388
590
 
389
591
  ---
390
592
 
@@ -85,4 +85,4 @@ If any of the above cannot be answered from the ticket, ask exactly **one questi
85
85
  - [ ] Baseline defined (majority class, heuristic, or current production model)
86
86
  - [ ] Success threshold quantified (not "as high as possible")
87
87
  - [ ] Constraints listed (latency, memory, interpretability, data volume, compliance)
88
- - [ ] Findings written to `plan/[ticket-id]/ml-problem.md`
88
+ - [ ] Findings written to `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md` (see `custom/rules/ml-conventions.md` — do NOT use the legacy `plan/[ticket-id]/` path)
@@ -6,6 +6,8 @@ keywords: spec, plan, implementation, tdd, coding plan
6
6
 
7
7
  # Implementation Plan — Gate 2
8
8
 
9
+ > ⚠️ **Only invoke for `feature`, `bug-fix`, `refactor`, `investigation`, and `documentation` tasks.** For `gen-doc` tasks, skip this skill entirely — Gate 2 goes directly to document generation, no `plan.md` needed.
10
+
9
11
  > **GATE 2: Runs after Gate 1 (requirement document) has been APPROVED by DEV.**
10
12
  >
11
13
  > Principle: AI uses the approved requirement document to create a detailed implementation plan with TDD steps. DEV confirms the plan before coding begins.
@@ -32,6 +34,20 @@ When updating `AK-Docs/04.Coding/04.Reviews/[functionId]/[ticketId].md` in **fas
32
34
 
33
35
  Read `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md` — use the chosen approach, file list, and testing plan as input.
34
36
 
37
+ ### Step 1.5: Read Design Context (if present)
38
+
39
+ If `plan/[ticket-id]/design/design-context.md` exists (UI ticket from Gate 1):
40
+
41
+ 1. Read `design-context.md` — do NOT call Figma MCP again; the design is already cached.
42
+ 2. Feed these into the TDD plan:
43
+ - **Component tree** → one build task per component (with its variants/states)
44
+ - **Design tokens table** → mapping notes per component (color/type/space → project token)
45
+ - **Image Map** → a task to copy images from `plan/[ticket-id]/design/images/`
46
+ to `public/assets/figma/` before the component task that consumes them
47
+ 3. Each UI task must carry an acceptance note: "matches design-context.md (layout, color, type, spacing)".
48
+
49
+ If the file is absent → skip this step (non-UI ticket).
50
+
35
51
  ### Step 2: Create Implementation Plan
36
52
 
37
53
  **INVOKE:** `superpowers:writing-plans`
@@ -56,6 +72,9 @@ Create a detailed step-by-step plan based on the requirement document:
56
72
  ```
57
73
  ```
58
74
 
75
+ > For UI tasks, reference the exact node/component from `design-context.md` in the Task column
76
+ > (e.g. "Build UserCard — nodeId 78-910"). Add an image-copy task when the Image Map is non-empty.
77
+
59
78
  ### Step 3: GATE 2 — Present Plan & Start Coding
60
79
 
61
80
  ```markdown
@@ -76,7 +76,9 @@ When creating `AK-Docs/04.Coding/04.Reviews/[functionId]/[ticketId].md` during G
76
76
 
77
77
  5. Display Gate 1 prompt and wait for `APPROVED`.
78
78
 
79
- > After APPROVED, proceed to Gate 2. The lean doc is intentional — Gate 2 plan will fill in the details.
79
+ > After APPROVED, proceed to Gate 2.
80
+ > - **`gen-doc` tasks:** Gate 2 generates the output document immediately (no `plan.md`, no TDD). Self-review + task-summary.md are created automatically.
81
+ > - **All other tasks:** Gate 2 plan fills in the implementation details.
80
82
 
81
83
  ---
82
84
 
@@ -111,6 +113,63 @@ Do this investigation **before** asking any questions. Come prepared.
111
113
 
112
114
  ---
113
115
 
116
+ ### Step 1.5: Detect & Read Figma Design (UI tickets only)
117
+
118
+ Run this only when the ticket touches UI. Skip entirely for non-UI tickets.
119
+
120
+ 1. **Detect a Figma URL** in this order:
121
+ - `current.json` → `description`
122
+ - `current.json` → `supplementaryContext[]` items
123
+ - Pattern: `https://www.figma.com/design/<fileKey>/...?node-id=<nodeId>`
124
+ 2. **No URL but ticket looks like UI** (mentions screen, page, component, layout, "theo design"):
125
+ ask the DEV **once** to paste a Figma URL. If DEV skips → write "Design: TBD" in the
126
+ Design Analysis section and continue. Do NOT ask again.
127
+ 3. **URL found** → invoke `figma-to-component` Steps 0–2.5 (verify MCP, read design,
128
+ detect & export images). Then persist the shared artifact:
129
+ - Create `plan/[ticket-id]/design/`
130
+ - Save raw response to `plan/[ticket-id]/design/nodes.json` (cache for later gates)
131
+ - Save exported images to `plan/[ticket-id]/design/images/`
132
+ - Write `plan/[ticket-id]/design/figma-manifest.json` (nodeId → image file) — per-ticket,
133
+ NOT a shared global manifest
134
+ - Write `plan/[ticket-id]/design/design-context.md` using the template below
135
+ 4. **Figma MCP not connected** → tell DEV to run `aiflow init -a figma` (or `-a figma-desktop`),
136
+ mark Design Analysis as "⚠️ pending MCP", and continue with the non-UI parts of the requirement.
137
+ Do NOT abort the ticket.
138
+
139
+ **`design-context.md` template:**
140
+
141
+ ```markdown
142
+ # Design Context: [ticket-id]
143
+
144
+ **Figma URL:** <url> **fileKey:** xxx **nodeId:** 123-456
145
+ **Fetched:** [YYYY-MM-DD] **Adapter:** figma (REST) | figma-desktop
146
+
147
+ ## 1. Layout Structure
148
+ - Node tree: Frame > Header / Body > Card[] / Footer
149
+ - Flex direction, gap, padding, alignment per region
150
+
151
+ ## 2. Design Tokens
152
+ | Type | Figma value | Project token |
153
+ |------|-------------|---------------|
154
+ | Color | #3B82F6 | blue-500 / --color-primary |
155
+ | Type | 16/600 | text-base font-semibold |
156
+ | Space | 16px | p-4 / gap-4 |
157
+
158
+ ## 3. Components to build
159
+ - [ ] UserCard (variants: default, hover) — nodeId 78-910
160
+ - [ ] Header — nodeId 12-3
161
+
162
+ ## 4. Image Map
163
+ | nodeId | layer | file |
164
+ |--------|-------|------|
165
+ | 123-456 | Banner Top | design/images/banner-top-123-456.png |
166
+
167
+ ## 5. Notes
168
+ - Anything not mapped 1:1 (custom fonts, effects…)
169
+ ```
170
+
171
+ ---
172
+
114
173
  ### Step 2: Clarify Requirements via Q&A
115
174
 
116
175
  Ask clarifying questions directly — **one question at a time**, wait for the developer's response before asking the next.
@@ -227,6 +286,15 @@ Save to `AK-Docs/04.Coding/01.Requirements/[functionId]/[ticketId].md`:
227
286
 
228
287
  ---
229
288
 
289
+ ## Design Analysis (UI tickets only)
290
+
291
+ - **Source:** [Figma URL or "TBD" or "⚠️ pending MCP"]
292
+ - **Artifact:** `plan/[ticket-id]/design/design-context.md`
293
+ - **Summary:** layout, key components to build, design tokens to map, images exported
294
+ - **Impact on approach:** how the design shapes the proposed solution
295
+
296
+ ---
297
+
230
298
  ## 4. Impact Analysis
231
299
 
232
300
  **Impact Level:** 🟢 Low / 🟡 Medium / 🔴 High