@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 +1 -1
- package/benchmarks/execution-profiles/README.md +18 -0
- package/benchmarks/execution-profiles/api-feature.json +1 -1
- package/benchmarks/execution-profiles/authentication-change.json +1 -1
- package/benchmarks/execution-profiles/documentation-correction.json +1 -1
- package/benchmarks/execution-profiles/infrastructure-release.json +1 -1
- package/benchmarks/execution-profiles/novatask-saas-landing-page.json +1 -1
- package/benchmarks/execution-profiles/small-bug-fix.json +1 -1
- package/benchmarks/execution-profiles/static-landing-page.json +1 -1
- package/docs/AGENT_PROTOCOL_SUMMARY.md +1 -1
- package/docs/EXECUTION_PROFILE_BENCHMARKS.md +218 -3
- package/docs/MCP.md +1 -1
- package/docs/RELEASE_CHECKLIST.md +12 -0
- package/package.json +7 -2
- package/schemas/execution-profile-benchmark-aggregate.schema.json +51 -1
- package/schemas/execution-profile-benchmark-run.schema.json +40 -2
- package/scripts/report-execution-profile-outliers.mjs +136 -0
- package/scripts/report-tail-interpretation.mjs +156 -0
- package/scripts/run-execution-profile-benchmarks.mjs +112 -36
- package/src/core/execution-profile-benchmarks.js +509 -35
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,
|
|
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.
|
|
@@ -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.
|
|
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
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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.
|
|
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.
|
|
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": { "
|
|
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": { "
|
|
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": { "
|
|
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"],
|