instar 1.3.1213 → 1.3.1215
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 +33 -0
- package/dist/commands/server.js.map +1 -1
- package/dist/core/tailscaleStatusParser.d.ts +27 -2
- package/dist/core/tailscaleStatusParser.d.ts.map +1 -1
- package/dist/core/tailscaleStatusParser.js +30 -4
- package/dist/core/tailscaleStatusParser.js.map +1 -1
- package/dist/data/standards-guard-index.json +1 -1
- package/dist/data/standards-guard-index.meta.json +2 -2
- package/dist/data/standards-registry.meta.json +1 -1
- package/dist/monitoring/RopeHealthMonitor.d.ts +13 -0
- package/dist/monitoring/RopeHealthMonitor.d.ts.map +1 -1
- package/dist/monitoring/RopeHealthMonitor.js +25 -2
- package/dist/monitoring/RopeHealthMonitor.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +1 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/testing/selfActionRegistry.d.ts.map +1 -1
- package/dist/testing/selfActionRegistry.js +38 -0
- package/dist/testing/selfActionRegistry.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +46 -46
- package/src/data/standards-guard-index.json +1 -1
- package/src/data/standards-guard-index.meta.json +2 -2
- package/src/data/standards-registry.meta.json +1 -1
- package/upgrades/1.3.1214.md +24 -0
- package/upgrades/1.3.1215.md +39 -0
- package/upgrades/side-effects/rope-key-expiry-mesh-scope.md +85 -0
- package/upgrades/side-effects/w29-ledger-selfaction-model.md +39 -0
- package/upgrades/w29-ledger-selfaction-model.eli16.md +7 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The Tailscale key-expiry tier of `RopeHealthMonitor` now scans only tailnet nodes that back
|
|
9
|
+
a mesh rope (plus self), rather than every node on the tailnet. `parseTailscaleStatus`
|
|
10
|
+
takes an optional mesh-address set and flags each entry `backsMeshRope`; `soonestKeyExpiry`
|
|
11
|
+
takes `meshScopedOnly`; `server.ts` supplies the addresses from the registry's `tailscale`
|
|
12
|
+
endpoints. An unreadable or empty address source falls back to the previous tailnet-wide
|
|
13
|
+
scan, so a failure is never quieter.
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
Your machines warn you when a Tailscale key is about to expire — but they were checking
|
|
18
|
+
every device on your account, including phones and old laptops that aren't part of the
|
|
19
|
+
mesh. One dead device with a lapsed key made that warning permanent, so it stopped meaning
|
|
20
|
+
anything, and on 2026-08-29 it was read as a live risk and reported as one.
|
|
21
|
+
|
|
22
|
+
The warning now covers only the devices your machines actually reach each other on. Same
|
|
23
|
+
horizon, same wording — it just stops crying wolf about hardware that can't affect
|
|
24
|
+
anything.
|
|
25
|
+
|
|
26
|
+
## Summary of New Capabilities
|
|
27
|
+
|
|
28
|
+
- Key-expiry warnings are scoped to devices that genuinely carry mesh traffic.
|
|
29
|
+
- This machine's own key always counts, since its expiry would drop every route it has.
|
|
30
|
+
- Every failure path (unreadable registry, empty list) falls back to the old tailnet-wide
|
|
31
|
+
scan — the change can make the check noisier, never quieter.
|
|
32
|
+
- No device names, addresses, or account details leave the parser; addresses go in, a
|
|
33
|
+
boolean comes out.
|
|
34
|
+
|
|
35
|
+
## Evidence
|
|
36
|
+
|
|
37
|
+
- Unit: `tests/unit/tailscaleStatusParser.test.ts` (+6), `tests/unit/RopeHealthMonitor.test.ts` (+2),
|
|
38
|
+
verified red-then-green against pre-fix behaviour.
|
|
39
|
+
- Side-effects review: `upgrades/side-effects/rope-key-expiry-mesh-scope.md`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Side-effects review — rope key-expiry mesh scoping
|
|
2
|
+
|
|
3
|
+
**Change:** the Tailscale key-expiry tier of `RopeHealthMonitor` now considers only tailnet
|
|
4
|
+
nodes that back a mesh rope (plus self), instead of every node on the tailnet.
|
|
5
|
+
`parseTailscaleStatus` gained an optional mesh-address set and a per-entry
|
|
6
|
+
`backsMeshRope` flag; `soonestKeyExpiry` gained `opts.meshScopedOnly`; `server.ts` supplies
|
|
7
|
+
the addresses from the registry's `tailscale` endpoints.
|
|
8
|
+
|
|
9
|
+
**Origin (live, 2026-08-29, topic 62395):** a tailnet node offline since 2026-08-13 with a
|
|
10
|
+
lapsed key was the tailnet-wide soonest expiry, so `GET /mesh/rope-health` reported
|
|
11
|
+
`warn: true, inDays: -16.6` continuously. Every real mesh machine's key was valid into
|
|
12
|
+
Dec 2026 / Feb 2027. The permanent warning was not merely noise — it was read as a live
|
|
13
|
+
finding and relayed to the operator as a real risk requiring their login.
|
|
14
|
+
|
|
15
|
+
## 1. Over-block — what legitimate input does this now reject?
|
|
16
|
+
|
|
17
|
+
A genuine expiry on a tailnet node that backs a mesh rope but whose address is NOT in the
|
|
18
|
+
registry's endpoint list — e.g. a peer reachable over tailscale that has only ever
|
|
19
|
+
advertised `lan`/`cloudflare`. That node's expiry would no longer warn.
|
|
20
|
+
|
|
21
|
+
Bounded by two fallbacks that both fail LOUD: an unreadable address source and an empty
|
|
22
|
+
address set BOTH degrade to the tailnet-wide scan. So the narrowed scope applies only when
|
|
23
|
+
a non-empty mesh address list is genuinely available. Self is unconditionally included.
|
|
24
|
+
|
|
25
|
+
## 2. Under-block — what does this still miss?
|
|
26
|
+
|
|
27
|
+
It does not detect a rope dropping for any reason other than key expiry (unchanged), and
|
|
28
|
+
it cannot warn about a mesh machine whose tailscale address this machine has never
|
|
29
|
+
recorded. It also does not change the two-week horizon, so a key that lapses inside one
|
|
30
|
+
check interval is still reported late — pre-existing, untouched.
|
|
31
|
+
|
|
32
|
+
## 3. Level-of-abstraction fit
|
|
33
|
+
|
|
34
|
+
Correct. The parser owns the scrubbed shape and is the only place that may see addresses,
|
|
35
|
+
so the matching belongs there; the monitor owns the policy (`meshScopedOnly`); the wiring
|
|
36
|
+
site owns knowledge of the registry. Putting the filter in the monitor would have required
|
|
37
|
+
addresses to escape the parser, breaking that file's stated content-scrub boundary.
|
|
38
|
+
|
|
39
|
+
## 4. Signal vs authority compliance
|
|
40
|
+
|
|
41
|
+
Compliant. This is a digest/status signal with no blocking authority — it gates nothing,
|
|
42
|
+
changes no routing, and cannot suppress a rope. It makes an existing signal more accurate.
|
|
43
|
+
|
|
44
|
+
## 5. Interactions
|
|
45
|
+
|
|
46
|
+
- The `key-expiry-warning` metric fires strictly less often (that is the fix).
|
|
47
|
+
- `composeDigest()` drops the permanent expiry sentence when scoped — the other digest
|
|
48
|
+
sentences (per-peer conditions) are untouched.
|
|
49
|
+
- `TailscaleKeyExpiryEntry` gained a field; one existing unit assertion deep-equalled the
|
|
50
|
+
old shape and was updated. No serialized/persisted format includes this type.
|
|
51
|
+
- No interaction with the U4.3 recovery prober or the resolver — the expiry tier has its
|
|
52
|
+
own cadence and data source.
|
|
53
|
+
|
|
54
|
+
## 6. External surfaces
|
|
55
|
+
|
|
56
|
+
`GET /mesh/rope-health → keyExpiry.soonest` may now name a later expiry (a mesh node)
|
|
57
|
+
where it previously named an earlier one (an unrelated node). No shape change. The
|
|
58
|
+
content-scrub boundary is preserved: addresses flow INTO the parser and only a boolean
|
|
59
|
+
flows out — no identity, address, or account data is added to any output.
|
|
60
|
+
|
|
61
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
62
|
+
|
|
63
|
+
**Machine-local BY DESIGN.** Each machine runs its own `tailscale status` and reads its own
|
|
64
|
+
registry, so each scopes to the peers it knows. This is correct rather than a limitation: a
|
|
65
|
+
tailnet node backing a rope is a per-observer fact, and the digest is composed per machine.
|
|
66
|
+
No replication path added. A single-machine agent supplies an empty address list and
|
|
67
|
+
therefore keeps exactly today's tailnet-wide behaviour.
|
|
68
|
+
|
|
69
|
+
## 8. Rollback cost
|
|
70
|
+
|
|
71
|
+
Trivial. Remove the `meshTailscaleAddresses` dep from the `server.ts` construction and the
|
|
72
|
+
monitor reverts to the tailnet-wide scan by an explicitly-tested path. No persisted data,
|
|
73
|
+
no migration, no state repair.
|
|
74
|
+
|
|
75
|
+
## Tests
|
|
76
|
+
|
|
77
|
+
- Unit `tests/unit/tailscaleStatusParser.test.ts` (+6): flagging, mesh-scoped soonest,
|
|
78
|
+
un-scoped soonest (pre-fix behaviour retained), no-set and empty-set back-compat, self
|
|
79
|
+
always counts, node with no address array is not mesh-backing.
|
|
80
|
+
- Unit `tests/unit/RopeHealthMonitor.test.ts` (+2): the dead-node regression through the
|
|
81
|
+
monitor (scoped vs un-scoped on identical input), and the throwing/empty source falling
|
|
82
|
+
back to tailnet-wide rather than to a silent empty scope. Verified RED against pre-fix
|
|
83
|
+
behaviour and green after.
|
|
84
|
+
- E2E: not applicable — no new route or feature-liveness surface; this narrows an existing
|
|
85
|
+
status field already covered by the monitor's own suite.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Side-Effects Review — window-lifecycle self-action convergence model
|
|
2
|
+
|
|
3
|
+
**Slug:** w29-ledger-selfaction-model · **Date:** 2026-08-29 · **Author:** Codey (W29 Lane C2), commit ritual by Echo/Observer 1 · **Tier:** 1 (test infrastructure, 40 LOC)
|
|
4
|
+
|
|
5
|
+
## Summary
|
|
6
|
+
Registers the WindowLifecycleObligationLedger's owned 60s notify tick in `src/testing/selfActionRegistry.ts` (a faithful convergence model of its save-before-send dedupe brake) plus the `@self-action-controller` annotation at the real emit site in `src/server/routes.ts`. Closes the ACT-320 closure:gap declared at the W28 merge.
|
|
7
|
+
|
|
8
|
+
## 1. Over-block
|
|
9
|
+
None — the change blocks nothing; it is a registry entry + comment. The ratchet could over-fail future edits to the real brake; that is its purpose.
|
|
10
|
+
|
|
11
|
+
## 2. Under-block
|
|
12
|
+
The model covers the dedupe-brake class only (one issue → one emit, restart-surviving). It does not model the tick's other behaviors (evaluation cost, remediation flows) — those are not self-action emits.
|
|
13
|
+
|
|
14
|
+
## 3. Level-of-abstraction fit
|
|
15
|
+
Matches the established registry pattern (30th entry, same shape as the other 29): modeled trigger→brake→emit under the pinned PressureFixture. No new mechanism.
|
|
16
|
+
|
|
17
|
+
## 4. Signal vs authority compliance
|
|
18
|
+
No decision authority anywhere — pure test infrastructure. The ratchet is CI signal.
|
|
19
|
+
|
|
20
|
+
## 5. Interactions
|
|
21
|
+
The forcing lint (`lint-no-unregistered-self-action`) stops flagging this emit (verified); no other check consumes the registry entry. No double-fire risk — the annotation is a comment.
|
|
22
|
+
|
|
23
|
+
## 6. External surfaces
|
|
24
|
+
None. No runtime behavior, routes, or messaging changes.
|
|
25
|
+
|
|
26
|
+
## 7. Multi-machine posture
|
|
27
|
+
Not applicable — test-only code; the modeled controller itself is Echo-local by the W28 spec's non-leakage rule.
|
|
28
|
+
|
|
29
|
+
## 8. Rollback cost
|
|
30
|
+
Revert the commit; the lint returns to report-only flagging of the emit. No data or state involved.
|
|
31
|
+
|
|
32
|
+
## Fidelity verification (the load-bearing check)
|
|
33
|
+
The model records the issue into durable state BEFORE emitting, mirroring `routes.ts` where `ledger.surfacedIssues.push(...)` + `windowStore.save(...)` precede the async `sendToTopic` (verified at the shipped lines during this review). Ratchet: 141/141 including the new entry's bounded-emission and restart cases.
|
|
34
|
+
|
|
35
|
+
## Review record
|
|
36
|
+
Lane C2 (codex): 1 review cycle, clean, stop conditions declared before cycle 1, last-material-defect cycle 0 (none found). Observer independently verified fidelity + gates at commit time.
|
|
37
|
+
|
|
38
|
+
## Conclusion
|
|
39
|
+
Clear to ship.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# ELI16 — proving the rulebook engine's messenger can't spam
|
|
2
|
+
|
|
3
|
+
The window-rulebook engine that shipped this week has a background loop that checks, every minute, whether any window duty is being violated — and when it finds a new problem, it sends one notice to the observers' channel. A loop that sends messages on its own is exactly the kind of thing that has caused message floods before, so this repo keeps a registry of every such self-acting loop, each paired with a small simulated model of its braking logic. A test then squeezes every model under sustained worst-case pressure — the problem never goes away, the process restarts mid-stream — and proves the loop settles at a bounded number of actions instead of firing forever.
|
|
4
|
+
|
|
5
|
+
The engine's loop was shipped with its brake in the code (it durably records each issue BEFORE sending, so the same issue can never send twice — even across a restart) but WITHOUT its entry in that registry, which was tracked as a follow-up with a deadline. This change pays that debt: it adds the faithful model of the engine's brake to the registry (the model was checked line-against-line with the real code: record-first, then send), plus the one-line annotation at the real send site that links code and registry. The pressure test now covers it — 141 checks pass, including the new ones proving one problem yields exactly one notice, forever, restart included.
|
|
6
|
+
|
|
7
|
+
Nothing about the engine's behavior changes. This is test infrastructure: the safety net under the engine's messenger, not the messenger itself. If someone later edits the engine's brake and breaks it, the registry test is now the tripwire that catches it before it ships.
|