instar 1.3.450 → 1.3.451

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 (39) hide show
  1. package/dist/config/ConfigDefaults.d.ts.map +1 -1
  2. package/dist/config/ConfigDefaults.js +26 -0
  3. package/dist/config/ConfigDefaults.js.map +1 -1
  4. package/dist/core/types.d.ts +47 -0
  5. package/dist/core/types.d.ts.map +1 -1
  6. package/dist/core/types.js.map +1 -1
  7. package/dist/messaging/slack/SlackAdapter.d.ts +8 -0
  8. package/dist/messaging/slack/SlackAdapter.d.ts.map +1 -1
  9. package/dist/messaging/slack/SlackAdapter.js +10 -0
  10. package/dist/messaging/slack/SlackAdapter.js.map +1 -1
  11. package/dist/monitoring/GrowthMilestoneAnalyst.d.ts +169 -0
  12. package/dist/monitoring/GrowthMilestoneAnalyst.d.ts.map +1 -0
  13. package/dist/monitoring/GrowthMilestoneAnalyst.js +500 -0
  14. package/dist/monitoring/GrowthMilestoneAnalyst.js.map +1 -0
  15. package/dist/permissions/AmbientContributionGate.d.ts +100 -0
  16. package/dist/permissions/AmbientContributionGate.d.ts.map +1 -1
  17. package/dist/permissions/AmbientContributionGate.js +85 -3
  18. package/dist/permissions/AmbientContributionGate.js.map +1 -1
  19. package/dist/scaffold/templates.d.ts.map +1 -1
  20. package/dist/scaffold/templates.js +5 -0
  21. package/dist/scaffold/templates.js.map +1 -1
  22. package/dist/server/AgentServer.d.ts +1 -0
  23. package/dist/server/AgentServer.d.ts.map +1 -1
  24. package/dist/server/AgentServer.js +41 -0
  25. package/dist/server/AgentServer.js.map +1 -1
  26. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  27. package/dist/server/CapabilityIndex.js +14 -0
  28. package/dist/server/CapabilityIndex.js.map +1 -1
  29. package/dist/server/routes.d.ts +5 -0
  30. package/dist/server/routes.d.ts.map +1 -1
  31. package/dist/server/routes.js +77 -0
  32. package/dist/server/routes.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/data/builtin-manifest.json +47 -47
  35. package/src/scaffold/templates.ts +5 -0
  36. package/upgrades/1.3.451.md +57 -0
  37. package/upgrades/side-effects/growth-milestone-analyst-dev-gate.md +99 -0
  38. package/upgrades/side-effects/growth-milestone-analyst.md +92 -0
  39. package/upgrades/side-effects/slack-livetest-cleanups.md +75 -0
@@ -0,0 +1,92 @@
1
+ # Side-Effects Review — Growth & Milestone Analyst (slice 1)
2
+
3
+ **Version / slug:** `growth-milestone-analyst`
4
+ **Date:** `2026-06-08`
5
+ **Author:** `echo`
6
+ **Tier:** `1` (ships dark, flag-off, compute + read-only, fully reversible)
7
+ **Second-pass reviewer:** `not required`
8
+
9
+ ## Summary of the change
10
+
11
+ Adds `GrowthMilestoneAnalyst` (`src/monitoring/`) — a pure observer that composes
12
+ the existing `InitiativeTracker` (rollout stages + staleness), `ApprovalLedger`
13
+ (approve-vs-change), and `CorrectionLedger` (recurrence) into one digest with five
14
+ explicit notify-rules (R1 promotion-ready, R2 incubation-expired-unproven, R3
15
+ initiative-stalling, R4 spec-pattern, R5 correction-pattern). It keeps ONE piece of
16
+ internal bookkeeping — a stage-observation journal — so "days in stage" is robust
17
+ where the rollout engines do not stamp it. Wires four read routes (`GET
18
+ /growth/digest|findings|status`, `POST /growth/tick`), a `monitoring.growthAnalyst`
19
+ config block (defaults OFF), and the AgentServer construction (guarded; null →
20
+ routes 503). Ships DARK: compute + read only, no Telegram sending.
21
+
22
+ ## Decision-point inventory
23
+
24
+ - **`classifyRollout`** (the window-expiry verdict): in-window / at-boundary /
25
+ expired × proved / unproved / unknown × stage. Both sides of every edge are unit
26
+ tested.
27
+ - **Per-rule enable gates** (`settings.rules.*`): each rule suppresses iff its flag
28
+ is false.
29
+ - **Construction gate** in AgentServer: analyst built only when
30
+ `monitoring.growthAnalyst.enabled === true` AND a tracker + stateDir exist.
31
+
32
+ ## 1. Over-block
33
+
34
+ **What legitimate inputs does this change reject?** Nothing user-facing is rejected.
35
+ The only "rejection" is structural: when the feature is OFF (the default), every
36
+ `/growth/*` route returns 503 — by design, mirroring the established dark-feature
37
+ contract (e.g. `correctionLearning`). No existing route, job, message, or gate
38
+ changes behavior. The analyst never blocks, delays, or rewrites anything.
39
+
40
+ ## 2. Under-block
41
+
42
+ **What does this still miss?** Three deliberate gaps, all deferred to later slices:
43
+ (a) no Telegram/event delivery — it computes but does not speak, so a real milestone
44
+ won't reach the operator until the sending slice; (b) proof-of-life
45
+ (`evidenceCounter`) is unwired, so every expiry currently classifies as
46
+ R2-unknown rather than R1 until a per-feature activation source is plumbed — this is
47
+ surfaced honestly as `proved:'unknown'`, never masked; (c) the muted analyzers
48
+ (`correctionLearning`, `failureLearning`) are NOT enabled here — that flood-sensitive
49
+ step is its own slice.
50
+
51
+ ## 3. Level-of-abstraction fit
52
+
53
+ **Right layer?** Yes. The analyst lives in `src/monitoring/` beside the other
54
+ observe-only components (TokenLedger, ResourceLedger). It reads through the engines'
55
+ public methods (`tracker.list/digest`, `approvalLedger.summarize`,
56
+ `correctionLedger.list`) rather than reaching into their storage. The stage journal
57
+ is analyst-private state under `stateDir/state/growth-milestone-analyst/`.
58
+
59
+ ## 4. Reversibility
60
+
61
+ Fully reversible: the feature ships behind `monitoring.growthAnalyst.enabled`
62
+ (default false). Disabling it (or removing the construction block) returns the
63
+ system to byte-identical prior behavior — the routes 503, nothing else references
64
+ the analyst. The only persisted artifact is a small JSON journal that is pruned and
65
+ self-heals.
66
+
67
+ ## 5. Anti-flood discipline (relevant because this REVERSES an over-silence)
68
+
69
+ The whole point is to speak more, so overshooting into a new flood is the risk to
70
+ guard. This slice does not send at all. The digest is structurally ONE object — a
71
+ burst of N window-expiries aggregates into one digest with counts, never N messages
72
+ (unit-tested at N=500). When the sending slice lands it must route through the
73
+ existing budget-guarded attention/post-update surfaces and aggregate, never create
74
+ one topic per feature. That guardrail is stated here so the next slice inherits it.
75
+
76
+ ## 6. Framework generality
77
+
78
+ Not framework-specific. The analyst is a server-side monitoring component that reads
79
+ instar's own ledgers/trackers; it does not spawn sessions, call an LLM, or route
80
+ through any agentic framework (Claude/Codex/Gemini/pi). It behaves identically
81
+ regardless of which framework the agent runs on. No per-framework branching exists
82
+ or is needed.
83
+
84
+ ## 7. Migration parity
85
+
86
+ - Config defaults auto-apply to existing agents via `ConfigDefaults` +
87
+ `applyDefaults` deep-merge (the established no-separate-migrateConfig path for a
88
+ new `monitoring.*` sub-key).
89
+ - The CLAUDE.md template (`generateClaudeMd`) documents the routes for NEW agents.
90
+ - A `migrateClaudeMd` content-sniff + the scheduled digest job are deferred to the
91
+ promotion slice — a dark, route-only feature needs no live agent-awareness
92
+ migration until it actually speaks.
@@ -0,0 +1,75 @@
1
+ # Side-Effects Review — Slack live-test cleanups (#2 ambient-silence observability, #5 spec/type alignment)
2
+
3
+ **Version / slug:** `slack-livetest-cleanups`
4
+ **Date:** `2026-06-09`
5
+ **Author:** `Instar Agent (echo)`
6
+ **Second-pass reviewer:** `not required` (Tier-1; observability-only + doc-accuracy; no decision authority touched)
7
+
8
+ ## Summary of the change
9
+
10
+ Two small cleanups the Slack-org live-test plan flagged.
11
+
12
+ **Cleanup #2 (observability):** the `AmbientContributionGate` previously only left a trace when it SPOKE (the speak-path `console.log` + the `onDecision` log fires on `speak:true`). A wrongful SILENCE left no measurable record, so the ambient false-positive (wrongful-silence) / false-negative rate could not be measured during the observe-only live test. This adds a bounded, in-memory aggregate inside the gate — per-channel `{evaluated, spoke, silent, nearMissSilent, silentByReason}` plus a bounded ring of the most-recent near-miss silences — read via a new `getStats()` method, a `SlackAdapter.getAmbientStats()` passthrough, and a read-only `GET /permissions/ambient-stats` route (reads the live `ctx.slack` instance). Files: `src/permissions/AmbientContributionGate.ts`, `src/messaging/slack/SlackAdapter.ts`, `src/server/routes.ts`, plus unit + integration tests.
13
+
14
+ **Cleanup #5 (doc accuracy):** `SLACK-ORG-INTEGRATION-SPEC.md` named a `respondMode: 'considered'` third mode, but the shipped `SlackRespondMode` type is `'all' | 'mention-only'`; ambient rides on `ambientContribution.enabledChannelIds` ON TOP of `mention-only`. The spec (§5.2 and the §15 migration-parity bullet) is rewritten to match the shipped reality — the lower-risk fix. No type value added; no code path needed it.
15
+
16
+ ## Decision-point inventory
17
+
18
+ - `AmbientContributionGate.shouldSpeak` (the speak/silence decision) — **pass-through** — the verdict is computed exactly as before; the aggregate is updated AFTER the verdict is formed, inside `decide()`, wrapped in try/catch, and `decide()` returns the decision unchanged. The recording cannot alter the outcome.
19
+ - `GET /permissions/ambient-stats` — **add** — read-only observability surface; performs no mutation and no messaging.
20
+
21
+ ---
22
+
23
+ ## 1. Over-block
24
+
25
+ **What legitimate inputs does this change reject that it shouldn't?**
26
+
27
+ No block/allow surface — over-block not applicable. The aggregate is signal-only and the new route is read-only. The speak/silence decision is unchanged (a dedicated regression test asserts identical verdicts with the aggregate present).
28
+
29
+ ---
30
+
31
+ ## 2. Under-block
32
+
33
+ **What failure modes does this still miss?**
34
+
35
+ No block/allow surface — under-block not applicable. The aggregate is an in-memory FP-measurement counter, not a gate. It is reset on restart, which is acceptable for an FP-rate-measurement surface (the durable per-decision record is the file-backed `/permissions/decisions`). Worst case is a momentary loss of accumulated counts after a restart — never an over- or under-speak.
36
+
37
+ ---
38
+
39
+ ## 3. Level-of-abstraction fit
40
+
41
+ **Is this at the right layer?**
42
+
43
+ Yes. The aggregate lives ON the gate that produces the decisions it counts, so every decision (including the previously-invisible silences) is observed at the single chokepoint `decide()` — no parallel detector, no double-counting. The route reads the live `ctx.slack` adapter (already in `RouteContext`), mirroring how the existing observe-only `/permissions/*` surfaces expose internal state. A durable counter could replace the in-memory map later without changing the contract.
44
+
45
+ ---
46
+
47
+ ## 4. Signal vs authority compliance
48
+
49
+ **Does this hold blocking authority with brittle logic, or produce a signal?**
50
+
51
+ Pure signal. Per `docs/signal-vs-authority.md`: the aggregate is a detector/observability surface with ZERO authority — it never blocks, delays, or rewrites a message, and it cannot change the speak/silence verdict (recording runs after the verdict and returns it unchanged; a stats bug is swallowed by try/catch). The ambient gate's own fail-to-silence authority is untouched.
52
+
53
+ ---
54
+
55
+ ## 5. Interactions
56
+
57
+ **Does it shadow another check, get shadowed, double-fire, or race?**
58
+
59
+ No. The new counters are independent of the existing `onDecision` hook and the speak-path `console.log` (both retained). No timer, no shared mutable state with another component. The `recordSpoke()` rate-limit budget is a separate concern and is not affected. The new route shares the `/permissions/*` prefix, already allowlisted as dark/internal in `CapabilityIndex` (line ~1023), so it does not trip the route-discoverability scan.
60
+
61
+ ---
62
+
63
+ ## 6. External surfaces
64
+
65
+ **Does it change anything visible to other agents / users / systems?**
66
+
67
+ Only the new authenticated read-only route `GET /permissions/ambient-stats` (returns `{ present: false }` when no ambient gate is attached — the default). It creates NO Telegram message and NO forum topic, so it cannot contribute to a notification flood (verified: the notification-flood burst-invariant test still passes). It is dark unless a channel is opted into ambient contribution. No timing/conversation-state dependency.
68
+
69
+ ---
70
+
71
+ ## 7. Rollback cost
72
+
73
+ **If this turns out wrong in production, what's the back-out?**
74
+
75
+ Trivial. The aggregate is in-memory (no persistence, no migration, no agent-state repair) and the route is additive. Reverting the commit removes both with no residue. Cleanup #5 is a doc edit with zero runtime effect.