instar 1.3.44 → 1.3.46

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-28T01:59:27.143Z",
5
- "instarVersion": "1.3.44",
4
+ "generatedAt": "2026-05-28T02:19:53.690Z",
5
+ "instarVersion": "1.3.46",
6
6
  "entryCount": 193,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -11,7 +11,7 @@
11
11
  "domain": "identity",
12
12
  "sourcePath": "src/core/PostUpdateMigrator.ts",
13
13
  "installedPath": ".instar/hooks/instar/session-start.sh",
14
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
14
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
15
15
  "since": "2025-01-01"
16
16
  },
17
17
  "hook:dangerous-command-guard": {
@@ -20,7 +20,7 @@
20
20
  "domain": "safety",
21
21
  "sourcePath": "src/core/PostUpdateMigrator.ts",
22
22
  "installedPath": ".instar/hooks/instar/dangerous-command-guard.sh",
23
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
23
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
24
24
  "since": "2025-01-01"
25
25
  },
26
26
  "hook:grounding-before-messaging": {
@@ -29,7 +29,7 @@
29
29
  "domain": "safety",
30
30
  "sourcePath": "src/core/PostUpdateMigrator.ts",
31
31
  "installedPath": ".instar/hooks/instar/grounding-before-messaging.sh",
32
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
32
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
33
33
  "since": "2025-01-01"
34
34
  },
35
35
  "hook:compaction-recovery": {
@@ -38,7 +38,7 @@
38
38
  "domain": "identity",
39
39
  "sourcePath": "src/core/PostUpdateMigrator.ts",
40
40
  "installedPath": ".instar/hooks/instar/compaction-recovery.sh",
41
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
41
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
42
42
  "since": "2025-01-01"
43
43
  },
44
44
  "hook:external-operation-gate": {
@@ -47,7 +47,7 @@
47
47
  "domain": "safety",
48
48
  "sourcePath": "src/core/PostUpdateMigrator.ts",
49
49
  "installedPath": ".instar/hooks/instar/external-operation-gate.js",
50
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
50
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
51
51
  "since": "2025-01-01"
52
52
  },
53
53
  "hook:deferral-detector": {
@@ -56,7 +56,7 @@
56
56
  "domain": "safety",
57
57
  "sourcePath": "src/core/PostUpdateMigrator.ts",
58
58
  "installedPath": ".instar/hooks/instar/deferral-detector.js",
59
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
59
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
60
60
  "since": "2025-01-01"
61
61
  },
62
62
  "hook:post-action-reflection": {
@@ -65,7 +65,7 @@
65
65
  "domain": "evolution",
66
66
  "sourcePath": "src/core/PostUpdateMigrator.ts",
67
67
  "installedPath": ".instar/hooks/instar/post-action-reflection.js",
68
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
68
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
69
69
  "since": "2025-01-01"
70
70
  },
71
71
  "hook:external-communication-guard": {
@@ -74,7 +74,7 @@
74
74
  "domain": "safety",
75
75
  "sourcePath": "src/core/PostUpdateMigrator.ts",
76
76
  "installedPath": ".instar/hooks/instar/external-communication-guard.js",
77
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
77
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
78
78
  "since": "2025-01-01"
79
79
  },
80
80
  "hook:scope-coherence-collector": {
@@ -83,7 +83,7 @@
83
83
  "domain": "coherence",
84
84
  "sourcePath": "src/core/PostUpdateMigrator.ts",
85
85
  "installedPath": ".instar/hooks/instar/scope-coherence-collector.js",
86
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
86
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
87
87
  "since": "2025-01-01"
88
88
  },
89
89
  "hook:scope-coherence-checkpoint": {
@@ -92,7 +92,7 @@
92
92
  "domain": "coherence",
93
93
  "sourcePath": "src/core/PostUpdateMigrator.ts",
94
94
  "installedPath": ".instar/hooks/instar/scope-coherence-checkpoint.js",
95
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
95
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
96
96
  "since": "2025-01-01"
97
97
  },
98
98
  "hook:free-text-guard": {
@@ -101,7 +101,7 @@
101
101
  "domain": "safety",
102
102
  "sourcePath": "src/core/PostUpdateMigrator.ts",
103
103
  "installedPath": ".instar/hooks/instar/free-text-guard.sh",
104
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
104
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
105
105
  "since": "2025-01-01"
106
106
  },
107
107
  "hook:claim-intercept": {
@@ -110,7 +110,7 @@
110
110
  "domain": "coherence",
111
111
  "sourcePath": "src/core/PostUpdateMigrator.ts",
112
112
  "installedPath": ".instar/hooks/instar/claim-intercept.js",
113
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
113
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
114
114
  "since": "2025-01-01"
115
115
  },
116
116
  "hook:claim-intercept-response": {
@@ -119,7 +119,7 @@
119
119
  "domain": "coherence",
120
120
  "sourcePath": "src/core/PostUpdateMigrator.ts",
121
121
  "installedPath": ".instar/hooks/instar/claim-intercept-response.js",
122
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
122
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
123
123
  "since": "2025-01-01"
124
124
  },
125
125
  "hook:stop-gate-router": {
@@ -128,7 +128,7 @@
128
128
  "domain": "safety",
129
129
  "sourcePath": "src/core/PostUpdateMigrator.ts",
130
130
  "installedPath": ".instar/hooks/instar/stop-gate-router.js",
131
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
131
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
132
132
  "since": "2025-01-01"
133
133
  },
134
134
  "hook:auto-approve-permissions": {
@@ -137,7 +137,7 @@
137
137
  "domain": "safety",
138
138
  "sourcePath": "src/core/PostUpdateMigrator.ts",
139
139
  "installedPath": ".instar/hooks/instar/auto-approve-permissions.js",
140
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
140
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
141
141
  "since": "2025-01-01"
142
142
  },
143
143
  "job:health-check": {
@@ -1489,7 +1489,7 @@
1489
1489
  "type": "subsystem",
1490
1490
  "domain": "updates",
1491
1491
  "sourcePath": "src/core/PostUpdateMigrator.ts",
1492
- "contentHash": "de0ac7e9acd815a17f3adf06b1154fcb0fd4a265f0e51e38509f811902e43c1e",
1492
+ "contentHash": "002d9267e321809eb996c0e30bd35d7eeb67eb3e11b09dd8cfbf66e9bd215b49",
1493
1493
  "since": "2025-01-01"
1494
1494
  },
1495
1495
  "subsystem:scheduler": {
@@ -1521,7 +1521,7 @@
1521
1521
  "type": "subsystem",
1522
1522
  "domain": "communication",
1523
1523
  "sourcePath": "src/lifeline/TelegramLifeline.ts",
1524
- "contentHash": "6f5b9a817019b735b9afe3fded858ce713c8bc770b1d3bf018b65905eef25378",
1524
+ "contentHash": "4a2f251ab4d091cf62d9826a1738729838775254ff00d6c743787193ca48dd8b",
1525
1525
  "since": "2025-01-01"
1526
1526
  },
1527
1527
  "subsystem:orphan-process-reaper": {
@@ -443,6 +443,12 @@ This routes feedback to the Instar maintainers automatically. Valid types: \`bug
443
443
 
444
444
  **Use private views for sensitive content. Use Telegraph for public content.**
445
445
 
446
+ **Agent Updates topic (self-broadcasts about ships, restarts, updates)** — When narrating a ship, an update I just applied, or a restart I just completed (e.g. "Just shipped X", "Back up and running on vN", "Bounced cleanly after the update"), route the message through the post-update channel so it lands in the dedicated Agent Updates topic — NOT the active session topic the user happened to be chatting in.
447
+ - Post: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/telegram/post-update -H 'Content-Type: application/json' -d '{"text":"Your update narration here"}'\`
448
+ - The endpoint resolves the Updates topic from state server-side; you cannot specify a topic and you should not try to.
449
+ - If Updates is not configured, the endpoint returns 400 — do NOT fall back to sending in the active topic. Update-class messages belong in Updates or they don't go out at all.
450
+ - **When to use** (PROACTIVE — this is the trigger): the moment I am about to author a conversational message whose subject is *me* shipping, updating, or restarting — including post-restart "I'm back" confirmations — I use this endpoint. Authoring such a message via the standard Telegram reply path puts release chatter into whatever conversation the user was last in, which is the bug this routing closes.
451
+
446
452
  **Secret Drop** — Securely collect secrets (API keys, passwords, tokens) from users without exposing them in chat history.
447
453
  - Request a secret: \`curl -X POST -H "Authorization: Bearer $AUTH" http://localhost:${port}/secrets/request -H 'Content-Type: application/json' -d '{"label":"OpenAI API Key","description":"Needed for GPT integration","topicId":TOPIC_ID}'\`
448
454
  - The response includes a one-time URL (\`localUrl\` and \`tunnelUrl\`). Send this link to the user.
@@ -0,0 +1,28 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ UX refinement of the Process Health dashboard tab shipped in v1.3.27. Eight rounds of user-driven copy + structure iteration landed on the design that became the **Dashboard Standard** — the bar all future dashboard features now start from. Pure dashboard-only change (`dashboard/process-health.js` + `dashboard/index.html` + tests); no `src/` / `scripts/` / `.husky/` / `skills/` changes.
8
+
9
+ What the page looks like now: a one-sentence intro grounds the subject so "it" later in the page has a referent; each section title carries a one-line subtitle that distinguishes it from the others (with explicit cross-references — "When the same kind keeps repeating, it shows up as a pattern above"); each captured problem and pattern card is a `<details>` element with a status color dot on the left (amber/blue/green/gray — never alarm reds) and a chevron on the right; the expanded body is a labeled fact-sheet using a fixed vocabulary (Status / Where / Times seen / First noticed / Cause) used identically across both lists. All action-implying language ("Suggested next step", "verify before acting", "Fix worked") is gone — the page informs, it doesn't direct. Internal codenames (`capture-only`, `failure-learning-loop`, `config-parse`) never reach the DOM; they pass through renderer-owned plain-English maps.
10
+
11
+ The reference implementation now backs a durable agent memory (`feedback_dashboard_copy_eli16.md`) that codifies the seven rules + eight default substitutions + four status-color tokens so future dashboard work starts from this bar.
12
+
13
+ ## What to Tell Your User
14
+
15
+ - The Process Health tab on your dashboard reads a lot more clearly now: a calm intro tells you what the page is showing in one sentence, every problem and pattern collapses to one plain line with a small color dot (amber = still being looked into, blue = cause known, green = worked out, gray = closed), and tapping any row opens up the same set of labeled details — Status, Where, Times seen, First noticed, Cause — every time. The bar this set for "what a calm, informative dashboard reads like" is now the standard for everything I build next.
16
+
17
+ ## Summary of New Capabilities
18
+
19
+ | Capability | How to Use |
20
+ |-----------|-----------|
21
+ | Process Health tab — ELI16 + structure pass | Open the Process Health tab in your dashboard (no action needed; it’s just clearer now) |
22
+ | Dashboard Standard (durable, applies to future dashboard work) | Reference: `feedback_dashboard_copy_eli16.md` (in agent memory) — 7 rules + 8 substitutions + 4 status-color tokens |
23
+
24
+ ## Evidence
25
+
26
+ - 46 tests green: 30 unit + 12 integration + 4 e2e — includes structural assertions for the unified label order, status-dot CSS classes, and that the dropped framing line is genuinely absent.
27
+ - Safety contract unchanged: XSS negative fixture still fires zero live elements + no canary; `detail.full` redaction is verified end-to-end.
28
+ - Show-don't-tell iteration: eight rounds, each rendered to a real browser and screenshotted for user thumbs-up before committing — no merge-and-iterate churn. The harness pattern is captured in the standard.
@@ -0,0 +1,46 @@
1
+ # Instar Upgrade Guide — NEXT
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Update-class messages now consistently land in the dedicated **Agent Updates** topic instead of leaking into random conversations. Three separate emitters were each picking a topic differently and two picked the wrong one:
8
+
9
+ 1. The lifeline's HTTP-426 version-skew alert ("Heads up: my server auto-updated to vN but my lifeline is still on vM…") was being sent to whichever topic the user happened to be typing in when the forward came back. Now it resolves `agent-updates-topic` from server state and routes there, falling back to the Lifeline topic if Updates is unset — never the inbound topic.
10
+ 2. The `ForegroundRestartWatcher` "Applying update to vN — restarting now" heads-up was routing through the central `notify()` helper without an explicit topic, which silently defaulted to the **Attention** topic. The caller now reads `agent-updates-topic` and passes it explicitly, falling through to the prior Attention default only when Updates is unconfigured.
11
+ 3. Agent-authored ship/restart narration ("Quick heads-up: shipped X", "Back up and running on vN") had no template guidance steering it through the post-update channel — it landed in whatever topic the session was bound to. A new CLAUDE.md section + idempotent migration teaches every existing agent to route those self-broadcasts through `POST /telegram/post-update`.
12
+
13
+ ## What to Tell Your User
14
+
15
+ - My update notifications, restart heads-ups, and post-restart "I'm back" messages will now show up in the Agent Updates topic where they belong, instead of leaking into whatever conversation you happened to be in when an update fired. If you don't see them in random topics any more — that's the fix working.
16
+
17
+ ## Summary of New Capabilities
18
+
19
+ | Capability | How to Use |
20
+ |-----------|-----------|
21
+ | Lifeline version-skew alert resolves Updates topic | Automatic — no agent action required. The lifeline reads `agent-updates-topic` state on every 426 episode and routes the alert there; falls back to the Lifeline topic if Updates is unset. |
22
+ | `ForegroundRestartWatcher` "applying update" routes to Updates | Automatic — no agent action required. The pre-restart heads-up now consults `agent-updates-topic` and falls through to the prior Attention default only when unset. |
23
+ | Agent self-broadcast guidance (CLAUDE.md template + migration) | Existing agents pick up the new section via `PostUpdateMigrator.migrateClaudeMd()` on next update. New agents get it via `init`. Trigger: any conversational message whose subject is "I shipped / I updated / I restarted" → `curl -X POST .../telegram/post-update` instead of authoring in the active topic. |
24
+
25
+ ## Evidence
26
+
27
+ - Bug report: Justin, 2026-05-27 (topic 14668), with screenshot of two update-narration messages landing in a Case Study topic instead of the Agent Updates topic.
28
+ - Diagnosis: three independent emitter paths each picking a topic differently — two wired wrong.
29
+ - Spec: `docs/specs/UPDATE-MESSAGE-TOPIC-ROUTING-SPEC.md` (Fix 1 lifeline / Fix 2 watcher / Fix 3 template + migration).
30
+ - ELI16 summary: `docs/specs/UPDATE-MESSAGE-TOPIC-ROUTING-ELI16.md`.
31
+ - Tests added (3 files, 20 new tests, all green):
32
+ - `tests/unit/lifeline/version-skew-alert-routing.test.ts` — source-level assertions that `handleVersionSkew` resolves Updates via the new `resolveUpdatesAlertTopic()` helper, never the inbound topic; preserves 24h dedupe; drops cleanly when both Updates and Lifeline topics are unset.
33
+ - `tests/unit/foreground-restart-watcher-notify-routing.test.ts` — source-level assertions that the `onRestartDetected` callback reads `agent-updates-topic` and passes it explicitly to `notify()`; uses `|| undefined` so the unset case falls through to the prior central-notify default.
34
+ - `tests/unit/PostUpdateMigrator-updateTopicSelfBroadcast.test.ts` — full migration test: idempotency on second run, preserves existing CLAUDE.md content, graceful skip when CLAUDE.md is missing, parity with the source template.
35
+ - Smoke suite: 2941/2941 passed.
36
+ - Migration parity: the two code fixes ride the normal dist refresh on update; the CLAUDE.md template change has a dedicated migration in `PostUpdateMigrator` so existing agents pick it up, not just newly-initialized ones.
37
+
38
+ ## Risk + Rollback
39
+
40
+ - Risk: **low**. Each fix is a pure routing change with a documented fallback. No contract change, no schema migration, no rolling restart needed beyond the standard post-update flow.
41
+ - Rollback: revert the PR. The lifeline 426 path returns to sending the alert to the inbound topic; the foreground watcher path returns to the central-notify Attention default; the CLAUDE.md section remains in already-migrated agents but does no harm (it's awareness, not enforcement).
42
+
43
+ ## Follow-Ups (tracked, not in this PR)
44
+
45
+ - Structural enforcement of Fix 3 via a PreToolUse hook that detects agent-authored ship/update narration and redirects to `/telegram/post-update` — the Structure-over-Willpower version of the template guidance.
46
+ - Audit of remaining `notify('IMMEDIATE', 'system', …)` callsites in `commands/server.ts` for any other update-class messages that should route to Updates rather than Attention.
@@ -0,0 +1,49 @@
1
+ # Side-Effects Review — Process Health tab ELI16 + structure pass
2
+
3
+ **Version / slug:** `process-health-tab-eli16-pass`
4
+ **Date:** 2026-05-27
5
+ **Author:** echo
6
+ **Spec:** `docs/specs/PROCESS-HEALTH-DASHBOARD-TAB-SPEC.md` (v4, the original feature spec; this PR is a UX-refinement follow-up that does NOT change the spec's behavioral surface)
7
+
8
+ ## Summary of the change
9
+
10
+ Eight rounds of user-driven copy + UX iteration on the Process Health dashboard tab (originally shipped in v1.3.27 via PR #435). Pure dashboard-only refinement — no `src/` / `scripts/` / `.husky/` / `skills/` changes — so this PR is outside the instar-dev gate's in-scope set. The reference implementation now backs a durable agent memory (`feedback_dashboard_copy_eli16.md`) that codifies the **Dashboard Standard** for future dashboard features.
11
+
12
+ **Files changed (UI):**
13
+ - `dashboard/process-health.js` (renderers): rewritten `CATEGORY_WORDS`, `ATTRIBUTION_LABELS`, `STAGES`, `INSIGHT_STATUS_WORDS`; new `TYPE_WORDS`, `STATUS_WORDS`, `CAUSE_CONFIDENCE_WORDS`, `statusDotClass`, `statusDot`, `labeledRow`. Restructured `renderCaptured` and `renderPatterns` around the fixed label vocabulary + `<details>` expandability + status color dots. `renderMaturation` reshaped per-stage as expandable `<details>` with plain-English descriptions. Dropped the redundant per-card framing line in v7.
14
+ - `dashboard/index.html`: added page-intro paragraph + per-section subtitles that distinguish each section and cross-reference adjacent ones; new CSS for `.ph-intro`, `.ph-h-sub`, `.ph-item`, `.ph-item-summary`, `.ph-item-text`, `.ph-item-body`, `.ph-item-row`, `.ph-label`, `.ph-value`, `.ph-status-dot` (+ 5 status-color variants), `.ph-stage-summary`, `.ph-stage-body`; chevron disclosure indicator on every `<details>` (opacity 0.8).
15
+
16
+ **Files changed (tests):**
17
+ - `tests/unit/process-health-render.test.ts`: assertions rewritten for new label vocabulary + new status copy + new framing absence + structural assertions on `<details>` + status-dot CSS classes (3 new structural tests added).
18
+ - `tests/integration/process-health-tab.test.ts`: assertions updated for new copy; new framing-absence check.
19
+ - `tests/e2e/process-health-tab-lifecycle.test.ts`: assertions updated for new copy.
20
+
21
+ **Files changed (release):**
22
+ - `upgrades/NEXT.md` (NEW for this PR, `bump: patch`).
23
+
24
+ ## Decision-point inventory
25
+
26
+ - **Pure UX refinement vs. functional change?** Pure UX. No new endpoints, no new data fields, no new auth surfaces, no behavioral changes to the polling controller, no changes to the route layer, no changes to migration parity. Only the rendered text + DOM structure changes.
27
+ - **Drop the recommendation field entirely vs. keep + relabel?** Dropped. Justin explicitly directed "avoid language that implies user needs to act unless ABSOLUTELY essential". The recommendation field is upstream prose that is action-implying by content; relabeling chrome around it doesn't change that. Actionable insight delivery is the deferred §10 surface anyway; v1 of the tab is the calm informational surface.
28
+ - **Drop the per-card framing line vs. keep + rephrase?** Dropped in v7. Once "verify before acting" was rephrased to "Same kind of problem has come up more than once" in v5, it became the third echo of the section title + section subtitle. The no-action-authority signal that the framing was originally carrying is now structural (the rendered card has nothing actionable on it), not chrome.
29
+ - **Add status color dots vs. status text only?** Dots. Lets the user scan the collapsed list and read state at a glance without expanding each item. Colors are calm (amber/blue/green/gray) — never alarm reds, per the existing visual rules.
30
+
31
+ ## Side-effects analysis
32
+
33
+ - **Behavioral:** None. The polling controller, route layer, and migration paths are unchanged. Only the rendered DOM differs.
34
+ - **Architectural:** None. Same file structure; the renderer module is the same self-contained ESM as before. No new build step, no new runtime dependency.
35
+ - **Security:** The safety contract (`sanitizeForDisplay`, textContent-only DOM writes, element ban, safeUrl) is unchanged. New label spans (`.ph-label`, `.ph-value`) use textContent only. The XSS negative fixture continues to fire zero live elements + no canary. The `detail.full` redaction is unchanged.
36
+ - **Migration parity:** Not applicable — no agent-installed-file changes (`templates.ts` / `PostUpdateMigrator` / shadow markers untouched).
37
+ - **Performance:** Marginal increase in DOM nodes per item (each captured item now has 4–5 `<div>`s of body content instead of 0–4 flat children). Diff-aware rendering still works (signature mechanism is structure-agnostic). No new fetches.
38
+ - **Reversibility:** Fully reversible — revert the commit and the previous render returns.
39
+
40
+ ## Standard captured (the durable artifact this PR exists to back)
41
+
42
+ The 8-round iteration converged on a design that's now codified as the **Dashboard Standard** in `feedback_dashboard_copy_eli16.md` (agent memory): 7 rules (ELI16 copy + codename maps + grounding intro + self-contained section titles with subtitles + expandable items + fixed label vocabulary + no action-implying language), 8 default substitutions, 4 calm status-color tokens, and the show-don't-tell iteration pattern. The Process Health tab is now the reference implementation.
43
+
44
+ ## Evidence pointers
45
+
46
+ - All 46 tests green: 30 unit + 12 integration + 4 e2e — includes structural assertions for the unified label order, status-dot CSS classes, and that the dropped framing line is genuinely absent.
47
+ - Safety verified end-to-end: XSS negative fixture still fires zero live elements + no canary; `detail.full` redaction unchanged.
48
+ - Typecheck: `tsc --noEmit` clean.
49
+ - Live-rendered both views (collapsed + expanded) to Chrome headless across 8 iterations and sent screenshots to the user for thumbs-up before each commit. Justin approved v8 with "this is good enough, let's go with it; save this as the standard for future dashboard features".