Secondary SDR panel: never present an unreported SDR count or run state as fact

QA (drb-qa-review) blockers: sdr_count defaulted to 1 for nodes that
never sent it, so the panel claimed 'reports 1 SDR (0 spare)'. It is now
None until reported, and the count is only quoted alongside a real
secondary_sdr_running report. Rows read 'Not reported' instead of
'Waiting for SDR' when the node hasn't said what's running (closes #187).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-09-27 14:14:42 -04:00
co-authored by Claude Opus 5.5
parent 3cbb0828ae
commit 012cca402a
4 changed files with 22 additions and 7 deletions
+1 -1
View File
@@ -114,7 +114,7 @@ class MQTTHandler:
"secondary_sdr_mode": payload.get("secondary_sdr_mode", "none"),
"secondary_sdr_priority": payload.get("secondary_sdr_priority", []),
"secondary_sdr_running": payload.get("secondary_sdr_running"),
"sdr_count": payload.get("sdr_count", 1),
"sdr_count": payload.get("sdr_count"), # None until reported, never a guessed 1
"enforce_override_timeout": payload.get("enforce_override_timeout", True),
"is_overridden": False,
"override_system_id": None,
+1 -1
View File
@@ -68,7 +68,7 @@ class NodeRecord(BaseModel):
# checkin, which is the source of truth; set via PATCH /nodes/{id}.
secondary_sdr_priority: List[str] = []
secondary_sdr_running: Optional[List[str]] = None # what the node reports actually running
sdr_count: int = 1 # self-reported by the node's checkin, best-effort
sdr_count: Optional[int] = None # self-reported by the node's checkin; None = never reported
enforce_override_timeout: bool = True
is_overridden: bool = False
override_system_id: Optional[str] = None
@@ -22,6 +22,9 @@ function rowsFrom(priority: string[]): Row[] {
export function SecondarySdrPriority({ node, canEdit }: { node: NodeRecord; canEdit: boolean }) {
const priority = node.secondary_sdr_priority ?? [];
// null/absent = the node has never reported (older firmware, container down
// at checkin): unknown, not "nothing running" (server-26#187).
const reported = node.secondary_sdr_running != null;
const running = node.secondary_sdr_running ?? [];
const [rows, setRows] = useState<Row[]>(() => rowsFrom(priority));
const [dirty, setDirty] = useState(false);
@@ -62,8 +65,9 @@ export function SecondarySdrPriority({ node, canEdit }: { node: NodeRecord; canE
}
}
const sdrCount = node.sdr_count ?? 1;
const spare = Math.max(sdrCount - 1, 0);
// Only quote a count the node actually sent alongside its running list; a
// bare sdr_count may be the Firestore default, not a report.
const sdrCount = reported ? node.sdr_count : undefined;
let rank = 0;
return (
@@ -71,13 +75,24 @@ export function SecondarySdrPriority({ node, canEdit }: { node: NodeRecord; canE
<h2 className="text-sm font-semibold text-gray-400 uppercase tracking-wider mb-1">Secondary SDRs</h2>
<p className="text-xs text-gray-500 font-mono mb-3">
OP25 always keeps its own SDR. Every other SDR runs the next enabled item, top first.
{" "}This node reports {sdrCount} SDR{sdrCount === 1 ? "" : "s"} ({spare} spare).
{" "}
{sdrCount != null
? `This node reports ${sdrCount} SDR${sdrCount === 1 ? "" : "s"} (${Math.max(sdrCount - 1, 0)} spare).`
: "This node hasn't reported its SDRs yet."}
</p>
<div className="bg-gray-900 border border-gray-800 rounded-lg divide-y divide-gray-800 font-mono text-sm">
{rows.map((row, i) => {
const meta = MODES.find((x) => x.mode === row.mode)!;
const isRunning = running.includes(row.mode);
const state = !row.enabled ? "Off" : dirty ? "Unsaved" : isRunning ? "Running" : "Waiting for SDR";
const state = !row.enabled
? "Off"
: dirty
? "Unsaved"
: !reported
? "Not reported"
: isRunning
? "Running"
: "Waiting for SDR";
return (
<div key={row.mode} className="flex items-center gap-3 px-4 py-2.5">
<span className="w-4 text-right text-gray-600 text-xs">{row.enabled ? ++rank : ""}</span>
+1 -1
View File
@@ -58,7 +58,7 @@ export interface NodeRecord {
secondary_sdr_priority?: string[];
/** What the node's last checkin reported actually running. */
secondary_sdr_running?: string[] | null;
sdr_count?: number;
sdr_count?: number | null; // null = never reported
enforce_override_timeout?: boolean;
is_overridden?: boolean;
override_system_id?: string | null;