@akagilnc/pi-workflow-roles 0.1.5303 → 0.1.5307

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.
@@ -2,9 +2,6 @@ import { extractStatus } from "./acceptance-success-rework.js";
2
2
  function isRecord(value) {
3
3
  return typeof value === "object" && value !== null && !Array.isArray(value);
4
4
  }
5
- function wallMsFromSpan(startedAt, endedAt) {
6
- return Date.parse(endedAt) - Date.parse(startedAt);
7
- }
8
5
  function readClassCount(body) {
9
6
  if (!isRecord(body.outcome))
10
7
  return undefined;
@@ -44,7 +41,7 @@ function projectRunRow(facts) {
44
41
  role: facts.role,
45
42
  startedAt,
46
43
  endedAt,
47
- wallMs: wallMsFromSpan(startedAt, endedAt),
44
+ wallMs: facts.frameSpan.wallMs,
48
45
  terminal: projectTerminal(facts),
49
46
  };
50
47
  }
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import { buildAcceptanceSuccessReworkSection } from "./analyst-metric-families/acceptance-success-rework.js";
12
12
  import { medianNumber } from "./analyst-median.js";
13
+ import { sortUnreadable } from "./analyst-page.js";
13
14
  /**
14
15
  * Build the raw group key for one leg from its ordered-unique model sequence.
15
16
  * Empty sequence → undefined (no inventable group; caller lists as typed vacancy).
@@ -33,13 +34,6 @@ function displayNameFor(rawGroupKey, combinationMapping) {
33
34
  const aliased = combinationMapping[rawGroupKey];
34
35
  return aliased === undefined ? rawGroupKey : aliased;
35
36
  }
36
- function sortUnreadable(unreadable) {
37
- return [...unreadable].sort((a, b) => {
38
- if (a.book !== b.book)
39
- return a.book.localeCompare(b.book);
40
- return a.runId.localeCompare(b.runId);
41
- });
42
- }
43
37
  /**
44
38
  * Legs with no usable session model identity cannot join any model group.
45
39
  * Reuse the typed unreadable path (locatable missing-source) — not an empty-key group.
@@ -10,6 +10,7 @@ import { createHash } from "node:crypto";
10
10
  import { dirname, join } from "node:path";
11
11
  import { writeFileAtomically } from "./atomic-write.js";
12
12
  import { assertLedgerFileInsideHome, ensureRealDirectoryTree, physicalPathIdentity, } from "./activation-ledger-topology.js";
13
+ import { compareAnalystLegs, sumAnalystRunWallMs } from "./analyst-ledger.js";
13
14
  import { loadAnalystIssueMetricFamilies } from "./analyst-metric-families.js";
14
15
  import { composeAnalystMetricFamilySections } from "./analyst-metric-family.js";
15
16
  export function analystIssuePageKey(address) {
@@ -35,15 +36,9 @@ export function analystIssuePageAddressFromPage(page) {
35
36
  };
36
37
  }
37
38
  function sortLegs(legs) {
38
- return [...legs].sort((a, b) => {
39
- if (a.book !== b.book)
40
- return a.book.localeCompare(b.book);
41
- if (a.role !== b.role)
42
- return a.role.localeCompare(b.role);
43
- return a.runId.localeCompare(b.runId);
44
- });
39
+ return [...legs].sort(compareAnalystLegs);
45
40
  }
46
- function sortUnreadable(unreadable) {
41
+ export function sortUnreadable(unreadable) {
47
42
  return [...unreadable].sort((a, b) => {
48
43
  if (a.book !== b.book)
49
44
  return a.book.localeCompare(b.book);
@@ -95,19 +90,15 @@ export function computeAnalystMsPerKLines(totalElapsedMs, changedLines) {
95
90
  value: totalElapsedMs / (changedLines.value / 1000),
96
91
  };
97
92
  }
98
- function frameSpanWallMs(span) {
99
- return Date.parse(span.endedAt) - Date.parse(span.startedAt);
100
- }
101
93
  /**
102
94
  * Σ readable wall clocks + max end-frame across ALL runs (C1 efficiency / index).
103
95
  * Unreadable runs never enter totalElapsedMs; their available lastFrameAt still
104
96
  * competes for lastActivityAt (PRD ②: 全部 run 末帧之最大者).
105
97
  */
106
98
  export function summarizeAnalystRunEfficiency(runs, unreadable = []) {
107
- let totalElapsedMs = 0;
99
+ const totalElapsedMs = sumAnalystRunWallMs(runs);
108
100
  let latestEndedAt;
109
101
  for (const run of runs) {
110
- totalElapsedMs += frameSpanWallMs(run.frameSpan);
111
102
  const endedAt = run.frameSpan.endedAt;
112
103
  if (latestEndedAt === undefined || endedAt > latestEndedAt) {
113
104
  latestEndedAt = endedAt;
@@ -15958,11 +15958,21 @@ function admitFrameSpanFromRows(rows) {
15958
15958
  }
15959
15959
  return {
15960
15960
  models,
15961
- frameSpan: { startedAt: span.startedAt, endedAt: span.endedAt },
15961
+ frameSpan: { startedAt: span.startedAt, endedAt: span.endedAt, wallMs: endedMs - startedMs },
15962
15962
  partialFirstFrameAt: { status: "present", at: span.startedAt },
15963
15963
  partialLastFrameAt: { status: "present", at: span.endedAt }
15964
15964
  };
15965
15965
  }
15966
+ function sumAnalystRunWallMs(runs) {
15967
+ let total = 0;
15968
+ for (const run of runs) total += run.frameSpan.wallMs;
15969
+ return total;
15970
+ }
15971
+ function compareAnalystLegs(a, b) {
15972
+ if (a.book !== b.book) return a.book.localeCompare(b.book);
15973
+ if (a.role !== b.role) return a.role.localeCompare(b.role);
15974
+ return a.runId.localeCompare(b.runId);
15975
+ }
15966
15976
  async function classifyScopedRun(input) {
15967
15977
  const missingSources = [];
15968
15978
  const reasons = [];
@@ -16243,9 +16253,6 @@ var init_analyst_ledger = __esm({
16243
16253
  function isRecord13(value) {
16244
16254
  return typeof value === "object" && value !== null && !Array.isArray(value);
16245
16255
  }
16246
- function wallMsFromSpan(span) {
16247
- return Date.parse(span.endedAt) - Date.parse(span.startedAt);
16248
- }
16249
16256
  function findCollectorGroups(body) {
16250
16257
  if (Array.isArray(body.groups)) return body.groups;
16251
16258
  const receipt = body.receipt;
@@ -16354,7 +16361,7 @@ function projectLegs(runs) {
16354
16361
  book: run.book,
16355
16362
  role: run.role,
16356
16363
  startedAt: run.frameSpan.startedAt,
16357
- wallMs: wallMsFromSpan(run.frameSpan),
16364
+ wallMs: run.frameSpan.wallMs,
16358
16365
  terminalLabel: mapped.terminalLabel,
16359
16366
  accepted: mapped.accepted,
16360
16367
  success: mapped.success,
@@ -16364,11 +16371,7 @@ function projectLegs(runs) {
16364
16371
  rework: ordinal >= 2
16365
16372
  });
16366
16373
  }
16367
- return legs.sort((a, b) => {
16368
- if (a.book !== b.book) return a.book.localeCompare(b.book);
16369
- if (a.role !== b.role) return a.role.localeCompare(b.role);
16370
- return a.runId.localeCompare(b.runId);
16371
- });
16374
+ return legs.sort(compareAnalystLegs);
16372
16375
  }
16373
16376
  function aggregateByRole(legs) {
16374
16377
  const roles = [...new Set(legs.map((leg) => leg.role))].sort((a, b) => a.localeCompare(b));
@@ -16412,12 +16415,10 @@ function aggregateByRole(legs) {
16412
16415
  };
16413
16416
  });
16414
16417
  }
16415
- function reworkLens(legs) {
16418
+ function reworkLens(legs, totalWallMs) {
16416
16419
  let reworkWallMs = 0;
16417
- let totalWallMs = 0;
16418
16420
  let reworkLegCount = 0;
16419
16421
  for (const leg of legs) {
16420
- totalWallMs += leg.wallMs;
16421
16422
  if (leg.rework) {
16422
16423
  reworkWallMs += leg.wallMs;
16423
16424
  reworkLegCount += 1;
@@ -16438,13 +16439,14 @@ function buildAcceptanceSuccessReworkSection(runs) {
16438
16439
  kind: "analyst-acceptance-success-rework",
16439
16440
  legs,
16440
16441
  byRole: aggregateByRole(legs),
16441
- rework: reworkLens(legs)
16442
+ rework: reworkLens(legs, sumAnalystRunWallMs(runs))
16442
16443
  };
16443
16444
  }
16444
16445
  var WORKER_ROLES, ACCEPTED_STATUS, SUCCESS_STATUS, acceptanceSuccessReworkFamily, acceptance_success_rework_default;
16445
16446
  var init_acceptance_success_rework = __esm({
16446
16447
  "src/analyst-metric-families/acceptance-success-rework.ts"() {
16447
16448
  "use strict";
16449
+ init_analyst_ledger();
16448
16450
  init_analyst_median();
16449
16451
  init_packaged_role_registry();
16450
16452
  WORKER_ROLES = /* @__PURE__ */ new Set(["coder", "fixer"]);
@@ -16477,117 +16479,6 @@ var init_acceptance_success_rework = __esm({
16477
16479
  }
16478
16480
  });
16479
16481
 
16480
- // src/analyst-model-groups.ts
16481
- function analystModelGroupKey(models) {
16482
- if (models.length === 0) return void 0;
16483
- if (models.length === 1) return models[0];
16484
- return `mixed:${models.join("+")}`;
16485
- }
16486
- function rate(numerator, denominator) {
16487
- if (denominator === 0) return void 0;
16488
- return numerator / denominator;
16489
- }
16490
- function displayNameFor(rawGroupKey, combinationMapping) {
16491
- if (combinationMapping === void 0) return rawGroupKey;
16492
- const aliased = combinationMapping[rawGroupKey];
16493
- return aliased === void 0 ? rawGroupKey : aliased;
16494
- }
16495
- function sortUnreadable(unreadable) {
16496
- return [...unreadable].sort((a, b) => {
16497
- if (a.book !== b.book) return a.book.localeCompare(b.book);
16498
- return a.runId.localeCompare(b.runId);
16499
- });
16500
- }
16501
- function modelIdentityAbsentEntry(run) {
16502
- return {
16503
- runId: run.runId,
16504
- book: run.book,
16505
- missingSources: ["session-model"],
16506
- reason: "session has no usable model identity",
16507
- firstFrameAt: { status: "present", at: run.frameSpan.startedAt },
16508
- // Readable legs already admitted a full span — retain end edge for lastActivityAt.
16509
- lastFrameAt: { status: "present", at: run.frameSpan.endedAt }
16510
- };
16511
- }
16512
- function buildAnalystModelGroupsPage(input) {
16513
- const groupedRuns = [];
16514
- const modelAbsent = [];
16515
- for (const run of input.runs) {
16516
- const rawGroupKey = analystModelGroupKey(run.models);
16517
- if (rawGroupKey === void 0) {
16518
- modelAbsent.push(modelIdentityAbsentEntry(run));
16519
- } else {
16520
- groupedRuns.push({ run, rawGroupKey });
16521
- }
16522
- }
16523
- const acceptance = buildAcceptanceSuccessReworkSection(
16524
- groupedRuns.map(({ run }) => run)
16525
- );
16526
- const legByRunId = new Map(
16527
- (acceptance?.legs ?? []).map((leg) => [leg.runId, leg])
16528
- );
16529
- const byRaw = /* @__PURE__ */ new Map();
16530
- for (const { run, rawGroupKey } of groupedRuns) {
16531
- const leg = legByRunId.get(run.runId);
16532
- if (leg === void 0) {
16533
- throw new Error(
16534
- `analyst model-groups: missing acceptance projection for run ${run.runId}`
16535
- );
16536
- }
16537
- let acc = byRaw.get(rawGroupKey);
16538
- if (acc === void 0) {
16539
- acc = {
16540
- acceptedCount: 0,
16541
- successCount: 0,
16542
- successEligibleCount: 0,
16543
- noReceiptCount: 0,
16544
- walls: []
16545
- };
16546
- byRaw.set(rawGroupKey, acc);
16547
- }
16548
- if (leg.accepted) acc.acceptedCount += 1;
16549
- if (leg.success) acc.successCount += 1;
16550
- if (leg.successEligible) acc.successEligibleCount += 1;
16551
- if (leg.noReceipt) acc.noReceiptCount += 1;
16552
- acc.walls.push(leg.wallMs);
16553
- }
16554
- const rawKeys = [...byRaw.keys()].sort((a, b) => a.localeCompare(b));
16555
- const groups = rawKeys.map((rawGroupKey) => {
16556
- const acc = byRaw.get(rawGroupKey);
16557
- const legCount = acc.walls.length;
16558
- return {
16559
- rawGroupKey,
16560
- displayName: displayNameFor(rawGroupKey, input.combinationMapping),
16561
- legCount,
16562
- acceptedCount: acc.acceptedCount,
16563
- acceptanceRate: rate(acc.acceptedCount, legCount),
16564
- successCount: acc.successCount,
16565
- successEligibleCount: acc.successEligibleCount,
16566
- successRate: rate(acc.successCount, acc.successEligibleCount),
16567
- noReceiptCount: acc.noReceiptCount,
16568
- noReceiptRate: rate(acc.noReceiptCount, legCount),
16569
- wallClockMedianMs: medianNumber(acc.walls)
16570
- };
16571
- });
16572
- const unreadable = sortUnreadable([...input.unreadable, ...modelAbsent]);
16573
- return {
16574
- kind: "analyst-model-groups",
16575
- mode: "model-groups",
16576
- projectRoots: [...input.projectRoots].sort((a, b) => a.localeCompare(b)),
16577
- groups,
16578
- legCount: groupedRuns.length,
16579
- unreadableCount: unreadable.length,
16580
- unreadable
16581
- };
16582
- }
16583
- var init_analyst_model_groups = __esm({
16584
- "src/analyst-model-groups.ts"() {
16585
- "use strict";
16586
- init_acceptance_success_rework();
16587
- init_analyst_median();
16588
- }
16589
- });
16590
-
16591
16482
  // src/analyst-metric-families/b2-frame-buckets-actions.ts
16592
16483
  function timestampMs(iso) {
16593
16484
  const ms = Date.parse(iso);
@@ -16710,7 +16601,7 @@ function sortActionsDescending(actions) {
16710
16601
  function computeAnalystB2RunMetrics(facts) {
16711
16602
  const frameStartMs = timestampMs(facts.frameSpan.startedAt);
16712
16603
  const frameEndMs = timestampMs(facts.frameSpan.endedAt);
16713
- const wallMs = Math.max(0, frameEndMs - frameStartMs);
16604
+ const wallMs = facts.frameSpan.wallMs;
16714
16605
  const tools = clipToolsToFrame(closedTools(facts.toolIntervals), frameStartMs, frameEndMs);
16715
16606
  const toolUnion = mergeUnion(tools);
16716
16607
  const toolBucketMs = toolUnion.reduce(
@@ -16740,15 +16631,12 @@ var init_b2_frame_buckets_actions = __esm({
16740
16631
  "src/analyst-metric-families/b2-frame-buckets-actions.ts"() {
16741
16632
  "use strict";
16742
16633
  init_analyst_median();
16634
+ init_analyst_ledger();
16743
16635
  b2FrameBucketsActionsFamily = {
16744
16636
  id: "b2-frame-buckets-actions",
16745
16637
  contribute(input) {
16746
16638
  if (input.runs.length === 0) return void 0;
16747
- const runs = [...input.runs].map(computeAnalystB2RunMetrics).sort((a, b) => {
16748
- if (a.book !== b.book) return a.book.localeCompare(b.book);
16749
- if (a.role !== b.role) return a.role.localeCompare(b.role);
16750
- return a.runId.localeCompare(b.runId);
16751
- });
16639
+ const runs = [...input.runs].map(computeAnalystB2RunMetrics).sort(compareAnalystLegs);
16752
16640
  const section = {
16753
16641
  kind: "analyst-b2-frame-buckets-actions",
16754
16642
  runs
@@ -16781,11 +16669,6 @@ function projectLeg(facts) {
16781
16669
  rounds
16782
16670
  };
16783
16671
  }
16784
- function compareLegs(a, b) {
16785
- if (a.book !== b.book) return a.book.localeCompare(b.book);
16786
- if (a.role !== b.role) return a.role.localeCompare(b.role);
16787
- return a.runId.localeCompare(b.runId);
16788
- }
16789
16672
  function emptyAccum() {
16790
16673
  return { rounds: 0, bounceCount: 0, passCount: 0, wallSum: 0 };
16791
16674
  }
@@ -16821,11 +16704,12 @@ var gateCyclesFamily, gate_cycles_default;
16821
16704
  var init_gate_cycles = __esm({
16822
16705
  "src/analyst-metric-families/gate-cycles.ts"() {
16823
16706
  "use strict";
16707
+ init_analyst_ledger();
16824
16708
  gateCyclesFamily = {
16825
16709
  id: "gate-cycles",
16826
16710
  contribute(input) {
16827
16711
  if (input.runs.length === 0) return void 0;
16828
- const legs = input.runs.map(projectLeg).sort(compareLegs);
16712
+ const legs = input.runs.map(projectLeg).sort(compareAnalystLegs);
16829
16713
  const section = {
16830
16714
  kind: "analyst-gate-cycles",
16831
16715
  legs,
@@ -16839,28 +16723,24 @@ var init_gate_cycles = __esm({
16839
16723
  });
16840
16724
 
16841
16725
  // src/analyst-metric-families/leg-wall-clock.ts
16842
- function frameSpanWallMs(span) {
16843
- return Date.parse(span.endedAt) - Date.parse(span.startedAt);
16844
- }
16845
16726
  function projectEntry(facts) {
16846
16727
  return {
16847
16728
  runId: facts.runId,
16848
16729
  book: facts.book,
16849
16730
  role: facts.role,
16850
- wallMs: frameSpanWallMs(facts.frameSpan)
16731
+ wallMs: facts.frameSpan.wallMs
16851
16732
  };
16852
16733
  }
16853
16734
  function compareRankingDesc(a, b) {
16854
16735
  if (b.wallMs !== a.wallMs) return b.wallMs - a.wallMs;
16855
- if (a.book !== b.book) return a.book.localeCompare(b.book);
16856
- if (a.role !== b.role) return a.role.localeCompare(b.role);
16857
- return a.runId.localeCompare(b.runId);
16736
+ return compareAnalystLegs(a, b);
16858
16737
  }
16859
16738
  var legWallClockFamily, leg_wall_clock_default;
16860
16739
  var init_leg_wall_clock = __esm({
16861
16740
  "src/analyst-metric-families/leg-wall-clock.ts"() {
16862
16741
  "use strict";
16863
16742
  init_analyst_median();
16743
+ init_analyst_ledger();
16864
16744
  legWallClockFamily = {
16865
16745
  id: "leg-wall-clock",
16866
16746
  contribute(input) {
@@ -16873,13 +16753,11 @@ var init_leg_wall_clock = __esm({
16873
16753
  if (medianWallMs === void 0) {
16874
16754
  return void 0;
16875
16755
  }
16876
- let totalElapsedMs = 0;
16877
- for (const wallMs of walls) totalElapsedMs += wallMs;
16878
16756
  const section = {
16879
16757
  kind: "analyst-leg-wall-clock",
16880
16758
  ranking,
16881
16759
  medianWallMs,
16882
- totalElapsedMs
16760
+ totalElapsedMs: sumAnalystRunWallMs(input.runs)
16883
16761
  };
16884
16762
  return { legWallClock: section };
16885
16763
  }
@@ -16892,9 +16770,6 @@ var init_leg_wall_clock = __esm({
16892
16770
  function isRecord14(value) {
16893
16771
  return typeof value === "object" && value !== null && !Array.isArray(value);
16894
16772
  }
16895
- function wallMsFromSpan2(startedAt, endedAt) {
16896
- return Date.parse(endedAt) - Date.parse(startedAt);
16897
- }
16898
16773
  function readClassCount(body) {
16899
16774
  if (!isRecord14(body.outcome)) return void 0;
16900
16775
  if (!isRecord14(body.outcome.decisiveFacts)) return void 0;
@@ -16931,7 +16806,7 @@ function projectRunRow(facts) {
16931
16806
  role: facts.role,
16932
16807
  startedAt,
16933
16808
  endedAt,
16934
- wallMs: wallMsFromSpan2(startedAt, endedAt),
16809
+ wallMs: facts.frameSpan.wallMs,
16935
16810
  terminal: projectTerminal(facts)
16936
16811
  };
16937
16812
  }
@@ -17063,13 +16938,9 @@ function analystIssuePageAddressFromPage(page) {
17063
16938
  };
17064
16939
  }
17065
16940
  function sortLegs(legs) {
17066
- return [...legs].sort((a, b) => {
17067
- if (a.book !== b.book) return a.book.localeCompare(b.book);
17068
- if (a.role !== b.role) return a.role.localeCompare(b.role);
17069
- return a.runId.localeCompare(b.runId);
17070
- });
16941
+ return [...legs].sort(compareAnalystLegs);
17071
16942
  }
17072
- function sortUnreadable2(unreadable) {
16943
+ function sortUnreadable(unreadable) {
17073
16944
  return [...unreadable].sort((a, b) => {
17074
16945
  if (a.book !== b.book) return a.book.localeCompare(b.book);
17075
16946
  return a.runId.localeCompare(b.runId);
@@ -17105,14 +16976,10 @@ function computeAnalystMsPerKLines(totalElapsedMs, changedLines) {
17105
16976
  value: totalElapsedMs / (changedLines.value / 1e3)
17106
16977
  };
17107
16978
  }
17108
- function frameSpanWallMs2(span) {
17109
- return Date.parse(span.endedAt) - Date.parse(span.startedAt);
17110
- }
17111
16979
  function summarizeAnalystRunEfficiency(runs, unreadable = []) {
17112
- let totalElapsedMs = 0;
16980
+ const totalElapsedMs = sumAnalystRunWallMs(runs);
17113
16981
  let latestEndedAt;
17114
16982
  for (const run of runs) {
17115
- totalElapsedMs += frameSpanWallMs2(run.frameSpan);
17116
16983
  const endedAt = run.frameSpan.endedAt;
17117
16984
  if (latestEndedAt === void 0 || endedAt > latestEndedAt) {
17118
16985
  latestEndedAt = endedAt;
@@ -17137,7 +17004,7 @@ async function buildAnalystIssueMetricsPage(input) {
17137
17004
  role: run.role
17138
17005
  }))
17139
17006
  );
17140
- const unreadable = sortUnreadable2(input.unreadable);
17007
+ const unreadable = sortUnreadable(input.unreadable);
17141
17008
  const scopeConflicts = sortScopeConflicts(input.scopeConflicts ?? []);
17142
17009
  const projectRoot = physicalPathIdentity(input.projectRoot);
17143
17010
  const { totalElapsedMs, lastActivityAt } = summarizeAnalystRunEfficiency(
@@ -17183,11 +17050,118 @@ var init_analyst_page = __esm({
17183
17050
  "use strict";
17184
17051
  init_atomic_write();
17185
17052
  init_activation_ledger_topology();
17053
+ init_analyst_ledger();
17186
17054
  init_analyst_metric_families();
17187
17055
  init_analyst_metric_family();
17188
17056
  }
17189
17057
  });
17190
17058
 
17059
+ // src/analyst-model-groups.ts
17060
+ function analystModelGroupKey(models) {
17061
+ if (models.length === 0) return void 0;
17062
+ if (models.length === 1) return models[0];
17063
+ return `mixed:${models.join("+")}`;
17064
+ }
17065
+ function rate(numerator, denominator) {
17066
+ if (denominator === 0) return void 0;
17067
+ return numerator / denominator;
17068
+ }
17069
+ function displayNameFor(rawGroupKey, combinationMapping) {
17070
+ if (combinationMapping === void 0) return rawGroupKey;
17071
+ const aliased = combinationMapping[rawGroupKey];
17072
+ return aliased === void 0 ? rawGroupKey : aliased;
17073
+ }
17074
+ function modelIdentityAbsentEntry(run) {
17075
+ return {
17076
+ runId: run.runId,
17077
+ book: run.book,
17078
+ missingSources: ["session-model"],
17079
+ reason: "session has no usable model identity",
17080
+ firstFrameAt: { status: "present", at: run.frameSpan.startedAt },
17081
+ // Readable legs already admitted a full span — retain end edge for lastActivityAt.
17082
+ lastFrameAt: { status: "present", at: run.frameSpan.endedAt }
17083
+ };
17084
+ }
17085
+ function buildAnalystModelGroupsPage(input) {
17086
+ const groupedRuns = [];
17087
+ const modelAbsent = [];
17088
+ for (const run of input.runs) {
17089
+ const rawGroupKey = analystModelGroupKey(run.models);
17090
+ if (rawGroupKey === void 0) {
17091
+ modelAbsent.push(modelIdentityAbsentEntry(run));
17092
+ } else {
17093
+ groupedRuns.push({ run, rawGroupKey });
17094
+ }
17095
+ }
17096
+ const acceptance = buildAcceptanceSuccessReworkSection(
17097
+ groupedRuns.map(({ run }) => run)
17098
+ );
17099
+ const legByRunId = new Map(
17100
+ (acceptance?.legs ?? []).map((leg) => [leg.runId, leg])
17101
+ );
17102
+ const byRaw = /* @__PURE__ */ new Map();
17103
+ for (const { run, rawGroupKey } of groupedRuns) {
17104
+ const leg = legByRunId.get(run.runId);
17105
+ if (leg === void 0) {
17106
+ throw new Error(
17107
+ `analyst model-groups: missing acceptance projection for run ${run.runId}`
17108
+ );
17109
+ }
17110
+ let acc = byRaw.get(rawGroupKey);
17111
+ if (acc === void 0) {
17112
+ acc = {
17113
+ acceptedCount: 0,
17114
+ successCount: 0,
17115
+ successEligibleCount: 0,
17116
+ noReceiptCount: 0,
17117
+ walls: []
17118
+ };
17119
+ byRaw.set(rawGroupKey, acc);
17120
+ }
17121
+ if (leg.accepted) acc.acceptedCount += 1;
17122
+ if (leg.success) acc.successCount += 1;
17123
+ if (leg.successEligible) acc.successEligibleCount += 1;
17124
+ if (leg.noReceipt) acc.noReceiptCount += 1;
17125
+ acc.walls.push(leg.wallMs);
17126
+ }
17127
+ const rawKeys = [...byRaw.keys()].sort((a, b) => a.localeCompare(b));
17128
+ const groups = rawKeys.map((rawGroupKey) => {
17129
+ const acc = byRaw.get(rawGroupKey);
17130
+ const legCount = acc.walls.length;
17131
+ return {
17132
+ rawGroupKey,
17133
+ displayName: displayNameFor(rawGroupKey, input.combinationMapping),
17134
+ legCount,
17135
+ acceptedCount: acc.acceptedCount,
17136
+ acceptanceRate: rate(acc.acceptedCount, legCount),
17137
+ successCount: acc.successCount,
17138
+ successEligibleCount: acc.successEligibleCount,
17139
+ successRate: rate(acc.successCount, acc.successEligibleCount),
17140
+ noReceiptCount: acc.noReceiptCount,
17141
+ noReceiptRate: rate(acc.noReceiptCount, legCount),
17142
+ wallClockMedianMs: medianNumber(acc.walls)
17143
+ };
17144
+ });
17145
+ const unreadable = sortUnreadable([...input.unreadable, ...modelAbsent]);
17146
+ return {
17147
+ kind: "analyst-model-groups",
17148
+ mode: "model-groups",
17149
+ projectRoots: [...input.projectRoots].sort((a, b) => a.localeCompare(b)),
17150
+ groups,
17151
+ legCount: groupedRuns.length,
17152
+ unreadableCount: unreadable.length,
17153
+ unreadable
17154
+ };
17155
+ }
17156
+ var init_analyst_model_groups = __esm({
17157
+ "src/analyst-model-groups.ts"() {
17158
+ "use strict";
17159
+ init_acceptance_success_rework();
17160
+ init_analyst_median();
17161
+ init_analyst_page();
17162
+ }
17163
+ });
17164
+
17191
17165
  // src/analyst-entry.ts
17192
17166
  import { readFile as readFile20 } from "node:fs/promises";
17193
17167
  import { Type as Type12 } from "typebox";