mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-05-25 02:35:17 +00:00
2beeb2b324
Red commit:75563ce(CI run: pending — pushed at branch open) Follows up PR #1198 round-2 adversarial review (issue #1199). Six robustness / perf-hot-path / maintenance items, one commit per logical change. Stacked on top of `fix/issue-1197` (PR #1198) — base must move to `master` after #1198 merges. | # | Item | Commit(s) | Discipline | |---|---|---|---| | 1 | Brittle static-grep regex → go/parser AST walk in `resolve_context_callsites_test.go` |33d80b6(RED) →450236d(GREEN) | red→green | | 2 | `computeAnalyticsTopology` double-pass filter → materialize `filteredTxs` once |00005f6| refactor | | 3 | `BenchmarkBuildAggregateHopContextPubkeys` baseline + tiny smoke test |b520048| net-new bench/test | | 4 | `hopResolverPerTx` CONCURRENCY doc — single-goroutine invariant |155ff07| doc-only | | 5 | `schemaDegradationLogged` package-level `sync.Map` → PacketStore field |75563ce(RED) →7dbf193(GREEN) | red→green | | 6 | `buildHopContextPubkeys` `out` slice cap hint (`make([]string, 0, 16)`) |2040962| refactor | Items 2 & 6 are pure refactors — no test files modified for items 2 & 6 (per AGENTS.md exemption rule). Existing tests stay green and unaltered. Item 4 is doc-only (CONCURRENCY: comment); no behavior change. Item 3 adds a bench + a smoke assertion for the aggregate helper that previously had no coverage. Local arm64 baseline: ~72ms/op, 130k allocs at 5k txs. Items 1 & 5 follow red→green:33d80b6demonstrates the regex blindspot via a synthetic AST-detectable input the regex misses;75563cedemonstrates per-store log dedup leaks across instances. Both flips visible in branch history. Full `go test ./cmd/server/...` runs clean post-amend. Fixes #1199 --------- Co-authored-by: openclaw-bot <bot@openclaw.local>
143 lines
4.6 KiB
Go
143 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"testing"
|
|
)
|
|
|
|
// BenchmarkBuildHopContextPubkeys exercises the hot per-tx context builder
|
|
// at a realistic shape: ~50 nodes (mixed role), 6-hop path, sender + observer
|
|
// pubkey populated. Required by AGENTS.md hot-path benchmark rule (#1197 r1
|
|
// carmack #6).
|
|
func BenchmarkBuildHopContextPubkeys(b *testing.B) {
|
|
nodes := make([]nodeInfo, 0, 64)
|
|
for i := 0; i < 50; i++ {
|
|
nodes = append(nodes, nodeInfo{
|
|
PublicKey: fmt.Sprintf("%012x", i*0x101010101),
|
|
Role: "repeater",
|
|
Name: fmt.Sprintf("N%d", i),
|
|
ObservationCount: i * 3,
|
|
Lat: 37.0 + float64(i)*0.01,
|
|
Lon: -122.0 - float64(i)*0.01,
|
|
HasGPS: true,
|
|
})
|
|
}
|
|
pm := buildPrefixMap(nodes)
|
|
|
|
hops := []string{
|
|
nodes[1].PublicKey[:6], nodes[3].PublicKey[:6], nodes[5].PublicKey[:6],
|
|
nodes[7].PublicKey[:6], nodes[9].PublicKey[:6], nodes[11].PublicKey[:6],
|
|
}
|
|
pathJSON, _ := json.Marshal(hops)
|
|
decoded, _ := json.Marshal(map[string]interface{}{"pubKey": "cc4444444444"})
|
|
tx := &StoreTx{
|
|
PathJSON: string(pathJSON),
|
|
DecodedJSON: string(decoded),
|
|
ObserverID: "dd5555555555",
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = buildHopContextPubkeys(tx, pm)
|
|
}
|
|
}
|
|
|
|
// BenchmarkBuildAggregateHopContextPubkeys exercises the aggregate context
|
|
// builder at the hot scale called out by #1197 (subpath/topology bulk
|
|
// aggregations): ~5k txs sharing a node pool of ~50 prefixes. The aggregate
|
|
// builder unions per-tx contexts with its own dedupe map; this benchmark
|
|
// gives us a baseline so a future regression (e.g. accidental O(n²) dedupe)
|
|
// shows up immediately. No assertion threshold yet — see #1199 item 3.
|
|
func BenchmarkBuildAggregateHopContextPubkeys(b *testing.B) {
|
|
const numNodes = 50
|
|
const numTxs = 5000
|
|
|
|
nodes := make([]nodeInfo, 0, numNodes)
|
|
for i := 0; i < numNodes; i++ {
|
|
nodes = append(nodes, nodeInfo{
|
|
PublicKey: fmt.Sprintf("%012x", i*0x101010101),
|
|
Role: "repeater",
|
|
Name: fmt.Sprintf("N%d", i),
|
|
ObservationCount: i * 3,
|
|
Lat: 37.0 + float64(i)*0.01,
|
|
Lon: -122.0 - float64(i)*0.01,
|
|
HasGPS: true,
|
|
})
|
|
}
|
|
pm := buildPrefixMap(nodes)
|
|
|
|
txs := make([]*StoreTx, 0, numTxs)
|
|
for i := 0; i < numTxs; i++ {
|
|
hops := []string{
|
|
nodes[(i+1)%numNodes].PublicKey[:6],
|
|
nodes[(i+3)%numNodes].PublicKey[:6],
|
|
nodes[(i+5)%numNodes].PublicKey[:6],
|
|
nodes[(i+7)%numNodes].PublicKey[:6],
|
|
nodes[(i+9)%numNodes].PublicKey[:6],
|
|
nodes[(i+11)%numNodes].PublicKey[:6],
|
|
}
|
|
pathJSON, _ := json.Marshal(hops)
|
|
decoded, _ := json.Marshal(map[string]interface{}{
|
|
"pubKey": fmt.Sprintf("cc%010x", i),
|
|
})
|
|
txs = append(txs, &StoreTx{
|
|
PathJSON: string(pathJSON),
|
|
DecodedJSON: string(decoded),
|
|
ObserverID: fmt.Sprintf("dd%010x", i%32),
|
|
})
|
|
}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
_ = buildAggregateHopContextPubkeys(txs, pm)
|
|
}
|
|
}
|
|
|
|
// TestBuildAggregateHopContextPubkeysSmoke is a tiny correctness anchor for
|
|
// the aggregate helper: union over per-tx contexts, deduped. Lives next to
|
|
// the benchmark so the file ships an assertion (preflight gate). See #1199
|
|
// item 3.
|
|
func TestBuildAggregateHopContextPubkeysSmoke(t *testing.T) {
|
|
pm := buildPrefixMap([]nodeInfo{{PublicKey: "aabbccddeeff"}})
|
|
d1, _ := json.Marshal(map[string]interface{}{"pubKey": "1111111111"})
|
|
d2, _ := json.Marshal(map[string]interface{}{"pubKey": "2222222222"})
|
|
d3, _ := json.Marshal(map[string]interface{}{"pubKey": "1111111111"}) // dup
|
|
txs := []*StoreTx{
|
|
{DecodedJSON: string(d1)},
|
|
{DecodedJSON: string(d2)},
|
|
{DecodedJSON: string(d3)},
|
|
}
|
|
got := buildAggregateHopContextPubkeys(txs, pm)
|
|
if len(got) != 2 {
|
|
t.Fatalf("expected 2 deduped pubkeys, got %d (%v)", len(got), got)
|
|
}
|
|
// Content assertion — proves dedup actually keeps the right pubkeys
|
|
// (not just any 2). Without this the test would pass even if dedup
|
|
// returned, e.g., one pubkey twice or two unrelated pubkeys. See
|
|
// #1199 r1 review (adv #1).
|
|
wantSet := map[string]bool{"1111111111": true, "2222222222": true}
|
|
gotSet := map[string]bool{}
|
|
for _, pk := range got {
|
|
gotSet[pk] = true
|
|
}
|
|
for pk := range wantSet {
|
|
if !gotSet[pk] {
|
|
t.Fatalf("expected pubkey %q in deduped result, got %v", pk, got)
|
|
}
|
|
}
|
|
for pk := range gotSet {
|
|
if !wantSet[pk] {
|
|
t.Fatalf("unexpected pubkey %q in deduped result, got %v", pk, got)
|
|
}
|
|
}
|
|
if buildAggregateHopContextPubkeys(nil, pm) != nil {
|
|
t.Fatalf("nil tx slice must yield nil")
|
|
}
|
|
if buildAggregateHopContextPubkeys(txs, nil) != nil {
|
|
t.Fatalf("nil prefix map must yield nil")
|
|
}
|
|
}
|