instar 1.2.75 → 1.2.76

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,40 @@
1
+ /**
2
+ * Usher HTTP routes — the read-only pull surface for the Usher's re-surface
3
+ * signals + precision metrics (rung 4). Signal-only: consumers PULL; the Usher
4
+ * never pushes to chat and never injects.
5
+ *
6
+ * GET /usher/signals?topicId=N — recent re-surface suggestions
7
+ * GET /usher/metrics?topicId=N — fired / acted precision funnel
8
+ *
9
+ * Operator-facing (INTERNAL_PREFIXES). Spec: docs/specs/cwa-usher.md §3–4.
10
+ */
11
+ import { Router } from 'express';
12
+ import { z } from 'zod';
13
+ const TopicIdParam = z.coerce.number().int().nonnegative();
14
+ export function createUsherRoutes(deps) {
15
+ const router = Router();
16
+ const store = deps.signalStore;
17
+ if (!store) {
18
+ router.use('/usher', (_req, res) => res.status(503).json({ error: 'usher disabled' }));
19
+ return router;
20
+ }
21
+ router.get('/usher/signals', (req, res) => {
22
+ const parsed = TopicIdParam.safeParse(req.query.topicId);
23
+ if (!parsed.success)
24
+ return res.status(400).json({ error: 'topicId query param required' });
25
+ const limit = Math.min(50, Math.max(1, Number(req.query.limit) || 20));
26
+ res.json({ topicId: parsed.data, signals: store.getSignals(parsed.data, limit) });
27
+ });
28
+ router.get('/usher/metrics', (req, res) => {
29
+ const parsed = TopicIdParam.safeParse(req.query.topicId);
30
+ if (!parsed.success)
31
+ return res.status(400).json({ error: 'topicId query param required' });
32
+ const m = store.getMetrics(parsed.data);
33
+ // Precision = acted / fired (the read that gates rung 5; paired externally
34
+ // with the human-as-detector miss-map for the "what it missed" half).
35
+ const precision = m.fired > 0 ? m.acted / m.fired : null;
36
+ res.json({ topicId: parsed.data, metrics: { ...m, precision } });
37
+ });
38
+ return router;
39
+ }
40
+ //# sourceMappingURL=usherRoutes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usherRoutes.js","sourceRoot":"","sources":["../../src/server/usherRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC;AAE3D,MAAM,UAAU,iBAAiB,CAAC,IAA8C;IAC9E,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC;IAE/B,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACvF,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;QAC5F,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACvE,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,GAAY,EAAE,GAAa,EAAE,EAAE;QAC3D,MAAM,MAAM,GAAG,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;QAC5F,MAAM,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxC,2EAA2E;QAC3E,sEAAsE;QACtE,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACzD,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.2.75",
3
+ "version": "1.2.76",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-25T09:19:12.673Z",
5
- "instarVersion": "1.2.75",
4
+ "generatedAt": "2026-05-25T19:10:38.599Z",
5
+ "instarVersion": "1.2.76",
6
6
  "entryCount": 191,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -1440,7 +1440,7 @@
1440
1440
  "type": "subsystem",
1441
1441
  "domain": "server",
1442
1442
  "sourcePath": "src/server/AgentServer.ts",
1443
- "contentHash": "038365abc27a181166c64817b88b92dd4cd4fdcf33d9444040da91ba9f821f5b",
1443
+ "contentHash": "074c270761f1a6bd512d77c09465217087d169a19d012a9b2bf76d270b5811e5",
1444
1444
  "since": "2025-01-01"
1445
1445
  },
1446
1446
  "subsystem:session-manager": {
@@ -0,0 +1,64 @@
1
+ # Upgrade Guide — the Usher (a quiet mid-task reminder)
2
+
3
+ <!-- bump: minor -->
4
+ <!-- minor = new features, new APIs, new capabilities (backwards-compatible) -->
5
+
6
+ ## What Changed
7
+
8
+ **I now notice, mid-conversation, when something we set aside earlier matters again.**
9
+
10
+ The memory and briefing only get consulted at two moments — when a session starts
11
+ and right before I send a message. Between those, a context can fade out of view
12
+ and then become relevant again, and nothing pulled it back. The Usher fills that
13
+ gap: on each substantive message, it does one cheap check — "did this just make a
14
+ faded, tracked context relevant again?" — and if so it leaves a quiet reminder on
15
+ a side board.
16
+
17
+ The deliberate, important part: **it is signal-only.** It writes suggestions to a
18
+ read-only surface that's pulled (an endpoint / the dashboard); it never pushes to
19
+ chat and never forces anything into my context. And before any future step is
20
+ allowed to let it actually interrupt mid-task, we **measure how often its
21
+ reminders were useful** (a precision number = acted ÷ fired) and pair that with
22
+ the human-as-detector heat map for what it missed. The data has to earn the right
23
+ to interrupt — that precision is written in as the hard precondition for the next
24
+ rung.
25
+
26
+ It's bounded and safe by construction: one cheap check per substantive message
27
+ (rate-limited, backs off under quota pressure, skipped when nothing's faded),
28
+ fire-and-forget so it can never slow a reply, and degrade-safe (no model, no
29
+ candidates, or an error → no reminder, never a crash). On by default, with a
30
+ kill-switch.
31
+
32
+ **Evidence**: 19 new tests (13 unit — prompt/parse + refId validation, degrade
33
+ paths, all watcher branches incl. never-throws, and the signal store; 6 boot-path
34
+ route tests — the pull surface is alive, returns signals + precision, 503 when
35
+ disabled, and a wiring-integrity guard that the watcher is attached to the live
36
+ message callback). The discoverability/config suites stay green. `tsc` + lint
37
+ clean (incl. the no-raw-model-call guard).
38
+
39
+ Spec: `docs/specs/cwa-usher.md` (approved; Claude-authored + manual review —
40
+ fuller multi-model review advisable, especially the precision definition that
41
+ gates rung 5; caveat ratified). ELI16: `docs/specs/cwa-usher.eli16.md`.
42
+ Side-effects: `upgrades/side-effects/cwa-usher.md`.
43
+
44
+ ## What to Tell Your User
45
+
46
+ - **Quiet reminders when something's relevant again**: "If we set something aside
47
+ and it suddenly matters again mid-conversation, I'll leave a quiet note about it
48
+ on a side board — I won't interrupt you with it yet. We'll first check those
49
+ notes are actually useful before letting them ever interrupt."
50
+
51
+ ## Summary of New Capabilities
52
+
53
+ | Capability | How to Use |
54
+ |-----------|-----------|
55
+ | Mid-task re-surface signals | Automatic (signal-only); read at `GET /usher/signals?topicId=N` |
56
+ | Usher precision metrics | `GET /usher/metrics?topicId=N` → fired / acted / precision |
57
+
58
+ ## Evidence
59
+
60
+ Not a bug fix — a new signal-only capability. Verified by 19 tests including 6
61
+ that boot the real AgentServer and confirm the pull surface returns signals +
62
+ precision and 503s when disabled, plus a wiring-integrity guard that server.ts
63
+ attaches the watcher to the live message callback. By construction it has no
64
+ inject/block path. `tsc` + lint clean.
@@ -0,0 +1,82 @@
1
+ # Side-effects review — the Usher (rung 4, signal-only)
2
+
3
+ **Scope**: A signal-only mid-task watcher that re-surfaces faded-but-now-relevant
4
+ context. Per the ratified spec (`docs/specs/cwa-usher.md`): on each substantive
5
+ inbound turn, query the faded tail of the topic-intent store, ask a cheap LLM
6
+ whether the turn re-activates any, and emit re-surface SIGNALS to a read-only pull
7
+ surface. It NEVER injects (rung 5, gated on the Usher's measured precision).
8
+
9
+ **Files touched**:
10
+ - `src/core/UsherSignalStore.ts` — NEW. File-backed per-topic store of signals +
11
+ precision metrics (fired/acted); atomic writes; best-effort (never throws);
12
+ capped at 50 signals/topic.
13
+ - `src/core/Usher.ts` — NEW. `buildUsherPrompt`/`parseUsherResponse` (anti-injection,
14
+ refId-validated), `createUsherCheckFn` (injected provider, degrade-safe),
15
+ `usherCheckTurn`/`createUsherLoop` (pre-filter reuse, shed/rate gates, faded-tail
16
+ = observation-tier refs, fire-and-forget, never-throws). Reacts to USER turns only.
17
+ - `src/server/usherRoutes.ts` — NEW. `GET /usher/signals` + `GET /usher/metrics`
18
+ (with precision = acted/fired). 503-stub when the store is absent.
19
+ - `src/server/AgentServer.ts` — new optional `usherSignalStore`; mount the routes.
20
+ - `src/commands/server.ts` — construct `UsherSignalStore` (unless disabled); chain
21
+ the Usher loop onto `onMessageLogged` AFTER the capture chain (reusing the
22
+ queued subscription provider + LlmQueue); pass the store to AgentServer.
23
+ - `src/server/CapabilityIndex.ts` — `usher` → `INTERNAL_PREFIXES`.
24
+ - `src/config/ConfigDefaults.ts` + `src/core/types.ts` — `usher.enabled` default true.
25
+ - Tests: unit (Usher + store) + boot-path route tests + the discoverability scan
26
+ now includes `usherRoutes.ts`.
27
+
28
+ **Under-block**: The Usher only *emits suggestions to a pull surface* — it blocks
29
+ nothing. Its checks are gated (pre-filter, shed, rate ceiling) and every gate
30
+ fails toward "no signal", so it can't suppress anything either. RefIds are
31
+ validated against the candidate set (a poisoned/hallucinated id is dropped).
32
+
33
+ **Over-block**: None possible — there is no `block`/`inject` path in the code.
34
+ A false signal costs one line on a side board the consumer pulls.
35
+
36
+ **Level-of-abstraction fit**: The Usher reuses the established seam
37
+ (`onMessageLogged`), the topic-intent store's faded tail (observation-tier refs),
38
+ the queued subscription provider (never a raw client), and the capture loop's
39
+ pre-filter — it adds a watcher + a pull surface, not a new subsystem. "Faded" is
40
+ defined precisely as below-briefing-tier (observation), the genuine re-warm case.
41
+
42
+ **Signal vs authority (defining constraint)**: The Usher is a pure signal
43
+ producer. Authority to act on a signal (mid-task injection) is withheld for rung
44
+ 5, which the spec makes conditional on the Usher's measured precision. The surface
45
+ is PULL (endpoint/dashboard), never a chat push — so even a noisy Usher can't
46
+ train anyone to tune it out (Near-Silent).
47
+
48
+ **Interactions**:
49
+ - Chained AFTER the capture loop on the single-assignment `onMessageLogged`
50
+ property (prior callback preserved — verified by the wiring-integrity source
51
+ guard). Fire-and-forget (`void usherLoop(...)`) so Usher latency never reaches
52
+ the delivery path.
53
+ - One fast-tier LLM call per substantive USER turn, background lane on the shared
54
+ LlmQueue, rate-limited (20/60s/topic), skipped under QuotaTracker pressure, and
55
+ skipped entirely when the topic has no faded candidates — same cost envelope as
56
+ capture. Agent turns are skipped (capture handles those).
57
+ - `precision = acted/fired` on `/usher/metrics` is the read that rung 5's spec
58
+ will cite as its precondition; pairs with the human-as-detector miss-map.
59
+ - Construction broadened nothing — the assembler/capture wiring is unchanged; the
60
+ Usher is purely additive within the existing `sharedIntelligence` block.
61
+
62
+ **External surfaces**: `GET /usher/signals`, `GET /usher/metrics` (INTERNAL
63
+ prefix). New config `usher.enabled` (default true). New modules `Usher.ts`,
64
+ `UsherSignalStore.ts`. No injection, no chat push, no change to existing routes.
65
+
66
+ **Deferred (tracked)**: mid-task injection (`cwa-injection`, gated on this
67
+ rung's precision), per-tool-call seam (`cwa-usher-tool-seam`), capability/standards
68
+ descriptors as candidates (`cwa-capability-index-context`).
69
+
70
+ **Rollback cost**: Low, strictly additive. Remove the watcher wiring + routes +
71
+ store; nothing depends on it (rung 5 isn't built). Kill-switch `usher.enabled:
72
+ false` stops the watcher (routes 503). No data migration.
73
+
74
+ **Migration parity**: Additive watcher wiring + routes + config default
75
+ (existence-checked) + INTERNAL prefix — all server-side (every agent on update).
76
+ The signal store is created lazily; no schema migration. No hook/template/skill change.
77
+
78
+ **Convergence honesty**: Claude-authored + manual review; multi-model tooling
79
+ absent on host. The Usher is deliberately the safe half (signal-only, pull
80
+ surface, precision-measured before rung 5 earns authority), but a fuller review —
81
+ especially of the `acted` precision definition that gates rung 5 — remains
82
+ advisable before relying on it.