@evident-ai/runner-synchroniser 3.1.1-dev.997b038 → 3.1.1-dev.fbc0f17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -2
- package/dist/cli.js +567 -209
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ bundle directly (`node cli.js <command>`).
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
The package is published to npm as `@evident-ai/runner-synchroniser`, exposing one
|
|
26
|
-
`runner-synchroniser` binary and requiring Node >= 22:
|
|
26
|
+
`runner-synchroniser` binary and requiring Node >= 22.13.0:
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
npx @evident-ai/runner-synchroniser@dev env
|
|
@@ -63,6 +63,7 @@ version at all.
|
|
|
63
63
|
| `model-auth-ready` | — | `0` = ready, `10` = not ready; other = tool broken |
|
|
64
64
|
| `self-stop` | — | `0` = stopped, `20` = keep the task; other = tool broken |
|
|
65
65
|
| `session-db-classify <litestream-restore-exit-code> <attempt> [--on-unusable-replica=<prune\|leave\|clear\|crash>]` | — | `0` = restored/no-replica/disabled, `32` = re-run and ask again, `31` = unusable (booted fresh, starts a fresh backup chain), `30` = fatal; other = usage/tool broken |
|
|
66
|
+
| `session-db-verify <litestream-config-path>` | — | `0` = healthy/skipped/walked-back, `33` = every retained restore point was exhausted (booted fresh, starts a fresh backup chain); other = usage/tool broken |
|
|
66
67
|
|
|
67
68
|
`self-stop` scales this agent's own ECS service to `desiredCount=0` on a clean idle exit
|
|
68
69
|
(see Configuration for `CLUSTER`/`SERVICE`/`EVIDENT_SELFSTOP_ROLE_ARN`). It exits `0`
|
|
@@ -220,11 +221,79 @@ at boot the newest L0 is normally *absent* (`noL0Present`) or freshly written an
|
|
|
220
221
|
(`targetHealthy`) — `prune`'s real-world reach is narrower than the code alone suggests,
|
|
221
222
|
and it can never repair corruption at a higher compaction level.
|
|
222
223
|
|
|
223
|
-
`EVIDENT_ON_UNUSABLE_REPLICA` is a `packages/runner-image` (entrypoint) variable translated into the flag above at boot — this CLI never reads it, so it has no row in this README's Configuration table below; see [runner-image's README](../runner-image/README.md#when-the-replica-is-unusable-evident_on_unusable_replica). An unrecognised value (including wrong casing, e.g. `Prune`) exits `2`, outside `entrypoint.sh`'s `0|10|20|30|31|32` allow-list — a typo **crash-loops the task on attempt 1** rather than falling back to `prune`, and also logs the misleading "credential persistence is DEGRADED" ERROR.
|
|
224
|
+
`EVIDENT_ON_UNUSABLE_REPLICA` is a `packages/runner-image` (entrypoint) variable translated into the flag above at boot — this CLI never reads it, so it has no row in this README's Configuration table below; see [runner-image's README](../runner-image/README.md#when-the-replica-is-unusable-evident_on_unusable_replica). An unrecognised value (including wrong casing, e.g. `Prune`) exits `2`, outside `entrypoint.sh`'s `0|10|20|30|31|32|33` allow-list — a typo **crash-loops the task on attempt 1** rather than falling back to `prune`, and also logs the misleading "credential persistence is DEGRADED" ERROR.
|
|
224
225
|
|
|
225
226
|
See `specs/local-runner.feature`'s "Recovering session history at startup" scenarios for
|
|
226
227
|
the behavioural anchor (31 comes online, 30 does not).
|
|
227
228
|
|
|
229
|
+
### `session-db-verify`
|
|
230
|
+
|
|
231
|
+
The 8th command: it runs *after* the restore loop above has settled and *before*
|
|
232
|
+
`opencode` opens the DB. The restore loop only proves litestream could write a file;
|
|
233
|
+
this command is what proves that file is actually intact (#1345 — a leaf-page-corrupt
|
|
234
|
+
but openable `opencode.db` was re-restored unchanged every boot, forever, because
|
|
235
|
+
nothing had ever run a real `PRAGMA integrity_check`).
|
|
236
|
+
|
|
237
|
+
#### Positional
|
|
238
|
+
|
|
239
|
+
| Positional | Meaning |
|
|
240
|
+
| --- | --- |
|
|
241
|
+
| `<litestream-config-path>` | Path to the `litestream.yml` this CLI itself generated (`litestream-config`); used to enumerate and restore from retained points. |
|
|
242
|
+
|
|
243
|
+
#### What it does
|
|
244
|
+
|
|
245
|
+
1. `PRAGMA integrity_check` the local `opencode.db`. Healthy → done, `0`.
|
|
246
|
+
2. On failure, enumerate litestream's retained restore points (`litestream ltx`) and
|
|
247
|
+
walk them back from newest to oldest (excluding the one that just failed), restoring
|
|
248
|
+
each into a scratch path and integrity-checking it there. The first one that passes
|
|
249
|
+
is adopted — renamed over `opencode.db`, replacing it and its stale sidecars.
|
|
250
|
+
3. If nothing retained passes (or there's nothing to try, or the search runs out of
|
|
251
|
+
time/points), the corrupt local DB is discarded and the boot proceeds with a
|
|
252
|
+
genuinely fresh one — exactly `session-db-classify`'s `31` guarantee, so
|
|
253
|
+
`litestream replicate` starting against it afterwards is just as safe.
|
|
254
|
+
|
|
255
|
+
A walked-back boot keeps replicating into the **same** replica — no S3 mutation, no new
|
|
256
|
+
prefix. litestream re-bases to the replica's high-water mark and continues the txid
|
|
257
|
+
chain from there; the pre-walkback lineage stays independently restorable at its old
|
|
258
|
+
txids. (Measured end-to-end against a `file` replica with a tiny DB; not measured
|
|
259
|
+
against S3 at the ~1 GB scale a production replica can reach.)
|
|
260
|
+
|
|
261
|
+
#### Outcome → exit code
|
|
262
|
+
|
|
263
|
+
| Outcome | Code | When |
|
|
264
|
+
| --- | --- | --- |
|
|
265
|
+
| `skipped` | `0` | local DB absent or zero bytes — nothing to verify |
|
|
266
|
+
| `healthy` | `0` | the local DB passed its integrity check as-is |
|
|
267
|
+
| `walkedBack` | `0` | the local DB failed, but an older retained restore point passed and was adopted |
|
|
268
|
+
| `exhausted` (`noCandidates`) | `33` | the local DB failed and litestream retains no older restore point |
|
|
269
|
+
| `exhausted` (`allFailed`) | `33` | every retained restore point was tried and every one failed |
|
|
270
|
+
| `exhausted` (`budgetExhausted`) | `33` | the search stopped on `EVIDENT_SESSION_DB_WALKBACK_MAX_POINTS`/`_BUDGET_SECONDS` before trying every retained point |
|
|
271
|
+
| `exhausted` (`enumerationFailed`) | `33` | `litestream ltx` could not be read (bad exit, non-JSON, malformed listing) |
|
|
272
|
+
|
|
273
|
+
`healthy`/`walkedBack`/`skipped` all share exit `0` deliberately: the shell's behaviour
|
|
274
|
+
afterwards — start `litestream replicate` — is identical either way, so a further split
|
|
275
|
+
would be a distinction with no consumer. `noCandidates`/`allFailed` are kept distinct
|
|
276
|
+
from `budgetExhausted` for the same reason `unusableReplica`'s reasons are kept distinct
|
|
277
|
+
above: conflating "we looked and nothing was good" with "we ran out of time/points
|
|
278
|
+
before looking at everything" would report the wrong conclusion to the operator.
|
|
279
|
+
|
|
280
|
+
#### Boot markers
|
|
281
|
+
|
|
282
|
+
| Marker | Emitted from | When it fires | Fields |
|
|
283
|
+
| --- | --- | --- | --- |
|
|
284
|
+
| `WARNING: SESSION-DB-INTEGRITY-FAILED` | `verifySessionDb` (`session-db-verify.ts`) | The local DB fails its check, before the walkback starts | — (prose carries the PRAGMA's own detail) |
|
|
285
|
+
| `WARNING: SESSION-DB-WALKBACK-ENUMERATION-FAILED` | the walkback loop (`session-db-verify.ts`) | `litestream ltx` exited non-zero (prose carries its stderr — missing binary, bad `-config`, S3 error) or answered with a listing that could not be parsed | — (prose carries litestream's own stderr) |
|
|
286
|
+
| `WARNING: SESSION-DB-WALKBACK-CANDIDATE-FAILED` | the walkback loop (`session-db-verify.ts`) | A candidate restore point fails to restore, or restores but also fails its own check | `txid` |
|
|
287
|
+
| `INFO: SESSION-DB-WALKBACK-ADOPTED` | `adopt` (`session-db-verify.ts`) | A candidate passes and is adopted over `opencode.db` | `txid`, `candidates`, `bytes` |
|
|
288
|
+
| `SESSION-DB-INTEGRITY` | `describeSessionDbVerification` (`diagnostics.ts`), logged once per invocation as the final outcome | The local DB passed its check as-is | `bytes` |
|
|
289
|
+
| `SESSION-DB-INTEGRITY-WALKBACK` | `describeSessionDbVerification` (`diagnostics.ts`), logged once per invocation as the final outcome | Same event as `SESSION-DB-WALKBACK-ADOPTED` above, restated as the command's outcome | `txid`, `candidates`, `bytes` |
|
|
290
|
+
| `SESSION-DB-INTEGRITY-EXHAUSTED` | `describeSessionDbVerification` (`diagnostics.ts`), logged once per invocation as the final outcome | Nothing retained passed (any `exhausted` reason); the boot proceeds with a fresh DB | `candidatesTried` (in prose, not `k=v`) |
|
|
291
|
+
|
|
292
|
+
The first four fire only while the walkback loop runs; the last three are always the
|
|
293
|
+
one message this command logs as its own final word on the outcome — `entrypoint.sh`
|
|
294
|
+
reuses `SESSION-DB-INTEGRITY-EXHAUSTED` verbatim when it logs its own `33` handling, the
|
|
295
|
+
same way it already reuses `SESSION-DB-REPLICA-UNUSABLE` for `session-db-classify`'s `31`.
|
|
296
|
+
|
|
228
297
|
### Why the contract is asymmetric
|
|
229
298
|
|
|
230
299
|
`restore` and `sync-once` **never** report a domain outcome through the exit code. A
|
|
@@ -276,6 +345,8 @@ key, so they never appear in `env`'s output or `litestream.yml`.
|
|
|
276
345
|
| `LITESTREAM_BUCKET` / `LITESTREAM_PREFIX` | Object-store bucket and key prefix. | Persistence off (needs **both**): `restore`/`sync-once` no-op, `env` warns. |
|
|
277
346
|
| `AWS_REGION` | Region for the AWS clients (S3, and the ECS/STS calls `self-stop` makes). | Left to the SDK's own resolution. |
|
|
278
347
|
| `CREDS_SYNC_INTERVAL` | Seconds between sync ticks, reported by `env` for the caller's loop. | Falls back to `60`; also on unparseable or non-positive values. |
|
|
348
|
+
| `EVIDENT_SESSION_DB_WALKBACK_MAX_POINTS` | Distinct restore points `session-db-verify`'s walkback will try before giving up. | Falls back to `10`; also on unparseable or non-positive values. |
|
|
349
|
+
| `EVIDENT_SESSION_DB_WALKBACK_BUDGET_SECONDS` | Wall-clock budget, in seconds, for the whole walkback loop. | Falls back to `180`; also on unparseable or non-positive values. |
|
|
279
350
|
| `ANTHROPIC_API_KEY` / `OPENAI_API_KEY` | Presence alone counts as configured model auth (see `model-auth-ready`). | No API-key fallback; `model-auth-ready` then depends solely on the credential files. |
|
|
280
351
|
| `CLUSTER` † / `SERVICE` † | ECS cluster/service `self-stop` scales to `desiredCount=0`. | Warns "cannot self-stop" and exits `20` (keep the task). Ignored by every other command. |
|
|
281
352
|
| `EVIDENT_SELFSTOP_ROLE_ARN` † | Role `self-stop` assumes for its ECS calls. | Optional: falls back to the task role's own credentials. A failed/incomplete assume-role → `20`. |
|