Root reorg: src/ config/ plans/ layout + admin facelift #9

Merged
alee merged 18 commits from neuralwatt-router-service into main 2026-08-30 04:52:49 +00:00

18 Commits

Author SHA1 Message Date
adlee-was-taken
847675962d fix: disable pinch, relevance, circuit_breaker per shipped defaults; restore outlined logo 2026-08-30 00:47:04 -04:00
adlee-was-taken
0f9f831ab5 feat(admin): outlined mascot + speed lines at 64px, favicon data URIs updated 2026-08-30 00:46:59 -04:00
adlee-was-taken
661be2e05b docs: consolidate planning/review dirs into plans/ and update path references 2026-08-30 00:21:40 -04:00
adlee-was-taken
794c8f2e5a deploy: add PYTHONPATH for src/ layout and use python -m for maintenance scripts 2026-08-30 00:11:54 -04:00
adlee-was-taken
109b0e7545 refactor: move config data files into config/ and update all references 2026-08-30 00:03:05 -04:00
adlee-was-taken
0945a68fe7 refactor: move .py modules to src/, fix file anchors, and run maintenance scripts as python -m 2026-08-29 23:53:18 -04:00
adlee-was-taken
6642658dc8 docs: refresh admin portal section of README with four-page screenshots; fix test counts
The admin portal grew from a single index.html into a four-page liquid-glass
console (dashboard, models, decisions, controls) but README.md still described
it as a 'small management UI' pointing only at index.html.

- README.md: rewrite the admin section to describe each of the four pages,
  embed current screenshots (captured against the live service at :8080) under
  assets/screenshots/, add a Features bullet and TOC entry for the portal, add
  admin.py to the Modules table and test_admin_frontend.py to the test matrix,
  and correct the test count 731 -> 733.
- CLAUDE.md: correct the tests count 731 -> 733.
- AGENTS.md: correct the stale stack-snapshot and post-change test counts
  (562 -> 733).

The 562/568/673 figures in code_reviews/*.md are left untouched - those are
point-in-time audit records, not live counts.
2026-08-29 22:51:30 -04:00
adlee-was-taken
55a238885d docs(admin): add admin UI work framework and codify settings-row grammar
Formalize how to touch the admin portal so results transfer to the next page:

- code_plans/admin-work-framework.md: the 5-move method distilled from the
  controls relayout (c22bbae) — surface diagnosis, grammar-first rule
  extraction, S1-S5 survival re-verification, the pytest + Playwright-1400/800
  + REFRESH_MS-idle evidence bar, and writing the commit as a standalone
  learning input.
- code_plans/admin-design-standards.md: add the settings-row and card-level
  layout grammar as transferable rules (one CSS-grid row key|meta|176px;
  never restate a control's own value; single-line button strip goes full
  width in .card-actions) so the Controls layout becomes apply-able, not just
  described.
- AGENTS.md: point admin editors at the framework alongside the standards.
2026-08-29 22:48:36 -04:00
adlee-was-taken
b2601ecb85 chore: check in admin facelift plan, QA screenshots, and TUI review notes
Working artifacts accumulated during the admin frontend uplift: the
facelift plan, the layout/viewport QA captures taken while iterating, and
two code_reviews docs (TUI panel polish plan, verdict-bar label review).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-08-29 22:46:11 -04:00
adlee-was-taken
c22bbae726 fix(admin): rebuild Controls on one settings-row grammar
The page had three distinct layout problems, all visible at a glance:

- Operational Triggers is a single line of buttons but sat in a col-xl-6
  next to the much taller Runtime Knobs, so half that row was permanently
  empty. No align-items value fixes that; the card is now a full-width
  strip with its buttons in .card-actions.
- Both settings panels used a 5/3/4 Bootstrap grid, which put the control
  mid-row at three different widths and spent a whole trailing column
  restating the value the control already displays (true / true / 0.1).
  Both now use one CSS-grid row -- key | meta | 176px control -- so every
  switch, input and select lands on the same right edge.
- Rows alternated switches and text inputs, which differ ~10px in natural
  height and read as ragged. Fixed at min-height 38px.

The freed meta column now carries only what a control cannot show: the
kWh unit on the two energy keys, and an amber `file: <value>` badge when a
runtime knob disagrees with config.yaml.

Two consistency fixes alongside: persisted-config booleans were bare
checkboxes while the runtime knobs were switches, and dotted keys now dim
the scope so the leaf reads first.

Persisted Config also stopped being a blind save -- edits mark the row and
the button counts them (`Save 2 changes`, disabled at zero), and only
dirty rows are written rather than every allowlisted key on every click.

The frontend test asserted on that button's literal text, which is now
rendered from the dirty count, so it asserts on the element id instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-08-29 22:46:05 -04:00
adlee-was-taken
daaa9d3d33 fix(admin): circuit_breaker toggle + enum dropdowns for Controls
circuit_breaker was the one runtime knob with no toggle switch, silently
falling through to plain text. Root cause: GET /admin/api/runtime reported
it as a nested {"enabled": ...} object while every other knob (including
its own POST key, circuit_breaker_enabled) is a flat bool -- an
inconsistency with no functional reason, introduced when the knob was
added. Flattened to match; the frontend's existing boolean-detection logic
picks it up automatically, no JS special-casing needed. Updated the one
test asserting the old nested shape.

default_flex_preference (Runtime Knobs) and routing.default_flex_preference
+ logging.level (Persisted Config) were free-text inputs for values that
are actually closed 4-way enums on the backend (FlexPreference; logging's
own field_validator). Now <select> dropdowns sourced from those legal
values, shared between both panels via one ENUM_VALUES table instead of
duplicating the list.

Also: Operational Triggers no longer stretches to match Runtime Knobs'
height (row-level align-items-start), which was leaving a slab of dead
space under its four buttons.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-08-29 22:33:44 -04:00
adlee-was-taken
a51bcacd35 feat(admin): pagination + density pass on Decisions, layout fixes elsewhere
Decisions page: 50/100/250-per-page pagination with Prev/Next and a page
indicator (fetch bumped to 1000 rows to have enough to paginate through);
category/source get the same colored-badge treatment kind already had
(tier reverted back to plain colored text -- a filled pill was overkill);
capability flags (tools/images/json-mode/streamed) as compact on-only
chips in a new Flags column; row padding and font-size tightened for a
noticeably denser scan.

Fixes:
- Category Breakdown label truncation ("tool_use_ag...", "coding_refac...")
  -- it was reusing Verdict Mix's 88px label column, sized for short verdict
  words, not task_category names. Split into its own 128px .cat-label.
- Controls page: Operational Triggers was stretching to match Runtime
  Knobs' height (Bootstrap row default align-items:stretch) and sitting on
  a pile of dead space below its own content. align-items-start on that
  row only; the full-width Persisted Config row below is unaffected.

AGENTS.md/CLAUDE.md: admin portal doc updates from the parallel opencode
session, plus code_plans/admin-design-standards.md it now links to as the
one design-system reference for admin/frontend/*.html.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-08-29 22:27:59 -04:00
adlee-was-taken
cc8231367b feat(admin): rebuild frontend on a true Tabler shell with liquid-glass theme
Standalone pages for Models and the new Decisions log (filter/search over
route_decisions, live via SSE), full page/page-wrapper/page-header/page-body
shell on Dashboard/Controls/Models/Decisions, and a glass-effect pass
(translucent blurred navbar/cards/buttons/badges/progress bars) over the
previously flat Tabler skin.

Dashboard reshuffle: Quota Meter and Warnings cards replaced by a header
capsule chip (click -> popup, also links out to the NeuralWatt dashboard)
and a navbar bell with a dismissible dropdown; Category Breakdown gets real
bars instead of bare dots; Per-Model Usage is a responsive grid with a
Calls/Cost/Energy sort toggle; Recent Decisions moved to the bottom with a
link to the full log.

Fixes bundled in along the way:
- objective.max_energy_per_request: Persisted Config was sending the
  literal string "null" instead of JSON null, so every save 422'd. Null
  fields now render empty with a placeholder and save as real null.
- Category Breakdown's counts were unreadable: bg-secondary badge text
  color was too close to its own background.
- Logo lost its color/face: the filter:none override lost the cascade to
  Tabler's [data-bs-theme=dark] .navbar-brand-autodark rule (higher
  specificity); needed !important. controls.html was missing the fix,
  the favicon link, and the 36px (now 45px) sizing entirely.
- Persistent left-edge gap at wide viewports: this Chrome/Linux build
  reports a phantom left margin on <html> equal to the scrollbar's width
  whenever <html> itself is the scrolling element. Moved the scroll
  context down to <body>.
- Warnings dropdown rendered behind the quota chip: backdrop-filter on
  header.navbar creates a stacking context, and the later-in-DOM .page
  element (whose quota chip also has backdrop-filter) painted on top of
  it regardless of the dropdown's own z-index. Pinned the navbar's
  stacking context above it explicitly.
- Admin pages had no Cache-Control, so browsers served stale pages after
  every edit during iteration; now explicitly no-cache.

AGENTS.md: manual/dev instances now bind :8081 instead of a bare 8080,
with an explicit warning not to pkill/kill anything matching
uvicorn/dispatcher/8080 -- that's the systemd-managed production
instance (opencode's own model traffic runs through it), and killing it
by pattern match was today's actual cause of the router's "flaky
restarts" incident, documented in CLAUDE.md.

config.yaml: circuit_breaker, session_cache, pinch, and pinch.relevance
flipped to enabled -- deliberate, to start collecting real-traffic signal
on knobs that shipped off by design.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRQXz5SYZYVWscxS1QqF6U
2026-08-29 22:13:43 -04:00
adlee-was-taken
906c9e6316 fix(admin): replace stretched verdict doughnut with partition bar and split history into per-metric mini charts 2026-08-29 14:49:58 -04:00
adlee-was-taken
08eb4369cb chore: ignore admin config backups and playwright node artifacts
Ignore config.yaml.bak.* (timestamped config-write backups), node_modules/, package.json, package-lock.json (Playwright browser-QA noise), and .playwright-mcp/.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-08-29 13:40:45 -04:00
adlee-was-taken
642773ab63 chore(admin): normalize config.yaml formatting from admin config round-trip
Cosmetic only: 0.10 -> 0.1, null -> blank scalar, and block-list re-indentation produced by the ruamel.yaml round-trip write path (no semantic value changes). Harmless, and shows what an allowlisted /admin/api/config write produces.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-08-29 13:40:41 -04:00
adlee-was-taken
71939fdea2 docs(admin): document admin portal and refresh test count
Add the admin web portal section to README (dashboards, triggers, runtime toggles, config edits, availability overrides) and document admin.py/admin_schema.sql/admin/frontend in CLAUDE.md. Update the test count to the verified 731 tests across 40 files.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-08-29 13:40:36 -04:00
adlee-was-taken
162cc6e113 feat(admin): wire admin router into the service dispatch path
Mount the admin portal at /admin via build_router(cfg, _db, root), extend the startup migration to ensure admin tables (renaming _ensure_route_decisions_table -> _ensure_tables), and feed model deprecation overrides into the routing hard filters through _admin_deprecated_models(). Pin ruamel.yaml==0.18.10 (comment-preserving writes) for the /admin/api/config persisted-config editor.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-08-29 13:40:33 -04:00