feat(controller-status): render election term/time in ctrlstatus CLI (task 7.5)

cmd_ctrlstatus (src/harness/test.c) now prints electedTerm/electedAt
right after the Primary: line, gated on the same NULLSTR(primaryName)
"unknown" check that line already uses. electedTerm prints the existing
term field verbatim (no new wire field, per design's Locked Decision 1);
electedAt reuses the existing ctrlstatus_format_time_ms formatter
already used for responderTime, falling back to "unknown" on a NULL
format result. No leakage of a stale term/elected_at_ms when no primary
is known.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
This commit is contained in:
Rongsong Shen 2026-09-16 07:54:04 +00:00
parent 93f32b5d84
commit d982d34eb5
No known key found for this signature in database
GPG key ID: 5BCDAAE0123E9FE2
2 changed files with 25 additions and 1 deletions

View file

@ -124,7 +124,7 @@
- _Boundary: ctrlstatus_fill_
- _Depends: 7.1_
- [ ] 7.5 Render the election term and time in the `ctrlstatus` client command
- [x] 7.5 Render the election term and time in the `ctrlstatus` client command
- Print the primary's election term and election time next to the primary's identity in the client command's output, rendering the election time on the same clock/format already used for the responder snapshot timestamp; render both as "unknown" whenever the primary identity itself is reported as unknown.
- Observable: piping `ctrlstatus` through the client prints the election term and a log-comparable election-time string alongside the existing fields when a primary is known, and prints "unknown" for both when it is not.
- _Requirements: 12.1, 12.3, 12.4, 12.6_

View file

@ -3097,6 +3097,30 @@ int cmd_ctrlstatus(int argc, char* argv[])
printf("Primary: %s\n",
NULLSTR(status->primaryName) ? "unknown" : status->primaryName);
/* Election term + time of the CURRENT primary (Req 12.1/12.3/12.4/12.6):
* gated on the SAME primaryName-known/unknown derivation the Primary:
* line above already computes (Req 2.2/2.3) -- a stale/learned
* elected_at_ms left over from a since-lost primary must never surface
* once primaryName itself reports "unknown" (design.md Locked Decision
* 3). electedTerm is DERIVED client-side from the existing `term` field
* (no new wire field, design.md Locked Decision 1); electedAt renders
* `elected_at_ms` on the same clock/format as responderTime below,
* reusing ctrlstatus_format_time_ms (design.md Locked Decision 4). */
if (NULLSTR(status->primaryName)) {
printf("electedTerm: unknown\n");
printf("electedAt: unknown\n");
} else {
char etbuf[64];
printf("electedTerm: %llu\n", (unsigned long long)status->term);
if (ctrlstatus_format_time_ms(status->elected_at_ms, etbuf,
sizeof(etbuf)) != NULL) {
printf("electedAt: %s\n", etbuf);
} else {
printf("electedAt: unknown\n");
}
}
/* Answering node + role, framed as a property of the responder and kept
* DISTINCT from the authoritative Primary line above (Req 3.1/3.2/3.3): a
* transient responder role (electing/initializing) must not be misread as