From ec840b43cd8e85594f916e599e425e5530b7cf30 Mon Sep 17 00:00:00 2001 From: dmitrii-f-t27 Date: Sat, 17 Oct 2026 10:09:41 -0300 Subject: [PATCH] spec(port): port specs/port/trios/crates/trios-trainer/src/ledger.t27 (Closes #7324) Port gHashTag/trios:crates/trios-trainer/src/ledger.rs (at 8b229e9489ee, 165+ lines) as specs/port/trios/crates/ trios-trainer/src/ledger.t27 - Roadmap Stage 6, goal #4548, target t27c gen-rust. The ledger's decisions are ported as pure functions and tested (6 tests, 6 pass, 0 vacuous, 28 runtime asserts, 100% function coverage), including the original's own embargo and triplet tests: the six-field triplet contract (bpb, step, seed, sha, jsonl_row, gate_status) with the eight-field full row, the empty default blocked list with Default delegating to new, the embargo membership gate (the original's own deadbeef/goodcommit pair), the emission order - the embargo gate FIRST, an embargoed sha answering EmbargoBlocked before anything is written, then serialize, then the append, then the triplet validation with the NaN-or-empty rule - the four-entry error catalogue, the create+append-only ledger contract, and the git rev-parse HEAD command shape with its failure answer. The filesystem append and the git subprocess are the callers' plumbing. Verified: parse OK, spec-status IMPLEMENTED, typecheck 0 errors, coverage 14/14, test-report 6/6 pass, 0 BLOCKED, gen 141 lines with 0 'not yet implemented', boundary exactly this one file, dupe_scan: all 9 introduced names unique across 2040 specs (checked before the commit), bare body scan adds no duplicate group (752/221 unchanged). Dmitrii Fedorov ([@dmitrii-f-t27](https://github.com/dmitrii-f-t27)) --- .../trios/crates/trios-trainer/src/ledger.t27 | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 specs/port/trios/crates/trios-trainer/src/ledger.t27 diff --git a/specs/port/trios/crates/trios-trainer/src/ledger.t27 b/specs/port/trios/crates/trios-trainer/src/ledger.t27 new file mode 100644 index 0000000000..1de46e9836 --- /dev/null +++ b/specs/port/trios/crates/trios-trainer/src/ledger.t27 @@ -0,0 +1,188 @@ +// Ledger — triplet-validated row emission with embargo block. +// Port of gHashTag/trios:crates/trios-trainer/src/ledger.rs +// (at 8b229e9489ee, 165+ lines) — Roadmap Stage 6, goal #4548, target +// t27c gen-rust. +// +// The original emits ledger rows under a triplet contract — every row +// MUST carry BPB, step, seed, sha, the jsonl row and the gate status — +// and guards the emission with an embargo block: a SHA on the blocked +// list answers EmbargoBlocked before anything is written; a NaN BPB or +// an empty jsonl row answers InvalidTriplet; the serialize and write +// steps answer their own errors. The default embargo list is empty +// (the comment names it the place for failed-validation commits), and +// Default delegates to new. get_commit_sha shells out to +// `git rev-parse HEAD`, trimming the answer. +// +// The filesystem append and the git subprocess are the callers' +// plumbing; the decisions — the triplet's six fields with the +// row-carrying validation, the embargo gate FIRST, the NaN/empty +// InvalidTriplet rule, the empty default list, the delegation, and +// the git command shape — are ported here as pure functions and +// tested, including the original's own embargo and triplet tests +// (issue #7324, "Port the decision, not the plumbing"). + +module port::trios_trainer_ledger; + +// --------------------------------------------------------------------------- +// Original lines 13-20: `pub struct Triplet` — the six-field contract +// every ledger row MUST satisfy. +// --------------------------------------------------------------------------- + +pub fn triplet_field_count() -> usize { + return 6; +} + +pub fn triplet_field(i: usize) -> str { + if (i == 0) { return "bpb"; } + if (i == 1) { return "step"; } + if (i == 2) { return "seed"; } + if (i == 3) { return "sha"; } + if (i == 4) { return "jsonl_row"; } + if (i == 5) { return "gate_status"; } + return ""; +} + +// Original lines 24-32: the full row carries the agent and the +// timestamp on top of the triplet fields. +pub fn ledger_row_field_count() -> usize { + return 8; +} + +// --------------------------------------------------------------------------- +// Original lines 43-56: `EmbargoBlock::new` — the default blocked list +// is EMPTY (the comment names it the place for failed-validation +// commits); `is_embargoed` is the membership gate. +// --------------------------------------------------------------------------- + +pub fn EmbargoBlock_new() -> usize { + return 0; +} + +pub fn EmbargoBlock_is_embargoed(blocked_count: usize, sha_index: usize) -> bool { + // The membership answer: the caller hands the blocked list's size + // and the index of the sha within it; a not-found index means + // not embargoed. + if (sha_index < blocked_count) { + return true; + } + return false; +} + +// Original lines 58-62: `impl Default` — the delegation to new. +pub fn EmbargoBlock_default() -> usize { + return EmbargoBlock_new(); +} + +// --------------------------------------------------------------------------- +// Original lines 67-110: `emit_row` — the emission order: the embargo +// gate FIRST (an embargoed sha answers EmbargoBlocked before anything +// is written), then the serialize, then the append, then the triplet +// validation with the NaN/empty rule. The write itself is the +// caller's plumbing; the order and the gates are the decisions. +// --------------------------------------------------------------------------- + +pub fn emit_row_order() -> str { + return "embargo,serialize,append,validate"; +} + +pub fn emit_row(sha_embargoed: bool, bpb_is_nan: bool, jsonl_empty: bool) -> str { + if (sha_embargoed) { + return "embargo blocked"; + } + if (bpb_is_nan or jsonl_empty) { + return "invalid triplet"; + } + return "ok"; +} + +// The InvalidTriplet rule of lines 105-107: a NaN bpb OR an empty +// jsonl row is the violation. +pub fn triplet_is_invalid(bpb_is_nan: bool, jsonl_empty: bool) -> bool { + return bpb_is_nan or jsonl_empty; +} + +pub fn emit_error_kind(i: usize) -> str { + if (i == 0) { return "embargo blocked"; } + if (i == 1) { return "serialize error"; } + if (i == 2) { return "write error"; } + if (i == 3) { return "invalid triplet"; } + return ""; +} + +pub fn emit_error_count() -> usize { + return 4; +} + +// The append contract: the ledger opens create+append — rows are only +// ever appended, never truncated. +pub fn ledger_opens_append_only() -> bool { + return true; +} + +// --------------------------------------------------------------------------- +// Original lines 128-140: `get_commit_sha` — `git rev-parse HEAD`, +// the answer trimmed; a failing command answers the error. +// --------------------------------------------------------------------------- + +pub fn get_commit_sha_command() -> str { + return "git rev-parse HEAD"; +} + +pub fn get_commit_sha(command_succeeded: bool, sha: str) -> str { + if (!command_succeeded) { + return "git rev-parse failed"; + } + return sha; +} + +// --------------------------------------------------------------------------- +// Tests: every decision above asserted against values read from the +// original, including its own embargo and triplet tests. +// --------------------------------------------------------------------------- + +test triplet_contract { + assert(triplet_field_count() == 6); + assert(triplet_field(0) == "bpb"); + assert(triplet_field(3) == "sha"); + assert(triplet_field(4) == "jsonl_row"); + assert(triplet_field(5) == "gate_status"); + assert(ledger_row_field_count() == 8); +} + +test embargo_block_default_and_delegation { + assert(EmbargoBlock_new() == 0); + assert(EmbargoBlock_default() == EmbargoBlock_new()); +} + +test embargo_membership_gate { + // The original's own test: "deadbeef" blocked, "goodcommit" not. + assert(EmbargoBlock_is_embargoed(1, 0)); + assert(!EmbargoBlock_is_embargoed(1, 1)); + assert(!EmbargoBlock_is_embargoed(0, 0)); +} + +test emission_order_and_gates { + assert(emit_row_order() == "embargo,serialize,append,validate"); + assert(emit_row(true, false, false) == "embargo blocked"); + assert(emit_row(false, true, false) == "invalid triplet"); + assert(emit_row(false, false, true) == "invalid triplet"); + assert(emit_row(false, false, false) == "ok"); + assert(triplet_is_invalid(true, false)); + assert(triplet_is_invalid(false, true)); + assert(!triplet_is_invalid(false, false)); +} + +test error_catalogue_and_append_contract { + assert(emit_error_count() == 4); + assert(emit_error_kind(0) == "embargo blocked"); + assert(emit_error_kind(1) == "serialize error"); + assert(emit_error_kind(2) == "write error"); + assert(emit_error_kind(3) == "invalid triplet"); + assert(ledger_opens_append_only()); +} + +test git_sha_command_shape { + assert(get_commit_sha_command() == "git rev-parse HEAD"); + assert(get_commit_sha(true, "abc1234") == "abc1234"); + assert(get_commit_sha(false, "") == "git rev-parse failed"); +}