You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/audit/SUMMARY.md

347 lines
28 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Audit Summary — rolling
summary-version: 8 — AUDIT COMPLETE
updated-at: 2026-06-26
batches-complete: 8 of 8 — **124/124 components audited** (words/palabras/chronos excluded per user directive)
(B1 overlays · B2 menus/overlays · B3 pickers+calendar · B4 fields · B5 collections+data · B6 disclosure+controls ·
B7 actions+feedback+misc · B8 eidos-only primitives: layout/typography/visual/composite+service/infra)
## Counts by severity (FINAL — cumulative B1..B8)
| Severity | B1 | B2 | B3 | B4 | B5 | B6 | B7 | B8 | TOTAL |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| CRITICAL | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | **0** |
| HIGH | 8 | 2 | 0 | 0 | 6 | 1 | 1 | 0 | **18** |
| MEDIUM | 17 | 23 | 21 | 22 | 14 | 11 | 18 | 3 | **129** |
| LOW | 5 | 17 | 11 | 5 | 2 | 5 | 3 | 12 | **60** |
## Final verdict
**The framework is in strong shape. 0 CRITICAL, 18 HIGH across 124 components — and the HIGH findings cluster into a
handful of systemic patterns with shared, mechanical fixes, not scattered one-offs.** The single highest-leverage fix is
**SYS-7** (the A31 O(N²) selection pattern: 9 components, 6 of them HIGH, one ~3-line `selectedSet`/`expandedSet` lift
each). After that it is mostly MEDIUM hygiene: **SYS-1 scope-drift** (~33 components, one definitional decision),
**THEME-SYS-1** (overlay z-index ladder, ~10 recipes, one tokenization sweep), and the smaller systemic patterns below.
The non-A31 HIGH findings are isolated and each well-grounded:
- **dialog-001** — Content `role`/`aria-roledescription` double-write (a11y race for `alertdialog` variant).
- **dialog-002** — dead/conflicting `[data-dialog-trigger]` CSS envelope after the Button migration.
- **combobox-001** — virtual+real focus mix (A17 / APG break).
- **select-001/002/003** — querySelector injection · `focus.trap` declared-not-implemented · keyboard-route divergence.
- **alert-dialog-001** — the only `: Morfo` annotation (degrades `createAttrs`).
- **navigation-menu-006** — an undisposed `$effect.root` (bounded leak).
- **collapsible-NEW-001** — `collapse` `sequence:'pre'` + handler-state (the Checkbox-244ms-lag mechanism).
- **breadcrumb-001** — `archetype:'item'` false-affordance on a display `<li>` (the bug Timeline explicitly avoided).
**Method honesty (recorded throughout):** every HIGH/CRITICAL was lead-verified against the cited source. The
adversarial-verify stage repeatedly earned its keep — it refuted a false CRITICAL (eidos-imports-soma on onion-menu), a
false HIGH (button archetype, inert because the part isn't runtime-registered), every CSS.escape-on-framework-value
HIGH/CRITICAL (grid selectors), and the non-canonical-role flags (content-color slots, not the 9 roles). The lead's own
independent greps caught real defects the agents missed (the A31 cluster pre-confirmed) AND made one error of its own
(a single-line grep wrongly cleared the field-family A30, which the workflow caught) — no single source was infallible;
the cross-check (grep × agent × verify × lead read) is what produced the verdict. The lead also corrected the verify in
both directions: elevated under-rated findings (range-calendar Home/End → systemic; collapsible seq-lag MEDIUM→HIGH) and
downgraded over-rated ones (tag-group rovingTarget HIGH→LOW; many magic-literals).
**Positive references (cite these when building/reviewing):** NumberField (renderProps + direct id-wiring + A13),
Popover (Close-via-Button, no role override, hover guards), DropdownMenu (roving-focus consistency, self-managed cleanup,
eidos-in-scope), Button (clean action recipe), Dialog's `data-color` subset (neutral/risk/threat), Timeline (correctly
omits `archetype:'item'`), VirtualList (SvelteMap), accordion + tabs (fully clean). The eidos theming layer is clean
(roles/variants/sizes/naming all canonical across 124 components).
## Counts by severity (per batch, historical)
> **B7 result:** the action/feedback layer is healthy. The two documented reactivity incidents **stayed fixed**:
> Toolbar A35 (`isTabStop` uses `untrack`, the counter was removed) and Form A36 (`form-core.svelte.ts:262
> return untrack(...)`) — both lead-verified, both REFUTED when an agent re-raised them. Timers route through
> `uix.timers` (toast/clipboard/drag-drop) → no A6 leaks. **Button is CLEAN — the reference action component** (its
> one archetype finding was inert: the Spinner part isn't runtime-registered, so `data-archetype` never reaches the
> DOM — the verify caught the false premise). The one real HIGH: **breadcrumb-001** — the Item part (a display `<li>`)
> declares `archetype:'item'` AND is runtime-registered (provider:123), so `data-archetype='item'` IS emitted and
> archetypes.css paints it with `cursor:pointer` + hover (a false affordance on a non-clickable container). The
> insight: **Timeline explicitly avoided this** (its morfo comments "no archetype:'item' — a display `<li>` omits it");
> breadcrumb didn't. A targeted, lead-verified contract bug — not systemic, but a clean example of the archetype-pull
> anti-pattern one sibling fixed and the other didn't.
> **B6 result:** the disclosure/selection controls are well-built — accordion + tabs are fully CLEAN, the sequence
> doctrine is correctly applied everywhere it was checked (checkbox/toggle/switch = `post`; accordion/tabs/radio-group/
> stepper set state at the call-site so `pre` is fine), slider has no gesture A6 leak. ONE real HIGH: **collapsible's
> `collapse` event is `sequence:'pre'` while setting state in the handler** — the verifier traced the runtime and
> proved it serializes (emit-then-handler), so `open=false` lags the full ~240ms `brief` hold (the same mechanism as
> the documented Checkbox 244ms-lag). The analyze agent AND the morfo's own comment marked it clean on a false
> "emit overlaps handler" assumption. **Lead note:** I initially downgraded it to MEDIUM ("it's the canonical
> emerge.dismiss `pre`") then RESTORED it to HIGH after re-reading — dialog masks the hold with a `data-event`/Presence
> exit animation, but collapsible's exit is keyed on the (delayed) `data-state`, so the 240ms is a real dead delay.
> Verifying the adversarial-verify's own catch corrected me — the cross-check cuts both ways.
> **B5 result:** the collections are where the **A31 O(N²) selection pattern lives** — 6 HIGH, all the SAME root
> cause: a per-item `$derived` calling `provider.isSelected(v)` / `provider.isExpanded(v)` that does `.includes()`
> on the global array (listbox, grid-list ×2, tree-view, tree-grid, tag-group). **All 6 lead-verified by direct read
> of the cited `.includes` method bodies** (matches an independent lead grep run before the workflow). SYS-7 now
> spans 7 components with ONE shared fix. The verify did its job: it refuted feed's A31 (per-item derived doesn't read
> global state), downgraded table's (engine-backed by `$libs/datagrid`), and confirmed virtual-list/grid as
> A33-clean (SvelteMap). The lead refuted one verifier-ADDED HIGH (tag-group-004 "rovingTarget A31") — `rovingTargetEl`
> is already LIFTED to a single provider `$derived` and the per-item check is an O(1) pointer compare; downgraded to a
> LOW A18 nit. Even verifier-added findings get verified.
> **B4 result:** the field family is healthy — **zero HIGH survived verification.** Dominated by SYS-1 scope-drift
> (nearly all 14), test gaps, a new systemic A30-doctrine deviation, and label-font/magic-literal nits. NumberField
> is confirmed the clean **reference** (correct renderProps + direct id-wiring + A13 hidden input). The analyze pass
> over-reported: the `field` agent emitted 6 "clean-check" pseudo-findings (impact = "no fix needed"); the verify
> refuted all 6, and the generator drops clean-checks. **Method-honesty note:** the lead's own independent grep for
> A30 violations used a single-line pattern and WRONGLY concluded "field family A30-clean"; the workflow's
> analyze+verify caught the multi-line `$effect` that the grep missed (SYS-A30-EFFECT below). No single source —
> grep, agent, verify, or lead — is infallible; the cross-check is what produced truth.
> **B3 result:** the picker + calendar family is in good shape — **zero HIGH survived verification** (the analyze
> pass raised 2 CRITICAL + several HIGH; all were CSS.escape-on-numeric/ISO-selectors or local-z-index, correctly
> downgraded to LOW, plus one keyboard-label drift the lead elevated to a systemic MEDIUM). The dominant B3 issues
> are SYS-1 scope-drift (all 10), inert `open`/`commit-reset` events (pickers), magic literals, and jsdom-only tests.
> Method note: the lead's own memory ("pickers don't fire close events") was STALE — an independent grep proved each
> picker now fires `trigger('close')`; the inert-events findings are about `open`/`commit-reset`, which the verify +
> grep agree ARE inert. Verifying against current code, not memory, mattered.
> **Method note (B2):** Batch 2 was run as an adversarially-verified workflow (one analyze agent per component →
> a skeptical verify agent that re-reads the cited code). The verify stage refuted/downgraded a large fraction of
> the analyze pass's claims (it caught a false-positive CRITICAL on onion-menu — "eidos imports soma" is the normal
> direction, not a frontier violation — and a false-positive HIGH A30 on context-menu). **Both surviving B2 HIGH
> findings were personally re-verified against the cited source by the lead before shipping.** This validates the
> standing rule "unverified agent finding = not a finding": the raw analyze pass over-reported ~15 HIGHs that
> collapsed to 2 after verification.
### B2 HIGH findings (both lead-verified)
- **alert-dialog-001 (HIGH, A)** — `export const alertDialogMorfo: Morfo = {…}` uses a `: Morfo` annotation instead
of `as const satisfies Morfo`; this widens literal types and degrades `createAttrs`/`compileMorfo` key narrowing.
The ONLY morfo in the audited set with this defect. (Lead-verified: alert-dialog.ts:4.)
- **navigation-menu-006 (HIGH, B/A6)** — `openedAtEffect = $effect.root(() => { $effect(() => …) })` (provider:523)
is a DETACHED reactive root whose disposer is stored but never called; each NavigationMenuTriggerProvider leaks one
root permanently subscribed to `isOpen`. A bare `$effect` (auto-disposed) is the correct tool. (Lead-verified: the
only `$effect.root` in any provider; no dispose anywhere in the file.)
## Counts by severity (Batch 1)
| Severity | Count |
| --- | --- |
| CRITICAL | 0 |
| HIGH | 8 |
| MEDIUM | 17 |
| LOW | 5 |
| **total** | **30** |
## Counts by component
| Component | C | H | M | L | headline |
| --- | --- | --- | --- | --- | --- |
| select | 0 | 4 | 5 | 2 | injection, focus.trap-unimpl, kbd-route divergence, kbd untested |
| dialog | 0 | 2 | 2 | 2 | role double-write (alertdialog race), dead trigger envelope |
| popover | 0 | 0 | 3 | 0 | cleanest — close double-write, magic-z, test gap |
| combobox | 0 | 2 | 3 | 0 | virtual+real focus mix (A17), kbd untested |
| dropdown-menu | 0 | 0 | 4 | 1 | most disciplined — nav dup, checkbox silent, magic-z |
## Counts by dimension (findings tagged with each)
| Dim | What | Count |
| --- | --- | --- |
| A (contract) | scope-drift, undeclared parts, aria-not-in-morfo, translationRef, checkbox silent, virtual-part data | 8 |
| B (behavior) | focus mix, kbd-route divergence, A31, loop off-by, sequence | 7 |
| C (selectors) | querySelector injection | 1 |
| D (frontier) | double-writes, dead trigger envelope, undeclared parts | 5 |
| E (TSC) | 0 (TSC usage was clean where present) | 0 |
| E-bis (theming) | magic z-index, em-font literal, magic opacity, raw rem, subset | 9 |
| F (tests) | jsdom-only + keyboard/focus/dismissal untested | 5 |
| G (redundancy) | directional-nav duplication | 2 |
## Top findings by impact
1. **combobox-001 (HIGH)** — Combobox mixes virtual focus (`aria-activedescendant`) with real `dom.focus()` on
items; violates A17 and the APG combobox contract (focus must stay on the textbox).
2. **dialog-001 (HIGH)** — Dialog Content double-writes `role` (syncAttrs `'dialog'` vs Svelte `variant`); for
`variant='alertdialog'` the accessible role is a non-deterministic race.
3. **select-001 (HIGH)** — `scrollSelectedIntoView` interpolates the user value into a `querySelector` without
`CSS.escape` (the safe helper it imports does escape — this path bypasses it).
4. **select-002 (HIGH)** — morfo declares `focus.trap:true` + `initial:'first-focusable'` but the provider
implements virtual focus (no FocusScope) — dead/contradictory contract.
5. **select-003 (HIGH)** — two keyboard routes (virtual trigger vs real-focus content) duplicate index math and
diverge; the content loop path lands `n-2` (off-by) and reads `activeElement` though the component is virtual.
6. **dialog-002 (HIGH)** — `[data-dialog-trigger]` full-chrome CSS envelope survives the trigger's migration to
a composed `<Button>`; both recipes paint the same element (order-dependent).
7. **SYSTEMIC: MAGIC-Z (5/5)** — see systemic #2.
8. **SYSTEMIC: JSDOM + keyboard/focus untested (5/5)** — see systemic #3.
9. **SYSTEMIC: SCOPE-DRIFT (4/5)** — see systemic #1.
10. **SYSTEMIC: DIRECTIONAL-NAV duplication (3+ components, 4+ copies)** — see systemic #4 + SHARED_EXTRACTION.
## Systemic issues (recur in ≥3 components → one structural fix each)
### SYS-1 · SCOPE-DRIFT — eidos recipe exists but morfo `scope` omits `'eidos'` <!-- id: SYS-001 -->
- components: select, dialog, popover, combobox (4/5). dropdown-menu CORRECTLY declares `['soma','sema','eidos']`.
- evidence: each has a full `eidos/components/{c}/` recipe + wrapper, yet `scope: ['soma','sema']`.
- why it matters: `scope` is documented (glossary) as "which layers implement the component"; the 2-of-3 rule
and tooling key off it. An inconsistent scope makes "which components have eidos" unanswerable from the morfo.
- one fix: decide the semantics (does `scope` list authored layers or all consuming layers?) and make it
consistent — either add `'eidos'` everywhere an eidos recipe exists, or document that eidos is implicit and
`scope` lists only soma/sema. Affects ~40+ interactive components beyond Batch 1.
- resolution: `scope` lists IMPLEMENTING layers; added `'eidos'` to all 62 drifted morfos (scope-drift now 0).
Regression guard added in `contracts.test.ts` ("…declares 'eidos' in morfo scope (SYS-1)") — fails if any
maintained component ships an eidos recipe without `'eidos'` in scope (proven to catch drift; dev-track excluded).
- fix-status: fixed (212624e0)
### SYS-2 · MAGIC-Z — overlay `content-z`/`overlay-z` are hardcoded integers <!-- id: SYS-002 -->
- components: select (80), dialog (70 + content calc+1), popover (75 / overlay 60), combobox (80),
dropdown-menu (80). **5/5.**
- evidence: `lib/recipes/base.ts` per-recipe integer z values; no `--z-index-*` overlay ladder consumed.
- why it matters: overlay stacking is inherently cross-component; scattered integers (60/70/75/80) can't be
coordinated or reasoned about, and a new overlay just guesses a number.
- one fix: define a canonical overlay z-ladder (`--z-index-{popover,menu,modal,...}`) and map every overlay
recipe to it in one sweep. (THEMING §35 Bloque C already mandates this for "magic z-index".)
- fix-status: open
### SYS-3 · TEST-FIDELITY — interaction-heavy overlays tested jsdom-only, keyboard/focus/dismissal unpinned <!-- id: SYS-003 -->
- components: all 5. select + combobox HIGH (the focus bugs live exactly in the untested paths); dialog,
popover, dropdown-menu MEDIUM.
- evidence: every `*-provider.svelte.test.ts` is `@vitest-environment jsdom` and asserts selection/open-close
logic; none exercise the directional-nav index math, typeahead, dismissal trigger-exclusion, focus
trap/return, or aria-activedescendant sync. jsdom can't validate focus/layout/hydration.
- why it matters: the highest-risk behaviors (and several of the HIGH defects above) would ship green.
- one fix: (a) add provider unit tests for the keyboard routes + dismissal exclusion; (b) add a client/
Playwright project test per focus-bearing overlay asserting focus return + activedescendant/roving invariants.
- fix-status: open
### SYS-4 · DIRECTIONAL-NAV duplication (+ shared loop off-by) <!-- id: SYS-004 -->
- components: select (content route), combobox (content), dropdown-menu (content + sub-content). 4+ copies.
- evidence: identical next/prev/Home/End index math; the `currentIndex===-1` + prev + loop branch computes
`n-2` (off-by) in select-003 and dropdown-menu-001.
- one fix: a pure `nextIndex(curr, key, len, {loop, dir, orientation})` helper, unit-tested once. See
SHARED_EXTRACTION DIRECTIONAL-NAV.
- fix-status: open
### SYS-5 · SYNCATTRS + MANUAL DOUBLE-WRITE <!-- id: SYS-005 -->
- components: dialog (role/aria-roledescription — HIGH, live race), popover (Close type/aria-label — MEDIUM,
benign-valued). 2/5 so far; likely more downstream.
- evidence: a part registered `syncAttrs: true` (runtime writes the morfo attrs via `dom.apply`) AND the props
block re-sets a morfo-declared attr → two authorities (active_architecture §7.7).
- one fix: a lint that flags `syncAttrs:true` parts whose `props` block keys intersect morfo-declared
attrs (role/aria-*/type). See VALIDATOR_GAPS. Per-component: drop the manual re-set or switch to
`renderProps()` + single override.
- fix-status: open
### SYS-6 · UNDECLARED-EIDOS-PARTS — recipe styles `data-{c}-{part}` absent from the morfo <!-- id: SYS-006 -->
- components: select (`indicator`, `item-indicator`), dialog (`header`, `footer` — acknowledged). 2/5 so far.
- evidence: CSS selectors on parts with no morfo entry (decorative/layout). eidos-lint would classify them
eidos-only/invalid.
- one fix: a project convention for eidos-only parts — declare them `kind:'internal'` in the morfo OR a
documented per-recipe allow-list — applied uniformly.
- fix-status: open
### SYS-7 · A31 O(N²) — per-item `isSelected`/`isExpanded` `.includes` on the global array <!-- id: SYS-007 -->
- **components (9, lead-verified):** select-007 (M), combobox-004 (M) [B1] + listbox-001, grid-list-001/002,
tree-view-002, tree-grid-001, tag-group-001 (HIGH) [B5] + **toggle-group-001 (M), checkbox-001 (M, via CheckboxGroup)**
[B6]. Each has a per-item `$derived` calling a provider method (`isSelected`/`isExpanded`/`isItemPressed`/`isItemChecked`)
that does `array.includes(v)` — O(K) per item × N items on every mutation = O(N²). Lead-confirmed by reading the exact
method bodies: listbox:157, grid-list:151, tree-view:96-97/146, tree-grid:148/189, tag-group:116, toggle-group:72,
checkbox:313, select:158, combobox:182. (radio-group is CLEAN — single-value `===`, not `.includes`.)
- **severity split (legitimate):** select/combobox are usually small single-select (K≤1) → MEDIUM; the collections are
large multi-select / many-expanded (the documented "hangs at 30+" case) → HIGH. The *root cause and fix are identical.*
- **the proof it's a miss, not a design choice:** these providers ALREADY lift `rovingTargetEl` to ONE Set-backed
provider `$derived` (with comments citing "avoids an O(N²) cascade") — but left the sibling `isSelected` calling the
O(N) method per-item. The asymmetry is the tell.
- **one structural fix:** a provider-level `readonly selectedSet = $derived(new SvelteSet(opts.value.current))` (and
`expandedSet` for trees); `isSelected`/`isExpanded` consult `.has()` (O(1)). ~2 lines per component. See
SHARED_EXTRACTION EX-3 (now the highest-value extraction in the audit).
- fix-status: open
### SYS-A33-CLONE · Reactive-collection clone-and-reassign instead of SvelteMap/Set <!-- id: SYS-008 -->
- components (B5): listbox, grid-list, tree-grid, tag-group use the `this.x = new Map(this.x)` clone-and-reassign
workaround for a registry/cache; combobox previously did (now fixed). It IS reactive (field reassignment tracks) but
O(N) per mutation + fragile (breaks silently if refactored to `.set()` direct) — A33 says rewrite to SvelteMap.
virtual-list is the positive model (4× SvelteMap). No plain `$state(new Map/Set)` anywhere in B5 (the dangerous form).
- one fix: migrate the four clone-reassign sites to `SvelteMap`/`SvelteSet` (O(1) `.set`, no clone). MEDIUM.
- fix-status: open
## Batch-2 systemic confirmations + corrections
- **SYS-1 (scope-drift) — heavily confirmed.** B2 adds menubar, navigation-menu, drawer, command, link-preview,
float-panel, menu-dial (7 more) → ~11 components confirmed; tooltip/context-menu/alert-dialog/onion-menu correctly
declare or don't need eidos-in-scope. Now the dominant contract-consistency issue. Severity normalized to MEDIUM
per-component (it's an informational drift, no user-visible effect) — the fix is the one structural SYS-1 decision.
- **SYS-2 (magic-z) — confirmed + made authoritative.** B2 adds tooltip `content-z:76`, drawer `overlay-z:72`/
`inline-z:64`, link-preview `preview-z:99`. Lead independently verified the canonical scale `STATIC_Z_INDEX`
(base 0 · raised 1 · sticky 100 · dropdown 300 · popover 400 · tooltip 500 · modal 700 · toast 900) EXISTS and is
consumed by the depth planes + **menu-dial** (`var(--z-index-sticky)`). So the overlay recipes hardcode an ad-hoc
parallel 60–99/1200 scale whose ordering doesn't even match canon. The token they should use exists. See
THEMING_COHERENCE THEME-SYS-1 for the precise per-component mapping.
- **SYS-3 (test fidelity) — confirmed across all 11.** Every B2 component is jsdom/node-unit only; the keyboard/
focus/dismissal hard paths are untested. menu-dial/onion-menu test only the pure nav math (correct as far as it
goes) but never the focus/two-moments integration.
- **SYS-4 (directional-nav off-by) — PARTIALLY DISPROVEN (important correction).** The `currentIndex===-1 + prev +
loop → n-2` off-by is NOT universal: navigation-menu's loop math is CORRECT (modulo `(i+1)%n`/`(i-1+n)%n` WITH a
`currentIndex===-1` early-return guard, verified at provider:325/336-345). The off-by is specific to Select's and
DropdownMenu's content routes, which lack that guard. The shared-helper opportunity (EX-1) stands, but the BUG is
narrower than B1 implied — fix select/dropdown, don't assume every menu has it.
- **SYS-5 (syncAttrs double-write) — one more (drawer-007, MEDIUM).** Drawer Content manually sets `role:'dialog'`
+ `aria-modal` which the morfo declares; benign value (role constant) so MEDIUM, not the HIGH dialog-001 race.
- **SYS-6 (undeclared eidos parts) — mostly REFUTED in B2.** The B2 analyze pass flagged data-size/data-depth/
data-floating-gap as "undeclared parts" on menubar/navigation-menu/float-panel; the verify stage refuted these —
they are eidos-owned VISUAL data-attrs (the sanctioned `data-{prop}` pattern, like Dialog's data-size), not
morfo parts. SYS-6 remains valid only for genuine decorative *parts* (select indicator, dialog header/footer).
## Batch-3 systemic confirmations + new patterns
- **SYS-1 (scope-drift) — now ~21 components.** All 10 B3 components hit it (incl. the pickers and calendar,
range-calendar nominally includes eidos in scope but its recipe entry is thin). It is the single most pervasive
finding in the whole audit. The fix is one decision (does `scope` enumerate authored layers or all consumers?).
- **SYS-INERT (NEW) — pickers declare events the provider never fires.** date-picker/date-range-picker/time-picker/
time-range-picker/color-picker each declare an `open` event and a `commit-reset` event in the morfo that the
provider NEVER triggers (it only fires `close` + the field/area events). Lead-verified by grep: each picker
provider calls `trigger('close')` (1×; color-picker 7× incl. commit-set/handle-*) but never `trigger('open')`/
`trigger('commit-reset')`. The events exist only to satisfy the schema validator — a 2-of-3 / contract-honesty
gap (MEDIUM). Fix: either fire them (perceptual signal on open / on clear) or drop them from the morfo.
- **SYS-CAL-HOMEEND (NEW) — calendar + range-calendar Home/End label vs behavior.** The morfo declares the Home/End
actions as `first/last-day-of-week` but both providers implement `start/end-of-month`. Either an APG deviation
(WAI-ARIA Date Picker Dialog: Home/End move within the WEEK) or a stale label. 2 components (MEDIUM, lead-elevated
from the verify's LOW because shared-ness = systemic).
- **CSS.escape-on-grid-selectors — a consistent LOW class, not a bug.** calendar/month-grid/year-grid interpolate
framework-derived NUMERIC (month 1..12, year arithmetic) or ISO (`DateValue.toString()`) values into
`querySelector` without `CSS.escape`. The analyze pass over-rated these HIGH/CRITICAL; verification correctly
downgraded ALL to LOW (the values provably cannot contain CSS metacharacters). A defense-in-depth nicety to add
uniformly, never a user-hittable defect. (Contrast Select's user-VALUE interpolation, select-001, which is real.)
- **THEME-SYS-2 (magic opacity) extended** — calendar `day-outside-opacity 0.62` (off the 0.05-step `--opacity-*`
scale; the same `0.62`/`62%` recurs as overlay-opacity in dialog/drawer). See THEMING_COHERENCE.
## Batch-4 systemic confirmations + new patterns
- **SYS-A30-EFFECT (NEW) — segmented fields register `inputId` via `$effect`, not direct assignment.** date-field
(provider:932-936), time-field (531-535), color-field (521-525) wrap the `field.inputId.current = opts.id.current`
registration in a `$effect`; the reference NumberField (585-587) does it as a direct constructor guard. Lead-verified
in all four. No live loop (the child only WRITES inputId, never reads it; `opts.id` is stable) — so it is an A30
*doctrine* deviation (MEDIUM), not a freeze. But it is exactly the shape A30 warns about; a future two-way change
reintroduces the freeze. One fix: make all three match NumberField's direct assignment. (Note: the date-field +
color-field agents both listed "A30/Behavior" as a no-findings dimension — they MISSED their own `$effect`; only
time-field's agent caught it; the lead added the twins.)
- **SYS-1 (scope-drift) — nearly universal in the field family** (field, date/time/date-range/time-range/color/css/
search/password-field, pin-input, textarea, tags-input, editable). Now the audit's single most pervasive finding
across ~33 components. The verify even noted the project's own reference (NumberField) shares the condition — so the
one SYS-1 decision must also settle whether NumberField/field "count".
- **SYS-3 (test gaps) — the segmented fields under-test their hardest paths**: every B4 test is jsdom-only and none
exercise the A24 readonly-without-value `logger.warn` (trivial to assert — the harness already stubs `warn`), the
hidden-input render, the commit events, or APG segment keyboard. password-field + textarea have NO provider test.
- **CLEAN REFERENCE confirmed — NumberField.** Correct renderProps (no double-write), direct id-wiring (A30), A13
hidden input, all declared events actually fired. Use it as the field-family template (and the contrast that makes
SYS-A30-EFFECT visible).
- **A26 / A13 — verified PRESENT, no findings.** Lead grep + agents + verify agree: date/time/color-field have
`onbeforeinput`; the range fields inherit it by composing the single-field Input (A27); number/color/css/tags/pin
all render the A13 hidden input. The analyze pass's tentative "missing A26/A13" angles were refuted.
## New validator-gap findings from B2 (see VALIDATOR_GAPS)
- **VG-8** — `morfo:check` does NOT flag a morfo declared with `: Morfo` instead of `as const satisfies Morfo`
(alert-dialog-001 shipped). The single highest-leverage cheap fix: a lint that greps every `*Morfo` export for
the `as const satisfies Morfo` closer.
- **VG-9** — nothing flags an undisposed `$effect.root` in a provider (navigation-menu-006). A lint: `$effect.root`
outside a test whose returned disposer isn't wired into a teardown.
## Notes
- No CRITICAL across 16 components (the one CRITICAL the B2 agents raised was a false positive, refuted).
- Two B1 HIGH a11y correctness issues (combobox-001 focus mix, dialog-001 role race) remain the most user-impactful;
the B2 HIGHs are contract (alert-dialog `:Morfo`) + a bounded leak (navmenu `$effect.root`).
- Positive baselines for later batches: **popover** (Close-via-Button, no role override, hover guards) and
**dropdown-menu** (roving-focus consistency, uniform renderProps, self-managed cleanup, eidos-in-scope).

Powered by TurnKey Linux.