@dzhechkov/harness-core 0.7.6 → 0.7.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/.dz-manifest.json +81 -21
- package/README.md +34 -3
- package/dist/checkpoint-stamp.d.ts +31 -0
- package/dist/checkpoint-stamp.d.ts.map +1 -0
- package/dist/checkpoint-stamp.js +54 -0
- package/dist/checkpoint-stamp.js.map +1 -0
- package/dist/feature-adr-checkpoints.d.ts +20 -0
- package/dist/feature-adr-checkpoints.d.ts.map +1 -1
- package/dist/feature-adr-checkpoints.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/ledger-backfill.d.ts +114 -0
- package/dist/ledger-backfill.d.ts.map +1 -0
- package/dist/ledger-backfill.js +183 -0
- package/dist/ledger-backfill.js.map +1 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +40 -0
- package/dist/operations.js.map +1 -1
- package/dist/score.d.ts +29 -0
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +108 -0
- package/dist/score.js.map +1 -1
- package/dist/telemetry-vocabulary.d.ts +87 -0
- package/dist/telemetry-vocabulary.d.ts.map +1 -0
- package/dist/telemetry-vocabulary.js +109 -0
- package/dist/telemetry-vocabulary.js.map +1 -0
- package/package.json +7 -7
- package/sbom.json +170 -20
- package/src/checkpoint-stamp.ts +50 -0
- package/src/feature-adr-checkpoints.ts +20 -0
- package/src/index.ts +5 -0
- package/src/ledger-backfill.ts +237 -0
- package/src/operations.ts +36 -0
- package/src/score.ts +96 -0
- package/src/telemetry-vocabulary.ts +138 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One name per measured quantity — copied, not imported.
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM (MEASURED 2026-08-25). Fifteen telemetry stores in this repo, each naming the same
|
|
5
|
+
* thing differently: `durationMs` here, `minutes` there, `wallMs` in a third; `tokens` vs
|
|
6
|
+
* `totalTokens` vs `tokensIn`/`tokensOut`. Joining two of them was interpretation, not lookup, which
|
|
7
|
+
* is why cost-per-feature was 76% typed by a human.
|
|
8
|
+
*
|
|
9
|
+
* WHY LITERALS AND NOT A DEPENDENCY. OpenTelemetry's `gen_ai.*` conventions are the right vocabulary
|
|
10
|
+
* and there is no package to depend on:
|
|
11
|
+
* • `@opentelemetry/semantic-conventions-genai` → 404 on npm (verified 2026-08-25);
|
|
12
|
+
* • in semconv v1.42.0 every `gen_ai.*` convention was DEPRECATED out of the main repo and moved
|
|
13
|
+
* to a new one with zero tags and zero releases;
|
|
14
|
+
* • 197 of 197 documents in that spec carry `stability: development`, which its own status page
|
|
15
|
+
* defines as "SHOULD NOT be used in production";
|
|
16
|
+
* • 40 fragments are queued, 6 of them breaking — and FOUR of those six are agent-layer.
|
|
17
|
+
* So: copy the names, version the copy, and mark the volatile half. A rename upstream then becomes a
|
|
18
|
+
* data migration against ONE file instead of a code change across call sites.
|
|
19
|
+
*
|
|
20
|
+
* WHAT THIS DOES NOT DO. It renames nothing. Migrating the existing stores onto these names is a
|
|
21
|
+
* separate change with its own risk; this module only makes the join possible.
|
|
22
|
+
*
|
|
23
|
+
* NOT in the loop-blob registry, deliberately: a module mirrored into the sandboxed workflow drags a
|
|
24
|
+
* registry regeneration and a region re-render behind every edit to it.
|
|
25
|
+
*
|
|
26
|
+
* @packageDocumentation
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* The contract's own version. Bump it when a name changes, and the change is then a migration
|
|
30
|
+
* against a versioned file — which is the whole point of copying rather than depending.
|
|
31
|
+
*/
|
|
32
|
+
export const TELEMETRY_VOCAB_VERSION = 'dz-telemetry-vocab-1';
|
|
33
|
+
/**
|
|
34
|
+
* The vocabulary. Keys are stable identifiers for OUR code to reference; `field` is what goes on
|
|
35
|
+
* disk, so an upstream rename touches the value and never the call sites.
|
|
36
|
+
*/
|
|
37
|
+
export const TELEMETRY_FIELDS = {
|
|
38
|
+
requestModel: { field: 'gen_ai.request.model', source: 'otel', means: 'the model id a stage asked for', unit: null },
|
|
39
|
+
// The upstream field means the SERVICE PROVIDER — anthropic, openai — not the product family.
|
|
40
|
+
// Cross-family review caught this being described as "claude, codex", which are our model
|
|
41
|
+
// families; those now have their own local field below rather than being smuggled in here.
|
|
42
|
+
providerName: { field: 'gen_ai.provider.name', source: 'otel', means: 'the inference provider — anthropic, openai', unit: null },
|
|
43
|
+
operationName: { field: 'gen_ai.operation.name', source: 'otel', means: 'what the call was: invoke_agent, invoke_workflow, plan, execute_tool', unit: null },
|
|
44
|
+
inputTokens: { field: 'gen_ai.usage.input_tokens', source: 'otel', means: 'tokens SENT — not a total', unit: 'tokens' },
|
|
45
|
+
outputTokens: { field: 'gen_ai.usage.output_tokens', source: 'otel', means: 'tokens PRODUCED — not a total', unit: 'tokens' },
|
|
46
|
+
evaluationLabel: { field: 'gen_ai.evaluation.score.label', source: 'otel', means: 'a graded verdict — our QE letter grade', unit: null },
|
|
47
|
+
// OpenTelemetry carries elapsed time as span structure, not as an attribute, so there is no
|
|
48
|
+
// upstream name to copy for a JSONL row. Ours, and said so.
|
|
49
|
+
durationMs: { field: 'dz.duration_ms', source: 'local', means: 'elapsed wall time of a stage or run', unit: 'ms' },
|
|
50
|
+
// Upstream splits usage into input and output and has no TOTAL. Ours are totals, and folding them
|
|
51
|
+
// into input_tokens would silently change the measured quantity (cross-family review).
|
|
52
|
+
totalTokens: { field: 'dz.total_tokens', source: 'local', means: 'input + output for a run or stage', unit: 'tokens' },
|
|
53
|
+
// Our routing families (claude, codex) are not providers; see providerName above.
|
|
54
|
+
modelFamily: { field: 'dz.model_family', source: 'local', means: 'the routing family — claude, codex', unit: null },
|
|
55
|
+
runId: { field: 'dz.run_id', source: 'local', means: 'the host workflow run a record belongs to', unit: null },
|
|
56
|
+
stage: { field: 'dz.stage', source: 'local', means: 'the feature-adr stage a record is about', unit: null },
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* The names whose upstream churn is highest — the agent layer, where FOUR of the six queued breaking
|
|
60
|
+
* changes land (`gen_ai.agent.version` removed from internal invoke_agent spans,
|
|
61
|
+
* `gen_ai.provider.name` dropped as required, `gen_ai.agent.id` scope changed).
|
|
62
|
+
*
|
|
63
|
+
* Separated by NAME rather than by footnote so a reader can tell "safe to build on" from "expect this
|
|
64
|
+
* to move" without reading a comment. Build on these only where a rename is cheap.
|
|
65
|
+
*/
|
|
66
|
+
export const PROVISIONAL_TELEMETRY_FIELDS = {
|
|
67
|
+
agentId: { field: 'gen_ai.agent.id', source: 'otel', means: 'PROVISIONAL — the agent instance', unit: null },
|
|
68
|
+
agentName: { field: 'gen_ai.agent.name', source: 'otel', means: 'PROVISIONAL — the agent role/label', unit: null },
|
|
69
|
+
agentVersion: { field: 'gen_ai.agent.version', source: 'otel', means: 'PROVISIONAL — slated for removal from internal spans', unit: null },
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* What this repo already writes → which vocabulary key it means.
|
|
73
|
+
*
|
|
74
|
+
* Without this the contract is a glossary nobody can act on. With it, the cost join that was hand
|
|
75
|
+
* work becomes a lookup. Wrong BY OMISSION for any store added without updating it — which is why
|
|
76
|
+
* {@link telemetryFieldFor} returns nothing rather than guessing.
|
|
77
|
+
*/
|
|
78
|
+
export const LOCAL_FIELD_ALIASES = {
|
|
79
|
+
durationMs: 'durationMs',
|
|
80
|
+
wallMs: 'durationMs',
|
|
81
|
+
// `minutes` is DELIBERATELY absent. It names the same quantity in a different unit, and an alias
|
|
82
|
+
// carries no conversion — following it would write minutes into a field whose name ends `_ms`.
|
|
83
|
+
// An unmapped name is visible at the call site; a wrong unit is not (cross-family review).
|
|
84
|
+
tokens: 'totalTokens',
|
|
85
|
+
totalTokens: 'totalTokens',
|
|
86
|
+
recordTotalTokens: 'totalTokens',
|
|
87
|
+
tokensIn: 'inputTokens',
|
|
88
|
+
tokensOut: 'outputTokens',
|
|
89
|
+
model: 'requestModel',
|
|
90
|
+
coder: 'modelFamily',
|
|
91
|
+
family: 'modelFamily',
|
|
92
|
+
grade: 'evaluationLabel',
|
|
93
|
+
runId: 'runId',
|
|
94
|
+
stage: 'stage',
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* The vocabulary field a local name means, or `undefined` when we do not know.
|
|
98
|
+
*
|
|
99
|
+
* The unknown case is the load-bearing one. A vocabulary that invents a mapping for a field it has
|
|
100
|
+
* never seen produces a join that is silently wrong; one that returns nothing makes the gap visible
|
|
101
|
+
* at the call site, where somebody can fix it.
|
|
102
|
+
*/
|
|
103
|
+
export function telemetryFieldFor(localName) {
|
|
104
|
+
const key = LOCAL_FIELD_ALIASES[localName];
|
|
105
|
+
if (key === undefined)
|
|
106
|
+
return undefined;
|
|
107
|
+
return TELEMETRY_FIELDS[key] ?? PROVISIONAL_TELEMETRY_FIELDS[key];
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=telemetry-vocabulary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry-vocabulary.js","sourceRoot":"","sources":["../src/telemetry-vocabulary.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dzhechkov/harness-core",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"description": "Shared harness logic - skill loading, additive apply, and the init/sync/verify/doctor operations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,17 +30,17 @@
|
|
|
30
30
|
"proper-lockfile": "^4.1.2",
|
|
31
31
|
"yaml": "^2.0.0",
|
|
32
32
|
"@dzhechkov/adapter-agents-md": "0.1.3",
|
|
33
|
+
"@dzhechkov/adapter-claude": "^0.2.2",
|
|
33
34
|
"@dzhechkov/adapter-codex": "^0.2.2",
|
|
34
|
-
"@dzhechkov/adapter-cursor": "0.1.3",
|
|
35
35
|
"@dzhechkov/adapter-copilot": "0.1.3",
|
|
36
|
+
"@dzhechkov/adapter-cursor": "0.1.3",
|
|
36
37
|
"@dzhechkov/adapter-gemini": "0.1.3",
|
|
37
|
-
"@dzhechkov/adapter-openclaude": "^0.1.2",
|
|
38
|
-
"@dzhechkov/adapter-claude": "^0.2.2",
|
|
39
38
|
"@dzhechkov/adapter-hermes": "^0.2.2",
|
|
40
|
-
"@dzhechkov/adapter-
|
|
41
|
-
"@dzhechkov/core": "0.2.17",
|
|
39
|
+
"@dzhechkov/adapter-openclaude": "^0.1.2",
|
|
42
40
|
"@dzhechkov/adapter-windsurf": "0.1.3",
|
|
43
|
-
"@dzhechkov/
|
|
41
|
+
"@dzhechkov/core": "0.2.17",
|
|
42
|
+
"@dzhechkov/memory": "0.2.15",
|
|
43
|
+
"@dzhechkov/adapter-opencode": "^0.2.2"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"@ruvector/rvf": {
|
package/sbom.json
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"hashes": [
|
|
26
26
|
{
|
|
27
27
|
"alg": "SHA-256",
|
|
28
|
-
"content": "
|
|
28
|
+
"content": "da09a44bfc467f67e142638f1a57e072c0dcfbf04f3f43229e7045bf51a0eb9d"
|
|
29
29
|
}
|
|
30
30
|
]
|
|
31
31
|
},
|
|
@@ -669,6 +669,46 @@
|
|
|
669
669
|
}
|
|
670
670
|
]
|
|
671
671
|
},
|
|
672
|
+
{
|
|
673
|
+
"type": "file",
|
|
674
|
+
"name": "dist/checkpoint-stamp.d.ts",
|
|
675
|
+
"hashes": [
|
|
676
|
+
{
|
|
677
|
+
"alg": "SHA-256",
|
|
678
|
+
"content": "bcd22740dabf30df0b71f2164dd13c9c7fe619746a852929c7e8bd4edd049556"
|
|
679
|
+
}
|
|
680
|
+
]
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
"type": "file",
|
|
684
|
+
"name": "dist/checkpoint-stamp.d.ts.map",
|
|
685
|
+
"hashes": [
|
|
686
|
+
{
|
|
687
|
+
"alg": "SHA-256",
|
|
688
|
+
"content": "ff59e5bc4e293a465dae508d6c50fead4d9925b890f33a737b8716ae0529287f"
|
|
689
|
+
}
|
|
690
|
+
]
|
|
691
|
+
},
|
|
692
|
+
{
|
|
693
|
+
"type": "file",
|
|
694
|
+
"name": "dist/checkpoint-stamp.js",
|
|
695
|
+
"hashes": [
|
|
696
|
+
{
|
|
697
|
+
"alg": "SHA-256",
|
|
698
|
+
"content": "925ab26d210efe89d02924e979b6cb1598a3289af4c94c87734af04e7b992620"
|
|
699
|
+
}
|
|
700
|
+
]
|
|
701
|
+
},
|
|
702
|
+
{
|
|
703
|
+
"type": "file",
|
|
704
|
+
"name": "dist/checkpoint-stamp.js.map",
|
|
705
|
+
"hashes": [
|
|
706
|
+
{
|
|
707
|
+
"alg": "SHA-256",
|
|
708
|
+
"content": "aa2887d4e9129aa14cb8b6dbd138307c1a9f06860cfe80cb985176b17db399e3"
|
|
709
|
+
}
|
|
710
|
+
]
|
|
711
|
+
},
|
|
672
712
|
{
|
|
673
713
|
"type": "file",
|
|
674
714
|
"name": "dist/claim-check-hook-policy.d.ts",
|
|
@@ -1355,7 +1395,7 @@
|
|
|
1355
1395
|
"hashes": [
|
|
1356
1396
|
{
|
|
1357
1397
|
"alg": "SHA-256",
|
|
1358
|
-
"content": "
|
|
1398
|
+
"content": "ba30eb15d8b125a3fbf71897fc848807b4636f676b2bc5c0cfb14c71d4667fa0"
|
|
1359
1399
|
}
|
|
1360
1400
|
]
|
|
1361
1401
|
},
|
|
@@ -1365,7 +1405,7 @@
|
|
|
1365
1405
|
"hashes": [
|
|
1366
1406
|
{
|
|
1367
1407
|
"alg": "SHA-256",
|
|
1368
|
-
"content": "
|
|
1408
|
+
"content": "c1ee8730f59317e337b65fb200e2c2d6a817f87014ce84f192702aed9e38d14f"
|
|
1369
1409
|
}
|
|
1370
1410
|
]
|
|
1371
1411
|
},
|
|
@@ -1385,7 +1425,7 @@
|
|
|
1385
1425
|
"hashes": [
|
|
1386
1426
|
{
|
|
1387
1427
|
"alg": "SHA-256",
|
|
1388
|
-
"content": "
|
|
1428
|
+
"content": "739d561a337682247f3341878b2c65254a2cf90db38513a73535a6f1dd7f0752"
|
|
1389
1429
|
}
|
|
1390
1430
|
]
|
|
1391
1431
|
},
|
|
@@ -1635,7 +1675,7 @@
|
|
|
1635
1675
|
"hashes": [
|
|
1636
1676
|
{
|
|
1637
1677
|
"alg": "SHA-256",
|
|
1638
|
-
"content": "
|
|
1678
|
+
"content": "38dd2203725d14c8cc6a160b6dc5d5cc87a8a68fca1fc97adfe5dac2f4b614da"
|
|
1639
1679
|
}
|
|
1640
1680
|
]
|
|
1641
1681
|
},
|
|
@@ -1645,7 +1685,7 @@
|
|
|
1645
1685
|
"hashes": [
|
|
1646
1686
|
{
|
|
1647
1687
|
"alg": "SHA-256",
|
|
1648
|
-
"content": "
|
|
1688
|
+
"content": "f332fe0f06b828770b57c108c2e0800a0357348d4ac3836f32cf7bb1d21c8bcc"
|
|
1649
1689
|
}
|
|
1650
1690
|
]
|
|
1651
1691
|
},
|
|
@@ -1655,7 +1695,7 @@
|
|
|
1655
1695
|
"hashes": [
|
|
1656
1696
|
{
|
|
1657
1697
|
"alg": "SHA-256",
|
|
1658
|
-
"content": "
|
|
1698
|
+
"content": "3bf1303754b6ef33cd1411eb5b66c8ab3dc23d0b64e08ec25f2eb2c89df2d605"
|
|
1659
1699
|
}
|
|
1660
1700
|
]
|
|
1661
1701
|
},
|
|
@@ -1665,7 +1705,7 @@
|
|
|
1665
1705
|
"hashes": [
|
|
1666
1706
|
{
|
|
1667
1707
|
"alg": "SHA-256",
|
|
1668
|
-
"content": "
|
|
1708
|
+
"content": "deefbbeece6faa04ae970a7bad4a2671922646e75a7206ac8f0b0119b8681ac6"
|
|
1669
1709
|
}
|
|
1670
1710
|
]
|
|
1671
1711
|
},
|
|
@@ -1709,6 +1749,46 @@
|
|
|
1709
1749
|
}
|
|
1710
1750
|
]
|
|
1711
1751
|
},
|
|
1752
|
+
{
|
|
1753
|
+
"type": "file",
|
|
1754
|
+
"name": "dist/ledger-backfill.d.ts",
|
|
1755
|
+
"hashes": [
|
|
1756
|
+
{
|
|
1757
|
+
"alg": "SHA-256",
|
|
1758
|
+
"content": "ef962a467ec121fa41ed346fe1ac619333f7e76c209173a7d4d5897ef9d6d5c7"
|
|
1759
|
+
}
|
|
1760
|
+
]
|
|
1761
|
+
},
|
|
1762
|
+
{
|
|
1763
|
+
"type": "file",
|
|
1764
|
+
"name": "dist/ledger-backfill.d.ts.map",
|
|
1765
|
+
"hashes": [
|
|
1766
|
+
{
|
|
1767
|
+
"alg": "SHA-256",
|
|
1768
|
+
"content": "776d033d3aeffeb40af85cf2dd318ddff35bf08c8867cd56502f3240e841deb3"
|
|
1769
|
+
}
|
|
1770
|
+
]
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
"type": "file",
|
|
1774
|
+
"name": "dist/ledger-backfill.js",
|
|
1775
|
+
"hashes": [
|
|
1776
|
+
{
|
|
1777
|
+
"alg": "SHA-256",
|
|
1778
|
+
"content": "d8849acd78274c7f5ac82fda839899b1df107eab5cb4d58086d3b89a38fb30af"
|
|
1779
|
+
}
|
|
1780
|
+
]
|
|
1781
|
+
},
|
|
1782
|
+
{
|
|
1783
|
+
"type": "file",
|
|
1784
|
+
"name": "dist/ledger-backfill.js.map",
|
|
1785
|
+
"hashes": [
|
|
1786
|
+
{
|
|
1787
|
+
"alg": "SHA-256",
|
|
1788
|
+
"content": "f3d4b2dfaef7cf56542d489bc57a6dcbca97f20181bc1fd2d293341be5dd3706"
|
|
1789
|
+
}
|
|
1790
|
+
]
|
|
1791
|
+
},
|
|
1712
1792
|
{
|
|
1713
1793
|
"type": "file",
|
|
1714
1794
|
"name": "dist/loop-blobs.generated.d.ts",
|
|
@@ -2285,7 +2365,7 @@
|
|
|
2285
2365
|
"hashes": [
|
|
2286
2366
|
{
|
|
2287
2367
|
"alg": "SHA-256",
|
|
2288
|
-
"content": "
|
|
2368
|
+
"content": "d1c3b12bfae90c560ccd3a20a988e219d215da92122da4729a1a549f32894656"
|
|
2289
2369
|
}
|
|
2290
2370
|
]
|
|
2291
2371
|
},
|
|
@@ -2295,7 +2375,7 @@
|
|
|
2295
2375
|
"hashes": [
|
|
2296
2376
|
{
|
|
2297
2377
|
"alg": "SHA-256",
|
|
2298
|
-
"content": "
|
|
2378
|
+
"content": "e48fe1595148cc7b8859d8d89eef7c444c5d9c3025a3addfaa669d6762789c3f"
|
|
2299
2379
|
}
|
|
2300
2380
|
]
|
|
2301
2381
|
},
|
|
@@ -2305,7 +2385,7 @@
|
|
|
2305
2385
|
"hashes": [
|
|
2306
2386
|
{
|
|
2307
2387
|
"alg": "SHA-256",
|
|
2308
|
-
"content": "
|
|
2388
|
+
"content": "cea487680c0fdfa429a06815ef5362f9c635bc3e9d3592efc8d7db526f3d21d4"
|
|
2309
2389
|
}
|
|
2310
2390
|
]
|
|
2311
2391
|
},
|
|
@@ -3355,7 +3435,7 @@
|
|
|
3355
3435
|
"hashes": [
|
|
3356
3436
|
{
|
|
3357
3437
|
"alg": "SHA-256",
|
|
3358
|
-
"content": "
|
|
3438
|
+
"content": "0558d5a3ea988184f08459a3ed0c6e138541b86cb78cbca378a6ceef797f3c1f"
|
|
3359
3439
|
}
|
|
3360
3440
|
]
|
|
3361
3441
|
},
|
|
@@ -3365,7 +3445,7 @@
|
|
|
3365
3445
|
"hashes": [
|
|
3366
3446
|
{
|
|
3367
3447
|
"alg": "SHA-256",
|
|
3368
|
-
"content": "
|
|
3448
|
+
"content": "4775208c01c974b495c6001974902447bf3375ed675e4822dc8c1d5022b2e665"
|
|
3369
3449
|
}
|
|
3370
3450
|
]
|
|
3371
3451
|
},
|
|
@@ -3375,7 +3455,7 @@
|
|
|
3375
3455
|
"hashes": [
|
|
3376
3456
|
{
|
|
3377
3457
|
"alg": "SHA-256",
|
|
3378
|
-
"content": "
|
|
3458
|
+
"content": "ce87f3d528feaeb2f5c9d1c0287065078b388fd2b061a3412a49a836938ca7a8"
|
|
3379
3459
|
}
|
|
3380
3460
|
]
|
|
3381
3461
|
},
|
|
@@ -3385,7 +3465,7 @@
|
|
|
3385
3465
|
"hashes": [
|
|
3386
3466
|
{
|
|
3387
3467
|
"alg": "SHA-256",
|
|
3388
|
-
"content": "
|
|
3468
|
+
"content": "7bcbb79b446908423948e131d1abfc3b01f6caf1ddcadeeffe083614bf119bbf"
|
|
3389
3469
|
}
|
|
3390
3470
|
]
|
|
3391
3471
|
},
|
|
@@ -3909,6 +3989,46 @@
|
|
|
3909
3989
|
}
|
|
3910
3990
|
]
|
|
3911
3991
|
},
|
|
3992
|
+
{
|
|
3993
|
+
"type": "file",
|
|
3994
|
+
"name": "dist/telemetry-vocabulary.d.ts",
|
|
3995
|
+
"hashes": [
|
|
3996
|
+
{
|
|
3997
|
+
"alg": "SHA-256",
|
|
3998
|
+
"content": "034f40510ecaa9ae9d867f482c87dbf3a1f771bc9b7ec67ff181fa4f9acf6499"
|
|
3999
|
+
}
|
|
4000
|
+
]
|
|
4001
|
+
},
|
|
4002
|
+
{
|
|
4003
|
+
"type": "file",
|
|
4004
|
+
"name": "dist/telemetry-vocabulary.d.ts.map",
|
|
4005
|
+
"hashes": [
|
|
4006
|
+
{
|
|
4007
|
+
"alg": "SHA-256",
|
|
4008
|
+
"content": "9431269b10db42cba8796139d104a61182b08f080c7497b84542e7649c9947b5"
|
|
4009
|
+
}
|
|
4010
|
+
]
|
|
4011
|
+
},
|
|
4012
|
+
{
|
|
4013
|
+
"type": "file",
|
|
4014
|
+
"name": "dist/telemetry-vocabulary.js",
|
|
4015
|
+
"hashes": [
|
|
4016
|
+
{
|
|
4017
|
+
"alg": "SHA-256",
|
|
4018
|
+
"content": "9cedc164e6d9b68583912a738c70b712763241c6b2d91a9e904505ebd31118e1"
|
|
4019
|
+
}
|
|
4020
|
+
]
|
|
4021
|
+
},
|
|
4022
|
+
{
|
|
4023
|
+
"type": "file",
|
|
4024
|
+
"name": "dist/telemetry-vocabulary.js.map",
|
|
4025
|
+
"hashes": [
|
|
4026
|
+
{
|
|
4027
|
+
"alg": "SHA-256",
|
|
4028
|
+
"content": "a35a1fc29fc679ed9f27e43482a041a9d32f61289924f6e7599765043be8ec45"
|
|
4029
|
+
}
|
|
4030
|
+
]
|
|
4031
|
+
},
|
|
3912
4032
|
{
|
|
3913
4033
|
"type": "file",
|
|
3914
4034
|
"name": "dist/tg-post.d.ts",
|
|
@@ -4315,7 +4435,7 @@
|
|
|
4315
4435
|
"hashes": [
|
|
4316
4436
|
{
|
|
4317
4437
|
"alg": "SHA-256",
|
|
4318
|
-
"content": "
|
|
4438
|
+
"content": "9f9f11a90c62c19e029e256d4ebf4d4e1b2c232103cfc0acb899e0760b3a6011"
|
|
4319
4439
|
}
|
|
4320
4440
|
]
|
|
4321
4441
|
},
|
|
@@ -4479,6 +4599,16 @@
|
|
|
4479
4599
|
}
|
|
4480
4600
|
]
|
|
4481
4601
|
},
|
|
4602
|
+
{
|
|
4603
|
+
"type": "file",
|
|
4604
|
+
"name": "src/checkpoint-stamp.ts",
|
|
4605
|
+
"hashes": [
|
|
4606
|
+
{
|
|
4607
|
+
"alg": "SHA-256",
|
|
4608
|
+
"content": "35fdc7c788149c846114641b8dca2594a800e8210062478de04f42d0a11cc076"
|
|
4609
|
+
}
|
|
4610
|
+
]
|
|
4611
|
+
},
|
|
4482
4612
|
{
|
|
4483
4613
|
"type": "file",
|
|
4484
4614
|
"name": "src/claim-check-hook-policy.ts",
|
|
@@ -4655,7 +4785,7 @@
|
|
|
4655
4785
|
"hashes": [
|
|
4656
4786
|
{
|
|
4657
4787
|
"alg": "SHA-256",
|
|
4658
|
-
"content": "
|
|
4788
|
+
"content": "1b857c02834026d729b35a2df5998bc8a8e42dc124c6f6f07dad3b5a08d2e6f2"
|
|
4659
4789
|
}
|
|
4660
4790
|
]
|
|
4661
4791
|
},
|
|
@@ -4725,7 +4855,7 @@
|
|
|
4725
4855
|
"hashes": [
|
|
4726
4856
|
{
|
|
4727
4857
|
"alg": "SHA-256",
|
|
4728
|
-
"content": "
|
|
4858
|
+
"content": "f708c193adde6854ca13b7bb6e1d2918a5216c249d67d5e10c83f846320082b5"
|
|
4729
4859
|
}
|
|
4730
4860
|
]
|
|
4731
4861
|
},
|
|
@@ -4739,6 +4869,16 @@
|
|
|
4739
4869
|
}
|
|
4740
4870
|
]
|
|
4741
4871
|
},
|
|
4872
|
+
{
|
|
4873
|
+
"type": "file",
|
|
4874
|
+
"name": "src/ledger-backfill.ts",
|
|
4875
|
+
"hashes": [
|
|
4876
|
+
{
|
|
4877
|
+
"alg": "SHA-256",
|
|
4878
|
+
"content": "5659ef646baec7a952a4c7bf9eddc1cde24205ae8eb39f43999c5656ace42224"
|
|
4879
|
+
}
|
|
4880
|
+
]
|
|
4881
|
+
},
|
|
4742
4882
|
{
|
|
4743
4883
|
"type": "file",
|
|
4744
4884
|
"name": "src/loop-blobs.generated.ts",
|
|
@@ -4885,7 +5025,7 @@
|
|
|
4885
5025
|
"hashes": [
|
|
4886
5026
|
{
|
|
4887
5027
|
"alg": "SHA-256",
|
|
4888
|
-
"content": "
|
|
5028
|
+
"content": "3b61b04d7fbcf6186695ea9afc8750d4d3c7dd633285a53b972e6544579a5c7b"
|
|
4889
5029
|
}
|
|
4890
5030
|
]
|
|
4891
5031
|
},
|
|
@@ -5135,7 +5275,7 @@
|
|
|
5135
5275
|
"hashes": [
|
|
5136
5276
|
{
|
|
5137
5277
|
"alg": "SHA-256",
|
|
5138
|
-
"content": "
|
|
5278
|
+
"content": "31c96e4bae47eedea0ef30b4a79997ef05e950dc8c61a3fd9b4c41070bb72ada"
|
|
5139
5279
|
}
|
|
5140
5280
|
]
|
|
5141
5281
|
},
|
|
@@ -5279,6 +5419,16 @@
|
|
|
5279
5419
|
}
|
|
5280
5420
|
]
|
|
5281
5421
|
},
|
|
5422
|
+
{
|
|
5423
|
+
"type": "file",
|
|
5424
|
+
"name": "src/telemetry-vocabulary.ts",
|
|
5425
|
+
"hashes": [
|
|
5426
|
+
{
|
|
5427
|
+
"alg": "SHA-256",
|
|
5428
|
+
"content": "8d6c4da15bb76eca46bff58a0519e4fc0f0b835e5a2b20fa701425ae8d518f10"
|
|
5429
|
+
}
|
|
5430
|
+
]
|
|
5431
|
+
},
|
|
5282
5432
|
{
|
|
5283
5433
|
"type": "file",
|
|
5284
5434
|
"name": "src/tg-post.ts",
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stamp a checkpoint line with the instant it was WRITTEN.
|
|
3
|
+
*
|
|
4
|
+
* Deliberately NOT part of `feature-adr-checkpoints.ts`. That module's functions are mirrored
|
|
5
|
+
* verbatim into the sandboxed workflow through the loop-blob registry, and the sandbox has no
|
|
6
|
+
* `Date` — so a clock has no business inside a function the clockless copy also runs. Changing the
|
|
7
|
+
* mirrored serializer would also drag the whole blob regeneration + region re-render behind a
|
|
8
|
+
* one-field addition, which is a large machine for a small honest fact.
|
|
9
|
+
*
|
|
10
|
+
* The stamp belongs to the WRITER. Only the CLI performing the append has a clock, so only the CLI
|
|
11
|
+
* stamps, here, at the boundary.
|
|
12
|
+
*
|
|
13
|
+
* WHY IT EXISTS (MEASURED 2026-08-25): `.fa-state/checkpoints.jsonl` carried no time field of any
|
|
14
|
+
* kind, so across 241 feature dirs "how long did this stage take" had no answer for a single run —
|
|
15
|
+
* and no future run could answer it either.
|
|
16
|
+
*
|
|
17
|
+
* @packageDocumentation
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** An ISO-8601 UTC instant exactly as `Date#toISOString` emits it. Anything else we did not write. */
|
|
21
|
+
const ISO_INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?Z$/;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Return `line` with a `ts` field, or `line` UNCHANGED when the stamp is absent or malformed.
|
|
25
|
+
*
|
|
26
|
+
* Three properties, each a test:
|
|
27
|
+
* - an ABSENT stamp leaves the record with no `ts` — unknown, never zero and never "now". Inventing
|
|
28
|
+
* one would make every pre-existing record indistinguishable from a measured one.
|
|
29
|
+
* - a MALFORMED stamp is dropped. A wrong instant is worse than an absent one: only the absent one
|
|
30
|
+
* is readable as unmeasured.
|
|
31
|
+
* - an EXISTING `ts` is never overwritten, and a line that is not a JSON object is passed through
|
|
32
|
+
* untouched — this runs on the way to an append-only log.
|
|
33
|
+
*/
|
|
34
|
+
export function stampCheckpointLine(line: string, ts: string): string {
|
|
35
|
+
if (!ISO_INSTANT.test(ts)) return line;
|
|
36
|
+
let parsed: unknown;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(line);
|
|
39
|
+
} catch {
|
|
40
|
+
return line;
|
|
41
|
+
}
|
|
42
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return line;
|
|
43
|
+
const row = parsed as Record<string, unknown>;
|
|
44
|
+
if (typeof row['ts'] === 'string') return line;
|
|
45
|
+
try {
|
|
46
|
+
return JSON.stringify({ ...row, ts });
|
|
47
|
+
} catch {
|
|
48
|
+
return line;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -56,6 +56,26 @@ export interface CheckpointEntry {
|
|
|
56
56
|
stage: string;
|
|
57
57
|
inputHash: string;
|
|
58
58
|
result: unknown;
|
|
59
|
+
/**
|
|
60
|
+
* ISO-8601 UTC instant the checkpoint was WRITTEN, supplied by the writer.
|
|
61
|
+
*
|
|
62
|
+
* OPTIONAL by necessity and by design. The sandboxed workflow has no `Date` at all, so it cannot
|
|
63
|
+
* stamp its own records — only the CLI that performs the append can, and only for the write, not
|
|
64
|
+
* for the stage's start. Absent `ts` therefore means UNKNOWN, never zero and never "instant": a
|
|
65
|
+
* pre-2026-08-25 record simply predates the field, and a reader must say so rather than compute a
|
|
66
|
+
* duration from a missing number.
|
|
67
|
+
*
|
|
68
|
+
* Why this exists at all: until it was added, `.fa-state/checkpoints.jsonl` carried no time field
|
|
69
|
+
* of any kind, so across 241 feature dirs the question "how long did this stage take" had no
|
|
70
|
+
* answer for a single run — and no FUTURE run could answer it either. This is the whole of the
|
|
71
|
+
* fix: one optional field, and every run from now on can be placed on a timeline.
|
|
72
|
+
*
|
|
73
|
+
* Deliberately NOT accompanied by a {@link CKPT_SCHEMA_VERSION} bump. The version is SALTED into
|
|
74
|
+
* every input hash, so bumping it would hash every in-flight checkpoint stale and force each
|
|
75
|
+
* feature to re-run router+design+plan. Stage semantics did not change; an additive optional field
|
|
76
|
+
* that old readers ignore and new readers treat as unknown is not a format break.
|
|
77
|
+
*/
|
|
78
|
+
ts?: string;
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
/** Oversize guard: a result JSON above this is NOT checkpointed (the stage simply re-runs on resume).
|
package/src/index.ts
CHANGED
|
@@ -77,6 +77,11 @@ export { checkUpstream, checkAllUpstream, discoverSourcePackages, loadSourcesMan
|
|
|
77
77
|
export type { SyncUpstreamReport, UpstreamCheckResult, SourcesManifest, SourcePackageInfo } from './sync-upstream.js';
|
|
78
78
|
export { sweepSkillDrift, syncCanonicalSkill } from './skill-drift.js';
|
|
79
79
|
export { SKILL_INSTALL_ROOTS, SKILL_INSTALL_ROOT_BY_TARGET, DEV_SKILL_ROOT, TARGET_ENRICHMENT_ASSETS } from './skill-install-roots.js';
|
|
80
|
+
export { stampCheckpointLine } from './checkpoint-stamp.js';
|
|
81
|
+
export { TELEMETRY_VOCAB_VERSION, TELEMETRY_FIELDS, PROVISIONAL_TELEMETRY_FIELDS, LOCAL_FIELD_ALIASES, telemetryFieldFor } from './telemetry-vocabulary.js';
|
|
82
|
+
export type { TelemetryField, FieldSource } from './telemetry-vocabulary.js';
|
|
83
|
+
export { planLedgerBackfill, LEDGER_FILL_SOURCE, AMBIGUOUS, resolveLedgerRunId } from './ledger-backfill.js';
|
|
84
|
+
export type { LedgerBackfillPlan, LedgerBackfillRow, RunCostFacts } from './ledger-backfill.js';
|
|
80
85
|
export type { SweepResult, DriftedSkill, SyncResult, SyncCanonicalOptions } from './skill-drift.js';
|
|
81
86
|
export { benchmarkSkill, benchmarkSkills, compareSkills } from './benchmark.js';
|
|
82
87
|
export { buildRegistry, searchRegistry, filterByCategory, skillPackBaseDirs, discoverSkillPackDirs, discoverVerifiablePackDirs } from './registry.js';
|