Repository navigation
Fix organization safety threshold reporting zero - #67
Open
tmosleyIII wants to merge 2 commits into
Open
tmosleyIII wants to merge 2 commits into
tmosleyIII wants to merge 2 commits into
Conversation
Aggregating by organization maps every trusted validator to its organization and skips the ones that belong to none. When nothing survives that mapping, the self-reference each group receives is all that is left, and the threshold clamp makes it satisfiable: an organization trusting only itself, with a threshold of one. That is a quorum of one. It is disjoint from every other quorum, so the FBAS containing it has no quorum intersection, so python-fbas answers every splitting set with zero however the real validators are wired. It is also an artifact rather than a trust declaration. The organization's validators do trust other validators; those validators just belong to no organization in the set being aggregated, so the mapping dropped them. withoutSelfTrustingGroups leaves such a group out. It is deliberately a separate step rather than part of aggregateByOrganization: the narrow top-tier aggregation has no such groups, and dropping them there would silently move a figure that is answering its question correctly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
python-fbas answers with a minimal splitting-set cardinality of zero when the FBAS it was handed has no quorum intersection: two disjoint quorums already exist, so no organization has to fail for safety to break. It is a statement about the FBAS, not a safety threshold. analyzeNetworkWideOrgSplittingSet returned it anyway, and the override below only skips undefined, so zero won over a perfectly good restricted answer. On the dashboard that rendered as a Safety thresholds chart whose Organization line sat at zero, and a verdict card reading "Core forks if 4 orgs collude" directly above "Nodes cut off by 0 orgs". Every neighbouring path in this file already avoids emitting zero for exactly this reason, and "No splitting set found" arrives as an error rather than a zero, so there is no real answer of zero being discarded here. Report it as not computed and let the restricted figure stand. The preceding commit removes the known cause; this is the backstop for any other degenerate shape, and it logs when it fires so a recurrence is visible rather than silent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tmosleyIII
temporarily deployed
to
obsrvr-radar-staging
November 10, 2026 15:14 — with
GitHub Actions
Inactive
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The Safety thresholds card on production has an Organization line pinned at zero, next to a healthy top-tier figure. The verdict card shows the contradiction directly: "Core forks if 4 orgs collude" sitting above "Nodes cut off by 0 orgs".
The network is fine. The reporting is not.
What the scans show
Every scan reports it, while the restricted answers in those same scans are healthy —
splittingSetsMinSizeof 4, 5 and 2 across the aggregated levels, andsplittingSetsTopTierMinSizeof 4–6. Only the Organization series is affected; Node, Country and ISP are untouched.Why zero
min_size: 0is not an error code and not a safety threshold. It is python-fbas reporting that the FBAS it was handed has no quorum intersection: two disjoint quorums already exist, so zero organizations have to fail for safety to break.app.pyturns "No splitting set found" into an error precisely so it never arrives as a zero, so zero always means "already split".The FBAS being handed over is already split because of how the wider set aggregates.
mergeQuorumSetsForOrganizationsmaps each trusted validator to its organization and skips the ones that belong to none, then always adds a self-reference and clamps the threshold down to the surviving count. An organization whose validators trust keys that no organization claims therefore comes out asthreshold 1, trusts [itself]— a quorum of one, disjoint from every other quorum.Confirmed against the real aggregator:
NetworkScannerfeeds this path every validating node (103 → 23 orgs) rather than the 33 core nodes (→ 11 orgs), so the wider set is exactly where these peripheral organizations enter. Nothing caught it either:validateAggregatedNodesonly rejectsthreshold <= 0and empty quorum sets, andthreshold: 1, validators: [self]passes clean — which is why the logs show no aggregation warning.The two fixes
a1a22b0— stop the aggregation manufacturing a quorum of one.withoutSelfTrustingGroupsdrops organizations left trusting nothing but themselves. Deliberately a separate step rather than folded intoaggregateByOrganization: the narrow top-tier aggregation has no such groups, and filtering there would silently move a figure that is currently answering its question correctly. Organizations that still depend on the core are kept, so the feature keeps doing its job.8cf6dc1— never publish zero as a threshold. The override only skippedundefined, so0 !== undefinedmeant zero beat the real restricted answer. It now reports "not computed" and lets the restricted figure stand, and logs when it fires so a recurrence is visible rather than silent. Every neighbouring path in that file already avoids emitting zero for this exact reason.The first commit removes the known cause; the second is the backstop for any other degenerate shape.
Scope note
This is a reporting bug only — no measurement, scan or persistence behaviour changes, and the restricted org-level analysis is byte-identical. Users of the wider figure should see 4–5 instead of 0 on the next scan.
Verification
keeps the restricted answer rather than publishing zero; neutralising the filter fails 2 aggregator tests. Neither test is vacuous.tsc --buildclean, eslint clean, prettier applied.Not fixed here: the 1Y/30D views will still show the dip back to 2026-10-01, when
#65introduced the override — this corrects the figure going forward, it does not backfill stored measurements.🤖 Generated with Claude Code