From d982d34eb583646a91e491056697da0580db2d30 Mon Sep 17 00:00:00 2001 From: Rongsong Shen Date: Wed, 16 Sep 2026 07:54:04 +0000 Subject: [PATCH] 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 Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC --- .kiro/specs/controller-status/tasks.md | 2 +- src/harness/test.c | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/.kiro/specs/controller-status/tasks.md b/.kiro/specs/controller-status/tasks.md index dbfc22fe..2cd58bff 100644 --- a/.kiro/specs/controller-status/tasks.md +++ b/.kiro/specs/controller-status/tasks.md @@ -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_ diff --git a/src/harness/test.c b/src/harness/test.c index 92c36271..f9108539 100644 --- a/src/harness/test.c +++ b/src/harness/test.c @@ -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