Commit Graph
3 Commits
Author SHA1 Message Date
Jesper B 8c48f2b49a feat(#1784): wire display consumers to path trust threshold (#1841)
Fixes #1784

## Summary

Step 4 of the #1784 multi-PR project — wires all frontend display
consumers to respect the configured `pathTrust.minHashBytesForMapping`
value.

**Depends on:** #1840 (must be merged first — provides
`MC_meetsPathTrust` / `MC_pathBelowTrust` / `MC_getPathTrustThreshold`
helpers and `PATH_TRUST` global).

## Changes

### `map.js` — trust-gated route display
- `drawPacketRoute` checks `MC_pathBelowTrust` before drawing polylines
- When all path hops are below the configured threshold, shows a "Route
not displayed" message with config guidance instead of speculative
polylines
- Cleans up the trust message control when a new route is drawn

### `analytics.js` — subpath trust filtering
- `renderTable` in `renderSubpaths` filters route patterns whose hops
are below trust threshold
- Combined filter logic: both the 1-byte hide toggle AND trust threshold
are applied together
- Info line shows which filters are active ("1-byte hide + 2-byte
trust", etc.)
- No-data message explains which filters caused exclusion

### `route-view.js` — speculative path annotation
- Path picker groups tagged with `belowTrust` flag when any hop doesn't
meet the configured threshold
- Speculative paths show `(speculative, <N-byte hops)` annotation with
tooltip explaining the trust threshold
- Tooltip includes guidance on changing
`pathTrust.minHashBytesForMapping` in config.json

### `live.js` — Paths Through widget
- `_pathHopsBelowTrust()` helper checks whether all hops in a path are
below trust threshold
- Widget fallback message distinguishes between "1-byte filtered"
(display toggle) and "N-byte trust threshold" (server config)
- Message includes the config key for operators to adjust

### `nodes.js` — confidence weight adjustment
- `modeWeight` initialization considers the trust threshold
- Hash modes below threshold get zero confidence weight
- Bucket-0 (legacy/unknown) excluded at threshold >= 2 per #1784
bucket-0 policy

## Testing

`test-issue-1633-hide-1byte-hops.js`:
- 5 new source-grep guards verifying each consumer references the trust
threshold helpers
- All 26 tests passing (21 existing + 5 new)

## Files changed (6 files, +136/-6)

```
public/analytics.js                | 28 ++++++++++++++++++---
public/live.js                     | 19 ++++++++++++++-
public/map.js                      | 21 ++++++++++++++++
public/nodes.js                    |  8 ++++++
public/route-view.js               | 16 +++++++++++-
test-issue-1633-hide-1byte-hops.js | 50 ++++++++++++++++++++++++++++++
```

---

**Depends on:** #1840
**Written by:** DeepSeek V4 Pro in Max Mode
2026-09-02 09:50:09 +02:00
eba9e89a72 fix(#1203): path-inspector — singleflight + stale-while-revalidate (#1208)
Red commit: c84a8f575a (CI run: pending
push)

Fixes #1203 — path-inspector 503 storm.

Three sub-fixes, each shipped as red→green per AGENTS TDD:

**A. Singleflight on rebuild** (`ensureNeighborGraph`)
Hand-rolled `sync.Mutex + chan` singleflight — no new deps (x/sync was
not in cmd/server's go.mod). Concurrent callers attach to one in-flight
rebuild instead of N parallel `BuildFromStore` goroutines.
- Red: `7340f23b` — test asserts ≤1 build under 10 concurrent callers
(saw 10 on master)
- Green: `abac6b3c`

**B. Stale-while-revalidate** (`handlePathInspect`)
Stale non-nil graph is served immediately with `"stale": true` while a
background rebuild runs (deduped by A). The 2s synchronous gate is gone.
Stale responses are not cached, so the next request after rebuild lands
fresh.
- Red: `c84a8f57` — test asserts 200+`stale:true`+rebuild-kickoff
(master returned 503)
- Green: `5eb86975`

**C. Cold-start 503 still kicks rebuild**
True cold start (`graph == nil`) is the only path that still returns 503
`{"retry": true}`, but it now spawns an async `ensureNeighborGraph` so
the very next request warms up.
- Green test: `f5ac7059` (passed on top of A+B)

Singleflight verified: `TestEnsureNeighborGraph_Singleflight`
Stale-while-revalidate verified:
`TestHandlePathInspect_StaleWhileRevalidate`
Cold-start verified: `TestHandlePathInspect_ColdStartKicksRebuild`

**Acceptance criteria (issue #1203):**
- [x] Concurrent requests share ONE rebuild
- [x] Stale non-nil graph served with `stale:true` async
- [x] 503 only on true cold-start
- [x] Cold-start 503 kicks rebuild → follow-up warm
- [ ] p99 < 500ms under load (not unit-testable; design satisfies it)
- [x] No regression in existing tests

**Out of scope (per issue):** 5-min TTL constant, `BuildFromStore` perf,
`/api/analytics/topology`, persist-lock contention.

No new deps.

---------

Co-authored-by: corescope-bot <bot@corescope.local>
Co-authored-by: corescope-bot <bot@corescope.dev>
2026-05-15 22:46:28 -07:00
Kpa-clawbotandyou 54f7f9d35b feat: path-prefix candidate inspector with map view (#944) (#945)
## feat: path-prefix candidate inspector with map view (#944)

Implements the locked spec from #944: a beam-search-based path prefix
inspector that enumerates candidate full-pubkey paths from short hex
prefixes and scores them.

### Server (`cmd/server/path_inspect.go`)

- **`POST /api/paths/inspect`** — accepts 1-64 hex prefixes (1-3 bytes,
uniform length per request)
- Beam search (width 20) over cached `prefixMap` + `NeighborGraph`
- Per-hop scoring: edge weight (35%), GPS plausibility (20%), recency
(15%), prefix selectivity (30%)
- Geometric mean aggregation with 0.05 floor per hop
- Speculative threshold: score < 0.7
- Score cache: 30s TTL, keyed by (prefixes, observer, window)
- Cold-start: synchronous NeighborGraph rebuild with 2s hard timeout →
503 `{retry:true}`
- Body limit: 4096 bytes via `http.MaxBytesReader`
- Zero SQL queries in handler hot path
- Request validation: rejects empty, odd-length, >3 bytes, mixed
lengths, >64 hops

### Frontend (`public/path-inspector.js`)

- New page under Tools route with input field (comma/space separated hex
prefixes)
- Client-side validation with error feedback
- Results table: rank, score (color-coded speculative), path names,
per-hop evidence (collapsed)
- "Show on Map" button calls `drawPacketRoute` (one path at a time,
clears prior)
- Deep link: `#/tools/path-inspector?prefixes=2c,a1,f4`

### Nav reorganization

- `Traces` nav item renamed to `Tools`
- Backward-compat: `#/traces/<hash>` redirects to `#/tools/trace/<hash>`
- Tools sub-routing dispatches to traces or path-inspector

### Store changes

- Added `LastSeen time.Time` to `nodeInfo` struct, populated from
`nodes.last_seen`
- Added `inspectMu` + `inspectCache` fields to `PacketStore`

### Tests

- **Go unit tests** (`path_inspect_test.go`): scoreHop components, beam
width cap, speculative flag, all validation error cases, valid request
integration
- **Frontend tests** (`test-path-inspector.js`): parse
comma/space/mixed, validation (empty, odd, >3 bytes, mixed lengths,
invalid hex, valid)
- Anti-tautology gate verified: removing beam pruning fails width test;
removing validation fails reject tests

### CSS

- `--path-inspector-speculative` variable in both themes (amber, WCAG AA
on both dark/light backgrounds)
- All colors via CSS variables (no hardcoded hex in production code)

Closes #944

---------

Co-authored-by: you <you@example.com>
2026-04-30 23:28:16 -07:00