SIGN IN SIGN UP

feat(rustd): the runner plane closes a lease — issue, report, renew, tail

M177 §2, §3 and the first verb of §4. The lease verb was code-complete but
uncommitted across two sessions; it lands here with the report that ends a
lease and the renew that keeps one alive.

§2 — lease issue. The claim, the three gates in the order a refusal must not
be charged in, the policy, and the row. Answers serialized bytes rather than a
struct: ExecutionPolicy borrows from the config, the resolved provider and the
declared credentials, so assembly, payload and serialization all happen inside
one borrow. Deep-owning would copy exactly what the borrows exist to avoid, and
assembling twice would put a second opinion about what a run may do in the one
place that must have one.

§3 — report and renew. claimReport() ports as one writable-CTE statement:
fence check, active→reported flip, both metering cursors, the wallet drain, the
`stage` ledger row and the lifetime tally, every arm gated FROM guard so a
superseded holder writes none of them. Fusing the claim and the settle is what
makes the MAX_RUNTIME path safe — split in two, a racing reclaim wins the fence
between them and the last slice of a twelve-hour run is charged to nobody.
Renew advances the lease row and the affinity slot together, clamped to
min(now + LEASE_TTL_MS, created_at + MAX_RUNTIME_MS); a half-applied extend is
reported LOST, because the deadline it would name is one the slot will not keep.

§4 — activity. Live-tail frames publish to fleet:{id}:activity. Best-effort by
contract, so a dropped frame is logged and the verb still answers; the one hard
check is that the lease resolves to the presenting runner, without which a
runner could write into another fleet's tail.

Five error codes are REFERENCED from the Zig registry, never invented here:
UZ-RUN-005/006/010/011/012. test_entries_match_the_zig_registry reads
error_entries.zig directly and caught a real gap — no Zig spelling was recorded
for 409.

Both atomic statements are byte-identical to their Zig originals (Invariant 5),
and their bind orders were diffed positionally against the Zig, 17/17 each. This
workspace disables sqlx's macros feature, so nothing else would catch a
transposition among eleven same-typed bigints.

Zig shapes NOT carried across, per the no-regressions rule — each was a
workaround for something Zig's standard library lacks:

  SettleOutcome{claimed: bool, charged_nanos} → enum Settled, so reading a
    charge off a fenced report does not compile rather than merely being wrong
  MeterInputs, seven bare integers → Meter{Cumulative, SliceRates}
  truncateUtf8's 0xC0 mask-and-walk → str::is_char_boundary
  buildMeterInputs swallowing two failure classes → Accounts::meter answers a
    value for a catalogue miss and an Error for a fault; the fail-open posture
    is applied at the verb, where a reader can find it
  a std.json.Value built and dropped per tool call → serde_json RawValue, which
    validates the runner's arguments without materialising them

parsePosture's platform fallback is deliberately kept: correcting it would move
billing, and the Zig's own comment calls that a product decision.

Nine routes mounted of eighty-one tabled.
test_only_the_ported_routes_are_mounted is the tripwire and moved with them.

Six integration suites cover dimensions 3.1–3.4. They are #[ignore]d and have
NOT been executed — make test-integration-rustd is the only lane that runs them,
and it is deferred with the rest of the sweep until §6 closes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
K
Kishore Kumar committed
f4bd5583c79403ff5798eea7a4c64f475456a2d5
Parent: 626ce72