Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 172 additions & 0 deletions specs/port/trios-railway/crates/trios-railway-audit/src/event.t27
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// AU-02 — the Neon audit_event writer and its JSON artifact.
// Port of gHashTag/trios-railway:crates/trios-railway-audit/src/event.rs
// (at 8b229e9489ee, 182 lines) — Roadmap Stage 6, goal #4548, target t27c
// gen-rust.
//
// The original writes one audit row into the Neon igla_race_trials table
// and returns the inserted row id, never silently swallowing errors (R5);
// the JSON artifact it emits to stdout lets the hourly watchdog parse the
// result without re-querying Neon. The tokio-postgres connect, the INSERT
// round-trip and the JSON serialization are plumbing; the decisions the
// file makes — the Gate-2 contribution rule (this row contributes exactly
// when bpb < target_bpb, strictly), the image_sha kept-length rule (at
// most the first eight characters, a shorter sha kept whole), the insert
// shape (four columns, returning the id), and the Neon env fallback order
// (RAILWAY_POSTGRES_URL preferred, the legacy NEON_DATABASE_URL accepted)
// — are ported here as pure functions and tested, including the
// original's own four artifact tests. The clock is a parameter the caller
// passes (the original stamps Utc::now inside; the port carries the ts it
// is given), and the sha truncation is carried as the kept-length
// decision — the slicing itself is the caller's string plumbing. The
// audit_event transport keeps its name with an `undefined;` body that no
// test calls (issue #9790, "Port the decision, not the plumbing").

module port::trios_railway_audit_event;

// ---------------------------------------------------------------------------
// Original lines 49-67: `pub struct AuditArtifact` — the stdout artifact
// for the hourly watchdog. Only the facts the decisions read.
// ---------------------------------------------------------------------------

pub struct AuditArtifact {
ts: i64,
seed: i32,
bpb: f64,
step: i32,
image_sha: str,
row_id: i64,
target_bpb: f64,
gate2_contribution: bool,
}

// ---------------------------------------------------------------------------
// Original lines 69-91: `impl AuditArtifact { pub fn new(...) -> Self }`.
// The artifact carries the writer's output; the clock is the caller's
// (Utc::now inside the original becomes the ts parameter), and the
// image_sha is carried as passed — the kept-length decision below is the
// truncation rule the caller applies. The Gate-2 contribution is the
// one computed decision: strictly below the target.
// ---------------------------------------------------------------------------

pub fn AuditArtifact_new(
seed: i32,
bpb: f64,
step: i32,
image_sha: str,
row_id: i64,
target_bpb: f64,
ts: i64,
) -> AuditArtifact {
return AuditArtifact {
ts: ts,
seed: seed,
bpb: bpb,
step: step,
image_sha: image_sha,
row_id: row_id,
target_bpb: target_bpb,
gate2_contribution: gate2_contributes(bpb, target_bpb),
};
}

// Original line 88: `gate2_contribution: bpb < target_bpb` — this row
// contributes to Gate-2 PASS exactly when the recorded BPB is strictly
// below the target.
pub fn gate2_contributes(bpb: f64, target_bpb: f64) -> bool {
if (bpb < target_bpb) {
return true;
}
return false;
}

// Original line 85: `image_sha[..image_sha.len().min(8)]` — at most the
// first eight characters; a shorter sha kept whole.
pub fn image_sha_kept_len(sha_len: usize) -> usize {
if (sha_len > 8) {
return 8;
}
return sha_len;
}

// ---------------------------------------------------------------------------
// Original lines 109-140: `pub async fn audit_event(...) -> Result<RowId>`.
// Connects to Neon, inserts one audit row and returns the id. Pure
// transport — it never silently swallows errors (R5); the insert shape
// and the env fallback order are its decisions, ported below.
// ---------------------------------------------------------------------------

pub fn audit_event(seed: i32, bpb: f64, step: i32, image_sha: str, neon_url: str) -> ?i64 {
return undefined; // plumbing: Neon connect + INSERT ... RETURNING id (lines 109-140)
}

// Original lines 129-131: the insert writes four columns — seed, bpb,
// step, image_sha — and returns the id.
pub fn insert_column_count() -> usize {
return 4;
}

pub fn insert_returns_id() -> bool {
return true;
}

// Original lines 101-103: the connection string comes from
// RAILWAY_POSTGRES_URL, the legacy NEON_DATABASE_URL accepted as the
// fallback (L-NEON-RENAME).
pub fn preferred_neon_env() -> str {
return "RAILWAY_POSTGRES_URL";
}

pub fn legacy_neon_env() -> str {
return "NEON_DATABASE_URL";
}

pub fn neon_env_var_count() -> usize {
return 2;
}

// ---------------------------------------------------------------------------
// Tests: every decision above asserted against values read from the
// original's own tests (lines 146-181). No test calls the audit_event
// transport.
// ---------------------------------------------------------------------------

test artifact_gate2_contribution_true_below_target {
const a = AuditArtifact_new(100, 1.83, 2000, "abc123de", 42, 1.85, 1700000000);
assert(a.gate2_contribution);
assert(a.seed == 100);
assert(a.row_id == 42);
}

test artifact_gate2_contribution_false_at_or_above_target {
const a = AuditArtifact_new(101, 2.10, 1500, "xyz", 43, 1.85, 1700000000);
assert(!a.gate2_contribution);
assert(!gate2_contributes(1.85, 1.85));
}

test image_sha_truncated_to_eight {
assert(image_sha_kept_len(16) == 8);
assert(image_sha_kept_len(9) == 8);
assert(image_sha_kept_len(8) == 8);
}

test image_sha_short_kept_whole {
assert(image_sha_kept_len(3) == 3);
assert(image_sha_kept_len(1) == 1);
}

test artifact_carries_the_writer_output {
const a = AuditArtifact_new(100, 1.83, 2000, "deadbeef", 7, 1.85, 1700000000);
assert(a.ts == 1700000000);
assert(a.bpb == 1.83);
assert(a.step == 2000);
assert(a.target_bpb == 1.85);
assert(a.image_sha == "deadbeef");
}

test insert_shape_and_env_fallback {
assert(insert_column_count() == 4);
assert(insert_returns_id());
assert(preferred_neon_env() == "RAILWAY_POSTGRES_URL");
assert(legacy_neon_env() == "NEON_DATABASE_URL");
assert(neon_env_var_count() == 2);
}
Loading