code wiki / (root) / nx_toolcall_idem_candidate_t190.nx

nx_toolcall_idem_candidate_t190.nx

buildroot/runtime/nx_toolcall_idem_candidate_t190.nx

11425 B231 linesdepth 7pulls 7 transitivereach 4 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_toolcall_idem_lib.nx -- IDEMPOTENCY KEYS ON tools/call (/compare/dataio DI4 `ta_idempotency_key`, 2026-09-05). WHY: every seat's write to the estate crosses ONE transport, and that transport answers "Outcome Unknown" whenever the backend accepted a request and produced no reply inside the edge window. MEASURED the day this landed: nine such replies in one seat session, each adjudicated by hand by re-reading the artifact, and two verb shapes with NO safe retry at all (a self-anchored insert applies twice; an append has no anchor to lose). The field's answer is the IETF Idempotency-Key: the caller names the request, the server records the FIRST outcome under that name, and a retry carrying the same name is REPLAYED, never re-executed. Done sovereign, on the lane every seat already uses: params._idem = "<token>" (a sibling of _cap and _async; absent = the call behaves exactly as before) THE OUTCOME IS RESERVED BEFORE IT IS EXECUTED. A key is claimed with O_EXCL on <dir>/idem_<digest>.claim -- the same primitive the job lane reserves ids with -- so two racing calls under one key cannot both execute: the loser reads IN-FLIGHT. The first APPLIED outcome is then recorded in the estate's append-only ledger (nx_apistack_idempotency: first-write-wins, read whole) as ONE line: lane=async|promote tool=<t> job=<id> the job id is the outcome; the caller polls it like any JOB-STARTED lane=sync|http tool=<t> exit=<ec> bytes=<n> out=<dir>/idem_<digest>.out the bytes are kept so the replay is the same text HONESTY LIMITS, stated: a claim whose holder died before recording (the daemon killed between reserve and record) reads IN-FLIGHT for as long as the claim exists; the reply names the claim's age so the caller can adjudicate the artifact -- today's situation, but confined to that one window instead of every call. A refused or harness-failed run RELEASES its claim: nothing was applied, so a retry must be judged afresh (the same rule nx_fsops_write keeps). Every path is parameterised by (ledger, dir) so the gate drives it on /tmp fixtures; the API passes the consts. license_tier: ORIGINAL No hw writes (Rule 26).

dependencies 3 imports · 1 importers

nx_syscalls.nx nx_apistack_idempotency_candidate_ nx_sha256.nx nx_toolcall_idem_candidate_t19 nx_tools_api_idem_candidate_t190.n

imports: nx_syscalls.nxnx_apistack_idempotency_candidate_t190.nxnx_sha256.nx

imported by: nx_tools_api_idem_candidate_t190.nx

structs

none

consts

26const TI_LEDGER: *u8 = "knowledge/status/toolcall_idem.jrnl" as *u8
27const TI_DIR: *u8 = "_jobs" as *u8
28const TI_KEY_MIN_CH: i64 = 33 // printable ASCII, no whitespace: a TAB or newline would corrupt the ledger row
29const TI_KEY_MAX_CH: i64 = 126
30const TI_KEY_MAX_LEN: i64 = 200 // a key is a token, not a payload; the ledger row must stay one line
31const TI_HEX_CH: i64 = 16 // 64 bits of the key's SHA-256 name the claim and the replay artifact
32const TI_HEX_BYTES: i64 = 8
33const TI_ROW_CAP: i64 = 1024
34const TI_PATH_CAP: i64 = 512
35const TI_DIGEST_B: i64 = 32
36const TI_SYS_OPENAT: i64 = 257
37const TI_SYS_UNLINKAT: i64 = 263
38const TI_AT_FDCWD: i64 = 0 - 100
39const TI_OEXCL: i64 = 193 // O_CREAT|O_EXCL|O_WRONLY
40const TI_CLAIMMODE: i64 = 420
43const TI_NOKEY: i64 = 0 // no _idem present: the call behaves exactly as before
44const TI_BADKEY: i64 = 1 // present but not a token: REFUSE before executing
45const TI_NEW: i64 = 2 // reserved by this call: execute, then record
46const TI_REPLAY: i64 = 3 // recorded: emit the first outcome, do NOT execute
47const TI_EVIDENCE_ERROR:i64=5 // retained ledger is unreadable, malformed, missing or result exceeds caller extent
48const TI_INFLIGHT: i64 = 4 // reserved by another call that has not recorded yet: do NOT execute, say so

functions

50func ti_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
51func ti_cat(d: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; var oo: i64 = o; while s[i] != (0 as u8) { d[oo] = s[i]; oo = oo + 1; i = i + 1 } d[oo] = 0 as u8; return oo }
52func ti_catb(d: *u8, o: i64, s: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { d[o + i] = s[i]; i = i + 1 } d[o + n] = 0 as u8; return o + n }
53func ti_catn(d: *u8, o: i64, v: i64) -> i64
65func ti_hexd(v: i64) -> i64 { if v < 10 { return 48 + v } return 87 + v }
called by 1: ti_key_hex
66func ti_is_digit(c: i64) -> i64 { if c >= 48 { if c <= 57 { return 1 } } return 0 }
called by 1: ti_row_int
67func ti_state_name(st: i64) -> *u8
77func ti_key_ok(key: *u8, n: i64) -> i64
called by 1: ti_classify
90func ti_key_hex(key: *u8, n: i64, out: *u8) -> i64
103func ti_claim_path(dir: *u8, hex: *u8, out: *u8) -> i64 { var o: i64 = ti_cat(out, 0, dir); o = ti_cat(out, o, "/idem_" as *u8); o = ti_cat(out, o, hex); o = ti_cat(out, o, ".claim" as *u8); return o }
104func ti_out_path(dir: *u8, hex: *u8, out: *u8) -> i64 { var o: i64 = ti_cat(out, 0, dir); o = ti_cat(out, o, "/idem_" as *u8); o = ti_cat(out, o, hex); o = ti_cat(out, o, ".out" as *u8); return o }
called by 2: ti_row_syncta_mcp_call calls 1: ti_cat
108func ti_reserve(dir: *u8, hex: *u8, now: i64) -> i64
123func ti_release(dir: *u8, hex: *u8) -> i64
called by 1: ta_mcp_call calls 2: sys_mmapti_claim_path
131func ti_row_int(row: *u8, needle: *u8) -> i64
158func ti_row_has(row: *u8, needle: *u8) -> i64
calls 1: ti_slen
173func ti_claim_age(dir: *u8, hex: *u8, now: i64) -> i64
188func ti_classify(ledger: *u8, dir: *u8, key: *u8, n: i64, hex_out: *u8, row_out: *u8, rowcap: i64, now: i64) -> i64
206func ti_row_job(row: *u8, cap: i64, lane: *u8, tool: *u8, tl: i64, jid: i64) -> i64
called by 1: ta_mcp_call calls 3: ti_catti_catbti_catn
215func ti_row_sync(row: *u8, cap: i64, lane: *u8, tool: *u8, tl: i64, ec: i64, bytes: i64, dir: *u8, hex: *u8) -> i64
231func ti_record(ledger: *u8, key: *u8, n: i64, row: *u8, rl: i64) -> i64 { return id_record(ledger, key, n, row, rl) }
called by 1: ta_mcp_call calls 1: id_record