You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(api): say why the public anchor list is empty instead of implying health (#9721)
`GET /v1/public/decision-ledger/anchors` returned `{"anchors":[]}` for three
completely different situations — anchoring was never configured, there is no
ledger to anchor, or it is configured and simply has not run yet. From outside
they were indistinguishable, and an empty list reads as a healthy one, so a
silently misconfigured deployment looked exactly like a working one.
That is the gap ledger-anchor-persistence.ts's own header set out to close
("an operator whose anchoring silently fails could quietly regress the ledger
back to tamper-evident-only with no visible signal"): the guarantee only held
AFTER the scheduler's two guards passed, and both of those return without
writing anything a reader can see.
The response now carries `status`: anchored | empty_ledger | unconfigured |
pending. The predicate is pure and its guard order deliberately mirrors
runScheduledLedgerAnchor's own — tip first, then signing key — so the published
status always names the same reason the scheduler would act on rather than
offering a second opinion.
Only computed for an unfiltered first page: with a backend/before filter an
empty page means "none matched", which is a different question from "is
anchoring running at all", so `status` is omitted there rather than answering
the wrong one.
Refs #9719
Copy file name to clipboardExpand all lines: apps/loopover-ui/public/openapi.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -20802,7 +20802,7 @@
20802
20802
],
20803
20803
"responses": {
20804
20804
"200": {
20805
-
"description": "{ anchors: [{ id, seq, rowHash, keyId, backend, backendRef, status, error, createdAt }], nextBefore} — a failed attempt is returned identically to a successful one, never filtered out or reshaped"
20805
+
"description": "{ anchors: [{ id, seq, rowHash, keyId, backend, backendRef, status, error, createdAt }], nextBefore, status } — a failed attempt is returned identically to a successful one, never filtered out or reshaped. The top-level `status` (anchored | empty_ledger | unconfigured | pending) says why the list looks as it does, so an empty list cannot be mistaken for a healthy one; it is omitted when a backend/before filter is applied, where empty just means none matched"
200: {description: "{ anchors: [{ id, seq, rowHash, keyId, backend, backendRef, status, error, createdAt }], nextBefore} — a failed attempt is returned identically to a successful one, never filtered out or reshaped"},
1909
+
200: {description: "{ anchors: [{ id, seq, rowHash, keyId, backend, backendRef, status, error, createdAt }], nextBefore, status } — a failed attempt is returned identically to a successful one, never filtered out or reshaped. The top-level `status` (anchored | empty_ledger | unconfigured | pending) says why the list looks as it does, so an empty list cannot be mistaken for a healthy one; it is omitted when a backend/before filter is applied, where empty just means none matched"},
0 commit comments