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.
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +29 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +57 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/PreferencesManager.d.ts +121 -0
- package/dist/core/PreferencesManager.d.ts.map +1 -0
- package/dist/core/PreferencesManager.js +223 -0
- package/dist/core/PreferencesManager.js.map +1 -0
- package/dist/core/SecretMigrator.d.ts +6 -0
- package/dist/core/SecretMigrator.d.ts.map +1 -1
- package/dist/core/SecretMigrator.js +6 -2
- package/dist/core/SecretMigrator.js.map +1 -1
- package/dist/core/types.d.ts +49 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/CoherenceMonitor.d.ts.map +1 -1
- package/dist/monitoring/CoherenceMonitor.js +8 -1
- package/dist/monitoring/CoherenceMonitor.js.map +1 -1
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +6 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/CapabilityIndex.d.ts.map +1 -1
- package/dist/server/CapabilityIndex.js +12 -0
- package/dist/server/CapabilityIndex.js.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +36 -0
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +62 -62
- package/src/scaffold/templates.ts +6 -0
- package/upgrades/1.3.127.md +39 -0
- package/upgrades/1.3.128.md +84 -0
- package/upgrades/side-effects/correction-preference-learning-sentinel-slice1a.md +132 -0
- 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.
|