mister-wolf 2.3.2 → 2.5.0

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 (55) hide show
  1. package/dist/adapters/cli/cli-entry.d.ts.map +1 -1
  2. package/dist/adapters/cli/cli-entry.js +2 -0
  3. package/dist/adapters/cli/cli-entry.js.map +1 -1
  4. package/dist/adapters/cli/commands/analytics.d.ts +7 -2
  5. package/dist/adapters/cli/commands/analytics.d.ts.map +1 -1
  6. package/dist/adapters/cli/commands/analytics.js +83 -24
  7. package/dist/adapters/cli/commands/analytics.js.map +1 -1
  8. package/dist/adapters/cli/commands/dashboard.d.ts +5 -0
  9. package/dist/adapters/cli/commands/dashboard.d.ts.map +1 -1
  10. package/dist/adapters/cli/commands/dashboard.js +41 -19
  11. package/dist/adapters/cli/commands/dashboard.js.map +1 -1
  12. package/dist/adapters/cli/commands/memory-effectiveness.d.ts.map +1 -1
  13. package/dist/adapters/cli/commands/memory-effectiveness.js +3 -3
  14. package/dist/adapters/cli/commands/memory-effectiveness.js.map +1 -1
  15. package/dist/adapters/cli/commands/table-render.d.ts +0 -3
  16. package/dist/adapters/cli/commands/table-render.d.ts.map +1 -1
  17. package/dist/adapters/cli/commands/table-render.js +0 -9
  18. package/dist/adapters/cli/commands/table-render.js.map +1 -1
  19. package/dist/adapters/cli/commands/task-eval.d.ts +3 -0
  20. package/dist/adapters/cli/commands/task-eval.d.ts.map +1 -0
  21. package/dist/adapters/cli/commands/task-eval.js +38 -0
  22. package/dist/adapters/cli/commands/task-eval.js.map +1 -0
  23. package/dist/adapters/fs/session-metrics-log.d.ts +75 -41
  24. package/dist/adapters/fs/session-metrics-log.d.ts.map +1 -1
  25. package/dist/adapters/fs/session-metrics-log.js +90 -9
  26. package/dist/adapters/fs/session-metrics-log.js.map +1 -1
  27. package/dist/adapters/mcp/mcp-schemas.d.ts +2 -1
  28. package/dist/adapters/mcp/mcp-schemas.d.ts.map +1 -1
  29. package/dist/adapters/mcp/mcp-schemas.js +14 -1
  30. package/dist/adapters/mcp/mcp-schemas.js.map +1 -1
  31. package/dist/adapters/mcp/mcp-tools.d.ts.map +1 -1
  32. package/dist/adapters/mcp/mcp-tools.js +7 -4
  33. package/dist/adapters/mcp/mcp-tools.js.map +1 -1
  34. package/dist/app/use-cases/build-analytics.d.ts +78 -9
  35. package/dist/app/use-cases/build-analytics.d.ts.map +1 -1
  36. package/dist/app/use-cases/build-analytics.js +212 -19
  37. package/dist/app/use-cases/build-analytics.js.map +1 -1
  38. package/dist/app/use-cases/build-dashboard.d.ts +5 -0
  39. package/dist/app/use-cases/build-dashboard.d.ts.map +1 -1
  40. package/dist/app/use-cases/build-dashboard.js +2 -1
  41. package/dist/app/use-cases/build-dashboard.js.map +1 -1
  42. package/dist/app/use-cases/effectiveness.d.ts +4 -4
  43. package/dist/app/use-cases/effectiveness.d.ts.map +1 -1
  44. package/dist/app/use-cases/effectiveness.js +7 -7
  45. package/dist/app/use-cases/effectiveness.js.map +1 -1
  46. package/dist/app/use-cases/snapshot-delta.js +3 -3
  47. package/dist/app/use-cases/snapshot-delta.js.map +1 -1
  48. package/dist/app/use-cases/tally-council-votes.d.ts +2 -0
  49. package/dist/app/use-cases/tally-council-votes.d.ts.map +1 -1
  50. package/dist/app/use-cases/tally-council-votes.js +1 -1
  51. package/dist/app/use-cases/tally-council-votes.js.map +1 -1
  52. package/package.json +1 -1
  53. package/templates/base/agents/worker-implementer.md +2 -0
  54. package/templates/base/agents/worker-researcher.md +2 -0
  55. package/templates/base/agents/worker-reviewer.md +2 -0
@@ -1,10 +1,11 @@
1
1
  /**
2
- * M5 (ядро L2): `wolf analytics` — реестры и воронка (Q1–Q4, Q6, Q8, Q10–Q12).
2
+ * M5 (ядро L2): `wolf analytics` — реестры и недельная активность (Q1–Q4, Q6, Q8, Q10–Q12).
3
3
  * Чистая детерминированная агрегация store + signals + event-log + run-log, без LLM.
4
4
  * Дизайн: docs/superpowers/specs/2026-09-03-analytics-metrics-dashboard-design.md §5 M5, §6.2.
5
5
  */
6
6
  import type { MemoryStore } from '../../ports/memory-store.port.js';
7
7
  import type { EventLog } from '../../ports/event-log.port.js';
8
+ import type { RelationLog } from '../../ports/relation-log.port.js';
8
9
  import type { Clock } from '../../ports/clock.port.js';
9
10
  import { type SignalEvent } from '../../adapters/fs/session-metrics-log.js';
10
11
  import type { PricingTable } from '../../domain/pricing.js';
@@ -60,7 +61,7 @@ export interface RuleRankingRow {
60
61
  checked: number | null;
61
62
  silent: boolean;
62
63
  }
63
- export interface FunnelWeek {
64
+ export interface WeeklyActivityWeek {
64
65
  week: string;
65
66
  writes: number;
66
67
  delivers: number;
@@ -80,17 +81,34 @@ export interface OutlierRun {
80
81
  export interface AgentLedgerRow {
81
82
  agent: string;
82
83
  runs: number;
83
- failures: number;
84
- failureRatePct: number | null;
84
+ processFailures: number;
85
+ processFailureRatePct: number | null;
85
86
  weighted: number;
86
87
  avgDurationMs: number | null;
87
88
  costUsd: number | null;
88
89
  toolErrors: number;
89
90
  complaintsBy: number;
90
91
  complaintsAbout: number;
91
- successes: number;
92
+ completedRuns: number;
93
+ accepted: number;
92
94
  holdoutPrevented: number | null;
93
95
  }
96
+ /** D4: accepted-вердикты по строгой session-связке (link ненадёжен до P1). */
97
+ export interface AcceptanceStats {
98
+ accepted: number;
99
+ costPerAcceptedTask: number | null;
100
+ }
101
+ /** D5: coverage — scored-вердикты / run-сигналы (интерим-знаменатель, честный — P1). */
102
+ export interface CoverageStats {
103
+ scored: number;
104
+ runs: number;
105
+ scoredTaskRatePct: number | null;
106
+ }
107
+ /** D7: data-quality сигнального лога (битые строки не роняют контур — только метрика). */
108
+ export interface DataQualityStats {
109
+ validEventRatePct: number | null;
110
+ malformedLines: number;
111
+ }
94
112
  export interface StewardView {
95
113
  mutations: {
96
114
  kind: string;
@@ -124,6 +142,44 @@ export interface ExperimentReadiness {
124
142
  runs: number;
125
143
  }[];
126
144
  }
145
+ export interface CouncilWeekActivity {
146
+ week: string;
147
+ questions: number;
148
+ opinions: number;
149
+ syntheses: number;
150
+ }
151
+ export interface CouncilOpenQuestion {
152
+ id: string;
153
+ title: string;
154
+ daysOpen: number;
155
+ opinions: number;
156
+ votes: Record<string, number>;
157
+ }
158
+ export interface CouncilsView {
159
+ questions: {
160
+ total: number;
161
+ inWindow: number;
162
+ open: number;
163
+ };
164
+ opinions: {
165
+ total: number;
166
+ perQuestionMin: number | null;
167
+ perQuestionAvg: number | null;
168
+ perQuestionMax: number | null;
169
+ };
170
+ participation: {
171
+ agent: string;
172
+ opinions: number;
173
+ }[];
174
+ votes: Record<string, number>;
175
+ synthesis: {
176
+ questionsWithSynthesis: number;
177
+ sharePct: number | null;
178
+ medianHours: number | null;
179
+ };
180
+ weeks: CouncilWeekActivity[];
181
+ openQuestions: CouncilOpenQuestion[];
182
+ }
127
183
  export interface AnalyticsReport {
128
184
  generatedAt: string;
129
185
  thresholds: LifecycleThresholds;
@@ -133,15 +189,20 @@ export interface AnalyticsReport {
133
189
  };
134
190
  tools: ToolLedgerRow[];
135
191
  rules: RuleRankingRow[];
136
- funnel: FunnelWeek[];
192
+ weeklyActivity: WeeklyActivityWeek[];
137
193
  outliers: OutlierRun[];
138
194
  agents: AgentLedgerRow[];
139
195
  steward: StewardView;
140
196
  readiness: ExperimentReadiness;
197
+ councils: CouncilsView;
198
+ acceptance: AcceptanceStats;
199
+ coverage: CoverageStats;
200
+ dataQuality: DataQualityStats;
141
201
  }
142
202
  export interface AnalyticsDeps {
143
203
  store: MemoryStore;
144
204
  log: EventLog;
205
+ relations: RelationLog;
145
206
  clock: Clock;
146
207
  }
147
208
  export interface AnalyticsInput {
@@ -152,6 +213,11 @@ export interface AnalyticsInput {
152
213
  weeks?: number;
153
214
  topOutliers?: number;
154
215
  pricing?: PricingTable;
216
+ /** D7: счётчики readSignalLog — источник dataQuality (undefined → n/a). */
217
+ signalLogStats?: {
218
+ malformedLines: number;
219
+ totalLines: number;
220
+ };
155
221
  }
156
222
  /**
157
223
  * Полный аналитический отчёт M5 из трёх портов: чистая агрегация, детерминированная.
@@ -159,7 +225,7 @@ export interface AnalyticsInput {
159
225
  */
160
226
  export declare function buildAnalyticsReport(deps: AnalyticsDeps, input: AnalyticsInput): Promise<AnalyticsReport>;
161
227
  export interface AnalyticsViewFilter {
162
- view: 'memory' | 'tools' | 'rules' | 'funnel' | 'agents' | 'steward' | 'outliers' | 'readiness' | 'all';
228
+ view: 'memory' | 'tools' | 'rules' | 'weeklyActivity' | 'agents' | 'steward' | 'outliers' | 'readiness' | 'councils' | 'all';
163
229
  class?: 'new' | 'sleeper' | 'workhorse' | 'dead';
164
230
  type?: string;
165
231
  origin?: 'script' | 'model-native';
@@ -178,8 +244,8 @@ export type AnalyticsViewPayload = {
178
244
  view: 'rules';
179
245
  rows: RuleRankingRow[];
180
246
  } | {
181
- view: 'funnel';
182
- weeks: FunnelWeek[];
247
+ view: 'weeklyActivity';
248
+ weeks: WeeklyActivityWeek[];
183
249
  } | {
184
250
  view: 'agents';
185
251
  rows: AgentLedgerRow[];
@@ -192,6 +258,9 @@ export type AnalyticsViewPayload = {
192
258
  } | {
193
259
  view: 'readiness';
194
260
  readiness: ExperimentReadiness;
261
+ } | {
262
+ view: 'councils';
263
+ councils: CouncilsView;
195
264
  } | {
196
265
  view: 'all';
197
266
  report: AnalyticsReport;
@@ -1 +1 @@
1
- {"version":3,"file":"build-analytics.d.ts","sourceRoot":"","sources":["../../../src/app/use-cases/build-analytics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build-analytics.d.ts","sourceRoot":"","sources":["../../../src/app/use-cases/build-analytics.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { UNCATEGORIZED_ERROR_CLASS } from '../../domain/error-class.js';
4
4
  import { runCostUsd } from '../../domain/pricing.js';
5
5
  import { silentRuleIds } from './learn-decay.js';
6
6
  import { mondayOf } from './generate-insights.js';
7
+ import { extractVote } from './tally-council-votes.js';
7
8
  export const DEFAULT_LIFECYCLE_THRESHOLDS = { newDays: 14, workhorseUses: 3 };
8
9
  /** Override из config (analytics.thresholds) поверх дефолтов (D7). */
9
10
  export function resolveLifecycleThresholds(override) {
@@ -201,9 +202,10 @@ function weekBuckets(now, weeks) {
201
202
  keys.push(new Date(currentMondayMs - i * 7 * 86_400_000).toISOString().slice(0, 10));
202
203
  return keys;
203
204
  }
204
- /** Воронка Q6: write (memory.added) → deliver (delivery-сигналы) → trigger (уникальные имена).
205
- * prevented НЕ входит: holdout-счётчики кумулятивны, без таймстампов (спека §5 M5, rev.4). */
206
- function buildFunnel(events, signals, now, weeks) {
205
+ /** Недельная активность Q6: write (memory.added) → deliver (delivery-сигналы) → trigger
206
+ * (уникальные имена). prevented НЕ входит: holdout-счётчики кумулятивны, без
207
+ * таймстампов (спека §5 M5, rev.4). */
208
+ function buildWeeklyActivity(events, signals, now, weeks) {
207
209
  const buckets = new Map();
208
210
  for (const week of weekBuckets(now, weeks)) {
209
211
  buckets.set(week, { week, writes: 0, delivers: 0, names: new Set() });
@@ -250,10 +252,58 @@ function buildOutliers(runLogText, pricing, top) {
250
252
  tools: e.tools ?? [],
251
253
  }));
252
254
  }
255
+ /** Acceptance D4: accepted-вердикт считается ТОЛЬКО при строгой session-связке —
256
+ * session_id !== null и существует ≥1 run-сигнал с тем же session_id (без связки
257
+ * вердикт не атрибутируется: link ненадёжен до P1). costPerAcceptedTask = сумма
258
+ * weighted linked-ранов / число вердиктов. Атрибуция: каждому агенту множества
259
+ * gen_ai.agent linked-ранов вердикта +1 (дедуп внутри одного вердикта). */
260
+ function buildAcceptance(signals) {
261
+ const runsBySession = new Map();
262
+ for (const s of signals) {
263
+ if (s.event !== 'run' || s.session_id === null)
264
+ continue;
265
+ const arr = runsBySession.get(s.session_id) ?? [];
266
+ arr.push(s);
267
+ runsBySession.set(s.session_id, arr);
268
+ }
269
+ const acceptedByAgent = new Map();
270
+ const acceptedSessions = new Set();
271
+ let accepted = 0;
272
+ for (const s of signals) {
273
+ if (s.event !== 'task_evaluated' || s.detail?.verdict !== 'accepted')
274
+ continue;
275
+ // strict-link: без session_id или без run-связки вердикт НЕ считается
276
+ if (s.session_id === null || !runsBySession.has(s.session_id))
277
+ continue;
278
+ accepted += 1;
279
+ acceptedSessions.add(s.session_id);
280
+ const agents = new Set();
281
+ for (const r of runsBySession.get(s.session_id)) {
282
+ if (typeof r.gen_ai.agent === 'string' && r.gen_ai.agent !== '')
283
+ agents.add(r.gen_ai.agent);
284
+ }
285
+ for (const a of agents)
286
+ acceptedByAgent.set(a, (acceptedByAgent.get(a) ?? 0) + 1);
287
+ }
288
+ let linkedWeighted = 0;
289
+ for (const [session, runs] of runsBySession) {
290
+ if (!acceptedSessions.has(session))
291
+ continue;
292
+ for (const r of runs)
293
+ linkedWeighted += finiteNumber(r.weighted) ?? 0;
294
+ }
295
+ return { accepted, costPerAcceptedTask: accepted > 0 ? linkedWeighted / accepted : null, acceptedByAgent };
296
+ }
297
+ /** Coverage D5: scored = task_evaluated (любой verdict), runs = run-сигналы. */
298
+ function buildCoverage(signals) {
299
+ const scored = signals.filter((s) => s.event === 'task_evaluated').length;
300
+ const runs = signals.filter((s) => s.event === 'run').length;
301
+ return { scored, runs, scoredTaskRatePct: runs > 0 ? (scored / runs) * 100 : null };
302
+ }
253
303
  /** Agent ledger Q11: строки по run-агентам ∪ complaint-акторам `agent:<имя>`; три уровня —
254
- * объём (runs/weighted/duration/cost), проблемы (failures/toolErrors/жалобы), достижения
255
- * (successes/holdout_prevented его rule/lesson). */
256
- function buildAgents(signals, objects, pricing) {
304
+ * объём (runs/weighted/duration/cost), проблемы (processFailures/toolErrors/жалобы), достижения
305
+ * (completedRuns/accepted/holdout_prevented его rule/lesson). */
306
+ function buildAgents(signals, objects, pricing, acceptedByAgent) {
257
307
  const AGENT_PREFIX = 'agent:';
258
308
  const acc = new Map();
259
309
  const rowOf = (name) => {
@@ -261,8 +311,9 @@ function buildAgents(signals, objects, pricing) {
261
311
  if (r === undefined) {
262
312
  r = {
263
313
  runs: 0,
264
- failures: 0,
265
- successes: 0,
314
+ processFailures: 0,
315
+ completedRuns: 0,
316
+ accepted: 0,
266
317
  weighted: 0,
267
318
  durations: [],
268
319
  cost: null,
@@ -282,9 +333,9 @@ function buildAgents(signals, objects, pricing) {
282
333
  const r = rowOf(ev.gen_ai.agent);
283
334
  r.runs += 1;
284
335
  if (ev.outcome === 'ok')
285
- r.successes += 1;
336
+ r.completedRuns += 1;
286
337
  else
287
- r.failures += 1;
338
+ r.processFailures += 1;
288
339
  r.weighted += finiteNumber(ev.weighted) ?? 0;
289
340
  const d = finiteNumber(ev.duration_ms);
290
341
  if (d !== null)
@@ -334,19 +385,23 @@ function buildAgents(signals, objects, pricing) {
334
385
  acc.get(name).hasHoldout = true;
335
386
  }
336
387
  }
388
+ // D4: accepted-атрибуция — строки linked-ранов уже существуют (раны их создали)
389
+ for (const [name, n] of acceptedByAgent)
390
+ rowOf(name).accepted += n;
337
391
  return [...acc.entries()]
338
392
  .map(([agent, r]) => ({
339
393
  agent,
340
394
  runs: r.runs,
341
- failures: r.failures,
342
- failureRatePct: r.runs > 0 ? (r.failures / r.runs) * 100 : null,
395
+ processFailures: r.processFailures,
396
+ processFailureRatePct: r.runs > 0 ? (r.processFailures / r.runs) * 100 : null,
343
397
  weighted: r.weighted,
344
398
  avgDurationMs: r.durations.length > 0 ? r.durations.reduce((s, v) => s + v, 0) / r.durations.length : null,
345
399
  costUsd: r.cost,
346
400
  toolErrors: r.toolErrors,
347
401
  complaintsBy: r.complaintsBy,
348
402
  complaintsAbout: r.complaintsAbout,
349
- successes: r.successes,
403
+ completedRuns: r.completedRuns,
404
+ accepted: r.accepted,
350
405
  holdoutPrevented: r.hasHoldout ? r.holdoutSum : null,
351
406
  }))
352
407
  .sort((a, b) => b.runs - a.runs || a.agent.localeCompare(b.agent));
@@ -370,7 +425,7 @@ function mutationKindOf(ev) {
370
425
  }
371
426
  }
372
427
  const MUTATION_KINDS = ['update', 'supersede', 'resolve', 'transition', 'tool-mutation'];
373
- /** Steward view Q12: мутации за окно weeks (то же, что воронка), жалобная воронка,
428
+ /** Steward view Q12: мутации за окно weeks (то же, что weekly activity), жалобная воронка,
374
429
  * SLA-эскалации (dispatch_ages >= 3), рецидивы, churn, доля авто-мутаций. */
375
430
  function buildSteward(events, signals, objects, now, weeks) {
376
431
  const keys = weekBuckets(now, weeks);
@@ -518,6 +573,124 @@ function buildReadiness(signals) {
518
573
  // ---------------------------------------------------------------------------
519
574
  // Use-case
520
575
  // ---------------------------------------------------------------------------
576
+ /** Консилиумы: вопросы/мнения/синтезы из councils-subdir + relations answers/based_on.
577
+ * Чистая агрегация по уже выгруженным объектам; ровно два вызова relations.list
578
+ * (predicate answers и based_on — без N+1 по вопросам). Голоса — extractVote
579
+ * из tally-council-votes (единственный парсер). */
580
+ async function buildCouncils(objects, relations, now, weeks) {
581
+ const byId = new Map(objects.map((o) => [o.id, o]));
582
+ const questions = objects.filter((o) => o.type === 'council-question');
583
+ const opinions = objects.filter((o) => o.type === 'council-opinion');
584
+ const syntheses = objects.filter((o) => o.type === 'synthesis');
585
+ // вопрос → id его мнений; субъект-реляция засчитывается только если это
586
+ // существующее в store мнение (прецедент tallyCouncilVotes)
587
+ const answersByQuestion = new Map();
588
+ for (const r of await relations.list({ predicate: 'answers' })) {
589
+ const op = byId.get(r.subject);
590
+ if (op === undefined || op.type !== 'council-opinion')
591
+ continue;
592
+ const arr = answersByQuestion.get(r.object) ?? [];
593
+ arr.push(op.id);
594
+ answersByQuestion.set(r.object, arr);
595
+ }
596
+ // недельные бакеты (те же ключи, что weekly activity) по mondayOf(created_at)
597
+ const buckets = new Map(weekBuckets(now, weeks).map((week) => [week, { week, questions: 0, opinions: 0, syntheses: 0 }]));
598
+ const bump = (o, key) => {
599
+ const b = buckets.get(mondayOf(o.created_at));
600
+ if (b !== undefined)
601
+ b[key] += 1;
602
+ };
603
+ for (const q of questions)
604
+ bump(q, 'questions');
605
+ for (const op of opinions)
606
+ bump(op, 'opinions');
607
+ for (const s of syntheses)
608
+ bump(s, 'syntheses');
609
+ const weeksOut = [...buckets.values()];
610
+ const inWindow = weeksOut.reduce((sum, w) => sum + w.questions, 0);
611
+ // per-question статистика по ВСЕМ вопросам (вопрос без мнений — 0)
612
+ const counts = questions.map((q) => (answersByQuestion.get(q.id) ?? []).length);
613
+ // участие: мнения по created_by (voter = created_by, прецедент CouncilTally)
614
+ const partAcc = new Map();
615
+ for (const op of opinions)
616
+ partAcc.set(op.created_by, (partAcc.get(op.created_by) ?? 0) + 1);
617
+ const participation = [...partAcc.entries()]
618
+ .map(([agent, n]) => ({ agent, opinions: n }))
619
+ .sort((a, b) => b.opinions - a.opinions || a.agent.localeCompare(b.agent));
620
+ // голоса: единый парсер extractVote (поле vote → body VOTE: → TIMEOUT)
621
+ const tally = (ops) => {
622
+ const v = {};
623
+ for (const opId of ops) {
624
+ const vote = extractVote(byId.get(opId));
625
+ v[vote] = (v[vote] ?? 0) + 1;
626
+ }
627
+ return v;
628
+ };
629
+ const votes = tally(opinions.map((o) => o.id));
630
+ // синтез: вопрос «с синтезом» = ∃ синтез с based_on → мнение этого вопроса;
631
+ // берём самый ранний подходящий синтез (медиана времени до синтеза)
632
+ const questionByOpinionId = new Map();
633
+ for (const [qid, opIds] of answersByQuestion) {
634
+ for (const opId of opIds)
635
+ questionByOpinionId.set(opId, qid);
636
+ }
637
+ const earliestSynByQuestion = new Map();
638
+ for (const r of await relations.list({ predicate: 'based_on' })) {
639
+ const syn = byId.get(r.subject);
640
+ if (syn === undefined || syn.type !== 'synthesis')
641
+ continue;
642
+ const qid = questionByOpinionId.get(r.object);
643
+ if (qid === undefined)
644
+ continue;
645
+ const cur = earliestSynByQuestion.get(qid);
646
+ if (cur === undefined || syn.created_at < cur)
647
+ earliestSynByQuestion.set(qid, syn.created_at);
648
+ }
649
+ const questionsWithSynthesis = earliestSynByQuestion.size;
650
+ const hours = [...earliestSynByQuestion].map(([qid, synTs]) => (Date.parse(synTs) - Date.parse(byId.get(qid).created_at)) / 3_600_000);
651
+ hours.sort((a, b) => a - b);
652
+ const medianHours = hours.length === 0
653
+ ? null
654
+ : hours.length % 2 === 1
655
+ ? hours[(hours.length - 1) / 2]
656
+ : (hours[hours.length / 2 - 1] + hours[hours.length / 2]) / 2;
657
+ // открытые вопросы: возраст, число мнений, расклад голосов
658
+ const openQuestions = questions
659
+ .filter((q) => q.status === 'open')
660
+ .map((q) => {
661
+ const opIds = answersByQuestion.get(q.id) ?? [];
662
+ return {
663
+ id: q.id,
664
+ title: q.title,
665
+ daysOpen: Math.floor((now.getTime() - Date.parse(q.created_at)) / 86_400_000),
666
+ opinions: opIds.length,
667
+ votes: tally(opIds),
668
+ };
669
+ })
670
+ .sort((a, b) => b.daysOpen - a.daysOpen || a.id.localeCompare(b.id));
671
+ return {
672
+ questions: {
673
+ total: questions.length,
674
+ inWindow,
675
+ open: questions.filter((q) => q.status === 'open').length,
676
+ },
677
+ opinions: {
678
+ total: opinions.length,
679
+ perQuestionMin: questions.length > 0 ? Math.min(...counts) : null,
680
+ perQuestionAvg: questions.length > 0 ? counts.reduce((s, v) => s + v, 0) / counts.length : null,
681
+ perQuestionMax: questions.length > 0 ? Math.max(...counts) : null,
682
+ },
683
+ participation,
684
+ votes,
685
+ synthesis: {
686
+ questionsWithSynthesis,
687
+ sharePct: questions.length > 0 ? (questionsWithSynthesis / questions.length) * 100 : null,
688
+ medianHours,
689
+ },
690
+ weeks: weeksOut,
691
+ openQuestions,
692
+ };
693
+ }
521
694
  /**
522
695
  * Полный аналитический отчёт M5 из трёх портов: чистая агрегация, детерминированная.
523
696
  * Не падает на пустой памяти — все блоки возвращают нули/null/пустые массивы.
@@ -532,22 +705,40 @@ export async function buildAnalyticsReport(deps, input) {
532
705
  const memory = buildMemoryLedger(allObjects, events, input.signals, now, thresholds);
533
706
  const tools = buildToolLedger(allObjects.filter((o) => o.type === 'tool'), input.signals, input.runLogText, input.patternThreshold ?? DEFAULT_PATTERN_THRESHOLD);
534
707
  const rules = buildRuleRanking(allObjects.filter((o) => o.type === 'rule'), input.signals);
535
- const funnel = buildFunnel(events, input.signals, now, weeks);
708
+ const weeklyActivity = buildWeeklyActivity(events, input.signals, now, weeks);
536
709
  const outliers = buildOutliers(input.runLogText, input.pricing, input.topOutliers ?? 10);
537
- const agents = buildAgents(input.signals, allObjects, input.pricing);
710
+ const acceptance = buildAcceptance(input.signals);
711
+ const agents = buildAgents(input.signals, allObjects, input.pricing, acceptance.acceptedByAgent);
538
712
  const steward = buildSteward(events, input.signals, allObjects, now, weeks);
539
713
  const readiness = buildReadiness(input.signals);
714
+ const councils = await buildCouncils(allObjects, deps.relations, now, weeks);
715
+ const coverage = buildCoverage(input.signals);
716
+ // D7: без signalLogStats (старые вызывающие) → n/a; totalLines=0 → null-процент
717
+ const dataQuality = input.signalLogStats === undefined
718
+ ? { validEventRatePct: null, malformedLines: 0 }
719
+ : {
720
+ validEventRatePct: input.signalLogStats.totalLines > 0
721
+ ? ((input.signalLogStats.totalLines - input.signalLogStats.malformedLines) /
722
+ input.signalLogStats.totalLines) *
723
+ 100
724
+ : null,
725
+ malformedLines: input.signalLogStats.malformedLines,
726
+ };
540
727
  return {
541
728
  generatedAt: now.toISOString(),
542
729
  thresholds,
543
730
  memory,
544
731
  tools,
545
732
  rules,
546
- funnel,
733
+ weeklyActivity,
547
734
  outliers,
548
735
  agents,
549
736
  steward,
550
737
  readiness,
738
+ councils,
739
+ acceptance: { accepted: acceptance.accepted, costPerAcceptedTask: acceptance.costPerAcceptedTask },
740
+ coverage,
741
+ dataQuality,
551
742
  };
552
743
  }
553
744
  /** Срез отчёта по view-фильтру (§6.2); top ограничивает строки, дефолт 20. */
@@ -574,8 +765,8 @@ export function filterAnalytics(report, filter) {
574
765
  rows = rows.filter((r) => r.silent === filter.silent);
575
766
  return { view: 'rules', rows: rows.slice(0, top) };
576
767
  }
577
- case 'funnel':
578
- return { view: 'funnel', weeks: report.funnel };
768
+ case 'weeklyActivity':
769
+ return { view: 'weeklyActivity', weeks: report.weeklyActivity };
579
770
  case 'agents': {
580
771
  let rows = report.agents;
581
772
  if (filter.agent !== undefined)
@@ -588,6 +779,8 @@ export function filterAnalytics(report, filter) {
588
779
  return { view: 'outliers', runs: report.outliers.slice(0, top) };
589
780
  case 'readiness':
590
781
  return { view: 'readiness', readiness: report.readiness };
782
+ case 'councils':
783
+ return { view: 'councils', councils: report.councils };
591
784
  case 'all':
592
785
  return { view: 'all', report };
593
786
  }