@starci/skills 1.1.0 → 1.2.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.
Files changed (75) hide show
  1. package/INDEX.md +3 -1
  2. package/INDEX.vi.md +3 -1
  3. package/README.md +6 -1
  4. package/README.vi.md +6 -1
  5. package/knowledge/ui/presentation/INDEX.md +5 -0
  6. package/knowledge/ui/presentation/INDEX.vi.md +1 -0
  7. package/knowledge/ui/presentation/radius.md +183 -0
  8. package/knowledge/ui/presentation/radius.vi.md +182 -0
  9. package/operators/INDEX.md +5 -5
  10. package/operators/INDEX.vi.md +5 -5
  11. package/operators/architecture-decide/operator.md +27 -4
  12. package/operators/architecture-decide/operator.vi.md +23 -4
  13. package/operators/architecture-decide/self-test.mjs +18 -1
  14. package/operators/architecture-decide/validate.mjs +29 -1
  15. package/operators/backend-source-apply/operator.md +197 -182
  16. package/operators/backend-source-apply/operator.vi.md +190 -178
  17. package/operators/backend-source-apply/self-test.mjs +257 -257
  18. package/operators/backend-source-apply/validate.mjs +240 -240
  19. package/operators/business-decide/self-test.mjs +2 -1
  20. package/operators/business-decide/validate.mjs +3 -0
  21. package/operators/content-generate/self-test.mjs +1 -1
  22. package/operators/frontend-direction-decide/self-test.mjs +1 -1
  23. package/operators/frontend-presentation-resolve/operator.md +6 -0
  24. package/operators/frontend-presentation-resolve/operator.vi.md +6 -0
  25. package/operators/frontend-presentation-resolve/self-test.mjs +6 -5
  26. package/operators/frontend-presentation-resolve/validate.mjs +30 -6
  27. package/operators/frontend-source-apply/operator.md +3 -1
  28. package/operators/frontend-source-apply/operator.vi.md +3 -1
  29. package/operators/frontend-source-apply/self-test.mjs +1 -1
  30. package/operators/frontend-surface-audit/self-test.mjs +1 -1
  31. package/operators/git-publish/self-test.mjs +1 -1
  32. package/operators/platform-operate/self-test.mjs +1 -1
  33. package/operators/quality-verify/operator.md +5 -1
  34. package/operators/quality-verify/operator.vi.md +5 -1
  35. package/operators/quality-verify/self-test.mjs +15 -2
  36. package/operators/quality-verify/validate.mjs +21 -1
  37. package/operators/release-deploy/self-test.mjs +235 -235
  38. package/operators/uat-verify/operator.md +20 -6
  39. package/operators/uat-verify/operator.vi.md +21 -7
  40. package/operators/uat-verify/self-test.mjs +6 -5
  41. package/operators/uat-verify/validate.mjs +10 -4
  42. package/operators/workspace-bind/operator.md +18 -4
  43. package/operators/workspace-bind/operator.vi.md +16 -4
  44. package/operators/workspace-bind/self-test.mjs +3 -1
  45. package/operators/workspace-bind/validate.mjs +1 -0
  46. package/package.json +1 -1
  47. package/readiness/initialization/workspaces/local-route.schema.json +1 -1
  48. package/resources/orchestrator.json +14 -8
  49. package/routing.json +2 -1
  50. package/scripts/validate-request.mjs +12 -1
  51. package/scripts/validate-response.mjs +14 -3
  52. package/scripts/validate-step.mjs +2 -1
  53. package/scripts/validate-workflows.mjs +8 -1
  54. package/templates/kinds/architecture-decision.contract.json +1 -0
  55. package/templates/kinds/architecture-decision.skeleton.md +6 -0
  56. package/templates/kinds/backend-source-application.contract.json +1 -1
  57. package/templates/kinds/backend-source-application.skeleton.md +1 -1
  58. package/templates/kinds/frontend-presentation-resolution.contract.json +1 -1
  59. package/templates/kinds/frontend-presentation-resolution.skeleton.md +1 -0
  60. package/templates/kinds/mutations.schema.json +65 -65
  61. package/templates/kinds/route.schema.json +4 -2
  62. package/templates/kinds/stack-model.schema.json +23 -1
  63. package/templates/kinds/workspace-route-binding.contract.json +2 -2
  64. package/templates/step/response.schema.json +10 -0
  65. package/templates/step/state.schema.json +205 -0
  66. package/workflows/README.md +3 -0
  67. package/workflows/README.vi.md +3 -0
  68. package/workflows/backend-feature.json +26 -5
  69. package/workflows/content-unit.json +4 -1
  70. package/workflows/frontend-new-surface.json +15 -5
  71. package/workflows/frontend-reconstruct.json +10 -4
  72. package/workflows/frontend-refine.json +10 -4
  73. package/workflows/frontend-with-uat.json +15 -3
  74. package/workflows/full-feature.json +31 -8
  75. package/workflows/release.json +7 -1
package/INDEX.md CHANGED
@@ -1,4 +1,4 @@
1
- # StarCi Skills 1.1.0
1
+ # StarCi Skills 1.2.0
2
2
 
3
3
  This tree is the runtime. Read [SKILL.md](SKILL.md) next; it is the single entry that freezes a
4
4
  mission's scope, selects the one operator that owns the outcome, and routes between operators on
@@ -62,6 +62,8 @@ head or the head is not publishable.
62
62
 
63
63
  ## Lineage
64
64
 
65
+ 1.2.0 (2026-09-03): the second test round (tests/) and its fixes: state.json has a schema and the resume linkage is checked; a workflow declares asks; response.next must be offered by the Next table; UNKNOWN_STOP is emittable; the architecture decision publishes the operations the backend plan consumes and cites coverage-matrix dimensions instead of BA-<n>; uat.verify accepts its own lawful refusal; a radius topic.
66
+
65
67
  1.1.0 (2026-09-03): the tree ships as the npm package @starci/skills; npx @starci/skills init installs it as a repository's .claude runtime with the CLAUDE.md and AGENTS.md bootstraps, update keeps local edits, doctor runs the validators on the installed copy; @starci/grammar 0.4.2 (the core entry re-exports Common).
66
68
 
67
69
  1.0.3 (2026-09-03): a tools registry replaces grants and policies (resources/tools.json, @tools/<id> in Steps, per-runtime support, profile equivalents); every operator binds an OpenAI profile for the Codex processor; the first test round (tests/) and its fixes; docs/ and sites/ return.
package/INDEX.vi.md CHANGED
@@ -1,4 +1,4 @@
1
- # StarCi Skills 1.1.0
1
+ # StarCi Skills 1.2.0
2
2
 
3
3
  Cây này chính là runtime. Đọc tiếp `SKILL.vi.md` nếu có, hoặc `SKILL.md`; đó là cửa vào duy nhất,
4
4
  đóng băng phạm vi của một nhiệm vụ, chọn đúng một operator sở hữu kết quả, rồi định tuyến giữa các
@@ -63,6 +63,8 @@ thì không được publish.
63
63
 
64
64
  ## Dòng dõi
65
65
 
66
+ 1.2.0 (2026-09-03): vòng test thứ hai (tests/) và các sửa từ đó: state.json có schema và liên kết resume được kiểm; workflow khai asks; response.next phải nằm trong bảng Next; UNKNOWN_STOP phát được; quyết định kiến trúc công bố các operation mà kế hoạch backend tiêu thụ và trích dẫn dimension của ma trận bao phủ thay cho BA-<n>; uat.verify chấp nhận lời từ chối hợp luật của chính nó; chủ đề radius.
67
+
66
68
  1.1.0 (2026-09-03): cây phát hành thành gói npm @starci/skills; npx @starci/skills init cài nó làm runtime .claude của một repository kèm bootstrap CLAUDE.md và AGENTS.md, update giữ sửa đổi tay, doctor chạy validator trên bản đã cài; @starci/grammar 0.4.2 (entry core re-export Common).
67
69
 
68
70
  1.0.3 (2026-09-03): sổ tool thay cho grant và policy (resources/tools.json, @tools/<id> trong Các bước, hỗ trợ theo runtime, profile tương đương); mọi operator ràng profile OpenAI cho processor Codex; vòng test đầu (tests/) và các sửa từ đó; docs/ và sites/ trở lại.
package/README.md CHANGED
@@ -14,7 +14,12 @@ npx @starci/skills init
14
14
  Run it at the root of the repository that will own the runtime. It copies the tree into `./.claude`,
15
15
  writes `CLAUDE.md` (read by Claude Code) and `AGENTS.md` (read by Codex) when they do not exist, and
16
16
  adds `.worktrees/sessions/` to `.gitignore`, where sessions live. Commit `.claude/` with the repository:
17
- it is source, not a cache. Requires Node 20 or newer; the CLI has no dependencies.
17
+ it is source, not a cache. Requires Node 20 or newer; the CLI has no dependencies. The same CLI runs
18
+ straight from a git tag when the registry has not yet listed a version:
19
+
20
+ ```bash
21
+ npx --package=github:starci183/starci-skills#v1.1.0 starci-skills init
22
+ ```
18
23
 
19
24
  | Command | What it does |
20
25
  | --- | --- |
package/README.vi.md CHANGED
@@ -14,7 +14,12 @@ npx @starci/skills init
14
14
  Chạy ở gốc repository sẽ sở hữu runtime. Lệnh chép cây vào `./.claude`, viết `CLAUDE.md` (Claude Code
15
15
  đọc) và `AGENTS.md` (Codex đọc) khi chưa có, và thêm `.worktrees/sessions/` vào `.gitignore` vì phiên
16
16
  làm việc nằm ở đó. Hãy commit `.claude/` cùng repository: nó là source, không phải cache. Cần Node 20
17
- trở lên; CLI không có dependency.
17
+ trở lên; CLI không có dependency. Cùng CLI đó chạy thẳng từ một tag git khi registry chưa liệt kê phiên
18
+ bản:
19
+
20
+ ```bash
21
+ npx --package=github:starci183/starci-skills#v1.1.0 starci-skills init
22
+ ```
18
23
 
19
24
  | Lệnh | Việc nó làm |
20
25
  | --- | --- |
@@ -43,10 +43,15 @@ is context, not a presentation recommendation.
43
43
  | [Tone](tone.md) | Default, muted, and accent by information rank; never a raw colour | TONE-1 to TONE-3 |
44
44
  | [Surface](surface.md) | Which semantic surface an app-owned region takes, with its paired foreground | SURFACE-1 to SURFACE-6 |
45
45
  | [Boundary](boundary.md) | Which separator or border draws an app-owned edge, and which edge drops it | BOUNDARY-1 to BOUNDARY-6 |
46
+ | [Radius](radius.md) | How round the corner of an app-owned surface, mark, or pill is | RADIUS-2 to RADIUS-9, on a ramp with reserved addresses |
46
47
  | [Measure](measure.md) | `width`, `height`, and their minima and maxima for app-owned regions | MEASURE-1 to MEASURE-7 |
47
48
  | [Text flow](text-flow.md) | `text-align`, wrapping, `white-space`, truncation, line clamping | FLOW-1 to FLOW-5 |
48
49
  | [Overflow](overflow.md) | Scroll, clip, and containment boundaries owned by the app | OVERFLOW-1 to OVERFLOW-5 |
49
50
 
51
+ Radius has its own closed ramp, every step a fixed multiple of the theme's one `--radius` number, so
52
+ its rule numbers are ordinal positions there and a step nobody writes twice keeps a reserved address
53
+ rather than a rule.
54
+
50
55
  Gap, padding, and margin share `COMMON_SPACING_SCALE`, so their rule numbers are ordinal positions on
51
56
  that one closed scale. Font and tone have their own closed scales. Measure, surface, boundary, text
52
57
  flow, and overflow have no value ramp, so their numbers address constraint kinds instead, and each
@@ -43,6 +43,7 @@ không phải recommendation của presentation.
43
43
  | Nhấn mạnh text default, muted và accent | [Tone](tone.vi.md) |
44
44
  | Surface ngữ nghĩa của vùng do app sở hữu, kèm foreground đi cặp | [Surface](surface.vi.md) |
45
45
  | Separator hay border vẽ cạnh do app sở hữu, và cạnh nào bỏ đường kẻ | [Boundary](boundary.vi.md) |
46
+ | Góc của surface, mark hay pill do app sở hữu tròn tới đâu | [Radius](radius.vi.md) |
46
47
  | Giới hạn width và height của content region | [Measure](measure.vi.md) |
47
48
  | Wrapping, alignment và truncation | [Text flow](text-flow.vi.md) |
48
49
  | Scroll và clipping boundary do app sở hữu | [Overflow](overflow.vi.md) |
@@ -0,0 +1,183 @@
1
+ # Radius presentation
2
+
3
+ This file answers one question: given a boundary the application owns, how round is its corner?
4
+
5
+ Composition has already chosen the DOM tree and the Grammar objects. Radius presentation resolves the
6
+ corner of application-owned surfaces, marks and pills only. The corner of a card, input, button, or any
7
+ other Grammar object belongs to Grammar, which draws it from its own tokens and never from a class the
8
+ application passes in.
9
+
10
+ ## Scale
11
+
12
+ Every step is a multiple of one number. The theme publishes `--radius` and derives the whole ramp from
13
+ it, so the ramp moves as a body when a visual family changes that one number: the application root sets
14
+ `--radius: .5rem`, Grammar's core family sets it to `--starci-core-control-radius` (`.75rem`), and the
15
+ heritage family sets it to `0`. The rule ID is the ordinal position on that ramp. It is not a size word
16
+ and not a component variant.
17
+
18
+ | Rule | Class | Factor | Value at `--radius: .5rem` |
19
+ | --- | --- | --- | --- |
20
+ | — | `rounded-none` | `0` | `0` |
21
+ | — | `rounded-xs` | `× .25` | `.125rem` |
22
+ | RADIUS-2 | `rounded-sm` | `× .5` | `.25rem` |
23
+ | — | `rounded-md` | `× .75` | `.375rem` |
24
+ | RADIUS-4 | `rounded-lg` | `× 1` | `.5rem` |
25
+ | RADIUS-5 | `rounded-xl` | `× 1.5` | `.75rem` |
26
+ | RADIUS-6 | `rounded-2xl` | `× 2` | `1rem` |
27
+ | RADIUS-7 | `rounded-3xl` | `× 3` | `1.5rem` |
28
+ | — | `rounded-4xl` | `× 4` | `2rem` |
29
+ | RADIUS-9 | `rounded-full` | none | a corner larger than the box |
30
+
31
+ The rule number is the row's position on that ramp, counting `rounded-none` as zero, and it is a stable
32
+ address: the ramp is printed whole so the published numbers never shift when a step is added. A step
33
+ gets its number, and a case table below, only once two authorized blocks write it; the four steps
34
+ reading `—` are reserved addresses, because one occurrence is a product decision, not a rule.
35
+
36
+ Because the factors are fixed and only `--radius` moves, an application that writes a rem value
37
+ directly — `rounded-[1.25rem]` — freezes one family's decision into every family and leaves the ramp
38
+ behind.
39
+
40
+ `rounded-field` is not a step. It is the vendor's field utility, resolving to `--field-radius`, and it
41
+ belongs to the field family rather than to an application choice.
42
+
43
+ ## Owner
44
+
45
+ Each case names who owns the corner. The owner decides whether the application writes a class at all.
46
+
47
+ | Owner | Meaning | Application writes |
48
+ | --- | --- | --- |
49
+ | `App` | The boundary belongs to the application | The class |
50
+ | A component name | Common already rounds this boundary inside that component | Nothing. Compose it |
51
+ | `—` | Common exposes no public path for this boundary | The class, recorded as a workaround |
52
+
53
+ Writing a class where a component is the owner is `APP_REIMPLEMENTATION`. Reaching into a Grammar
54
+ component with a selector or a passed class to change its corner is `APP_OVERRIDE`.
55
+
56
+ ## Classes off the scale
57
+
58
+ `rounded-small`, `rounded-medium` and `rounded-large` are not on this scale and are not utilities this
59
+ app publishes. They are the vendor's Tailwind 3 plugin names, and the compiled stylesheet of this head
60
+ emits no rule for any of them: `rounded-` prints `none`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`, `full`
61
+ and `field`, and nothing else. A boundary written with one of them therefore renders square while the
62
+ source reads as though a corner were chosen.
63
+
64
+ They are removed rather than translated. The removal reason is `off the closed scale`, and the
65
+ replacement is the ramp step the boundary's case names, not the step whose word happens to match.
66
+
67
+ An arbitrary value such as `rounded-[1.25rem]` is off the scale for the same reason and by a shorter
68
+ argument: it is a number nobody can cite and nobody can move.
69
+
70
+ ## Radius Common already owns
71
+
72
+ Common rounds its own objects from three tokens published by `@grammar/core`, and no application class
73
+ reaches them: `--starci-core-surface-radius` (`1rem`) rounds every surface, including
74
+ `.starci-core-surface` and the `MediaFrame` viewport; `--starci-core-control-radius` (`.75rem`) rounds
75
+ controls and tooltip content; `--starci-core-pill-radius` (`999px`) rounds the pill shapes. A visual
76
+ family may set those tokens to its own numbers, which is why an application that copies the current
77
+ number freezes one family's decision into every family.
78
+
79
+ `scripts/generate-presentation-owned.mjs` does not yet carry a `RADIUS` topic, so this file has no
80
+ generated ownership table. Until it does, a reader rules out writing a class by finding the boundary
81
+ among the three tokens above.
82
+
83
+ ## RADIUS-2 — `rounded-sm` / `.25rem`
84
+
85
+ The smallest corner that still reads as intentional, for a mark small enough that a larger corner would
86
+ eat its body.
87
+
88
+ | Case | When | Owner | Render |
89
+ | --- | --- | --- | --- |
90
+ | Case 1 | A dense grid cell or legend swatch a few pixels on a side | `App` | `<span className="size-3 rounded-sm bg-default" />` |
91
+ | Case 2 | A skeleton line standing in for text while it loads | `App` | `<div className="h-4 w-40 rounded-sm" />` |
92
+
93
+ Not this rule: a container holding readable content, which needs a corner proportional to its inset.
94
+ Use RADIUS-5.
95
+
96
+ ## RADIUS-4 — `rounded-lg` / `.5rem`
97
+
98
+ A compact interactive boundary: a small square badge or a control-sized region the application owns.
99
+
100
+ | Case | When | Owner | Render |
101
+ | --- | --- | --- | --- |
102
+ | Case 1 | A fixed square marker carrying a number or a glyph | `App` | `<span className="flex size-8 items-center justify-center rounded-lg bg-accent-soft">` |
103
+ | Case 2 | An app-owned segmented control's own segment | `App` | `<button className="min-h-9 rounded-lg px-3">` |
104
+ | Case 3 | A small bordered notice sitting inside a larger surface | `App` | `<div className="rounded-lg border border-separator p-3">` |
105
+
106
+ Not this rule: an object Common already draws as a control. Compose the component and pass no class.
107
+
108
+ ## RADIUS-5 — `rounded-xl` / `.75rem`
109
+
110
+ The standard corner for an app-owned region nested inside a surface: a band, a notice, a bordered
111
+ group that is part of a card rather than a card of its own.
112
+
113
+ | Case | When | Owner | Render |
114
+ | --- | --- | --- | --- |
115
+ | Case 1 | A bordered group of content inside a section | `App` | `<div className="rounded-xl border border-separator p-4">` |
116
+ | Case 2 | A soft-toned notice or status band | `App` | `<div className="rounded-xl bg-accent-soft px-3 py-2">` |
117
+ | Case 3 | A square icon tile beside a row of text | `App` | `<span className="flex size-11 items-center justify-center rounded-xl bg-accent-soft">` |
118
+
119
+ Not this rule: the outermost surface of a region, which takes the surface corner. Use RADIUS-6.
120
+
121
+ ## RADIUS-6 — `rounded-2xl` / `1rem`
122
+
123
+ The surface corner: an app-owned region that reads as a card in its own right, matching the value
124
+ Common gives its own surfaces.
125
+
126
+ | Case | When | Owner | Render |
127
+ | --- | --- | --- | --- |
128
+ | Case 1 | An app-owned panel that stands as its own surface on the page | `App` | `<div className="min-w-0 overflow-hidden rounded-2xl bg-surface-secondary">` |
129
+ | Case 2 | A full-width notice occupying a whole region of the page | `App` | `<div className="rounded-2xl bg-warning-soft p-4">` |
130
+ | Case 3 | A surface whose block start alone is rounded, because its end runs into what follows | `App` | `<div className="rounded-t-2xl">` |
131
+
132
+ Not this rule: a card Common already draws. Compose `SurfaceCard` and write no corner.
133
+
134
+ A rounded surface that paints or lays out children clips them, so `overflow-hidden` belongs with the
135
+ corner wherever a child would otherwise cross it.
136
+
137
+ ## RADIUS-7 — `rounded-3xl` / `1.5rem`
138
+
139
+ The largest ramp corner in use: a hero band whose size makes the surface corner look tight.
140
+
141
+ | Case | When | Owner | Render |
142
+ | --- | --- | --- | --- |
143
+ | Case 1 | A page-opening hero region spanning the full content width | `App` | `<div className="grid min-w-0 overflow-hidden rounded-3xl bg-accent-soft">` |
144
+
145
+ Not this rule: an ordinary panel, which reads as inflated at this radius. Use RADIUS-6.
146
+
147
+ ## RADIUS-9 — `rounded-full` / a corner larger than the box
148
+
149
+ The end of the ramp, and a shape rather than a value: the boundary is a circle or a pill, and the value is whatever the
150
+ box needs to make it one.
151
+
152
+ | Case | When | Owner | Render |
153
+ | --- | --- | --- | --- |
154
+ | Case 1 | A dot, avatar frame or other equal-sided circular mark | `App` | `<span className="size-2 rounded-full bg-accent" />` |
155
+ | Case 2 | A pill-shaped app-owned band or floating action | `App` | `<div className="inline-flex items-center gap-2 rounded-full px-3 py-2">` |
156
+
157
+ Not this rule: a wide rectangle, where a pill corner reads as a mistake rather than a shape. Use the
158
+ ramp step its size calls for.
159
+
160
+ ## Corner variants
161
+
162
+ `rounded-t-*`, `rounded-b-*`, `rounded-s-*`, `rounded-e-*` and the single-corner classes are not
163
+ separate rules. They apply an existing rule to the corners they name, for a boundary whose sides do not
164
+ all end the same way.
165
+
166
+ | Corners | Class | Meaning |
167
+ | --- | --- | --- |
168
+ | One block edge | `rounded-t-*`, `rounded-b-*` | The chosen rule applies to that edge's two corners |
169
+ | One inline edge | `rounded-s-*`, `rounded-e-*` | The chosen rule applies to that edge's two corners |
170
+ | One corner | `rounded-tl-*`, `rounded-br-*`, and siblings | The chosen rule applies to that corner only |
171
+
172
+ A corner variant needs a reason from the tree: an edge that meets another surface, or a single corner
173
+ that points at what the element belongs to. Without one it is a decoration, and every corner of the
174
+ boundary takes the rule.
175
+
176
+ On the same element the narrower class wins the corners it names rather than adding, so
177
+ `rounded-2xl rounded-b-none` is `1rem` at the top and square at the bottom.
178
+
179
+ ## What this file does not decide
180
+
181
+ Which surface or tone the region takes is [Surface](surface.md). Which line draws its edge is
182
+ [Boundary](boundary.md). Its inset is [Padding](padding.md), and clipping is [Overflow](overflow.md);
183
+ a corner and a clip are decided together but recorded apart.
@@ -0,0 +1,182 @@
1
+ # Radius presentation
2
+
3
+ File này trả lời đúng một câu hỏi: với một boundary do ứng dụng sở hữu, góc của nó tròn tới đâu?
4
+
5
+ Composition đã chọn xong cây DOM và các object Grammar. Radius presentation chỉ giải góc của những
6
+ surface, mark và pill do ứng dụng sở hữu. Góc của một card, input, button hay bất kỳ object Grammar
7
+ nào thuộc về Grammar, và Grammar vẽ nó từ token của chính nó chứ không bao giờ từ một class ứng dụng
8
+ truyền vào.
9
+
10
+ ## Thang giá trị
11
+
12
+ Mỗi bước là một bội số của cùng một con số. Theme công bố `--radius` rồi suy ra cả cái ramp từ đó,
13
+ nên cả ramp dịch chuyển thành một khối khi một visual family đổi con số ấy: gốc ứng dụng đặt
14
+ `--radius: .5rem`, family core của Grammar đặt nó bằng `--starci-core-control-radius` (`.75rem`), còn
15
+ family heritage đặt nó bằng `0`. Số hiệu rule là vị trí thứ tự trên ramp ấy. Nó không phải một từ chỉ
16
+ kích cỡ và không phải một variant của component.
17
+
18
+ | Rule | Class | Hệ số | Giá trị khi `--radius: .5rem` |
19
+ | --- | --- | --- | --- |
20
+ | — | `rounded-none` | `0` | `0` |
21
+ | — | `rounded-xs` | `× .25` | `.125rem` |
22
+ | RADIUS-2 | `rounded-sm` | `× .5` | `.25rem` |
23
+ | — | `rounded-md` | `× .75` | `.375rem` |
24
+ | RADIUS-4 | `rounded-lg` | `× 1` | `.5rem` |
25
+ | RADIUS-5 | `rounded-xl` | `× 1.5` | `.75rem` |
26
+ | RADIUS-6 | `rounded-2xl` | `× 2` | `1rem` |
27
+ | RADIUS-7 | `rounded-3xl` | `× 3` | `1.5rem` |
28
+ | — | `rounded-4xl` | `× 4` | `2rem` |
29
+ | RADIUS-9 | `rounded-full` | không có | một góc lớn hơn cả cái hộp |
30
+
31
+ Số hiệu rule là vị trí của hàng trên ramp, tính `rounded-none` là không, và nó là một địa chỉ ổn định:
32
+ ramp được in trọn vẹn nên các số đã công bố không bao giờ xê dịch khi thêm một bước. Một bước chỉ nhận
33
+ số hiệu của mình, và nhận bảng case bên dưới, khi đã có hai block được uỷ quyền viết nó; bốn bước đang
34
+ ghi `—` là những địa chỉ đã giữ chỗ, vì xuất hiện một lần là quyết định sản phẩm, chưa phải rule.
35
+
36
+ Vì các hệ số cố định và chỉ `--radius` di chuyển, một ứng dụng viết thẳng giá trị rem —
37
+ `rounded-[1.25rem]` — đóng băng quyết định của một family vào mọi family và bỏ ramp lại phía sau.
38
+
39
+ `rounded-field` không phải một bước. Nó là utility field của vendor, giải về `--field-radius`, và
40
+ thuộc về family field chứ không phải một lựa chọn của ứng dụng.
41
+
42
+ ## Owner
43
+
44
+ Mỗi case gọi tên ai sở hữu góc. Chủ sở hữu quyết định ứng dụng có được viết class hay không.
45
+
46
+ | Owner | Nghĩa | Ứng dụng viết |
47
+ | --- | --- | --- |
48
+ | `App` | Boundary thuộc về ứng dụng | Class |
49
+ | Tên một component | Common đã bo góc này bên trong component đó | Không gì cả. Ghép nó vào |
50
+ | `—` | Common không mở đường công khai nào cho boundary này | Class, ghi lại như một cách chữa cháy |
51
+
52
+ Viết class ở nơi chủ là một component là `APP_REIMPLEMENTATION`. Với tay vào trong một component
53
+ Grammar bằng selector hay bằng class truyền vào để đổi góc của nó là `APP_OVERRIDE`.
54
+
55
+ ## Những class nằm ngoài thang
56
+
57
+ `rounded-small`, `rounded-medium` và `rounded-large` không nằm trên thang này và cũng không phải
58
+ utility mà app này công bố. Chúng là tên plugin Tailwind 3 của vendor, và stylesheet đã biên dịch của
59
+ head hiện tại không phát ra quy tắc nào cho chúng cả: `rounded-` chỉ in ra `none`, `sm`, `md`, `lg`,
60
+ `xl`, `2xl`, `3xl`, `full` và `field`, không gì khác. Một boundary viết bằng một trong ba tên ấy vì
61
+ thế render vuông trong khi source đọc lên như thể đã chọn một góc.
62
+
63
+ Chúng bị gỡ chứ không được dịch sang. Lý do gỡ là `off the closed scale`, và thứ thay thế là bước ramp
64
+ mà case của boundary ấy gọi tên, không phải bước có từ ngữ tình cờ trùng khớp.
65
+
66
+ Một giá trị tuỳ tiện như `rounded-[1.25rem]` cũng nằm ngoài thang, vì một lý do ngắn hơn: đó là con số
67
+ không ai dẫn được và không ai dịch chuyển được.
68
+
69
+ ## Radius mà Common đã sở hữu
70
+
71
+ Common bo góc các object của nó từ ba token do `@grammar/core` công bố, và không class ứng dụng nào
72
+ với tới được: `--starci-core-surface-radius` (`1rem`) bo mọi surface, gồm cả `.starci-core-surface` và
73
+ viewport của `MediaFrame`; `--starci-core-control-radius` (`.75rem`) bo các control và nội dung
74
+ tooltip; `--starci-core-pill-radius` (`999px`) bo các hình pill. Một visual family có thể đặt những
75
+ token ấy thành con số của riêng nó, và đó chính là lý do một ứng dụng chép lại con số hiện tại đã đóng
76
+ băng quyết định của một family vào mọi family.
77
+
78
+ `scripts/generate-presentation-owned.mjs` chưa mang topic `RADIUS`, nên file này chưa có bảng sở hữu
79
+ được sinh ra. Cho tới khi có, người đọc loại trừ việc viết class bằng cách tìm boundary ấy trong ba
80
+ token ở trên.
81
+
82
+ ## RADIUS-2 — `rounded-sm` / `.25rem`
83
+
84
+ Góc nhỏ nhất mà vẫn đọc ra là cố ý, dành cho một mark nhỏ tới mức một góc lớn hơn sẽ ăn mất thân nó.
85
+
86
+ | Case | Dùng khi | Owner | Render |
87
+ | --- | --- | --- | --- |
88
+ | Case 1 | Một ô lưới dày hoặc ô chú giải chỉ vài pixel mỗi cạnh | `App` | `<span className="size-3 rounded-sm bg-default" />` |
89
+ | Case 2 | Một dòng skeleton thay chỗ cho chữ trong lúc tải | `App` | `<div className="h-4 w-40 rounded-sm" />` |
90
+
91
+ Không phải rule này: một container chứa nội dung đọc được, cần góc tương xứng với inset của nó. Dùng
92
+ RADIUS-5.
93
+
94
+ ## RADIUS-4 — `rounded-lg` / `.5rem`
95
+
96
+ Một boundary tương tác gọn: một badge vuông nhỏ hoặc một vùng cỡ control do ứng dụng sở hữu.
97
+
98
+ | Case | Dùng khi | Owner | Render |
99
+ | --- | --- | --- | --- |
100
+ | Case 1 | Một marker vuông cố định mang một con số hay một glyph | `App` | `<span className="flex size-8 items-center justify-center rounded-lg bg-accent-soft">` |
101
+ | Case 2 | Một đoạn của segmented control do ứng dụng sở hữu | `App` | `<button className="min-h-9 rounded-lg px-3">` |
102
+ | Case 3 | Một notice nhỏ có viền nằm bên trong một surface lớn hơn | `App` | `<div className="rounded-lg border border-separator p-3">` |
103
+
104
+ Không phải rule này: một object mà Common đã vẽ sẵn như một control. Ghép component vào và không
105
+ truyền class nào.
106
+
107
+ ## RADIUS-5 — `rounded-xl` / `.75rem`
108
+
109
+ Góc tiêu chuẩn cho một vùng do ứng dụng sở hữu nằm lồng trong một surface: một band, một notice, một
110
+ nhóm có viền là phần của card chứ không phải một card riêng.
111
+
112
+ | Case | Dùng khi | Owner | Render |
113
+ | --- | --- | --- | --- |
114
+ | Case 1 | Một nhóm nội dung có viền bên trong một section | `App` | `<div className="rounded-xl border border-separator p-4">` |
115
+ | Case 2 | Một notice hay band trạng thái tông mềm | `App` | `<div className="rounded-xl bg-accent-soft px-3 py-2">` |
116
+ | Case 3 | Một ô icon vuông đứng cạnh một hàng chữ | `App` | `<span className="flex size-11 items-center justify-center rounded-xl bg-accent-soft">` |
117
+
118
+ Không phải rule này: surface ngoài cùng của một vùng, vốn lấy góc surface. Dùng RADIUS-6.
119
+
120
+ ## RADIUS-6 — `rounded-2xl` / `1rem`
121
+
122
+ Góc surface: một vùng do ứng dụng sở hữu và tự nó đọc lên như một card, khớp với giá trị Common dành
123
+ cho surface của chính nó.
124
+
125
+ | Case | Dùng khi | Owner | Render |
126
+ | --- | --- | --- | --- |
127
+ | Case 1 | Một panel do ứng dụng sở hữu, đứng như surface của riêng nó trên trang | `App` | `<div className="min-w-0 overflow-hidden rounded-2xl bg-surface-secondary">` |
128
+ | Case 2 | Một notice trải hết bề ngang, chiếm trọn một vùng của trang | `App` | `<div className="rounded-2xl bg-warning-soft p-4">` |
129
+ | Case 3 | Một surface chỉ bo ở cạnh đầu khối, vì cạnh cuối chạy thẳng vào thứ tiếp theo | `App` | `<div className="rounded-t-2xl">` |
130
+
131
+ Không phải rule này: một card mà Common đã vẽ. Ghép `SurfaceCard` và không viết góc nào.
132
+
133
+ Một surface đã bo mà còn tô hoặc dàn con bên trong thì cắt mất chúng, nên `overflow-hidden` đi cùng
134
+ với góc ở mọi chỗ mà một đứa con sẽ vượt qua đường bo ấy.
135
+
136
+ ## RADIUS-7 — `rounded-3xl` / `1.5rem`
137
+
138
+ Góc ramp lớn nhất đang dùng: một band hero mà kích thước của nó làm góc surface trông chật.
139
+
140
+ | Case | Dùng khi | Owner | Render |
141
+ | --- | --- | --- | --- |
142
+ | Case 1 | Một vùng hero mở đầu trang, trải hết bề ngang nội dung | `App` | `<div className="grid min-w-0 overflow-hidden rounded-3xl bg-accent-soft">` |
143
+
144
+ Không phải rule này: một panel bình thường, vốn đọc lên như bị thổi phồng ở bán kính này. Dùng
145
+ RADIUS-6.
146
+
147
+ ## RADIUS-9 — `rounded-full` / một góc lớn hơn cả cái hộp
148
+
149
+ Điểm cuối của ramp, và là một hình dạng chứ không phải một giá trị: boundary là hình tròn hoặc hình
150
+ pill, và giá trị là bất cứ thứ gì cái hộp cần để thành hình đó.
151
+
152
+ | Case | Dùng khi | Owner | Render |
153
+ | --- | --- | --- | --- |
154
+ | Case 1 | Một chấm, khung avatar hay mark tròn đều cạnh khác | `App` | `<span className="size-2 rounded-full bg-accent" />` |
155
+ | Case 2 | Một band hay nút hành động nổi hình pill do ứng dụng sở hữu | `App` | `<div className="inline-flex items-center gap-2 rounded-full px-3 py-2">` |
156
+
157
+ Không phải rule này: một hình chữ nhật rộng, nơi góc pill đọc lên như một lỗi chứ không như một hình
158
+ dạng. Dùng bước ramp mà kích thước của nó đòi.
159
+
160
+ ## Biến thể theo góc
161
+
162
+ `rounded-t-*`, `rounded-b-*`, `rounded-s-*`, `rounded-e-*` và các class một góc không phải rule riêng.
163
+ Chúng áp một rule đã có lên đúng những góc chúng gọi tên, cho một boundary mà các cạnh không kết thúc
164
+ giống nhau.
165
+
166
+ | Góc | Class | Nghĩa |
167
+ | --- | --- | --- |
168
+ | Một cạnh khối | `rounded-t-*`, `rounded-b-*` | Rule đã chọn áp cho hai góc của cạnh đó |
169
+ | Một cạnh dòng | `rounded-s-*`, `rounded-e-*` | Rule đã chọn áp cho hai góc của cạnh đó |
170
+ | Một góc | `rounded-tl-*`, `rounded-br-*` và anh em | Rule đã chọn chỉ áp cho góc đó |
171
+
172
+ Một biến thể góc cần một lý do lấy từ cây: một cạnh chạm vào surface khác, hoặc một góc đơn chỉ về thứ
173
+ mà phần tử ấy thuộc về. Không có lý do thì nó là trang trí, và mọi góc của boundary đều lấy rule.
174
+
175
+ Trên cùng một phần tử, class hẹp hơn thắng ở những góc nó gọi tên chứ không cộng thêm, nên
176
+ `rounded-2xl rounded-b-none` là `1rem` ở trên và vuông ở dưới.
177
+
178
+ ## File này không quyết định
179
+
180
+ Vùng ấy lấy surface hay tông nào là [Surface](surface.vi.md). Đường nào vẽ cạnh của nó là
181
+ [Boundary](boundary.vi.md). Inset của nó là [Padding](padding.vi.md), còn cắt là
182
+ [Overflow](overflow.vi.md); góc và cắt được quyết cùng nhau nhưng ghi lại tách nhau.
@@ -6,8 +6,8 @@ Generated by `scripts/generate-operators-index.mjs` from every `operator.md`; `-
6
6
 
7
7
  | Operator | Profile | Context | Inputs (kinds) | Outputs (kinds) | Steps | Stop codes |
8
8
  | --- | --- | --- | --- | --- | --- | --- |
9
- | `architecture.decide` | `sol-fresh` | `@knowledge/patterns`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision` | `architecture-decision`, `current-state`, `stack-model`, `alternatives`, `independent-critique` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CURRENT_STATE_UNOBSERVED`, `BUSINESS_AUTHORITY_REQUIRED`, `CONSTRAINT_CONTRADICTION`, `NO_VIABLE_ALTERNATIVE`, `CHOICE_REQUIRED`, `COMPATIBILITY_UNVERIFIED`, `DATA_OWNERSHIP_UNASSIGNED`, `CRITIQUE_UNRESOLVED` |
10
- | `backend.source.apply` | `luna` | `@knowledge/patterns/be`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `backend-source-application` | `backend-source-application`, `changes`, `mutations`, `conformance`, `proof` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `CONTRACT_UNFROZEN`, `CONTRACT_WIDENED`, `BUSINESS_AUTHORITY_MISSING`, `OWNER_CONFLICT`, `PATTERN_UNBOUND`, `PROOF_UNAVAILABLE` |
9
+ | `architecture.decide` | `sol-fresh` | `@knowledge/patterns`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `model` | `architecture-decision`, `current-state`, `stack-model`, `alternatives`, `independent-critique` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CURRENT_STATE_UNOBSERVED`, `BUSINESS_AUTHORITY_REQUIRED`, `CONSTRAINT_CONTRADICTION`, `NO_VIABLE_ALTERNATIVE`, `CHOICE_REQUIRED`, `COMPATIBILITY_UNVERIFIED`, `DATA_OWNERSHIP_UNASSIGNED`, `CRITIQUE_UNRESOLVED` |
10
+ | `backend.source.apply` | `luna` | `@knowledge/patterns/be`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `model`, `backend-source-application` | `backend-source-application`, `changes`, `mutations`, `conformance`, `proof` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `CONTRACT_UNFROZEN`, `CONTRACT_WIDENED`, `BUSINESS_AUTHORITY_MISSING`, `OWNER_CONFLICT`, `PATTERN_UNBOUND`, `PROOF_UNAVAILABLE` |
11
11
  | `business.decide` | `sol-fresh` | `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `backend-source-application` | `business-promise-authority`, `claims`, `coverage-matrix`, `model` | 9 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CONTRADICTION_UNRESOLVED`, `LIFECYCLE_TRANSITION_INVALID`, `AUTHORITY_CONFLICT`, `APPROVAL_REQUIRED`, `COVERAGE_INCOMPLETE`, `CONSUMER_UNPROVEN`, `RECONCILIATION_DISCREPANCY` |
12
12
  | `content.generate` | `luna` | `@remote/minio/<contentId>/<locale>`, `@worktrees/sessions/central-runtime` | `content-generation-receipt` | `content-generation-receipt`, `content-brief`, `e2e`, `content-review`, `article`, `image`, `image-prompt`, `track` | 9 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `BRIEF_UNBOUND`, `OUTCOME_UNCOVERED`, `IMAGE_UNAVAILABLE`, `CODE_BUILD_FAILED`, `E2E_FAILED`, `CONTRACT_WEAKENED`, `REVIEW_REVISION_REQUIRED`, `REVIEW_ROUNDS_EXHAUSTED` |
13
13
  | `frontend.direction.decide` | `sol-fresh` | `@grammar/core`, `@knowledge/grammars/starci`, `@knowledge/ui/composition`, `@workspaces/fe`, `@worktrees/uat/<flow>/<case>` | `business-promise-authority`, `backend-source-application`, `architecture-decision`, `frontend-direction-decision` | `frontend-direction-decision`, `ui-coverage`, `candidates`, `direction-image` | 12 | `INVALID_INPUT`, `ROUTE_UNVERIFIED`, `SOURCE_DRIFT`, `SCOPE_UNFROZEN`, `CHANGE_LEVEL_AMBIGUOUS`, `OWNER_CEILING_INVALID`, `BUSINESS_REQUIRED`, `BACKEND_REQUIRED`, `ARCHITECTURE_REQUIRED`, `GRAMMAR_REQUIRED`, `EVIDENCE_MISSING`, `REFERENCE_EVIDENCE_EXHAUSTED`, `NO_VIABLE_DIRECTION`, `DIRECTION_CHOICE_REQUIRED`, `NO_PROGRESS` |
@@ -18,7 +18,7 @@ Generated by `scripts/generate-operators-index.mjs` from every `operator.md`; `-
18
18
  | `platform.operate` | `luna` | `@workspaces/device-state`, `@workspaces/ports/<project>`, `@workspaces/projects/<project>/<role>`, `@worktrees/sessions/central-runtime` | — | `platform-operation-receipt`, `delta`, `checks` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `AUTHORITY_DRIFT`, `CAPABILITY_MISSING`, `INVENTORY_DRIFT`, `PORT_CONFLICT`, `EFFECT_UNAUTHORIZED`, `SERVICE_UNAVAILABLE`, `PROOF_FAILED` |
19
19
  | `quality.verify` | `luna` | `@workspaces/<project>/<role>/gates`, `@workspaces/be`, `@workspaces/fe`, `@worktrees/debts` | `backend-source-application`, `frontend-source-application`, `changes` | `quality-verification`, `gate-result`, `coverage` | 7 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `PREDECESSOR_MIXED`, `PREDECESSOR_STALE`, `GATE_UNAVAILABLE`, `DEBT_UNAPPROVED` |
20
20
  | `release.deploy` | `luna` | `@remote/ghcr/<image>`, `@remote/github-actions/<runId>`, `@workspaces/device-state` | `quality-verification` | `release-deployment`, `probes` | 10 | `INVALID_INPUT`, `NO_PROGRESS`, `AUTHORIZATION_MISSING`, `MANIFEST_INVALID`, `APPROVAL_REQUIRED`, `CREDENTIAL_UNAVAILABLE`, `HOST_UNAVAILABLE`, `ARTIFACT_MISSING`, `MIGRATION_BLOCKED`, `DOMAIN_UNRECONCILED`, `ROLLOUT_FAILED`, `RECOVERY_EXHAUSTED`, `CONCURRENT_DRIFT`, `ROLLBACK_IDENTITY_MISSING`, `STEADY_STATE_UNPROVEN` |
21
- | `uat.verify` | `sol-fresh` | `@workspaces/be`, `@workspaces/device-state`, `@worktrees/_templates`, `@worktrees/sessions/central-runtime`, `@worktrees/uat/<flow>/<case>` | `frontend-surface-audit`, `quality-verification` | `uat-flow-verification`, `uat-snapshot`, `uat-capture`, `uat-verdicts`, `screenshot`, `sheet` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `ADMISSION_MISSING`, `PROVISIONING_UNAVAILABLE`, `LEASE_INVALID`, `RUNTIME_UNAVAILABLE`, `EVIDENCE_UNAVAILABLE`, `FIXTURE_VIOLATION`, `CANONICAL_WRITE_DENIED` |
21
+ | `uat.verify` | `sol-fresh` | `@workspaces/be`, `@workspaces/device-state`, `@worktrees/_templates`, `@worktrees/sessions/central-runtime`, `@worktrees/uat/<flow>/<case>` | `frontend-surface-audit`, `quality-verification`, `route` | `uat-flow-verification`, `uat-snapshot`, `uat-capture`, `uat-verdicts`, `screenshot`, `sheet` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `ADMISSION_MISSING`, `PROVISIONING_UNAVAILABLE`, `LEASE_INVALID`, `RUNTIME_UNAVAILABLE`, `EVIDENCE_UNAVAILABLE`, `FIXTURE_VIOLATION`, `CANONICAL_WRITE_DENIED` |
22
22
  | `workspace.bind` | `luna` | `@workspaces/device-state`, `@workspaces/local/routes/<project>/<role>`, `@workspaces/ports/<project>`, `@workspaces/projects/<project>/<role>`, `@worktrees/sessions/central-runtime` | — | `workspace-route-binding`, `route` | 6 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `IDENTITY_UNVERIFIED`, `ROUTE_UNDECLARED`, `ROUTE_UNHYDRATED`, `ROUTE_MISMATCH`, `BRANCH_POLICY_VIOLATION`, `CHECKOUT_DIRTY`, `ENDPOINT_AUTHORITY_STALE`, `RUNTIME_NOT_READY` |
23
23
 
24
24
  ## Hand-offs between branches
@@ -57,7 +57,7 @@ Every kind that crosses between operators, who writes it, and who reads it. A ki
57
57
  | `image-prompt` | `content.generate` | — |
58
58
  | `independent-critique` | `architecture.decide` | — |
59
59
  | `inventory` | `frontend.presentation.resolve` | — |
60
- | `model` | `business.decide` | |
60
+ | `model` | `business.decide` | `architecture.decide (optional)`, `backend.source.apply (optional)` |
61
61
  | `mutations` | `backend.source.apply` | — |
62
62
  | `platform-operation-receipt` | `platform.operate` | — |
63
63
  | `probes` | `release.deploy` | — |
@@ -65,7 +65,7 @@ Every kind that crosses between operators, who writes it, and who reads it. A ki
65
65
  | `quality-verification` | `quality.verify` | `git.publish`, `release.deploy`, `uat.verify` |
66
66
  | `release-deployment` | `release.deploy` | — |
67
67
  | `resolved-tree` | `frontend.presentation.resolve` | — |
68
- | `route` | `workspace.bind` | |
68
+ | `route` | `workspace.bind` | `uat.verify` |
69
69
  | `screenshot` | `frontend.surface.audit`, `uat.verify` | — |
70
70
  | `sheet` | `uat.verify` | — |
71
71
  | `stack-model` | `architecture.decide` | — |
@@ -6,8 +6,8 @@ Sinh bởi `scripts/generate-operators-index.mjs` từ mọi `operator.md`; `--c
6
6
 
7
7
  | Operator | Profile | Context | Đầu vào (kind) | Đầu ra (kind) | Số bước | Mã dừng |
8
8
  | --- | --- | --- | --- | --- | --- | --- |
9
- | `architecture.decide` | `sol-fresh` | `@knowledge/patterns`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision` | `architecture-decision`, `current-state`, `stack-model`, `alternatives`, `independent-critique` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CURRENT_STATE_UNOBSERVED`, `BUSINESS_AUTHORITY_REQUIRED`, `CONSTRAINT_CONTRADICTION`, `NO_VIABLE_ALTERNATIVE`, `CHOICE_REQUIRED`, `COMPATIBILITY_UNVERIFIED`, `DATA_OWNERSHIP_UNASSIGNED`, `CRITIQUE_UNRESOLVED` |
10
- | `backend.source.apply` | `luna` | `@knowledge/patterns/be`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `backend-source-application` | `backend-source-application`, `changes`, `mutations`, `conformance`, `proof` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `CONTRACT_UNFROZEN`, `CONTRACT_WIDENED`, `BUSINESS_AUTHORITY_MISSING`, `OWNER_CONFLICT`, `PATTERN_UNBOUND`, `PROOF_UNAVAILABLE` |
9
+ | `architecture.decide` | `sol-fresh` | `@knowledge/patterns`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `model` | `architecture-decision`, `current-state`, `stack-model`, `alternatives`, `independent-critique` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CURRENT_STATE_UNOBSERVED`, `BUSINESS_AUTHORITY_REQUIRED`, `CONSTRAINT_CONTRADICTION`, `NO_VIABLE_ALTERNATIVE`, `CHOICE_REQUIRED`, `COMPATIBILITY_UNVERIFIED`, `DATA_OWNERSHIP_UNASSIGNED`, `CRITIQUE_UNRESOLVED` |
10
+ | `backend.source.apply` | `luna` | `@knowledge/patterns/be`, `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `model`, `backend-source-application` | `backend-source-application`, `changes`, `mutations`, `conformance`, `proof` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `CONTRACT_UNFROZEN`, `CONTRACT_WIDENED`, `BUSINESS_AUTHORITY_MISSING`, `OWNER_CONFLICT`, `PATTERN_UNBOUND`, `PROOF_UNAVAILABLE` |
11
11
  | `business.decide` | `sol-fresh` | `@workspaces/be`, `@worktrees/businesses/<featureId>` | `architecture-decision`, `backend-source-application` | `business-promise-authority`, `claims`, `coverage-matrix`, `model` | 9 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `EVIDENCE_MISSING`, `CONTRADICTION_UNRESOLVED`, `LIFECYCLE_TRANSITION_INVALID`, `AUTHORITY_CONFLICT`, `APPROVAL_REQUIRED`, `COVERAGE_INCOMPLETE`, `CONSUMER_UNPROVEN`, `RECONCILIATION_DISCREPANCY` |
12
12
  | `content.generate` | `luna` | `@remote/minio/<contentId>/<locale>`, `@worktrees/sessions/central-runtime` | `content-generation-receipt` | `content-generation-receipt`, `content-brief`, `e2e`, `content-review`, `article`, `image`, `image-prompt`, `track` | 9 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `BRIEF_UNBOUND`, `OUTCOME_UNCOVERED`, `IMAGE_UNAVAILABLE`, `CODE_BUILD_FAILED`, `E2E_FAILED`, `CONTRACT_WEAKENED`, `REVIEW_REVISION_REQUIRED`, `REVIEW_ROUNDS_EXHAUSTED` |
13
13
  | `frontend.direction.decide` | `sol-fresh` | `@grammar/core`, `@knowledge/grammars/starci`, `@knowledge/ui/composition`, `@workspaces/fe`, `@worktrees/uat/<flow>/<case>` | `business-promise-authority`, `backend-source-application`, `architecture-decision`, `frontend-direction-decision` | `frontend-direction-decision`, `ui-coverage`, `candidates`, `direction-image` | 12 | `INVALID_INPUT`, `ROUTE_UNVERIFIED`, `SOURCE_DRIFT`, `SCOPE_UNFROZEN`, `CHANGE_LEVEL_AMBIGUOUS`, `OWNER_CEILING_INVALID`, `BUSINESS_REQUIRED`, `BACKEND_REQUIRED`, `ARCHITECTURE_REQUIRED`, `GRAMMAR_REQUIRED`, `EVIDENCE_MISSING`, `REFERENCE_EVIDENCE_EXHAUSTED`, `NO_VIABLE_DIRECTION`, `DIRECTION_CHOICE_REQUIRED`, `NO_PROGRESS` |
@@ -18,7 +18,7 @@ Sinh bởi `scripts/generate-operators-index.mjs` từ mọi `operator.md`; `--c
18
18
  | `platform.operate` | `luna` | `@workspaces/device-state`, `@workspaces/ports/<project>`, `@workspaces/projects/<project>/<role>`, `@worktrees/sessions/central-runtime` | — | `platform-operation-receipt`, `delta`, `checks` | 8 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `AUTHORITY_DRIFT`, `CAPABILITY_MISSING`, `INVENTORY_DRIFT`, `PORT_CONFLICT`, `EFFECT_UNAUTHORIZED`, `SERVICE_UNAVAILABLE`, `PROOF_FAILED` |
19
19
  | `quality.verify` | `luna` | `@workspaces/<project>/<role>/gates`, `@workspaces/be`, `@workspaces/fe`, `@worktrees/debts` | `backend-source-application`, `frontend-source-application`, `changes` | `quality-verification`, `gate-result`, `coverage` | 7 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `PREDECESSOR_MIXED`, `PREDECESSOR_STALE`, `GATE_UNAVAILABLE`, `DEBT_UNAPPROVED` |
20
20
  | `release.deploy` | `luna` | `@remote/ghcr/<image>`, `@remote/github-actions/<runId>`, `@workspaces/device-state` | `quality-verification` | `release-deployment`, `probes` | 10 | `INVALID_INPUT`, `NO_PROGRESS`, `AUTHORIZATION_MISSING`, `MANIFEST_INVALID`, `APPROVAL_REQUIRED`, `CREDENTIAL_UNAVAILABLE`, `HOST_UNAVAILABLE`, `ARTIFACT_MISSING`, `MIGRATION_BLOCKED`, `DOMAIN_UNRECONCILED`, `ROLLOUT_FAILED`, `RECOVERY_EXHAUSTED`, `CONCURRENT_DRIFT`, `ROLLBACK_IDENTITY_MISSING`, `STEADY_STATE_UNPROVEN` |
21
- | `uat.verify` | `sol-fresh` | `@workspaces/be`, `@workspaces/device-state`, `@worktrees/_templates`, `@worktrees/sessions/central-runtime`, `@worktrees/uat/<flow>/<case>` | `frontend-surface-audit`, `quality-verification` | `uat-flow-verification`, `uat-snapshot`, `uat-capture`, `uat-verdicts`, `screenshot`, `sheet` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `ADMISSION_MISSING`, `PROVISIONING_UNAVAILABLE`, `LEASE_INVALID`, `RUNTIME_UNAVAILABLE`, `EVIDENCE_UNAVAILABLE`, `FIXTURE_VIOLATION`, `CANONICAL_WRITE_DENIED` |
21
+ | `uat.verify` | `sol-fresh` | `@workspaces/be`, `@workspaces/device-state`, `@worktrees/_templates`, `@worktrees/sessions/central-runtime`, `@worktrees/uat/<flow>/<case>` | `frontend-surface-audit`, `quality-verification`, `route` | `uat-flow-verification`, `uat-snapshot`, `uat-capture`, `uat-verdicts`, `screenshot`, `sheet` | 10 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `ADMISSION_MISSING`, `PROVISIONING_UNAVAILABLE`, `LEASE_INVALID`, `RUNTIME_UNAVAILABLE`, `EVIDENCE_UNAVAILABLE`, `FIXTURE_VIOLATION`, `CANONICAL_WRITE_DENIED` |
22
22
  | `workspace.bind` | `luna` | `@workspaces/device-state`, `@workspaces/local/routes/<project>/<role>`, `@workspaces/ports/<project>`, `@workspaces/projects/<project>/<role>`, `@worktrees/sessions/central-runtime` | — | `workspace-route-binding`, `route` | 6 | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS`, `IDENTITY_UNVERIFIED`, `ROUTE_UNDECLARED`, `ROUTE_UNHYDRATED`, `ROUTE_MISMATCH`, `BRANCH_POLICY_VIOLATION`, `CHECKOUT_DIRTY`, `ENDPOINT_AUTHORITY_STALE`, `RUNTIME_NOT_READY` |
23
23
 
24
24
  ## Bàn giao giữa các nhánh
@@ -57,7 +57,7 @@ Mọi kind đi qua giữa các operator, ai ghi nó, ai đọc nó. Kind không
57
57
  | `image-prompt` | `content.generate` | — |
58
58
  | `independent-critique` | `architecture.decide` | — |
59
59
  | `inventory` | `frontend.presentation.resolve` | — |
60
- | `model` | `business.decide` | |
60
+ | `model` | `business.decide` | `architecture.decide (optional)`, `backend.source.apply (optional)` |
61
61
  | `mutations` | `backend.source.apply` | — |
62
62
  | `platform-operation-receipt` | `platform.operate` | — |
63
63
  | `probes` | `release.deploy` | — |
@@ -65,7 +65,7 @@ Mọi kind đi qua giữa các operator, ai ghi nó, ai đọc nó. Kind không
65
65
  | `quality-verification` | `quality.verify` | `git.publish`, `release.deploy`, `uat.verify` |
66
66
  | `release-deployment` | `release.deploy` | — |
67
67
  | `resolved-tree` | `frontend.presentation.resolve` | — |
68
- | `route` | `workspace.bind` | |
68
+ | `route` | `workspace.bind` | `uat.verify` |
69
69
  | `screenshot` | `frontend.surface.audit`, `uat.verify` | — |
70
70
  | `sheet` | `uat.verify` | — |
71
71
  | `stack-model` | `architecture.decide` | — |
@@ -32,6 +32,18 @@ axis is a partial check wearing a complete label. Every boundary answers the dat
32
32
  at least one store or states that it owns none; a store names one owning boundary that writes it,
33
33
  and a second writer exists only with an explicit shared-write justification.
34
34
 
35
+ ## The decision names every write it commits to
36
+
37
+ A boundary that owns a store says nothing about who writes it, when, or under which transaction, so
38
+ the decision closes that gap itself: `response/data/stack-model.json` carries one `operations` entry
39
+ per write this architecture commits to, and `## Operations` of the receipt restates the same rows.
40
+ Each entry names its transport, its writer, the stores it touches, its transaction boundary, its
41
+ idempotency kind, the migrations it ships, and the coverage-matrix dimensions of the business head it
42
+ implements. That list is the frozen contract `backend.source.apply` fills: the implementation restates
43
+ those operations unchanged and may add none, so an operation nobody declared here cannot be written
44
+ anywhere. Declaring a write is not the same as choosing an implementation, which is why the writer is
45
+ the one file path this operator names.
46
+
35
47
  ## The critique is a nested exchange
36
48
 
37
49
  After the selected alternative is deepened, the branch pauses: it emits `response/response.json`
@@ -50,12 +62,16 @@ alternative was asked for, and `response.json`; the critique agent writes only
50
62
  reconfigure runtime services, name implementation files in the handoff, or claim that an
51
63
  implementation, a quality gate, or a UAT run has passed.
52
64
 
65
+ When the `model` Input is present it is the authority for this run and the published head is lineage
66
+ only, because a decision taken against yesterday's promise is a decision against the wrong promise.
67
+ When it is absent the published head is the authority.
68
+
53
69
  ## Context
54
70
 
55
71
  | Alias | Bind | Required |
56
72
  | --- | --- | --- |
57
73
  | `@workspaces/be` | the routed backend checkout read at the frozen head; the inventory comes from its manifests and deployment files | yes |
58
- | `@worktrees/businesses/<featureId>` | the published business head, the promise the architecture must keep | yes |
74
+ | `@worktrees/businesses/<featureId>` | the published business head, the promise the architecture must keep; evidence when the session carries a `model` Input | yes |
59
75
  | `@knowledge/patterns` | reusable shapes the scope may bind; a shape, never a selection | no |
60
76
 
61
77
  ## Inputs
@@ -63,6 +79,7 @@ implementation, a quality gate, or a UAT run has passed.
63
79
  | Kind | From | Required |
64
80
  | --- | --- | --- |
65
81
  | `architecture-decision` | a prior run of `architecture.decide` on the same or an adjacent boundary; lineage that may be contradicted, never ignored | no |
82
+ | `model` | `business.decide`; the head that branch modelled, when it has not been published yet | no |
66
83
 
67
84
  ## Requirements
68
85
 
@@ -83,11 +100,11 @@ implementation, a quality gate, or a UAT run has passed.
83
100
  | --- | --- | --- | --- | --- | --- |
84
101
  | 1 | Validate the gate and resume | `resume`, `approval` | `request/request.json`, input `architecture-decision` when present, @workspaces/be at the frozen head | — | `INVALID_INPUT`, `SOURCE_DRIFT`, `NO_PROGRESS` |
85
102
  | 2 | Observe the current state | — | @workspaces/be at the frozen head: manifests, configuration, deployment files, @tools/git | `response/data/current-state.json` | `CURRENT_STATE_UNOBSERVED` |
86
- | 3 | Bind the inventory to the business promise | — | `response/data/current-state.json`, @worktrees/businesses/<featureId> at its published head | — | `BUSINESS_AUTHORITY_REQUIRED`, `EVIDENCE_MISSING` |
103
+ | 3 | Bind the inventory to the business promise | — | `response/data/current-state.json`, input `model` when present, otherwise @worktrees/businesses/<featureId> at its published head | — | `BUSINESS_AUTHORITY_REQUIRED`, `EVIDENCE_MISSING` |
87
104
  | 4 | Frame the decision | `objective`, `decisionId`, `constraints`, `tradeoffAxes` | `request/request.json` requirements | — | `CONSTRAINT_CONTRADICTION` |
88
105
  | 5 | Generate the alternatives | `alternatives` | `response/data/current-state.json`, @knowledge/patterns, @tools/websearch | `response/artifacts/<decisionId>-alternatives.html` only when more than one alternative was asked for, @tools/visualize | `NO_VIABLE_ALTERNATIVE` |
89
106
  | 6 | Select | `selectionPolicy`, `tradeoffAxes`, `approval` | `response/artifacts/<decisionId>-alternatives.html` when present | — | `CHOICE_REQUIRED` |
90
- | 7 | Deepen the selected alternative | `constraints` | `response/data/current-state.json` | `response/data/stack-model.json` | `DATA_OWNERSHIP_UNASSIGNED`, `COMPATIBILITY_UNVERIFIED` |
107
+ | 7 | Deepen the selected alternative and declare the operations it commits to | `constraints` | `response/data/current-state.json`, the bound business head's coverage matrix for the dimensions each operation cites | `response/data/stack-model.json`, including its `operations` | `DATA_OWNERSHIP_UNASSIGNED`, `COMPATIBILITY_UNVERIFIED` |
91
108
  | 8 | Await the critique: pause, a fresh agent attacks the selection, resume when it answers | — | `critique/response/critique.md` once the exchange is done | `response/response.json` (waiting, awaiting critique) | `CRITIQUE_UNRESOLVED` |
92
109
  | 9 | Confirm or return the selection | `selectionPolicy` | `critique/response/critique.md`, `response/data/stack-model.json` | — | `CHOICE_REQUIRED`, `NO_VIABLE_ALTERNATIVE` |
93
110
  | 10 | Write the handoff and emit | — | everything above | `response/response.md`, `response/response.json` | — |
@@ -95,7 +112,9 @@ implementation, a quality gate, or a UAT run has passed.
95
112
  Under the defaults, step 5 produces one design and no comparison page, step 6 has nothing to
96
113
  choose, and the decision's quality rests on step 8. When the only alternative fails an attack, step 9
97
114
  stops with `NO_VIABLE_ALTERNATIVE`, not `CHOICE_REQUIRED`. The handoff names contracts, never
98
- implementation files, because choosing the files is the next domain's job.
115
+ implementation files, because choosing the files is the next domain's job; the one exception is the
116
+ writer of each declared operation, which this operator does name, because the implementation may not
117
+ choose its own writer.
99
118
 
100
119
  ## Outputs
101
120
 
@@ -107,6 +126,10 @@ implementation files, because choosing the files is the next domain's job.
107
126
  | `alternatives` | `response/artifacts/<decisionId>-alternatives.html` | artifact | no |
108
127
  | `independent-critique` | `critique/response/critique.md` | md | yes |
109
128
 
129
+ `response/response.md` carries the `## Operations` table and `response/data/stack-model.json` carries
130
+ the matching `operations` array; together they are the mutation contract `backend.source.apply`
131
+ consumes, and no other output of this operator crosses into that step.
132
+
110
133
  ## Stops
111
134
 
112
135
  | Code | Disposition |