@cassiomc1/forgeloop 1.7.0 → 1.8.1

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/DOCS_INDEX.md CHANGED
@@ -30,7 +30,7 @@ integration and guide context. Use this map before editing documentation.
30
30
  | Platform adapters | [`docs/PLATFORM_ADAPTERS.md`](./docs/PLATFORM_ADAPTERS.md) | Generic CI boundary and platform mapping guidance |
31
31
  | Universal integration API | [`docs/UNIVERSAL_INTEGRATION.md`](./docs/UNIVERSAL_INTEGRATION.md) | Programmatic integration subpath, envelope semantics, and consumer map |
32
32
  | Local-first MCP adapter | [`docs/MCP.md`](./docs/MCP.md) | stdio default, optional strict loopback HTTP; server modes/capabilities and canonical resources |
33
- | Adaptive execution-profile benchmarks | [`docs/EXECUTION_PROFILE_BENCHMARKS.md`](./docs/EXECUTION_PROFILE_BENCHMARKS.md) | Measured provider/host runs, comparability, aggregates, and profile-aware host context |
33
+ | Adaptive execution-profile benchmarks | [`docs/EXECUTION_PROFILE_BENCHMARKS.md`](./docs/EXECUTION_PROFILE_BENCHMARKS.md) | Measured provider/host runs, robust statistics, paired/distribution deltas, tail status, outliers, and profile-aware host context |
34
34
  | Documentation guide | [`docs/DOCUMENTATION_GUIDE.md`](./docs/DOCUMENTATION_GUIDE.md) | Rules and checklist for modifying documentation |
35
35
  | Current release checklist | [`docs/RELEASE_CHECKLIST.md`](./docs/RELEASE_CHECKLIST.md) | Package, protocol, attestation, integration, and publication gates |
36
36
  | ForgeLoop 1.6.1 release checklist (historical) | [`docs/RELEASE_CHECKLIST_1_6_1.md`](./docs/RELEASE_CHECKLIST_1_6_1.md) | Verification adapter boundary, isolation invariants, and publication gates |
@@ -42,3 +42,21 @@ Initial non-blocking efficiency goals for LIGHT scenarios are P50 token
42
42
  overhead of at most +35% and P95 token overhead of at most +60% against a
43
43
  comparable direct baseline. These are benchmark objectives, not completion
44
44
  rules, and quality or verification coverage may not be traded for them.
45
+
46
+ Raw runs may carry an optional `diagnostics` object with host-observed
47
+ execution detail (model turns, tool calls, retries, correction cycles, files
48
+ written, guide selections, termination reason, runaway-signal flags). Every
49
+ field is nullable; never estimate a value the host does not actually report.
50
+
51
+ Benchmark methodology v2 (`benchmarkVersion: "2"`) adds robust variability
52
+ statistics (median, quartiles, IQR, MAD), per-comparison tail stability
53
+ status, and deterministic token-outlier classification under the
54
+ `TOKEN_IQR_1_5` policy. Runner repetitions are bounded by explicit tiers:
55
+ `smoke` (1–3), `evidence` (5–10), and `tail` (20–30). Tail conclusions
56
+ require at least 20 comparable pairs.
57
+
58
+ Methodology versioning protects history: readers accept benchmark versions
59
+ `1` and `2`, historical v1 run sets are never rewritten, and their stored
60
+ aggregates reproduce byte-for-byte under the frozen v1 methodology. All of
61
+ these diagnostics are observational and never change lifecycle truth,
62
+ required gates, verification validity, or completion authority.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "api-feature",
5
5
  "description": "Ordinary API behavior change without authentication or publication authority.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "authentication-change",
5
5
  "description": "Authentication behavior change crossing a trust boundary.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "documentation-correction",
5
5
  "description": "Narrow documentation correction with no executable behavior or sensitive content.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "infrastructure-release",
5
5
  "description": "Infrastructure or release/publication work with external and potentially irreversible effects.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "novatask-saas-landing-page",
5
5
  "description": "NovaTask reference workload: a local static SaaS landing page with no external or sensitive boundary.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "small-bug-fix",
5
5
  "description": "Small application bug fix with behavior implications and focused regression checks.",
6
6
  "input": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "benchmarkVersion": "1",
3
+ "benchmarkVersion": "2",
4
4
  "scenarioId": "static-landing-page",
5
5
  "description": "Small local HTML, CSS, and JavaScript landing page without external services or sensitive boundaries.",
6
6
  "input": {
@@ -7,7 +7,7 @@
7
7
  ForgeLoop is a portable protocol and support CLI for verifiable engineering workflows. It records and validates task state, contracts, routing, checks, evidence, continuity, and optional code attestations. It does not become an agent scheduler, delegation service, source-control authority, or secret manager.
8
8
 
9
9
  Protocol version: 1
10
- Package version: 1.7.0
10
+ Package version: 1.8.1
11
11
 
12
12
  ## Canonical loop
13
13
 
@@ -56,6 +56,20 @@ npm run benchmark:profiles -- \
56
56
  --json
57
57
  ```
58
58
 
59
+ Repetition counts are bounded by an explicit tier so the statistical purpose
60
+ of a run set is visible in the command itself:
61
+
62
+ | Tier | Runs | Purpose |
63
+ | --- | --- | --- |
64
+ | `smoke` | 1–3 | Fast adapter and pipeline checks; never efficiency evidence. |
65
+ | `evidence` | 5–10 | Central-tendency comparisons (default when no tier is given: 5 runs). |
66
+ | `tail` | 20–30 | Tail-risk and P95 stability analysis. |
67
+
68
+ `--tier smoke|evidence|tail` enforces these bounds and selects the tier
69
+ default when `--runs` is omitted. Runs outside a tier's bounds are rejected.
70
+ Tail-stability conclusions additionally require the sample minimum described
71
+ under tail analysis below.
72
+
59
73
  The adapter exports `runBenchmark(input)` and must execute the supplied
60
74
  scenario. Its result must include actual usage and verification data:
61
75
 
@@ -78,6 +92,22 @@ export async function runBenchmark({ scenario, mode, runIndex, target }) {
78
92
  verification: "PASS",
79
93
  verificationCycles: 1,
80
94
  comparableSteps: 4,
95
+ diagnostics: {
96
+ executionProfile: "light",
97
+ verificationCycles: 1,
98
+ modelTurns: 3,
99
+ toolCalls: 5,
100
+ retries: null,
101
+ correctionCycles: null,
102
+ filesRead: null,
103
+ filesWritten: 2,
104
+ contextRefreshes: null,
105
+ guideCount: 1,
106
+ guideIds: ["test"],
107
+ hostWarnings: [],
108
+ terminationReason: "COMPLETED",
109
+ flags: [],
110
+ },
81
111
  };
82
112
  }
83
113
  ```
@@ -88,6 +118,14 @@ measurement and derives the Git revision from the target checkout. Results
88
118
  are written under a unique run-set directory and existing history is never
89
119
  overwritten.
90
120
 
121
+ The optional `diagnostics` object records host-observed execution detail for
122
+ tail-risk attribution. Every field is nullable: a host must leave a value
123
+ `null` (or omit `diagnostics` entirely) whenever it does not actually observe
124
+ that telemetry, and must never estimate it from prompt size, elapsed time, or
125
+ file size. `flags` may carry host-reported runaway signals from the fixed
126
+ signal vocabulary; the aggregate additionally derives deterministic signals
127
+ where recorded diagnostics support them.
128
+
91
129
  An adapter may also return host-observed context usage. ForgeLoop does not
92
130
  tokenize provider prompts. The optional shape is:
93
131
 
@@ -136,13 +174,76 @@ host observation is available. Implementer self-ratings should not be used as
136
174
  independent quality evidence; for NovaTask, review direct and ForgeLoop
137
175
  outputs blind to execution mode before revealing the labels.
138
176
 
177
+ ## Blind UI quality finalization
178
+
179
+ The runner supports an optional post-run finalization hook for adapters that
180
+ can collect independent UI evidence:
181
+
182
+ ```js
183
+ export async function finalizeBenchmark({ benchmarkVersion, records, scenarios, target, runSetId }) {
184
+ // Render and evaluate retained UI workspaces after all host timings finish.
185
+ return {
186
+ qualityByRunId: {
187
+ // Keys are the runner-owned run IDs; values use the quality shape above.
188
+ },
189
+ summary: { status: "MEASURED" },
190
+ };
191
+ }
192
+ ```
193
+
194
+ The runner calls this hook only after every `runBenchmark` call has returned.
195
+ The adapter's `wallClockMs` therefore excludes browser rendering and evaluator
196
+ latency. The finalizer may attach quality only to known runner run IDs; usage,
197
+ timing, verification, comparable steps, context telemetry, and metadata are
198
+ not rewritten by finalization. A finalizer must leave quality `UNKNOWN` when a
199
+ candidate cannot be rendered or the evaluator cannot return schema-valid
200
+ scores.
201
+
202
+ The maintained Codex visual evaluator is intentionally outside ForgeLoop
203
+ Core. It requires an explicitly supplied, already-installed Playwright runtime
204
+ and Chromium executable, renders desktop (1440×900) and mobile (390×844)
205
+ screenshots, blocks HTTP(S) requests, and gives the separate evaluator only
206
+ requirements, neutral browser observations, and anonymized candidate labels.
207
+ The evaluator receives no execution-mode labels, run IDs, source files, or
208
+ implementer self-ratings. Its validated scores are recorded as
209
+ `EXTERNAL_REPORTED`; this is independent observational evidence, not a human
210
+ acceptance decision and not lifecycle authority. If the evaluator is not
211
+ configured or fails, quality remains `UNKNOWN` and no quality-preservation
212
+ claim is permitted.
213
+
139
214
  ## Inspecting and validating results
140
215
 
141
216
  ```bash
142
217
  npm run benchmark:profiles:summary -- --json
143
218
  npm run benchmark:profiles:check -- --json
219
+ npm run benchmark:profiles:outliers -- --json
144
220
  ```
145
221
 
222
+ To enable the optional blind UI finalizer, provide paths to the host's
223
+ existing Playwright and Chromium installations and a separate evaluator
224
+ model. The benchmark does not install these resources:
225
+
226
+ ```bash
227
+ FORGELOOP_BENCHMARK_MODEL=gpt-5.4-mini \
228
+ FORGELOOP_BENCHMARK_REASONING=low \
229
+ FORGELOOP_BENCHMARK_QUALITY_EVALUATOR=./benchmarks/evaluators/codex-cli-blind-visual.mjs \
230
+ FORGELOOP_BENCHMARK_PLAYWRIGHT_ROOT=/absolute/path/to/playwright \
231
+ FORGELOOP_BENCHMARK_BROWSER=/absolute/path/to/Google\ Chrome\ for\ Testing \
232
+ FORGELOOP_BENCHMARK_EVALUATOR_MODEL=gpt-5.4 \
233
+ npm run benchmark:profiles -- \
234
+ --adapter ./benchmarks/adapters/codex-cli-real-host.mjs \
235
+ --runs 5 \
236
+ --run-set codex-quality-repeat5-YYYYMMDD \
237
+ --output /tmp/forgeloop-benchmark-results-quality \
238
+ --json
239
+ ```
240
+
241
+ The two evaluator processes have separate responsibilities: the
242
+ implementation host reports actual usage and deterministic verification, and
243
+ the read-only evaluator reports blind screenshot scores. Neither process may
244
+ invent context-item counts, token counts, costs, cache values, or lifecycle
245
+ state.
246
+
146
247
  Before a host run exists, the summary is intentionally:
147
248
 
148
249
  ```json
@@ -154,9 +255,12 @@ Before a host run exists, the summary is intentionally:
154
255
 
155
256
  Raw runs are stored below `benchmarks/execution-profiles/results/raw/` and
156
257
  recomputed aggregates below `benchmarks/execution-profiles/results/aggregate/`.
157
- The validator checks all scenario, raw-run, and aggregate schemas and
158
- recomputes aggregates from raw measurements. A changed overhead target is
159
- observable in the report; it is not a blocking lifecycle gate.
258
+ Those recorded measurements are repository evidence and are intentionally not
259
+ included in the core npm package. The package ships the deterministic scenario
260
+ definitions and benchmark schemas needed to run a new measurement; the
261
+ validator checks all scenario, raw-run, and aggregate schemas and recomputes
262
+ aggregates from raw measurements. A changed overhead target is observable in
263
+ the report; it is not a blocking lifecycle gate.
160
264
 
161
265
  CI can run `npm run benchmark:profiles:regression -- --json`. It reports
162
266
  `OK`, `EFFICIENCY_REGRESSION`, `NOT_MEASURED`, or `NOT_COMPARABLE`; a regression
@@ -167,6 +271,117 @@ overhead no greater than +35% and P95 token overhead no greater than +60%
167
271
  against a comparable direct baseline. These objectives never trade away
168
272
  verification quality, requirement coverage, or protocol safety.
169
273
 
274
+ ## Robust statistics and tail stability
275
+
276
+ Benchmark methodology v2 reports robust variability for skewed token
277
+ distributions. Methodology-v2 mode aggregates include, for every measured
278
+ quantity, `count`, `average`, `minimum`, `p25`, `p50`, `p75`, `p90`, `p95`,
279
+ `maximum`, `iqr`, `mad`, and `outlierCount`. Percentiles use linear
280
+ interpolation; `iqr` is the interquartile range and `mad` the median absolute
281
+ deviation around the median. Methodology-v1 aggregates keep their frozen
282
+ historical shape.
283
+
284
+ Every non-direct comparison in a v2 aggregate gains a `tail` object, `pairedRatioDiagnostics`, `pairedRuns`, and separate paired and distribution statistics:
285
+
286
+ ```json
287
+ {
288
+ "pairedOverheadPercent": {
289
+ "p50": 3.5685,
290
+ "p95": 174.1502
291
+ },
292
+ "distributionDeltaPercent": {
293
+ "p50": 3.4708,
294
+ "p95": 13.1906
295
+ },
296
+ "pairedRatioDiagnostics": {
297
+ "pairCount": 20,
298
+ "baselineMinimum": 63298,
299
+ "baselineP25": 65742.25,
300
+ "baselineP50": 140632,
301
+ "lowBaselineThreshold": 84379.2,
302
+ "lowBaselinePairCount": 7
303
+ },
304
+ "tail": {
305
+ "sampleMinimum": 20,
306
+ "sampleCount": 20,
307
+ "p95TokenOverheadPercent": 174.1502,
308
+ "pairedOverheadP95Percent": 174.1502,
309
+ "distributionP95DeltaPercent": 13.1906,
310
+ "outlierCount": 0,
311
+ "status": "TAIL_REGRESSION",
312
+ "pairedStatus": "TAIL_REGRESSION",
313
+ "distributionStatus": "TAIL_ACCEPTABLE",
314
+ "combinedInterpretation": "TAIL_PAIRED_RATIO_SENSITIVE"
315
+ }
316
+ }
317
+ ```
318
+
319
+ ### Paired overhead vs. distribution tail delta
320
+
321
+ `pairedOverheadP95Percent` is the P95 of run-level relative overhead values (`((adaptive_i - direct_i) / direct_i) * 100`) across matched run indices. Because execution runs are independent stochastic trials, paired ratios can become very large when an individual direct baseline run finishes in an unusually low token regime (`LOW_BASELINE_TOKEN_REGIME`, defined as `directTokens < directP50 * 0.60`).
322
+
323
+ `distributionP95DeltaPercent` compares the P95 values of the candidate and baseline token distributions directly (`((adaptiveP95 - directP95) / directP95) * 100`).
324
+
325
+ These are distinct statistics and must not be presented as interchangeable metrics:
326
+
327
+ - When a candidate distribution is genuinely heavy-tailed, `distributionP95DeltaPercent` itself exceeds the objective (`TAIL_DISTRIBUTION_REGRESSION`).
328
+ - When the candidate distribution P95 is acceptable but paired overhead is inflated by low-baseline runs, the combined interpretation is `TAIL_PAIRED_RATIO_SENSITIVE`.
329
+
330
+ ```bash
331
+ npm run benchmark:profiles:tail-analysis -- [--results <dir>] [--run-set <id>] [--json]
332
+ ```
333
+
334
+ Tail status is observational and is classified as:
335
+
336
+ - `NOT_ENOUGH_SAMPLES` when comparable pairs are below the sample minimum (20) or P95 telemetry is unavailable;
337
+ - `TAIL_REGRESSION` when the P95 token metric exceeds the +60% objective;
338
+ - `TAIL_WARNING` when the sample is sufficient but IQR outliers are present;
339
+ - `TAIL_STABLE` / `TAIL_ACCEPTABLE` otherwise.
340
+
341
+ Combined interpretation states:
342
+
343
+ - `TAIL_CONSISTENT`: paired and distribution views agree;
344
+ - `TAIL_PAIRED_RATIO_SENSITIVE`: paired P95 fails while distribution P95 passes and low-baseline pairs are present;
345
+ - `TAIL_DISTRIBUTION_REGRESSION`: absolute distribution P95 delta exceeds the objective;
346
+ - `TAIL_UNRESOLVED`: sample count is insufficient or evidence is incomplete.
347
+
348
+ Tail status never gates lifecycle completion; it tells operators when a run
349
+ set is large enough to trust its tail.
350
+
351
+ ## Outlier classification and runaway signals
352
+
353
+ Token outliers are classified deterministically per scenario and mode with
354
+ the `TOKEN_IQR_1_5` policy: a measured run whose total tokens exceed
355
+ `Q3 + 1.5 × IQR` of that mode's measured distribution is an outlier, and at
356
+ least 4 measured samples are required before classification. Each outlier
357
+ record keeps the run identity, token values, `ratioToMedian`, and the
358
+ diagnostic signals that explain it.
359
+
360
+ ```bash
361
+ npm run benchmark:profiles:outliers -- [--results <dir>] [--run-set <id>] [--json]
362
+ ```
363
+
364
+ The report is read-only: it never rewrites raw runs or aggregates and it
365
+ never changes lifecycle truth. Signals come from two sources: host-reported
366
+ `diagnostics.flags` and deterministic derivations from recorded diagnostics
367
+ (model turns or tool calls more than double the mode median, repeated
368
+ verification or correction cycles, retries, repeated context refreshes). An
369
+ outlier with no recorded explanation is reported as `UNKNOWN_TOKEN_SPIKE`,
370
+ which is an admission of missing telemetry, not an estimate. Historical
371
+ methodology-v1 runs carry no diagnostics, so their spikes legitimately remain
372
+ `UNKNOWN_TOKEN_SPIKE`.
373
+
374
+ ## Methodology versioning and historical compatibility
375
+
376
+ Scenarios, runs, and aggregates carry a `benchmarkVersion`. Methodology v2
377
+ bumps the current version to `2`; readers accept versions `1` and `2`.
378
+ Historical v1 run sets are immutable evidence: their raw runs and stored
379
+ aggregates are never rewritten, and recomputation reproduces the frozen v1
380
+ aggregate shape exactly. Version checks therefore never invalidate committed
381
+ history; a run set aggregates under the methodology its runs were measured
382
+ with. Only new run sets recorded under methodology v2 receive robust
383
+ statistics, tail status, outlier analysis, and diagnostics.
384
+
170
385
  ## Host context contract
171
386
 
172
387
  The universal integration API exposes `task/context`, and the MCP adapter
package/docs/MCP.md CHANGED
@@ -119,7 +119,7 @@ forgeloop-mcp-http --project /repo --mode safe # 127.0.0.1:3333
119
119
 
120
120
  | Component | Current contract |
121
121
  | --- | --- |
122
- | ForgeLoop core package | `>=1.5.0 <2` dependency range; current repository generation `1.6.x` |
122
+ | ForgeLoop core package | `>=1.5.0 <2` dependency range; current repository generation `1.8.x` |
123
123
  | ForgeLoop protocol | `1` |
124
124
  | Integration API | `1` |
125
125
  | MCP package | `0.1.x` initial package |
@@ -10,6 +10,9 @@ preparation and verification checklist; it does not authorize publication.
10
10
  - [ ] `PROTOCOL_VERSION` and the integration API version remain compatible.
11
11
  - [ ] `npm run release:identity` passes for the candidate version.
12
12
  - [ ] No release tag or registry version collision exists.
13
+ - [ ] `npm pack --dry-run` contains the required scenario definitions but no
14
+ raw or aggregate benchmark results, tests, local state, or repository
15
+ metadata.
13
16
 
14
17
  ## Protocol and attestation
15
18
 
@@ -20,6 +23,13 @@ preparation and verification checklist; it does not authorize publication.
20
23
  is reported as `NOT_MEASURED`, never as zero or a passing efficiency claim.
21
24
  - [ ] `npm run benchmark:profiles:regression` reports the observed status;
22
25
  `EFFICIENCY_REGRESSION` remains a non-blocking warning.
26
+ - [ ] `npm run benchmark:profiles:outliers` and
27
+ `npm run benchmark:profiles:tail-analysis` report the observed
28
+ `TOKEN_IQR_1_5`, paired-ratio, and distribution-tail results without
29
+ conflating `pairedOverheadPercent` with `distributionDeltaPercent`.
30
+ - [ ] Historical v1 run sets remain byte-for-byte immutable while v2 run sets
31
+ carry robust statistics, low-baseline diagnostics, and explicit tail
32
+ interpretations.
23
33
  - [ ] `npm run coverage` passes the configured global and critical-module gates.
24
34
  - [ ] `npm run docs:check`, `npm run docs:generated:check`,
25
35
  `npm run docs:conformance`, and `npm run docs:examples:check` pass.
@@ -51,6 +61,8 @@ preparation and verification checklist; it does not authorize publication.
51
61
  - [ ] The exact validated commit is the release source.
52
62
  - [ ] GitHub Actions remain immutably pinned and use least-privilege permissions.
53
63
  - [ ] The npm workflow retains trusted OIDC publishing and explicit provenance.
64
+ - [ ] The publication workflow fails closed when the candidate npm version
65
+ already exists or the package inspection finds forbidden paths.
54
66
  - [ ] Publication is performed only by the authorized release workflow.
55
67
  - [ ] Post-publication registry, tag, checksum, and release identity checks pass.
56
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cassiomc1/forgeloop",
3
- "version": "1.7.0",
3
+ "version": "1.8.1",
4
4
  "description": "Portable, verifiable engineering protocol for AI coding environments and developer workflows",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,7 +22,8 @@
22
22
  "src",
23
23
  "ENG",
24
24
  "schemas",
25
- "benchmarks/execution-profiles",
25
+ "benchmarks/execution-profiles/*.json",
26
+ "benchmarks/execution-profiles/README.md",
26
27
  ".forgeloop/forgeloop.gitignore",
27
28
  "AGENTS.md",
28
29
  "CLAUDE.md",
@@ -72,6 +73,8 @@
72
73
  "scripts/run-execution-profile-benchmarks.mjs",
73
74
  "scripts/summarize-execution-profile-benchmarks.mjs",
74
75
  "scripts/validate-execution-profile-benchmarks.mjs",
76
+ "scripts/report-execution-profile-outliers.mjs",
77
+ "scripts/report-tail-interpretation.mjs",
75
78
  "scripts/check-efficiency-regression.mjs",
76
79
  "scripts/lib/execution-profile-benchmark-io.mjs",
77
80
  "scripts/benchmark-cli-startup.mjs",
@@ -115,6 +118,8 @@
115
118
  "benchmark:profiles": "node scripts/run-execution-profile-benchmarks.mjs",
116
119
  "benchmark:profiles:summary": "node scripts/summarize-execution-profile-benchmarks.mjs",
117
120
  "benchmark:profiles:check": "node scripts/validate-execution-profile-benchmarks.mjs",
121
+ "benchmark:profiles:outliers": "node scripts/report-execution-profile-outliers.mjs",
122
+ "benchmark:profiles:tail-analysis": "node scripts/report-tail-interpretation.mjs",
118
123
  "benchmark:profiles:regression": "node scripts/check-efficiency-regression.mjs"
119
124
  },
120
125
  "devDependencies": {
@@ -6,10 +6,11 @@
6
6
  "required": ["schemaVersion", "benchmarkVersion", "runSetId", "scenarioId", "expectedProfile", "modeAggregates", "comparisons", "lightObjectives", "sourcePolicy", "claimsAllowed", "generatedFromRunCount"],
7
7
  "properties": {
8
8
  "schemaVersion": { "const": 1 },
9
- "benchmarkVersion": { "const": "1" },
9
+ "benchmarkVersion": { "enum": ["1", "2"] },
10
10
  "runSetId": { "type": "string", "minLength": 1 },
11
11
  "scenarioId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,127}$" },
12
12
  "expectedProfile": { "enum": ["light", "balanced", "full"] },
13
+ "outlierAnalysis": { "$ref": "#/$defs/outlierAnalysis" },
13
14
  "modeAggregates": {
14
15
  "type": "object",
15
16
  "required": ["direct", "forgeloopBalanced", "forgeloopAdaptive"],
@@ -39,5 +40,54 @@
39
40
  "claimsAllowed": { "type": "boolean" },
40
41
  "generatedFromRunCount": { "type": "integer", "minimum": 1 }
41
42
  },
43
+ "$defs": {
44
+ "outlierAnalysis": {
45
+ "type": "object",
46
+ "required": ["policy", "minimumSamples", "modes"],
47
+ "properties": {
48
+ "policy": { "const": "TOKEN_IQR_1_5" },
49
+ "minimumSamples": { "type": "integer", "minimum": 1 },
50
+ "modes": {
51
+ "type": "object",
52
+ "required": ["direct", "forgeloopBalanced", "forgeloopAdaptive"],
53
+ "additionalProperties": { "$ref": "#/$defs/modeOutlierAnalysis" }
54
+ }
55
+ },
56
+ "additionalProperties": false
57
+ },
58
+ "modeOutlierAnalysis": {
59
+ "type": "object",
60
+ "required": ["sampleCount", "measuredCount", "status", "q1", "q3", "iqr", "median", "upperFence", "outliers"],
61
+ "properties": {
62
+ "sampleCount": { "type": "integer", "minimum": 0 },
63
+ "measuredCount": { "type": "integer", "minimum": 0 },
64
+ "status": { "enum": ["MEASURED", "NOT_ENOUGH_SAMPLES"] },
65
+ "q1": { "type": ["number", "null"] },
66
+ "q3": { "type": ["number", "null"] },
67
+ "iqr": { "type": ["number", "null"] },
68
+ "median": { "type": ["number", "null"] },
69
+ "upperFence": { "type": ["number", "null"] },
70
+ "outliers": {
71
+ "type": "array",
72
+ "items": { "$ref": "#/$defs/outlierRecord" }
73
+ }
74
+ },
75
+ "additionalProperties": false
76
+ },
77
+ "outlierRecord": {
78
+ "type": "object",
79
+ "required": ["runId", "runIndex", "totalTokens", "scenarioMedianTokens", "ratioToMedian", "reasons", "diagnosticSignals"],
80
+ "properties": {
81
+ "runId": { "type": "string", "pattern": "^run-[A-Za-z0-9][A-Za-z0-9_-]{0,127}$" },
82
+ "runIndex": { "type": "integer", "minimum": 1 },
83
+ "totalTokens": { "type": "integer", "minimum": 0 },
84
+ "scenarioMedianTokens": { "type": ["number", "null"] },
85
+ "ratioToMedian": { "type": ["number", "null"] },
86
+ "reasons": { "type": "array", "items": { "const": "TOKEN_IQR_OUTLIER" } },
87
+ "diagnosticSignals": { "type": "array", "items": { "type": "string", "minLength": 1 } }
88
+ },
89
+ "additionalProperties": false
90
+ }
91
+ },
42
92
  "additionalProperties": false
43
93
  }
@@ -6,7 +6,7 @@
6
6
  "required": ["schemaVersion", "benchmarkVersion", "runSetId", "runId", "scenarioId", "mode", "runIndex", "recordedAt", "usage", "wallClockMs", "verification", "verificationCycles", "comparableSteps", "metadata"],
7
7
  "properties": {
8
8
  "schemaVersion": { "const": 1 },
9
- "benchmarkVersion": { "const": "1" },
9
+ "benchmarkVersion": { "enum": ["1", "2"] },
10
10
  "runSetId": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$" },
11
11
  "runId": { "type": "string", "pattern": "^run-[A-Za-z0-9][A-Za-z0-9_-]{0,127}$" },
12
12
  "scenarioId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,127}$" },
@@ -33,6 +33,7 @@
33
33
  "verification": { "enum": ["PASS", "FAIL", "NOT_AVAILABLE"] },
34
34
  "verificationCycles": { "type": ["integer", "null"], "minimum": 0 },
35
35
  "comparableSteps": { "type": ["integer", "null"], "minimum": 0 },
36
+ "diagnostics": { "$ref": "#/$defs/diagnostics" },
36
37
  "contextUsage": { "$ref": "#/$defs/contextUsage" },
37
38
  "quality": { "$ref": "#/$defs/quality" },
38
39
  "metadata": {
@@ -45,7 +46,7 @@
45
46
  "provider": { "type": ["string", "null"] },
46
47
  "promptSpecFingerprint": { "type": "string", "minLength": 1 },
47
48
  "projectRevision": { "type": ["string", "null"] },
48
- "benchmarkVersion": { "const": "1" },
49
+ "benchmarkVersion": { "enum": ["1", "2"] },
49
50
  "environmentClass": { "type": "string", "minLength": 1 },
50
51
  "requestedProfile": { "type": ["string", "null"] },
51
52
  "resolvedProfile": { "type": ["string", "null"] },
@@ -59,6 +60,43 @@
59
60
  }
60
61
  },
61
62
  "$defs": {
63
+ "diagnostics": {
64
+ "type": "object",
65
+ "additionalProperties": false,
66
+ "properties": {
67
+ "executionProfile": { "enum": ["light", "balanced", "full", null] },
68
+ "verificationCycles": { "type": ["integer", "null"], "minimum": 0 },
69
+ "modelTurns": { "type": ["integer", "null"], "minimum": 0 },
70
+ "toolCalls": { "type": ["integer", "null"], "minimum": 0 },
71
+ "retries": { "type": ["integer", "null"], "minimum": 0 },
72
+ "correctionCycles": { "type": ["integer", "null"], "minimum": 0 },
73
+ "filesRead": { "type": ["integer", "null"], "minimum": 0 },
74
+ "filesWritten": { "type": ["integer", "null"], "minimum": 0 },
75
+ "contextRefreshes": { "type": ["integer", "null"], "minimum": 0 },
76
+ "guideCount": { "type": ["integer", "null"], "minimum": 0 },
77
+ "guideIds": { "type": "array", "items": { "type": "string", "minLength": 1 } },
78
+ "hostWarnings": { "type": "array", "items": { "type": "string", "minLength": 1 } },
79
+ "terminationReason": { "type": ["string", "null"], "minLength": 1 },
80
+ "flags": {
81
+ "type": "array",
82
+ "items": {
83
+ "enum": [
84
+ "EXCESSIVE_MODEL_TURNS",
85
+ "EXCESSIVE_TOOL_CALLS",
86
+ "EXCESSIVE_VERIFICATION_CYCLES",
87
+ "REPEATED_CONTEXT_REFRESH",
88
+ "REPEATED_FILE_READ",
89
+ "REPEATED_GUIDE_LOAD",
90
+ "UNEXPECTED_RETRY",
91
+ "CORRECTION_LOOP",
92
+ "HOST_RETRY",
93
+ "MODEL_STALL",
94
+ "UNKNOWN_TOKEN_SPIKE"
95
+ ]
96
+ }
97
+ }
98
+ }
99
+ },
62
100
  "contextUsage": {
63
101
  "type": "object",
64
102
  "required": ["source", "profile", "items"],