Commit Graph

1935 Commits

Author SHA1 Message Date
OpenClaw Bot 4ed272761b test(#1188): red — /api/packets must return observer_iata per row
Adds three tests asserting the API surfaces observer_iata on:
- ungrouped /api/packets rows
- grouped /api/packets?groupByHash=true rows
- per-observation entries in /api/packets/{id} detail response

Currently fails: the SQL joins select obs.id, obs.name but not obs.iata.
Fixing the join in cmd/server/db.go is the green commit.
2026-05-11 05:22:15 +00:00
OpenClaw Bot 2c182ebd23 feat(#1188): green — observer_iata/iata filter grammar evaluator
- resolveField returns packet.observer_iata for both 'observer_iata' and
  'iata' (alias) field names
- in (...) operator evaluator: case-insensitive membership in value list
- Add observer_iata + iata to FIELDS metadata (autocomplete dropdown)
- Add 'in' to OPERATORS list with example
2026-05-11 05:20:12 +00:00
OpenClaw Bot 271d72f19d test(#1188): red — observer_iata/iata filter grammar tests
Add tests for observer_iata and iata (alias) filter fields:
- equality (==, !=)
- in (a, b, c)
- contains
- missing-iata handling
- combined with type
- presence in suggest field list

Also adds parser support for: 'in' operator + comma + LPAREN/RPAREN
value lists, so tests reach the assertion stage (not parse errors).
Field stub returns empty string — tests fail on the assertion that
'observer_iata == "SJC"' should match a packet with that IATA.
2026-05-11 05:18:02 +00:00
Kpa-clawbot 03b5d3fe28 fix(#1065): first-visit gesture discoverability hints (#1186)
Red commit: 4e0a168bc0 (CI run: see Checks
tab — branch pushes don't trigger CI on this repo; first CI is on this
PR)

Fixes #1065. Parent: #1052.

## What
First-visit gesture discoverability hints. Brief animated balloons
appear 800ms after page settle on first visit, announcing each gesture:
swipe-row-action, swipe-between-tabs, edge-swipe-drawer,
pull-to-refresh. Each hint dismisses individually via "Got it";
dismissed hints persist across sessions; "Reset gesture hints" in
Customize → Display restores them.

## Decisions
- **localStorage namespace:** `meshcore-gesture-hints-<id>` with keys
`row-swipe`, `tab-swipe`, `edge-drawer`, `pull-refresh`. Value:
`"seen"`.
- **Hint timing:** 800ms post-settle delay (lets page render); no
auto-mark — hints fade after 8s but only "Got it" sets the flag (so
users who miss the fade still see them next visit). Conservative
interpretation of AC.
- **Settings reset location:** Customize → Display tab → "Gesture Hints"
subsection → `↺ Reset gesture hints` button. Calls
`window.GestureHints.reset()` which clears all four keys + removes any
visible balloons.
- **Pull-to-refresh fallback:** hint only shown if `.pull-to-reconnect`
element exists in DOM (per #1063). If absent, the hint is silently
skipped — other 3 still show.
- **prefers-reduced-motion:** `animation-name: none !important` under
the media query; only opacity transition remains.
- **No focus stealing:** no `autofocus`, no `.focus()` calls. Wrapper
has `pointer-events: none`; only the inner balloon + dismiss button
capture pointer, so the row underneath stays interactive (no conflict
with #1185 row-swipe).
- **Singleton + cleanup:** module-scoped `window.__gestureHints1065Init`
counter; `hashchange` listener bound exactly once across SPA mounts;
dismissed hints don't re-show on route change (gated by `localStorage`).
- **Relevance gating:** row-swipe hint only on `/#/packets|nodes|live`;
edge-drawer only at viewport > 768px (matches #1064 drawer scope).

## E2E
`test-gesture-hints-1065-e2e.js` — Playwright covering first-visit show,
"Got it" dismiss + flag persistence, reload-no-show, Settings reset →
reload → re-show, edge-drawer at 1024x800, prefers-reduced-motion →
animation-name: none, focus not stolen, singleton across 5 SPA
round-trips.

E2E assertion added: test-gesture-hints-1065-e2e.js:90

Browser verified: pending CI run.

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
Co-authored-by: corescope-bot <bot@corescope.local>
2026-05-09 20:03:54 -07:00
Kpa-clawbot b4f186af19 fix(#1062): gesture system — swipe rows, tabs, slide-over dismiss (#1185)
Red commit: bbb98cf81a (CI run: pending —
see Checks tab)

Fixes #1062. Parent: #1052.

## Gesture system

Adds touch-gesture handling on phones (≤768px):

1. **Swipe-left on a packets/nodes/observers row** → reveals row-action
overlay (trace, filter, copy hash). Threshold: 24% of row width OR 80px.
Sub-threshold = visual peek that snaps back.
2. **Horizontal swipe on the bottom-nav strip** → advances tabs in TAB
order from `bottom-nav.js`. Packets ↔ Live ↔ Map etc.
3. **Swipe-down on a slide-over panel** → calls
`window.SlideOver.close()`.

## Hard constraints met

- **Pointer Events ONLY** — no `touchstart`/`touchend` mixing.
`setPointerCapture` for tracking continuity.
- **Axis-lock** — direction committed in first 8–12px movement. Vertical
scroll is never blocked unless we explicitly committed to a horizontal
swipe. `body { touch-action: pan-y }` so the browser owns vertical
natively.
- **Leaflet exclusion** — handlers early-bail on
`e.target.closest('.leaflet-container')` so pinch/pan on the map tab are
untouched.
- **Singleton pattern** — module-scoped `__touchGestures1062InitCount`
guard. Document-level pointer listeners registered exactly once even if
the script loads multiple times (mirrors the #1180 fix class).
- **prefers-reduced-motion** — animations have `transition-duration: 0s`
under the media query; gestures still trigger, snaps are instant.

## E2E

`test-gestures-1062-e2e.js` — Playwright with synthesized PointerEvents
(page.touchscreen unreliable in headless for axis-locked custom
handlers). Wired into the deploy.yml matrix.

E2E assertion added: test-gestures-1062-e2e.js:120 (overlay-visible
after left-swipe), :201 (tab advance), :219 (Leaflet exclusion), :247
(slide-over dismiss).

---------

Co-authored-by: openclaw-bot <bot@openclaw>
Co-authored-by: OpenClaw Bot <bot@openclaw.dev>
Co-authored-by: openclaw-bot <openclaw-bot@users.noreply.github.com>
Co-authored-by: clawbot <clawbot@users.noreply.github.com>
Co-authored-by: corescope-bot <bot@corescope.local>
Co-authored-by: openclaw-bot <bot@openclaw.local>
2026-05-09 18:41:19 -07:00
Kpa-clawbot 9b9848611b fix(#1064): edge-swipe nav drawer (Option A, wide-only) (#1184)
Red commit: a810b1fac5 (CI run pending —
draft PR)

Fixes #1064 (parent epic #1052).

## What
Edge-swipe nav drawer (slide-over from left). Pointer-down within left
20px → drag-follows-finger animation → settles open/closed on velocity
threshold. Drawer surfaces the same long-tail routes as the More sheet
(PR #1174) as an alternate entry point at the EDGE.

## Decisions
**Option A — drawer wide-only (>768px).** At ≤768px the bottom-nav has
the More tab (PR #1174); a left-edge drawer there would compete with
that UX. Wide viewports have no More tab, so the drawer replaces the
top-nav hamburger as a faster keyboard-free entry. Bottom-nav
coexistence at narrow widths: none — drawer is disabled.

**Singleton + cleanup.** Module-scoped guard +
`__navDrawerPointerBindCount` debug seam — same pattern as #1180 fix.
`pointermove`/`pointerup` are bound on `document` exactly once across
SPA mounts.

**`body { touch-action: pan-y }`.** Vertical scroll preserved
everywhere; the drawer claims horizontal swipes only inside our
viewport. iOS browser-back left-edge gesture still works (it's the OS,
not the page).

**Accessibility.** `inert` on the drawer when closed, removed when open.
Focus trap (Tab cycles last↔first). Esc closes. Backdrop tap closes.
`prefers-reduced-motion`: instant snap, no animation.

## Tests (TDD)
Red commit pushes the E2E first; CI must FAIL on assertion.
E2E assertion added: `test-nav-drawer-1064-e2e.js:1`

## CSS coordination with #1062
Additions are fenced (`/* === Issue #1064 — Edge-swipe nav drawer === */
… /* === end #1064 === */`) to minimize merge friction.

---------

Co-authored-by: corescope-bot <bot@corescope>
Co-authored-by: openclaw-bot <bot@openclaw>
Co-authored-by: OpenClaw Bot <bot@openclaw.local>
Co-authored-by: corescope-bot <bot@corescope.local>
2026-05-09 17:55:42 -07:00
Kpa-clawbot 7c60d9db4b ci: update go-server-coverage.json [skip ci] 2026-05-09 18:13:39 +00:00
Kpa-clawbot 8bb994750e ci: update go-ingestor-coverage.json [skip ci] 2026-05-09 18:13:38 +00:00
Kpa-clawbot a069586f43 ci: update frontend-tests.json [skip ci] 2026-05-09 18:13:37 +00:00
Kpa-clawbot 433ba0d30b ci: update frontend-coverage.json [skip ci] 2026-05-09 18:13:36 +00:00
Kpa-clawbot d7b343ccce ci: update e2e-tests.json [skip ci] 2026-05-09 18:13:35 +00:00
Kpa-clawbot 9d1f5d2395 fix(#1061): bottom navigation for narrow viewports (#1174)
Red commit: a200704d5e (CI URL added once
Actions resolves the run)

Fixes #1061

## What
Bottom navigation at ≤768px with 5 tabs in spec order: Home, Packets,
Live, Map, Channels. Top-nav suppressed at the same breakpoint — no
duplicate nav UX.

## Files
- NEW `public/bottom-nav.js` — renders 5 tabs, syncs `.active` on
`hashchange`, reuses the existing in-app hash router (`<a
href="#/...">`). Stable selector `[data-bottom-nav-tab="<route>"]`.
Container `[data-bottom-nav]`.
- NEW `public/bottom-nav.css` — styles. Tokens reused: `--nav-bg`,
`--nav-text`, `--nav-text-muted`, `--nav-active-bg`, `--accent`,
`--border` (all global → resolve in BOTH light and dark themes).
- `public/index.html` — one `<link>` for the CSS, one `<script>` after
`app.js`. The `<nav>` is appended by JS as a sibling of `<main
id="app">` at DOMContentLoaded.
- `test-bottom-nav-1061-e2e.js` + `.github/workflows/deploy.yml` —
Playwright wiring.

## Decisions
- **Breakpoint:** `@media (max-width: 768px)`. No `@container` rules
exist anywhere in `style.css` today — media query is consistent.
- **Top-nav suppression:** `display:none` at ≤768px. Simpler than a
hamburger collapse; long-tail routes (Tools/Lab/Perf) remain reachable
by URL; "More"-tab/hamburger fallback deferred per issue body.
- **Active indicator:** `var(--nav-active-bg)` + 2px accent top-border.
No moving pill.
- **Safe-area:** `padding-bottom: env(safe-area-inset-bottom)` on nav +
reciprocal `body` reservation. `viewport-fit=cover` already in place.
- **Reduced motion:** `prefers-reduced-motion: reduce` disables the
transition.

## TDD
- Red: `a200704` — assertions fail (no bottom-nav).
- Green: `53851a1` — component + styles.

E2E assertion added: `test-bottom-nav-1061-e2e.js:71` (case (a) —
bottom-nav visible at 360x800).

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
Co-authored-by: corescope-bot <bot@corescope.local>
Co-authored-by: clawbot <clawbot@users.noreply.github.com>
Co-authored-by: openclaw-bot <bot@openclaw>
2026-05-09 11:00:46 -07:00
Kpa-clawbot b95684e8ca ci: update go-server-coverage.json [skip ci] 2026-05-09 03:38:28 +00:00
Kpa-clawbot 10546f1870 ci: update go-ingestor-coverage.json [skip ci] 2026-05-09 03:38:27 +00:00
Kpa-clawbot b0da831d4e ci: update frontend-tests.json [skip ci] 2026-05-09 03:38:26 +00:00
Kpa-clawbot 50f2237cf7 ci: update frontend-coverage.json [skip ci] 2026-05-09 03:38:25 +00:00
Kpa-clawbot 09200c8dfe ci: update e2e-tests.json [skip ci] 2026-05-09 03:38:24 +00:00
Kpa-clawbot 05876b3a59 fix(#1173): replace #liveDot with packet-driven brand-logo node-pulse (#1177)
Red commit: PENDING (will update)

Fixes #1173.

Replaces the `#liveDot` WebSocket-connected indicator with a
packet-driven node-pulse animation on the brand logo's two inner
circles.

## Behavior (locked per issue spec)
- **Animation curve:** `ease-out` (default per open-question 1).
- **Rate cap:** 15/sec (66ms gap; default per open-question 2). Excess
triggers are dropped, never queued.
- **Direction:** alternates A→B / B→A across messages (aesthetic, not
semantic).
- **Idle ≥10s:** logo at full brightness, no animation.
- **Disconnected:** `.logo-disconnected` applies `filter: grayscale(0.6)
opacity(0.7)`.
- **`prefers-reduced-motion: reduce`:** single-step `.logo-pulse-blip`
on destination only.

## Implementation
- WS handler hook lives in `public/app.js` `connectWS()` (`ws.onmessage`
triggers `Logo.pulse()`; `ws.onopen`/`ws.onclose` toggle
`Logo.setConnected()`).
- `Logo` is a small IIFE in `app.js` that exposes
`window.__corescopeLogo` for E2E injection.
- All animation is pure CSS; JS only toggles `.logo-pulse-active` /
`.logo-pulse-blip` / `.logo-disconnected`. Colors come exclusively from
`--logo-accent` / `--logo-accent-hi` tokens.
- Two new classes (`.logo-node-a`, `.logo-node-b`) attached to inner
circles in both `.brand-logo` and `.brand-mark-only` SVGs so the mobile
mark animates too.

## `#liveDot` removal proof
```
$ grep -rn liveDot public/
(no output)
```

## E2E
- E2E assertion added: `test-logo-pulse-1173-e2e.js:54` and follows.
- Wired into the Playwright matrix in `.github/workflows/deploy.yml`
(mirrors PR #1168 pattern from commit `5442652`).
- Test injects synthetic pings via `window.__corescopeLogo.pulse({
synthetic: true })`; matches the existing harness style (no new WS-mock
pattern invented).

Red→green discipline preserved: the test commit lands first and CI fails
on assertion; the implementation commit follows.

---------

Co-authored-by: Kpa-clawbot <bot@kpa-clawbot>
Co-authored-by: corescope-bot <bot@corescope.local>
2026-05-08 20:25:42 -07:00
Kpa-clawbot f58214a6cc ci: update go-server-coverage.json [skip ci] 2026-05-09 02:03:36 +00:00
Kpa-clawbot 99677f71b6 ci: update go-ingestor-coverage.json [skip ci] 2026-05-09 02:03:35 +00:00
Kpa-clawbot 56167b4d28 ci: update frontend-tests.json [skip ci] 2026-05-09 02:03:34 +00:00
Kpa-clawbot cf136aa367 ci: update frontend-coverage.json [skip ci] 2026-05-09 02:03:33 +00:00
Kpa-clawbot 0063c7c24a ci: update e2e-tests.json [skip ci] 2026-05-09 02:03:32 +00:00
Kpa-clawbot 16c48e73b3 fix(live): compact header + pinned controls with narrow-viewport collapse (#1178, #1179) (#1180)
Red commit: 61fcc8c19b (CI run: pending —
see Checks tab on this PR)

Fixes #1178
Fixes #1179

## Summary
Live page layout polish — both issues touch `public/live.css` + a
small `public/live.js` slice, so they ship as one PR per AGENTS rule
34.

### #1178 — Header compactness + narrow-viewport collapse
- `.live-header` total height ≤ 40px at desktop widths (smaller
  padding, gap, title font, and pill sizing; `max-height: 40px` as a
  belt-and-suspenders gate).
- Body wrapped in `.live-header-body` so it can collapse cleanly.
- New 32×32 toggle button `[data-live-header-toggle]`, hidden at
  wide viewports, visible at `≤768px`.

### #1179 — Controls pinned bottom-right + narrow-viewport collapse
- New `.live-controls` cluster around the toggles list and audio
  controls, `position: fixed; right: 12px;` and
`bottom: calc(78px + var(--bottom-nav-height, 56px) +
env(safe-area-inset-bottom, 0px))`.
- That bottom calc reserves space for the VCR bar **and** the bottom
  nav (#1061, currently in PR #1174). When the bottom-nav exposes
  `--bottom-nav-height` the cluster tracks it; otherwise the 56px
  fallback keeps it clear regardless of merge order.
- `z-index: 1000` keeps it above map markers but below modals.
- New 32×32 toggle button `[data-live-controls-toggle]`, hidden at
  wide viewports, visible at `≤768px`.

### Breakpoint + selectors
- Narrow = `max-width: 768px` (matches #1061 bottom-nav activation).
- Stable selectors for E2E: `[data-live-header-toggle]`,
  `[data-live-header-body]`, `[data-live-controls-toggle]`,
  `[data-live-controls-body]`. No DOM-order dependence.

### Bottom-nav coexistence
The expanded narrow-viewport controls panel uses
`max-height: 50vh; overflow-y: auto` on its toggles list, and the
cluster's `bottom` reservation guarantees the panel's bottom edge
sits above the (possibly absent) bottom-nav region. The E2E test
asserts exactly this with `expandedRect.bottom + 8 < innerHeight −
navH`,
defaulting `navH` to 56 if `.bottom-nav` is not in the DOM yet.

### Theming
All new colors via existing CSS tokens (`--surface-1`, `--text`,
`--text-muted`, `--border`, `--accent`). check-css-vars passes.

### TDD
- Red commit: `61fcc8c` — assertions only (no impl), wired into
  `.github/workflows/deploy.yml` Playwright matrix.
- Green commit: `7d591be` — DOM split + CSS + collapse JS.
- E2E assertion added: `test-live-layout-1178-1179-e2e.js:55`
  (desktop header height) through `:170` (narrow controls
  bottom-nav coexistence).

### Local verification
```
./corescope-server -port 13581 -db test-fixtures/e2e-fixture.db &
CHROMIUM_PATH=/usr/bin/chromium BASE_URL=http://localhost:13581 \
  node test-live-layout-1178-1179-e2e.js
# → 8/8 passed
```

---------

Co-authored-by: meshcore-bot <bot@meshcore.local>
Co-authored-by: openclaw-bot <bot@openclaw.local>
2026-05-08 18:50:30 -07:00
Kpa-clawbot de2595a147 ci: update go-server-coverage.json [skip ci] 2026-05-09 00:47:14 +00:00
Kpa-clawbot 53762d341b ci: update go-ingestor-coverage.json [skip ci] 2026-05-09 00:47:13 +00:00
Kpa-clawbot ab3cbada13 ci: update frontend-tests.json [skip ci] 2026-05-09 00:47:12 +00:00
Kpa-clawbot 99cd0a8947 ci: update frontend-coverage.json [skip ci] 2026-05-09 00:47:11 +00:00
Kpa-clawbot a104cb963b ci: update e2e-tests.json [skip ci] 2026-05-09 00:47:10 +00:00
Kpa-clawbot 9774403fa4 fix(#1058): analytics chart containers — fluid + auto-stacking (#1175)
Red commit: 0f29da3 (CI is pending — will be linked once dispatched)

Fixes #1058

This PR is in **red phase**. The new E2E asserts the desired
fluid + auto-stacking behavior; with `master`'s code it FAILS at
≥768px (cards don't stack). Green commit follows.

E2E assertion added: `test-charts-fluid-1058-e2e.js:99`.

---------

Co-authored-by: OpenClaw Bot <bot@openclaw.local>
Co-authored-by: Kpa-clawbot <bot@kpa-clawbot>
2026-05-08 17:33:24 -07:00
Kpa-clawbot bc644a368e ci: update go-server-coverage.json [skip ci] 2026-05-08 23:41:50 +00:00
Kpa-clawbot b8f4a91381 ci: update go-ingestor-coverage.json [skip ci] 2026-05-08 23:41:49 +00:00
Kpa-clawbot 9c97c382ee ci: update frontend-tests.json [skip ci] 2026-05-08 23:41:48 +00:00
Kpa-clawbot 096c1ee489 ci: update frontend-coverage.json [skip ci] 2026-05-08 23:41:47 +00:00
Kpa-clawbot c2602e0fdd ci: update e2e-tests.json [skip ci] 2026-05-08 23:41:46 +00:00
Kpa-clawbot f4cf2acbc0 perf: cancelled writes + ingestor I/O + threshold tests (#1120 follow-up) (#1167)
Red commit: e964ec9c46 (CI run: pending —
workflow only triggers on PR open)

Partial fix for #1120 — finishes the four follow-up items left open
after PR #1123 (cancelled writes, ingestor I/O, threshold-flag tests,
docs).

## What's done

- **`cancelledWriteBytesPerSec`** — server `/proc/self/io` parser
handles `cancelled_write_bytes`; `/api/perf/io` exposes the per-second
rate; Perf page renders it next to Read/Write with ⚠️ when sustained >1
MB/s.
- **Ingestor `/proc/<pid>/io`** — `cmd/ingestor/stats_file.go` samples
its own `/proc/self/io` each tick and includes `procIO` in the snapshot.
The server's `/api/perf/io` reads it and surfaces `.ingestor`. Frontend
renders an `Ingestor process` Disk I/O block alongside the existing
`server process` block (issue mockup: "Both ingestor and server").
- **Threshold + anomaly tests** — `test-perf-disk-io-1120.js` now
asserts ⚠️ fires/suppresses on WAL>100MB, cache_hit<90%, and the
backfill-rate-vs-tx-rate guard with the `tx_inserted >= 100` baseline
floor. Drops the tautological `|| ... === false` short-circuits flagged
in MINOR m4.
- **Docs (m8)** — `config.example.json` adds `_comment_ingestorStats`
(env var, default path, shared-tmp security note);
`cmd/ingestor/README.md` adds `CORESCOPE_INGESTOR_STATS` to the env-var
table plus a `Stats file` section.

## What's NOT done (deferred)

m1 sync.Map → map+RWMutex, m2 perfIOMu rate caching, m3 negative
cacheSize translation, m5 deterministic-write test, m7 ctx-aware
shutdown — pure polish; will file a follow-up issue if the operator
wants them tracked.

## TDD

- Red: `e964ec9` — adds failing tests + stub field/handler shape
(cancelled missing from struct, ingestor stub returns nil, ingestor
procIO absent).
- Green: `1240703` — wires up the parser case, ingestor sampler,
frontend rendering, docs.

E2E assertion added: test-perf-disk-io-1120.js:108

---------

Co-authored-by: clawbot <clawbot@users.noreply.github.com>
Co-authored-by: Kpa-clawbot <bot@kpa-clawbot.local>
Co-authored-by: Kpa-clawbot <bot@kpa-clawbot>
2026-05-08 16:29:23 -07:00
Kpa-clawbot b4f31c95eb ci: update go-server-coverage.json [skip ci] 2026-05-08 21:26:51 +00:00
Kpa-clawbot 254f886ed9 ci: update go-ingestor-coverage.json [skip ci] 2026-05-08 21:26:50 +00:00
Kpa-clawbot 86eae59f46 ci: update frontend-tests.json [skip ci] 2026-05-08 21:26:49 +00:00
Kpa-clawbot 5de3ba907c ci: update frontend-coverage.json [skip ci] 2026-05-08 21:26:48 +00:00
Kpa-clawbot 8a0aa21348 ci: update e2e-tests.json [skip ci] 2026-05-08 21:26:47 +00:00
Kpa-clawbot 89d644dd72 fix(#1056): row-detail slide-over panel at narrow widths (AC #4) (#1168)
Red commit: 8ac568bac3 (CI run: pending)

## Summary
Implements AC #4 of #1056: row-detail **slide-over panel** at narrow
viewports for the Packets, Nodes, and Observers tables.

ACs #1–#3, #5 already shipped in #1099; this PR closes the remaining
criterion.

## Approach
- Shared `window.SlideOver` helper (`packets.js`, top of file next to
`TableResponsive`) — singleton overlay (`.slide-over-backdrop` +
`.slide-over-panel`) injected into `<body>`. Close affordances: X button
(`.slide-over-close`), backdrop click, Escape key. `aria-modal="true"`,
focus moved to close button on open.
- Breakpoint: `window.innerWidth <= 1023` (matches the
`data-priority="3"` threshold reused by `TableResponsive`). At `>=1024`
the existing right-side panel / full-screen behavior is preserved — no
regression.
- Each page (`packets.js`, `nodes.js`, `observers.js`) checks the
breakpoint at row-click time and routes the same detail content into
`SlideOver.open(node)` instead of the side panel / full-screen
navigation.
- Reuses the existing `slideInRight` keyframe in `style.css`.
- CSS additions live in the table section of `style.css` only.

## E2E
`test-slideover-1056-e2e.js` — at 800x800 clicks the first row of each
of the three tables, asserts `.slide-over-panel` +
`.slide-over-backdrop` are visible and the close X exists; verifies
Escape, backdrop click, and X click all dismiss; verifies that at 1440
the slide-over does NOT appear.

E2E assertion added: `test-slideover-1056-e2e.js:71`

## TDD
- Red commit: `8ac568b` — E2E asserts on `.slide-over-panel` which does
not exist yet.
- Green commit: forthcoming in this PR.

Fixes #1056

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
Co-authored-by: Kpa-clawbot <bot@kpa-clawbot.local>
Co-authored-by: corescope-bot <bot@corescope.local>
Co-authored-by: Kpa-clawbot <bot@kpa-clawbot>
2026-05-08 14:13:37 -07:00
Kpa-clawbot 79bf673fa3 ci: update go-server-coverage.json [skip ci] 2026-05-07 16:53:44 +00:00
Kpa-clawbot 6df72a4512 ci: update go-ingestor-coverage.json [skip ci] 2026-05-07 16:53:43 +00:00
Kpa-clawbot c5a7addbc8 ci: update frontend-tests.json [skip ci] 2026-05-07 16:53:42 +00:00
Kpa-clawbot f9cef6c9fa ci: update frontend-coverage.json [skip ci] 2026-05-07 16:53:41 +00:00
Kpa-clawbot f51329759d ci: update e2e-tests.json [skip ci] 2026-05-07 16:53:40 +00:00
Kpa-clawbot cf604ca788 fix(nav): #1109 mobile hamburger dropdown clipped by .top-nav overflow:hidden (#1163)
# Fix #1109 — mobile hamburger dropdown clipped invisible by `.top-nav {
overflow:hidden }`

Red commit: `5429b0f` (failing E2E, asserts pixel-level visibility).

## Symptom

On <768px viewports, tapping `#hamburger` toggles `.nav-links.open` and
`body.nav-open` correctly — DOM state is right, `aria-expanded="true"`,
computed `display:flex` — but **nothing appears below the navbar**. The
dropdown is laid out at `y=52..626` but visually clipped.

## Root cause

`.top-nav` is `position:sticky; height:52px; overflow:hidden` (added in
#1066 fluid scaffolding at `417b460` to guard against horizontal
overflow during the Priority+ measurement pass). At <768px the dropdown
becomes `position:absolute; top:52px`, so its containing block is
`.top-nav` — and `.top-nav`'s `overflow:hidden` clips everything below
`y=52`. Result: the dropdown renders inside a 52px box and the user sees
nothing.

Full RCA + screenshots:
https://github.com/Kpa-clawbot/CoreScope/issues/1109#issuecomment-4398900387

## Fix

In `public/style.css`, inside `@media (max-width: 767px)`, change
`.nav-links` from `position:absolute` to `position:fixed`.
`position:fixed` escapes any `overflow:hidden` ancestor (its containing
block becomes the viewport), so the dropdown is no longer clipped. All
other rules (display/flex/background/padding/z-index) keep working.

This deliberately does **not** relax `overflow:hidden` on `.top-nav` —
that would reopen the #1066 horizontal-overflow regression on desktop.

## Why prior tests missed this

Existing nav E2Es asserted `.classList.contains('open')` /
`getComputedStyle().display === 'flex'` — pure DOM state. Those passed
even while the dropdown was clipped invisibly. The new test in this PR
asserts **pixel-level visibility**:
`document.elementFromPoint(viewportWidth/2, 100)` must land on something
inside `.nav-links` (not `<body>`), and the first `.nav-link`'s bounding
rect must satisfy `bottom > 60` and have non-zero area. A state-only fix
can never satisfy this.

E2E assertion added:
`test-issue-1109-hamburger-dropdown-visible-e2e.js:113` (the
`hitInsideNavLinks` check).

## Files changed

- `public/style.css` — one line in the mobile media query: `position:
absolute` → `position: fixed`
- `test-issue-1109-hamburger-dropdown-visible-e2e.js` — new E2E
- `.github/workflows/deploy.yml` — wire the new E2E into the suite

Fixes #1109

---------

Co-authored-by: openclaw-bot <bot@openclaw.local>
2026-05-07 09:39:29 -07:00
Kpa-clawbot 0eee922d5a ci: update go-server-coverage.json [skip ci] 2026-05-07 15:42:22 +00:00
Kpa-clawbot a0651c4740 ci: update go-ingestor-coverage.json [skip ci] 2026-05-07 15:42:21 +00:00