instar 1.3.553 → 1.3.554
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +37 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +18 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/scheduler/JobLeaseClaimStore.d.ts +105 -0
- package/dist/scheduler/JobLeaseClaimStore.d.ts.map +1 -0
- package/dist/scheduler/JobLeaseClaimStore.js +165 -0
- package/dist/scheduler/JobLeaseClaimStore.js.map +1 -0
- package/dist/scheduler/JobLeaseCutoverGate.d.ts +73 -0
- package/dist/scheduler/JobLeaseCutoverGate.d.ts.map +1 -0
- package/dist/scheduler/JobLeaseCutoverGate.js +66 -0
- package/dist/scheduler/JobLeaseCutoverGate.js.map +1 -0
- package/dist/scheduler/JobScheduler.d.ts +53 -0
- package/dist/scheduler/JobScheduler.d.ts.map +1 -1
- package/dist/scheduler/JobScheduler.js +136 -20
- package/dist/scheduler/JobScheduler.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.3.554.md +79 -0
- package/upgrades/side-effects/ws43-journal-lease-cutover.md +132 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Side-Effects Review — WS4.3 journal-lease cutover
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/MULTI-MACHINE-SEAMLESSNESS-SPEC.md` §WS4.3 ("Cutover discipline")
|
|
4
|
+
**Slug:** ws43-journal-lease-cutover
|
|
5
|
+
**Tier:** 2 (multi-machine correctness invariant; safety-invariant risk floor)
|
|
6
|
+
**Flag:** `multiMachine.seamlessness.ws43JournalLease` (default false), `ws43JournalLeaseDryRun` (default true)
|
|
7
|
+
|
|
8
|
+
## What changed
|
|
9
|
+
|
|
10
|
+
Scheduled-job claim deduplication can now upgrade from the legacy best-effort
|
|
11
|
+
AgentBus broadcast (`JobClaimManager`) to a durable, epoch-fenced lease over the
|
|
12
|
+
replicated journal (`JobLeaseClaimStore`). A single pure decision point
|
|
13
|
+
(`JobLeaseCutoverGate.decideClaimPath`) selects which mechanism a job uses, and
|
|
14
|
+
the scheduler routes its three claim seams (remote-claim check, claim-before-spawn,
|
|
15
|
+
release-on-complete) through that decision. New files: `src/scheduler/
|
|
16
|
+
JobLeaseCutoverGate.ts`, `src/scheduler/JobLeaseClaimStore.ts`. Wired into
|
|
17
|
+
`JobScheduler` (new `setJournalLeaseCutover` injector + `resolveClaimPath`/
|
|
18
|
+
`releaseClaim` helpers) and `server.ts` (the production provider closure reading
|
|
19
|
+
the flag + coordinator lease epoch + pool peers' advertised capability). Config
|
|
20
|
+
defaults + types + the `seamlessnessFlags` heartbeat advert added.
|
|
21
|
+
|
|
22
|
+
## Phase 1 — Principle check (signal vs authority)
|
|
23
|
+
|
|
24
|
+
This IS a decision point (it gates which claim mechanism runs). It is correctly
|
|
25
|
+
an **authority** because dedup is a correctness mechanism, not a signal — but the
|
|
26
|
+
authority is NARROW and STRUCTURAL: the gate keys ONLY on objective facts (flag
|
|
27
|
+
state, online-peer presence, the boolean capability each peer advertises in its
|
|
28
|
+
authenticated heartbeat) — never on interpreting message content or any brittle
|
|
29
|
+
heuristic. It cannot block a user action; the worst case is "stay on the legacy
|
|
30
|
+
bus path," which is byte-for-byte today's behavior. The gate fails toward the
|
|
31
|
+
conservative side (bus) on any ambiguity (older peer, offline peer, throwing gate
|
|
32
|
+
read). This complies with `docs/signal-vs-authority.md`: a structural ownership/
|
|
33
|
+
coherence check, not a brittle content gate with blocking authority.
|
|
34
|
+
|
|
35
|
+
## Phase 4 — Review questions
|
|
36
|
+
|
|
37
|
+
1. **Over-block** — The gate never blocks a job; it only chooses a dedup
|
|
38
|
+
mechanism. The journal lease's epoch fence could in principle refuse OUR claim
|
|
39
|
+
if a peer holds a strictly-newer-epoch lease — but that is the correct
|
|
40
|
+
behavior (the newer-epoch holder is the current lease-holder; we must yield).
|
|
41
|
+
A same/older-epoch peer claim is fenced OUT, so we are never wrongly blocked by
|
|
42
|
+
a stale peer. No legitimate run is wrongly rejected.
|
|
43
|
+
|
|
44
|
+
2. **Under-block** — The journal-lease path relies on the replicated journal
|
|
45
|
+
actually carrying claim records between machines (`applyRemote`). This PR ships
|
|
46
|
+
the gate + the local epoch-fenced store + the cutover wiring; the journal
|
|
47
|
+
EMISSION/APPLY transport for the claim kind is the existing replication
|
|
48
|
+
substrate's responsibility and is gated behind the same flag-coherence advert
|
|
49
|
+
so an older peer that can't apply the kind keeps the WHOLE pool on the bus (it
|
|
50
|
+
never advertises `ws43JournalLease`). Until the flag is flipped on a fully
|
|
51
|
+
coherent pool, dedup behavior is IDENTICAL to today (bus). The dry-run default
|
|
52
|
+
means even a flag-on coherent pool stays on the bus while logging intended
|
|
53
|
+
claims — so under-block risk during rollout is zero (the bus is the baseline).
|
|
54
|
+
|
|
55
|
+
3. **Level-of-abstraction fit** — Correct layer. The cutover decision lives in
|
|
56
|
+
the scheduler (which owns the claim seams), the gate is a pure function (no IO,
|
|
57
|
+
independently testable), and the durable lease is its own store mirroring the
|
|
58
|
+
existing `JobClaimManager` shape. The flag-coherence read reuses the existing
|
|
59
|
+
`seamlessnessFlags` heartbeat advert + registry the WS1.1/WS4.4 gates already
|
|
60
|
+
use — no parallel coherence machinery.
|
|
61
|
+
|
|
62
|
+
4. **Signal vs authority compliance** — Compliant (see Phase 1). Structural
|
|
63
|
+
authority keyed on objective facts; fails conservative; no content heuristics;
|
|
64
|
+
cannot block a user action.
|
|
65
|
+
|
|
66
|
+
5. **Interactions** — The gate guarantees the journal lease and the bus broadcast
|
|
67
|
+
are NEVER both consulted for the same job in the same evaluation (exactly one
|
|
68
|
+
`path` per decision) — the named migration hazard. The release seam calls
|
|
69
|
+
BOTH stores' `completeClaim` idempotently (each is a no-op when this machine
|
|
70
|
+
doesn't own the slug's record), so a mid-run flag flip between claim and
|
|
71
|
+
complete cannot strand a lease. It composes cleanly with the WS4.3 role-guard
|
|
72
|
+
(a separate spawn-boundary refusal that runs BEFORE the claim seam) — the two
|
|
73
|
+
are orthogonal. No double-fire: `resolveClaimPath` is evaluated once at the
|
|
74
|
+
check seam and the result reused at the claim seam.
|
|
75
|
+
|
|
76
|
+
6. **External surfaces** — Adds one boolean field (`ws43JournalLease`) to the
|
|
77
|
+
`seamlessnessFlags` heartbeat advert. Additive — older peers omit it (read as
|
|
78
|
+
non-participant, the conservative side). No new HTTP route. No user-visible
|
|
79
|
+
message. The advert is only `true` when the flag is on AND not dry-run, so a
|
|
80
|
+
dry-run machine never advertises participation it isn't actually performing.
|
|
81
|
+
|
|
82
|
+
7. **Multi-machine posture** — This feature IS multi-machine machinery.
|
|
83
|
+
Posture: **machine-local decision fed by a proxied-on-read coherence view.**
|
|
84
|
+
Each machine independently runs the gate over the peers' advertised capability
|
|
85
|
+
(read live from the registry's heartbeat data), and the journal lease store is
|
|
86
|
+
per-machine but its records replicate via the journal. Invariant-5 flag
|
|
87
|
+
coherence is enforced: the cutover engages pool-wide ONLY when every online
|
|
88
|
+
peer advertises the capability — never a window where one machine leases while
|
|
89
|
+
a peer broadcasts. Single-machine (no peers) is a strict no-op (the gate
|
|
90
|
+
returns `bus`/`single-machine` and the journal store is never touched). The
|
|
91
|
+
epoch fence (coordinator lease epoch) carries ownership across a demotion so a
|
|
92
|
+
demoted machine's stale claim can't steal a job. Designed for N machines, no
|
|
93
|
+
2-peer assumption.
|
|
94
|
+
|
|
95
|
+
8. **Rollback cost** — Trivial. The feature is dark (flag default false). Flip
|
|
96
|
+
`multiMachine.seamlessness.ws43JournalLease` off (or leave it absent) and the
|
|
97
|
+
scheduler reverts to the legacy bus path with no migration, no data repair —
|
|
98
|
+
the journal lease store is just an inert local JSON ledger. Dry-run (default)
|
|
99
|
+
is an additional safe rung: flag on but no real cutover. The off-switch is read
|
|
100
|
+
live at each claim boundary, so a config edit + session restart fully reverts.
|
|
101
|
+
|
|
102
|
+
## Phase 5 — Second-pass review (high-risk: touches scheduler claim/dedup + a "gate")
|
|
103
|
+
|
|
104
|
+
Concern lens applied: could the cutover ever let TWO machines run the same job?
|
|
105
|
+
- Within ONE machine's evaluation, the gate returns exactly one path — verified by
|
|
106
|
+
the `NEVER returns both mechanisms` unit test and the integration/e2e
|
|
107
|
+
`never-both` assertions (coherent → journal only; mixed → bus only).
|
|
108
|
+
- ACROSS machines: the cutover engages pool-wide only under flag coherence (every
|
|
109
|
+
online peer advertises it), so the pool is either all-journal or all-bus for a
|
|
110
|
+
job set — never split. A peer that can't participate keeps everyone on the bus.
|
|
111
|
+
- A demotion race is fenced by the lease epoch (stale-epoch applyRemote rejected;
|
|
112
|
+
same/older-epoch tryClaim refused) — covered by the epoch-fence unit tests.
|
|
113
|
+
|
|
114
|
+
Concur with the review. The load-bearing invariant (no double-run across the
|
|
115
|
+
cutover; no stranded timers on a demoted machine) is structurally enforced by the
|
|
116
|
+
single-decision gate + epoch fence and is covered at all three test tiers.
|
|
117
|
+
|
|
118
|
+
## Tests
|
|
119
|
+
|
|
120
|
+
- Unit: `tests/unit/job-lease-cutover-gate.test.ts` (9), `tests/unit/
|
|
121
|
+
job-lease-claim-store.test.ts` (8) — gate decision matrix incl. never-both +
|
|
122
|
+
flag coherence + single-machine no-op; epoch fencing + durability.
|
|
123
|
+
- Integration: `tests/integration/scheduler-journal-lease-cutover.test.ts` (6) —
|
|
124
|
+
the scheduler routes through the gate; coherent→journal, mixed→bus, dry-run,
|
|
125
|
+
single-machine, remote-lease skip, live flag flip.
|
|
126
|
+
- E2E "feature is alive": `tests/e2e/scheduler-journal-lease-cutover-alive.test.ts`
|
|
127
|
+
(4) — the EXACT server.ts provider closure (real config + real coordinator
|
|
128
|
+
epoch + real MachinePoolRegistry heartbeat) drives a real triggerJob to take
|
|
129
|
+
the journal lease vs the bus; proves the wiring is live, not a stub.
|
|
130
|
+
|
|
131
|
+
All 27 new tests pass; tsc clean; no-silent-fallbacks, dark-gate line-map, and
|
|
132
|
+
feature-delivery-completeness gates pass; docs-coverage class floor improved.
|