@orkestrel/scaffold 0.0.63 → 0.0.65

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 (57) hide show
  1. package/README.md +29 -104
  2. package/dist/bin/main.js +95 -27
  3. package/dist/bin/main.js.map +1 -1
  4. package/dist/host/AGENTS.md +2 -2
  5. package/dist/host/CLAUDE.md +6 -0
  6. package/dist/host/agents/orchestration.md +23 -15
  7. package/dist/host/agents/skills/enterprise-bootstrap/SKILL.md +184 -177
  8. package/dist/host/agents/skills/enterprise-bootstrap/references/bootstrap-reference.md +314 -91
  9. package/dist/host/agents/skills/enterprise-bootstrap/references/color-modes.md +241 -0
  10. package/dist/host/agents/skills/enterprise-bootstrap/references/components.md +83 -36
  11. package/dist/host/agents/skills/enterprise-bootstrap/references/frontend-design.md +297 -98
  12. package/dist/host/agents/skills/enterprise-bootstrap/references/inputs.md +25 -14
  13. package/dist/host/agents/skills/enterprise-bootstrap/references/inspection.md +216 -128
  14. package/dist/host/agents/skills/enterprise-bootstrap/references/responsive-layout.md +187 -0
  15. package/dist/host/agents/skills/enterprise-bootstrap/references/utilities.md +109 -20
  16. package/dist/host/agents/skills/orkestrel-debrief/references/field-testing.md +5 -5
  17. package/dist/host/agents/skills/orkestrel-falsify/references/reconcile.md +1 -1
  18. package/dist/host/agents/skills/orkestrel-publish/SKILL.md +15 -15
  19. package/dist/host/agents/skills/orkestrel-publish/references/wave.md +43 -17
  20. package/dist/host/agents/skills/orkestrel-publish/references/window.md +41 -16
  21. package/dist/host/claude/agents/orkestrel.md +56 -56
  22. package/dist/host/claude/agents/reviewer.md +13 -0
  23. package/dist/host/claude/rules/architecture.md +51 -45
  24. package/dist/host/claude/rules/documentation.md +18 -1
  25. package/dist/host/claude/rules/portability.md +2 -0
  26. package/dist/host/claude/rules/quality.md +1 -1
  27. package/dist/host/claude/rules/tests.md +12 -11
  28. package/dist/host/claude/rules/typescript.md +5 -0
  29. package/dist/host/claude/rules/workspace.md +25 -20
  30. package/dist/host/claude/rules/writing.md +4 -0
  31. package/dist/host/claude/settings.json +1 -1
  32. package/dist/host/claude/skills/enterprise-bootstrap/SKILL.md +10 -9
  33. package/dist/host/codex/agents/orkestrel.toml +3 -3
  34. package/dist/host/codex/agents/reviewer.toml +4 -2
  35. package/dist/host/configs/helpers.ts +311 -2
  36. package/dist/host/configs/policy.ts +1100 -51
  37. package/dist/host/dotfiles/oxlintrc.json +72 -1
  38. package/dist/host/guides/guide.md +749 -222
  39. package/dist/host/guides/scaffold.md +529 -394
  40. package/dist/host/manifest.json +53 -40
  41. package/dist/host/scripts/ollama.sh +322 -13
  42. package/dist/host/tests/config.test.ts +1200 -16
  43. package/dist/host/tests/policy.test.ts +157 -173
  44. package/dist/host/tests/setupPolicy.ts +522 -1007
  45. package/dist/src/core/index.cjs +402 -287
  46. package/dist/src/core/index.cjs.map +1 -1
  47. package/dist/src/core/index.d.cts +160 -128
  48. package/dist/src/core/index.d.ts +160 -128
  49. package/dist/src/core/index.js +400 -286
  50. package/dist/src/core/index.js.map +1 -1
  51. package/dist/src/server/index.cjs +28 -21
  52. package/dist/src/server/index.cjs.map +1 -1
  53. package/dist/src/server/index.d.cts +38 -33
  54. package/dist/src/server/index.d.ts +38 -33
  55. package/dist/src/server/index.js +28 -21
  56. package/dist/src/server/index.js.map +1 -1
  57. package/package.json +18 -19
@@ -1,20 +1,25 @@
1
1
  # Instruments
2
2
 
3
- Reach for an instrument here where a capture cannot settle the claim. Run every one with its negative
4
- control, in the same conditions, on the real compiled cascade the page loads. Treat an instrument
5
- whose negative control passes as broken and refuse its reading as evidence;
6
- `.claude/rules/quality.md` owns that law where it is present.
7
-
8
- Take each entry's property, population, reading, negative control, and coverage as written, and hold
9
- every entry to these rules.
10
-
11
- - **Report the population.** A reading carries the population it walked. An empty population fails
12
- the run, because an extractor that quietly matched nothing satisfies every other assertion.
13
- - **Draw every negative control from outside the population.** Name the membership rule first, then
14
- pick a negative control the rule excludes. Reject a negative control that rule admits.
15
- - **Enter a negative control through the same door the surface enters.** A negative control handed
16
- straight to the reading tests the reading alone, so pair it with one appended to the tree, the stylesheet,
17
- or the registry the instrument walks wherever the instrument has an extraction step.
3
+ Reach for an instrument where a capture cannot settle the claim. Run it against the compiled
4
+ cascade the page loads, with its negative controls under the same conditions. Treat a missed
5
+ negative control as a broken instrument and refuse its reading as evidence;
6
+ `.claude/rules/quality.md` owns that law where present.
7
+
8
+ Keep mechanical results separate from visual judgments. Take each entry's property, population,
9
+ reading, negative control, and coverage as its contract. Report failures and untested coverage, not
10
+ a pass label alone.
11
+
12
+ - **Report the population.** Name the membership rule and count what the extractor walked. An
13
+ expected but empty population fails. Mark a genuinely absent feature not applicable with its
14
+ reason; do not count it as passing.
15
+ - **Keep controls independent.** Construct known-invalid fixtures in the harness, outside the
16
+ production population and the accepted set. Include them in the test run through the same
17
+ extraction path, and exclude them from production counts. Do not filter the defect out before
18
+ the reader can see it.
19
+ - **Test extraction as well as reading.** Pair a directly fed fixture with one appended to the
20
+ tree, stylesheet, or registry wherever extraction exists. Remove harness mutations afterward.
21
+ - **Bound the claim.** Name files, routes, themes, viewports, states, and exclusions actually read.
22
+ Unsupported input and unavailable tooling remain open, never passed by assumption.
18
23
 
19
24
  ## Contents
20
25
 
@@ -22,146 +27,229 @@ every entry to these rules.
22
27
  - [Declared class combinations](#declared-class-combinations)
23
28
  - [Style escapes](#style-escapes)
24
29
  - [Token discipline](#token-discipline)
30
+ - [Declared design scales](#declared-design-scales)
25
31
  - [Custom rule doing a utility's job](#custom-rule-doing-a-utilitys-job)
32
+ - [Color-mode inheritance](#color-mode-inheritance)
26
33
  - [Composited contrast in both themes](#composited-contrast-in-both-themes)
27
34
  - [One glyph, one meaning](#one-glyph-one-meaning)
35
+ - [Responsive task and reflow](#responsive-task-and-reflow)
36
+ - [Responsive interaction continuity](#responsive-interaction-continuity)
37
+ - [Rendered design review](#rendered-design-review)
28
38
  - [When an authored rule is already earned](#when-an-authored-rule-is-already-earned)
29
39
 
30
40
  ## Authored class in the shipped cascade
31
41
 
32
- - **Property.** Every class token the surface's own templates and components author has a rule in
33
- the compiled CSS the page loads.
34
- - **Population.** The class tokens the authored markup carries, read against every stylesheet the
35
- page loads: the vendor build, each skin, and the project's own.
36
- - **Reading.** Subtract the tokens the loaded stylesheets define from the tokens the markup carries.
37
- A remainder fails the run and names each token with the file that authored it. Report the token
38
- population walked, and fail a run that walked none.
39
- - **Negative control.** A fed control and an appended control, each of which the reading must report.
40
- Feed the first — a token no stylesheet defines — straight to the reading. Append the second through
41
- the extraction door: an element built in the harness carrying that undefined token on an SVG
42
- `class` attribute, added to the tree the reading walks. Each sits outside the population, which is
43
- authored tokens the cascade resolves.
44
- - **Coverage.** The fed negative control covers the subtraction. The appended negative control covers the extractor,
45
- and it is what fails a reading that never leaves the root or that drops SVG tokens by reaching for
46
- `className`, where the value is an `SVGAnimatedString` rather than a string. Together they prove
47
- authored tokens are a subset of the cascade. The instrument says nothing about a cascade rule
48
- nobody authored, a token a build step or a script adds after the read, or whether a resolved rule
49
- paints what the author intended.
42
+ - **Property.** Every styling class the surface authors resolves in the loaded CSS. Separately name
43
+ legitimate behavior/test hooks that require no CSS; never excuse an intended utility as a hook.
44
+ - **Population.** Authored class tokens, including SVG and conditional states, against vendor,
45
+ skin, dependency, generated-utility, and project stylesheets actually loaded.
46
+ - **Reading.** Parse selectors, subtract the defined styling tokens from the authored set, and
47
+ report each unresolved token with its source. Enumerate declared conditional classes not reached
48
+ in the mounted tree separately; an unreachable stylesheet is an open dependency, not an empty one.
49
+ - **Negative control.** Feed an undefined styling token to the reader, then append a harness SVG
50
+ carrying that token through the same tree extractor. Both must be reported.
51
+ - **Coverage.** The two controls cover set comparison and extraction, including SVG's non-string
52
+ `className`. Use `getAttribute('class')` or an equivalent safe reader. Resolution does not prove
53
+ the rule wins the cascade, paints the intended result, or covers a state never enumerated.
50
54
 
51
55
  ## Declared class combinations
52
56
 
53
- - **Property.** Every multi-utility chrome string the surface reuses is declared once by name with
54
- the invariant it holds, and the markup carries no undeclared combination.
55
- - **Population.** The declared combinations, each with its name and its invariant, and every
56
- multi-utility string the authored markup carries.
57
- - **Reading.** Match each string in the markup against the declared set. An undeclared combination
58
- fails and names the element that carries it.
59
- - **Negative control.** A fed control and an appended control, each of which the reading must refuse.
60
- Feed the first — a string one utility away from a declared combination — straight to the reading.
61
- Append the second through the extraction door: an element built in the harness carrying that same
62
- undeclared string on an SVG `class` attribute, added to the tree the reading walks. Each sits
63
- outside the declared set.
64
- - **Coverage.** The fed negative control covers the match against the declared set. The appended negative
65
- control covers the extractor, and it is what fails a reading that never leaves the root or that drops SVG
66
- tokens by reaching for `className`. Together they prove reused chrome is declared. The instrument
67
- does not prove a declared invariant is true, and it does not read a single utility used alone.
68
- - **Never substitute a cancellation heuristic.** A rule that flags a string for its utility count, or
69
- for mixing categories, refuses the legitimate transparent read chrome that keeps a read view and an
70
- edit view from reflowing.
57
+ - **Property.** Reused multi-utility chrome has one named declaration and a stated invariant.
58
+ - **Population.** Declared combinations and the authored instances of those reusable patterns.
59
+ Declare the pattern scope; do not require a registry entry for every one-off layout string.
60
+ - **Reading.** Compare token sets within that scope to the named contracts. Report an undeclared
61
+ or divergent instance. Keep utility order irrelevant unless the host's class merger makes it
62
+ meaningful; record that merger when it applies.
63
+ - **Negative control.** Feed a combination one utility away from its contract, then append an
64
+ instance carrying that mutation through the same extractor, including an SVG fixture. Report both.
65
+ - **Coverage.** This proves instances match declarations, not that an invariant renders correctly.
66
+ Pair geometry or contrast invariants with their own measurements. Never substitute utility-count
67
+ or mixed-category heuristics; a valid transparent read-only treatment can use several utilities.
71
68
 
72
69
  ## Style escapes
73
70
 
74
- - **Property.** The surface's own markup carries no `style` attribute and no `<style>` element.
75
- - **Population.** The elements of a freshly mounted, undriven tree — the surface as authored, before
76
- any interaction drives it.
77
- - **Reading.** Collect every element carrying an inline declaration or an embedded style element and
78
- report it with its markup. Any hit fails.
79
- - **Exemptions, declared by name.** Exempt the framework's own runtime styles and name each exemption
80
- in the instrument: a Bootstrap Modal, Offcanvas, Collapse, or Dropdown writes inline styles as it
81
- runs, and a conditional-visibility directive such as `v-show` emits `style="display: none"` at
82
- mount. Run the reading on an undriven tree, because a reading taken after a journey drives the
83
- surface reports on the framework rather than on the author.
84
- - **Negative control.** An element carrying an inline declaration, built in the harness rather
85
- than taken from the surface, fed to the reading. It sits outside the surface's own markup and the
86
- reading must report it.
87
- - **Coverage.** The instrument reads authored markup at mount. It does not see a style a component
88
- writes after the person interacts, a rule authored in a stylesheet, or an escape inside a
89
- third-party component's own markup.
71
+ - **Property.** Authored markup carries no `style` attribute or `<style>` element.
72
+ - **Population.** Authored templates and the freshly mounted, undriven tree. Keep source and mounted
73
+ readings distinct so generated framework styles are not mistaken for authored declarations.
74
+ - **Reading.** Report inline declarations and embedded style elements with their source or element.
75
+ Record framework/runtime exemptions by producer and purpose, never a blanket component exemption.
76
+ Bootstrap overlay positioning and conditional-visibility directives may write runtime styles.
77
+ - **Negative control.** Feed an element with an inline declaration, then append an inline-styled
78
+ element and a `<style>` element to the harness tree. Every non-exempt fixture must be reported.
79
+ - **Coverage.** This covers authored and mount-time escapes, not later interactions or third-party
80
+ internals outside the declared scope. Drive later states separately when making claims about them.
90
81
 
91
82
  ## Token discipline
92
83
 
93
- - **Property.** No authored rule carries a literal color, and every custom paint resolves through a
94
- token in each color mode the product ships.
95
- - **Population.** The project's own authored stylesheet rules, and the resolved value of each
96
- custom-painted property in each color mode.
97
- - **Reading.** A literal color in an authored declaration fails. For each custom paint, read the
98
- resolved value once per mode; a mode that leaves it unresolved fails, and so does a pair of modes
99
- that resolve it identically where the design says the modes differ.
100
- - **Negative control.** A rule carrying a literal color, and a paint whose token the cascade does
101
- not define, both fed to the reading rather than authored into the surface. Each sits outside the
102
- population of authored rules that pass, and the reading must report both.
103
- - **Coverage.** The instrument covers authored rules and the paints it was given. It does not judge
104
- whether the chosen token is the right one, and it reads no vendor rule and no inline declaration —
105
- [Style escapes](#style-escapes) covers those.
84
+ - **Property.** Literal colors live only in declared primitive definitions. Semantic and component
85
+ paint resolve through the declared token layers in each shipped color mode.
86
+ - **Population.** Project-authored color declarations and token references, the named primitive
87
+ definition locations, and custom-painted properties reached in each theme and state.
88
+ - **Reading.** Parse declarations, not color-looking text in comments or strings. Permit raw colors
89
+ only in the named primitive definitions; reject literals in component paint, unresolved or cyclic
90
+ references, and a component bypassing semantic tokens. Check RGB partners where consumed. A theme
91
+ pair may resolve identically unless the design contract requires it to differ.
92
+ - **Negative control.** Accept a valid primitive definition as a positive fixture. Feed a literal
93
+ component fill and an undefined token reference; append both to a harness stylesheet through the
94
+ same extractor. The valid definition must survive and every invalid fixture must fail.
95
+ - **Coverage.** This proves declared paint follows the token boundary in the read scope. It does not
96
+ prove mode adaptation, foreground ownership, legibility, or visual quality. Use Color-mode inheritance for the cascade contract. Vendor literals are not authored violations;
97
+ rendered contrast still measures their effect. Inline paint belongs to Style escapes.
98
+
99
+ ## Declared design scales
100
+
101
+ - **Property.** Authored type, spacing, width, radius, and elevation treatments use declared roles,
102
+ shipped scale steps, or documented extensions rather than untracked one-off values.
103
+ - **Population.** The project's scale/role definitions and authored declarations consuming them.
104
+ Include breakpoint rules, component variants, and any declared fluid sizing formulas.
105
+ - **Reading.** Resolve each treatment to its role or accepted step. Report undeclared values,
106
+ missing generated selectors, `em` font sizes, and `.small` nested inside `.small`. Validate fluid formulas against their declared bounds; do not reject
107
+ legitimate intermediate computed values as off-scale. Confirm required grouping relationships in
108
+ the rendered review rather than inferring them from token names.
109
+ - **Negative control.** Feed an undeclared spacing value and append an off-scale type declaration
110
+ through the stylesheet extractor. Report both. Accept a declared fluid value inside its bounds.
111
+ - **Coverage.** This checks consistency with a system, not whether the system suits the task. A
112
+ perfectly on-scale layout can still have ambiguous grouping, poor line breaks, or the wrong density.
106
113
 
107
114
  ## Custom rule doing a utility's job
108
115
 
109
- - **Property.** Every authored selector expresses something no shipped utility expresses, or records
110
- the reason the utility does not fit.
111
- - **Population.** The selectors in the project's own stylesheets.
112
- - **Reading.** For each selector, name the utility that would carry the same declarations. A selector
113
- a shipped utility already expresses fails unless it carries the recorded reason.
114
- - **Negative control.** A rule restating a shipped utility exactly — a padding declaration matching
115
- a spacing step — fed to the reading rather than authored into the stylesheet. It sits outside the
116
- set of authored selectors that pass, and the reading must report it.
117
- - **Coverage.** The instrument reads declarations, not intent. A rule that does a utility's job
118
- alongside something else passes it, so a person still reads the authored stylesheet.
116
+ - **Property.** Each authored selector expresses a need no shipped utility expresses, or records
117
+ why the utility does not fit. Declared component-variable overrides and generated utilities stay
118
+ on their extension rung; they are not automatically bespoke styling violations.
119
+ - **Population.** Project-authored selectors, their declarations, and the loaded utility rules.
120
+ - **Reading.** Compare declarations and name the equivalent utility when one exists. Report a
121
+ duplicate without a recorded reason. Read mixed-purpose rules too; adding an unrelated declaration
122
+ does not excuse the duplicated part.
123
+ - **Negative control.** Feed a rule that exactly repeats a shipped padding utility, then append it
124
+ through the stylesheet extractor. Report it in both runs.
125
+ - **Coverage.** This checks expressible equivalence, not the intent or merit of an exception. Review
126
+ the reason and styling-rung authorization separately; specificity and state scope can matter.
127
+
128
+ ## Color-mode inheritance
129
+
130
+ - **Property.** Ordinary content inherits its body or component foreground. Quiet adaptive fills
131
+ add no arbitrary text color. Intentional solid and local-mode boundaries own a measured pair;
132
+ native component states retain their foreground behavior. Take the contract from
133
+ [color-modes.md](color-modes.md).
134
+ - **Population.** Rendered text, status marks, badges, tags, links, fields, selected controls, table
135
+ cells, and overlays in the actual loaded build. Include supported nested modes, skin overrides,
136
+ and portal mount points; name the boundaries that own an explicit foreground.
137
+ - **Reading.** Drive the existing mounted tree from light to dark and back. Read computed text,
138
+ painted backgrounds, relevant custom properties, and winning declarations after each transition.
139
+ Confirm quiet ordinary text matches its intended inherited foreground; identify the owner when
140
+ a component legitimately differs. Check supported system preference and reload behavior when the
141
+ mode controller is in scope. A class-name match or a changing variable alone does not pass.
142
+ - **Negative control.** Add fixed `text-dark` on a dark body surface, a stock `.badge` with a subtle
143
+ fill but no inheritance reset in light mode, and an opposite-mode plain region without its owned
144
+ foreground/background pair. Require the reader to detect each violated contract. For projects
145
+ using aliases, add a root-resolved foreground alias inherited into an opposite-mode scope.
146
+ Verify each control is invalid in that build; a class name alone does not establish the defect.
147
+ - **Coverage.** Pair the cascade reading with Composited contrast; correct inheritance can still
148
+ produce insufficient contrast on a changed surface. An isolated stock fixture establishes only
149
+ that fixture's behavior, not the host skin or application. Unreached states and mounts stay open.
119
150
 
120
151
  ## Composited contrast in both themes
121
152
 
122
- - **Property.** Every pairing the surface paints meets its bar in every theme: 4.5:1 for anything
123
- information-bearing, 3:1 for textless marks and the chrome that carries state.
124
- - **Population.** The pairings the surface renders, read per theme on the compiled cascade, with
125
- every translucent layer composited. Exempt disabled controls, per [SKILL.md](../SKILL.md) →
126
- Surfaces, color, contrast.
127
- - **Reading.** Composite the painted layers, read the ratio, and fail anything under its bar with the
128
- pairing named. Take the mechanics from [bootstrap-reference.md](bootstrap-reference.md) → Measuring
129
- the bars.
130
- - **Negative control.** An opaque pairing and a translucent stack, each of which the reading must
131
- fail. Compose the opaque pairing in the harness at a ratio known to sit under the bar. Compose the
132
- stack with a translucent layer over a floor, so its composited ratio sits under the bar while its
133
- top layer read alone sits above it. Each is composed in the harness rather than taken from the
134
- surface, so each sits outside the rendered population.
135
- - **Coverage.** The opaque pairing covers the ratio arithmetic. The translucent stack covers the
136
- compositing step, and it is what fails a reader that takes the top layer's declared color and skips
137
- the layers under it. Together they measure what rendered, in the themes and viewports the run
138
- entered. A pairing that appears only in a state the run never reached is unmeasured, so name the
139
- states the run covered beside the result.
153
+ - **Property.** Every measured pairing meets the package bar: 4.5:1 for information-bearing text,
154
+ 3:1 for meaningful textless marks and state/focus chrome, in each declared theme and reached state.
155
+ - **Population.** Rendered text and meaningful graphics, their actual surfaces, and all paint layers
156
+ affecting contrast. Name exemptions for disabled controls; do not exempt readable metadata.
157
+ - **Reading.** Composite translucent backgrounds onto the opaque base and translucent foregrounds
158
+ onto that result before calculating contrast. Include ancestor opacity where relevant. Report the
159
+ pairing, ratio, bar, theme, and state for each failure. Take the mechanics from
160
+ [bootstrap-reference.md](bootstrap-reference.md) → Measuring the bars.
161
+ - **Negative control.** Feed an opaque pair known to fail and a translucent stack whose composited
162
+ ratio fails although a flat read would pass. Append both through the rendered-pair extractor and
163
+ require all failures. Include the same theme scopes and paint mechanism as the production run.
164
+ - **Coverage.** Flat computed colors cannot settle text over images, gradients, masks, blend modes,
165
+ or unsupported compositing. Read the actual background under the text with an appropriate method,
166
+ or mark the pairing open. Never average an image into a passing color. Name unvisited states;
167
+ measurements from one surface, theme, or crop do not establish another.
140
168
 
141
169
  ## One glyph, one meaning
142
170
 
143
- - **Property.** Each status meaning takes one glyph, each glyph serves one meaning, and every
144
- registered glyph resolves in the icon set the product actually ships.
145
- - **Population.** The registry of meanings and glyphs the surface uses, and the shipped icon set.
146
- - **Reading.** A meaning registered twice, a glyph registered against two meanings, or a glyph the
147
- shipped set does not resolve fails, each named.
148
- - **Negative control.** A registry entry binding a second meaning to a glyph already registered,
149
- plus a glyph name the shipped set lacks. Both sit outside the registered set, and the reading must
150
- report both.
151
- - **Coverage.** The instrument proves the registry is consistent and resolvable. It does not prove
152
- the markup draws the registered glyph for the meaning it carries, so pair it with a capture of the
153
- states that use marks.
171
+ - **Property.** Each registered status meaning takes one glyph; each registered glyph serves one
172
+ status meaning and resolves in the icon set the product ships.
173
+ - **Population.** The surface's status registry and the shipped icon set. Keep generic action icons
174
+ outside this status-only contract unless the project explicitly includes them.
175
+ - **Reading.** Report duplicate meanings, a status glyph bound to two meanings, and missing glyphs.
176
+ - **Negative control.** Feed a second meaning for a registered glyph and an unavailable glyph name;
177
+ append equivalent invalid entries through the registry extractor. Report both kinds of failure.
178
+ - **Coverage.** This proves registry consistency, not that the markup uses the correct glyph or that
179
+ its optical size and contrast work. Capture the states that use the marks and inspect their names.
180
+
181
+ ## Responsive task and reflow
182
+
183
+ - **Property.** The declared task remains readable and operable without unintended page overflow,
184
+ concealed content, or clipped controls at the widths in [responsive-layout.md](responsive-layout.md).
185
+ - **Population.** Changed routes, responsive regions, required task fields/actions, local scrollers,
186
+ and their reached data states. Include conditional content and loaded fonts/assets. Name the
187
+ Bootstrap build and every environment substitution; a missing dependency is not a passing page.
188
+ - **Reading.** Record viewport and container bounds, document width, local client/scroll dimensions,
189
+ critical text bounds, effective target sizes, and required content/action visibility. Check both
190
+ sides of each actual transition. Use a small declared rounding tolerance. Keep intentional data
191
+ scrolling separate from document overflow; identify the owner and prove reach to its final item.
192
+ Read task regions as well as `documentElement.scrollWidth`; hidden overflow is not a repair.
193
+ - **Negative control.** Feed a too-wide region to the bounds reader; append an oversized child,
194
+ conceal it behind a clipping parent, and hide a required primary action in separate harness runs.
195
+ Each defect must be reported by the same production extraction path. Include a positive local
196
+ table scroller so the reader cannot pass by banning all overflow.
197
+ - **Coverage.** Test 320/390 CSS px, a wide view, each used boundary, long content, and short height.
198
+ Record enlarged-text and real browser-zoom tests separately. Reducing the viewport is a reflow
199
+ proxy, not execution of 400% browser zoom. Geometry does not establish aesthetics, full text
200
+ contrast, real-device keyboard behavior, or an exhaustive accessibility result.
201
+
202
+ ## Responsive interaction continuity
203
+
204
+ - **Property.** Narrow/wide changes preserve access, state, and meaningful focus; responsive chrome
205
+ does not leave a stale overlay, scroll lock, or trap.
206
+ - **Population.** Navigation triggers/panels, forms, selections, filters, sort/pagination, disclosures,
207
+ and overlays changed by a breakpoint. Record which controls are functional and which are fixtures.
208
+ - **Reading.** Complete the narrow primary flow. Open/close navigation with pointer and keyboard,
209
+ test Escape/focus return, resize while open, and return below the threshold. Carry selected IDs,
210
+ filters, sort, field values, and active detail context through both directions. Check reachable
211
+ dialog actions in a short viewport and with enlarged text. Confirm actual row/filter changes,
212
+ not merely `aria-sort`, labels, or a success message.
213
+ - **Negative control.** Remove the required narrow trigger, break its target, and erase a selected
214
+ record during a harness resize. Drive the same interaction assertions; each must fail. Mark an
215
+ absent component not applicable rather than treating an empty locator set as success.
216
+ - **Coverage.** Desktop mouse, keyboard, and emulated touch are separate runs. Keep real-device
217
+ browser chrome/soft keyboard, unsupported engines, persistence, and server actions open unless
218
+ exercised. For dual presentations, inspect IDs and the accessibility tree: only the active view
219
+ may expose its controls. Attribute presence alone does not establish any interaction result.
220
+
221
+ ## Rendered design review
222
+
223
+ Use captures for these judgments, not synthetic negative controls. Record the criterion, capture,
224
+ viewport/theme/state, finding, and disposition. A missing capture leaves the judgment open. For a
225
+ requested review round or campaign, use `orkestrel-polish-surface` rather than creating one here.
226
+
227
+ - **Task and hierarchy:** the main information and action lead; supporting content remains readable;
228
+ labels, semantics, and destructive rank match the work. Check a grayscale view as a hierarchy aid.
229
+ - **Grouping and density:** inter-group gaps exceed internal gaps; labels/help/errors stay with the
230
+ right control after wrapping. Width serves the content; rails, forms, and tables use it deliberately.
231
+ - **Type and reflow:** line length, baseline alignment, line-height, numeric comparison, and fallback
232
+ text work at the declared widths and enlarged text. No essential content is clipped or hidden.
233
+ - **Color, depth, and imagery:** light/dark transitions preserve hierarchy without gratuitous text overrides; color has a second encoding;
234
+ elevation describes layers; crops and icon sizes preserve useful detail; the frame stays quiet.
235
+ - **States and restraint:** first-use, filtered-empty, loading, partial, and error retain a useful
236
+ next step. Long or missing content holds up. The signature belongs to the brief; accessories do not
237
+ compete with the task. Motion-free operation remains complete.
238
+
239
+ A visual review does not establish keyboard behavior, contrast arithmetic, or full WCAG conformance.
240
+ Pair each such claim with the relevant instrument or interaction test and its actual coverage.
154
241
 
155
242
  ## When an authored rule is already earned
156
243
 
157
- Leave rung 4 to the developer, per [SKILL.md](../SKILL.md) → When custom CSS is justified. Write an
158
- authored rule without asking only when every one of these holds:
244
+ Leave rung 4 to the developer, per [SKILL.md](../SKILL.md) → When custom CSS is justified. Write a
245
+ rule without asking only when every condition holds:
159
246
 
160
- - an instrument here reports the vendor cascade failing a stated bar — the focus ring under 3:1, the
161
- status text under 4.5:1, the shipped component with no class for the state the surface must
162
- show;
163
- - the rule cites that reading beside it, naming the instrument, the bar, and the value read;
164
- - the rule restores the bar and does nothing else;
165
- - the rule is written over `--bs-*` tokens, so both color modes move with the theme.
247
+ - an instrument reports a vendor failure against a stated requirement, such as a focus ring below
248
+ 3:1 or information-bearing status text below 4.5:1;
249
+ - the rule cites the instrument, failing reading, and required bar beside it;
250
+ - rungs 1–3 cannot restore the requirement, and the rule repairs that failure without unrelated polish;
251
+ - the rule uses `--bs-*` paint tokens and declared scales, and the repaired result is re-measured in
252
+ every affected theme and state.
166
253
 
167
- Treat anything wider as a proposal: name what the rule would buy, and stop.
254
+ A visual preference alone does not open this exception. Treat anything wider as a proposal: name
255
+ what the rule would buy and stop until authorized.
@@ -0,0 +1,187 @@
1
+ # Responsive layout
2
+
3
+ > Part of the `enterprise-bootstrap` package. Use before composing a screen, shell, toolbar,
4
+ > form, overlay, or data view. Operate layer: [SKILL.md](../SKILL.md).
5
+
6
+ ## Contents
7
+
8
+ - [Declare the contract](#declare-the-contract)
9
+ - [Build the base](#build-the-base)
10
+ - [Expand by available space](#expand-by-available-space)
11
+ - [Keep the task intact](#keep-the-task-intact)
12
+ - [Handle navigation and overlays](#handle-navigation-and-overlays)
13
+ - [Prove the result](#prove-the-result)
14
+
15
+ ## Declare the contract
16
+
17
+ Record one row per distinct region before writing its layout. Reuse a region's contract instead
18
+ of repeating it on every screen. Take the host's supported range; absent one, prove normal content
19
+ at 320 CSS px and compose first at a representative 390 CSS px. These are verification widths,
20
+ not new Bootstrap breakpoints or guarantees about physical devices.
21
+
22
+ | Region | Narrow behavior | Expansion condition | Information/actions retained | Overflow |
23
+ | ---------------- | ------------------------------------------------------------- | --------------------------------------- | -------------------------------------------------- | ---------------------------- |
24
+ | Navigation | Named trigger opens a drawer | Rail plus usable main content fit | Same destinations and current state | Drawer body only when needed |
25
+ | Search/actions | Search and actions stack; filters wrap or disclose | Labels and hit areas fit together | Search, active filters, clear path, primary action | None |
26
+ | Record list | Identity, decision fields, primary action; details disclosure | Comparison columns fit beside any rail | Same data, sorting, selection, actions | None for the list |
27
+ | Comparison table | Named, keyboard-operable local scroller | Columns fit without a scroller | All comparison columns and row identity | Table region only |
28
+ | Form/dialog | One reading column; natural height | Related fields or explanation have room | Labels, errors, consequences, cancel/commit | One vertical owner |
29
+ | Hero/preview | Copy, actions, then legible evidence | Both columns remain useful | Thesis, primary action, useful demonstration | Decorative layer only |
30
+
31
+ Name the actual thresholds used and why. Do not give every region the same breakpoint by habit.
32
+ Build and use the narrow primary flow before adding desktop chrome or finishing details.
33
+
34
+ ## Build the base
35
+
36
+ Use Bootstrap's mobile-first direction: unprefixed rules apply from the smallest width; `sm`,
37
+ `md`, `lg`, `xl`, and `xxl` add behavior at their minimum widths. `xs` has no class infix.
38
+ Take the installed breakpoint map, not device labels, from
39
+ [Breakpoints & layout](bootstrap-reference.md#breakpoints--layout).
40
+
41
+ Prefer shipped structure before custom media queries:
42
+
43
+ ```html
44
+ <!-- One field per row until the content supports a pair. -->
45
+ <div class="row g-3">
46
+ <div class="col-12 col-md-6"><!-- labelled field --></div>
47
+ <div class="col-12 col-md-6"><!-- related labelled field --></div>
48
+ </div>
49
+
50
+ <!-- Stretch actions at the base; use their natural widths from sm. -->
51
+ <div class="d-grid gap-2 d-sm-flex flex-sm-wrap">
52
+ <button type="submit" class="btn btn-primary">Save changes</button>
53
+ <button type="button" class="btn btn-outline-secondary">Cancel</button>
54
+ </div>
55
+
56
+ <!-- Give search its own narrow row rather than crushing its input. -->
57
+ <form class="row g-2 align-items-end" role="search" aria-label="Find invoices">
58
+ <div class="col-12 col-md">
59
+ <label class="form-label" for="invoice-search">Search invoices</label>
60
+ <input class="form-control" id="invoice-search" type="search" />
61
+ </div>
62
+ <div class="col-12 col-sm-6 col-md-auto">
63
+ <label class="form-label" for="invoice-status">Status</label>
64
+ <select class="form-select" id="invoice-status">
65
+ <option>All statuses</option>
66
+ </select>
67
+ </div>
68
+ </form>
69
+ ```
70
+
71
+ Keep DOM order meaningful before arranging columns. Do not use visual `order-*` to separate focus
72
+ order from reading order. Use `p-3 p-lg-4` and `g-3 g-lg-4` to grow outer space independently of
73
+ control size. Keep `.row` gutters inside a compatible container or padded parent; do not add
74
+ unbudgeted `gap-*` to percentage columns whose widths already total the row.
75
+
76
+ Check the generated CSS. Stock width/height, overflow, and general position utilities do not all
77
+ ship breakpoint variants. Do not invent `w-md-auto`, `overflow-lg-auto`, `position-lg-sticky`, or
78
+ `min-w-0`. Responsive sticky helpers are a separate shipped family. Take missing roles through
79
+ [Layout and type extensions](bootstrap-reference.md#layout-and-type-extensions).
80
+
81
+ ## Expand by available space
82
+
83
+ Measure the content container after rails, gutters, and panel padding. A wide viewport can contain
84
+ a narrow main region, split pane, or dialog. Delay columns, keep an intrinsic layout, or use an
85
+ authorized container-query extension when reuse requires it. A viewport breakpoint alone does not
86
+ prove the component fits.
87
+
88
+ Let flex/grid children shrink: use the project's zero-inline-minimum role and, for custom grids,
89
+ `minmax(0, 1fr)` where appropriate. Break long identifiers at safe opportunities; expose complete
90
+ values through a usable detail view when truncation is unavoidable. Never shrink amounts, labels,
91
+ or input text to rescue a desktop row. Let identity/amount headers wrap independently and bound
92
+ long action labels to their container; a wrapping parent does not constrain an oversized child.
93
+ Preserve native input scrolling for long editable values.
94
+
95
+ Use a content-led maximum width, not an unconditional fixed width or `vw-100` inside a padded
96
+ container. Let content set height. Prefer ordinary page scrolling to a phone-sized nested viewport;
97
+ reserve bounded table scrolling for a documented comparison task. Do not use `vh-100`, transforms,
98
+ CSS zoom, or root `overflow-x-hidden` to make an oversized layout appear to fit.
99
+
100
+ Keep large typography and presentation space responsive without shrinking body text or hit areas.
101
+ Bootstrap RFS scales supported type; it does not reflow navigation, dialogs, or preview content.
102
+ A readable line count beats mechanically preserving a desktop hero's proportions.
103
+
104
+ ## Keep the task intact
105
+
106
+ Choose a data strategy by the task, not a fixed ranking:
107
+
108
+ - **Record work:** use a compact list or labelled stack when the job is finding and acting on one
109
+ record. Keep identity, status, amount, due date, and the relevant action directly discoverable;
110
+ put secondary details behind a named disclosure. Generate variants from one data/state model.
111
+ - **Comparison work:** retain a semantic table when column comparison is essential. Local horizontal
112
+ scrolling is valid; name the region, provide a scroll cue, and verify keyboard reach to both ends.
113
+ Keep search and pagination outside it. Do not turn every comparison into cards.
114
+ - **Priority columns:** omit a column from the narrow presentation only when the same information is
115
+ available through an operable detail path. `d-none` alone is not a content strategy.
116
+
117
+ Do not render two independent forms or state stores for narrow/wide variants. Keep IDs unique and
118
+ only the active representation in the accessibility/focus tree. Preserve filters, values, selected
119
+ record IDs, sort, and open-detail context across a live resize. Restore focus to the equivalent
120
+ visible control if its representation disappears; do not steal unrelated focus. Track the control
121
+ before hiding it: the browser may move focus to the body before a media-query listener runs.
122
+ A dialog closed after reflow returns to the visible equivalent of its original trigger.
123
+
124
+ Keep search and action bars in normal flow. Stack or wrap ordinary controls before considering a
125
+ scroller; put additional filters behind a working disclosure with active-filter count and reset.
126
+ Use a wrapping group of independent buttons or a select, not a joined `.btn-group` bent over two
127
+ rows. Keep consequential button labels visible. Preserve the current page and previous/next when
128
+ reducing a pager's numbered links.
129
+
130
+ Keep record actions outside a clipped table wrapper when necessary. Popper placement alone does
131
+ not guarantee escape from an overflow ancestor. Prefer a root-mounted dialog or an existing
132
+ portal implementation over z-index escalation.
133
+
134
+ Make touch targets comfortable without making text larger: prefer 44×44 CSS px for primary mobile
135
+ controls; retain the package's 24×24 minimum for every applicable target. Enlarge the actual button
136
+ or associated label, not merely the icon's surrounding decoration. Keep action affordances visible
137
+ without hover. Measure effective label hit areas for native checkboxes and switches.
138
+
139
+ ## Handle navigation and overlays
140
+
141
+ Use `navbar-expand-*` or responsive `offcanvas-*` from the installed build. Match the trigger's
142
+ visibility threshold to the inline panel. Preserve one destination set, a named trigger, current
143
+ state, keyboard operation, Escape, and focus return. Exercise a drawer opened below a threshold,
144
+ resized above it, then returned below; no stale backdrop, body scroll lock, or invisible focus trap
145
+ may remain. Do not assume the host wrapper behaves exactly like the stock plugin.
146
+
147
+ Keep overlay width within the viewport and height content-led with an explicit vertical scroll
148
+ owner. Bootstrap's `modal-fullscreen-*-down` belongs to its modal structure, not a native `<dialog>`.
149
+ For native dialogs, declare a bounded logical size in the stylesheet when needed; keep consequences,
150
+ fields, safe dismissal, and commit reachable on short screens and with enlarged text. Check the
151
+ initial view as well as the scrolled footer. When action focus would hide the beginning, focus a
152
+ static top heading with `tabindex="-1"`; keep a safe dismissal in the tab sequence. Follow the
153
+ [dialog focus guidance](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/).
154
+
155
+ Let nonessential sticky chrome become static on narrow or short screens. Where fixed controls are
156
+ required, reserve their space, account for safe-area insets, and check focus visibility. Use a
157
+ supported dynamic viewport unit only for a genuine viewport-bound requirement; it does not prove
158
+ virtual-keyboard behavior. Test the soft keyboard and browser chrome on a real supported device,
159
+ or leave that coverage open.
160
+
161
+ Keep theme ownership intact during reflow. A dark hero or drawer on a light page establishes its
162
+ foreground/background at its boundary; ordinary descendants inherit. Take adaptive subtle fills
163
+ and exceptions from [color-modes.md](color-modes.md), not a separate mobile palette.
164
+
165
+ ## Prove the result
166
+
167
+ Run [Responsive task and reflow](inspection.md#responsive-task-and-reflow) and
168
+ [Responsive interaction continuity](inspection.md#responsive-interaction-continuity). Check 320 and
169
+ 390 CSS px, one wide view, and `b−1`, `b`, `b+1` for each used breakpoint; deduplicate overlaps.
170
+ Check narrow/short landscape, long unbroken identifiers, expanded copy, enlarged text, and the
171
+ states actually used. Cross light/dark with the important narrow/wide states.
172
+
173
+ Require both geometry and task evidence. A page with no horizontal overflow can still hide its
174
+ primary action, clip a menu, or push decision fields into an undiscoverable scroller. Conversely,
175
+ a valid local two-dimensional scroller is not a page-level reflow failure.
176
+
177
+ Capture narrow output first and inspect it before desktop. Preserve before/after evidence for
178
+ regressions; run known-invalid controls through the same readers. State the Bootstrap build,
179
+ browser, assets, CSS viewport, state, and exclusions. Do not call a screenshot, class scan, reduced
180
+ viewport, device-pixel-ratio change, or emulated touch a real-device or complete accessibility pass.
181
+
182
+ Take upstream behavior from Bootstrap's [breakpoints](https://getbootstrap.com/docs/5.3/layout/breakpoints/),
183
+ [grid](https://getbootstrap.com/docs/5.3/layout/grid/), [flex](https://getbootstrap.com/docs/5.3/utilities/flex/),
184
+ [offcanvas](https://getbootstrap.com/docs/5.3/components/offcanvas/), and
185
+ [tables](https://getbootstrap.com/docs/5.3/content/tables/). Distinguish this package's test matrix
186
+ from the requirements and two-dimensional-content exception in
187
+ [WCAG reflow](https://www.w3.org/WAI/WCAG22/Understanding/reflow.html).