instar 1.3.246 → 1.3.248
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 +39 -6
- package/dist/commands/server.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +15 -1
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/RelocationNicknameSet.d.ts +42 -0
- package/dist/core/RelocationNicknameSet.d.ts.map +1 -0
- package/dist/core/RelocationNicknameSet.js +47 -0
- package/dist/core/RelocationNicknameSet.js.map +1 -0
- package/dist/core/TopicPlacementDescription.d.ts +46 -0
- package/dist/core/TopicPlacementDescription.d.ts.map +1 -0
- package/dist/core/TopicPlacementDescription.js +32 -0
- package/dist/core/TopicPlacementDescription.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +3 -1
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +6 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +3 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +11 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +163 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +64 -64
- package/src/scaffold/templates.ts +3 -1
- package/upgrades/1.3.247.md +48 -0
- package/upgrades/1.3.248.md +46 -0
- package/upgrades/side-effects/mm-placement-transfer-robustness.md +45 -0
- package/upgrades/side-effects/telegraph-e2e-flake-tolerant.md +58 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
The Telegraph publishing end-to-end test (`tests/e2e/telegraph-publish.test.ts`)
|
|
9
|
+
makes real calls to the live Telegraph API, which occasionally returns transient
|
|
10
|
+
errors (`PAGE_SAVE_FAILED`, network blips, 5xx, rate-limit) through no fault of
|
|
11
|
+
ours. Because the suite runs in the standard CI lane (it only skips when
|
|
12
|
+
`SKIP_E2E=1`), one such hiccup failed the entire build on an unrelated PR — a
|
|
13
|
+
Gemini quota change (#756) that touches zero Telegraph code got a red build
|
|
14
|
+
purely because the Telegraph service blinked at the wrong moment.
|
|
15
|
+
|
|
16
|
+
This change adds a test-local `withTransientRetry` helper wrapping the six
|
|
17
|
+
live-API call sites (`ensureAccount` / `publishPage` / `editPage` /
|
|
18
|
+
`getPageViews`): a transient / network / 5xx / 429 error is retried up to 4× with
|
|
19
|
+
short backoff; a real failure — an assertion-worthy bug, or a persistent outage
|
|
20
|
+
after retries are exhausted — still fails immediately and loudly.
|
|
21
|
+
|
|
22
|
+
## What to Tell Your User
|
|
23
|
+
|
|
24
|
+
Nothing user-facing — this is an internal CI-reliability fix. No shipped behavior
|
|
25
|
+
changes; agent-only.
|
|
26
|
+
|
|
27
|
+
## Summary of New Capabilities
|
|
28
|
+
|
|
29
|
+
None — internal test-suite robustness improvement (flaky external-API e2e no
|
|
30
|
+
longer fails CI on unrelated PRs).
|
|
31
|
+
|
|
32
|
+
## Evidence
|
|
33
|
+
|
|
34
|
+
- **Reproduction:** Codey PR #756 (a Gemini quota-state change touching zero
|
|
35
|
+
Telegraph code) got a red CI build when the live Telegraph API returned a
|
|
36
|
+
transient `PAGE_SAVE_FAILED` during the Unit-Tests node-22 shard. Confirmed via
|
|
37
|
+
`instar dev:ci-failures 756`:
|
|
38
|
+
`✗ src/publishing/TelegraphService.ts:298 Telegraph API error: PAGE_SAVE_FAILED`
|
|
39
|
+
surfacing at `tests/e2e/telegraph-publish.test.ts:102`.
|
|
40
|
+
- **Before:** any transient Telegraph hiccup failed the whole build on unrelated
|
|
41
|
+
PRs — a false failure that blocks merges and sends people chasing a non-bug.
|
|
42
|
+
- **After:** the six live-API calls retry transient errors up to 4×; real
|
|
43
|
+
failures still fail immediately. Verified locally: `tsc --noEmit` clean and all
|
|
44
|
+
5 e2e tests pass against the live API
|
|
45
|
+
(`npx vitest run tests/e2e/telegraph-publish.test.ts --config vitest.e2e.config.ts`
|
|
46
|
+
→ `Tests 5 passed (5)`).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Multi-Machine Placement Observability + Reliable Transfer — Plain-English Overview
|
|
2
|
+
|
|
3
|
+
> The one-line version: an agent (and a user) can now reliably ASK which machine a topic is running on and WHY, and move a topic between machines deterministically — instead of guessing from a hostname and hoping a phrase gets recognized.
|
|
4
|
+
|
|
5
|
+
## The problem in one breath
|
|
6
|
+
|
|
7
|
+
While testing live topic-transfer on a real laptop↔mini pair, two gaps surfaced. (1) "Move this to <a machine>" worked toward a peer but silently did nothing when moving *back* to the machine currently handling the topic — the command fell through into the session as a normal message. (2) From a standby session there was no way to read where a topic actually runs or why, so the agent inferred placement and stated a guess as fact, confusing the user.
|
|
8
|
+
|
|
9
|
+
## What already exists
|
|
10
|
+
|
|
11
|
+
- **Session pool routing (§L4)** — the lease-holder polls Telegram and forwards a topic's messages to the machine that owns the session; ownership lives in the SessionOwnership registry, hard pins in the TopicPlacementPinStore (a holder-local file).
|
|
12
|
+
- **"move this to <nickname>" recognizer** — a deterministic recognizer over the known-machine nickname set, fed from `MachinePoolRegistry.getCapacities()`.
|
|
13
|
+
- **GET /pool** — shows machines, nicknames, the lease-holder. It does NOT answer per-topic placement.
|
|
14
|
+
|
|
15
|
+
## What this adds
|
|
16
|
+
|
|
17
|
+
The root cause of (1): the recognizer's known-nickname set came straight from `getCapacities()`, which can omit a machine's OWN nickname. Because the lifeline forwards inbound to the holder, the relocation check runs on the very machine you're moving back to — so its own nickname being absent made "move to self" unrecognizable. The fix unions the local machine's own nickname (resolved capacities → identity entry → deterministic derive) into the recognizer set.
|
|
18
|
+
|
|
19
|
+
On top of that, two new HTTP surfaces:
|
|
20
|
+
|
|
21
|
+
- **GET /pool/placement?topic=N** — owner machine + nickname, the REASON (`pinned` = deliberate move vs `placed` = load-balanced vs `unowned`), and the lease-holder. Answerable from any machine: a non-holder proxies to the holder, whose pin store is authoritative.
|
|
22
|
+
- **POST /pool/transfer {topic, to}** — a deterministic move that runs the SAME validated planner as the natural-language path (rate-limit, online, already-there checks), without depending on phrasing. A non-holder proxies to the holder.
|
|
23
|
+
|
|
24
|
+
## The new pieces
|
|
25
|
+
|
|
26
|
+
- **RelocationNicknameSet** (pure) — builds the recognizer's nickname set, unioning the self nickname. Cannot do I/O; fully unit-tested.
|
|
27
|
+
- **TopicPlacementDescription** (pure) — computes the placement answer from already-resolved state + a nickname resolver. No I/O.
|
|
28
|
+
- **Two routes** in the existing pool route group — read-only placement; mutating transfer. Both 503 when the pool is dark/single-machine.
|
|
29
|
+
|
|
30
|
+
## The safeguards
|
|
31
|
+
|
|
32
|
+
- **Reversibility / blast radius** — the recognizer change is behaviorally identical when the self nickname is already present (the common case); it only ADDS resolution when it was missing. The routes are gated: they 503 unless the pool is wired (dark by default on the fleet), so production agents are unaffected until the pool is enabled.
|
|
33
|
+
- **No new authority** — the transfer route reuses the existing `planTransferByNickname` planner (same rate-limit + offline-confirm gates); it does not invent a new mutation path. Ownership release uses the existing CAS.
|
|
34
|
+
- **Migration parity** — `PostUpdateMigrator` gains an idempotent block that appends the two new capability lines to agents that already have the pool section (guarded by a unique `/pool/placement` marker), and the freshly-injected section includes them for new agents. The CLAUDE.md template is updated in lockstep (Agent Awareness Standard).
|
|
35
|
+
- **Tests** — Tier 1 (12 unit: both pure helpers, incl. the exact regression), Tier 2 (11 integration: both routes over HTTP incl. pinned-vs-placed, 404/409/confirm), Tier 3 (3 e2e: routes alive through the real AgentServer + auth-gated). Full `tsc --noEmit` clean.
|
|
36
|
+
|
|
37
|
+
## Spec lineage
|
|
38
|
+
|
|
39
|
+
This is §L4 (Session Router / placement + TopicPlacement metadata) and §L5 (Transfer orchestrator) of the approved `docs/specs/MULTI-MACHINE-SESSION-POOL-SPEC.md` — surfacing observability + a deterministic lever over machinery the spec already defines. No new primitives, no new authority.
|
|
40
|
+
|
|
41
|
+
## CI follow-up (same PR #750)
|
|
42
|
+
|
|
43
|
+
Two CI gates flagged the additive surface; both fixed without behavior change:
|
|
44
|
+
- **Docs Coverage** (`route`/`class` floors): documented the new routes + helper classes (and several related pool/mesh ones) in `site/src/content/docs/architecture/multi-machine-session-pool.md` and `features/multi-machine.md` — real feature docs the area lacked. Both floors back ≥55%.
|
|
45
|
+
- **no-silent-fallbacks ratchet** (457): the proxy/best-effort `catch` blocks added by the two new routes + the self-nickname resolver are annotated `@silent-fallback-ok` with honest justifications (the proxy fallbacks are explicitly labelled in the response or surface a 502; the ownership-release catch is a best-effort optimization the pin already covers). Count back to the 457 baseline — no new genuine silent fallbacks.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Side-Effects Review — Telegraph e2e tolerant of transient external-API errors
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `telegraph-e2e-flake-tolerant`
|
|
4
|
+
**Date:** `2026-06-04`
|
|
5
|
+
**Author:** `echo`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
`tests/e2e/telegraph-publish.test.ts` makes REAL calls to the public Telegraph
|
|
11
|
+
API. That API intermittently returns transient errors (`PAGE_SAVE_FAILED`,
|
|
12
|
+
network blips, 5xx, rate-limit) under no fault of ours. Because the suite runs
|
|
13
|
+
in the standard CI lane (it only skips when `SKIP_E2E=1`), a transient hiccup
|
|
14
|
+
fails the whole build on UNRELATED PRs — it just failed the Unit-Tests shard on
|
|
15
|
+
Codey PR #756 (a Gemini quota change touching zero Telegraph code).
|
|
16
|
+
|
|
17
|
+
The fix adds a test-local `withTransientRetry(label, fn)` helper and wraps the
|
|
18
|
+
six live-API call sites (`ensureAccount` ×2, `publishPage` ×2, `editPage`,
|
|
19
|
+
`getPageViews`). On a transient/network error it retries up to 4× with linear
|
|
20
|
+
backoff; a non-transient error (real bug / assertion-worthy failure) throws
|
|
21
|
+
immediately; if all retries are exhausted it throws (genuinely-down → fail).
|
|
22
|
+
|
|
23
|
+
## Decision-point inventory
|
|
24
|
+
|
|
25
|
+
One decision point: `withTransientRetry` classifies a caught error as transient
|
|
26
|
+
(via the `TRANSIENT_API_ERROR` regex) or not. Transient → retry/eventually-fail;
|
|
27
|
+
non-transient → rethrow immediately.
|
|
28
|
+
|
|
29
|
+
## 1. Over-block
|
|
30
|
+
|
|
31
|
+
**What legitimate failures does this now hide?** None that matter. The regex
|
|
32
|
+
matches only transient external-service signatures (`PAGE_SAVE_FAILED`,
|
|
33
|
+
`ENOTFOUND`/`ECONNRESET`/`ETIMEDOUT`/`EAI_AGAIN`, `socket hang up`,
|
|
34
|
+
`fetch failed`, 5xx, 429). Assertion failures (`expect(...)`) are NOT thrown by
|
|
35
|
+
the wrapped service calls, so real test-logic regressions still fail. A genuine
|
|
36
|
+
persistent API outage still fails the test after the retries are exhausted.
|
|
37
|
+
|
|
38
|
+
## 2. Under-block
|
|
39
|
+
|
|
40
|
+
**What does it still catch?** Any non-transient error from the service (bad
|
|
41
|
+
auth, a real TelegraphService bug, a 4xx other than 429) rethrows on the first
|
|
42
|
+
attempt — no masking. The retry is scoped to the e2e file only; no production
|
|
43
|
+
code path retries (so the publish-idempotency concern — a retry creating a
|
|
44
|
+
duplicate page — is irrelevant: duplicate test pages are harmless, Telegraph
|
|
45
|
+
pages are free + don't expire, and the assertions check `>= 1`, not an exact
|
|
46
|
+
count).
|
|
47
|
+
|
|
48
|
+
## 3. Blast radius
|
|
49
|
+
|
|
50
|
+
Test-only: one file, `tests/e2e/telegraph-publish.test.ts`. No `src/` change, no
|
|
51
|
+
production behavior change, no API/schema/config change. The helper is local to
|
|
52
|
+
the file (not exported / not shared).
|
|
53
|
+
|
|
54
|
+
## 4. Reversibility
|
|
55
|
+
|
|
56
|
+
Fully reversible: revert the one file. No state, no migration, no persisted
|
|
57
|
+
format. Verified locally: `tsc --noEmit` clean and all 5 e2e tests pass against
|
|
58
|
+
the live API.
|