mirror of
https://github.com/Kpa-clawbot/meshcore-analyzer.git
synced 2026-06-30 03:02:16 +00:00
Red commit: e5668585da
Fixes #1534
## Problem
`cmd/ingestor/main.go:720` called `UpdateNodeDefaultScope` whenever a
packet was transport-scoped (`IsTransportScoped == true`), without
checking whether `matchScope()` actually returned a region match.
Transport-scoped adverts from non-matching regions carry `ScopeName=""`,
which then overwrote previously-correct `nodes.default_scope` values
with the empty string — surfacing as "unknown scope" / "--" in the node
sidebar.
## Fix
Extracted the guard into `shouldUpdateDefaultScope(pktData)` and added
the non-empty `ScopeName` check:
```go
return pktData.IsTransportScoped && pktData.ScopeName != ""
```
## TDD
- Red commit (`e5668585`): adds
`TestBuildPacketDataScopeMatchingNoMatch` + helper that mirrors the
buggy guard. CI must fail on assertion.
- Green commit (`aab7f5d7`): adds the `ScopeName != ""` check. Test
passes.
## Out of scope (deferred)
- The optional one-time backfill / migration marker removal described in
the issue — new matching adverts will self-correct existing rows.
- Refactor of `IsTransportScoped` + `ScopeName` into a typed wrapper.
## Files
- `cmd/ingestor/main.go` — guard + new helper
- `cmd/ingestor/main_test.go` — regression test
## Preflight
`bash ~/.openclaw/skills/pr-preflight/scripts/run-all.sh origin/master`
— clean.
---------
Co-authored-by: corescope-bot <bot@corescope.local>
This commit is contained in:
+10
-2
@@ -715,8 +715,8 @@ func handleMessage(store *Store, tag string, source MQTTSource, m mqtt.Message,
|
||||
log.Printf("MQTT [%s] node telemetry update error: %v", tag, err)
|
||||
}
|
||||
}
|
||||
// Update default_scope when advert carries a matched transport scope (#899)
|
||||
if pktData.IsTransportScoped {
|
||||
// Update default_scope when advert carries a matched transport scope (#899, #1534)
|
||||
if shouldUpdateDefaultScope(pktData) {
|
||||
if err := store.UpdateNodeDefaultScope(decoded.Payload.PubKey, pktData.ScopeName); err != nil {
|
||||
log.Printf("MQTT [%s] node default_scope update error: %v", tag, err)
|
||||
}
|
||||
@@ -1356,3 +1356,11 @@ func init() {
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
// shouldUpdateDefaultScope returns true when the packet carries a transport
|
||||
// scope whose region key matched (#1534). Without the ScopeName non-empty
|
||||
// guard, transport-scoped adverts from non-matching regions would overwrite
|
||||
// previously-correct default_scope values with the empty string.
|
||||
func shouldUpdateDefaultScope(pktData *PacketData) bool {
|
||||
return pktData.IsTransportScoped && pktData.ScopeName != ""
|
||||
}
|
||||
|
||||
@@ -1053,3 +1053,38 @@ func TestHandleMessageObserverIATAWhitelist(t *testing.T) {
|
||||
t.Errorf("observer from whitelisted IATA ARN should be accepted, got count=%d", count)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBuildPacketDataScopeMatchingNoMatch covers the #1534 regression: a
|
||||
// transport-scoped advert from a non-matching region carries
|
||||
// IsTransportScoped=true and ScopeName="". The default_scope update guard
|
||||
// must skip these packets so previously-correct scopes aren't overwritten
|
||||
// with the empty string.
|
||||
func TestBuildPacketDataScopeMatchingNoMatch(t *testing.T) {
|
||||
// Code1=2AB5 is the precomputed code for region "#test" (payload="hello",
|
||||
// payloadType=5). Build a region-key map for a DIFFERENT region so
|
||||
// matchScope() finds no match and returns "".
|
||||
const rawHex = "142AB500000068656C6C6F"
|
||||
otherKey, _ := hex.DecodeString("aabbccddeeff00112233445566778899")
|
||||
regionKeys := map[string][]byte{"#other": otherKey}
|
||||
|
||||
decoded, err := DecodePacket(rawHex, nil, false)
|
||||
if err != nil {
|
||||
t.Fatalf("DecodePacket: %v", err)
|
||||
}
|
||||
msg := &MQTTPacketMessage{Raw: rawHex}
|
||||
pktData := BuildPacketData(msg, decoded, "obs1", "region1", regionKeys)
|
||||
|
||||
if !pktData.IsTransportScoped {
|
||||
t.Fatalf("precondition: IsTransportScoped should be true (Code1 != 0000)")
|
||||
}
|
||||
if pktData.ScopeName != "" {
|
||||
t.Fatalf("precondition: ScopeName should be empty (no region match), got %q", pktData.ScopeName)
|
||||
}
|
||||
|
||||
// Regression assertion: when ScopeName is empty, the guard must skip the
|
||||
// UpdateNodeDefaultScope call so an empty value never overwrites a
|
||||
// previously-correct default_scope (#1534).
|
||||
if shouldUpdateDefaultScope(pktData) {
|
||||
t.Errorf("shouldUpdateDefaultScope = true for empty ScopeName; want false (would overwrite default_scope with \"\")")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user