instar 1.3.802 → 1.3.804

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.
@@ -0,0 +1,29 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Commitment auto-expiry addresses the live backlog shape from 2026-07-10: 652 open commitments, 626 agent-owned and older than 7 days, mostly completed work that was never explicitly closed. `CommitmentTracker` now has a bounded periodic sweep controlled by `commitments.autoExpiry` (`enabled:true`, `maxAgeDays:21`, `sweepIntervalMs:21600000`, `dryRun:true` by default). It targets only old agent-owned open commitments, never `owner:"user"`, never young commitments, and never a commitment with an unmet future `hardDeadlineAt`. Eligible rows move through the existing terminal `expired` state with resolution `auto-expired: aged out >Nd, presumed completed-but-unclosed`.
9
+
10
+ The sweep copies the existing verify-sweep write discipline: every per-commitment transition marks the store dirty under `batchingSaves`, then flushes exactly one commitments-store write at the end. It is capped at 500 expirations per pass and logs one aggregate line per sweep (`scanned`, `eligible`, `expired`, `dryRun`, `maxAgeDays`, `capped`) rather than one line per row. Dry-run mode logs eligibility without mutating, so this release proves the candidate count and log shape before any cleanup is armed.
11
+
12
+ ## What to Tell Your User
13
+
14
+ - Old agent-owned follow-up promises now have a cleanup path. By default the system only reports how many stale rows it would expire; when dry-run is later turned off, it will close old agent-owned commitments automatically instead of letting the backlog drown current promises.
15
+ - The cleanup is deliberately conservative: it never touches commitments owned by you, never touches recent commitments, and respects future hard deadlines. The first live cleanup after promotion is expected to catch the existing stale backlog in capped batches and report one aggregate count.
16
+
17
+ ## Summary of New Capabilities
18
+
19
+ | Capability | How to Use |
20
+ |---|---|
21
+ | Commitment auto-expiry dry run | Config defaults enable the sweep in dry-run mode; watch the aggregate `CommitmentTracker` sweep log |
22
+ | Stale commitment cleanup promotion | Turn off `commitments.autoExpiry.dryRun` after reviewing dry-run counts; rows expire through the existing terminal `expired` state |
23
+
24
+ ## Evidence
25
+
26
+ - Tier 1: `tests/unit/CommitmentTracker-auto-expiry.test.ts` (8 tests — old agent-owned pending expires; user-owned old row does not; young row does not; future hard deadline does not; dry-run logs without mutation; second sweep is idempotent; persistence coalesces to one store write; ConfigDefaults add-missing migration preserves operator choices).
27
+ - Tier 2: `tests/integration/commitment-auto-expiry-lifecycle.test.ts` (persist expired row, reload tracker, verify it is terminal/inactive and a second sweep changes zero rows).
28
+ - Tier 3: `tests/e2e/commitment-auto-expiry-api-lifecycle.test.ts` (real AgentServer commitments API: expired row disappears from active view but remains inspectable with the auto-expiry resolution).
29
+ - Regression sweep: `tests/unit/CommitmentTracker.test.ts`, `tests/unit/CommitmentTracker-verify-batches-saves.test.ts`, `tests/unit/ConfigDefaults.test.ts`, and `npx tsc --noEmit` are green.
@@ -0,0 +1,19 @@
1
+ # ELI16 — Commitment Auto-Expiry
2
+
3
+ ## What Changed
4
+
5
+ The commitment tracker now has a quiet cleanup loop for old agent-owned commitments. If an agent promised to follow up, the promise stayed open forever unless another part of the system explicitly closed it. That was fine when there were a few commitments, but the live store now has hundreds of stale agent-owned rows that were probably completed weeks ago and never marked closed. The result is a backlog where the important current promises are mixed with old noise.
6
+
7
+ This change adds `commitments.autoExpiry`, enabled by default but shipped in `dryRun: true`. The default policy is simple: after 21 days, an open agent-owned commitment with no future hard deadline is eligible to move to the existing terminal `expired` state. User-owned commitments are never touched. Young commitments are never touched. A commitment with an unmet future hard deadline is never touched.
8
+
9
+ ## Why It Is Safe
10
+
11
+ The cleanup uses the existing terminal status instead of inventing a new lifecycle. The sweep is bounded to 500 commitments per pass and uses the tracker's existing batched-save discipline, so a large first cleanup does not write the whole commitments file once per row. In dry-run mode it only logs the aggregate count it would expire.
12
+
13
+ The rollout is deliberately conservative. Existing agents receive the config defaults through the normal add-missing migration path, but `dryRun` remains true until an operator flips it. That means the first release proves the candidates and log shape before any live store mutation happens.
14
+
15
+ ## How To Verify
16
+
17
+ The focused tests create old and young commitments, agent-owned and user-owned commitments, and future-deadline commitments. Only the old agent-owned open row expires. The dry-run test proves the row is not mutated. The idempotency test proves a second sweep over the same state changes zero rows. The write-coalescing test proves twelve expirations produce exactly one commitments-store write for the sweep.
18
+
19
+ Integration and e2e tests reload the tracker and hit the commitments API after expiry. The expired record is still inspectable, but it disappears from the active commitment view.
@@ -0,0 +1,31 @@
1
+ # Side-Effects Review — v1.3.802 (version-named pairing)
2
+
3
+ This is the version-named pairing for the v1.3.802 release, completing the
4
+ rename step the release cut is expected to perform alongside the
5
+ `NEXT.md → 1.3.802.md` guide rename (see `scripts/pre-push-gate.js` check 5:
6
+ "the fragment/NEXT.md -> <version>.md rename pairs with an artifact rename").
7
+ The release flow did not perform the artifact half of the pairing, which makes
8
+ check 5 false-positive on every docs-only push from a clean post-release tree
9
+ — the same recurrence previously repaired for v1.3.492
10
+ (`upgrades/side-effects/1.3.492.md`).
11
+
12
+ The actual side-effects reviews for everything shipped in the
13
+ v1.3.800–v1.3.802 window are:
14
+
15
+ - `upgrades/side-effects/attention-single-topic-routing.md`
16
+ (#1417, v1.3.800 — single-alerts-topic routing; every alert lands in the
17
+ ONE Attention hub by default)
18
+ - `upgrades/side-effects/self-action-governor.md`
19
+ (#1418, v1.3.801 — SelfActionGovernor unified self-action backpressure
20
+ chokepoint, observe-only fleet-wide)
21
+ - `upgrades/side-effects/session-listing-hygiene.md`
22
+ (#1419, v1.3.802 — bounded finished-session retention, active-by-default
23
+ `GET /sessions`, genuine cross-machine duplicate flag)
24
+
25
+ Those artifacts are left in place under their slug names because each release
26
+ guide's Evidence section cites them by those paths. This file exists so the
27
+ repo state matches the gate's documented post-release expectation. The
28
+ underlying gap (release automation never renames artifacts) remains logged in
29
+ the framework-issues ledger under dedupKey
30
+ `pre-push-gate-versioned-artifact-fallback`; this is its second observed
31
+ recurrence after v1.3.492.
@@ -0,0 +1,108 @@
1
+ # Side-Effects Review — Commitment auto-expiry
2
+
3
+ **Version / slug:** `commitment-auto-expiry`
4
+ **Date:** `2026-07-10`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ This change adds a bounded auto-expiry sweep to `src/monitoring/CommitmentTracker.ts`, configures it through top-level `commitments.autoExpiry`, and wires the server construction path to pass that config into the tracker. The sweep targets stale agent-owned open commitments only, uses the existing `expired` terminal state, preserves user-owned commitments, respects future hard deadlines, ships dry-run-first, and coalesces all per-commitment persistence into one store write per sweep. Tests cover unit, integration, and e2e paths.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `CommitmentTracker.sweepAutoExpiry` — add — decides whether a commitment is eligible for terminal expiry based on owner, status, age, and future hard deadline.
15
+ - `CommitmentTracker.expire` / `expireSync` — add/modify — centralizes the existing expired-state transition so old `expiresAt` expiry and new auto-expiry use one terminal transition helper.
16
+ - `ConfigDefaults.commitments.autoExpiry` — add — defaults the sweep on, 21-day age, 6-hour cadence, dry-run true.
17
+
18
+ ---
19
+
20
+ ## 1. Over-block
21
+
22
+ The only possible over-close shape is an old agent-owned open commitment that is still genuinely active but has no hard future deadline recorded. This is why the feature ships with `dryRun: true`: the first rollout logs aggregate eligibility without changing rows. The hard guardrails are also narrow: owner must be exactly `agent`, status must be open (`pending` or `violated`), age must exceed the configured threshold, and a future `hardDeadlineAt` blocks expiry.
23
+
24
+ User-owned commitments are never eligible. Young commitments are never eligible. Terminal commitments are never eligible.
25
+
26
+ ---
27
+
28
+ ## 2. Under-block
29
+
30
+ The sweep intentionally misses stale commitments that are marked `verified`, because `verified` is treated as a non-open status for this cleanup even though some old stores may still show it in active-ish views. It also misses old user-owned commitments, old rows with malformed `createdAt`, and old rows with a future hard deadline even if that deadline is probably obsolete. Those are deliberate safety choices for the first rollout.
31
+
32
+ ---
33
+
34
+ ## 3. Level-of-abstraction fit
35
+
36
+ Correct layer. `CommitmentTracker` owns the lifecycle state, terminal status semantics, persistence batching, and active-record filtering. Putting the cleanup in an external job would either duplicate those invariants or risk writing the store by hand. The sweep is a mechanical lifecycle policy, not an LLM judgment; it uses explicit structured fields only.
37
+
38
+ ---
39
+
40
+ ## 4. Signal vs authority compliance
41
+
42
+ - [x] No — this change has no block/allow surface.
43
+
44
+ The sweep does hold lifecycle authority over a narrow state transition, but it does not block a user, tool, message, or operation. It converts stale structured records to the existing terminal `expired` state. The first release runs in dry-run mode, and the live transition requires an operator config flip.
45
+
46
+ ---
47
+
48
+ ## 5. Interactions
49
+
50
+ - **Existing `expiresAt` expiry:** still runs inside `verify()` and now routes through `expireSync`, preserving behavior while centralizing the terminal transition.
51
+ - **Write coalescing:** auto-expiry uses the same `batchingSaves` / `pendingSave` pattern documented for the verify sweep. A test asserts twelve expirations produce exactly one commitments-store write.
52
+ - **PromiseBeacon and active views:** expired commitments are terminal; existing active filters already exclude `expired`, so no new filtering contract is needed.
53
+ - **Startup timing:** an initial sweep is scheduled shortly after tracker start, then every configured interval. `stop()` clears both the initial timeout and recurring interval.
54
+ - **Dry-run logs:** the sweep emits one aggregate log line per pass. It does not log per commitment.
55
+
56
+ ---
57
+
58
+ ## 6. External surfaces
59
+
60
+ - **Config:** new top-level `commitments.autoExpiry` block: `enabled`, `maxAgeDays`, `sweepIntervalMs`, `dryRun`.
61
+ - **Persistent state:** when `dryRun:false`, eligible commitments move to `status:"expired"` with resolution `auto-expired: aged out >Nd, presumed completed-but-unclosed`.
62
+ - **API reads:** active commitment API views shrink after expiry because they already exclude terminal expired rows. Individual records remain inspectable.
63
+ - **Operator surface:** no new operator action or dashboard form. Operators can tune the config through the existing config path.
64
+
65
+ ---
66
+
67
+ ## 6b. Operator-surface quality
68
+
69
+ No operator surface — not applicable.
70
+
71
+ ---
72
+
73
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
74
+
75
+ **Replicated when commitments replication is enabled, otherwise local to the agent store.** The sweep mutates the canonical commitments store through the tracker transition path, so the existing Commitments Coherence replication machinery sees the same terminal-state mutation as any other commitment lifecycle change. It emits no user-facing notices, generates no URLs, and holds no machine-specific runtime state beyond timer handles. If multiple machines run the same agent with replicated commitments, the first machine to expire a row moves it terminal and later sweeps see it as ineligible, making the operation idempotent.
76
+
77
+ ---
78
+
79
+ ## 8. Rollback cost
80
+
81
+ Low. The shipped default is dry-run, so rollback before promotion is a code/config revert with no data repair. After a future `dryRun:false` promotion, rollback stops future expiry but does not reopen already-expired commitments; that is acceptable because the transition is intentionally terminal and inspectable. If an operator needs to reverse a specific row, they can use existing commitment mutation tools rather than a schema migration.
82
+
83
+ ---
84
+
85
+ ## Conclusion
86
+
87
+ The change directly addresses commitment backlog rot while preserving the safety floor: dry-run-first rollout, strict owner/age/deadline eligibility, one aggregate log line, bounded 500-row passes, and exactly one store write per sweep. No material side-effect concern remains for the initial dry-run release.
88
+
89
+ ---
90
+
91
+ ## Second-pass review (if required)
92
+
93
+ **Reviewer:** not required
94
+ **Independent read of the artifact:** not required for this Tier-1 dry-run-first lifecycle cleanup.
95
+
96
+ ---
97
+
98
+ ## Evidence pointers
99
+
100
+ - `npx tsc --noEmit`
101
+ - `npx vitest run tests/unit/CommitmentTracker-auto-expiry.test.ts tests/integration/commitment-auto-expiry-lifecycle.test.ts tests/e2e/commitment-auto-expiry-api-lifecycle.test.ts`
102
+ - `npx vitest run tests/unit/CommitmentTracker.test.ts tests/unit/CommitmentTracker-verify-batches-saves.test.ts tests/unit/ConfigDefaults.test.ts`
103
+
104
+ ---
105
+
106
+ ## Class-Closure Declaration (display-only mirror)
107
+
108
+ No agent-authored-artifact defect — not applicable. The new self-triggered loop has an explicit convergence bound: disabled by config, dry-run by default, one initial timeout plus one recurring interval, max 500 state transitions per pass, one aggregate log line, no per-item user-facing output, and one coalesced persistence write per sweep. Guard evidence: `tests/unit/CommitmentTracker-auto-expiry.test.ts` covers dry-run zero mutation, idempotent second sweep, and one-write batching.
@@ -0,0 +1,103 @@
1
+ # Side-Effects Review — Non-gating swap timeout
2
+
3
+ **Version / slug:** `non-gating-swap-timeout`
4
+ **Date:** `2026-07-10`
5
+ **Author:** `instar-codey`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ `src/core/IntelligenceRouter.ts` now resolves non-gating failure-swap attempt caps from `nonGatingSwapTimeoutMs` instead of the global safety-gating `swapAttemptTimeoutMs`. `src/commands/server.ts` wires the new value from `config.intelligence?.nonGatingSwapTimeoutMs ?? 15000`, and `src/config/ConfigDefaults.ts` seeds that default through normal add-missing init/migration. The associated type, generated awareness text, and unit/integration/e2e tests were updated.
11
+
12
+ ## Decision-point inventory
13
+
14
+ - `IntelligenceRouter.evaluate` gating/deferrable failure-swap loop — pass-through — still uses `swapAttemptTimeoutMs` and is intentionally unchanged.
15
+ - `IntelligenceRouter.tryNonGatingSwap` — modified — chooses the timeout cap for non-gating swap attempts.
16
+ - `ConfigDefaults.applyDefaults` migration path — pass-through — add-missing default seeding for the new config field.
17
+
18
+ ---
19
+
20
+ ## 1. Over-block
21
+
22
+ No new block/allow surface. This change does not reject calls, messages, jobs, or operator actions. It lengthens only the timeout for non-gating swap attempts, so the over-block risk is not a false rejection; the relevant risk is extra wait time on advisory/background calls.
23
+
24
+ ---
25
+
26
+ ## 2. Under-block
27
+
28
+ This does not change safety-gating fail-closed behavior. A non-gating call can now wait up to 15s for a cold-start provider before falling through, so a genuinely stuck non-gating provider may occupy its attempt for longer than before. The attempt remains bounded, still respects maxAttempts, still excludes Claude/default targets, and still reports timeout degradation.
29
+
30
+ ---
31
+
32
+ ## 3. Level-of-abstraction fit
33
+
34
+ The router is the right layer because it already owns provider failure-swap attempt timing and timeout propagation to providers. ConfigDefaults is the right layer for the default because the task requires existing agents to receive the knob through add-missing migration while preserving operator overrides.
35
+
36
+ ---
37
+
38
+ ## 4. Signal vs authority compliance
39
+
40
+ Required reference: [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
41
+
42
+ - [x] No — this change has no block/allow surface.
43
+
44
+ This is a timeout policy split inside an existing retry mechanism. It does not add a detector or an authority, and it does not make a semantic decision about user intent or message meaning.
45
+
46
+ ---
47
+
48
+ ## 5. Interactions
49
+
50
+ - **Shadowing:** The non-gating helper now has its own global fallback cap. Per-target framework caps still shadow it when configured for a target, preserving the existing specificity order.
51
+ - **Double-fire:** No new reporter path is added. Existing timeout degradation reasons continue to fire when an attempt times out.
52
+ - **Races:** No shared mutable state is added. The cap is read from router options and applied per call.
53
+ - **Feedback loops:** Longer non-gating waits can reduce heuristic fallback churn but do not change retry counts, scheduler cadence, or provider circuit-breaker rules.
54
+
55
+ ---
56
+
57
+ ## 6. External surfaces
58
+
59
+ Operators get a new config knob: `intelligence.nonGatingSwapTimeoutMs`, default 15000. Existing config migration adds the missing value and preserves explicit overrides. Existing agent awareness text now mentions the knob. No Telegram, Slack, GitHub, Cloudflare, dashboard UI, persistent database schema, or URL surface changes. No operator-facing action is added.
60
+
61
+ ---
62
+
63
+ ## 6b. Operator-surface quality
64
+
65
+ No operator surface — not applicable.
66
+
67
+ ---
68
+
69
+ ## 7. Multi-machine posture
70
+
71
+ Machine-local by design. This is per-agent runtime configuration read from that agent's local `.instar/config.json`. On multi-machine setups, each machine may tune the timeout to its own provider startup behavior. It emits no user-facing notices directly, holds no new durable state beyond config defaults, and generates no URLs.
72
+
73
+ ---
74
+
75
+ ## 8. Rollback cost
76
+
77
+ Hot-fix release: revert the router option, config default, server wiring, awareness text, and tests. No data migration or agent state repair is needed. Existing configs that received `nonGatingSwapTimeoutMs: 15000` would carry an unused field after rollback, which is harmless.
78
+
79
+ ---
80
+
81
+ ## Conclusion
82
+
83
+ Clear to ship. The change fixes the observed cold-start timeout without slowing safety gates. The main side effect is intentional: non-gating internal calls may wait longer before falling back to heuristics, but the wait remains bounded and scoped away from the gating fail-closed path.
84
+
85
+ ---
86
+
87
+ ## Second-pass review (if required)
88
+
89
+ **Reviewer:** not required
90
+ **Independent read of the artifact:** not required
91
+
92
+ ---
93
+
94
+ ## Evidence pointers
95
+
96
+ - `instar dev:claim-check src/core/IntelligenceRouter.ts src/core/types.ts src/config/ConfigDefaults.ts src/commands/server.ts src/core/PostUpdateMigrator.ts src/scaffold/templates.ts`
97
+ - `npm test -- tests/unit/nongating-failure-swap.test.ts tests/unit/ConfigDefaults.test.ts tests/unit/PostUpdateMigrator-nonGatingFailureSwap.test.ts tests/integration/nongating-failure-swap-routing.test.ts tests/e2e/nongating-failure-swap-lifecycle.test.ts`
98
+
99
+ ---
100
+
101
+ ## Class-Closure Declaration (display-only mirror)
102
+
103
+ No agent-authored-artifact defect and no self-triggered controller addition — not applicable.