tickmarkr 2.8.6 → 2.8.8
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/dist/adapters/grok.js +5 -9
- package/dist/adapters/prompt.js +9 -1
- package/dist/adapters/types.d.ts +1 -0
- package/dist/adapters/types.js +12 -0
- package/dist/cli/commands/compile.js +1 -1
- package/dist/cli/commands/init.d.ts +10 -0
- package/dist/cli/commands/init.js +13 -3
- package/dist/cli/commands/report.js +21 -12
- package/dist/cli/commands/status.js +14 -2
- package/dist/cli/commands/verify.js +29 -5
- package/dist/cli/commands/version.d.ts +1 -1
- package/dist/cli/commands/version.js +36 -2
- package/dist/cli/help.d.ts +1 -0
- package/dist/cli/help.js +6 -3
- package/dist/compile/collateral.d.ts +3 -1
- package/dist/compile/collateral.js +8 -16
- package/dist/compile/native.js +7 -2
- package/dist/drivers/subprocess.js +9 -4
- package/dist/gates/acceptance.d.ts +8 -0
- package/dist/gates/acceptance.js +54 -37
- package/dist/gates/baseline.js +47 -7
- package/dist/gates/run-gates.js +31 -22
- package/dist/report/bundle.d.ts +5 -2
- package/dist/report/bundle.js +11 -6
- package/dist/report/compare.d.ts +9 -0
- package/dist/report/compare.js +58 -40
- package/dist/report/operator-record.js +4 -3
- package/dist/run/daemon.d.ts +7 -3
- package/dist/run/daemon.js +157 -58
- package/dist/run/git.d.ts +5 -0
- package/dist/run/git.js +51 -1
- package/dist/run/journal.js +11 -2
- package/dist/run/repair-disposition.d.ts +2 -2
- package/dist/run/repair-disposition.js +35 -4
- package/dist/run/stall.d.ts +2 -0
- package/dist/run/stall.js +12 -4
- package/package.json +1 -1
- package/skills/tickmarkr-auto/SKILL.md +10 -8
- package/skills/tickmarkr-loop/SKILL.md +10 -8
- package/skills/tickmarkr-overseer/SKILL.md +10 -8
package/dist/report/compare.js
CHANGED
|
@@ -1,43 +1,50 @@
|
|
|
1
|
+
import { normalizeGateOutcome } from "../run/outcome.js";
|
|
1
2
|
import { estimateCosts } from "./cost.js";
|
|
2
3
|
export function hasRunStart(events) {
|
|
3
4
|
return events.some((e) => e.event === "run-start");
|
|
4
5
|
}
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
6
|
+
// Queue 35 (D-2134 R6): validate each session's stamp before folding the run's identity.
|
|
7
|
+
function parseEnvironment(env) {
|
|
8
|
+
if (!env || typeof env !== "object" || Array.isArray(env))
|
|
9
|
+
return undefined;
|
|
10
|
+
const o = env;
|
|
11
|
+
if (typeof o.tickmarkrVersion !== "string" || !o.tickmarkrVersion.trim()
|
|
12
|
+
|| typeof o.configHash !== "string" || !o.configHash.trim())
|
|
13
|
+
return undefined;
|
|
14
|
+
if (!o.adapterVersions || typeof o.adapterVersions !== "object" || Array.isArray(o.adapterVersions))
|
|
15
|
+
return undefined;
|
|
16
|
+
const adapterVersions = {};
|
|
17
|
+
for (const [k, v] of Object.entries(o.adapterVersions)) {
|
|
18
|
+
if (typeof v !== "string")
|
|
17
19
|
return undefined;
|
|
18
|
-
|
|
19
|
-
for (const [k, v] of Object.entries(o.adapterVersions)) {
|
|
20
|
-
if (typeof v !== "string")
|
|
21
|
-
return undefined;
|
|
22
|
-
adapterVersions[k] = v;
|
|
23
|
-
}
|
|
24
|
-
// Capacity arrived in v2.0 as a pair. Two absent fields are an honest older record; one without
|
|
25
|
-
// the other is a malformed new record and fails closed instead of being compared as legacy.
|
|
26
|
-
const hasCores = Object.hasOwn(o, "cores");
|
|
27
|
-
const hasForkCap = Object.hasOwn(o, "forkCap");
|
|
28
|
-
if (hasCores !== hasForkCap)
|
|
29
|
-
return undefined;
|
|
30
|
-
if (hasCores && (typeof o.cores !== "number" || !Number.isFinite(o.cores) || o.cores <= 0
|
|
31
|
-
|| typeof o.forkCap !== "number" || !Number.isFinite(o.forkCap) || o.forkCap <= 0))
|
|
32
|
-
return undefined;
|
|
33
|
-
return {
|
|
34
|
-
tickmarkrVersion: o.tickmarkrVersion,
|
|
35
|
-
configHash: o.configHash,
|
|
36
|
-
adapterVersions,
|
|
37
|
-
...(hasCores ? { cores: o.cores, forkCap: o.forkCap } : {}),
|
|
38
|
-
};
|
|
20
|
+
adapterVersions[k] = v;
|
|
39
21
|
}
|
|
40
|
-
|
|
22
|
+
// Capacity arrived in v2.0 as a pair. Two absent fields are an honest older record; one without
|
|
23
|
+
// the other is a malformed new record and fails closed instead of being compared as legacy.
|
|
24
|
+
const hasCores = Object.hasOwn(o, "cores");
|
|
25
|
+
const hasForkCap = Object.hasOwn(o, "forkCap");
|
|
26
|
+
if (hasCores !== hasForkCap)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (hasCores && (typeof o.cores !== "number" || !Number.isFinite(o.cores) || o.cores <= 0
|
|
29
|
+
|| typeof o.forkCap !== "number" || !Number.isFinite(o.forkCap) || o.forkCap <= 0))
|
|
30
|
+
return undefined;
|
|
31
|
+
return {
|
|
32
|
+
tickmarkrVersion: o.tickmarkrVersion,
|
|
33
|
+
configHash: o.configHash,
|
|
34
|
+
adapterVersions,
|
|
35
|
+
...(hasCores ? { cores: o.cores, forkCap: o.forkCap } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function recordedEnvironments(events) {
|
|
39
|
+
return events.flatMap((e) => e.event === "run-start" || e.event === "run-resume"
|
|
40
|
+
? [{ event: e.event, ts: e.ts, environment: parseEnvironment(e.data.environment) }]
|
|
41
|
+
: []);
|
|
42
|
+
}
|
|
43
|
+
export function recordedEnvironment(events) {
|
|
44
|
+
const sessions = recordedEnvironments(events);
|
|
45
|
+
const first = sessions[0]?.environment;
|
|
46
|
+
return first && sessions.every(({ environment }) => environment && envEqual(first, environment))
|
|
47
|
+
? first : undefined;
|
|
41
48
|
}
|
|
42
49
|
// Canonical identity string for the `recorded` field — configHash is the axis the acceptance
|
|
43
50
|
// criteria name; full environment equality still decides .comparable.
|
|
@@ -81,12 +88,14 @@ export function runMetrics(events, rows = [], cost = {}) {
|
|
|
81
88
|
durationMs = to - from;
|
|
82
89
|
}
|
|
83
90
|
const gates = events.filter((e) => e.event === "gate-result");
|
|
84
|
-
const gatePass = gates.filter((e) => e.data.
|
|
85
|
-
const gateFail = gates.filter((e) => e.data.
|
|
91
|
+
const gatePass = gates.filter((e) => normalizeGateOutcome(e.data).kind === "passed").length;
|
|
92
|
+
const gateFail = gates.filter((e) => normalizeGateOutcome(e.data).kind === "failed").length;
|
|
86
93
|
let costUsd;
|
|
87
94
|
let costSum = 0;
|
|
88
95
|
let hasCost = false;
|
|
89
|
-
|
|
96
|
+
const prices = estimateCosts(rows, cost);
|
|
97
|
+
const costPartial = prices.some((p) => p.partialMetering);
|
|
98
|
+
for (const p of prices) {
|
|
90
99
|
if (p.apiUsd !== undefined) {
|
|
91
100
|
costSum += p.apiUsd;
|
|
92
101
|
hasCost = true;
|
|
@@ -110,7 +119,7 @@ export function runMetrics(events, rows = [], cost = {}) {
|
|
|
110
119
|
}
|
|
111
120
|
if (hasTokens)
|
|
112
121
|
tokensTotal = tokenSum;
|
|
113
|
-
return { durationMs, gatePass, gateFail, gateTotal: gates.length, costUsd, tokensTotal };
|
|
122
|
+
return { durationMs, gatePass, gateFail, gateTotal: gates.length, costUsd, costPartial, tokensTotal };
|
|
114
123
|
}
|
|
115
124
|
const n = (x) => x.toLocaleString("en-US");
|
|
116
125
|
const EM = "—";
|
|
@@ -161,6 +170,9 @@ function comparabilityLine(cmp, baselineEnv, currentEnv) {
|
|
|
161
170
|
if (cmp.reason === "unbound") {
|
|
162
171
|
return "comparability caveat — one or both runs lack a recorded environment identity; not apples-to-apples";
|
|
163
172
|
}
|
|
173
|
+
if (cmp.mixedSessions) {
|
|
174
|
+
return "comparability caveat — environment identity disagrees across mixed sessions; not apples-to-apples";
|
|
175
|
+
}
|
|
164
176
|
const base = baselineEnv?.configHash ?? EM;
|
|
165
177
|
const cur = currentEnv?.configHash ?? EM;
|
|
166
178
|
return `comparability caveat — environment identity disagrees (baseline configHash=${base} ≠ current configHash=${cur}; recorded baseline ${cmp.recorded}); not apples-to-apples`;
|
|
@@ -182,7 +194,7 @@ export function renderComparison(opts) {
|
|
|
182
194
|
`| duration | ${fmtDuration(baseline.durationMs)} | ${fmtDuration(current.durationMs)} | ${fmtSignedDuration(delta.durationMs)} |`,
|
|
183
195
|
`| gate failures | ${fmtInt(baseline.gateFail)} | ${fmtInt(current.gateFail)} | ${fmtSignedInt(delta.gateFail)} |`,
|
|
184
196
|
`| gate pass rate | ${baseline.gateTotal ? `${baseline.gatePass}/${baseline.gateTotal}` : EM} | ${current.gateTotal ? `${current.gatePass}/${current.gateTotal}` : EM} | ${EM} |`,
|
|
185
|
-
`| cost | ${fmtUsd(baseline.costUsd)} | ${fmtUsd(current.costUsd)} | ${fmtSignedUsd(delta.costUsd)} |`,
|
|
197
|
+
`| cost | ${fmtUsd(baseline.costUsd)}${baseline.costPartial ? " (partial)" : ""} | ${fmtUsd(current.costUsd)}${current.costPartial ? " (partial)" : ""} | ${fmtSignedUsd(delta.costUsd)}${delta.costPartial ? " (partial)" : ""} |`,
|
|
186
198
|
`| tokens | ${fmtInt(baseline.tokensTotal)} | ${fmtInt(current.tokensTotal)} | ${fmtSignedInt(delta.tokensTotal)} |`,
|
|
187
199
|
"",
|
|
188
200
|
];
|
|
@@ -208,10 +220,16 @@ export function compareRuns(opts) {
|
|
|
208
220
|
}
|
|
209
221
|
const baselineEnv = recordedEnvironment(opts.baselineEvents);
|
|
210
222
|
const currentEnv = recordedEnvironment(opts.events);
|
|
211
|
-
const
|
|
223
|
+
const sessions = [...recordedEnvironments(opts.baselineEvents), ...recordedEnvironments(opts.events)];
|
|
224
|
+
const comparability = sessions.some((s) => !s.environment)
|
|
225
|
+
? { comparable: false, reason: "unbound" }
|
|
226
|
+
: !baselineEnv || !currentEnv
|
|
227
|
+
? { comparable: false, reason: "mismatch", recorded: baselineEnv?.configHash ?? "mixed sessions", mixedSessions: true }
|
|
228
|
+
: environmentComparable(baselineEnv, currentEnv);
|
|
212
229
|
const baseline = runMetrics(opts.baselineEvents, opts.baselineRows ?? [], opts.cost ?? {});
|
|
213
230
|
const current = runMetrics(opts.events, opts.rows ?? [], opts.cost ?? {});
|
|
214
231
|
const delta = {
|
|
232
|
+
costPartial: current.costPartial || baseline.costPartial,
|
|
215
233
|
durationMs: current.durationMs !== undefined && baseline.durationMs !== undefined
|
|
216
234
|
? current.durationMs - baseline.durationMs
|
|
217
235
|
: undefined,
|
|
@@ -37,15 +37,16 @@ export function formatRateBasis(row) {
|
|
|
37
37
|
export function formatChannelMoney(row) {
|
|
38
38
|
const prices = [];
|
|
39
39
|
const bases = [];
|
|
40
|
+
const floor = row.partialMetering ? "≥ " : "";
|
|
40
41
|
if (row.apiUsd !== undefined)
|
|
41
|
-
prices.push(`price: $${row.apiUsd.toFixed(6)}`);
|
|
42
|
+
prices.push(`price: ${floor}$${row.apiUsd.toFixed(6)}`);
|
|
42
43
|
if (row.amortizedUsd !== undefined && row.subPlan !== undefined) {
|
|
43
44
|
const [low, high] = row.amortizedUsd;
|
|
44
|
-
prices.push(`price: $${low.toFixed(6)}–$${high.toFixed(6)} amortized`);
|
|
45
|
+
prices.push(`price: ${floor}$${low.toFixed(6)}–$${high.toFixed(6)} amortized`);
|
|
45
46
|
bases.push(`${n(row.attempts)} windows × $${row.subPlan.planMonthly}/month ÷ ${row.subPlan.windowsPerMonthHigh}–${row.subPlan.windowsPerMonthLow} windows/month`);
|
|
46
47
|
}
|
|
47
48
|
if (row.counterfactualUsd !== undefined)
|
|
48
|
-
prices.push(`API-equivalent: $${row.counterfactualUsd.toFixed(6)}`);
|
|
49
|
+
prices.push(`API-equivalent: ${floor}$${row.counterfactualUsd.toFixed(6)}`);
|
|
49
50
|
const basis = formatRateBasis(row);
|
|
50
51
|
if (basis)
|
|
51
52
|
bases.push(basis);
|
package/dist/run/daemon.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type ModeResolution, type RoutingMode, type TickmarkrConfig } from "../
|
|
|
3
3
|
import { type DriverChoice } from "../drivers/index.js";
|
|
4
4
|
import { type ExecutorDriver, type Slot } from "../drivers/types.js";
|
|
5
5
|
import { type Baseline, type BaselineProvenance, type GateEvidenceOptions } from "../gates/baseline.js";
|
|
6
|
+
import { environmentFingerprint } from "../gates/cache.js";
|
|
6
7
|
import type { GateResult } from "../gates/types.js";
|
|
7
8
|
import { type RunGraph, type Task } from "../graph/schema.js";
|
|
8
9
|
import { type PreserveProducer, type RunCapacity } from "./git.js";
|
|
@@ -226,6 +227,7 @@ export declare function resetHarvestSilentMsForTests(): void;
|
|
|
226
227
|
export declare const HARVESTED_RESULT_SUMMARY = "harvested: the worktree carries committed work; the worker emitted no TICKMARKR_RESULT trailer";
|
|
227
228
|
/** T4 (OBS-266): identity of the command SET a tip verify ran — a changed command is a different verify. */
|
|
228
229
|
export declare function commandsHash(commands: Record<string, string>): string;
|
|
230
|
+
type TipEnvironment = ReturnType<typeof environmentFingerprint>;
|
|
229
231
|
export interface TipProof {
|
|
230
232
|
kind: "fresh" | "reused" | "failed" | "incomplete";
|
|
231
233
|
/** Each completed gate keeps its own execution provenance, even in a mixed cycle. */
|
|
@@ -261,6 +263,7 @@ export interface TipClose {
|
|
|
261
263
|
expected?: string;
|
|
262
264
|
identityFailed: boolean;
|
|
263
265
|
deferred: DeferredVerdict[];
|
|
266
|
+
tipEnvironment?: TipEnvironment;
|
|
264
267
|
}
|
|
265
268
|
interface TipVerifyOptions {
|
|
266
269
|
lastMergedTask?: string;
|
|
@@ -293,6 +296,7 @@ export declare function appendIdentityFailure(journal: Journal, f: {
|
|
|
293
296
|
state?: IntegrationRefState;
|
|
294
297
|
cmdHash: string;
|
|
295
298
|
capacity: RunCapacity;
|
|
299
|
+
tipEnvironment?: TipEnvironment;
|
|
296
300
|
infra?: boolean;
|
|
297
301
|
}): void;
|
|
298
302
|
/** O: I(expected) — or, with no expected value, the ref must be regular and its commit becomes the expected. */
|
|
@@ -309,9 +313,9 @@ export declare function openingIdentity(identity: TipIdentity, journal: Journal)
|
|
|
309
313
|
/**
|
|
310
314
|
* OBS-34's strict tip verify, but it stops re-paying for an unmoved tip (~334m corpus-wide; 69.5m in
|
|
311
315
|
* one park-heavy run whose 18 resume cycles merged nothing new). The verify journals the SHA it
|
|
312
|
-
* verified and the hash of the command set, so a later run-end can recognize the same verified state
|
|
313
|
-
*
|
|
314
|
-
* `tip-verify-cached`
|
|
316
|
+
* verified and the hash of the command set, so a later run-end can recognize the same verified state.
|
|
317
|
+
* Queue row 24 (D-2134): the last green also binds every row's stamped runner and environment identity
|
|
318
|
+
* and capacity before `tip-verify-cached` can skip with no checkout. ANY doubt — moved tip, changed commands, a gate
|
|
315
319
|
* missing from that cycle's green set, a failure recorded in it, a cycle older than the last one —
|
|
316
320
|
* runs the full verify. 2.8.1 T1 (ANL-023 §7.1): with `identity` (the daemon always passes it) run end
|
|
317
321
|
* verifies a fresh detached checkout of the expected commit under a validated HEAD reflog, never the
|