code wiki / _hdl_build / nx_apistack_idempotency.nx

nx_apistack_idempotency.nx

buildroot/runtime/_hdl_build/nx_apistack_idempotency.nx

11245 B245 linesdepth 6pulls 6 transitivereach 62 importersview sourcekind librarytopic apistack
docsdependenciesstructsconstsfunctions

about

Retained idempotency evidence. Sequential replay is not an exactly-once transaction: mutation and journal commit remain separate. Missing or malformed evidence is not NEW. THE READ LOCK IS SHARED (2026-09-16, debt 1789503583). A reader used to take LOCK_EX|LOCK_NB, so a concurrent reader, or the recorder inside its one append+fsync, made every keyed tools/call fail closed as EVIDENCE_UNAVAILABLE and the tools API could not be re-shipped from this tree. Readers now take LOCK_SH and wait: a recorder holds LOCK_EX for exactly one append and one fsync, and flock releases on death, so the wait is bounded by one write and is never held by another reader. Blocking is chosen over a retry budget on purpose: a budget is a magic number that fails closed under exactly the load that makes the wait long, and the old immediate refusal WAS the defect. MALFORMED ROWS ARE QUARANTINED, NOT POISONOUS (same day). One row with a CR, a NUL, two TABs, no TAB, or a torn tail used to refuse the whole ledger for every key. A malformed row is now skipped and COUNTED (r.quarantined, with the first bad line in r.first_bad_line, both handed out by id_lookup_q) -- EXCEPT when its key field is the key being looked up: evidence about the sought key that cannot be read is not NEW, so that one lookup still fails closed (EBADMSG) exactly as before. A torn last row (no trailing newline) is a torn append and is judged by the same rule.

dependencies 2 imports · 13 importers

nx_syscalls.nx nx_fio.nx nx_apistack_idempotency.nx nx_apistack_idempotency_epoch_cand nx_apistack_idempotency_gate.nx nx_fsops_write.nx nx_fsops_write_combined_t150.nx nx_fsops_write_dynamic_t145.nx nx_id_concurrent_canonical_gate_t1 nx_id_evidence_canonical_gate_t190 nx_id_ledger_audit_t190.nx nx_id_ledger_claim_audit_t219.nx nx_id_ledger_existing_keys_audit_t

diagram shows first 10 each side; +0 more imports, +3 more importers in the complete lists below.

imports: nx_syscalls.nxnx_fio.nx

imported by: nx_apistack_idempotency_epoch_candidate_t293.nxnx_apistack_idempotency_gate.nxnx_fsops_write.nxnx_fsops_write_combined_t150.nxnx_fsops_write_dynamic_t145.nxnx_id_concurrent_canonical_gate_t190.nxnx_id_evidence_canonical_gate_t190.nxnx_id_ledger_audit_t190.nxnx_id_ledger_claim_audit_t219.nxnx_id_ledger_existing_keys_audit_t219.nxnx_id_legacy_reconcile_gate_t219.nxnx_toolcall_idem_lib.nxnx_writer_bound_canonical_gate_t190.nx

structs

28struct NxIdEvidence
200struct NxIdLegacyRow

consts

17const ID_NOT_FOUND:i64=0-1
18const ID_EVIDENCE_ERROR:i64=0-2
19const ID_MISSING:i64=0-3
20const ID_CAPACITY:i64=0-4
21const ID_RESOURCE:i64=0-5
22const ID_SIGNED_MAX:i64=9223372036854775807
23const ID_O_RDONLY:i64=0
24const ID_O_RDWR_APPEND_CREATE:i64=1090
25const ID_O_NONBLOCK:i64=2048
26const ID_O_NOFOLLOW:i64=131072
27const ID_O_CLOEXEC:i64=524288
193const ID_ROW_EMPTY:i64=1
194const ID_ROW_COMMENT:i64=2
195const ID_ROW_NO_TAB:i64=4
196const ID_ROW_EXTRA_TAB:i64=8
197const ID_ROW_EMPTY_KEY:i64=16
198const ID_ROW_CONTROL:i64=32
199const ID_ROW_UNTERMINATED:i64=64

functions

31func id_evidence_init(r:*NxIdEvidence)->i64
called by 1: id_read_evidence
35func id_evidence_close(r:*NxIdEvidence)->i64
39func id_field_valid(p:*u8,n:i64,key:i64)->i64
46func id_read_evidence(path:*u8,key:*u8,key_n:i64,r:*NxIdEvidence)->i64
120func id_lookup_q(path:*u8,key:*u8,key_n:i64,out:*u8,cap:i64,q:*i64)->i64
134func id_lookup(path:*u8,key:*u8,key_n:i64,out:*u8,cap:i64)->i64
137func id_seen(path:*u8,key:*u8,key_n:i64)->i64
146func id_record(path:*u8,key:*u8,key_n:i64,result:*u8,result_n:i64)->i64
206func id_legacy_row_next(source:*u8,bytes:i64,start:i64,row:*NxIdLegacyRow)->i64