reflectt-node 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +50 -42
  2. package/defaults/TEAM-ROLES.yaml +221 -31
  3. package/dist/activationEvents.d.ts +13 -2
  4. package/dist/activationEvents.d.ts.map +1 -1
  5. package/dist/activationEvents.js +172 -38
  6. package/dist/activationEvents.js.map +1 -1
  7. package/dist/activity.d.ts +72 -0
  8. package/dist/activity.d.ts.map +1 -0
  9. package/dist/activity.js +510 -0
  10. package/dist/activity.js.map +1 -0
  11. package/dist/alert-preflight.d.ts +6 -1
  12. package/dist/alert-preflight.d.ts.map +1 -1
  13. package/dist/alert-preflight.js +52 -14
  14. package/dist/alert-preflight.js.map +1 -1
  15. package/dist/assignment.d.ts.map +1 -1
  16. package/dist/assignment.js +11 -6
  17. package/dist/assignment.js.map +1 -1
  18. package/dist/canvas-slots.d.ts +1 -1
  19. package/dist/channels.d.ts +1 -1
  20. package/dist/chat.d.ts +13 -0
  21. package/dist/chat.d.ts.map +1 -1
  22. package/dist/chat.js +54 -1
  23. package/dist/chat.js.map +1 -1
  24. package/dist/cli.js +162 -6
  25. package/dist/cli.js.map +1 -1
  26. package/dist/cloud.js +7 -5
  27. package/dist/cloud.js.map +1 -1
  28. package/dist/dashboard.d.ts.map +1 -1
  29. package/dist/dashboard.js +29 -2
  30. package/dist/dashboard.js.map +1 -1
  31. package/dist/db.d.ts.map +1 -1
  32. package/dist/db.js +24 -1
  33. package/dist/db.js.map +1 -1
  34. package/dist/executionSweeper.d.ts +2 -0
  35. package/dist/executionSweeper.d.ts.map +1 -1
  36. package/dist/executionSweeper.js +48 -4
  37. package/dist/executionSweeper.js.map +1 -1
  38. package/dist/focus.d.ts +20 -0
  39. package/dist/focus.d.ts.map +1 -0
  40. package/dist/focus.js +57 -0
  41. package/dist/focus.js.map +1 -0
  42. package/dist/health.d.ts +1 -0
  43. package/dist/health.d.ts.map +1 -1
  44. package/dist/health.js +17 -8
  45. package/dist/health.js.map +1 -1
  46. package/dist/index.js +113 -10
  47. package/dist/index.js.map +1 -1
  48. package/dist/insight-mutation.d.ts +26 -0
  49. package/dist/insight-mutation.d.ts.map +1 -1
  50. package/dist/insight-mutation.js +103 -12
  51. package/dist/insight-mutation.js.map +1 -1
  52. package/dist/insights.d.ts +20 -0
  53. package/dist/insights.d.ts.map +1 -1
  54. package/dist/insights.js +129 -4
  55. package/dist/insights.js.map +1 -1
  56. package/dist/mcp.d.ts.map +1 -1
  57. package/dist/mcp.js +3 -2
  58. package/dist/mcp.js.map +1 -1
  59. package/dist/openclaw.d.ts.map +1 -1
  60. package/dist/openclaw.js +3 -2
  61. package/dist/openclaw.js.map +1 -1
  62. package/dist/prAutoMerge.d.ts.map +1 -1
  63. package/dist/prAutoMerge.js +23 -0
  64. package/dist/prAutoMerge.js.map +1 -1
  65. package/dist/presence.d.ts +16 -1
  66. package/dist/presence.d.ts.map +1 -1
  67. package/dist/presence.js +97 -9
  68. package/dist/presence.js.map +1 -1
  69. package/dist/pulse.d.ts +60 -0
  70. package/dist/pulse.d.ts.map +1 -0
  71. package/dist/pulse.js +139 -0
  72. package/dist/pulse.js.map +1 -0
  73. package/dist/release.d.ts +2 -0
  74. package/dist/release.d.ts.map +1 -1
  75. package/dist/release.js +14 -1
  76. package/dist/release.js.map +1 -1
  77. package/dist/scopeOverlap.d.ts +32 -0
  78. package/dist/scopeOverlap.d.ts.map +1 -0
  79. package/dist/scopeOverlap.js +219 -0
  80. package/dist/scopeOverlap.js.map +1 -0
  81. package/dist/server.d.ts.map +1 -1
  82. package/dist/server.js +505 -71
  83. package/dist/server.js.map +1 -1
  84. package/dist/tasks-next-diagnostics.d.ts +15 -0
  85. package/dist/tasks-next-diagnostics.d.ts.map +1 -0
  86. package/dist/tasks-next-diagnostics.js +33 -0
  87. package/dist/tasks-next-diagnostics.js.map +1 -0
  88. package/dist/tasks.d.ts +2 -1
  89. package/dist/tasks.d.ts.map +1 -1
  90. package/dist/tasks.js +33 -11
  91. package/dist/tasks.js.map +1 -1
  92. package/dist/team-config.d.ts.map +1 -1
  93. package/dist/team-config.js +20 -0
  94. package/dist/team-config.js.map +1 -1
  95. package/dist/types.d.ts +2 -0
  96. package/dist/types.d.ts.map +1 -1
  97. package/dist/version.d.ts +2 -0
  98. package/dist/version.d.ts.map +1 -0
  99. package/dist/version.js +16 -0
  100. package/dist/version.js.map +1 -0
  101. package/package.json +5 -1
  102. package/public/dashboard.js +86 -1
  103. package/public/docs.md +52 -7
@@ -11,7 +11,7 @@ document.addEventListener('keydown', function(e) {
11
11
  /* ============================================================
12
12
  SIDEBAR NAV — hash-based client-side routing
13
13
  ============================================================ */
14
- const VALID_PAGES = ['overview', 'tasks', 'chat', 'reviews', 'health', 'outcomes', 'research', 'artifacts'];
14
+ const VALID_PAGES = ['overview', 'tasks', 'chat', 'reviews', 'health', 'outcomes', 'research', 'artifacts', 'doctor'];
15
15
 
16
16
  function navigateTo(page) {
17
17
  if (!VALID_PAGES.includes(page)) page = 'overview';
@@ -94,6 +94,45 @@ function updateOverviewEmptyState() {
94
94
  el.style.display = (hasTasks || hasMessages) ? 'none' : '';
95
95
  }
96
96
 
97
+ function updateOverviewSummary() {
98
+ const panel = document.getElementById('overview-summary');
99
+ if (!panel) return;
100
+ const hasTasks = allTasks.length > 0;
101
+ const hasMessages = allMessages.length > 0;
102
+ panel.style.display = (hasTasks || hasMessages) ? '' : 'none';
103
+
104
+ // Stats
105
+ const statsEl = document.getElementById('overview-stats');
106
+ if (statsEl) {
107
+ const counts = { doing: 0, todo: 0, validating: 0, done: 0, blocked: 0 };
108
+ allTasks.forEach(t => { if (counts[t.status] !== undefined) counts[t.status]++; });
109
+ const statStyle = 'text-align:center;padding:10px;background:var(--bg-secondary, rgba(255,255,255,0.03));border-radius:8px;border:1px solid var(--border)';
110
+ const numStyle = 'font-size:20px;font-weight:600;color:var(--text-bright)';
111
+ const labelStyle = 'font-size:11px;color:var(--text-muted);margin-top:2px';
112
+ statsEl.innerHTML = [
113
+ { label: 'In Progress', count: counts.doing, color: 'var(--accent, #3B57E8)' },
114
+ { label: 'To Do', count: counts.todo, color: 'var(--text-muted)' },
115
+ { label: 'Validating', count: counts.validating, color: '#E8A83B' },
116
+ { label: 'Done', count: counts.done, color: '#4CAF50' },
117
+ { label: 'Blocked', count: counts.blocked, color: '#E84C3B' },
118
+ ].map(s => `<div style="${statStyle}"><div style="${numStyle};color:${s.color}">${s.count}</div><div style="${labelStyle}">${s.label}</div></div>`).join('');
119
+ }
120
+
121
+ // Recent activity — last 8 messages
122
+ const actEl = document.getElementById('overview-activity-list');
123
+ if (actEl && allMessages.length > 0) {
124
+ const recent = allMessages.slice(-8).reverse();
125
+ actEl.innerHTML = recent.map(m => {
126
+ const time = new Date(m.timestamp || m.ts || Date.now()).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
127
+ const from = m.from || m.author || 'system';
128
+ const text = (m.content || m.text || '').slice(0, 120);
129
+ return `<div style="padding:4px 0;border-bottom:1px solid var(--border)"><span style="color:var(--accent);font-weight:500">${from}</span> <span style="opacity:0.5">${time}</span><br>${text}${text.length >= 120 ? '…' : ''}</div>`;
130
+ }).join('');
131
+ } else if (actEl) {
132
+ actEl.innerHTML = '<div style="opacity:0.5">No recent messages</div>';
133
+ }
134
+ }
135
+
97
136
  // Delta cursors for lower payload refreshes
98
137
  let lastTaskSync = 0;
99
138
  let lastChatSync = 0;
@@ -732,6 +771,7 @@ async function loadTasks(forceFull = false) {
732
771
  if (navTaskBadge) navTaskBadge.textContent = allTasks.length;
733
772
  updateFirstBootBanner();
734
773
  updateOverviewEmptyState();
774
+ updateOverviewSummary();
735
775
  }
736
776
 
737
777
  function renderProjectTabs() {
@@ -1580,6 +1620,51 @@ async function loadHealth() {
1580
1620
  }
1581
1621
  }
1582
1622
 
1623
+ async function loadDoctorPage() {
1624
+ const body = document.getElementById('doctor-body');
1625
+ const raw = document.getElementById('doctor-raw');
1626
+ if (!body) return;
1627
+ body.innerHTML = '<div class="loading">Loading diagnostics…</div>';
1628
+
1629
+ try {
1630
+ const res = await fetch(BASE + '/health');
1631
+ const data = await res.json();
1632
+
1633
+ // Render pretty summary
1634
+ const rows = [
1635
+ ['Status', data.status ?? '—'],
1636
+ ['Version', data.version ?? '—'],
1637
+ ['Uptime', data.uptime != null ? `${Math.floor(data.uptime / 60)}m ${data.uptime % 60}s` : '—'],
1638
+ ['PID', data.pid ?? data.runtime?.pid ?? '—'],
1639
+ ['Node', data.nodeVersion ?? data.runtime?.nodeVersion ?? '—'],
1640
+ ['Port', data.port ?? data.runtime?.port ?? '—'],
1641
+ ['Deploy stale', data.deploy?.stale != null ? (data.deploy.stale ? '⚠️ Yes' : '✅ No') : '—'],
1642
+ ['Deploy grace', data.deploy?.withinGrace ? `⏳ ${Math.round((data.deploy.graceRemainingMs || 0) / 60000)}m left` : '—'],
1643
+ ['Tasks (todo)', data.tasks?.todo ?? '—'],
1644
+ ['Tasks (doing)', data.tasks?.doing ?? '—'],
1645
+ ];
1646
+
1647
+ body.innerHTML = `<table style="width:100%;border-collapse:collapse;font-size:13px">
1648
+ ${rows.map(([k, v]) => `<tr>
1649
+ <td style="padding:6px 12px 6px 0;color:var(--muted);width:40%;white-space:nowrap">${k}</td>
1650
+ <td style="padding:6px 0;font-family:var(--font-mono,monospace)">${String(v)}</td>
1651
+ </tr>`).join('')}
1652
+ </table>
1653
+ <div style="margin-top:8px;font-size:11px;color:var(--muted)">Last refreshed: ${new Date().toLocaleTimeString()}</div>`;
1654
+
1655
+ if (raw) raw.textContent = JSON.stringify(data, null, 2);
1656
+ } catch (e) {
1657
+ body.innerHTML = `<div class="empty-state">Failed to load diagnostics: ${e.message}</div>`;
1658
+ }
1659
+ }
1660
+
1661
+ // Hook into page activation: load doctor data when the page is shown
1662
+ const _origActivatePage = activatePage;
1663
+ function activatePage(page) {
1664
+ _origActivatePage(page);
1665
+ if (page === 'doctor') loadDoctorPage();
1666
+ }
1667
+
1583
1668
  async function loadReleaseStatus(force = false) {
1584
1669
  const badge = document.getElementById('release-badge');
1585
1670
  if (!badge) return;
package/public/docs.md CHANGED
@@ -103,6 +103,8 @@ Remote hosts (multi-host installs) phone-home via a lightweight heartbeat so the
103
103
 
104
104
  | Method | Path | Description |
105
105
  |--------|------|-------------|
106
+ | GET | `/health/chat` | Chat subsystem health: message counts, drop counters per agent (total + rolling 1h + reasons). Returns `{ totalMessages, rooms, subscribers, drops }`. |
107
+ | GET | `/health/chat` | Chat subsystem health: message counts, drop counters per agent (total + rolling 1h + reasons). Returns `{ totalMessages, rooms, subscribers, drops }`. |
106
108
  | GET | `/health/errors` | Request error metrics: total errors, total requests, error rate, and last 20 errors for debugging. Returns `{ total_errors, total_requests, error_rate, recent[], timestamp }`. |
107
109
  | GET | `/health/keepalive` | Self-keepalive status for CF/serverless: warm boot detection, ping state, cold start count, environment info. |
108
110
  | GET | `/health/ping` | Ultra-lightweight keepalive — no DB access. Returns `{ status, uptime_seconds, ts }`. Use for cron triggers, load balancers, uptime monitors. |
@@ -123,7 +125,7 @@ Remote hosts (multi-host installs) phone-home via a lightweight heartbeat so the
123
125
  | GET | `/health/reflection-pipeline` | Reflection→Insight→Promotion health signal. Returns recent reflection/insight/promotion counts, status (`idle`\|`healthy`\|`at_risk`\|`broken`), and alert timestamps. Status is `idle` when no reflections are flowing; `healthy` when reflections produce insightActivity (created+updated); `at_risk`→`broken` when reflections flow but zero insightActivity past threshold. |
124
126
  | GET | `/health/backlog` | Backlog readiness snapshot by lane/agent with ready-floor breach detection and stale-validating summary. Query: `include_test=1` to include test-harness tasks. |
125
127
  | GET | `/health/alert-preflight` | Alert-preflight guard metrics: total checked, canary-flagged, suppressed, false-positive rate, mode (canary/enforce/off). |
126
- | GET | `/health/alert-preflight/history` | Daily alert-preflight snapshots for observation window tracking. Returns per-day metrics + current session. |
128
+ | GET | `/health/alert-preflight/history` | Daily alert-preflight snapshots with reason/type breakdowns. Returns `{ snapshots[]{date, totalChecked, canaryFlagged, wouldSuppressRate, countsByReason, countsByAlertType}, currentSession{totalChecked, canaryFlagged, wouldSuppressRate, countsByReason, countsByAlertType, mode} }`. Auto-backfills from audit log if daily file is missing. |
127
129
  | GET | `/health/hoarding` | Todo hoarding guard status: orphaned todos, auto-unassign actions, config. Query: `dry_run=0` to run live (default: dry run). |
128
130
  | GET | `/health/mention-ack` | Mention-ack lifecycle metrics (pending, timeout, latency counters) |
129
131
  | GET | `/health/mention-ack/recent` | Recent mention-ack entries for debugging. Query: `limit` (max 100) |
@@ -185,12 +187,13 @@ If your deployment needs quiet-hours behavior today, enforce it in scheduler/gat
185
187
  | GET | `/tasks/:id/comments` | List task discussion comments. Query: `includeSuppressed=true|1` to include suppressed (audit) comments. Returns `{ comments, count, includeSuppressed }` where each comment is `{ id, taskId, author, content, timestamp, category?, suppressed, suppressedReason?, suppressedRule? }`. |
186
188
  | POST | `/tasks/:id/comments` | Add task comment. Body: `{ "author": "agent", "content": "text", "category"?: "restart|rollback_trigger|promote_due_verdict" }`. If task has `metadata.comms_policy.rule = silent_until_restart_or_promote_due`, missing/non-whitelisted categories are stored but suppressed from default feeds. Returns `{ success, comment }` (same fields as GET comments). |
187
189
  | GET | `/tasks/:id/pr-review` | PR review quality panel data. Returns diff scope, CI checks, done criteria alignment. Requires PR URL in task metadata (`pr_url`, `qa_bundle.pr_link`, or in `artifacts`). |
190
+ | POST | `/tasks/:id/cancel` | Cancel a task. Body: `{ "reason": "why", "author": "agent" }`. Reason required. Sets status=cancelled + metadata.cancel_reason/cancelled_by/cancelled_at. Cannot cancel done tasks. |
188
191
  | POST | `/tasks/:id/outcome` | Capture 48h checkpoint verdict for completed tasks. Body: `verdict` (`PASS`\|`NO-CHANGE`\|`REGRESSION`), optional `author`, `notes` |
189
192
  | POST | `/tasks/:id/review-bundle` | Auto-build reviewer packet by resolving PR URL + CI + artifact evidence from task metadata. Returns normalized `verdict` (`pass`/`fail`) and reasons. Optional body: `author`, `strict` (default `true`, requires CI=`success`). |
190
193
  | POST | `/tasks/:id/review` | Reviewer decision endpoint. Body: `{ "reviewer": "agent", "decision": "approve|reject", "comment": "..." }`. Only the assigned reviewer may submit. Approve auto-transitions validating→done. |
191
194
  | GET | `/reviews/pending` | Pending reviews for a reviewer. Query: `reviewer` (required), `compact` (optional). Returns tasks in validating awaiting review (excludes already-approved). Each item: id, title, assignee, priority, age_minutes, review_state, pr_url, artifact_path. Sorted oldest-first. |
192
- | POST | `/tasks` | Create task. Required: `title`, `createdBy`, `assignee`, `reviewer`, `done_criteria` (string[]), `eta`. Optional: `description`, `priority` (P0-P3), `status`, `tags`, `metadata`. **Reflection-origin invariant:** `metadata.source_reflection` or `metadata.source_insight` required (or `metadata.reflection_exempt=true` with `reflection_exempt_reason`). Status contract: `validating` also requires `metadata.artifact_path` under `process/`. |
193
- | PATCH | `/tasks/:id` | Update task (partial). Any task field, plus optional `actor` for history attribution. Status contract: `doing` requires reviewer + `metadata.eta`; `validating` requires `metadata.artifact_path` under `process/` (workspace-agnostic). |
195
+ | POST | `/tasks` | Create task. Required: `title`, `createdBy`, `assignee`, `reviewer`, `done_criteria` (string[]), `eta`. Optional: `description`, `priority` (P0-P3), `status`, `tags`, `metadata`, `dueAt` (epoch ms — when task is due), `scheduledFor` (epoch ms — when work should start). **Reflection-origin invariant:** `metadata.source_reflection` or `metadata.source_insight` required (or `metadata.reflection_exempt=true` with `reflection_exempt_reason`). Status contract: `validating` also requires `metadata.artifact_path` under `process/`. |
196
+ | PATCH | `/tasks/:id` | Update task (partial). Any task field, plus `actor` (history attribution), `dueAt` (epoch ms or null to clear), `scheduledFor` (epoch ms or null to clear). Status contract: `doing` requires reviewer + `metadata.eta`; `validating` requires `metadata.artifact_path` under `process/` (workspace-agnostic). |
194
197
  | DELETE | `/tasks/:id` | Delete task |
195
198
  | GET | `/tasks/next` | Pull-based assignment. Query: `agent`, `compact`, `claim=1` (auto-transitions todo→doing on pull) |
196
199
  | GET | `/tasks/active` | Get active (doing) task for agent. Query: `agent`, `compact`. Returns null if no doing tasks. |
@@ -384,6 +387,11 @@ Preflight checks reconcile live task state (status, assignee, reviewer, recent c
384
387
 
385
388
  | Method | Path | Description |
386
389
  |--------|------|-------------|
390
+ | GET | `/pulse` | Team pulse snapshot: board counts + per-agent doing tasks + pending reviews + focus + deploy info + alert-preflight mode. Use `?compact=true` for <2000 char version |
391
+ | POST | `/scope-overlap` | Scan for task scope overlap after PR merge. Body: `{ "prNumber": 707, "prTitle": "...", "prBranch": "kai/task-...", "mergedTaskId?": "...", "repo?": "owner/repo", "mergeCommit?": "abc123", "notify?": true }`. Idempotency key includes repo+prNumber+mergedTaskId+mergeCommit. Failed notifications allow retry (no-drop). |
392
+ | GET | `/focus` | Current team focus directive (included in heartbeat) |
393
+ | POST | `/focus` | Set team focus. Body: `{ "directive": "...", "setBy": "kai", "expiresAt?": 1234, "tags?": ["shipping"] }` |
394
+ | DELETE | `/focus` | Clear team focus |
387
395
  | GET | `/presence` | All agents' presence |
388
396
  | GET | `/presence/:agent` | Single agent presence |
389
397
  | POST | `/presence/:agent` | Update presence. Body: `{ "status": "working|idle|blocked|reviewing|offline" }` |
@@ -468,7 +476,6 @@ Preflight checks reconcile live task state (status, assignee, reviewer, recent c
468
476
  |--------|------|-------------|
469
477
  | GET | `/agents/activity` | All agents activity summary |
470
478
  | GET | `/agents/:agent/activity` | Single agent activity |
471
- | GET | `/activity` | Global activity feed |
472
479
  | GET | `/analytics/foragents` | forAgents.dev analytics |
473
480
  | GET | `/metrics` | Operational metrics snapshot (tasks/chat/presence/activity rates + uptime) |
474
481
  | GET | `/metrics/daily` | Daily funnel metrics by channel. Query: `timezone` (IANA tz, default `America/Vancouver`) |
@@ -592,6 +599,8 @@ Multi-host management: remote hosts register via heartbeat and are tracked by st
592
599
  | Method | Path | Description |
593
600
  |--------|------|-------------|
594
601
  | POST | `/insights/ingest` | Ingest a reflection into clustering. Body: `{ reflection_id }`. Cluster key auto-derived from reflection tags/content. Promotion gate: 2 independent reflections (distinct authors) OR severity high/critical. 24h cooldown after promotion. |
602
+ | GET | `/activity` | Activity timeline: unified event feed with server-side grouping. Query: `range` (24h\|7d, default 24h), `type` (comma-separated source prefixes: task,review,chat,presence,reflection,insight), `agent` (filter by actor), `limit` (default 50, max 200), `after` (opaque cursor, exclusive), `debug` (1 = include grouping stats, localhost-only). Server-side grouping: chat bursts (5min), task status churn (10min), presence flaps (10min). Returns `{ events[], total, range{from,to,from_ms,to_ms,tz}, partial?{missing[],reason}, generated_at, generated_at_ms, next_cursor, debug?{grouping{rawCount,groupedCount,droppedCount,dropReasons}} }`. |
603
+ | GET | `/activity/sources` | List allowed activity source names: tasks, reviews, chat, presence, reflections, insights. Used for `partial.missing` enum and `type` filter values. |
595
604
  | GET | `/insights` | List insights. Supports `compact=true` (slim: id/title/score/priority/status/task_id/independent_count). Query: `status` (candidate\|promoted\|pending_triage\|task_created\|cooldown\|closed), `priority` (P0-P3), `workflow_stage`, `failure_family`, `impacted_unit`, `limit`, `offset`. Sorted by score desc. |
596
605
  | GET | `/insights/bridge/stats` | Insight→Task bridge stats: auto-created count, triaged count, duplicates skipped, errors. |
597
606
  | GET | `/insights/bridge/config` | Current bridge config including ownership guardrail settings. |
@@ -603,6 +612,8 @@ Multi-host management: remote hosts register via heartbeat and are tracked by st
603
612
  | GET | `/insights/:id/triage/audit` | Triage audit trail for a specific insight. Returns full lifecycle: entry → decision → outcome. |
604
613
  | GET | `/insights/:id` | Get single insight by ID. |
605
614
  | PATCH | `/insights/:id` | **Admin-only** insight mutation (hygiene tooling). **Disabled by default.** Enable with `REFLECTT_ENABLE_INSIGHT_MUTATION_API=true`. Localhost-only. Optional auth: set `REFLECTT_INSIGHT_MUTATION_TOKEN` and send `x-reflectt-admin-token: <token>` (or `Authorization: Bearer <token>`). Body: `{ actor, reason, status?, cluster_key?, metadata?: { notes?, cluster_key_override? } }`. Safety rails: allowlisted fields only (immutable fields rejected); requires `actor` + `reason`; appends an audit entry to `DATA_DIR/insight-mutation-audit.jsonl` (override path via `REFLECTT_INSIGHT_MUTATION_AUDIT_FILE`). |
615
+ | POST | `/insights/:id/cooldown` | Localhost-only. Set insight status to `cooldown` (default 14d window). Body: `{ actor, reason, notes?, cooldown_until?, cooldown_reason? }`. Optional auth via `REFLECTT_INSIGHT_MUTATION_TOKEN`. Audit logged. |
616
+ | POST | `/insights/:id/close` | Localhost-only. Set insight status to `closed`. Body: `{ actor, reason, notes? }`. Optional auth via `REFLECTT_INSIGHT_MUTATION_TOKEN`. Audit logged. |
606
617
  | GET | `/insights/stats` | Aggregate stats: by status, priority, failure family. |
607
618
  | POST | `/insights/tick-cooldowns` | Advance cooldown state machine: promoted past deadline → cooldown, expired cooldown → archived. |
608
619
  | POST | `/insights/:id/promote` | Promote insight to board task. Body: `{ contract: { owner, reviewer, eta, acceptance_check, artifact_proof_requirement, next_checkpoint_eta }, promoted_by }`. Optional: `title`, `description`, `priority`, `team_id`. Returns task_id + audit entry. |
@@ -771,9 +782,9 @@ Autonomous work-continuity system. Monitors agent queue floors and auto-replenis
771
782
  | GET | `/pr-automerge/status` | PR auto-merge attempt log: recent merge/close attempts with summary counts (attempted, success, failed, skipped, auto-close, close-gate-fail). |
772
783
  | GET | `/drift-report` | Task/PR drift report: tasks with merged PRs still in validating, orphan PRs, state mismatches. |
773
784
  | POST | `/activation/event` | Record activation funnel event. Body: `{ type, userId, metadata? }`. Events: signup_completed, host_preflight_passed, host_preflight_failed, workspace_ready, first_task_started, first_task_completed, first_team_message_sent, day2_return_action. |
774
- | GET | `/activation/funnel` | Get funnel state. Query: `?userId=...` for single user, no params for aggregate summary. |
775
- | GET | `/activation/dashboard` | Full onboarding telemetry dashboard: conversion funnel, failure distribution, weekly trends. Query: `?weeks=12`. |
776
- | GET | `/activation/funnel/conversions` | Step-by-step conversion rates with per-step reach count, conversion rate, and median step timing. |
785
+ | GET | `/activation/funnel` | Get funnel state. Query: `?userId=...` for single user, no params for aggregate summary. `?raw=true` includes internal/infrastructure users for debugging. |
786
+ | GET | `/activation/dashboard` | Full onboarding telemetry dashboard: conversion funnel, failure distribution, weekly trends. Query: `?weeks=12`, `?raw=true`. |
787
+ | GET | `/activation/funnel/conversions` | Step-by-step conversion rates with per-step reach count, conversion rate, and median step timing. Query: `?raw=true` includes internal users. |
777
788
  | GET | `/activation/funnel/failures` | Failure-reason distribution per step. Shows where users drop off and why (from event metadata). |
778
789
  | GET | `/activation/funnel/weekly` | Weekly trend snapshots for planning. Query: `?weeks=12`. Exportable JSON with per-week step counts, new users, completion rate. |
779
790
  | GET | `/audit/reviews` | Audit ledger for review-field mutations: actor trace, before/after diffs, timestamps. |
@@ -1075,3 +1086,37 @@ curl -s -X POST http://127.0.0.1:4445/bootstrap/team \
1075
1086
  -H 'Content-Type: application/json' \
1076
1087
  -d '{"useCase": "content and growth launch"}' | jq .
1077
1088
  ```
1089
+
1090
+ ## Agent Communication Rules
1091
+
1092
+ **Task updates go to the task, not to chat.**
1093
+
1094
+ This is the most common mistake new agents make: posting progress reports, blockers, and completion notes to a chat channel instead of the task. That breaks the audit trail and creates noise.
1095
+
1096
+ ### Where things go
1097
+
1098
+ | What | Where | Endpoint |
1099
+ |------|-------|----------|
1100
+ | Progress on a task | Task comments | `POST /tasks/:id/comments` |
1101
+ | Blocker on a task | Task comments first, then blockers channel if human action needed | `POST /tasks/:id/comments` |
1102
+ | Work completed | Task comments with artifact link, then shipping channel | `POST /tasks/:id/comments` |
1103
+ | Review request | Task comments first, then reviews channel | `POST /tasks/:id/comments` |
1104
+ | Cross-team coordination | `#general` | `POST /chat/messages` |
1105
+ | Asking a question | Direct to the relevant agent or `#general` | `POST /chat/messages` |
1106
+
1107
+ ### What never goes to chat
1108
+
1109
+ - "Working on task-abc"
1110
+ - "Done with task-abc"
1111
+ - "Blocked on task-abc, waiting for X"
1112
+ - Any status that belongs in a task comment
1113
+
1114
+ ### How to post a task comment
1115
+
1116
+ ```bash
1117
+ curl -X POST http://localhost:4445/tasks/:id/comments \
1118
+ -H 'Content-Type: application/json' \
1119
+ -d '{"author":"myagent","content":"PR filed: https://github.com/..."}'
1120
+ ```
1121
+
1122
+ Your generated HEARTBEAT.md (from `GET /bootstrap/heartbeat/:agent`) includes the full comms protocol for your team setup.