@ai-dossier/cli 0.9.1 → 0.11.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.
- package/README.md +345 -0
- package/dist/cache-resolver.d.ts.map +1 -1
- package/dist/cache-resolver.js +4 -16
- package/dist/cache-resolver.js.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cache.d.ts.map +1 -1
- package/dist/commands/cache.js +2 -14
- package/dist/commands/cache.js.map +1 -1
- package/dist/commands/keys.d.ts.map +1 -1
- package/dist/commands/keys.js +113 -28
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +4 -3
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/runstate.d.ts +12 -0
- package/dist/commands/runstate.d.ts.map +1 -0
- package/dist/commands/runstate.js +819 -0
- package/dist/commands/runstate.js.map +1 -0
- package/dist/commands/traces.d.ts.map +1 -1
- package/dist/commands/traces.js +6 -7
- package/dist/commands/traces.js.map +1 -1
- package/dist/duration.d.ts +29 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +63 -0
- package/dist/duration.js.map +1 -0
- package/dist/helpers.d.ts +8 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +17 -0
- package/dist/helpers.js.map +1 -1
- package/dist/issue-selection.d.ts +22 -0
- package/dist/issue-selection.d.ts.map +1 -0
- package/dist/issue-selection.js +88 -0
- package/dist/issue-selection.js.map +1 -0
- package/dist/runstate-stats.d.ts +157 -0
- package/dist/runstate-stats.d.ts.map +1 -0
- package/dist/runstate-stats.js +359 -0
- package/dist/runstate-stats.js.map +1 -0
- package/dist/runstate.d.ts +177 -0
- package/dist/runstate.d.ts.map +1 -0
- package/dist/runstate.js +438 -0
- package/dist/runstate.js.map +1 -0
- package/dist/table.d.ts +26 -0
- package/dist/table.d.ts.map +1 -0
- package/dist/table.js +49 -0
- package/dist/table.js.map +1 -0
- package/dist/verify-dossier.d.ts.map +1 -1
- package/dist/verify-dossier.js +43 -22
- package/dist/verify-dossier.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing analysis over `runstate:v1` milestone trails.
|
|
3
|
+
*
|
|
4
|
+
* Every milestone already stamps `at=`, so a run's per-phase durations are latent in the
|
|
5
|
+
* trail the moment it is written — nothing needs to be measured, stored, or timed at run
|
|
6
|
+
* time. This module is the read side of that decision: it turns the milestones
|
|
7
|
+
* {@link ./runstate!parseMilestones} produces into per-phase spans and aggregates.
|
|
8
|
+
*
|
|
9
|
+
* Pure and dependency-free — no `gh`, no network, no clock, no filesystem — so the
|
|
10
|
+
* arithmetic is unit-testable against fixture trails and the command layer only has to
|
|
11
|
+
* render what it returns.
|
|
12
|
+
*/
|
|
13
|
+
import { type ParsedMilestone } from './runstate';
|
|
14
|
+
/**
|
|
15
|
+
* The synthetic phase covering the gap between ship's two milestones — the PR is open and
|
|
16
|
+
* green-pending, and nothing is being worked on. It is reported separately because it is
|
|
17
|
+
* the one span in a run that measures waiting rather than working: folding it into `ship`
|
|
18
|
+
* would make ship's median a function of CI queue depth rather than of the work.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MERGE_WAIT_PHASE = "merge-wait";
|
|
21
|
+
/**
|
|
22
|
+
* Row order for aggregate tables: the protocol's phase order, with `merge-wait` sitting
|
|
23
|
+
* where it happens (between ship and report). Alphabetical order would read
|
|
24
|
+
* `gate, implement, merge-wait, plan, …`, which tells a reader nothing about a pipeline.
|
|
25
|
+
*/
|
|
26
|
+
export declare const STATS_PHASE_ORDER: readonly string[];
|
|
27
|
+
/** The bucket a run lands in when no milestone in the run carries a `model=` key. */
|
|
28
|
+
export declare const UNKNOWN_MODEL = "unknown";
|
|
29
|
+
/** The group a milestone lands in when it carries no `run=` id. */
|
|
30
|
+
export declare const UNKNOWN_RUN = "unknown-run";
|
|
31
|
+
/**
|
|
32
|
+
* Make a milestone-derived value safe to print.
|
|
33
|
+
*
|
|
34
|
+
* Control characters are the real hazard, not merely a cosmetic one: `parseMilestone` is
|
|
35
|
+
* deliberately tolerant and validates nothing but the marker, so `status=` or `model=` can
|
|
36
|
+
* carry ANSI escapes or a carriage return. Printed raw, those repaint or erase rows of the
|
|
37
|
+
* table an operator reads to decide whether a run succeeded. They also make `.length`
|
|
38
|
+
* disagree with the drawn width, which silently destroys column alignment.
|
|
39
|
+
*/
|
|
40
|
+
export declare function renderValue(value: string): string;
|
|
41
|
+
/** One phase span within a run: what ran, when it ended, and how long it took. */
|
|
42
|
+
export interface PhaseTiming {
|
|
43
|
+
/** Phase name, or {@link MERGE_WAIT_PHASE} for the gap between ship's two milestones. */
|
|
44
|
+
phase: string;
|
|
45
|
+
status: string;
|
|
46
|
+
/** The previous usable milestone's `at=`, or null when there is no measurable start. */
|
|
47
|
+
started_at: string | null;
|
|
48
|
+
/** This milestone's `at=`. */
|
|
49
|
+
ended_at: string;
|
|
50
|
+
/** Elapsed seconds, or null when `started_at` is null. May be negative under clock skew. */
|
|
51
|
+
seconds: number | null;
|
|
52
|
+
}
|
|
53
|
+
/** Every phase span of one run, plus what the whole run cost. */
|
|
54
|
+
export interface RunStats {
|
|
55
|
+
issue: number;
|
|
56
|
+
run: string;
|
|
57
|
+
/** The `model=` recorded by the run (see {@link modelOf}), or null. */
|
|
58
|
+
model: string | null;
|
|
59
|
+
phases: PhaseTiming[];
|
|
60
|
+
/** The last milestone's phase — how far the run actually got. */
|
|
61
|
+
last_phase: string;
|
|
62
|
+
/** The last milestone's status, so an in-flight or blocked run is recognisable. */
|
|
63
|
+
last_status: string;
|
|
64
|
+
/** First usable milestone's `at=`. */
|
|
65
|
+
started_at: string | null;
|
|
66
|
+
/** Last usable milestone's `at=`. */
|
|
67
|
+
ended_at: string | null;
|
|
68
|
+
/**
|
|
69
|
+
* `started_at` → `ended_at`, or null when the run has fewer than TWO usable milestones.
|
|
70
|
+
*
|
|
71
|
+
* One usable milestone is not a zero-length run — it is a run whose length is unknown,
|
|
72
|
+
* which is the normal state of anything still in flight. Reporting it as `0` would drag
|
|
73
|
+
* every median it feeds toward zero with a duration nobody measured.
|
|
74
|
+
*/
|
|
75
|
+
total_seconds: number | null;
|
|
76
|
+
}
|
|
77
|
+
/** Median/min/max over every sample of one phase across the selected runs. */
|
|
78
|
+
export interface PhaseAggregate {
|
|
79
|
+
phase: string;
|
|
80
|
+
/** Spans of this phase that had a measurable duration; unmeasurable ones are excluded. */
|
|
81
|
+
samples: number;
|
|
82
|
+
median_seconds: number;
|
|
83
|
+
min_seconds: number;
|
|
84
|
+
max_seconds: number;
|
|
85
|
+
/** Samples below zero, i.e. from clock skew — a median over these is not meaningful. */
|
|
86
|
+
negative_samples: number;
|
|
87
|
+
}
|
|
88
|
+
/** Per-`model=` view of whole-run totals — the point of recording `model=` at the gate. */
|
|
89
|
+
export interface ModelAggregate {
|
|
90
|
+
model: string;
|
|
91
|
+
runs: number;
|
|
92
|
+
/** Runs of this model whose total was measurable; the rest are excluded below. */
|
|
93
|
+
samples: number;
|
|
94
|
+
median_total_seconds: number | null;
|
|
95
|
+
min_total_seconds: number | null;
|
|
96
|
+
max_total_seconds: number | null;
|
|
97
|
+
negative_samples: number;
|
|
98
|
+
}
|
|
99
|
+
/** The two cross-run rollups: per-phase spread, and whole-run totals bucketed by model. */
|
|
100
|
+
export interface StatsAggregates {
|
|
101
|
+
phases: PhaseAggregate[];
|
|
102
|
+
models: ModelAggregate[];
|
|
103
|
+
}
|
|
104
|
+
/** An issue in the selection that could not be read at all, and why. */
|
|
105
|
+
export interface FailedIssue {
|
|
106
|
+
issue: number;
|
|
107
|
+
error: string;
|
|
108
|
+
}
|
|
109
|
+
/** Everything `runstate stats` needs to render, for one issue or many. */
|
|
110
|
+
export interface StatsReport {
|
|
111
|
+
/** The repository the trails were read from, when the caller named one. */
|
|
112
|
+
repo: string | null;
|
|
113
|
+
issues: number[];
|
|
114
|
+
runs: RunStats[];
|
|
115
|
+
aggregates: StatsAggregates;
|
|
116
|
+
/** Issues in the selection whose trail had no runstate milestones at all. */
|
|
117
|
+
issues_without_trail: number[];
|
|
118
|
+
/** Issues that could not be read — distinct from an issue that simply has no trail. */
|
|
119
|
+
issues_failed: FailedIssue[];
|
|
120
|
+
/** Degraded reads: skipped milestones, clock skew, missing run ids. */
|
|
121
|
+
warnings: string[];
|
|
122
|
+
}
|
|
123
|
+
/** True when `value` is a timestamp this module will measure against. */
|
|
124
|
+
export declare function isUsableTimestamp(value: string): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Median of a non-empty numeric list, rounded to whole seconds.
|
|
127
|
+
*
|
|
128
|
+
* Even counts average the two middle values — stated because the other convention (lower
|
|
129
|
+
* middle) is equally common and the difference shows up in exactly the small sample sizes
|
|
130
|
+
* these trails produce.
|
|
131
|
+
*
|
|
132
|
+
* @throws when `values` is empty — an empty median is `NaN`, which renders as a
|
|
133
|
+
* plausible-looking `NaN (NaNs)` cell rather than announcing itself.
|
|
134
|
+
*/
|
|
135
|
+
export declare function median(values: number[]): number;
|
|
136
|
+
/** One issue's trail, as the command layer hands it to {@link buildStatsReport}. */
|
|
137
|
+
export interface IssueTrail {
|
|
138
|
+
issue: number;
|
|
139
|
+
milestones: ParsedMilestone[];
|
|
140
|
+
}
|
|
141
|
+
/** One aggregate row's skew note, or null when every sample was forwards. */
|
|
142
|
+
export declare function skewNote(negativeSamples: number): string | null;
|
|
143
|
+
export interface StatsInput {
|
|
144
|
+
trails: IssueTrail[];
|
|
145
|
+
/** Issues that could not be read at all. */
|
|
146
|
+
failed?: FailedIssue[];
|
|
147
|
+
/** The repository the trails came from, for unambiguous issue references. */
|
|
148
|
+
repo?: string;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Build the whole report from already-fetched trails.
|
|
152
|
+
*
|
|
153
|
+
* Takes trails rather than issue numbers so every rule here — grouping, pairing, skipping,
|
|
154
|
+
* aggregating — is testable against fixture milestones without a `gh` in sight.
|
|
155
|
+
*/
|
|
156
|
+
export declare function buildStatsReport(input: StatsInput): StatsReport;
|
|
157
|
+
//# sourceMappingURL=runstate-stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runstate-stats.d.ts","sourceRoot":"","sources":["../src/runstate-stats.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,KAAK,eAAe,EAAmC,MAAM,YAAY,CAAC;AAEnF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAa7C;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAG3C,CAAC;AAEL,qFAAqF;AACrF,eAAO,MAAM,aAAa,YAAY,CAAC;AAEvC,mEAAmE;AACnE,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAgCzC;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,yFAAyF;IACzF,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,iEAAiE;AACjE,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,WAAW,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;IAChB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,2FAA2F;AAC3F,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,UAAU,EAAE,eAAe,CAAC;IAC5B,6EAA6E;IAC7E,oBAAoB,EAAE,MAAM,EAAE,CAAC;IAC/B,uFAAuF;IACvF,aAAa,EAAE,WAAW,EAAE,CAAC;IAC7B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAIxD;AAOD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAO/C;AAYD,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAqMD,6EAA6E;AAC7E,wBAAgB,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/D;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,WAAW,EAAE,CAAC;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CA+C/D"}
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Timing analysis over `runstate:v1` milestone trails.
|
|
4
|
+
*
|
|
5
|
+
* Every milestone already stamps `at=`, so a run's per-phase durations are latent in the
|
|
6
|
+
* trail the moment it is written — nothing needs to be measured, stored, or timed at run
|
|
7
|
+
* time. This module is the read side of that decision: it turns the milestones
|
|
8
|
+
* {@link ./runstate!parseMilestones} produces into per-phase spans and aggregates.
|
|
9
|
+
*
|
|
10
|
+
* Pure and dependency-free — no `gh`, no network, no clock, no filesystem — so the
|
|
11
|
+
* arithmetic is unit-testable against fixture trails and the command layer only has to
|
|
12
|
+
* render what it returns.
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.UNKNOWN_RUN = exports.UNKNOWN_MODEL = exports.STATS_PHASE_ORDER = exports.MERGE_WAIT_PHASE = void 0;
|
|
16
|
+
exports.renderValue = renderValue;
|
|
17
|
+
exports.isUsableTimestamp = isUsableTimestamp;
|
|
18
|
+
exports.median = median;
|
|
19
|
+
exports.skewNote = skewNote;
|
|
20
|
+
exports.buildStatsReport = buildStatsReport;
|
|
21
|
+
const duration_1 = require("./duration");
|
|
22
|
+
const runstate_1 = require("./runstate");
|
|
23
|
+
/**
|
|
24
|
+
* The synthetic phase covering the gap between ship's two milestones — the PR is open and
|
|
25
|
+
* green-pending, and nothing is being worked on. It is reported separately because it is
|
|
26
|
+
* the one span in a run that measures waiting rather than working: folding it into `ship`
|
|
27
|
+
* would make ship's median a function of CI queue depth rather than of the work.
|
|
28
|
+
*/
|
|
29
|
+
exports.MERGE_WAIT_PHASE = 'merge-wait';
|
|
30
|
+
/**
|
|
31
|
+
* Phase and status literals this module branches on.
|
|
32
|
+
*
|
|
33
|
+
* Annotated with the protocol's own types so a rename in {@link ./runstate!PHASES} or
|
|
34
|
+
* {@link ./runstate!STATUSES} fails the build here, rather than silently switching off
|
|
35
|
+
* merge-wait detection and the `model=` lookup — the two things this module exists for.
|
|
36
|
+
*/
|
|
37
|
+
const SHIP_PHASE = 'ship';
|
|
38
|
+
const GATE_PHASE = 'gate';
|
|
39
|
+
const AWAITING_MERGE = 'awaiting-merge';
|
|
40
|
+
/**
|
|
41
|
+
* Row order for aggregate tables: the protocol's phase order, with `merge-wait` sitting
|
|
42
|
+
* where it happens (between ship and report). Alphabetical order would read
|
|
43
|
+
* `gate, implement, merge-wait, plan, …`, which tells a reader nothing about a pipeline.
|
|
44
|
+
*/
|
|
45
|
+
exports.STATS_PHASE_ORDER = (() => {
|
|
46
|
+
const shipIdx = runstate_1.PHASES.indexOf(SHIP_PHASE);
|
|
47
|
+
return [...runstate_1.PHASES.slice(0, shipIdx + 1), exports.MERGE_WAIT_PHASE, ...runstate_1.PHASES.slice(shipIdx + 1)];
|
|
48
|
+
})();
|
|
49
|
+
/** The bucket a run lands in when no milestone in the run carries a `model=` key. */
|
|
50
|
+
exports.UNKNOWN_MODEL = 'unknown';
|
|
51
|
+
/** The group a milestone lands in when it carries no `run=` id. */
|
|
52
|
+
exports.UNKNOWN_RUN = 'unknown-run';
|
|
53
|
+
/**
|
|
54
|
+
* `at=` values that a shell was supposed to expand and did not.
|
|
55
|
+
*
|
|
56
|
+
* Milestones written before the `runstate post` CLI existed were heredocs, and agents
|
|
57
|
+
* pasted `at=$(date -u +%Y-%m-%dT%H:%M:%SZ)` verbatim often enough that real trails carry
|
|
58
|
+
* it (`imboard-ai/imboard-monorepo#3684`). The class also covers backticks, the other
|
|
59
|
+
* shell-substitution form: `post` rejects `$` outright so no new milestone can carry one,
|
|
60
|
+
* and a backtick is treated the same here defensively.
|
|
61
|
+
*/
|
|
62
|
+
const UNEXPANDED_RE = /[$`]/;
|
|
63
|
+
/**
|
|
64
|
+
* A timestamp we are willing to do arithmetic on: ISO-8601 to at least seconds, UTC or
|
|
65
|
+
* with an explicit offset. Deliberately stricter than `Date.parse`, which accepts
|
|
66
|
+
* `"phase"` as a date on some engines and would hand back a plausible-looking NaN chain.
|
|
67
|
+
*/
|
|
68
|
+
const TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$/;
|
|
69
|
+
/**
|
|
70
|
+
* Longest a milestone-derived value may be once it reaches a table cell or a warning.
|
|
71
|
+
*
|
|
72
|
+
* Every `key=value` in a trail is remote data — anyone who can comment on the issue can
|
|
73
|
+
* post something shaped like a milestone — so an untruncated value is a 65 KB comment
|
|
74
|
+
* pasted into an operator's terminal.
|
|
75
|
+
*/
|
|
76
|
+
const MAX_CELL_LENGTH = 120;
|
|
77
|
+
/** The replacement drawn in place of a control character. */
|
|
78
|
+
const CONTROL_REPLACEMENT = '�';
|
|
79
|
+
/**
|
|
80
|
+
* Make a milestone-derived value safe to print.
|
|
81
|
+
*
|
|
82
|
+
* Control characters are the real hazard, not merely a cosmetic one: `parseMilestone` is
|
|
83
|
+
* deliberately tolerant and validates nothing but the marker, so `status=` or `model=` can
|
|
84
|
+
* carry ANSI escapes or a carriage return. Printed raw, those repaint or erase rows of the
|
|
85
|
+
* table an operator reads to decide whether a run succeeded. They also make `.length`
|
|
86
|
+
* disagree with the drawn width, which silently destroys column alignment.
|
|
87
|
+
*/
|
|
88
|
+
function renderValue(value) {
|
|
89
|
+
let clean = '';
|
|
90
|
+
for (const char of value) {
|
|
91
|
+
const code = char.codePointAt(0) ?? 0;
|
|
92
|
+
clean += code < 0x20 || code === 0x7f ? CONTROL_REPLACEMENT : char;
|
|
93
|
+
}
|
|
94
|
+
return clean.length > MAX_CELL_LENGTH ? `${clean.slice(0, MAX_CELL_LENGTH)}…` : clean;
|
|
95
|
+
}
|
|
96
|
+
/** True when `value` is a timestamp this module will measure against. */
|
|
97
|
+
function isUsableTimestamp(value) {
|
|
98
|
+
if (value === '' || UNEXPANDED_RE.test(value))
|
|
99
|
+
return false;
|
|
100
|
+
if (!TIMESTAMP_RE.test(value))
|
|
101
|
+
return false;
|
|
102
|
+
return !Number.isNaN(Date.parse(value));
|
|
103
|
+
}
|
|
104
|
+
/** Whole seconds from `from` to `to`. Callers guarantee both are usable timestamps. */
|
|
105
|
+
function elapsedSeconds(from, to) {
|
|
106
|
+
return Math.round((Date.parse(to) - Date.parse(from)) / duration_1.MILLIS_PER_SECOND);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Median of a non-empty numeric list, rounded to whole seconds.
|
|
110
|
+
*
|
|
111
|
+
* Even counts average the two middle values — stated because the other convention (lower
|
|
112
|
+
* middle) is equally common and the difference shows up in exactly the small sample sizes
|
|
113
|
+
* these trails produce.
|
|
114
|
+
*
|
|
115
|
+
* @throws when `values` is empty — an empty median is `NaN`, which renders as a
|
|
116
|
+
* plausible-looking `NaN (NaNs)` cell rather than announcing itself.
|
|
117
|
+
*/
|
|
118
|
+
function median(values) {
|
|
119
|
+
if (values.length === 0) {
|
|
120
|
+
throw new Error('median() requires at least one sample');
|
|
121
|
+
}
|
|
122
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
123
|
+
const mid = Math.floor(sorted.length / 2);
|
|
124
|
+
return sorted.length % 2 === 1 ? sorted[mid] : Math.round((sorted[mid - 1] + sorted[mid]) / 2);
|
|
125
|
+
}
|
|
126
|
+
/** Smallest value, folded rather than spread — see {@link ./table!renderTable}. */
|
|
127
|
+
function minOf(values) {
|
|
128
|
+
return values.reduce((a, b) => (b < a ? b : a));
|
|
129
|
+
}
|
|
130
|
+
/** Largest value, folded rather than spread. */
|
|
131
|
+
function maxOf(values) {
|
|
132
|
+
return values.reduce((a, b) => (b > a ? b : a));
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Group an issue's milestones by `run=`, preserving first-seen run order and, within each
|
|
136
|
+
* run, the order the milestones were appended in.
|
|
137
|
+
*
|
|
138
|
+
* Grouping is the only reordering done. A resumed run keeps its id, so its milestones can
|
|
139
|
+
* appear in the comment stream interleaved with another run's, and pairing across that
|
|
140
|
+
* boundary would attribute one run's wait to another run's phase.
|
|
141
|
+
*
|
|
142
|
+
* Within a run, comment order is left alone rather than sorted by `at=`. The trail is
|
|
143
|
+
* append-only, so comment order IS the causal order — whereas `at=` is stamped by whichever
|
|
144
|
+
* machine ran the phase. Sorting on it would silently reorder two phases whose clocks
|
|
145
|
+
* disagree, turning skew into a plausible-looking sequence; leaving it alone surfaces the
|
|
146
|
+
* skew as a negative duration and a warning, which is a problem someone can act on.
|
|
147
|
+
*/
|
|
148
|
+
function groupByRun(milestones) {
|
|
149
|
+
const groups = new Map();
|
|
150
|
+
for (const milestone of milestones) {
|
|
151
|
+
const key = milestone.run || exports.UNKNOWN_RUN;
|
|
152
|
+
const group = groups.get(key);
|
|
153
|
+
if (group)
|
|
154
|
+
group.push(milestone);
|
|
155
|
+
else
|
|
156
|
+
groups.set(key, [milestone]);
|
|
157
|
+
}
|
|
158
|
+
return groups;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* The phase name a milestone is reported under.
|
|
162
|
+
*
|
|
163
|
+
* A `ship` milestone that follows ship's `awaiting-merge` is the far side of the CI +
|
|
164
|
+
* merge wait, so it is relabelled — the row measures the wait, not a second ship.
|
|
165
|
+
*/
|
|
166
|
+
function phaseNameFor(milestone, previous) {
|
|
167
|
+
const followsAwaitingMerge = previous !== null && previous.phase === SHIP_PHASE && previous.status === AWAITING_MERGE;
|
|
168
|
+
return milestone.phase === SHIP_PHASE && followsAwaitingMerge
|
|
169
|
+
? exports.MERGE_WAIT_PHASE
|
|
170
|
+
: milestone.phase;
|
|
171
|
+
}
|
|
172
|
+
/** Where an issue reference in a warning comes from, so `--repo` is not lost. */
|
|
173
|
+
function issueRef(repo, issue) {
|
|
174
|
+
return repo ? `${repo}#${issue}` : `#${issue}`;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Turn one run's milestones into phase spans.
|
|
178
|
+
*
|
|
179
|
+
* Each milestone is paired with the previous **usable** one. A milestone whose `at=` cannot
|
|
180
|
+
* be read is dropped AND breaks the chain: pairing across the hole would report a single
|
|
181
|
+
* duration silently covering two phases, which reads as a real measurement. The row after a
|
|
182
|
+
* break is `-`, and the warning says which milestone caused it.
|
|
183
|
+
*/
|
|
184
|
+
function timePhases(repo, issue, run, milestones, warn) {
|
|
185
|
+
const phases = [];
|
|
186
|
+
let previous = null;
|
|
187
|
+
let firstAt = null;
|
|
188
|
+
let lastAt = null;
|
|
189
|
+
let usable = 0;
|
|
190
|
+
const where = `issue ${issueRef(repo, issue)} run ${renderValue(run)}`;
|
|
191
|
+
for (const milestone of milestones) {
|
|
192
|
+
const phase = phaseNameFor(milestone, previous);
|
|
193
|
+
if (!isUsableTimestamp(milestone.at)) {
|
|
194
|
+
warn(`${where}: ${renderValue(milestone.phase) || '(no phase)'} milestone has an unusable at= value ('${renderValue(milestone.at) || '(empty)'}') — skipped, and the next phase's duration is reported as unknown`);
|
|
195
|
+
previous = null;
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const startedAt = previous === null ? null : previous.at;
|
|
199
|
+
const seconds = startedAt === null ? null : elapsedSeconds(startedAt, milestone.at);
|
|
200
|
+
if (seconds !== null && seconds < 0) {
|
|
201
|
+
warn(`${where}: ${renderValue(phase)} ended before it started (${startedAt} → ${milestone.at}) — reported as a negative duration; the milestones were stamped by clocks that disagree`);
|
|
202
|
+
}
|
|
203
|
+
phases.push({
|
|
204
|
+
phase,
|
|
205
|
+
status: milestone.status,
|
|
206
|
+
started_at: startedAt,
|
|
207
|
+
ended_at: milestone.at,
|
|
208
|
+
seconds,
|
|
209
|
+
});
|
|
210
|
+
if (firstAt === null)
|
|
211
|
+
firstAt = milestone.at;
|
|
212
|
+
lastAt = milestone.at;
|
|
213
|
+
usable += 1;
|
|
214
|
+
previous = milestone;
|
|
215
|
+
}
|
|
216
|
+
const last = milestones[milestones.length - 1];
|
|
217
|
+
return {
|
|
218
|
+
issue,
|
|
219
|
+
run,
|
|
220
|
+
model: modelOf(milestones),
|
|
221
|
+
phases,
|
|
222
|
+
last_phase: last?.phase ?? '',
|
|
223
|
+
last_status: last?.status ?? '',
|
|
224
|
+
started_at: firstAt,
|
|
225
|
+
ended_at: lastAt,
|
|
226
|
+
// Two usable milestones are the minimum that bounds a span at both ends.
|
|
227
|
+
total_seconds: usable >= 2 && firstAt !== null && lastAt !== null ? elapsedSeconds(firstAt, lastAt) : null,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* The run's `model=`, taken from its gate milestone.
|
|
232
|
+
*
|
|
233
|
+
* Only the gate is asked to record it (`imboard-ai/git/gate-issue` from 1.4.1 onward — the
|
|
234
|
+
* `examples/` copy in this repo predates the key), and only that one is authoritative. But
|
|
235
|
+
* a resumed run's later phases may have executed on a different agent, so any milestone
|
|
236
|
+
* carrying the key is accepted as a fallback rather than reporting `unknown` for a trail
|
|
237
|
+
* that plainly names its model.
|
|
238
|
+
*/
|
|
239
|
+
function modelOf(milestones) {
|
|
240
|
+
const gate = milestones.find((m) => m.phase === GATE_PHASE && m.keys.model);
|
|
241
|
+
if (gate)
|
|
242
|
+
return gate.keys.model;
|
|
243
|
+
return milestones.find((m) => m.keys.model)?.keys.model ?? null;
|
|
244
|
+
}
|
|
245
|
+
/** Per-phase median/min/max across every run in the report. */
|
|
246
|
+
function aggregatePhases(runs) {
|
|
247
|
+
const samples = new Map();
|
|
248
|
+
for (const run of runs) {
|
|
249
|
+
for (const phase of run.phases) {
|
|
250
|
+
if (phase.seconds === null)
|
|
251
|
+
continue;
|
|
252
|
+
const list = samples.get(phase.phase);
|
|
253
|
+
if (list)
|
|
254
|
+
list.push(phase.seconds);
|
|
255
|
+
else
|
|
256
|
+
samples.set(phase.phase, [phase.seconds]);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
return [...samples.entries()]
|
|
260
|
+
.map(([phase, values]) => ({
|
|
261
|
+
phase,
|
|
262
|
+
samples: values.length,
|
|
263
|
+
median_seconds: median(values),
|
|
264
|
+
min_seconds: minOf(values),
|
|
265
|
+
max_seconds: maxOf(values),
|
|
266
|
+
negative_samples: values.filter((v) => v < 0).length,
|
|
267
|
+
}))
|
|
268
|
+
.sort(byStatsPhaseOrder);
|
|
269
|
+
}
|
|
270
|
+
/** Protocol phase order, with anything unrecognised sorted alphabetically after it. */
|
|
271
|
+
function byStatsPhaseOrder(a, b) {
|
|
272
|
+
const ai = exports.STATS_PHASE_ORDER.indexOf(a.phase);
|
|
273
|
+
const bi = exports.STATS_PHASE_ORDER.indexOf(b.phase);
|
|
274
|
+
if (ai !== -1 && bi !== -1)
|
|
275
|
+
return ai - bi;
|
|
276
|
+
if (ai !== -1)
|
|
277
|
+
return -1;
|
|
278
|
+
if (bi !== -1)
|
|
279
|
+
return 1;
|
|
280
|
+
return a.phase.localeCompare(b.phase);
|
|
281
|
+
}
|
|
282
|
+
/** Whole-run totals bucketed by `model=`, so runs become comparable across models. */
|
|
283
|
+
function aggregateModels(runs) {
|
|
284
|
+
const buckets = new Map();
|
|
285
|
+
for (const run of runs) {
|
|
286
|
+
const key = run.model ?? exports.UNKNOWN_MODEL;
|
|
287
|
+
const bucket = buckets.get(key) ?? { runs: 0, totals: [] };
|
|
288
|
+
bucket.runs += 1;
|
|
289
|
+
if (run.total_seconds !== null)
|
|
290
|
+
bucket.totals.push(run.total_seconds);
|
|
291
|
+
buckets.set(key, bucket);
|
|
292
|
+
}
|
|
293
|
+
return [...buckets.entries()]
|
|
294
|
+
.map(([model, bucket]) => {
|
|
295
|
+
const measured = bucket.totals.length > 0;
|
|
296
|
+
return {
|
|
297
|
+
model,
|
|
298
|
+
runs: bucket.runs,
|
|
299
|
+
samples: bucket.totals.length,
|
|
300
|
+
median_total_seconds: measured ? median(bucket.totals) : null,
|
|
301
|
+
min_total_seconds: measured ? minOf(bucket.totals) : null,
|
|
302
|
+
max_total_seconds: measured ? maxOf(bucket.totals) : null,
|
|
303
|
+
negative_samples: bucket.totals.filter((v) => v < 0).length,
|
|
304
|
+
};
|
|
305
|
+
})
|
|
306
|
+
.sort((a, b) => a.model.localeCompare(b.model));
|
|
307
|
+
}
|
|
308
|
+
/** One aggregate row's skew note, or null when every sample was forwards. */
|
|
309
|
+
function skewNote(negativeSamples) {
|
|
310
|
+
if (negativeSamples === 0)
|
|
311
|
+
return null;
|
|
312
|
+
return `${negativeSamples} skewed`;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Build the whole report from already-fetched trails.
|
|
316
|
+
*
|
|
317
|
+
* Takes trails rather than issue numbers so every rule here — grouping, pairing, skipping,
|
|
318
|
+
* aggregating — is testable against fixture milestones without a `gh` in sight.
|
|
319
|
+
*/
|
|
320
|
+
function buildStatsReport(input) {
|
|
321
|
+
const { trails, failed = [], repo = null } = input;
|
|
322
|
+
// Counted rather than de-duplicated: two milestones skipped for the same reason produce
|
|
323
|
+
// byte-identical warnings, and collapsing them makes an operator under-count what was
|
|
324
|
+
// dropped. The Map also keeps this linear — `Array.includes` per warning is O(n²) over
|
|
325
|
+
// remote data, i.e. over however many comments anyone chose to post.
|
|
326
|
+
const counts = new Map();
|
|
327
|
+
const warn = (line) => counts.set(line, (counts.get(line) ?? 0) + 1);
|
|
328
|
+
const runs = [];
|
|
329
|
+
const withoutTrail = [];
|
|
330
|
+
for (const trail of trails) {
|
|
331
|
+
if (trail.milestones.length === 0) {
|
|
332
|
+
withoutTrail.push(trail.issue);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
for (const [run, milestones] of groupByRun(trail.milestones)) {
|
|
336
|
+
if (run === exports.UNKNOWN_RUN) {
|
|
337
|
+
warn(`issue ${issueRef(repo, trail.issue)}: ${milestones.length} milestone(s) carry no run= id — grouped together as '${exports.UNKNOWN_RUN}', so their durations may span unrelated runs`);
|
|
338
|
+
}
|
|
339
|
+
runs.push(timePhases(repo, trail.issue, run, milestones, warn));
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const phases = aggregatePhases(runs);
|
|
343
|
+
const models = aggregateModels(runs);
|
|
344
|
+
for (const phase of phases) {
|
|
345
|
+
if (phase.negative_samples > 0) {
|
|
346
|
+
warn(`aggregate for phase '${renderValue(phase.phase)}' includes ${phase.negative_samples} negative sample(s) from clock skew — its median and min are not meaningful`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
repo,
|
|
351
|
+
issues: trails.map((t) => t.issue),
|
|
352
|
+
runs,
|
|
353
|
+
aggregates: { phases, models },
|
|
354
|
+
issues_without_trail: withoutTrail,
|
|
355
|
+
issues_failed: failed,
|
|
356
|
+
warnings: [...counts.entries()].map(([line, n]) => (n > 1 ? `${line} (×${n})` : line)),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
//# sourceMappingURL=runstate-stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runstate-stats.js","sourceRoot":"","sources":["../src/runstate-stats.ts"],"names":[],"mappings":"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"}
|