@effect.healthcare/messenger 0.3.1

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.
@@ -0,0 +1,608 @@
1
+ # Workflow
2
+
3
+ This document defines the **workflow policy** for component development. It specifies how implementation proceeds from feature branch creation through to merge — the sequence of commits within a feature, the ordering of concerns across the policy hierarchy, the structure of every commit message, and the conventions that govern the entire development flow.
4
+
5
+ This document is intentionally **workflow** only, but part of a set of implementation policies which together define the policies which should be followed to transform specifications into an implementation which is predictable, maintainable, and production-ready at scale.
6
+
7
+ Testing patterns, unit test structure, and TDD discipline are covered in a separate testing policy.
8
+
9
+ ---
10
+
11
+ # How to Read This Policy
12
+
13
+ Rules in this policy fall into three strengths. Read each rule with its strength in mind:
14
+
15
+ - **Principles** are non-negotiable. They derive from framework correctness or TDD discipline and hold for every component. A conflict with a principle is a defect.
16
+ - **Templates** are invariant skeletons with explicit variation points. The skeleton applies to every component; specific steps activate or deactivate based on the component's declared classification (e.g., attribute-backed vs non-attribute, readonly vs writable, payload-bearing vs payload-free). Variation is part of the template, not a deviation from it.
17
+ - **Conventions** are canonical defaults that keep implementations readable across components. A second component may deviate when its shape genuinely warrants it; the deviation should be explained at review time, not forbidden by the policy.
18
+
19
+ When applying this policy to a new component, classify each rule before reconciling conflicts. A conflict with a principle is a defect; a conflict with a template means a variation point needs to be made explicit; a conflict with a convention is a documented deviation.
20
+
21
+ ---
22
+
23
+ # 1) Every Feature Is Developed on an Isolated Branch
24
+
25
+ Each new feature is developed in isolation on a dedicated feature branch created from main.
26
+
27
+ A feature branch:
28
+
29
+ - is created from the main branch before any work begins
30
+ - contains all commits belonging to a single feature cycle
31
+ - is merged into main via a `FEATURE` commit
32
+
33
+ The `FEATURE` commit is always the last commit on the feature branch. It marks the boundary of the cycle and the merge point back into main.
34
+
35
+ No behavioral work is committed directly to main. Direct commits to main are limited to non-feature concerns such as `PACKAGE`, `TYPES`, post-merge naming corrections, version bumps, or refactors.
36
+
37
+ # 2) Every Commit Must Use a Canonical Prefix
38
+
39
+ Every commit message must begin with a canonical prefix from the following fixed vocabulary:
40
+
41
+ | Prefix | Domain |
42
+ | ---------------- | ------------------------------------------------------------------------------------------------------------- |
43
+ | `COMPOSITION` | DOM structure and cached element references |
44
+ | `STATE` | State contract — metadata, type, enum values, getter, setter, mutation, attribute sync |
45
+ | `VALIDATION` | Input validation — `Validate` class methods and error boundaries (including setter-level invalid-value tests) |
46
+ | `OPERATION` | Public methods — metadata, existence, and behavioral outcome |
47
+ | `EVENT` | Event contract — metadata, setter, handler behavior, and payload |
48
+ | `GESTURE` | Interaction wiring — metadata and behavioral outcome |
49
+ | `DATA` | Component-owned data contract |
50
+ | `STYLE` | CSS rules |
51
+ | `SPECIFICATIONS` | Component specification document |
52
+ | `TESTING` | Test vocabulary corrections |
53
+ | `DOCUMENTATION` | Generated API documentation |
54
+ | `FEATURE` | Feature boundary marker |
55
+ | `PACKAGE` | Package metadata |
56
+ | `CONFIG` | Test and build infrastructure |
57
+ | `TYPES` | TypeScript type definitions independent of runtime behavior |
58
+
59
+ The prefix identifies the concern domain of the commit. It must always be uppercase and must be the first token in the commit message, followed by `: `.
60
+
61
+ Every commit must use exactly one prefix. The `Initial commit` and version-tag commits (e.g. `0.1.0`) are the only permitted exceptions.
62
+
63
+ `CONFIG`, `TYPES`, `TESTING`, and refactor prefixes are reserved for their respective concerns and may not appear in every feature cycle.
64
+
65
+ # 3) Every Behavioral Change Requires a FAIL/PASS Commit Pair
66
+
67
+ Every behavioral change — `COMPOSITION`, `STATE`, `VALIDATION`, `OPERATION`, `EVENT`, `GESTURE`, or `DATA` — must be introduced as a FAIL/PASS commit pair.
68
+
69
+ Structure:
70
+
71
+ - The `FAIL` commit introduces the test that describes the expected behavior. The test must fail at the point of commit.
72
+ - The `PASS` commit introduces the minimum implementation required to make the test pass. The test must pass at the point of commit.
73
+
74
+ Rules:
75
+
76
+ - The `FAIL` commit must precede the `PASS` commit.
77
+ - The `FAIL` and `PASS` commits must always be adjacent — no other commits may appear between them.
78
+ - Every `FAIL` must have a corresponding `PASS`.
79
+ - No behavioral implementation may be committed without a preceding `FAIL` commit.
80
+
81
+ `STYLE`, `SPECIFICATIONS`, `DOCUMENTATION`, `FEATURE`, `PACKAGE`, `CONFIG`, `TYPES`, `TESTING`, and refactor commits do not require a FAIL/PASS pair.
82
+
83
+ # 4) The Feature Development Sequence Is Policy-Ordered
84
+
85
+ Within a behavioral feature, commits must follow this canonical order:
86
+
87
+ ```
88
+ COMPOSITION
89
+ STATE
90
+ VALIDATION
91
+ OPERATION
92
+ EVENT
93
+ STYLE (state-driven)
94
+ GESTURE
95
+ DOCUMENTATION
96
+ FEATURE
97
+ ```
98
+
99
+ This ordering reflects the dependency structure of the implementation. Each layer depends on the layers above it, so work proceeds top-down through the policy hierarchy.
100
+
101
+ `STYLE` for state-driven rules appears after `EVENT` because the visual states it reflects are fully established only once the state and event contracts are in place.
102
+
103
+ `GESTURE` follows state-driven `STYLE` because gesture wiring depends on cached element references, which in turn depend on the composition being final.
104
+
105
+ Deviations from this order are permitted only under the just-in-time rule (see Section 14).
106
+
107
+ # 5) COMPOSITION Commits Follow an Outside-In Structural Order
108
+
109
+ `COMPOSITION` commits introduce structural DOM parts and cached element references.
110
+
111
+ Within a feature, `COMPOSITION` commits must precede all other behavioral commits, except for the cached-reference commit which is placed just-in-time between `GESTURE` metadata and `GESTURE` behavior (see Section 10).
112
+
113
+ Ordering rules:
114
+
115
+ - Container elements are introduced before their children.
116
+ - Parent-child structural relationships use the word `contains` in the commit description.
117
+ - Cached element references are a `COMPOSITION` concern and must use the `COMPOSITION` prefix.
118
+
119
+ Example:
120
+
121
+ ```
122
+ COMPOSITION: `pin.root` contains `div.icon` -> FAIL
123
+ COMPOSITION: `pin.root` contains `div.icon` -> PASS
124
+ COMPOSITION: `div.icon` contains `svg.unpinned` -> FAIL
125
+ COMPOSITION: `div.icon` contains `svg.unpinned` -> PASS
126
+ ```
127
+
128
+ Structural parts are added incrementally across features. Only the parts required by the current feature are introduced in that feature's cycle.
129
+
130
+ # 6) STATE Commits Follow a Fixed Coverage Sequence
131
+
132
+ For each state property introduced in a feature, `STATE` commits must follow this order:
133
+
134
+ 1. **Metadata pair** — `Attributes.X` and `State.X` tested together in one commit
135
+ 2. **Type** — the value-domain type for the state property (e.g. `Visibility`, `Status`)
136
+ 3. **Enum values** — tested in source-declaration order (the order they appear in `<component>.meta.ts`)
137
+ 4. **Getter existence**
138
+ 5. **Default value** — the internal runtime default returned by the getter
139
+ 6. **Attribute default** — only when the attribute is compulsory and always written to the DOM (two commits: `<attribute> attribute exists` and `<attribute> attribute is <default>`)
140
+ 7. **Setter existence**
141
+ 8. **Mutation persists** — setting the value via the setter updates the internal state
142
+ 9. **Null normalization** — only when the setter normalizes `null` to a default value
143
+ 10. **Attribute synchronization (state → attribute)** — setter assignment updates the DOM attribute
144
+ 11. **Attribute synchronization (attribute → state)** — `setAttribute` drives the getter
145
+
146
+ Steps 6 and 9 are conditional:
147
+
148
+ - Include attribute-default only when the attribute is compulsory and always present in the DOM.
149
+ - Include null normalization only when the setter contains normalization logic (`value ?? default`).
150
+
151
+ The validation-boundary commit — `set <component>.<state> to invalid throws error` — is logically a STATE-layer assertion but is committed under the `VALIDATION:` prefix. It appears immediately after the `VALIDATION` method-existence and method-error commits (see Section 7).
152
+
153
+ # 7) VALIDATION Commits Are Placed Between STATE and OPERATION
154
+
155
+ `VALIDATION` commits introduce the `Validate` class methods that enforce input boundaries.
156
+
157
+ Within a feature, `VALIDATION` commits appear after the main body of `STATE` commits and before `OPERATION` commits.
158
+
159
+ The validation block has three commit pairs:
160
+
161
+ 1. `VALIDATION: \`Validate.x\` static method exists`— verifies the method on the`Validate` class
162
+ 2. `VALIDATION: \`Validate.x(value)\` throws error if \`value\` is \`invalid\`` — verifies the validator-level error
163
+ 3. `VALIDATION: set \`pin.x\` to \`invalid\` throws error` — verifies that the setter propagates the validator error
164
+
165
+ The third commit is the setter-level validation boundary. Although it asserts on the STATE setter, it remains conceptually part of the validation contract and uses the `VALIDATION:` prefix.
166
+
167
+ Sequence:
168
+
169
+ ```
170
+ STATE: ... (main body, steps 1-11 excluding the boundary)
171
+ VALIDATION: `Validate.x` static method exists -> FAIL/PASS
172
+ VALIDATION: `Validate.x(value)` throws error if `value` is `invalid` -> FAIL/PASS
173
+ VALIDATION: set `pin.x` to `invalid` throws error -> FAIL/PASS
174
+ OPERATION: ...
175
+ ```
176
+
177
+ # 8) OPERATION Commits Follow a Semantic-Group Batch-Then-Sequence Pattern
178
+
179
+ Operations are grouped semantically — paired operations such as `hide`/`show` or `pin`/`unpin` belong to one group; composite or derived operations such as `toggle` belong to a separate group.
180
+
181
+ For each semantic group:
182
+
183
+ 1. Test all metadata constants for the group first — all `Operation.X exists` commits for the group appear before any method or behavior commit in that group.
184
+ 2. For each operation in the group: method exists → `Invoke` behavior.
185
+
186
+ Behavior commit rules:
187
+
188
+ - Use `Invoke` as the uniform verb for all operation behavior commits.
189
+ - Include a precondition in the commit description when the operation is only semantically meaningful from a specific prior state (e.g., `show` requires the component to already be hidden).
190
+ - Omit the precondition when the operation can be meaningfully called from the default state.
191
+ - When an operation covers a bidirectional transition, state both directions in one commit description using `from X to Y and visa versa`.
192
+
193
+ Example — paired group followed by composite group:
194
+
195
+ ```
196
+ OPERATION: `Operation.PIN` exists -> FAIL/PASS
197
+ OPERATION: `Operation.UNPIN` exists -> FAIL/PASS
198
+ OPERATION: `pin.pin` method exists -> FAIL/PASS
199
+ OPERATION: Invoke `pin.pin` sets `pin.status` to `Status.PINNED` -> FAIL/PASS
200
+ OPERATION: `pin.unpin` method exists -> FAIL/PASS
201
+ OPERATION: Invoke `pin.unpin` when `pin.status` is `Status.PINNED` sets `pin.status` to `Status.UNPINNED` -> FAIL/PASS
202
+ OPERATION: `Operation.TOGGLE` exists -> FAIL/PASS
203
+ OPERATION: `pin.toggle` method exists -> FAIL/PASS
204
+ OPERATION: Invoke `pin.toggle` toggles `pin.status` from `Status.UNPINNED` to `Status.PINNED` and visa versa -> FAIL/PASS
205
+ ```
206
+
207
+ # 9) EVENT Commits Follow a Three-Per-Event Pattern
208
+
209
+ For each semantic event group, `EVENT` commits follow this pattern:
210
+
211
+ 1. Test all event metadata constants for the group first — all `Event.ON_X exists` commits for the group appear before any setter, handler, or payload commit.
212
+ 2. For each event in the group, three behavioral commit pairs:
213
+ - **Setter existence** — `pin.on{x} setter exists`
214
+ - **Handler trigger** — `pin.on{x} listener is called when pin.<state> changes from <Before> to <After>`
215
+ - **Payload contract** — `When pin.on{x} listener is called then it is called with \`{ detail: { ... } }\``
216
+
217
+ Handler-trigger commit rules:
218
+
219
+ - Describe the full state transition using `from X to Y` phrasing.
220
+ - The direction must be explicit in the commit description — the before and after state values must both be named.
221
+
222
+ Example:
223
+
224
+ ```
225
+ EVENT: `Event.ON_HIDE` exists -> FAIL/PASS
226
+ EVENT: `Event.ON_SHOW` exists -> FAIL/PASS
227
+ EVENT: `pin.onhide` setter exists -> FAIL/PASS
228
+ EVENT: `pin.onhide` listener is called when `pin.visibility` changes from `Visibility.VISIBLE` to `Visibility.HIDDEN` -> FAIL/PASS
229
+ EVENT: When `pin.onhide` listener is called then it is called with `{ detail: { visibility: Visibility.HIDDEN } }` -> FAIL/PASS
230
+ EVENT: `pin.onshow` setter exists -> FAIL/PASS
231
+ EVENT: `pin.onshow` listener is called when `pin.visibility` changes from `Visibility.HIDDEN` to `Visibility.VISIBLE` -> FAIL/PASS
232
+ EVENT: When `pin.onshow` listener is called then it is called with `{ detail: { visibility: Visibility.VISIBLE } }` -> FAIL/PASS
233
+ ```
234
+
235
+ # 10) GESTURE Commits Bracket the COMPOSITION Cached Reference
236
+
237
+ `GESTURE` commits introduce interaction wiring.
238
+
239
+ Within a feature, `GESTURE` commits appear after `STYLE` and before `DOCUMENTATION`.
240
+
241
+ The `COMPOSITION` cached element reference commit is placed just-in-time between the gesture metadata commit and the gesture behavior commit — not at the start of the feature cycle — because the cache is the direct prerequisite for listener wiring and not needed before that point.
242
+
243
+ Order:
244
+
245
+ ```
246
+ GESTURE: `Gesture.X` exists -> FAIL/PASS
247
+ COMPOSITION: `pin.elements.x` is a cached reference to the `<element>` with class `<class>` -> FAIL/PASS
248
+ GESTURE: `Gesture.X` on `<element>` with class `<class>` <behavior> -> FAIL/PASS
249
+ ```
250
+
251
+ GESTURE behavior descriptions identify the realized DOM element using selector phrasing (`\`div\` with class \`icon\``), not by the cached reference name. This keeps the commit description aligned with how the test exercises the interaction — by querying the realized DOM.
252
+
253
+ When a gesture behavior covers a bidirectional toggle, both directions are stated in a single behavior commit description using `from X to Y and visa versa`.
254
+
255
+ Example:
256
+
257
+ ```
258
+ GESTURE: `Gesture.CLICK` exists -> FAIL/PASS
259
+ COMPOSITION: `pin.elements.icon` is a cached reference to the `div` with class `icon` -> FAIL/PASS
260
+ GESTURE: `Gesture.CLICK` on `div` with class `icon` toggle `pin.status` from `Status.UNPINNED` to `Status.PINNED` and visa versa -> FAIL/PASS
261
+ ```
262
+
263
+ # 11) STYLE Commits Are Placed at the Point of Visual Readiness
264
+
265
+ `STYLE` commits are placed at the earliest point in the feature cycle where the elements and state they depend on are fully established.
266
+
267
+ Two placement rules apply:
268
+
269
+ - **Base element styles** — styles that apply to DOM elements with no state dependency may be committed immediately after the `COMPOSITION` commits that establish those elements. These can appear before `STATE` commits if the elements already exist.
270
+ - **State-driven styles** — styles whose selectors depend on state attributes (`:host([attribute="value"])`) must appear after all `EVENT` commits for that state, since the full state contract must be in place before its visual representation is added.
271
+
272
+ All `STYLE` commits must appear before `DOCUMENTATION`.
273
+
274
+ `STYLE` commit rules:
275
+
276
+ - `STYLE` commits never have a FAIL/PASS pair.
277
+ - Use `Define` for base element styles — rules with no state dependency that establish a default appearance for a structural part.
278
+ - Use `Add` for state-driven styles, media-query styles, hover/focus styles, and any style that extends an existing visual contract.
279
+ - One selector (or one logically-grouped selector list bound to a single rule) per commit. Complementary visual states (e.g., pinned rules and unpinned rules) are separated into distinct `STYLE` commits.
280
+ - `@media` blocks are committed per rule inside the block — the media query is part of the commit description, not a wrapper around multiple selector commits.
281
+
282
+ Examples:
283
+
284
+ ```
285
+ STYLE: Define `svg` style
286
+ STYLE: Define `.icon` style
287
+ STYLE: Add `:host([visibility="hidden"])` style
288
+ STYLE: Add `:host([status="pinned"]) .icon` style
289
+ STYLE: Add `@media (hover: hover) .icon:hover svg` style
290
+ STYLE: Add `@media (prefers-color-scheme: dark) :host` style
291
+ ```
292
+
293
+ # 12) CSS-Only Features Follow a Collapsed Sequence
294
+
295
+ When a feature introduces only visual changes with no new behavioral contract, it follows a collapsed cycle with no `FAIL/PASS` pairs and no `DOCUMENTATION` commit:
296
+
297
+ ```
298
+ STYLE
299
+ FEATURE
300
+ ```
301
+
302
+ This applies to features whose entire change is within CSS — such as hover responsiveness or dark mode support. No behavioral commit sequence is required.
303
+
304
+ # 13) DOCUMENTATION Closes Every Behavioral Feature
305
+
306
+ After all `FAIL/PASS` pairs and `STYLE` commits are complete, the behavioral feature cycle closes with:
307
+
308
+ ```
309
+ DOCUMENTATION
310
+ FEATURE
311
+ ```
312
+
313
+ Rules:
314
+
315
+ - `DOCUMENTATION` is always generated after implementation is complete. It must not precede any behavioral commits.
316
+ - `FEATURE` follows `DOCUMENTATION`. It is the boundary commit for the branch.
317
+
318
+ # 14) Just-in-Time Addition of Infrastructure and Composition
319
+
320
+ Not all `COMPOSITION` parts and `CONFIG` infrastructure are added at the start of a feature cycle. They are added at the earliest point in the sequence where they become necessary.
321
+
322
+ Rules:
323
+
324
+ - A `CONFIG` commit introducing test infrastructure appears immediately before the first commit that requires it.
325
+ - A `COMPOSITION` commit for a structural part appears at the start of the feature cycle that first requires that part.
326
+ - A `COMPOSITION` cached reference commit appears between `GESTURE` metadata and `GESTURE` behavior — not at the start of the cycle — because the cache is the direct prerequisite for listener wiring.
327
+
328
+ The just-in-time principle avoids speculative additions and keeps every commit traceable to the specific need that drove it.
329
+
330
+ # 15) Commit Messages Must Follow a Canonical Format
331
+
332
+ Every commit message must conform to one of the following formats:
333
+
334
+ **Behavioral commit (FAIL):**
335
+
336
+ ```
337
+ {PREFIX}: {description} -> FAIL
338
+ ```
339
+
340
+ **Behavioral commit (PASS):**
341
+
342
+ ```
343
+ {PREFIX}: {description} -> PASS
344
+ ```
345
+
346
+ **Non-behavioral commit:**
347
+
348
+ ```
349
+ {PREFIX}: {description}
350
+ ```
351
+
352
+ Formatting rules within descriptions:
353
+
354
+ - Code references — types, values, methods, attributes — must be wrapped in backticks.
355
+ - Structural relationships use `contains` as the verb.
356
+ - Operation behavior commits begin with `Invoke`.
357
+ - Event handler behavior commits include `from X to Y` for state transitions.
358
+ - Event payload commits begin with `When ... listener is called then it is called with` followed by the backticked `{ detail: { ... } }` payload.
359
+ - Gesture behavior commits identify the target element by selector phrasing (`\`div\` with class \`icon\``), not by cached reference name.
360
+ - Bidirectional toggle behaviors state both directions: `from X to Y and visa versa`.
361
+ - Preconditions use `when {subject} is {value}` phrasing.
362
+
363
+ # 16) Commit-Message Hygiene Is a Reviewable Concern
364
+
365
+ Commit messages are part of the historical record and must be reviewed with the same discipline as code.
366
+
367
+ Policy:
368
+
369
+ - The `{PREFIX}: ` token must not be omitted from a behavioral commit.
370
+ - State values, event names, and operation names referenced in the description must match the values actually exercised by the test and the implementation.
371
+ - Typos in the feature name (the `FEATURE: ` boundary commit) must be corrected before merge.
372
+ - A commit message that misnames a state value, event handler, or operation is a defect even if the test and implementation are correct.
373
+
374
+ A standalone `TESTING: Update naming convention` commit may be used to correct historical commit-message drift only when the drift is in the test vocabulary itself. Correcting an isolated commit-message typo retroactively is not in scope — the discipline is to catch it before merge.
375
+
376
+ # 17) Naming Convention Corrections Are Standalone Commits
377
+
378
+ When test vocabulary drifts and requires correction, the correction is committed as a standalone `TESTING: Update naming convention` commit.
379
+
380
+ This commit must not be bundled with behavioral changes. It is standalone.
381
+
382
+ # 18) Refactor Commits Use the Domain Prefix
383
+
384
+ When implementation is refactored without changing behavior:
385
+
386
+ - Use the domain prefix of the area being refactored (`STATE: refactor ...`, not a separate `REFACTOR` prefix)
387
+ - Include `refactor` as a verb in the commit message body
388
+ - Do not use a FAIL/PASS pair — behavior does not change under a refactor
389
+
390
+ # 19) Non-Behavioral Prefixes Have Dedicated Scopes
391
+
392
+ Non-behavioral concerns use their own prefixes and are not embedded in behavioral commit sequences:
393
+
394
+ - `SPECIFICATIONS` — Component specification document. Appears at project initialization when the canonical specification is added or when the specification is updated independently of implementation.
395
+ - `TYPES` — TypeScript type changes independent of runtime behavior. May appear post-feature when a type correction is identified after merge.
396
+ - `PACKAGE` — Package metadata. Appears at project initialization or when package configuration changes.
397
+ - `CONFIG` — Test and build infrastructure. Added just-in-time when a new capability is needed.
398
+
399
+ ---
400
+
401
+ # Policy Applied to Specification
402
+
403
+ The Pin component was developed across four feature cycles. The following shows how the workflow policy maps onto each cycle.
404
+
405
+ ## Project Initialization
406
+
407
+ Direct commits to main:
408
+
409
+ ```
410
+ Initial commit
411
+ SPECIFICATIONS: Add `pin.specifications.json`
412
+ PACKAGE: Update package metadata
413
+ DOCUMENTATION: Generate API Docs
414
+ ```
415
+
416
+ ## Feature: Visibility Control
417
+
418
+ Branch: `feature/visibility-control`
419
+
420
+ Behavioral feature — full cycle:
421
+
422
+ ```
423
+ COMPOSITION: `pin.root` contains `div.icon` -> FAIL/PASS
424
+ COMPOSITION: `div.icon` contains `svg.unpinned` -> FAIL/PASS
425
+ STYLE: Define `.icon` style
426
+ STYLE: Define `svg` style
427
+ STATE: `Attributes.VISIBILITY` and `State.VISIBILITY` exists -> FAIL/PASS
428
+ STATE: `Visibility` exists -> FAIL/PASS
429
+ STATE: `Visibility.VISIBLE` exists -> FAIL/PASS
430
+ STATE: `Visibility.HIDDEN` exists -> FAIL/PASS
431
+ STATE: `pin.visibility` getter exists -> FAIL/PASS
432
+ STATE: `pin.visibility` getter returns `Visibility.VISIBLE` -> FAIL/PASS
433
+ STATE: `pin.visibility` setter exists -> FAIL/PASS
434
+ STATE: set `pin.visibility` to `Visibility.HIDDEN` updates state -> FAIL/PASS
435
+ STATE: set `pin.visibility` to `null` updates state to `Visibility.VISIBLE` -> FAIL/PASS
436
+ STATE: set `pin.visibility` to `Visibility.HIDDEN` updates attribute -> FAIL/PASS
437
+ STATE: set `visibility` attribute to `Visibility.HIDDEN` updates state -> FAIL/PASS
438
+ VALIDATION: `Validate.visibility` static method exists -> FAIL/PASS
439
+ VALIDATION: `Validate.visibility(value)` throws error if `value` is `invalid` -> FAIL/PASS
440
+ VALIDATION: set `pin.visibility` to `invalid` throws error -> FAIL/PASS
441
+ OPERATION: `Operation.HIDE` exists -> FAIL/PASS
442
+ OPERATION: `Operation.SHOW` exists -> FAIL/PASS
443
+ OPERATION: `pin.hide` method exists -> FAIL/PASS
444
+ OPERATION: Invoke `pin.hide` sets `pin.visibility` to `Visibility.HIDDEN` -> FAIL/PASS
445
+ OPERATION: `pin.show` method exists -> FAIL/PASS
446
+ OPERATION: Invoke `pin.show` when `pin.visibility` is `Visibility.HIDDEN` sets `pin.visibility` to `Visibility.VISIBLE` -> FAIL/PASS
447
+ EVENT: `Event.ON_HIDE` exists -> FAIL/PASS
448
+ EVENT: `Event.ON_SHOW` exists -> FAIL/PASS
449
+ EVENT: `pin.onhide` setter exists -> FAIL/PASS
450
+ EVENT: `pin.onhide` listener is called when `pin.visibility` changes from `Visibility.VISIBLE` to `Visibility.HIDDEN` -> FAIL/PASS
451
+ EVENT: When `pin.onhide` listener is called then it is called with `{ detail: { visibility: Visibility.HIDDEN } }` -> FAIL/PASS
452
+ EVENT: `pin.onshow` setter exists -> FAIL/PASS
453
+ EVENT: `pin.onshow` listener is called when `pin.visibility` changes from `Visibility.HIDDEN` to `Visibility.VISIBLE` -> FAIL/PASS
454
+ EVENT: When `pin.onshow` listener is called then it is called with `{ detail: { visibility: Visibility.VISIBLE } }` -> FAIL/PASS
455
+ STYLE: Add `:host([visibility="hidden"])` style
456
+ DOCUMENTATION: Generate API Docs
457
+ FEATURE: Visibility Control
458
+ ```
459
+
460
+ How the policy is applied:
461
+
462
+ - `COMPOSITION` parts added outside-in at the start of the cycle
463
+ - Base `STYLE` (`.icon`, `svg`) added just-in-time after the composed elements exist, before `STATE`
464
+ - `STATE` coverage follows the fixed sequence: metadata → type → enum values (source order) → getter → default → setter → mutation → null normalization → state→attribute → attribute→state
465
+ - Enum values tested in source-declaration order: `Visibility.VISIBLE` before `Visibility.HIDDEN`
466
+ - Null normalization included because `visibility` normalizes `null` to `Visibility.VISIBLE`
467
+ - Attribute-default omitted because `visibility` is optional — the attribute is absent when the value is the default
468
+ - `VALIDATION` commits include the method-existence pair, the method-error pair, and the setter-level boundary commit — all under the `VALIDATION:` prefix
469
+ - `OPERATION` metadata (`HIDE`, `SHOW`) batched before any method commits
470
+ - `EVENT` metadata (`ON_HIDE`, `ON_SHOW`) batched before any setter, handler, or payload commits
471
+ - Each event has three behavioral commits: setter existence, handler trigger, payload contract
472
+ - State-driven `STYLE` follows `EVENT`
473
+ - No `GESTURE` in this feature — visibility is controlled imperatively only
474
+ - `DOCUMENTATION` → `FEATURE` close the cycle
475
+
476
+ ## Feature: Pin and Unpin
477
+
478
+ Branch: `feature/pin-unpin`
479
+
480
+ Behavioral feature — full cycle:
481
+
482
+ ```
483
+ COMPOSITION: `div.icon` contains `svg.pinned` -> FAIL/PASS
484
+ STATE: `Attributes.STATUS` and `State.STATUS` exists -> FAIL/PASS
485
+ STATE: `Status` exists -> FAIL/PASS
486
+ STATE: `Status.PINNED` exists -> FAIL/PASS
487
+ STATE: `Status.UNPINNED` exists -> FAIL/PASS
488
+ STATE: `pin.status` getter exists -> FAIL/PASS
489
+ STATE: `pin.status` getter returns `Status.UNPINNED` -> FAIL/PASS
490
+ STATE: `status` attribute exists -> FAIL/PASS
491
+ STATE: `status` attribute is `Status.UNPINNED` -> FAIL/PASS
492
+ STATE: `pin.status` setter exists -> FAIL/PASS
493
+ STATE: set `pin.status` to `Status.PINNED` updates state -> FAIL/PASS
494
+ STATE: set `pin.status` to `Status.PINNED` updates attribute -> FAIL/PASS
495
+ STATE: set `status` attribute to `Status.PINNED` updates state -> FAIL/PASS
496
+ VALIDATION: `Validate.status` static method exists -> FAIL/PASS
497
+ VALIDATION: `Validate.status(value)` throws error if `value` is `invalid` -> FAIL/PASS
498
+ VALIDATION: set `pin.status` to `invalid` throws error -> FAIL/PASS
499
+ OPERATION: `Operation.PIN` exists -> FAIL/PASS
500
+ OPERATION: `Operation.UNPIN` exists -> FAIL/PASS
501
+ OPERATION: `pin.pin` method exists -> FAIL/PASS
502
+ OPERATION: Invoke `pin.pin` sets `pin.status` to `Status.PINNED` -> FAIL/PASS
503
+ OPERATION: `pin.unpin` method exists -> FAIL/PASS
504
+ OPERATION: Invoke `pin.unpin` when `pin.status` is `Status.PINNED` sets `pin.status` to `Status.UNPINNED` -> FAIL/PASS
505
+ OPERATION: `Operation.TOGGLE` exists -> FAIL/PASS
506
+ OPERATION: `pin.toggle` method exists -> FAIL/PASS
507
+ OPERATION: Invoke `pin.toggle` toggles `pin.status` from `Status.UNPINNED` to `Status.PINNED` and visa versa -> FAIL/PASS
508
+ EVENT: `Event.ON_PIN` exists -> FAIL/PASS
509
+ EVENT: `Event.ON_UNPIN` exists -> FAIL/PASS
510
+ EVENT: `pin.onpin` setter exists -> FAIL/PASS
511
+ EVENT: `pin.onpin` listener is called when `pin.status` changes from `Status.UNPINNED` to `Status.PINNED` -> FAIL/PASS
512
+ EVENT: When `pin.onpin` listener is called then it is called with `{ detail: { status: Status.PINNED } }` -> FAIL/PASS
513
+ EVENT: `pin.onunpin` setter exists -> FAIL/PASS
514
+ EVENT: `pin.onunpin` listener is called when `pin.status` changes from `Status.PINNED` to `Status.UNPINNED` -> FAIL/PASS
515
+ EVENT: When `pin.onunpin` listener is called then it is called with `{ detail: { status: Status.UNPINNED } }` -> FAIL/PASS
516
+ STYLE: Add `.unpinned` style
517
+ STYLE: Add `:host([status="unpinned"]) .pinned` style
518
+ STYLE: Add `:host([status="unpinned"]) .unpinned` style
519
+ STYLE: Add `.pinned` style
520
+ STYLE: Add `:host([status="pinned"]) .icon` style
521
+ STYLE: Add `:host([status="pinned"]) .pinned` style
522
+ STYLE: Add `:host([status="pinned"]) .unpinned` style
523
+ GESTURE: `Gesture.CLICK` exists -> FAIL/PASS
524
+ COMPOSITION: `pin.elements.icon` is a cached reference to the `div` with class `icon` -> FAIL/PASS
525
+ GESTURE: `Gesture.CLICK` on `div` with class `icon` toggle `pin.status` from `Status.UNPINNED` to `Status.PINNED` and visa versa -> FAIL/PASS
526
+ DOCUMENTATION: Generate API Docs
527
+ FEATURE: Pin and Unpin
528
+ ```
529
+
530
+ How the policy is applied:
531
+
532
+ - Only the remaining `COMPOSITION` part (`svg.pinned`) is added at the start — just the part this feature requires
533
+ - `STATE` enum values tested in source-declaration order: `Status.PINNED` before `Status.UNPINNED`
534
+ - `STATE` omits null normalization because `status` does not normalize `null`
535
+ - `STATE` includes the attribute-default pair (`status attribute exists`, `status attribute is Status.UNPINNED`) because `status` is compulsory and always written to the DOM
536
+ - `OPERATION` metadata for `PIN` and `UNPIN` batched together before their methods; `TOGGLE` introduced as a separate semantic group with its own metadata-then-method-then-behavior sequence after the paired operations
537
+ - Each event has three behavioral commits: setter existence, handler trigger, payload contract
538
+ - State-driven `STYLE` for pinned/unpinned visual states split per selector — complementary states separated
539
+ - `GESTURE` follows `STYLE`
540
+ - `COMPOSITION` cached reference inserted just-in-time between `GESTURE` metadata and `GESTURE` behavior
541
+ - Gesture behavior commit describes the target by selector (`\`div\` with class \`icon\``)
542
+ - `DOCUMENTATION` → `FEATURE` close the cycle
543
+
544
+ ## Feature: Hover Responsiveness
545
+
546
+ Branch: `feature/hover-responsiveness`
547
+
548
+ CSS-only feature — collapsed cycle:
549
+
550
+ ```
551
+ STYLE: Add `@media (hover: hover) .icon:hover svg` style
552
+ STYLE: Add `@media (hover: hover) :host([status="unpinned"]) .icon:hover` style
553
+ STYLE: Add `@media (hover: hover) :host([status="pinned"]) .icon:hover` style
554
+ FEATURE: Hover Responsiveness
555
+ ```
556
+
557
+ ## Feature: Theme Compatibility
558
+
559
+ Branch: `feature/theme-compatibility`
560
+
561
+ CSS-only feature — collapsed cycle:
562
+
563
+ ```
564
+ STYLE: Add `@media (prefers-color-scheme: dark) :host` style
565
+ FEATURE: Theme Compatibility
566
+ ```
567
+
568
+ ---
569
+
570
+ # Policy Checklist
571
+
572
+ A compliant feature branch must:
573
+
574
+ 1. Be developed on an isolated feature branch created from main.
575
+ 2. Begin every commit message with a canonical prefix from the defined vocabulary (with the sole exceptions of `Initial commit` and version-tag commits).
576
+ 3. Use exactly one prefix per commit.
577
+ 4. Introduce every behavioral change as a FAIL/PASS commit pair.
578
+ 5. Place the FAIL commit immediately before its PASS commit with no commits between them.
579
+ 6. Follow the policy-ordered development sequence: `COMPOSITION → STATE → VALIDATION → OPERATION → EVENT → STYLE → GESTURE → DOCUMENTATION → FEATURE`.
580
+ 7. Test `COMPOSITION` parts in outside-in structural order using `contains` in the description.
581
+ 8. Introduce only the `COMPOSITION` parts required by the current feature.
582
+ 9. Follow the fixed coverage sequence for each `STATE` property: metadata → type → enum values (source-declaration order) → getter → default → [attribute default] → setter → mutation → [null normalization] → state→attribute sync → attribute→state sync.
583
+ 10. Include attribute-default `STATE` tests only when the attribute is compulsory.
584
+ 11. Include null-normalization `STATE` tests only when the setter contains normalization logic.
585
+ 12. Use the verb `updates state` and `updates attribute` for mutation and sync commits — not `persists` or `sets`.
586
+ 13. Place `VALIDATION` commits after the `STATE` body and before `OPERATION`. Include three pairs: method existence, method error, and setter-level boundary — all under the `VALIDATION:` prefix.
587
+ 14. Batch `OPERATION` metadata constants per semantic group, before any method or behavior commits in that group. Composite operations such as `toggle` form their own semantic group.
588
+ 15. Use `Invoke` as the uniform verb for all `OPERATION` behavior commits.
589
+ 16. Include a precondition in `OPERATION` behavior commits only when the operation requires a specific prior state.
590
+ 17. Use `from X to Y and visa versa` for bidirectional `OPERATION` and `GESTURE` behavior commits.
591
+ 18. Batch `EVENT` metadata constants per semantic group, before any setter, handler, or payload commits in that group.
592
+ 19. Use three commits per event: setter existence, handler trigger (`listener is called when ... changes from X to Y`), and payload (`When ... listener is called then it is called with ...`).
593
+ 20. Place state-driven `STYLE` commits after `EVENT` and before `GESTURE`.
594
+ 21. Place base element `STYLE` commits just-in-time after the `COMPOSITION` parts they apply to are established.
595
+ 22. Use `Define` for base element styles and `Add` for state-driven, gesture-driven, media-query, and extension styles.
596
+ 23. Commit one selector per `STYLE` commit. Separate complementary visual states into distinct `STYLE` commits.
597
+ 24. Place the `COMPOSITION` cached reference commit between `GESTURE` metadata and `GESTURE` behavior.
598
+ 25. Describe `GESTURE` behavior targets by selector phrasing (`\`div\` with class \`icon\``), not by cached reference name.
599
+ 26. Close every behavioral feature with `DOCUMENTATION → FEATURE`.
600
+ 27. Follow the collapsed cycle (`STYLE → FEATURE`) for CSS-only features.
601
+ 28. Use the `FEATURE` commit only as a boundary marker — no new behavior, tests, or styles.
602
+ 29. Add `CONFIG` and `COMPOSITION` parts just-in-time at the earliest point they are needed.
603
+ 30. Wrap all code references in backticks in commit message descriptions.
604
+ 31. Commit test naming convention corrections as standalone `TESTING: Update naming convention` commits, never bundled with behavioral changes.
605
+ 32. Use the domain prefix for refactor commits with `refactor` in the message body; do not use a FAIL/PASS pair.
606
+ 33. Use `SPECIFICATIONS` for component specification commits.
607
+ 34. Use `TYPES` for TypeScript type changes independent of runtime behavior.
608
+ 35. Verify every commit message before pushing — prefix present, code references backticked, state values and event names correct, no typos in the feature name.
@@ -0,0 +1,11 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__chrome-devtools__navigate_page",
5
+ "mcp__chrome-devtools__list_network_requests",
6
+ "mcp__wallaby__wallaby_failingTests",
7
+ "Bash(git add *)",
8
+ "Bash(git commit *)"
9
+ ]
10
+ }
11
+ }
package/.mcp.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "chrome-devtools": {
4
+ "command": "npx",
5
+ "args": ["-y", "chrome-devtools-mcp@latest"]
6
+ },
7
+ "wallaby": {
8
+ "command": "powershell.exe",
9
+ "args": ["node", "$Env:USERPROFILE/.wallaby/mcp/"]
10
+ }
11
+ }
12
+ }