instar 1.3.28 → 1.3.30
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/dashboard/index.html +112 -0
- package/dashboard/process-health.js +504 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +17 -0
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/messaging/AgentTelegramComms.d.ts +156 -0
- package/dist/messaging/AgentTelegramComms.d.ts.map +1 -0
- package/dist/messaging/AgentTelegramComms.js +170 -0
- package/dist/messaging/AgentTelegramComms.js.map +1 -0
- package/dist/monitoring/FailureLedger.d.ts +11 -3
- package/dist/monitoring/FailureLedger.d.ts.map +1 -1
- package/dist/monitoring/FailureLedger.js +22 -5
- package/dist/monitoring/FailureLedger.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/routes.d.ts.map +1 -1
- package/dist/server/routes.js +48 -4
- package/dist/server/routes.js.map +1 -1
- package/package.json +2 -1
- package/scripts/analyze-release.js +21 -7
- package/src/data/builtin-manifest.json +62 -62
- package/src/scaffold/templates.ts +6 -0
- package/upgrades/1.3.29.md +42 -0
- package/upgrades/1.3.30.md +35 -0
- package/upgrades/side-effects/agent-telegram-comms-primitive.md +75 -0
- package/upgrades/side-effects/process-health-dashboard-tab.md +59 -0
- package/upgrades/side-effects/release-readiness-visibility-pr1.md +26 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Instar Upgrade Guide — NEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: minor -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
**New building block: agent-to-agent Telegram comms primitive (core logic).** This is the
|
|
8
|
+
first piece of a robust, reusable way for two Instar agents to talk over Telegram *knowingly*
|
|
9
|
+
— every agent-to-agent message carries a visible marker
|
|
10
|
+
(`[a2a:from=… to=… role=… id=… corr=… ts=… v=1]`) so the receiving side can tell it's from
|
|
11
|
+
another agent and apply anti-loop machinery, rather than treating it like a human user
|
|
12
|
+
message. This increment ships the pure, security-critical core: the strict marker
|
|
13
|
+
parser/formatter, the recipient routing decision (with the full drop matrix — malformed,
|
|
14
|
+
replay-window, user-spoof, wrong-recipient, unknown-sender, duplicate, and per-source role
|
|
15
|
+
admission), and the cycle-detection key. It ships **dark** — nothing wires it yet (the
|
|
16
|
+
TelegramAdapter integration and the first consumer, the mentor, land in follow-up PRs).
|
|
17
|
+
|
|
18
|
+
## What to Tell Your User
|
|
19
|
+
|
|
20
|
+
- Nothing changes in how your agent behaves today — this is groundwork. It's the foundation
|
|
21
|
+
for agents being able to message each other over Telegram safely (with built-in defenses
|
|
22
|
+
so they can't spoof each other or get stuck in a reply loop), which a later update will
|
|
23
|
+
switch on for the mentor feature.
|
|
24
|
+
|
|
25
|
+
## Summary of New Capabilities
|
|
26
|
+
|
|
27
|
+
| Capability | How to Use |
|
|
28
|
+
|-----------|-----------|
|
|
29
|
+
| `AgentTelegramComms` primitive (core) | Internal `parseMarker` / `formatMarker` / `decideRoute` / `CycleDetector` in `src/messaging/AgentTelegramComms.ts` — pure logic, I/O injected; not wired yet |
|
|
30
|
+
|
|
31
|
+
## Evidence
|
|
32
|
+
|
|
33
|
+
**Net-new feature, not a bug fix** — a new pure-logic module that nothing imports yet
|
|
34
|
+
(ships dark). Proven by 20 unit tests covering every branch of the security-critical logic:
|
|
35
|
+
marker parse/format (valid; no-marker vs malformed incl. missing `corr`/`ts`, charset
|
|
36
|
+
violation, no separator; round-trip); the full routing matrix (route + fall-through + every
|
|
37
|
+
drop reason, including the **user-spoof defense** — a human typing a marker-shaped string is
|
|
38
|
+
dropped even when from/id match an allowlisted bot — and **per-source role acceptance** — a
|
|
39
|
+
known role from the wrong source is dropped); and cycle-detection (key never collapses,
|
|
40
|
+
trips within window, no false collision). `tsc --noEmit` clean. The integration + e2e tiers
|
|
41
|
+
(real TelegramAdapter wiring, the bidirectional contract test, the supervised live cycle)
|
|
42
|
+
land with the follow-up PRs per the spec's staged plan.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: minor -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
Adds the **Process Health dashboard tab** — a calm, human-readable window into the Failure-Learning Loop (spec `docs/specs/PROCESS-HEALTH-DASHBOARD-TAB-SPEC.md`, converged v4, approved). Until now the loop's findings were API-only (reachable via `/failures*` curl); this tab surfaces them in the dashboard you actually look at.
|
|
8
|
+
|
|
9
|
+
The tab opens with one plain-English headline ("Watching — N issues recorded"), then surfaced patterns as readable cards (awareness-only — never auto-acted-on), recent captures as plain sentences, and a maturation track with a "← you're here" marker. The dense aggregate counts live in a collapsed "Detail" drawer at the bottom. When the Failure-Learning Loop is off, the tab shows a friendly "not turned on yet" message rather than an error.
|
|
10
|
+
|
|
11
|
+
UX is the centerpiece, not an afterthought: measurable type bars (headline ≥24px, section headers ≥20px, body ≥17px, line-height 1.5–1.6, zero monospace) are enforced by tests, and a glance check asserts the visible text never reads like a debug log. Every dynamic value (commit messages, agent diagnoses, the classifier's output) flows through a single sanitize-and-cap helper before the DOM — textContent-only writes, NFKC fold, control/bidi/chrome-glyph strip, grapheme-safe length caps, and a same-origin `safeUrl` — so untrusted upstream text can't inject markup, fake-authority glyphs, or invisible/right-to-left trickery. The redaction contract (`detail.full` never crosses the wire) is verified end-to-end against a live HTTP server.
|
|
12
|
+
|
|
13
|
+
Server-side this adds ETag/304 diff-aware polling on `/failures*`, a `before=` keyset-pagination parameter (rejects a non-ISO value with 400), and a `rollout` block on `/failures/analysis` (the maturation stage the tab draws). No behavioral change when the loop is disabled — every route still 503s and the tab renders its disabled copy.
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
- There's a new **Process Health** tab in your dashboard. It's a calm, plain-English view of what the failure-watching system is noticing — big readable type, short sentences, no wall of logs.
|
|
18
|
+
- Think of it like a dashboard light in a car, not the mechanic's diagnostic printout: one line tells you whether anything needs a look; the raw numbers are tucked away in a drawer you only open if you want them.
|
|
19
|
+
- If the failure-watching system isn't switched on for an agent, the tab just says so politely instead of looking broken.
|
|
20
|
+
- Nothing to run and nothing to babysit — it refreshes itself quietly while the tab is open and pauses when it isn't.
|
|
21
|
+
|
|
22
|
+
## Summary of New Capabilities
|
|
23
|
+
|
|
24
|
+
| Capability | How to Use |
|
|
25
|
+
|-----------|-----------|
|
|
26
|
+
| Process Health dashboard tab | Open the "Process Health" tab in the dashboard (give the user the dashboard URL + PIN) |
|
|
27
|
+
| Diff-aware polling (ETag/304) | Automatic — `GET /failures*` now return an `ETag`; a matching `If-None-Match` gets a 304 |
|
|
28
|
+
| Keyset pagination | `GET /failures?before=<ISO-ts>&limit=N` and `GET /failures/insights?before=<ISO-ts>&limit=N` |
|
|
29
|
+
| Rollout-stage readout | `GET /failures/analysis` now includes `rollout: { stage, enabled, insightTelegramEscalation }` |
|
|
30
|
+
|
|
31
|
+
## Evidence
|
|
32
|
+
|
|
33
|
+
- **3-tier + jsdom tests, all green:** unit (sanitize/safeUrl/wording + renderers against a real jsdom DOM + ledger pagination), integration (the polling controller — XSS negative, layout-bomb, out-of-order race, visibility-gating, staleness hard-fail AND the 304-pinned-headline case, 304 backoff/recovery, diff-aware zero-mutation; plus the route ETag/304/`before=`/rollout behaviors), and an E2E lifecycle test that boots a real HTTP server and drives the shipped controller through a jsdom-mounted tab with the feature ON and OFF.
|
|
34
|
+
- **Safety verified, not asserted:** the XSS negative fixture feeds `<img onerror>`/`<script>`/`<svg onload>` through the full controller path and asserts zero live elements + no canary fired; the E2E seeds a failure whose `detail.full` is a secret path and confirms it never appears in the rendered DOM.
|
|
35
|
+
- **Migration parity:** the CLAUDE.md "Process Health (Dashboard Tab)" section ships to existing agents via `PostUpdateMigrator.migrateClaudeMd`, and a shadow-capability marker carries it to Codex/Gemini agents — both enforced by the Feature Delivery Completeness test.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Side-Effects Review — Agent-to-Agent Telegram comms primitive (core logic, PR 1)
|
|
2
|
+
|
|
3
|
+
**Spec:** `docs/specs/MENTOR-LIVE-READINESS-SPEC.md` §Fix 2a (converged, approved by Justin
|
|
4
|
+
2026-05-27). Convergence report: `docs/specs/reports/mentor-live-readiness-convergence.md`.
|
|
5
|
+
**Change:** New module `src/messaging/AgentTelegramComms.ts` — the PURE, security-critical
|
|
6
|
+
core of the agent-to-agent Telegram comms primitive: strict marker parse/format, the
|
|
7
|
+
recipient routing matrix (every drop branch), and cycle-detection. I/O (the actual Telegram
|
|
8
|
+
send, audit ledgers, processed-id store) is **injected**, so this PR is pure logic + tests;
|
|
9
|
+
the TelegramAdapter wiring + ledger persistence is PR 2, the mentor consumer is PR 3.
|
|
10
|
+
**Files:** `src/messaging/AgentTelegramComms.ts` (new), `tests/unit/messaging/AgentTelegramComms.test.ts` (new).
|
|
11
|
+
**Ships dark:** nothing imports the module yet except its test — zero runtime behavior change.
|
|
12
|
+
|
|
13
|
+
## Principle check (Phase 1)
|
|
14
|
+
|
|
15
|
+
Decision point? Yes — this is the recipient admission/routing decision (`decideRoute`) and
|
|
16
|
+
the anti-loop cycle key. It is built as PURE functions returning a decision the caller acts
|
|
17
|
+
on; the blocking authority (drop vs route) is explicit + exhaustively tested. No existing
|
|
18
|
+
gate is loosened (nothing wired yet).
|
|
19
|
+
|
|
20
|
+
## The seven questions
|
|
21
|
+
|
|
22
|
+
1. **Over-block.** `decideRoute` drops on every ambiguous/unrecognized shape (malformed,
|
|
23
|
+
stale, spoofed, wrong-recipient, unknown-version, unknown-sender, duplicate,
|
|
24
|
+
role-not-allowed). Correct posture for a security boundary — a marker-shaped string is
|
|
25
|
+
guilty until allowlisted. The only fall-through is a genuine no-marker (normal user msg).
|
|
26
|
+
2. **Under-block.** The spoof defense (`!senderIsBot && senderChatId===undefined` → drop)
|
|
27
|
+
is the round-2 adversarial F1 closure — a human typing a marker can NEVER reach a
|
|
28
|
+
role-handler, even if from/id match. Tested explicitly. `corr`/`ts` are required in the
|
|
29
|
+
parser so neither the cycle key nor the replay window can be bypassed by omission.
|
|
30
|
+
3. **Level-of-abstraction fit.** Pure logic separated from I/O — the security decisions are
|
|
31
|
+
unit-testable in isolation (20 tests, every branch). I/O injection deferred to PR 2.
|
|
32
|
+
4. **Signal vs authority.** `decideRoute` IS the authority (drop/route); it returns a typed
|
|
33
|
+
decision + audit reason for every branch (no silent drops — caller writes the audit row).
|
|
34
|
+
5. **Interactions.** Module is dark (imported only by its test). No interaction with the
|
|
35
|
+
running system yet. PR 2 wires it into TelegramAdapter (multi-instance + handler-chain);
|
|
36
|
+
PR 3 wires the mentor consumer. Each subsequent PR re-runs the gate against the same spec.
|
|
37
|
+
6. **External surfaces.** None in this PR (no routes, no config consumed yet). The marker
|
|
38
|
+
format is the wire contract for PR 2/3 + Codey's side; `A2A_VERSION` is exported for
|
|
39
|
+
version pinning.
|
|
40
|
+
7. **Rollback cost.** Trivial — revert removes an unused module. No data, no migration.
|
|
41
|
+
|
|
42
|
+
## Build-time refinements beyond the spec text
|
|
43
|
+
|
|
44
|
+
- The spec mentioned `state/a2a-*.jsonl` (append-only JSONL audit) + a processed-id JSON
|
|
45
|
+
store. Convention note (MessageProcessingLedger header: "NOT a new ad-hoc JSON file") —
|
|
46
|
+
PR 2 will implement the processed-id store on the SQLite path (matching
|
|
47
|
+
PendingRelayStore/CommitmentTracker) rather than a JSON file; the append-only audit
|
|
48
|
+
ledgers stay JSONL (Codey designed the audit-row schema as JSONL, and append-only JSONL
|
|
49
|
+
is the right shape for a forensic trail). Flagged here so PR 2's choice is intentional.
|
|
50
|
+
- `senderBotId` resolution (`sender_chat.id ?? from.id`) + `senderIsBot` are passed in by
|
|
51
|
+
the caller (PR 2 resolves them from the Telegram update, after the Message type is
|
|
52
|
+
extended to expose `is_bot`/`sender_chat`). The pure core only consumes them.
|
|
53
|
+
|
|
54
|
+
## Testing
|
|
55
|
+
|
|
56
|
+
- 20 unit tests (`tests/unit/messaging/AgentTelegramComms.test.ts`), all passing:
|
|
57
|
+
- **Marker parse/format**: valid parse; no-marker (fall-through) vs malformed (drop) —
|
|
58
|
+
incl. missing `corr`, missing `ts`, charset violation, no blank-line separator;
|
|
59
|
+
format↔parse round-trip; format rejects charset-violating fields.
|
|
60
|
+
- **Routing matrix**: route success; fall-through; and every drop branch — malformed,
|
|
61
|
+
stale/future (replay), **user-spoof** (human-typed marker dropped even when from/id
|
|
62
|
+
match), group bot-as-channel accept, wrong-recipient, unsupported-version, unknown
|
|
63
|
+
sender, bot-id mismatch, duplicate, **role-not-allowed-from-source** (notify from echo
|
|
64
|
+
dropped even though notify is a known role), unknown-role.
|
|
65
|
+
- **Cycle-detection**: key never collapses (corr always present); trips within window,
|
|
66
|
+
clears after; no collision on different corr.
|
|
67
|
+
- tsc --noEmit clean.
|
|
68
|
+
- PR 2/3 add the integration + e2e tiers (TelegramAdapter wiring, mentor consumer, the
|
|
69
|
+
bidirectional contract test, the supervised live cycle).
|
|
70
|
+
|
|
71
|
+
## Migration parity
|
|
72
|
+
|
|
73
|
+
None for this PR — a new unwired module. No agent-installed file changes, no config, no
|
|
74
|
+
routes. PR 2/3 carry the config defaults + migration (file-outbox retirement, dead-config
|
|
75
|
+
removal) per the spec's §Migration parity.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Side-Effects Review — Process Health dashboard tab
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `process-health-dashboard-tab`
|
|
4
|
+
**Date:** 2026-05-27
|
|
5
|
+
**Author:** echo
|
|
6
|
+
**Spec:** `docs/specs/PROCESS-HEALTH-DASHBOARD-TAB-SPEC.md` (v4, converged, approved: true)
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Adds a read-only dashboard tab that renders the Failure-Learning Loop's data (captures, surfaced patterns, rollout stage) as a calm, plain-English surface. Until now those data were API-only (`/failures*`); this makes them visible in the dashboard. The feature ships with the loop's existing on/off flag — when the loop is disabled every `/failures*` route 503s and the tab renders a friendly disabled state.
|
|
11
|
+
|
|
12
|
+
**Files changed (source):**
|
|
13
|
+
- `dashboard/process-health.js` (NEW, ~504 lines) — browser-native ESM module: pure renderers + the polling controller, both exported for tests. The load-bearing safety contract lives here (`sanitizeForDisplay`, `safeUrl`, `isMixedScript`, friendly-wording maps).
|
|
14
|
+
- `dashboard/index.html` — the tab button, panel markup, calm CSS (measurable type bars, no monospace), tab registration, and the lazy-import lifecycle wiring (start on activate / stop on hide).
|
|
15
|
+
- `src/server/routes.ts` — ETag/304 on `/failures` + `/failures/insights`, `before=` ISO-validation (400 on garbage), and the `rollout` block assembled in `/failures/analysis` (stage derived from the two `failureLearning` flags).
|
|
16
|
+
- `src/monitoring/FailureLedger.ts` — `ListFilter.beforeMs`/`limit`, a new `InsightListFilter` (50-default / 1000-max), a `listInsights` query-builder rewrite (where[]+LIMIT), and a `discovered_at` index for keyset pagination.
|
|
17
|
+
- `src/scaffold/templates.ts` — the "Process Health (Dashboard Tab)" CLAUDE.md section for new agents (Agent Awareness Standard).
|
|
18
|
+
- `src/core/PostUpdateMigrator.ts` — `migrateClaudeMd` backfill of that section for existing agents + a `migrateFrameworkShadowCapabilities` marker so Codex/Gemini agents learn it (Migration Parity Standard).
|
|
19
|
+
|
|
20
|
+
**Files changed (tests):**
|
|
21
|
+
- `tests/unit/process-health-render.test.ts` (NEW) — sanitize/safeUrl/wording + renderers against jsdom + CSS type-bar assertions.
|
|
22
|
+
- `tests/integration/process-health-tab.test.ts` (NEW) — the polling controller's full §4.3 surface (XSS, layout-bomb, race, visibility-gating, staleness hard-fail + 304-pinned, backoff, diff-aware) + the glance no-debug-vocabulary check.
|
|
23
|
+
- `tests/e2e/process-health-tab-lifecycle.test.ts` (NEW) — real HTTP server + jsdom-mounted tab, feature ON and OFF; detail.full-never-leaks verified end-to-end.
|
|
24
|
+
- `tests/integration/failure-routes.test.ts` — ETag/304, `before=` 400, rollout-stage derivation.
|
|
25
|
+
- `tests/unit/FailureLedger.test.ts` — before=/limit pagination + insight clamp.
|
|
26
|
+
- `tests/unit/PostUpdateMigrator-processHealth.test.ts` (NEW) — runtime migration + idempotency.
|
|
27
|
+
- `tests/unit/feature-delivery-completeness.test.ts` — registered Process Health in `featureSections`; incidentally fixed a pre-existing untracked section (`Cross-Machine Seamlessness`).
|
|
28
|
+
|
|
29
|
+
**Files changed (dependency):** `package.json` / `package-lock.json` — added `jsdom` as a devDependency (the spec's chosen DOM test harness; no runtime dependency added).
|
|
30
|
+
|
|
31
|
+
**Files changed (release):** `upgrades/NEXT.md` (NEW) — the upgrade-guide leg, `bump: minor`.
|
|
32
|
+
|
|
33
|
+
## Decision-point inventory
|
|
34
|
+
|
|
35
|
+
- **New runtime dependency?** No. `jsdom` is devDependencies only; the tab ships as browser-native ESM with no build step and no new server-side package.
|
|
36
|
+
- **New auth surface?** No. The tab is served behind the existing dashboard PIN; it adds no endpoint that wasn't already auth-gated.
|
|
37
|
+
- **Untrusted-data rendering** (commit messages, agent diagnoses, classifier output): **render, but only via the sanitize-and-cap helper** — textContent-only DOM writes, NFKC fold, control/bidi/chrome-glyph strip, grapheme-safe caps, same-origin `safeUrl`. Patterns cards are awareness-only with renderer-owned framing and NO action authority.
|
|
38
|
+
- **Behavior when loop disabled:** unchanged — routes still 503, tab renders pinned disabled copy (no config-key string, no monospace), never an error.
|
|
39
|
+
|
|
40
|
+
## Side-effects analysis
|
|
41
|
+
|
|
42
|
+
- **Behavioral:** Additive. The new route behaviors (ETag/304, `before=`) are backward-compatible — a client that ignores ETags gets a normal 200; omitting `before=` is unchanged. The `rollout` block is a new field on an existing response, not a breaking change.
|
|
43
|
+
- **Architectural:** The tab is one self-contained module, not a refactor of the dashboard SPA (explicitly out of scope per spec §10). `listInsights` moved from a ternary to the same where[]+LIMIT builder `list()` already uses — same shape, lower divergence.
|
|
44
|
+
- **Security:** The primary surface is rendering untrusted upstream prose on a read tab. Mitigated by the single sanitize path + textContent-only + element-ban (verified by the XSS negative fixture firing no canary and producing zero live elements). The `detail.full` redaction contract is depended upon and verified end-to-end (a seeded secret path never appears in the DOM). Accepted residual: a low-severity social-engineering surface inherent to showing untrusted text — any future *actionable* treatment is gated behind the deferred `InsightRecord.provenance` contract (spec §10).
|
|
45
|
+
- **Migration parity:** Covered all three legs — templates.ts (new agents), PostUpdateMigrator (existing agents + shadow markers for Codex/Gemini), and NEXT.md (upgrade guide). Enforced by the Feature Delivery Completeness test.
|
|
46
|
+
- **Performance:** ETag/304 + diff-aware rendering means identical ticks do zero DOM mutations and 304s skip body transfer; 304-backoff widens the poll to 5 min after 5 idle ticks. The new `discovered_at` index supports keyset pagination without a full scan.
|
|
47
|
+
- **Reversibility:** Fully reversible by reverting the commit. The feature is gated OFF by default via the existing `failureLearning.enabled` flag — no agent sees the tab change behavior until the loop is enabled, and even then it is a read surface.
|
|
48
|
+
|
|
49
|
+
## Deferred (tracked, not silently dropped)
|
|
50
|
+
|
|
51
|
+
- **LLM text-smoke (spec §6.4b):** implemented the *deterministic* glance gate (no-debug-vocabulary + plain-state assertion across all 3 fixtures), which is structurally stronger than an LLM judgment for this property and runs in CI. The soft LLM-judgment variant (a Haiku call over the text projection) is deferred as a manual reviewer-attested pre-flight rather than a forever-skipped CI harness — consistent with §6.4a's "honestly labeled soft" framing.
|
|
52
|
+
- **Visual dashboard polish / extra ingestion sources:** already tracked as fast-follows on the initiative board (spec §10).
|
|
53
|
+
|
|
54
|
+
## Evidence pointers
|
|
55
|
+
|
|
56
|
+
- Typecheck: `tsc --noEmit` — 0 errors.
|
|
57
|
+
- CI-mirror smoke suite (`npm run test:smoke`): **149 files, 3553 tests passed, 0 failed**.
|
|
58
|
+
- New tests run green in isolation: unit render (27), controller integration (12), failure-routes (11), FailureLedger (11), migrator (2), E2E lifecycle (4).
|
|
59
|
+
- Safety verified not asserted: XSS fixture fires no canary + 0 live elements; E2E confirms a seeded `detail.full` secret path is absent from the rendered DOM.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Side-Effects Review — Release-Readiness Visibility, PR-1 (`analyze-release.js --ref`)
|
|
2
|
+
|
|
3
|
+
**Spec:** docs/specs/RELEASE-READINESS-VISIBILITY-SPEC.md (converged + approved 2026-05-27)
|
|
4
|
+
**Scope of this PR:** the prerequisite-only change — add a `--ref=<rev>` flag to `scripts/analyze-release.js` and thread it through the git-range queries. No sentinel, no job, no routes (those are PR-2/PR-3). Plus the approved spec docs + convergence report + a unit test.
|
|
5
|
+
|
|
6
|
+
## What changed
|
|
7
|
+
|
|
8
|
+
- `scripts/analyze-release.js`: new `REF` constant parsed from `--ref=<rev>` / `--ref <rev>` (default `HEAD`). Threaded into `getLastReleaseTag`, `getCommitsSinceTag`, `getDiffStat`, `getChangedFiles`, `getFileDiff` — every place that previously hardcoded `HEAD`.
|
|
9
|
+
- `tests/unit/analyze-release-ref-flag.test.ts`: 4 subprocess tests against a deterministic git fixture (default ≡ HEAD; `--ref=HEAD` ≡ default; `--ref=<earlier commit>` changes the analyzed tip — different nearest tag + commit count; space form ≡ equals form).
|
|
10
|
+
- Spec + ELI16 + convergence report (docs only).
|
|
11
|
+
|
|
12
|
+
## Side-effects analysis
|
|
13
|
+
|
|
14
|
+
**Over/under-reach.** The change is additive and opt-in. `REF` defaults to `'HEAD'`, so every existing caller — most importantly the `prepublishOnly` chain (`npm run check:release` → `analyze-release.js`, which never passes `--ref`) — produces byte-identical behavior to before. There is no path where omitting the flag changes output. Verified by the `--ref=HEAD ≡ default` test.
|
|
15
|
+
|
|
16
|
+
**Level-of-abstraction fit.** The ref is a module-level constant rather than a threaded parameter, matching the script's existing shape (`getLastReleaseTag()` already took no args and implicitly used HEAD). This keeps the diff minimal and the helpers' signatures unchanged for the four that already took `tag`.
|
|
17
|
+
|
|
18
|
+
**Signal vs authority.** N/A for this PR — `analyze-release.js` is a read-only analyzer (it only reads git and prints a report). It gates nothing. The flag does not grant or remove any blocking authority. The downstream consumer that WILL use `--ref=FETCH_HEAD` (Layer B's readiness sentinel) is signal-only and ships in PR-2.
|
|
19
|
+
|
|
20
|
+
**Interactions.** The only consumer touched today is the prepublish chain, which is unaffected (default HEAD). `check-upgrade-guide.js` is not touched. The `--ref` flag is forward-looking: PR-2's readiness job will invoke `--ref=FETCH_HEAD` after a bounded fetch of canonical main. Per §10 sequencing, PR-2 does not merge until this PR is on main, enforced by a required-status CI check that asserts `--ref=<known SHA>` differs from `--ref=HEAD` (i.e. the flag is genuinely threaded, not silently ignored).
|
|
21
|
+
|
|
22
|
+
**Input safety.** `REF` flows only into `git` argv arrays via the existing `gitRead` helper (`execFileSync`, no shell) — no shell-injection surface. A bogus ref makes the underlying `git` call fail and the existing `try/catch` returns the empty/initial-commit fallback, exactly as today for a tagless repo.
|
|
23
|
+
|
|
24
|
+
**Rollback cost.** Trivial — reverting this commit restores the hardcoded `HEAD`. No state, no config, no migration introduced by PR-1. The unit test reverts with it.
|
|
25
|
+
|
|
26
|
+
**Testing.** Unit tier covered (4 tests, green). Integration/E2E tiers are not applicable to PR-1 in isolation (no routes/jobs yet) and land with PR-2, which adds the `GET /release-readiness` route + the "feature is alive" E2E that exercises the full readiness pipeline including the `--ref` path.
|