Widgets lifecycle phase 3. A framed card whose effective launch policy is
`retain` keeps its frame mounted in the hidden page when the owner leaves
Widgets (`widgetsVisible` stays the mount gate, never a disposer); it starts
on the first visit like `auto`, never at app load, and still stops on the
owner's Stop, on the hard reset, when its skill leaves the live list — a
lifecycle event while the page is hidden now fetches the list and
force-stops kept frames whose skill vanished — and with the SPA by
construction. Its status reads "Keeps running" (dot + text, existing tone
rules). Refresh stays the hard reset and asks first, through the shared
confirm dialog (strict boolean), only while a kept-running card would be
stopped; Cancel changes nothing.
Masonry packs the cards in the page's explicit key order instead of the DOM
order and writes the plan back only as `--masonry-w/-x/-y` per card and
`--masonry-h` on the list, applied by static rules in style.css; the
generated per-container <style> with :nth-child rules, `ensureStyleElement`,
`nextId` and `data-masonry-id` are gone, frames coalesce, and `applyMasonry`
returns an idempotent disposer (both ResizeObservers, the MutationObserver,
the pending frame). A reorder (drag or keyboard) is a pure move in the key
order handed back to the page; neither it nor the keyed list patch moves an
<article>, so a running frame never reloads on reorder. Disclosed residual:
the Tab/focus order follows the DOM and can differ from the visible order
after a reorder until the hard reset rebuilds the cards.
The declarative chart helpers and the shared dotted-path reader move
unchanged into widget_chart.js to keep widgets.js under the size band
ceiling.
Tests: node (masonry key order / custom properties / no <style> / disposer;
moveWidgetKey; isRetainedWidget; honest badge; injectable Refresh
confirmation), static pins updated deliberately for the new contracts, and a
ui_browser retain test on chromium and webkit (same iframe and window across
pages, setInterval progress while hidden on both engines, rAF progress
asserted on webkit only and recorded per engine, bridged ticks while the
declarative poll stays silent, keyboard reorder without node move or reload,
Refresh confirm Cancel/Restart, Stop frees the frame, hidden disable
force-stops). Docs: ARCHITECTURE lifecycle doctrine, DEVELOPMENT typed
retention rule + focus-order residual + module map, CREATING_SKILLS launch
policy.
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
Operator phase 3, closing the owner-approved 6.65-6.67 release cycle.
Declarative widget schema v1 gains recursive group/metric/callout composition
with stable nested identity, bounded validation (depth 8 / 256 nodes), shared
safe fields, accessible chart fallbacks, and a native kanban Move-to path —
strictly additive, existing declarations unchanged. Visible UI completion now
requires vision-inspected evidence from a real consumer flow (risk-selected
states/viewports; mobile/WebKit are not universal). BIBLE gains the two
owner-approved one-line clarifications (P0 autonomous judgment, P2
smallest-class-fix scope); DEVELOPMENT records Pragmatic SOLID and the mutable
external-fact inventory without analyzers or runtime migrations; reviewer
prompts drop numeric finding pressure in favor of evidence-backed defects. The
operator review wrapper additionally probes the exact reviewer model per
candidate OpenRouter key.
Owner personally approved the rendered Widgets UI screenshots (desktop+narrow,
three live Hub skills) before review. Review: triad fable-5/gpt-5.6-sol/
gemini-3.5-flash + scope fable-5 all responded, aggregate PASSED first run
(20260716T230014Z, $14.32). Full non-serial+serial pytest, web node tests,
and the marker-gated UI browser smoke (12 passed) are green; ruff -F clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>