Commit Graph

12110 Commits

Author SHA1 Message Date
Jordan Ritter 7ef96237c9 fix(harness): fleet-health wires the contract's heartbeatParseable — unparseable heartbeats warned AND counted per cycle
The S10 caller's ad-hoc raw Date.parse check could disagree with
isWorkerStale's PB-space-form-normalized parser (engine-lenient vs
anchored), so the unparseable-heartbeat warn did not fire precisely when
the staleness check was blind. Wire the F2-exported heartbeatParseable
companion (contracts.ts documents fleet-health as its intended caller)
and surface a per-cycle unparseableHeartbeats count on the
fleet.health.cycle log — red-green pinned (the count was the new
observable; the cycle log previously never fired for a blind-but-online
corrupt row).
2026-06-11 20:42:45 -07:00
Jordan Ritter 82939a29f9 fix(dashboard): minors batch — mergeRowsToMap signal-presence warn noise + comment truth (CF7-F3 #5)
- mergeRowsToMap's disjoint-key divergence warn no longer fires on a
  signal undefined⇄defined flip between row groups (live-status.ts:
  coreRowFieldsEqual split out of rowsAreNoop): the initial fetch
  projects signal away while SSE deltas deliver full rows, so the flip
  is expected provenance, not a keyspace violation. upsertByKey's
  reducer keeps treating the flip as observable (existing tests pin it).
- __tests__/cell-model.test.ts destructure comment no longer claims
  noUncheckedIndexedAccess is enabled (it is not in this package's
  tsconfig) nor that the sibling matched (it did not).
- src/lib/cell-model.test.ts row() helper aligned to the
  destructure-with-fallback shape the comment describes.
- cell-model.ts:29-31 re-export rationale now cites the actual
  importer (__tests__/cell-model.test.ts).
2026-06-11 20:42:45 -07:00
Jordan Ritter 214c5707cb docs(dashboard): document the opposite-polarity fail-safe between isStale and the comm-error staleness gate (CF7-F3 #3)
staleness.ts isStale treats an unparseable observed_at as NOT stale
(false-stale would downgrade a live green row), while the FF7 gate in
decodeCellCommError treats unparseable as stale/skip (false-not-stale
would pin an uncleared overlay forever). isStale predates this branch
(blame: d0da6e357, pre-existing on main; untouched here), so per the
blame gate it is left as-is and the divergence is documented at the
FF7 site instead. Reported for the ledger.
2026-06-11 20:42:45 -07:00
Jordan Ritter f7daf5ca15 fix(dashboard): future-dated comm-error observedAt beyond 5min skew is treated as stale, not pinned (CF7-F3 #4)
decodeCellCommError's staleness gate (cell-model.ts:697) compared only
`now - parsed > staleAfterMs`, which is never true for a future-dated
observedAt — clock skew or a corrupt producer timestamp would pin the
unreachable/pending overlay indefinitely, the same permanent-phantom
failure mode the FF7 unparseable-timestamp skip prevents. A timestamp
more than COMM_ERROR_FUTURE_SKEW_TOLERANCE_MS (5min) ahead of now is
now skipped like an unparseable one; skew within tolerance still
surfaces (pinned by a companion test so the guard can't over-correct).
2026-06-11 20:42:44 -07:00
Jordan Ritter e69941795c fix(dashboard): absent D3/D4 family collapses the chip to unverified gray, never green (CF7-F3 #2)
The D1-D4 gate fires only on d3.exists/d4.exists, so a cell with ONLY
green D5/D6 rows (no e2e/chat/tools rows at all) slipped past it and
rendered a green chip + green d6Effective at achievedDepth=0/
ceilingDepth=0 — a false top-of-ladder claim contradicting the
strictness doctrine (PRESENT-but-null D4 grays; D5-no-data grays the
ladder). A wholly absent D3/D4 family now collapses to the gray
"unverified" chip (same shape as the d4NoData collapse) with red-D5/D6
dominance preserved, and d6Effective stays blocked (null).

cell-model.ts:847-852 (gate) / :905-921 (d6Effective).

One existing fixture (amber pass-through under reclaimed-pending) built
its amber from an absent-D3/D4 map; it now carries green e2e/chat rows
so the chip is genuinely amber through an intact ladder — the test's
never-mask assertion is unchanged.
2026-06-11 20:42:44 -07:00
Jordan Ritter da874b009f fix(dashboard): comm-error overlay visible from a COLD initial fetch — supplemental signal fetch for aggregate rows (CF7-F3 #1)
decodeCellCommError (cell-model.ts) derives the REQ-B unreachable/
pending overlay from row.signal, but the bulk initial fetch projects
STATUS_LIST_FIELDS, which omits signal (useLiveStatus.ts /
live-status.ts:STATUS_LIST_FIELDS) — so on every page refresh rows
materialized with signal undefined and ACTIVE overlays vanished until
an SSE delta happened to re-deliver that row.

Fix option (a) — matching the projection's data-volume rationale (the
signal blob is ~61% of the bulk payload): useLiveStatus now issues a
SUPPLEMENTAL initial fetch, concurrent with the bulk pages, of ONLY
the comm-error candidate aggregate rows (key has no /<featureId>
segment) for the four mirror dimensions, WITH signal, and merges them
over their projected bulk twins by key. That is ~4 rows per
integration, so the bulk projection's first-paint win is preserved.
Per-cell rows under the same dimensions carry heavy parity-diff
signals and are deliberately not re-fetched (a stale per-cell comm
error is only a same/lower-severity tie-break candidate against the
aggregate mirror).

- live-status.ts: new FLEET_COMM_AGGREGATE_DIMENSIONS single source of
  truth (d6/d4/e2e-demos/d5-single-pill-e2e); STATUS_LIST_FIELDS doc
  updated to the truth (buildCellModel reads signal per cell at render;
  the old "only ever read in the drilldown" claim was false).
- cell-model.ts: decodeCellCommError derives its aggregate candidates
  from the shared constant (scan order preserved; pinned by the
  equal-timestamp tie-break tests).
- useLiveStatus.ts: fetchCommAggregateRows + by-key merge; skipped
  entirely for dimension scopes outside the aggregate set; supplemental
  failure retries through the same connect() chain (fail loud).
- useLiveStatus.test.tsx: the PB mock now honours the fields projection
  (returning full rows for the projected bulk fetch is exactly how this
  bug stayed invisible to the suite) and serves the supplemental fetch
  from a dedicated fixture; new cold-fetch red-green tests assert the
  overlay renders end-to-end with NO SSE delta, the narrow filter
  shape, the out-of-set skip, and the in-set narrowing.
- live-status.test.ts: formatter pass on the CF7-F3 #5 test added in
  the previous commit (oxfmt).
2026-06-11 20:42:43 -07:00
Jordan Ritter cc16fe6752 test(harness): sweep e2e_d6 row-key fixtures to the contract-conformant d6:<slug> form (scope exception: recurring CR noise)
CR finding recurring 3x; fixture lines pre-existing on the base (f8aee59b62 /
ef76c6d0ff / 2a9b38bbfe). The fleet contract (contracts.ts ServiceJobResult
.aggregateKey) forbids an e2e_d6:<slug> row on the fleet path - the dashboard
only ever reads d6:<slug> - so fixtures pinning e2e_d6:* keys mask the exact
regression class (success-path vs error-path aggregate-key drift) these
suites exist to catch. Behavior-neutral: every assertion pins the same
production logic, now over conformant keys.

- contracts.test.ts: makeResult probeKey/aggregateKey + the projection pin
  -> d6:langgraph-python; fleetSurfaceState row key/dimension -> d6
- worker-loop.test.ts: makeDriver returns d6:<slug> (was e2e_d6:<slug>),
  unified with the comm-error/driver-error paths that already pin d6:...;
  all inline driver-fake fixtures + the buildServiceJobResult /
  runClaimedJob aggregateKey assertions swept in lockstep. The
  registry-routing `<kind>:routed` tagging keys are deliberately untouched
  (they tag by DRIVER KIND to prove dispatch, symmetric across
  e2e_smoke/e2e_demos)
- orchestrator.test.ts: driverInputs.key -> the d6:tracer-slug tracer,
  slug-ALIGNED across probeKey/serviceSlug/probe_key because the d6 driver
  derives its aggregate side-row slug from input.key (deriveSlug) while the
  loop filters by d6:<serviceSlug> - a mismatched tracer would surface the
  side row as a phantom cell; pass-through proof kept (aggregateKey echoes
  the tracer) and strengthened with the "no D5 features declared" signal pin
2026-06-11 20:42:43 -07:00
Jordan Ritter c3d396f66f fix(harness): statusSignalHasCommErrorKey companion makes an undecodable comm-error overlay observable (REQ-B version skew)
CR finding on commErrorFromStatusSignal (contracts.ts:433-463, decode-guard
region touched on this branch): a malformed embedded value decodes to
undefined - indistinguishable from "absent" - so a REQ-B overlay written by a
NEWER producer (new PoolCommErrorKind rolled out write-side first, or a
renamed required field) is silently dropped by an older reader.

- document the version-skew hazard on the decode (return type unchanged:
  every render path branches on presence)
- export statusSignalHasCommErrorKey(signal) so consumers can count/log
  "key present but undecodable" drops; mirrors the decoder's wire-shape
  guards (null/non-object/array are never valid signals)
- pinned with tests: unknown future kind, renamed required field, well-formed,
  genuinely-absent, and array/non-object wire shapes
- the mirrored commErrorFromStatusSignal REGION is untouched: companion +
  docs live OUTSIDE the byte-identity block; verified by running the
  dashboard's commError-contract-drift.test.ts (12/12 green) - the dashboard
  mirror (shell-dashboard live-status.ts) still needs its own sibling
  companion, to be landed by the dashboard owner
2026-06-11 20:42:42 -07:00
Jordan Ritter 0f3705f11f fix(harness): isWorkerStale parses the PB space-form heartbeat; heartbeatParseable companion surfaces corrupt timestamps (scope exception: recurring CR noise)
CR finding flagged 4x across 2 rounds (lines pre-existing on the base, f8aee59b62):
isWorkerStale (contracts.ts:610-618) did a bare Date.parse with NaN -> false,
making a corrupt heartbeat indistinguishable from a fresh one ("never stale
forever" = silent fleet-health blindness), and lacked the anchored PB
space->"T" normalization the queue-client treats as load-bearing for lease
timestamps (PB_DATE_SEP_RE, replicated locally - not imported, since
queue-client imports contracts).

- normalize the PB date form with the anchored regex before parsing
- keep isWorkerStale(...): boolean compat (unparseable stays not-yet-stale)
- export heartbeatParseable(lastHeartbeatAt) so fleet-health (S10) can
  warn/count unparseable heartbeats (caller wiring is a follow-up; the S10
  caller is outside this fix's file scope)
- red-green: PB space-form timestamps, corrupt timestamp, fresh/stale ISO
  boundary pins (strict > at exactly-the-window)
2026-06-11 20:42:42 -07:00
Jordan Ritter 7cee39d4a1 test(harness): control-plane FakeTimers is per-handle — both consumer and fleet-health intervals pinned to fire and to be cleared on stop (CF7 #12, scope exception: recurring CR noise)
The single-callback-slot fake let the fleet-health registration silently
overwrite the consumer's, making consumer-loop assertions vacuous with
fleetHealth injected and hiding leaked intervals from the cleared flag.
2026-06-11 20:42:41 -07:00
Jordan Ritter 3c063d4a20 fix(harness): CF7 #11 minors — meta.priority shape validation, aggregateKey empty-sentinel fallback, memoized auth route, documented 4xx repetition and 401 class
- assertServiceJobPayload rejects a non-number meta.priority when present
- protocolViolationResult falls back to a jobId-derived aggregateKey
  (defense-in-depth; empty probe_key is unreachable via claimNext's G1c gate)
- job-claim memoizes the working auth route so a v0.22 backend pays the
  /_superusers 404 probe once per process, not per token expiry
- raceCandidates' deterministic-4xx per-poll re-warn documented as accepted
- deterministicEndpointRejection notes why 401 is deterministic (postFleet
  already re-authed once)

shuffleInPlace rng clamp NOT done: lines are pre-existing (d408766cce on
origin/main) — blame-gated out.
2026-06-11 20:42:41 -07:00
Jordan Ritter a2c568a057 docs(harness): fix stale prose — expiredPending also counts long-expired claimed/running deletes, reclaimed excludes thrown releases, stale window is family-configured (CF7 #10)
Contracts-side SweepResult.expiredPending doc needs the sibling edit
(out of scope for this branch).
2026-06-11 20:42:40 -07:00
Jordan Ritter b93188df2b fix(harness): serialize concurrent sweepExpired calls with an in-client latch — the per-call grace set is not concurrency-safe (CF7 #9)
The SINGLE-SWEEPER comment claimed a singleton, but runControlPlane wires
four producers over one queue client, so cron overrun can overlap sweeps;
a concurrent sweep cannot see the first sweep's grace set and could
claim-delete a row it just re-queued. Overlapping callers now piggyback on
the in-flight sweep; cross-process replicas remain documented as uncovered
(fleet deploys one control-plane).
2026-06-11 20:42:40 -07:00
Jordan Ritter ebe30c85bb fix(harness): report() preserves the claim-time caches on the equality-invariant rejection — the worker still holds the job (CF7 #8)
The finally's unconditional eviction also fired on the malformed-input
refusal thrown BEFORE the release CAS, dropping the assumed-live lease the
indeterminate-renew containment depends on and killing the heartbeat of a
live job. The eviction is now scoped; the 'DONE either way' header claim is
corrected.
2026-06-11 20:42:39 -07:00
Jordan Ritter 24f684563d fix(harness): writeResult intra-call retry reads before rewriting — a committed-then-thrown attempt can no longer un-latch an aggregated result (CF7 #7)
Attempt N can commit server-side then throw; a blind attempt N+1 re-seeded
result_processed:false, un-latching what the consumer aggregated in the
250ms pause window. The cross-call retry path already guarded exactly this;
the same read-before-write guard now applies inside the retry loop, and a
failed pre-read refuses the blind rewrite.
2026-06-11 20:42:38 -07:00
Jordan Ritter 740150321e feat(harness): tick-while-stopped warn discriminates never-started from stopped-after-running (CF7 #6) 2026-06-11 20:42:38 -07:00
Jordan Ritter aa39c2d490 feat(harness): warm-up skip observability — per-spec debug with reason + one zero-warmable warn per tick (CF7 #5)
A warm-configured deployment whose enumerator stopped threading backendUrl
silently lost all #72 cold-start coverage with no trace at any log level.
2026-06-11 20:42:37 -07:00
Jordan Ritter 1ef53d6f84 fix(harness): buffer-overflow comm-error drop logs a capped jobIds sample like its sibling drop paths (CF7 #4) 2026-06-11 20:42:37 -07:00
Jordan Ritter b56ae9644a feat(harness): TickResult.backlogGateFailedOpen surfaces families kept via the gate's fail-open path (CF7 #3)
A family kept because countPendingForFamily failed (non-poisoned) was
indistinguishable from a clean zero-backlog read in the tick outcome —
the documented sweepFailed/enumerateFailed ambiguity class. Counted per
family and included in the tick-complete log meta.
2026-06-11 20:42:36 -07:00
Jordan Ritter eec645fb48 fix(harness): producer phantom-spec guard checks element shape before dereferencing probeKey (CF7 #2)
A null/undefined/primitive enumerator element threw a TypeError out of the
tick body, rejecting the tick promise and violating the 'tick never
rejects' invariant. Non-object elements are now dropped loudly and counted
in the existing invalid-spec accounting.
2026-06-11 20:42:36 -07:00
Jordan Ritter c600222cf3 fix(harness): poisoned-count backlog gate discriminates via exported PoisonedBacklogCountError, not message text (CF7 #1)
The fail-closed gate matched a message substring duplicated in 3 places;
any rewording silently flipped it fail-closed -> fail-open. The refusal is
now a dedicated exported class, the producer gates via instanceof, the test
literal copies use the real class, and a drift test drives the REAL
queue-client refusal through the producer gate.
2026-06-11 20:42:35 -07:00
Jordan Ritter 8119635ade docs(harness): ReportJobInput INTEGRATOR NOTE reflects report()'s equality enforcement (integration) 2026-06-11 20:42:35 -07:00
Jordan Ritter 5e471aab0e test(dashboard): drop the [0]! non-null assertion in the G3f aggregate-key helper — destructure with fallback survives noUncheckedIndexedAccess (CF6-G5 #9) 2026-06-11 20:42:34 -07:00
Jordan Ritter aa294dd6c3 fix(dashboard): drift-test surface-derivation parser guards against silent truncation at an internal ';' blank-line boundary (CF6-G5 #7) 2026-06-11 20:42:34 -07:00
Jordan Ritter c9663e258c fix(dashboard): drift-test kind parser strips comments before matching; fix the misleading line-position comment (CF6-G5 #6) 2026-06-11 20:42:33 -07:00
Jordan Ritter e742155e7f fix(dashboard): health label honors the staleness split — fresh producer-emitted degraded reads 'degraded', not 'stale' (CF6-G5 #2) 2026-06-11 20:42:33 -07:00
Jordan Ritter bbaf58a392 fix(dashboard): D4 missing-chat collapse renders the gray no-data chip, not a red gate failure (CF6-G5 #1) 2026-06-11 20:42:32 -07:00
Jordan Ritter 57054b9830 fix(harness): REQ-B sweep sink throws while the control-plane is unbound
A resolved sink call clears the producer's undelivered comm-error buffer
(deliverSweepCommErrors' at-least-once contract), so the late-bound sink
silently 'succeeding' before controlPlaneRef was assigned dropped the
batch permanently. Extract buildSweepCommErrorSink (exported for tests)
and reject on the unbound window so the producer re-buffers and
redelivers after assembly; pin with red-green unit tests.
2026-06-11 20:42:31 -07:00
Jordan Ritter 4bfeb121c4 fix(harness): drop enumerator specs with an empty probeKey at the tick boundary — no phantom '' family in the backlog gate, no unjoinable claim row; counted as enqueueFailures 2026-06-11 20:38:46 -07:00
Jordan Ritter 13a33bf97a fix(harness): warm-up branches on res.ok — a settled 404/5xx logs warm-failed (with status) instead of masquerading as warm-ok 2026-06-11 20:38:46 -07:00
Jordan Ritter ce22ff454d fix(harness): producer tick/stop survive a throwing logger transport — safeLogger wrapper keeps the 'a tick promise never rejects' invariant true and stopPromise unpoisoned 2026-06-11 20:38:45 -07:00
Jordan Ritter b3b3dbdc52 fix(harness): minor queue-client honesty fixes (empty enqueuedAt, 408/429 transient class, truncation warn, typo)
- assertServiceJobPayload rejects an empty meta.enqueuedAt — the
  emptyPayloadForLease never-aggregate sentinel, same forbidden class as
  the other empties (the minted fallback never crosses this boundary)
- 408/429 are excluded from the deterministic-4xx class (shared
  deterministicEndpointRejection helper): transient by meaning, they keep
  the assumed-live renew and at-least-once sweep containments
- the family-discovery truncation warn threads nextFamilyClauseSafe so a
  clause-unsafe garbage head can't masquerade as a hidden claimable family
- fix 'CONTROl' comment typo in queue-client.test.ts
2026-06-11 20:38:45 -07:00
Jordan Ritter 7c467f6231 fix(harness): report() enforces the ReportJobInput equality invariant and never skips cache eviction
Enforce the documented jobId/workerId equality between the top-level
input and the echoed result (a mismatched caller would release one row
while filing the result under another), and move the terminalJobStatus
computation inside the try so a malformed result can no longer throw
past the finally and leak the claim-time cache entry.

NOTE: contracts.ts's INTEGRATOR NOTE on ReportJobInput still says report()
does not validate this — contracts.ts is sibling-owned this round and is
NOT touched here; the note needs a follow-up edit.
2026-06-11 20:38:44 -07:00
Jordan Ritter 2982db35ef fix(harness): sweep deletes stale-aged expired rows with UNPARSEABLE leases in the lease phase
The long-expired carve-out required a finite parsed lease, so an expired
claimed/running row with an unparseable lease_expires_at was re-queued
with a 'back in flight' worker-reclaimed-pending signal — which the next
sweep falsified by claim-deleting the row (the recent-lease protection
also requires a finite lease). An unparseable lease carries no
recent-flight evidence either phase can honor: treat it as long-expired
and delete directly so the emitted signal matches the outcome. Pinned
with a two-sweep test.
2026-06-11 20:38:44 -07:00
Jordan Ritter ac1b5a2415 fix(harness): assertServiceJobPayload rejects a top-level array payload
An array is typeof 'object' and can carry expando fields that satisfy
every per-field check — the same hole the nested meta check's
Array.isArray guard already closes one level down. Reject it at the
shared enqueue/decode boundary.
2026-06-11 20:38:44 -07:00
Jordan Ritter 4108bc39f4 fix(harness): auth 4xx throws JobClaimEndpointError so the deterministic carve-outs fire for rotated creds
authenticate() threw plain Errors for every non-2xx, so the renew and
sweep deterministic-4xx carve-outs (instanceof JobClaimEndpointError +
4xx) never fired for auth failures — rotated creds rode the indeterminate
path forever: a phantom assumed-live lease per renew beat and a false
worker-reclaimed-pending comm error per sweep. 4xx auth responses now
carry the discriminable class (auth path + status); 5xx/network stay
plain (indeterminate). End-to-end pins go through the real job-claim
client for both the renew and sweep halves.
2026-06-11 20:38:44 -07:00
Jordan Ritter cedd7d481a fix(harness): won-without-job containment releases terminal 'failed' with a synthetic protocol-violation result
The pending-target release could never succeed: the hook refuses every
pending-target release on a live lease (refused_lease_live, no holder
exemption) and refused_not_holder otherwise, so the containment was inert
— the row wedged a lease window and got a false worker-reclaimed-pending
overlay. Mirror the decode-failure containment (terminal target passes
the live-lease gate) and share its synthetic-result builder. Tests now
use hook-faithful release fakes instead of unconditional released:true.
2026-06-11 20:38:44 -07:00
Jordan Ritter 46775478a6 docs(harness): SweepResult.commErrors doc covers the indeterminate (thrown-release) synthesis too — length = reclaimed + reclaimedIndeterminate (CR G2 #3) 2026-06-11 20:38:44 -07:00
Jordan Ritter d57a1320f8 fix(harness): commErrorFromStatusSignal rejects an array SIGNAL blob, not only an array nested value; dashboard mirror updated in lockstep (drift test pins byte-identity) (CR G2 #2) 2026-06-11 20:38:43 -07:00
Jordan Ritter cb5e4e4ccf fix(harness): land reclaimedIndeterminate on the shared SweepResult contract; producer reads it directly (integration) 2026-06-11 20:38:43 -07:00
Jordan Ritter 60c692d824 fix(dashboard): D5/D6 resolvers return the effective fold winner, fresh-degraded tooltip copy split from stale, document CellState.d6 as ungated (G2f ii+iii+v) 2026-06-11 20:38:43 -07:00
Jordan Ritter cb35d7fb4b fix(dashboard): D4 collapses a green fold when the unconditional chat row is missing; tie-break doc drops unreachable 'absent' case (G2f i+iv) 2026-06-11 20:38:43 -07:00
Jordan Ritter e7eca9174f fix(harness): fleet contracts polish — clamp WorkerCapacity.available at 0, ReportJobInput equality-invariant doc, enumerate both fleetSurfaceState/dashboard divergences (G2e) 2026-06-11 20:38:43 -07:00
Jordan Ritter c4854d40cc fix(harness): producer tick-outcome polish — queued-trigger-after-stop debug event, reclaimed at-least-once doc + reclaimedIndeterminate surfacing (G2d) 2026-06-11 20:38:42 -07:00
Jordan Ritter 86e717a370 fix(harness): share one stop completion so every producer stop() resolution implies the final comm-error drain finished (G2c) 2026-06-11 20:38:42 -07:00
Jordan Ritter 31d119683d fix(harness): make producer stop() before start() a no-op instead of a permanent brick (G2b) 2026-06-11 20:38:41 -07:00
Jordan Ritter bbd42449d1 fix(harness): fail the producer backlog gate CLOSED on the queue-client's poisoned-count refusal (G2a) 2026-06-11 20:38:41 -07:00
Jordan Ritter f8033fe6bf test(harness): G1h test-quality batch for the fleet queue/claim suites
- report ordering assertion made non-vacuous: capture rows[0].result INSIDE
  the releaseJob fake and assert undefined at release time.
- empty-slug-segment fixture carries probe_key 'd6:' on the claim fake's
  returned view too (no pinning of the internal key source).
- job-claim.test.ts: file-local silent logger replacing the shared logger
  import (spy-leak class under fork-reuse).
- auth-order tests: auth + endpoint URLs recorded in one call log, order
  asserted by index; fallback test pins _superusers-first order and the
  Authorization header carried to the endpoint.
- makeFakePb.list honesty: models created/lease_expires_at sorts (throws on
  unmodeled keys) and honors perPage/page truncation; self-tested in the
  fake-honesty suite.
- documented the interleaved-|| connective-guard limitation in
  rowMatchesFilter.
- renamed the renew 'convenience re-read returns null' test to the cache-hit
  pin it actually covers, with expect(getOneSpy).not.toHaveBeenCalled().
2026-06-11 20:38:40 -07:00
Jordan Ritter 34e67f7b4a fix(harness): G1g batch — report retry guard, at-least-once sweep split, 401 race, single-attempt decode write, hook jobId guard, doc corrections
- report() retry: a null getOne resolution is a FAILED read (throw, no blind
  write) and a "" result is PB's unset-JSON shape (absent → write proceeds).
- sweepExpired: thrown-release conservative maybes now counted on a separate
  reclaimedIndeterminate (SweepResultWithIndeterminate); reclaimed counts only
  CAS-confirmed re-queues. Producer one-liner documented for when the
  sibling-owned TickResult gains the field.
- job-claim 401 retry: snapshot the token the failed request used; only null
  authToken if unchanged (no clobbering a concurrently refreshed token).
- decode-failure synthetic result write: single attempt, no 250ms retry pacing
  inside the claim race (consumer crash-synthesis is the documented backstop).
- fleet-claim.pb.js: typeof jobId !== "string" → 400 in all three handlers.
- docs: recent-lease bound is expiryPeriods × period (not one window); claim
  5xx→won:false bounded false-overlay source; report retryability deploy-skew
  note; drainStalePending page-advance indeterminacy note.
2026-06-11 20:38:40 -07:00
Jordan Ritter 8a45823906 fix(harness): release a won-without-job claim back to pending instead of abandoning a possibly-owned row (G1e)
The won:true/no-job protocol breach may still have committed the claim, so
falling through abandoned a row this worker owns — wedging a full lease window
and producing a false worker-reclaimed-pending overlay on the next sweep.
Mirror the decode-failure containment: best-effort releaseJob(id, worker,
"pending") (no work happened) before continuing, with refusals and throws
swallowed+warned.
2026-06-11 20:38:39 -07:00