Commit Graph
4 Commits
Author SHA1 Message Date
40f664c587 chore(#1859): gofmt sweep + gofmt/go vet CI gate (rebase of #1881) (#1941)
Rebase of #1881 by @SaarMesh-Bot onto current master. Their three
commits are preserved, two of them cherry-picked with authorship intact;
the sweep itself had to be regenerated. Opened as a new PR rather than
force-pushing their branch.

Closes #1881 once merged. Addresses parts 1 and 3 of #1859; part 2
landed as #1937.

## Why regenerated rather than merged

The sweep in #1881 was cut on 2026-09-02 07:13 and roughly forty PRs
landed after it, so it went `CONFLICTING/DIRTY`. Re-running `gofmt` on
current master is cheaper and less error-prone than resolving 72
conflicts that are all whitespace. The drift it fixes also grew in the
meantime: 66 files now, against 72 then, but spread differently.

## The three commits

1. **`style(#1859)`** — `gofmt -w` across the 14 modules. 66 files.
2. **`test(#1859)`** — @SaarMesh-Bot's fix for the one `go vet`
copylocks finding, `cmd/ingestor/coverage_boost_test.go`: the range
variable copied a `Config` embedding `sync.Once`. Cherry-picked
unchanged.
3. **`ci(#1859)`** — @SaarMesh-Bot's CI step that fails on gofmt drift
or vet findings, plus `.git-blame-ignore-revs`. Cherry-picked with one
change, noted in the commit message: the ignore file pointed at
`04bc80ee`, the sweep commit on their branch, which does not exist on
this base and would make `git blame --ignore-revs-file` error. Repointed
at `d3a02599`, the sweep here.

## Verification

The claim "formatting only" is checked twice rather than asserted:

- Every changed file is byte-identical to `gofmt(previous content)`. 0
of 66 deviate.
- With line comments and all whitespace stripped, 0 of 66 files differ,
so no code outside comments changed.

14 of the 66 also show doc-comment reflow. Since Go 1.19 `gofmt`
re-indents indented comment blocks to tabs and inserts a blank comment
line before them; the behavior matrix above `resolveHopWithContext` in
`cmd/ingestor/path_resolver.go` is a clear example. That is gofmt's own
output, not an edit, but it is worth naming because it makes the diff
look larger than "whitespace" suggests.

The gate was run locally exactly as the workflow runs it: `gofmt` clean,
and `go vet` clean in all 14 modules, including `cmd/ingestor` which is
what commit 2 fixes.

Suites: `cmd/server` ok (80.7s), `internal/packetpath` ok (2.3s),
`cmd/ingestor` passes except
`TestWriteStatsAtomic_SymlinkAtDestIsReplaced`, which fails identically
on bare master with "A required privilege is not held by the client"
(Windows symlink privilege on my host, not code).

## Sequencing

This should go last in the queue. The sweep touches 66 files, so merging
it before the remaining open Go PRs gives each of them a conflict about
nothing but formatting. After it lands the gate is active, and any PR
with drift fails CI until it runs `gofmt -w`.

Excluded from the sweep: the misnamed `Dockerfile.go`, which is a
Dockerfile that gofmt cannot parse (the workflow excludes it too), and
`docs/DEPLOYMENT.md`, which a case-insensitive filesystem surfaces as a
spurious modification against `docs/deployment.md` and is unrelated.

---------

Co-authored-by: SaarMesh-Bot <300107934+SaarMesh-Bot@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-03 18:52:03 +02:00
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