instar 1.3.474 → 1.3.476

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,66 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ The growth analyst (`GrowthMilestoneAnalyst`) has, since Slice 1, *computed* a full growth
9
+ picture — stalling initiatives (R3), features that earned promotion (R1), incubation
10
+ windows that expired unproven (R2), spec approve-vs-change patterns (R4), recurring
11
+ corrections (R5), and dev-gate conformance (R6) — but nothing ever *sent* it. This slice
12
+ adds the voice: `GrowthDigestPublisher` (`src/monitoring/GrowthDigestPublisher.ts`), an
13
+ in-process component that, on the existing `monitoring.growthAnalyst.digestCron` cadence
14
+ (default Monday 11:00), formats ONE consolidated "growth check-in" and routes it to the
15
+ Agent Updates topic through the same flood-guarded path `/telegram/post-update` uses.
16
+
17
+ To guarantee the publisher cannot bypass the dedup/budget/tone guards, the change carves a
18
+ pure `res`-free `evaluateOutbound` funnel out of `checkOutboundMessage` and adds a
19
+ `postToUpdatesTopic` helper the route and the publisher both share — one guarded chokepoint,
20
+ not two. Hardening from the 8-reviewer convergence: a multi-machine lease gate (`isAwake`)
21
+ so an in-process cron never double-sends on a paired agent, calm-week silence by default,
22
+ missed-run catch-up (idempotent on the window ISO), a cadence sanity-floor, an in-flight
23
+ guard, and a render-boundary secret-scrub with high-priority findings never abbreviated.
24
+
25
+ It ships **dark**: `monitoring.growthAnalyst.digestDelivery` defaults to `'off'` — even on a
26
+ development agent — so merging the code sends nothing. The rollout path is
27
+ `off → dry-run (logs the would-send sample to logs/growth-digest.jsonl) → live`, opt-in by
28
+ the operator, dogfooded on Echo first. The fleet stays off.
29
+
30
+ ## What to Tell Your User
31
+
32
+ Nothing changes yet — this ships off by default, so no message is sent when it merges. Once
33
+ you ask me to turn it on, I'll start in a quiet "show me what you'd send" mode and only go
34
+ live once you're happy with a sample. From then on I post one short weekly growth check-in to
35
+ your Agent Updates topic: a consolidated summary of what's waiting on you, what's ready to
36
+ promote, and what's drifting — never a wall of items (big lists collapse to the top few with
37
+ a "plus N more"), and I stay silent on a fully-calm week unless you ask me to send a steady
38
+ heartbeat. I can only send the message or stay quiet — I never block or rewrite anything. You
39
+ can also just ask me for the same picture on demand any time.
40
+
41
+ ## Summary of New Capabilities
42
+
43
+ - `GrowthDigestPublisher` — cadenced, lease-gated, deterministic-format proactive growth
44
+ check-in to the Agent Updates topic (ships dark behind `digestDelivery`).
45
+ - `monitoring.growthAnalyst.digestDelivery` (`off` | `dry-run` | `live`, default `off`),
46
+ `digestSendOnCalmWeeks` (default `false`), `digestTimezone` (default `UTC`).
47
+ - A shared, `res`-free `evaluateOutbound` outbound-guard funnel + `postToUpdatesTopic`
48
+ helper — one chokepoint the route and the publisher both pass through.
49
+
50
+ ## Evidence
51
+
52
+ - `src/monitoring/GrowthDigestPublisher.ts` — the publisher, pure `formatDigest`, and the
53
+ `logs/growth-digest.jsonl` audit sink.
54
+ - `src/server/routes.ts` — `evaluateOutbound` (pure funnel), `checkOutboundMessage` (thin
55
+ adapter), `postToUpdatesTopic` (the publisher's guarded sender), `attachSender` hookup.
56
+ - `src/server/AgentServer.ts` — construction gate (`analyst && digestDelivery !== 'off'`),
57
+ lease gate (`isAwake`), `.stop()` teardown.
58
+ - 3-tier tests + wiring-integrity + burst-invariant: `tests/unit/GrowthDigestPublisher.test.ts`
59
+ (21), `tests/integration/growth-digest-publisher{,-wiring}.test.ts` (10),
60
+ `tests/e2e/growth-digest-publisher-lifecycle.test.ts` (3), and the growth-digest aggregation
61
+ block added to `tests/integration/notification-flood-burst-invariant.test.ts`.
62
+ - The pre-existing outbound-guard route suites (`post-update-gate-budget-route`,
63
+ `localhost-link-guard-route`, `outbound-content-dedup-route`, `outbound-gate-budget`) pass
64
+ unchanged — the `evaluateOutbound` extraction is behavior-preserving.
65
+ - Side-effects review: `upgrades/side-effects/proactive-growth-digest-publisher-slice2.md`.
66
+ - Spec: `docs/specs/PROACTIVE-GROWTH-DIGEST-PUBLISHER-SLICE2-SPEC.md` (converged + approved).
@@ -0,0 +1,33 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ Added a standalone test utility — `scripts/throwaway-identity.mjs` (+ `scripts/lib/`) — that
9
+ mints genuinely-distinct, readable throwaway email inboxes via the mail.tm public
10
+ disposable-mailbox API and extracts verification codes/links from them. It's the autonomous
11
+ half of provisioning distinct test identities for the Live Integration Security-Test Harness
12
+ (Slack today, any integration later): N distinct inboxes → N genuinely-distinct principals,
13
+ zero real accounts. No runtime code, gate, or config is touched.
14
+
15
+ ## What to Tell Your User
16
+
17
+ Nothing changes in how the agent runs. This is a developer/test tool. It lets the agent set
18
+ up several genuinely-different throwaway test users (and read their email) on its own, so a
19
+ live integration test can use real distinct identities without anyone hand-creating email
20
+ accounts. The only step it intentionally leaves to a human is passing an anti-bot CAPTCHA at
21
+ workspace creation.
22
+
23
+ ## Summary of New Capabilities
24
+
25
+ - `scripts/throwaway-identity.mjs mint` — create a fresh readable throwaway inbox.
26
+ - `scripts/throwaway-identity.mjs wait <token>` — await an email and extract its code/link.
27
+ - `scripts/lib/throwaway-identity.mjs` — importable helper (HTTP injectable for hermetic tests).
28
+
29
+ ## Evidence
30
+
31
+ - 15 hermetic unit tests (`tests/unit/throwaway-identity.test.ts`) — pure extractors + the
32
+ mint / poll-until-match / timeout flow, with fetch + clock injected (no network).
33
+ - Live CLI smoke minted a real inbox + token. `tsc --noEmit` clean.
@@ -0,0 +1,201 @@
1
+ # Side-Effects Review — Proactive Growth Digest Publisher (Slice 2)
2
+
3
+ **Version / slug:** `proactive-growth-digest-publisher-slice2`
4
+ **Date:** `2026-06-10`
5
+ **Author:** `echo`
6
+ **Second-pass reviewer:** `not required (Tier 2 — converged + approved spec, 8-reviewer panel, 3 iterations)`
7
+
8
+ ## Summary of the change
9
+
10
+ Adds `GrowthDigestPublisher` (`src/monitoring/GrowthDigestPublisher.ts`): an in-process
11
+ component that consumes the existing `monitoring.growthAnalyst.digestCron` and, on that
12
+ cadence, formats ONE consolidated "growth check-in" from the already-computed
13
+ `GrowthMilestoneAnalyst.buildDigest()` and routes it through the existing flood-guarded
14
+ post-update path. It is the cadence + delivery half (Slice 2) of the growth analyst;
15
+ Slice 1 (compute + read routes) already shipped. To give the publisher a delivery path
16
+ that provably cannot bypass the dedup/budget/tone guards, the change carves a pure,
17
+ `res`-free `evaluateOutbound` funnel out of `checkOutboundMessage` in
18
+ `src/server/routes.ts` and adds a `postToUpdatesTopic` helper both the route and the
19
+ publisher share. New config keys (`digestDelivery`, `digestTimezone`,
20
+ `digestSendOnCalmWeeks`) land in `ConfigDefaults.ts` + `types.ts`; wiring + teardown in
21
+ `AgentServer.ts`. Ships dark (`digestDelivery: 'off'` by default, even on a dev agent).
22
+
23
+ ## Decision-point inventory
24
+
25
+ - `evaluateOutbound` (`src/server/routes.ts`) — **add** — pure res-free extraction of the
26
+ localhost-link guard + tone-gate decision out of `checkOutboundMessage`. Both the route
27
+ adapter and the publisher's `postToUpdatesTopic` call this single function.
28
+ - `checkOutboundMessage` (`src/server/routes.ts`) — **modify** — now a thin route adapter:
29
+ fires the two observe-only observers (route-side) + delegates the decision to
30
+ `evaluateOutbound` + maps the decision to res. Behavior byte-identical for callers.
31
+ - `postToUpdatesTopic` (`src/server/routes.ts`) — **add** — the publisher's guarded sender:
32
+ resolve Updates topic → `evaluateOutbound` → `sendToTopic`. Returns a flat DeliveryResult.
33
+ - `GrowthDigestPublisher.publishOnce` — **add** — the lease-gate → mode → in-flight →
34
+ calm → format → deliver decision chain. The publisher holds NO authority: it only sends
35
+ a message or stays quiet; a guard block is a normal, non-error outcome it never re-acts on.
36
+ - `digestDelivery` / `digestSendOnCalmWeeks` / `digestTimezone` config — **add** — the
37
+ rollout + cadence dials under `monitoring.growthAnalyst`.
38
+
39
+ ---
40
+
41
+ ## 1. Over-block
42
+
43
+ **What legitimate inputs does this change reject that it shouldn't?**
44
+
45
+ The `evaluateOutbound` extraction preserves the EXACT block/allow logic of the prior
46
+ `checkOutboundMessage` (localhost-link guard + tone gate). No new block surface is added;
47
+ the decision function returns the same 422 bodies for the same inputs (verified by the
48
+ existing `post-update-gate-budget-route`, `localhost-link-guard-route`, and
49
+ `outbound-content-dedup-route` suites — all 20 tests pass unchanged). The publisher itself
50
+ adds no block/allow surface — it is a sender, not a gate. Over-block: not applicable to the
51
+ new code; preserved for the refactored code.
52
+
53
+ ---
54
+
55
+ ## 2. Under-block
56
+
57
+ **What failure modes does this still miss?**
58
+
59
+ The publisher's bounded multi-machine handoff edge (§3.7): if a lease handoff falls between
60
+ a window's fire time and the newly-awake machine's `.start()`/catch-up, that one window can
61
+ be re-sent once (the per-machine audit log has no record of the old machine's send). This is
62
+ a deliberately-accepted under-guard in the SAFE direction — a single bounded re-send through
63
+ the same aggregating/budgeted/deduped funnel, biased toward "the check-in arrives" over
64
+ "silently dropped," which is the slice's entire reason to exist. The near-simultaneous case
65
+ is absorbed by the shared `evaluateOutbound` dedup. No new under-block in the message-gate
66
+ logic (the refactor is behavior-preserving).
67
+
68
+ ---
69
+
70
+ ## 3. Level-of-abstraction fit
71
+
72
+ **Is this at the right layer?**
73
+
74
+ Correct layers. The publisher is a thin cadence/delivery wrapper (low-level orchestration)
75
+ that DELEGATES the block/allow decision to the existing smart gate via the shared
76
+ `evaluateOutbound` — it does not re-implement guarding. The formatter is a pure render with
77
+ no decision authority (the analyst already decided what crosses a rule). The funnel
78
+ extraction is specifically a level-of-abstraction fix: it ensures the publisher FEEDS the
79
+ existing chokepoint rather than running a parallel un-guarded `sendToTopic`. The two
80
+ observe-only observers (`observeSelfViolation`, `observePrincipalCoherence`) deliberately
81
+ stay route-side, not in `evaluateOutbound` — they have nothing to catch on a proactive
82
+ digest (it credits no operator role and is authored by no principal), so keeping them out
83
+ of the shared funnel both preserves byte-identical caller behavior and avoids meaningless
84
+ telemetry.
85
+
86
+ ---
87
+
88
+ ## 4. Signal vs authority compliance
89
+
90
+ **Required reference:** [docs/signal-vs-authority.md](../../docs/signal-vs-authority.md)
91
+
92
+ **Does this change hold blocking authority with brittle logic?**
93
+
94
+ - [x] No — this change has no block/allow surface (the publisher is a sender; the
95
+ refactored `evaluateOutbound` keeps the SAME smart gate — `messagingToneGate`, an
96
+ LLM-backed authority with recent conversational context — as the sole decider).
97
+
98
+ The publisher produces a message or stays silent; it never blocks, delays, or rewrites
99
+ anything. The §3.5 superseded-job belt is a SIGNAL (an audit line), never a cross-component
100
+ mutation — the publisher never disables another component's job. The funnel extraction
101
+ keeps the single smart authority (`messagingToneGate`) and merely makes the publisher route
102
+ through it rather than around it. No brittle detector gains block authority.
103
+
104
+ ---
105
+
106
+ ## 5. Interactions
107
+
108
+ **Does this interact with existing checks, recovery paths, or infrastructure?**
109
+
110
+ - **Shadowing:** `evaluateOutbound` runs the same localhost-guard-then-tone-gate order as
111
+ before; `checkOutboundMessage` still fires the two observers FIRST (route-side), so no
112
+ existing route caller's observation is shadowed. The publisher path intentionally does NOT
113
+ fire those observers (nothing to catch) — confirmed not relied on for the digest path.
114
+ - **Double-fire:** the in-process cron runs on BOTH the awake and standby machine → the
115
+ lease gate (`isAwake`) ensures only the awake machine sends (mirrors the
116
+ scheduler/ActivitySentinel precedent the superseded `initiative-digest-review` relied on).
117
+ The superseded job + the publisher both fire `0 11 * * 1` — handled by §3.5 (durable
118
+ source-template disable at the live-flip, NOT at this dark merge; while `digestDelivery`
119
+ is `off`/`dry-run` the publisher doesn't send, so the job stays the sole voice).
120
+ - **Races:** the in-flight guard + croner `protect:true` prevent overlapping `publishOnce`
121
+ passes. The audit log is the single shared state; window-key idempotency is recorded only
122
+ on a real post-lease decision.
123
+ - **Feedback loops:** none — the digest reads analyst state and emits one message; it feeds
124
+ no system that feeds back into the analyst.
125
+
126
+ ---
127
+
128
+ ## 6. External surfaces
129
+
130
+ **Does this change anything visible outside the immediate code path?**
131
+
132
+ - **Other agents on the same machine:** none — internal component, no shared external state.
133
+ - **Install base:** none at merge — ships `digestDelivery: 'off'`; existing agents get the
134
+ three new config defaults via `applyDefaults` add-missing-only deep-merge (no migrateConfig
135
+ needed, matching the rest of the `growthAnalyst` block). No CLAUDE.md template change at
136
+ this dark merge (it rides the live-flip per the Agent Awareness Standard, parent §9).
137
+ - **External systems (Telegram):** only when an operator flips `digestDelivery` to
138
+ `dry-run`/`live` — and then it sends ONE message into the EXISTING Agent Updates topic via
139
+ the same guarded path as `/telegram/post-update`. Never a new topic, never per-finding.
140
+ - **Persistent state:** a new append-only audit log at `logs/growth-digest.jsonl`
141
+ (best-effort, never throws). No DB, no schema change.
142
+ - **Timing:** the weekly cron + a 60s settle-delayed catch-up; the cadence sanity-floor
143
+ refuses a sub-hourly `digestCron`.
144
+
145
+ ---
146
+
147
+ ## 7. Rollback cost
148
+
149
+ **If this turns out wrong in production, what's the back-out?**
150
+
151
+ Pure code change shipping dark — revert and ship a patch. No persistent state needs cleanup
152
+ (`logs/growth-digest.jsonl` is an inert append-only log; leaving it is harmless). No agent
153
+ state repair (the publisher is simply not constructed when `digestDelivery: 'off'`). No
154
+ user-visible regression during the rollback window, because at merge nothing is sent
155
+ (default off). The `evaluateOutbound` extraction is behavior-preserving and covered by the
156
+ pre-existing route suites, so reverting it carries no caller-facing risk either.
157
+
158
+ ---
159
+
160
+ ## Conclusion
161
+
162
+ This review found no new block/allow surface and no signal-vs-authority violation: the
163
+ publisher is a sender that delegates every guard decision to the existing smart gate via a
164
+ deliberately-extracted single funnel, closing off the "second un-guarded send path" the
165
+ review flagged in the draft. The multi-machine double-send (the one SERIOUS finding from
166
+ convergence) is fixed by the lease gate; the bounded handoff re-send is an accepted,
167
+ SAFE-direction tradeoff. The change ships dark with zero user-facing surface at merge, so
168
+ rollback is a plain revert. Clear to ship.
169
+
170
+ ---
171
+
172
+ ## Second-pass review (if required)
173
+
174
+ **Reviewer:** not required
175
+
176
+ The change carries a converged + approved Tier-2 spec
177
+ (`docs/specs/PROACTIVE-GROWTH-DIGEST-PUBLISHER-SLICE2-SPEC.md`) reviewed by an 8-reviewer
178
+ panel (security, scalability, adversarial, integration, lessons-aware + gemini) over 3
179
+ iterations; the convergence report is the independent-read record.
180
+
181
+ ---
182
+
183
+ ## Evidence pointers
184
+
185
+ - `src/monitoring/GrowthDigestPublisher.ts` — the publisher + pure `formatDigest` +
186
+ `createGrowthDigestAuditSink`.
187
+ - `src/server/routes.ts` — `evaluateOutbound` (pure funnel), `checkOutboundMessage`
188
+ (thin adapter), `postToUpdatesTopic` (publisher sender), `attachSender` hookup.
189
+ - `src/server/AgentServer.ts` — construction gate (`analyst && digestDelivery !== 'off'`),
190
+ lease gate (`isAwake`), `.stop()` teardown.
191
+ - `tests/unit/GrowthDigestPublisher.test.ts` — 21 tests (publishOnce matrix, lease gate,
192
+ in-flight guard, missed-run catch-up idempotency, sanity-floor, formatter guarantees).
193
+ - `tests/integration/growth-digest-publisher.test.ts` +
194
+ `tests/integration/growth-digest-publisher-wiring.test.ts` — guarded delivery + single-
195
+ funnel + sender-not-a-no-op + lease-gate wiring (10 tests).
196
+ - `tests/e2e/growth-digest-publisher-lifecycle.test.ts` — boots the real AgentServer:
197
+ LIVE lands one check-in in the Updates topic; OFF / no-analyst → publisher null (3 tests).
198
+ - `tests/integration/notification-flood-burst-invariant.test.ts` — 500-finding burst → one
199
+ bounded message, high-priority finding rendered in full.
200
+ - `npm run lint` clean (incl. dev-agent-dark-gate); analyst + ConfigDefaults regression
201
+ suites green (80 tests).
@@ -0,0 +1,48 @@
1
+ # Side-Effects Review — throwaway-identity helper
2
+
3
+ **Version / slug:** `throwaway-identity-helper`
4
+ **Date:** `2026-06-10`
5
+ **Author:** `echo`
6
+ **Tier:** `1` (standalone test-tooling script + lib + hermetic test; no runtime/gate/config wiring)
7
+ **Second-pass reviewer:** `not required`
8
+
9
+ ## Summary of the change
10
+
11
+ Adds `scripts/lib/throwaway-identity.mjs` (importable) + `scripts/throwaway-identity.mjs`
12
+ (CLI) — mints genuinely-distinct, readable throwaway email inboxes via the mail.tm public
13
+ disposable-mailbox API, and polls/extracts codes+links from them. The autonomous half of
14
+ test-identity provisioning for live-integration test harnesses (Slack/Discord/…). + a fully
15
+ hermetic unit test (injected fetch + clock, no network) and an ELI16.
16
+
17
+ ## Decision-point inventory
18
+
19
+ None in runtime — it's standalone tooling, never imported by `src/` or wired into a gate.
20
+ Internal branch points (domain selection, message-match filter, timeout) are pure functions
21
+ covered by the test.
22
+
23
+ ## 1. Over-block
24
+
25
+ Nothing is rejected at runtime. The tool only calls a public disposable-mail API and reads
26
+ inboxes it just created. It is not on any agent code path.
27
+
28
+ ## 2. Under-block
29
+
30
+ It deliberately does NOT cover the anti-bot signup CAPTCHA at workspace/account creation —
31
+ that is a human-verification control and remains a ~30s human handoff (documented in the
32
+ live-run runbook). It is the email half only.
33
+
34
+ ## 3. Level-of-abstraction fit
35
+
36
+ Right layer: a `scripts/` + `scripts/lib/` test utility beside the other dev/test scripts,
37
+ with the HTTP injected so the test is hermetic. Reusable by any integration's live harness,
38
+ not coupled to the permission gate.
39
+
40
+ ## Migration / rollback
41
+
42
+ No migration (standalone tooling). Rollback = delete the two scripts + the test.
43
+
44
+ ## Testing-integrity note
45
+
46
+ 15 hermetic unit tests (pure extractors + the full mint / poll-until-match / timeout flow,
47
+ HTTP + clock injected). A separate live CLI smoke confirmed it mints a real inbox
48
+ (`echo-…@web-library.net` + token). `tsc --noEmit` clean.