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.
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +7 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/types.d.ts +13 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/GrowthDigestPublisher.d.ts +168 -0
- package/dist/monitoring/GrowthDigestPublisher.d.ts.map +1 -0
- package/dist/monitoring/GrowthDigestPublisher.js +477 -0
- package/dist/monitoring/GrowthDigestPublisher.js.map +1 -0
- package/dist/server/AgentServer.d.ts +1 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +67 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +5 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +95 -71
- package/dist/server/routes.js.map +1 -1
- package/package.json +1 -1
- package/scripts/lib/throwaway-identity.mjs +150 -0
- package/scripts/throwaway-identity.mjs +77 -0
- package/src/data/builtin-manifest.json +47 -47
- package/upgrades/1.3.475.md +66 -0
- package/upgrades/1.3.476.md +33 -0
- package/upgrades/side-effects/proactive-growth-digest-publisher-slice2.md +201 -0
- package/upgrades/side-effects/throwaway-identity-helper.md +48 -0
|
@@ -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.
|