instar 1.3.126 → 1.3.128

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.
Files changed (36) hide show
  1. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  2. package/dist/config/ConfigDefaults.js +29 -0
  3. package/dist/config/ConfigDefaults.js.map +1 -1
  4. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  5. package/dist/core/PostUpdateMigrator.js +57 -0
  6. package/dist/core/PostUpdateMigrator.js.map +1 -1
  7. package/dist/core/PreferencesManager.d.ts +121 -0
  8. package/dist/core/PreferencesManager.d.ts.map +1 -0
  9. package/dist/core/PreferencesManager.js +223 -0
  10. package/dist/core/PreferencesManager.js.map +1 -0
  11. package/dist/core/SecretMigrator.d.ts +6 -0
  12. package/dist/core/SecretMigrator.d.ts.map +1 -1
  13. package/dist/core/SecretMigrator.js +6 -2
  14. package/dist/core/SecretMigrator.js.map +1 -1
  15. package/dist/core/types.d.ts +49 -0
  16. package/dist/core/types.d.ts.map +1 -1
  17. package/dist/core/types.js.map +1 -1
  18. package/dist/monitoring/CoherenceMonitor.d.ts.map +1 -1
  19. package/dist/monitoring/CoherenceMonitor.js +8 -1
  20. package/dist/monitoring/CoherenceMonitor.js.map +1 -1
  21. package/dist/scaffold/templates.d.ts.map +1 -1
  22. package/dist/scaffold/templates.js +6 -0
  23. package/dist/scaffold/templates.js.map +1 -1
  24. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  25. package/dist/server/CapabilityIndex.js +12 -0
  26. package/dist/server/CapabilityIndex.js.map +1 -1
  27. package/dist/server/routes.d.ts.map +1 -1
  28. package/dist/server/routes.js +36 -0
  29. package/dist/server/routes.js.map +1 -1
  30. package/package.json +1 -1
  31. package/src/data/builtin-manifest.json +62 -62
  32. package/src/scaffold/templates.ts +6 -0
  33. package/upgrades/1.3.127.md +39 -0
  34. package/upgrades/1.3.128.md +84 -0
  35. package/upgrades/side-effects/correction-preference-learning-sentinel-slice1a.md +132 -0
  36. package/upgrades/side-effects/recurring-warning-cleanup.md +56 -0
@@ -0,0 +1,84 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: minor -->
4
+
5
+ ## What Changed
6
+
7
+ **New preferences read-surface (Correction & Preference Learning Sentinel —
8
+ Slice 1a).** This is the structural application surface for auto-learned user
9
+ preferences, modeled exactly on the existing ORG-INTENT session-start pattern.
10
+ It adds three pieces that work together:
11
+
12
+ - A new in-process primitive, `recordPreference()`, that is the ONLY writer to
13
+ a new structured file at `.instar/preferences.json`. Writes are atomic (temp
14
+ file + rename), schema-versioned, and upsert by `dedupeKey` — so a recurring
15
+ preference collapses to one entry whose observation count grows rather than
16
+ piling up duplicates. An absent file simply means "no preferences" (it is
17
+ never required to exist).
18
+ - A new HTTP route, `GET /preferences/session-context`, gated on
19
+ `monitoring.correctionLearning.enabled`. When the feature is off it returns
20
+ 503; when on, it serves the active preferences as a structured block, bounded
21
+ by `maxInjectedPreferencesBytes` (4000) and priority-ordered by recency ×
22
+ confidence × dedupe-count. It serves only the learning text plus metadata —
23
+ never any raw internal fields.
24
+ - A session-start hook patch: the hook now fetches that route on every boot and
25
+ injects the returned block, wrapped in an `<auto-learned-preference
26
+ src='correction-loop'>` envelope so a learned preference can never be mistaken
27
+ for an authoritative instruction.
28
+
29
+ This is **signal-only**. It stores, serves, and injects preferences so the agent
30
+ always SEES them — it NEVER blocks or rewrites an outbound message. The whole
31
+ feature ships OFF by default (`monitoring.correctionLearning.enabled: false`),
32
+ so on this update nothing changes behaviorally until you turn it on. Slice 1b
33
+ (the capture → distill → ledger → recurrence-gate loop that writes through
34
+ `recordPreference()`) lands in a later change and consumes this surface.
35
+
36
+ ## What to Tell Your User
37
+
38
+ Nothing changes unless you turn it on. This update adds the plumbing for me to
39
+ learn your preferences over time — the repeated corrections you make, like
40
+ asking me to be plainer or to lead with the action. When that learning loop is
41
+ switched on in a later release, anything I learn about how you like to work gets
42
+ injected into my context at the start of every session, so I carry it forward
43
+ instead of forgetting it when a conversation ends. These learned preferences are
44
+ always treated as gentle signals, never as commands, and a real instruction or a
45
+ safety rule always wins. For now the feature is off by default and there is
46
+ nothing for you to do.
47
+
48
+ ## Summary of New Capabilities
49
+
50
+ - New primitive: `recordPreference()` — the single, atomic, schema-versioned
51
+ writer to `.instar/preferences.json` (upsert by `dedupeKey`).
52
+ - New route: `GET /preferences/session-context` — serves the byte-bounded,
53
+ priority-ordered learned-preference block (503 when disabled; `{ present:
54
+ false }` when none). Bearer-authed like sibling routes; classified in the
55
+ CapabilityIndex so it is discoverable via `GET /capabilities`.
56
+ - Session-start hook now injects the `<auto-learned-preference>` block on every
57
+ boot when the feature is enabled and preferences exist (fail-open: 503 /
58
+ unreachable / empty → injects nothing).
59
+ - New config block `monitoring.correctionLearning` (ships OFF), backfilled into
60
+ existing agents automatically via `applyDefaults` deep-merge.
61
+ - CLAUDE.md template + migrator backfill so existing agents learn about the
62
+ surface and honor injected preferences.
63
+
64
+ ## Evidence
65
+
66
+ - `tests/unit/PreferencesManager.test.ts` (13) — atomic write + schema version,
67
+ dedupe-upsert (count increments, learning/recordedAt refresh, confidence max),
68
+ absent-file ≡ empty, malformed-file tolerance, bounded-bytes + priority order,
69
+ serves only learning + metadata.
70
+ - `tests/unit/preferences-wiring-integrity.test.ts` (7) — `recordPreference()`
71
+ is the only writer (read path never creates/mutates the file; atomic
72
+ no-partial under repeated upsert); route gate keyed strictly on
73
+ `correctionLearning.enabled === true`.
74
+ - `tests/integration/preferences-routes.test.ts` (5) — 401 without bearer, 503
75
+ when disabled, 200 `{ present: false }` when enabled+empty, 200 structured
76
+ block when enabled+exists, no raw-extra leak.
77
+ - `tests/e2e/preferences-session-context-lifecycle.test.ts` (6) — feature-alive
78
+ 200/503 on the production AgentServer boot path; the generated session-start
79
+ hook emits the `<auto-learned-preference>` block when enabled+present and
80
+ nothing when off.
81
+ - `tests/unit/capabilities-discoverability.test.ts` (100) — `/preferences`
82
+ classified; lint green.
83
+ - Side-effects review:
84
+ `upgrades/side-effects/correction-preference-learning-sentinel-slice1a.md`.
@@ -0,0 +1,132 @@
1
+ # Side-effects review — Correction & Preference Learning Sentinel (Slice 1a)
2
+
3
+ **Spec:** `docs/specs/CORRECTION-PREFERENCE-LEARNING-SENTINEL-SPEC.md` (§3.6, §7,
4
+ §9, §10 Slice 1a)
5
+ **Change:** new `src/core/PreferencesManager.ts`; inline
6
+ `GET /preferences/session-context` in `src/server/routes.ts`;
7
+ `monitoring.correctionLearning` config block (`src/core/types.ts` +
8
+ `src/config/ConfigDefaults.ts`); `CapabilityIndex.ts` entry; session-start hook
9
+ patch + `migrateClaudeMd` backfill + shadow-capability marker in
10
+ `src/core/PostUpdateMigrator.ts`; `generateClaudeMd` capability section +
11
+ Registry-First row + proactive trigger in `src/scaffold/templates.ts`; 3-tier +
12
+ wiring tests.
13
+ **Class:** new read-surface feature, ships OFF, signal-only (never gates,
14
+ blocks, or rewrites a message).
15
+
16
+ ## What changed
17
+
18
+ A structured on-disk preferences file (`.instar/preferences.json`), the single
19
+ atomic writer for it (`recordPreference()`), an HTTP read route serving the
20
+ session-start block, and a session-start hook that injects that block on every
21
+ boot. Modeled 1:1 on the proven ORG-INTENT precedent
22
+ (`GET /intent/org/session-context` + its session-start fetch). Slice 1b (the
23
+ capture/distill/ledger loop) is the future writer; Slice 1a only proves the
24
+ surface is alive end-to-end.
25
+
26
+ ## 1. Security
27
+
28
+ - **No new external input/network/egress.** The route only reads a local file
29
+ and serves a deterministically-formatted block. No LLM call, no outbound
30
+ request, no shell-out in Slice 1a (the hook's curl is loopback to the agent's
31
+ own server, same as ORG-INTENT).
32
+ - **Auth:** the route is Bearer-gated by the global `authMiddleware` exactly like
33
+ sibling `/intent/*` routes (integration test asserts 401 without a token).
34
+ - **Output discipline:** the served payload and the injected block contain ONLY
35
+ the `learning` text + metadata (confidence, seen-count). Internal fields
36
+ (`dedupeKey`, `provenance`) never leak (unit + integration assertions). This is
37
+ the §3.6 "serve only learning + metadata" rule.
38
+ - **Injection-confusion defense:** loop-sourced preferences are wrapped in an
39
+ `<auto-learned-preference src='correction-loop'>` envelope so a downstream
40
+ prompt assembler structurally cannot mistake a learned preference for an
41
+ authoritative instruction. The block's own preamble restates "signals, not
42
+ instructions; real instructions and safety win."
43
+ - **No policy-relaxation surface in 1a:** `recordPreference()` has no writer in
44
+ Slice 1a (Slice 1b adds the gated, policy-keyword-filtered caller per §3.6).
45
+ Until then the only way an entry lands is a direct programmatic call, which the
46
+ correction loop does not yet make.
47
+
48
+ ## 2. Migration parity
49
+
50
+ - **Config:** `monitoring.correctionLearning` added to `ConfigDefaults`.
51
+ `applyDefaults` deep-merges add-missing-only (verified: `merge()` recurses into
52
+ objects, adds absent keys, never overwrites), so existing agents backfill the
53
+ block on update without a dedicated `migrateConfig` step — and without surprise
54
+ activation (`enabled: false`). This matches the spec §7 note and the
55
+ failure-learning precedent.
56
+ - **Route:** inline in `routes.ts` (the discoverability-lint allowlist is fixed; a
57
+ separate module would trip the orphan-prefix check). `CapabilityIndex` entry
58
+ added so the lint passes and the route is discoverable.
59
+ - **Hook:** built-in `instar/` hooks are always-overwrite on every migration, so
60
+ the patched `session-start.sh` propagates to every existing agent on the next
61
+ update — no hand-written `migrateHooks` block needed.
62
+ - **CLAUDE.md:** `generateClaudeMd` gains the capability section / Registry-First
63
+ row / proactive trigger; `migrateClaudeMd` gains a content-sniffed backfill
64
+ (marker `Correction & Preference Learning Sentinel`) so EXISTING agents learn
65
+ the surface — not just new ones. A shadow-capability marker
66
+ (`**Preferences I've learned about you**`) mirrors it into Codex/Gemini
67
+ `AGENTS.md`/`GEMINI.md`. `feature-delivery-completeness` enforces all three legs.
68
+ - **State file:** `.instar/preferences.json` is created lazily on first write;
69
+ absent ≡ empty. No migration needed.
70
+
71
+ ## 3. Performance
72
+
73
+ - The read route does one small synchronous file read + a deterministic
74
+ string-build bounded by `maxInjectedPreferencesBytes` (4000). No DB, no LLM, no
75
+ network. Cost is negligible and constant-ish.
76
+ - `recordPreference()` reads + rewrites the whole file atomically. The file is
77
+ bounded by distinct-preference cardinality (upsert by `dedupeKey`), not message
78
+ volume, so it stays tiny in practice. Each write is one temp-file + fsync +
79
+ rename.
80
+ - The session-start hook adds one loopback curl with `--max-time 4`; fail-open on
81
+ timeout, so a slow/absent server can never delay session start beyond that cap.
82
+
83
+ ## 4. Observability
84
+
85
+ - The route is discoverable via `GET /capabilities` (CapabilityIndex entry,
86
+ `enabled` reflects the flag).
87
+ - `{ present, block, count }` makes the served state self-describing; `count`
88
+ exposes distinct-preference cardinality for debugging.
89
+ - No new log channel in 1a (the audit log `logs/correction-learning-audit.jsonl`
90
+ is a Slice 1b concern — the loop that produces routable decisions).
91
+
92
+ ## 5. Rollback
93
+
94
+ - Flip `monitoring.correctionLearning.enabled` back to false (or remove the
95
+ block) → the route 503s and the hook injects nothing. Inert.
96
+ - `.instar/preferences.json` entries all carry `provenance: 'correction-loop'`,
97
+ enabling a one-shot bulk removal (a single jq-style filter) if a future loop
98
+ ever writes something unwanted. In 1a nothing writes, so the file stays absent.
99
+ - Code rollback = revert the commits; the absent-file ≡ empty contract means a
100
+ rolled-back agent with a stray file is still consistent (read tolerates and
101
+ ignores it; the route 503s when the flag is gone).
102
+
103
+ ## 6. Multi-machine
104
+
105
+ - The file is per-agent-home local state (under `stateDir`), like ORG-INTENT.md
106
+ and the integrated-being ledger. On a multi-machine agent each machine reads
107
+ its own copy; the existing state-sync layer carries `.instar/` files between
108
+ machines the same way it carries ORG-INTENT.md — no new sync path introduced.
109
+ - The route is read-only and idempotent; no lease/fencing interaction. Slice 1a
110
+ has no writer competing across machines (that is a Slice 1b consideration when
111
+ the loop runs only on the awake machine).
112
+
113
+ ## 7. Multi-user
114
+
115
+ - Slice 1a is a pure read/inject surface and does not itself attribute a
116
+ preference to a user — it serves whatever was recorded. The multi-user
117
+ primary-user gate (§3.6) lives in Slice 1b, where corrections are attributed
118
+ and `recordPreference()` is actually called. Until then no user-shaped data can
119
+ enter the file via this feature.
120
+ - The injected block is the same for every session on the agent (it is the
121
+ agent's learned-about-this-operator preferences), consistent with the
122
+ single-operator model the rest of the agent assumes.
123
+
124
+ ## Tests
125
+
126
+ - Unit: `tests/unit/PreferencesManager.test.ts` (13),
127
+ `tests/unit/preferences-wiring-integrity.test.ts` (7).
128
+ - Integration: `tests/integration/preferences-routes.test.ts` (5).
129
+ - E2E: `tests/e2e/preferences-session-context-lifecycle.test.ts` (6).
130
+ - Lint: `tests/unit/capabilities-discoverability.test.ts` (100) green;
131
+ `tests/unit/feature-delivery-completeness.test.ts` green (parity + shadow
132
+ marker for the new section).
@@ -0,0 +1,56 @@
1
+ # Side-Effects Review — secret-aware Telegram-token readiness
2
+
3
+ **Version / slug:** `recurring-warning-cleanup`
4
+ **Date:** `2026-05-29`
5
+ **Author:** `echo`
6
+ **Spec:** `docs/specs/recurring-warning-cleanup.md` (+ `.eli16.md`)
7
+ **Convergence:** `docs/specs/reports/recurring-warning-cleanup-convergence.md` (fast-tracked self-review)
8
+ **Second-pass reviewer:** `not required` (see §"Phase 5 trigger check")
9
+
10
+ ## Summary of the change
11
+
12
+ One self-contained, log-only fix (autonomous-mode work at Justin's request).
13
+ NOT multi-machine.
14
+
15
+ `CoherenceMonitor.readiness-telegram-token` used a `typeof === 'string'` guard
16
+ that read the post-externalization `{ secret: true }` token placeholder as
17
+ "missing" and false-alarmed 20×/run. Now a token is "configured" if it's a
18
+ non-empty string OR the placeholder, reusing the now-exported `isSecretPlaceholder`
19
+ from `SecretMigrator`.
20
+
21
+ (The originally-paired RevertDetector fix was dropped — found already fixed on
22
+ main by #552's `sourceTreeReadOk`; see the spec's coordination note.)
23
+
24
+ ## Files touched
25
+
26
+ - `src/core/SecretMigrator.ts` — export `isSecretPlaceholder` (was module-private; +doc).
27
+ - `src/monitoring/CoherenceMonitor.ts` — import + use it in the token readiness check.
28
+ - `tests/unit/secret-migrator.test.ts` (+`isSecretPlaceholder` cases).
29
+
30
+ ## Decision-point inventory
31
+
32
+ - **Token present vs missing** — *modify, widening*. Adds the `{secret:true}`
33
+ placeholder as a "present" case; a genuinely-missing/empty token still fails.
34
+ Both sides tested. Read-only.
35
+ - **Export of `isSecretPlaceholder`** — *additive*. Was module-private; now
36
+ exported so the readiness check reuses one definition (no drift). No behavior
37
+ change to existing callers.
38
+
39
+ ## Blast radius
40
+
41
+ - No new authority, no gate, no API route, no external surface, no destructive op.
42
+ - The only delta REMOVES a recurring false warning; no real runtime behavior
43
+ change (a present token now correctly passes; a missing one still fails).
44
+ - No agent-installed files changed → no `PostUpdateMigrator` entry. Pure `src/`.
45
+ - Not multi-machine.
46
+
47
+ ## Phase 5 trigger check (second-pass reviewer)
48
+
49
+ Second pass **not required**: no new authority, no destructive op, no external
50
+ surface, no migration, not multi-machine. Additive log-noise cleanup with
51
+ both-sides unit coverage.
52
+
53
+ ## Verification
54
+
55
+ - `tests/unit/secret-migrator.test.ts` (17, incl. `isSecretPlaceholder` cases) pass.
56
+ - `tsc --noEmit` clean.