@mmerterden/multi-agent-pipeline 16.10.0 → 16.11.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/CHANGELOG.md +37 -0
- package/README.md +110 -1
- package/README.tr.md +111 -1
- package/install/templates/copilot-instructions.md +1 -1
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/analysis/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/channels/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/design-check/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/help/SKILL.md +4 -4
- package/pipeline/commands/multi-agent/language/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/purge/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/resume-local/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/review/SKILL.md +7 -6
- package/pipeline/commands/multi-agent/setup/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/stack/SKILL.md +12 -13
- package/pipeline/commands/multi-agent/update/SKILL.md +1 -1
- package/pipeline/lib/extract-conventions.sh +19 -18
- package/pipeline/multi-agent-refs/_account-picker.md +1 -1
- package/pipeline/multi-agent-refs/_dev-context.md +2 -2
- package/pipeline/multi-agent-refs/_input-parser.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +4 -4
- package/pipeline/multi-agent-refs/analysis/intake.md +112 -36
- package/pipeline/multi-agent-refs/analysis/locked.md +1 -1
- package/pipeline/multi-agent-refs/analysis/render.md +37 -14
- package/pipeline/multi-agent-refs/analysis/synthesis.md +7 -7
- package/pipeline/multi-agent-refs/analysis-template-corporate.md +1 -1
- package/pipeline/multi-agent-refs/analysis-template.md +6 -6
- package/pipeline/multi-agent-refs/channels/confluence.md +1 -0
- package/pipeline/multi-agent-refs/channels/pr.md +2 -2
- package/pipeline/multi-agent-refs/conventions-defaults.md +13 -13
- package/pipeline/multi-agent-refs/features/stack-skill-routing.md +1 -1
- package/pipeline/multi-agent-refs/phases/modes.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +10 -6
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +6 -5
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +4 -4
- package/pipeline/multi-agent-refs/phases/phase-6-commit.md +7 -7
- package/pipeline/multi-agent-refs/picker-contract.md +29 -4
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/rules.md +4 -4
- package/pipeline/multi-agent-refs/{frontend-guide.md → web-guide.md} +2 -2
- package/pipeline/schemas/analysis-output.schema.json +1 -1
- package/pipeline/schemas/analysis-spec.schema.json +3 -3
- package/pipeline/schemas/prefs.schema.json +18 -2
- package/pipeline/scripts/gen-skills-index.mjs +1 -1
- package/pipeline/scripts/validate-analysis-doc.mjs +7 -3
- package/pipeline/scripts/validate-analysis.mjs +6 -1
- package/pipeline/scripts/write-state.mjs +29 -11
- package/pipeline/skills/.skills-index.json +24 -2
- package/pipeline/skills/shared/README.md +9 -7
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +11 -12
- package/pipeline/skills/skills-index.md +5 -3
|
@@ -10,7 +10,7 @@ Sequential `AskUserQuestion` chain. Each answer is written to state under `state
|
|
|
10
10
|
|
|
11
11
|
#### Step 0 - Language resolution (BLOCKING, runs before any picker)
|
|
12
12
|
|
|
13
|
-
Before emitting the first `AskUserQuestion`, read `prefs.global.outputLanguage` (`tr` or `en`, default `tr`). Every `<localized: "...">` marker in the Phase 0 picker chain (Steps 1-5) MUST be rendered in the resolved language - this is not deferred to Phase 3. Per the Language note above: `question` and `description` follow `outputLanguage`;
|
|
13
|
+
Before emitting the first `AskUserQuestion`, read `prefs.global.outputLanguage` (`tr` or `en`, default `tr`). Every `<localized: "...">` marker in the Phase 0 picker chain (Steps 1-5) MUST be rendered in the resolved language - this is not deferred to Phase 3. Per the Language note above: `question`, `label` and `description` follow `outputLanguage`; only `header` stays English (<=12-char chip). If `outputLanguage == tr`, the user sees Turkish question text; do not emit the English literal inside the `<localized:>` marker.
|
|
14
14
|
|
|
15
15
|
#### Step 1 - Analysis name
|
|
16
16
|
|
|
@@ -59,14 +59,49 @@ question: <localized: "Which platforms is this analysis for?">
|
|
|
59
59
|
options:
|
|
60
60
|
- label: "iOS"
|
|
61
61
|
- label: "Android"
|
|
62
|
+
- label: "Web" -> platform id `web`
|
|
62
63
|
- label: "Backend"
|
|
63
|
-
- label: "Frontend"
|
|
64
64
|
- label: "No platform yet"
|
|
65
|
-
description: <localized: "Analysis and technical analysis only
|
|
65
|
+
description: <localized: "Derive the channels from the sources. Analysis and technical analysis only - the development analysis waits for a repo.">
|
|
66
66
|
```
|
|
67
67
|
Empty submit → re-ask. Result: `state.analysisSpec.platforms[]`.
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
`web` is the canonical id; the pre-rename `frontend` is still read back (older state,
|
|
70
|
+
`:stack frontend`, the `ai-frontend-toolkit` plugin id) and normalises to `web`.
|
|
71
|
+
|
|
72
|
+
**`No platform yet` is a real answer, not a cancel** (Locked 35). It leaves
|
|
73
|
+
`platforms[]` empty, skips Step 4 entirely, and the run continues: evidence is still
|
|
74
|
+
fetched from every declared source, and the document renders every layer that does not
|
|
75
|
+
need a target repository. Only the development layer and the Pass B projection drop,
|
|
76
|
+
and Section 20 records that they await a repo selection.
|
|
77
|
+
|
|
78
|
+
**The channel split is then derived from the evidence, not abandoned** (Locked 35,
|
|
79
|
+
which carries the reasoning). After evidence collection, classify the run's channels
|
|
80
|
+
from what the sources say:
|
|
81
|
+
|
|
82
|
+
| Signal | Reads as |
|
|
83
|
+
|---|---|
|
|
84
|
+
| Figma frames at a phone viewport or named for an app flow; text naming an app store, push, a deep link, a native permission | `mobile` |
|
|
85
|
+
| Figma frames at desktop / tablet width or named for a browser page; text naming a browser, a URL route, SEO, a breakpoint | `web` |
|
|
86
|
+
| A Swagger contract consumed by a named client | that client's channel |
|
|
87
|
+
|
|
88
|
+
`mobile` is one channel here, not iOS plus Android; once a repo is selected the normal
|
|
89
|
+
`ios` / `android` split applies.
|
|
90
|
+
|
|
91
|
+
**Confirm the derivation, do not act on it silently.** The evidence proposes; the
|
|
92
|
+
user decides how many documents this run produces:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
header: "Channels" question: <localized: "Hangi kanallar icin dokuman uretilsin?">
|
|
96
|
+
options (label + description in outputLanguage; semantics, not literals):
|
|
97
|
+
"Mobile and web" | "Mobile only" | "Web only" | "One combined"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Each description names the evidence behind that channel (`8 frame, 2 dokuman`), so the
|
|
101
|
+
answer is informed. The derived set is the recommended option; autopilot takes it
|
|
102
|
+
without asking and logs what it picked and why. One channel: ask only split-out or
|
|
103
|
+
channel-agnostic. None: emit `analysis/<feature>.md` and say no channel signal was
|
|
104
|
+
found.
|
|
70
105
|
|
|
71
106
|
**Platform coverage = provided platforms.** The analysis renders exactly one per-platform file (Locked 9) for each platform selected here and given a repo in Step 4: select iOS only -> a single iOS document; select iOS + Android -> one iOS and one Android document, each projected through that repo's own conventions (Phase 1c) and its own Code Connect index (Phase 1b.1, discovered from that repo's `*.figma.swift` / `*.figma.kt`). Do not analyze a platform the user did not select, and do not drop a selected platform that has a repo.
|
|
72
107
|
|
|
@@ -83,49 +118,82 @@ When `platforms[]` is empty (Step 3 resolved to `No platform yet`), skip Steps 4
|
|
|
83
118
|
For each selected platform, run one AskUserQuestion round. Reuse `_dev-context.md` logic:
|
|
84
119
|
- Run `~/.claude/lib/submodule-detector.sh "$REPO_PATH"` to enumerate submodules + `canPush`
|
|
85
120
|
- Augment with `prefs.projects[<key>].editableRelatedRepos[]` for iOS / Android / Backend
|
|
86
|
-
- For `
|
|
121
|
+
- For `Web`, read `prefs.projects[<key>].webRepos[]` (falling back to the pre-rename `frontendRepos[]`) as the primary source (since Web is rarely in the iOS submodule tree); fall back to Other input
|
|
87
122
|
- If no repos are detectable for a platform, present a single Other input asking for `<owner>/<repo>`
|
|
88
123
|
|
|
89
124
|
Result: `state.analysisSpec.repos[]` (each entry has `platform`, `name`, `path`, `canPush`).
|
|
90
125
|
|
|
91
|
-
#### Step 5 - Input
|
|
126
|
+
#### Step 5 - Input sources (7 questions, 2 fixed batches)
|
|
127
|
+
|
|
128
|
+
`AskUserQuestion` accepts at most **4 questions per call**, so the seven source types
|
|
129
|
+
are asked as two fixed batches. Do not improvise the split: seven at once is an invalid
|
|
130
|
+
tool call, and an improvised retry separates the spec sources from each other.
|
|
131
|
+
|
|
132
|
+
- **Batch 1/2 - what the feature IS**: Figma, Confluence, Document, Jira. A written
|
|
133
|
+
spec arrives as an attached `.docx` / `.pdf` at least as often as a Confluence page,
|
|
134
|
+
so both are on the same screen.
|
|
135
|
+
- **Batch 2/2 - what constrains it**: Swagger, Standards, Firebase.
|
|
136
|
+
|
|
137
|
+
**Development-layer questions are gated on a platform being selected.** With
|
|
138
|
+
`platforms[]` empty that layer does not render (Locked 35), so a question feeding only
|
|
139
|
+
it spends attention on an answer nothing consumes.
|
|
140
|
+
|
|
141
|
+
Two questions feed only that layer and are therefore skipped:
|
|
142
|
+
|
|
143
|
+
| Skipped question | Feeds |
|
|
144
|
+
|---|---|
|
|
145
|
+
| Standards | global 13.7 Standards binding = corporate 17 (Part C) |
|
|
146
|
+
| UI Tests (Step 5a) | global 15.6 = corporate 19 (Part C) |
|
|
147
|
+
|
|
148
|
+
Everything else is still asked: Firebase (global 11 = corporate 13) and A11y depth
|
|
149
|
+
(global 16 = corporate 15) land in Part B, and the five source questions feed Parts A
|
|
150
|
+
and B.
|
|
151
|
+
|
|
152
|
+
With no platform, batch 2 is a 2-question call (Swagger, Firebase) and Step 5a a
|
|
153
|
+
1-question call (A11y depth). Name the skipped questions and the reason in the batch
|
|
154
|
+
breadcrumb, the way an auto-resolved step still prints its own line
|
|
155
|
+
(`picker-contract.md` Step narration).
|
|
92
156
|
|
|
93
|
-
|
|
157
|
+
Announce which batch is showing (`1/2`, `2/2`) in the narrator line above the picker.
|
|
158
|
+
Each question carries a skip option plus the host's auto-added `Other` for free-text
|
|
159
|
+
input. Skipped questions yield no entry in `state.analysisSpec.contextLinks[]`.
|
|
160
|
+
|
|
161
|
+
Option `label`s and `description`s render in `outputLanguage`; `header` stays English
|
|
162
|
+
per the `rules.md` matrix. The quoted strings below are the option SEMANTICS, not
|
|
163
|
+
literals to print, and the run branches on which option was chosen, never on its text.
|
|
94
164
|
|
|
95
165
|
```
|
|
166
|
+
BATCH 1/2 - what the feature is
|
|
167
|
+
|
|
96
168
|
Q1: header="Figma URL"
|
|
97
169
|
question: <localized: "Do you have a Figma URL for this feature?">
|
|
98
|
-
options:
|
|
99
|
-
- label: "No Figma input"
|
|
100
|
-
- label: "Use repo Code Connect only"
|
|
170
|
+
options: "No Figma input" · "Use repo Code Connect only"
|
|
101
171
|
(Other: paste URL - comma-separated for multiple frames)
|
|
102
172
|
|
|
103
|
-
Q2: header="
|
|
104
|
-
question: <localized: "Do you have a Swagger / OpenAPI URL?">
|
|
105
|
-
options:
|
|
106
|
-
- label: "No Swagger input"
|
|
107
|
-
- label: "Extract from Confluence instead"
|
|
108
|
-
(Other: paste URL)
|
|
109
|
-
|
|
110
|
-
Q3: header="Confluence"
|
|
173
|
+
Q2: header="Confluence"
|
|
111
174
|
question: <localized: "Do you have a Confluence page URL for the feature spec?">
|
|
112
|
-
options:
|
|
113
|
-
- label: "No Confluence input"
|
|
175
|
+
options: "No Confluence input"
|
|
114
176
|
(Other: paste URL - comma-separated for multiple pages)
|
|
115
177
|
|
|
178
|
+
Q3: header="Document"
|
|
179
|
+
question: <localized: "Do you have the spec as a file? A Word .docx, a .pdf, a .md
|
|
180
|
+
or a .txt - give a local path or a URL.">
|
|
181
|
+
options: "No document input"
|
|
182
|
+
(Other: absolute or tilde path, or a URL - comma-separated for multiple)
|
|
183
|
+
|
|
116
184
|
Q4: header="Jira"
|
|
117
185
|
question: <localized: "Do you have a related Jira ID?">
|
|
118
|
-
options:
|
|
119
|
-
- label: "No Jira input"
|
|
186
|
+
options: "No Jira input"
|
|
120
187
|
(Other: type Jira ID like {JIRA_KEY}-12345 - comma-separated for multiple)
|
|
121
188
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
189
|
+
BATCH 2/2 - what constrains it
|
|
190
|
+
|
|
191
|
+
Q5: header="Swagger URL"
|
|
192
|
+
question: <localized: "Do you have a Swagger / OpenAPI URL?">
|
|
193
|
+
options: "No Swagger input" · "Extract from Confluence instead"
|
|
194
|
+
(Other: paste URL)
|
|
127
195
|
|
|
128
|
-
|
|
196
|
+
Q6: header="Standards"
|
|
129
197
|
question: <localized: "Do you have coding documentation or standards to bind the development plan? Confluence URL, GitHub wiki URL, or local file path.">
|
|
130
198
|
options:
|
|
131
199
|
- label: "No standards input"
|
|
@@ -133,7 +201,7 @@ Q5: header="Standards"
|
|
|
133
201
|
description: "Searches the auto-detect probe list below (canonical home-dir Standards file, repo CLAUDE.md / CONTRIBUTING.md, docs/architecture/*.md, and the wiki Home.md / Navigation.md if a GitHub wiki is configured)"
|
|
134
202
|
(Other: comma-separated mix of Confluence URLs, GitHub wiki URLs, and absolute / tilde-expanded local file paths)
|
|
135
203
|
|
|
136
|
-
|
|
204
|
+
Q7: header="Firebase"
|
|
137
205
|
question: <localized: "Do you have Firebase Analytics events for this feature? Comma-separated event-name list, a JSON schema file path, or a Firebase Console URL.">
|
|
138
206
|
options:
|
|
139
207
|
- label: "No Firebase input"
|
|
@@ -142,13 +210,17 @@ Q6: header="Firebase"
|
|
|
142
210
|
(Other: comma-separated mix of event names like 'profile.view,profile.opened', a /path/to/events.json, or a console.firebase.google.com URL)
|
|
143
211
|
```
|
|
144
212
|
|
|
145
|
-
After
|
|
213
|
+
After each batch is submitted, pipe every Other-provided string into
|
|
214
|
+
`~/.claude/lib/context-link-extractor.sh` on **stdin** (`printf '%s' "$answer" | ~/.claude/lib/context-link-extractor.sh`) - it takes no argv, and an
|
|
215
|
+
argv call silently returns `[]` rather than erroring. Results are typed and written to `state.analysisSpec.contextLinks[]`. Standards-question entries are additionally tagged `binding: true` so Phase 2 Section 7 treats them as hard constraints (see the Phase 1 type table and the Phase 2 Section 7 row).
|
|
146
216
|
|
|
147
|
-
**
|
|
217
|
+
**Type detection rules for every Other input** (also documented in `~/.claude/lib/context-link-extractor.sh`):
|
|
148
218
|
|
|
149
219
|
| Input shape | Detected type | Phase 1 strategy |
|
|
150
220
|
|---|---|---|
|
|
151
221
|
| Starts with `/` or `~` and ends with `.md` / `.markdown` / `.txt` | `local-file` | `Read` tool on the absolute path (tilde-expanded) |
|
|
222
|
+
| Starts with `/` or `~` and ends with `.docx` / `.pdf` / `.md` / `.markdown` / `.txt` | `document` (`metadata.source: path`) | `~/.claude/lib/fetch-document.sh <path>` - see the `evidence.md` fetch table |
|
|
223
|
+
| An `http(s)://` URL whose path ends with `.docx` / `.pdf` / `.md` / `.markdown` / `.txt` | `document` (`metadata.source: url`) | Same fetcher; the file is downloaded first |
|
|
152
224
|
| Host = `github.com` AND path matches `/<owner>/<repo>/wiki/<PageName>` (no `.md`) | `wiki` | `git clone --depth 1 https://github.com/<owner>/<repo>.wiki.git /tmp/<repo>-wiki && Read /tmp/<repo>-wiki/<PageName>.md` (URL `-` to ` ` decoding) |
|
|
153
225
|
| Host matches `confluence*.<tld>` AND path contains `/display/` or `/pages/viewpage.action?pageId=` | `standards-confluence` | Same fetcher as `confluence` but bucket goes to `evidence.standards[]` |
|
|
154
226
|
| Comma-separated lowercase tokens with `.` or `_` (e.g. `profile.view,screen_view`) and no slash / no scheme | `firebase-events:names` | Scaffold rows from names alone |
|
|
@@ -156,23 +228,25 @@ After submit, run `~/.claude/lib/context-link-extractor.sh` on each Other-provid
|
|
|
156
228
|
| Host `console.firebase.google.com` with `/analytics/` in path | `firebase-events:console` | Reference-only; INFO warning printed, no fetch |
|
|
157
229
|
| Any other `http(s)://` URL | `generic-doc` | `WebFetch` |
|
|
158
230
|
|
|
159
|
-
|
|
231
|
+
Standards question - Auto-detect mode probe order (option 2):
|
|
160
232
|
1. `~/<project>-Standards.md` - canonical home-dir reference file; the exact filename comes from `prefs.projects[<project>].standardsFile` (no hardcoded project name in this command)
|
|
161
233
|
2. `<repo>/CLAUDE.md`, `<repo>/CONTRIBUTING.md`
|
|
162
234
|
3. `<repo>/docs/architecture/*.md`
|
|
163
235
|
4. If a `*.wiki.git` mirror is reachable for the primary repo, clone and ingest `Home.md` + any page named `Navigation*.md`
|
|
164
236
|
|
|
165
|
-
|
|
237
|
+
Firebase question - Auto-detect mode probe order (option 2):
|
|
166
238
|
1. Per-repo grep for `Analytics\.logEvent\(`, `firebaseAnalytics\.logEvent\(`, `logEvent\(analytics,` and harvest the first string literal in each call as the event name
|
|
167
239
|
2. Generated `AnalyticsEvents/*.swift` / `AnalyticsEvents/*.kt` if present (treat each public struct conforming to `AnalyticsEvent` as one event)
|
|
168
240
|
3. Repo-level `firebase-events.json` / `analytics/events.json` files
|
|
169
241
|
|
|
170
242
|
#### Step 5a - Coverage options (opt-in, 2 questions)
|
|
171
243
|
|
|
172
|
-
One `AskUserQuestion` call with 2 parallel yes/no questions
|
|
244
|
+
One `AskUserQuestion` call with 2 parallel yes/no questions - or 1 when
|
|
245
|
+
`state.analysisSpec.platforms[]` is empty, since `uiTests` only gates a section the
|
|
246
|
+
development layer would have carried (see the gating table in Step 5). These are opt-INs, not source intake: an empty answer is NOT consent (per `feedback_no-inferred-defaults-from-empty-answer`) - re-ask on empty rather than defaulting silently once the picker is shown.
|
|
173
247
|
|
|
174
248
|
```
|
|
175
|
-
Q1: header="UI Tests"
|
|
249
|
+
Q1: header="UI Tests" (skipped entirely when platforms[] is empty)
|
|
176
250
|
question: <localized: "Should the analysis include UI test scenarios (XCUITest / Compose UI test)? Optional; unit + snapshot coverage is always included.">
|
|
177
251
|
options:
|
|
178
252
|
- label: "No UI tests" -> state.analysisSpec.options.uiTests = false (default)
|
|
@@ -185,7 +259,9 @@ Q2: header="A11y depth"
|
|
|
185
259
|
- label: "Full walkthrough" -> state.analysisSpec.options.a11yDepth = "full"
|
|
186
260
|
```
|
|
187
261
|
|
|
188
|
-
`options.uiTests` gates Section 15.6 (UI test flows)
|
|
262
|
+
`options.uiTests` gates Section 15.6 (UI test flows), which lives in the development
|
|
263
|
+
layer; `options.a11yDepth` gates the Section 16 VoiceOver / TalkBack walkthrough, which
|
|
264
|
+
does not. Both default to the lighter choice so the doc stays lean unless the user opts in.
|
|
189
265
|
|
|
190
266
|
#### Step 5b - Repo-evidence collector (automatic, no prompt)
|
|
191
267
|
|
|
@@ -55,4 +55,4 @@ When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>
|
|
|
55
55
|
32. **Analysis profile selected at intake.** `state.analysisSpec.profile` is `global` (default) or `corporate`, asked once at Phase 0 Step 1b and never re-asked mid-run. `global` renders `$HOME/.claude/multi-agent-refs/analysis-template.md` (23 sections, development handoff). `corporate` renders `$HOME/.claude/multi-agent-refs/analysis-template-corporate.md` (requirements document: `IG -> UC -> FG` spine, three traceability matrices, current-to-target state with impact analysis, then Technical Analysis and Development Analysis). **Both profiles read the same `state.analysisSpec.evidence.*`** - intake, fetching, repo evidence and convention extraction are shared and profile-independent; only the projection differs. This is what keeps the two templates from drifting into two products. One run emits one profile: rendering both from a single run would produce two documents describing the same feature, and the next reader would have to decide which one is current. When only one profile is available (`prefs.global.analysisProfiles` lists one, or the corporate profile has no binding configuration), the step auto-resolves and prints its breadcrumb with the resolution noted, per the picker contract.
|
|
56
56
|
33. **Corporate backbone always renders.** In the `corporate` profile the Locked 2 omission rule is replaced for Part A and the footer: those sections render even with zero evidence, carrying `N/A` when the section is genuinely out of scope for the feature and `EKLENECEK` when evidence is expected but missing. This is the point of a requirements document - a reader has to be able to tell "we considered hardware needs and there are none" from "nobody looked". Every `EKLENECEK` emits a matching Section 20 Risks and Open Questions row naming what is missing and who can answer it; an `EKLENECEK` with no such row fails the dispatch gate, because an unanswered question nobody owns is how a placeholder reaches production. **Missing inputs never block the run**: the corporate source practice of halting until every input arrives is deliberately not adopted - the document is produced with `EKLENECEK` in the gaps and the gaps are raised in Section 20. Part B follows the global omission table unchanged. In the `global` profile Locked 2 applies as written, with no placeholder of any kind.
|
|
57
57
|
34. **References are built from the evidence record, not written.** Section 21 is emitted by `$HOME/.claude/scripts/build-references.mjs` from `state.analysisSpec.evidence.*` in both profiles. Each row carries a precision anchor in its `Sürüm / Ref` column - Figma node id, Confluence `pageId` plus page version, the commit SHA a repo was read at, the Swagger spec version - because a reference with no anchor points at a moving target. Each row carries an `Erişim / Access` cell: a declared source that could not be fetched still gets a row reading `erişilemedi (<reason>)`, since a silently dropped source reads to the next person as a source that never existed. User statements from the conversation that no fetched source contains are recorded as `Serbest metin` rows, quoted verbatim, with the decision they settled. **Coverage gate**: every entry in `evidence.figma[]`, `confluence[]`, `jira[]`, `swagger[]`, `repo[]`, `standards[]`, `firebase[]`, `documents[]`, `outside[]`, `freeText[]` and every entry in `evidence.fetchErrors[]` must appear as a row, and every row must map to an evidence entry. A source that shaped the document but is missing from References fails the dispatch gate; so does an invented row with no evidence behind it.
|
|
58
|
-
35. **Stack-optional render.** Platform and repo selection are optional. When `state.analysisSpec.platforms[]` is empty, the run still completes: the analysis layers that do not need a target repository render in full - Part A and Part B in the corporate profile, Sections 1-12 and 16-17 in the global profile - and only the development layer is dropped (corporate Part C; global Sections 13, 14, 15) along with the Pass B projection, since there are no conventions to project onto. A Section 20 row records that the development analysis awaits a repo selection.
|
|
58
|
+
35. **Stack-optional render.** Platform and repo selection are optional. When `state.analysisSpec.platforms[]` is empty, the run still completes: the analysis layers that do not need a target repository render in full - Part A and Part B in the corporate profile, Sections 1-12 and 16-17 in the global profile - and only the development layer is dropped (corporate Part C; global Sections 13, 14, 15) along with the Pass B projection, since there are no conventions to project onto. A Section 20 row records that the development analysis awaits a repo selection. **The channel split survives the missing repo.** Channels are derived from the evidence instead of repo stack tags (`intake.md` Step 3 carries the signal table) and one document is emitted per derived channel - `mobile`, `web`, or both. A phone screen and a browser screen carry different requirements before anyone has picked a repository; the split (Locked 9) exists to carry that difference and only its *projection* half needs conventions. `mobile` stays one channel rather than iOS plus Android, since without conventions nothing tells the two apart. Evidence with no interface at all yields a single channel-agnostic `<feature>.md`. Files land under `~/Desktop/multiAgentAnalysis/<feature-name>/`, named `<feature>-<channel>.md` (or `<feature>.md` for the channel-agnostic case): the repo-relative `analysis/` path has nothing to be relative to without a repo, and the current working directory is never used, since for a repo-less run it is arbitrary. Desktop rather than a hidden directory because the document is a deliverable somebody is meant to open and hand over, and `multiAgentAnalysis` rather than a bare `Analysis` because a generic word collides with whatever else is on a desktop while the producer name groups every run this command ever writes. The Phase 3.5 picker shows the resolved path and takes an override through its Other input. A requirements document is useful before anyone has decided which repository will hold the code, and refusing to produce one until that decision exists inverts the order the work actually happens in.
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
2. **Markdown render**: for each platform in `state.analysisSpec.platforms[]`, concatenate the per-platform spec into one markdown file. Tables in pipe-syntax. Numbering uses plain `## 1.`, `## 2.`, ... - omitted sections do **not** create gaps. Visible numbering is sequential 1..N over the rendered set. In the corporate profile the Part A and footer numbers are fixed and do not re-flow, since the backbone never drops; Part B and Part C follow the omission table as usual.
|
|
12
12
|
|
|
13
|
-
**When `platforms[]` is empty** (Locked 35),
|
|
13
|
+
**When `platforms[]` is empty** (Locked 35), the channels come from the evidence instead of from repo stack tags, so this loop runs once per derived channel (`mobile`, `web`, or one channel-agnostic pass). What drops is the development layer (corporate Part C, global Sections 13, 14, 15) and the Pass B projection are skipped, Section 20 carries a row recording that they await a repo selection, and the front-matter `platform` key reads `none`. Everything that does not need a target repository still renders in full.
|
|
14
14
|
|
|
15
15
|
3. **Humanizer pass (MANDATORY: actually invoke the `ai-common-toolkit:humanizer` skill on the rendered markdown - the punctuation grep alone does NOT satisfy this step)** (`technical-explanatory` tone for the scratch buffer; per-channel re-humanize happens in Phase 4 when actually emitting):
|
|
16
16
|
```
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
and paste its output under the References heading. The model does not hand-write this table; it is a projection of `state.analysisSpec.evidence.*`, which is what keeps a source the run actually read from going unlisted and a remembered-but-unread source from appearing.
|
|
33
33
|
|
|
34
|
-
4. **Write scratch drafts**: create `/tmp/analysis-<feature-slug>-<UTC-iso8601>/` and write `<feature>-<platform>.md`
|
|
34
|
+
4. **Write scratch drafts**: create `/tmp/analysis-<feature-slug>-<UTC-iso8601>/` and write `<feature>-<platform>.md` per selected platform. With `platforms[]` empty, write one file per derived channel (`<feature>-mobile.md`, `<feature>-web.md`; Locked 35), or a single `<feature>.md` when the evidence describes no interface. Update `state.analysisSpec.outputs.draftDir` with the path.
|
|
35
35
|
|
|
36
36
|
5. **Surface the draft tree to the user**:
|
|
37
37
|
```
|
|
@@ -48,18 +48,18 @@ AskUserQuestion (multiSelect=true), at least one selection required. `Local file
|
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
header: "Output"
|
|
51
|
-
question: <localized: "Where should the
|
|
51
|
+
question: <localized: "Where should the analyses be written?">
|
|
52
52
|
options:
|
|
53
53
|
- label: "Local file"
|
|
54
|
-
description: <resolved path, shown literally: "<repo>/analysis/<feature>-<platform>.md" per selected repo, or "~/Desktop/multiAgentAnalysis/<feature-name>/<feature>.md" when no repo was selected>
|
|
54
|
+
description: <resolved path, shown literally: "<repo>/analysis/<feature>-<platform>.md" per selected repo, or "~/Desktop/multiAgentAnalysis/<feature-name>/<feature>-<channel>.md" when no repo was selected>
|
|
55
55
|
- label: "Confluence page"
|
|
56
56
|
- label: "Jira issue"
|
|
57
57
|
description: <localized: "As a comment by default; writing the description is a separate, explicit choice">
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Conditional follow-ups:
|
|
61
|
-
- If `Confluence` selected: ask `header="Parent page"`, free-text via Other for the parent page key or URL. One Confluence page per
|
|
62
|
-
- If `Jira` selected: if Step 5
|
|
61
|
+
- If `Confluence` selected: ask `header="Parent page"`, free-text via Other for the parent page key or URL. One Confluence page per emitted document is created under this parent, each titled `<Feature> - <Platform>` (or `<Feature> - Mobile` / `<Feature> - Web` on a repo-less run, or a bare `<Feature>` for a single channel-agnostic document).
|
|
62
|
+
- If `Jira` selected: if the Step 5 Jira question produced Jira IDs, AskUserQuestion (single-select) to pick which one; otherwise ask via Other. Per Locked decision 9 + design choice "single description with platform separators", the chosen issue receives one combined body holding all per-platform sections under `h2. Platform: <X>` separators (wiki markup - neither the comment nor the description field renders Markdown; conversion happens at dispatch, see Phase 4).
|
|
63
63
|
|
|
64
64
|
Then ask **where in the issue it goes**, because two of the three answers can destroy text somebody else wrote:
|
|
65
65
|
|
|
@@ -96,11 +96,11 @@ Iterate `state.analysisSpec.outputs.requested`. For each target:
|
|
|
96
96
|
|
|
97
97
|
| Target | Action |
|
|
98
98
|
|--------|--------|
|
|
99
|
-
| Local | For each per-platform draft, `cp /tmp/analysis-<feature-slug>-<ts>/<feature>-<platform>.md` into `analysis/<feature>-<platform>.md` in the matching repo's working tree. When multiple repos exist for the same platform, the file is duplicated into each and the dispatch report lists every destination. **When no repo was selected** (Locked 35) there is no working tree to be relative to, so
|
|
100
|
-
| Confluence | Re-humanize each
|
|
101
|
-
| Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate
|
|
99
|
+
| Local | For each per-platform draft, `cp /tmp/analysis-<feature-slug>-<ts>/<feature>-<platform>.md` into `analysis/<feature>-<platform>.md` in the matching repo's working tree. When multiple repos exist for the same platform, the file is duplicated into each and the dispatch report lists every destination. **When no repo was selected** (Locked 35) there is no working tree to be relative to, so files land in `~/Desktop/multiAgentAnalysis/<feature-name>/`, one per derived channel (`<feature>-mobile.md`, `<feature>-web.md`) or a single `<feature>.md` when none could be derived. The current working directory is never written to: for a repo-less run it is arbitrary, and creating a folder in whatever directory the command happened to be invoked from is the kind of surprise that costs a tool its trust. The user can override the path through the picker's Other input. **No commit.** |
|
|
100
|
+
| Confluence | Re-humanize each draft with `formal-stakeholder` tone. One page per draft under the chosen parent, titled `<Feature> - <Platform>` - including a repo-less run, whose drafts are the derived channels (`<Feature> - Mobile` / `<Feature> - Web`, Locked 35). A single channel-agnostic draft becomes one page titled `<Feature>`, with no suffix implying a split that was not made. Cross-link siblings inside each page via `<ac:link><ri:page ri:content-title="<Feature> - <OtherPlatform>"/></ac:link>`; a lone page has no sibling block. Markdown -> storage XML via `$HOME/.claude/multi-agent-refs/channels/confluence.md`. Re-emit on existing pages uses PUT with version bump. |
|
|
101
|
+
| Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate the drafts under `h2. Platform: <X>` separators in production order - `iOS`, `Android`, `Web`, `Backend` repo-backed, `Mobile` / `Web` for channels derived on a repo-less run (Locked 35). A single channel-agnostic draft gets no separator: a heading announcing a split of one is noise. then run the whole body through the markdown → Jira wiki conversion table in `$HOME/.claude/multi-agent-refs/channels/jira.md` - both the comment body and the `description` field render wiki markup, so raw `##`/`**`/backticks arrive as literal text. Write the converted body to a file and publish it with `$HOME/.claude/lib/jira-publish.sh`, never with a hand-rolled `curl`: <br><br>`bash "$HOME/.claude/lib/jira-publish.sh" --issue "$KEY" --body-file "$F" --target comment` <br>`bash "$HOME/.claude/lib/jira-publish.sh" --issue "$KEY" --body-file "$F" --target description --mode append` <br><br>The script owns the parts that are easy to get wrong: it runs `jira-wiki-escape.mjs` on the body, resolves host + token without putting either in argv, and on the description path it GETs the current value, writes it to a backup under `~/.claude/logs/multi-agent/jira-backups/` and reports the path, appends below a `----` rule by default, and **refuses with exit 3** when `--mode replace` would discard a non-empty description unless `--confirm-overwrite` is passed. Exit 3 is reported to the user with the backup path, never retried with the flag added automatically - only the user's explicit "Description - replace" answer from Phase 3.5 supplies it. `--dry-run` previews the exact final body without writing. |
|
|
102
102
|
|
|
103
|
-
**Output capture**: fill `state.analysisSpec.outputs.localPaths[]` (one entry per per-platform-per-repo write), `outputs.confluencePageUrls[]` (one entry per
|
|
103
|
+
**Output capture**: fill `state.analysisSpec.outputs.localPaths[]` (one entry per per-platform-per-repo write, or one per derived channel on a repo-less run), `outputs.confluencePageUrls[]` (one entry per emitted document), `outputs.jiraIssueKey` (single string).
|
|
104
104
|
|
|
105
105
|
### Phase 5 - Report & stop
|
|
106
106
|
|
|
@@ -169,9 +169,32 @@ Per the `analysis-output-confluence-on-request` memory, Confluence post is NEVER
|
|
|
169
169
|
2. Use parent page URL from user input. No default parent is hardcoded here; the user picks one at the prompt (LRU recents come from `prefs.projects[<project>].confluenceUrls`).
|
|
170
170
|
|
|
171
171
|
**Corporate profile exception.** When `state.analysisSpec.profile == "corporate"` and the bindings are configured, the destination is already settled and the prompt is skipped: the space comes from `prefs.global.analysisProfile.corporate.confluenceSpaceKey`, the parent from `prefs.global.analysisProfile.corporate.confluenceParentPageId`, and the page title is built from `prefs.global.analysisProfile.corporate.titleFormat` with `prefs.global.analysisProfile.corporate.titlePrefix` filling its `{prefix}` placeholder. A corporate analysis always lands in the same tree, so asking each time is a question whose answer never changes. Any of the four missing falls back to the prompt above rather than guessing, and a title that would collide with an existing page becomes an update (PUT with version bump), never a second page.
|
|
172
|
-
3.
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
172
|
+
3. **Publish with `md2confluence-v3.py`, never a hand-rolled conversion + curl.** The
|
|
173
|
+
script owns the three steps that are easy to get wrong and that a hand-rolled path
|
|
174
|
+
has already dropped in practice: the storage-XML conversion (the table in
|
|
175
|
+
`$HOME/.claude/multi-agent-refs/channels/confluence.md`), the multipart upload of
|
|
176
|
+
every PNG in `--attachments-dir`, and the `` to
|
|
177
|
+
`<ac:image><ri:attachment ri:filename="file.png"/></ac:image>` injection that makes
|
|
178
|
+
a frame gallery render as pictures instead of as filenames (Locked 18). It also
|
|
179
|
+
warns when a body references an image no attachment matched, which is the signal
|
|
180
|
+
that a screenshot never downloaded.
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
python3 "$HOME/.claude/lib/md2confluence-v3.py" create \
|
|
184
|
+
--space "$SPACE" --parent-page-id "$PARENT" --title "$TITLE" \
|
|
185
|
+
--markdown "$DRAFT" --attachments-dir "$(dirname "$DRAFT")"
|
|
186
|
+
# updating an existing page: `update --page-id <ID>` instead of `create --space ...`
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Screenshots must already sit in `--attachments-dir` before this runs. Point
|
|
190
|
+
`figma-screenshot.sh --output-dir` at the draft directory during evidence
|
|
191
|
+
collection rather than letting it default to its own `/tmp` folder, because a
|
|
192
|
+
frame gallery whose PNGs live somewhere else converts to `<a href="frame-NNN.png">`
|
|
193
|
+
and the page shows filenames where the pictures should be. MCP asset URLs expire
|
|
194
|
+
after 7 days, so the cell must reference the local file, never the remote URL.
|
|
195
|
+
4. Read the script's JSON envelope: it reports the page id and URL, every attachment
|
|
196
|
+
uploaded, and the `image reference has no matching attachment` warnings. A non-empty
|
|
197
|
+
warning list means the page shipped with missing pictures; surface it rather than
|
|
198
|
+
reporting a clean publish. Surface the page URL in the Phase 4 report.
|
|
176
199
|
|
|
177
200
|
Token miss handling: surface a single line `WARN: Confluence token not configured (prefs.global.keychainMapping.confluence). Run /multi-agent:setup or skip Confluence output.` and continue with local-only output.
|
|
@@ -13,11 +13,11 @@ Build one in-memory `synthesizedSections` object from all evidence. Apply the om
|
|
|
13
13
|
```
|
|
14
14
|
synthesizedSections = {
|
|
15
15
|
scope: { ... shared block ... },
|
|
16
|
-
design: { shared: {frameGallery, codeConnect}, byPlatform: {ios, android,
|
|
17
|
-
localization: { keys: [...], byPlatform: {ios: {source: "Localizable.strings", rows}, android: {source: "strings.xml", rows},
|
|
16
|
+
design: { shared: {frameGallery, codeConnect}, byPlatform: {ios, android, web} },
|
|
17
|
+
localization: { keys: [...], byPlatform: {ios: {source: "Localizable.strings", rows}, android: {source: "strings.xml", rows}, web: {source: "i18n/*.json", rows}} },
|
|
18
18
|
apiContracts: { ... shared verbatim ... },
|
|
19
|
-
deeplinkPush: { byPlatform: {ios, android,
|
|
20
|
-
business: { rules: [...], useCases: [...], firebaseEvents: [...], byPlatform: {ios: {testFramework: "Swift Testing", skeletons}, android: {testFramework: "JUnit5 + Turbine"},
|
|
19
|
+
deeplinkPush: { byPlatform: {ios, android, web, backend: null} },
|
|
20
|
+
business: { rules: [...], useCases: [...], firebaseEvents: [...], byPlatform: {ios: {testFramework: "Swift Testing", skeletons}, android: {testFramework: "JUnit5 + Turbine"}, web: {testFramework: "Vitest + RTL"}, backend: {testFramework: "pytest"}} },
|
|
21
21
|
devPlan: { byPlatform: {ios: {tasks, standards}, android: {...}, ...} }
|
|
22
22
|
}
|
|
23
23
|
```
|
|
@@ -28,7 +28,7 @@ synthesizedSections = {
|
|
|
28
28
|
| 2. Design | If `evidence.figma[]` is empty AND no `evidence.repoEvidence[*].buckets.uiComponents` direct-match → `byPlatform[*]` = null. Otherwise produce frame gallery (shared) + per-platform component inventory (rows from `evidence.repoEvidence[<repo>].buckets.uiComponents`). |
|
|
29
29
|
| 3. Localization | If both Figma annotations/text layers and `evidence.repoEvidence[*].buckets.localizationKeys` are empty → `byPlatform[*]` = null. Otherwise produce the key table per the project `localization.ownership` mode (Locked 20): `in-repo` fills the configured locale set (default `ar, de, en, es, fr, it, ru, tr`, RTL for ar); `externally-owned` lists key + status + copy source + base value and defers per-locale values. Base copy is sourced from the Figma annotation when present (Locked 3). |
|
|
30
30
|
| 4. API Contracts | If `evidence.swagger[]` is empty AND no Confluence embedded API table AND no `evidence.repoEvidence[*].buckets.services` direct-match → null. Otherwise produce endpoint summary + per-endpoint tables (shared verbatim across files). |
|
|
31
|
-
| 5. Deeplink / Push | Per-platform: iOS uses Universal Links / `UNUserNotificationCenter`; Android uses `intent-filter` / FCM;
|
|
31
|
+
| 5. Deeplink / Push | Per-platform: iOS uses Universal Links / `UNUserNotificationCenter`; Android uses `intent-filter` / FCM; Web uses web URL routing; Backend file omits this section entirely. |
|
|
32
32
|
| 6. Business + Tests | If sections 2 and 4 are both `null` AND `evidence.firebase[]` is empty → null. Otherwise produce use-case + mock stubs + per-platform test skeletons + shared Firebase events table. Reuse Red-Green-Refactor naming from `$HOME/.claude/rules/tdd.md`. |
|
|
33
33
|
| 7. Development Plan | Always present. Tasks for the current platform only. Architecture standards come from `evidence.standards[]` filtered by platform (see Pass B step 1). **Reuse-first rule (Locked 11)**: when an item has `direct-match` in `evidence.repoEvidence[<repo>].buckets.<X>`, emit `Reuse existing <FQN> (<file>:<line>)` instead of `Add new <FQN>`. New-write task with a `direct-match` competitor becomes a Risk row. |
|
|
34
34
|
|
|
@@ -85,8 +85,8 @@ For each `platform` in `state.analysisSpec.platforms[]`:
|
|
|
85
85
|
- `ios` → `prefs.projects[<key>].standardsFile` if present → glob `~/<project>-iOS-Standards.md` → `~/.claude/rules/swiftui-qa.md`
|
|
86
86
|
- `android` → `~/.claude/rules/kotlin-android.md` first → `evidence.standards[]` entries whose path contains `android` or `kotlin`
|
|
87
87
|
- `backend` → `evidence.standards[]` entries matching language hints (`python`, `go`, `node`, `fastapi`) → fall back to `~/.claude/rules/security.md` + `code-style.md`
|
|
88
|
-
- `
|
|
89
|
-
2. **Apply per-platform omission rules.** Backend-only file drops Sections 5, 6, 7, 8, 16.
|
|
88
|
+
- `web` → `evidence.standards[]` entries matching `react`, `vue`, `next`, `sveltekit` → `~/.claude/rules/code-style.md`
|
|
89
|
+
2. **Apply per-platform omission rules.** Backend-only file drops Sections 5, 6, 7, 8, 16. Web with no UI inventory still keeps 5 (UI exists in code). Sections 1, 2, 4, 9, 13, 14, 20, 21 always present per Locked decision 2 + 13.
|
|
90
90
|
3. **Resolve mode.** If user passed `--lite` → Lite. If user passed `--full` → Full. Otherwise use `state.analysisSpec.liteModeAuto`. Lite mode renders only Sections 1, 2, 4, 9, 13, 14, 21 plus optional 23.
|
|
91
91
|
4. **Produce YAML front-matter header** (see `$HOME/.claude/multi-agent-refs/analysis-template.md`). Include `profile: <state.analysisSpec.profile | global>` and `platform: <platform | none>` so the validator applies the right contract per profile (Locked 32) and recognises the stack-optional render (Locked 35), `mode: full | lite`, plus `ui_tests: <state.analysisSpec.options.uiTests | false>` and `a11y_depth: <state.analysisSpec.options.a11yDepth | basic>` so the pre-dispatch validator can enforce the opt-in coverage (15.6 present when ui_tests, 16.2 walkthrough present when a11y_depth is full).
|
|
92
92
|
5. **Read conventions for this platform's repo.** For each cell Pass B fills in Section 13 and in any per-platform projection (Sections 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17), read `state.analysisSpec.evidence.conventions[<repo>].<field>` and emit the value with a footnote (Locked 24). If `conventionOverrides` has an entry for that field, use the override and footnote with `^[user-override: <reason>]` instead of evidence path.
|
|
@@ -374,7 +374,7 @@ Which user-facing copy this feature needs, who owns it, and where it comes from.
|
|
|
374
374
|
|
|
375
375
|
# Bölüm B - Teknik Analiz / Part B - Technical Analysis
|
|
376
376
|
|
|
377
|
-
Part B carries what is technically true. It reuses the global template's scaffolds verbatim, renumbered. Read `analysis-template.md` for each one; only the number changes.
|
|
377
|
+
Part B carries what is technically true. It reuses the global template's scaffolds verbatim, renumbered. Read `analysis-template.md` for each one; only the number changes - the number, not the contents. Rebuilding a table from its heading instead of copying the scaffold is how the frame gallery lost its `` cells and shipped filenames as text.
|
|
378
378
|
|
|
379
379
|
| Corporate | Global | Section |
|
|
380
380
|
|---|---|---|
|
|
@@ -42,7 +42,7 @@ Every per-platform file starts with this YAML block:
|
|
|
42
42
|
```yaml
|
|
43
43
|
---
|
|
44
44
|
feature: <FeatureName>
|
|
45
|
-
platform: ios | android | backend |
|
|
45
|
+
platform: ios | android | web | backend | mobile | none
|
|
46
46
|
profile: global | corporate
|
|
47
47
|
language: tr | en
|
|
48
48
|
mode: full | lite
|
|
@@ -338,7 +338,7 @@ Precise-enough-to-reproduce layout. Spacing/padding are token names (no raw numb
|
|
|
338
338
|
Capture order (tokens never hardcoded): `mcp__claude_ai_Figma__get_metadata` (tree) -> `mcp__claude_ai_Figma__get_variable_defs` (resolve spacing/color/type tokens) -> render -> `mcp__claude_ai_Figma__get_screenshot` (visual check). Run per section/frame for fidelity, not per whole page.
|
|
339
339
|
```
|
|
340
340
|
|
|
341
|
-
|
|
341
|
+
Every Screenshot cell is a markdown image reference to a locally cached PNG - ``, never a bare filename and never a remote URL. Dispatch uploads them as Confluence multipart attachments and injects `<ac:image><ri:attachment ri:filename="..." /></ac:image>` (Locked 18, run by `md2confluence-v3.py --attachments-dir`). Section URL drilling enumerates all child frames automatically via `mcp__claude_ai_Figma__get_metadata` or `figma-screenshot.sh --section`.
|
|
342
342
|
|
|
343
343
|
## 6. Bileşen Envanteri / Component Inventory
|
|
344
344
|
|
|
@@ -414,7 +414,7 @@ Rendered when the design ships a dark variant (else drop with note `(N/A: no dar
|
|
|
414
414
|
| <named asset> | icon@light | icon@dark | asset-catalog appearance variant |
|
|
415
415
|
```
|
|
416
416
|
|
|
417
|
-
Per-platform projection translates token names: iOS uses `.Spacing.spacingN` enum + adaptive `Color(.systemBackground)` / asset appearances; Android uses `MaterialTheme.spacing.medium` + Material 3 color roles with tonal elevation in dark;
|
|
417
|
+
Per-platform projection translates token names: iOS uses `.Spacing.spacingN` enum + adaptive `Color(.systemBackground)` / asset appearances; Android uses `MaterialTheme.spacing.medium` + Material 3 color roles with tonal elevation in dark; Web uses CSS variables `--spacing-md` / `--color-*` per `prefers-color-scheme`; Backend section omitted.
|
|
418
418
|
|
|
419
419
|
## 8. Asset Envanteri / Asset Inventory
|
|
420
420
|
|
|
@@ -539,7 +539,7 @@ Per-platform projection (both modes):
|
|
|
539
539
|
| iOS | `Localizable.xcstrings` | hierarchical dot PascalCase | `Feature.Element` ^[C6 high] |
|
|
540
540
|
| Android | `strings.xml` | flat snake_case | `feature_element` ^[C6 high] |
|
|
541
541
|
| Backend | error code table | per server convention | uppercase enum |
|
|
542
|
-
|
|
|
542
|
+
| Web | `i18n/*.json` | hierarchical dot camelCase | `feature.element` ^[C6 high] |
|
|
543
543
|
|
|
544
544
|
## 11. Analytics
|
|
545
545
|
|
|
@@ -735,7 +735,7 @@ Per-platform projection.
|
|
|
735
735
|
|
|
736
736
|
Locked 31 - one sub-table per business rule from Section 4.4. Enumerate the cases: happy, boundary (min/max, off-by-one), error/failure, empty/nil. Each row is Given / When / Then plus a framework-correct test name that traces back to the `BR-` id. Boundary rows collapse into one parameterized test.
|
|
737
737
|
|
|
738
|
-
Framework per platform (from Phase 1c conventions; these are the modern defaults): iOS Swift Testing (`@Test`, `@Suite`, `@Test(arguments:)` for boundary tables, `#expect` / `#require`); Android JUnit5 + MockK (`coEvery` / `coVerify`) + Turbine (`flow.test { awaitItem() }`) + coroutines-test (`runTest`, `StandardTestDispatcher`); Backend pytest (parametrize);
|
|
738
|
+
Framework per platform (from Phase 1c conventions; these are the modern defaults): iOS Swift Testing (`@Test`, `@Suite`, `@Test(arguments:)` for boundary tables, `#expect` / `#require`); Android JUnit5 + MockK (`coEvery` / `coVerify`) + Turbine (`flow.test { awaitItem() }`) + coroutines-test (`runTest`, `StandardTestDispatcher`); Backend pytest (parametrize); Web Vitest.
|
|
739
739
|
|
|
740
740
|
**BR-<slug>-01**
|
|
741
741
|
|
|
@@ -1094,7 +1094,7 @@ Folder: `app/api/profile/`, `app/services/profile/`, `app/schemas/profile/`
|
|
|
1094
1094
|
Test name: `def test_fetch_valid_input_returns_profile():`
|
|
1095
1095
|
OpenAPI operationId: `updateProfile`
|
|
1096
1096
|
|
|
1097
|
-
##
|
|
1097
|
+
## Web render example
|
|
1098
1098
|
|
|
1099
1099
|
Conventions extracted: Next.js App Router, feature folder, React Query hooks, Zustand stores, Vitest, kebab data-testid, hierarchical dot camelCase i18n.
|
|
1100
1100
|
|
|
@@ -115,6 +115,7 @@ Auto-suggested as `"{jiraId} - {taskTitle}"` - user can edit at the prompt.
|
|
|
115
115
|
| Code fences ` ```lang ` | `<ac:structured-macro ac:name="code"><ac:parameter ac:name="language">lang</ac:parameter><ac:plain-text-body><![CDATA[...]]></ac:plain-text-body></ac:structured-macro>` |
|
|
116
116
|
| Inline `code` | `<code>code</code>` |
|
|
117
117
|
| Links `[t](u)` | `<a href="u">t</a>` |
|
|
118
|
+
| Images `` | `<ac:image><ri:attachment ri:filename="file.png"/></ac:image>`, with the file uploaded as a page attachment first (Locked 18). An `http(s)` src renders as an external image instead. `md2confluence-v3.py --attachments-dir <dir>` does both halves. **When the named file is not in that directory the converter degrades to `<a href="file.png">file.png</a>` - a page showing filenames instead of pictures means the PNGs never reached `--attachments-dir`, not that the syntax was wrong.** It emits `image reference has no matching attachment: <file>` for each one. |
|
|
118
119
|
| Lists | `<ul><li>...</li></ul>` / `<ol><li>...</li></ol>` |
|
|
119
120
|
| ` ```mermaid ` fences | `ac:name="mermaid"` macro (`md2confluence-v3.py` implements it, with a numbered-list fallback when the space lacks the plugin) - not the generic code macro |
|
|
120
121
|
|
|
@@ -31,11 +31,11 @@ The PR description targets code reviewers - it stays technical. Every adapter
|
|
|
31
31
|
- `<path/to/test.ext>` - <which scenarios were added/updated>
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Across stacks the same shape produces, for example: `LoginView.swift - ...` (iOS), `LoginScreen.kt - ...` (Android), `login-form.tsx - ...` (
|
|
34
|
+
Across stacks the same shape produces, for example: `LoginView.swift - ...` (iOS), `LoginScreen.kt - ...` (Android), `login-form.tsx - ...` (web), `auth_service.py - ...` (backend). File paths and symbol names are NOT translated - only the trailing description sentence follows `outputLanguage`.
|
|
35
35
|
|
|
36
36
|
**`architecture`** - only when the change involves a non-trivial decision (new abstraction, pattern change, data flow shift, dependency direction). Format: short paragraph stating the decision and the alternative considered. Skip the section entirely for mechanical refactors / dependency bumps / formatting passes.
|
|
37
37
|
|
|
38
|
-
**`verification`** - what the reviewer should run to confirm the change works. Commands first, manual steps next. Pick the commands for the project's stack - the pipeline supports iOS (Swift/Xcode), Android (Gradle),
|
|
38
|
+
**`verification`** - what the reviewer should run to confirm the change works. Commands first, manual steps next. Pick the commands for the project's stack - the pipeline supports iOS (Swift/Xcode), Android (Gradle), web (npm/pnpm/yarn), and backend (varies: pytest/jest/go test/etc). Do not hardcode one stack in the body; emit only the commands relevant to the repos touched by this PR.
|
|
39
39
|
|
|
40
40
|
Skeleton (the adapter fills the body with the actual stack-appropriate lines at write-time; the template lists the shape only):
|
|
41
41
|
|