@rasensio/aidlc 1.13.1 → 1.14.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/dist/commands/cost.d.ts.map +1 -1
- package/dist/commands/cost.js +16 -2
- package/dist/commands/cost.js.map +1 -1
- package/dist/commands/transition.js +31 -16
- package/dist/commands/transition.js.map +1 -1
- package/dist/core/types.d.ts +16 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/cost/ledger.d.ts.map +1 -1
- package/dist/cost/ledger.js +9 -0
- package/dist/cost/ledger.js.map +1 -1
- package/dist/cost/provenance.d.ts +80 -0
- package/dist/cost/provenance.d.ts.map +1 -0
- package/dist/cost/provenance.js +192 -0
- package/dist/cost/provenance.js.map +1 -0
- package/dist/cost/providers/claude-code.d.ts.map +1 -1
- package/dist/cost/providers/claude-code.js +24 -1
- package/dist/cost/providers/claude-code.js.map +1 -1
- package/dist/cost/purge.d.ts +65 -0
- package/dist/cost/purge.d.ts.map +1 -0
- package/dist/cost/purge.js +152 -0
- package/dist/cost/purge.js.map +1 -0
- package/dist/cost/recorder.d.ts +36 -1
- package/dist/cost/recorder.d.ts.map +1 -1
- package/dist/cost/recorder.js +112 -6
- package/dist/cost/recorder.js.map +1 -1
- package/dist/cost/rederive.d.ts +80 -0
- package/dist/cost/rederive.d.ts.map +1 -0
- package/dist/cost/rederive.js +257 -0
- package/dist/cost/rederive.js.map +1 -0
- package/dist/cost/report.d.ts +17 -0
- package/dist/cost/report.d.ts.map +1 -1
- package/dist/cost/report.js +49 -1
- package/dist/cost/report.js.map +1 -1
- package/dist/cost/sync.d.ts.map +1 -1
- package/dist/cost/sync.js +166 -40
- package/dist/cost/sync.js.map +1 -1
- package/dist/cost/types.d.ts +45 -1
- package/dist/cost/types.d.ts.map +1 -1
- package/dist/cost/types.js +16 -2
- package/dist/cost/types.js.map +1 -1
- package/dist/doctor/migrations/index.d.ts.map +1 -1
- package/dist/doctor/migrations/index.js +5 -0
- package/dist/doctor/migrations/index.js.map +1 -1
- package/dist/doctor/migrations/instance-completion.d.ts +85 -0
- package/dist/doctor/migrations/instance-completion.d.ts.map +1 -0
- package/dist/doctor/migrations/instance-completion.js +214 -0
- package/dist/doctor/migrations/instance-completion.js.map +1 -0
- package/dist/events/event-bus.d.ts.map +1 -1
- package/dist/events/event-bus.js +12 -1
- package/dist/events/event-bus.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cursor provenance: which repository did a ledger entry's usage actually come from?
|
|
3
|
+
*
|
|
4
|
+
* Every priced ledger entry carries a `cursor` — the uuid of the transcript record
|
|
5
|
+
* it was extracted from. That makes provenance *checkable* rather than inferred:
|
|
6
|
+
* find the transcript file containing that uuid and ask which repo it belongs to.
|
|
7
|
+
*
|
|
8
|
+
* This exists because `transcriptRoot` is one directory holding every project this
|
|
9
|
+
* machine has ever worked on, and `sync.ts:locateByInterval` walked all of them
|
|
10
|
+
* matching on file mtime with no repository check. The measured result was 711
|
|
11
|
+
* entries (262.5M tokens) from an unrelated repository sitting in two instance
|
|
12
|
+
* ledgers — one instance's entire cost figure was another project's work.
|
|
13
|
+
* `projectClaudeCodeRecords` already scopes *forward* correctly; this scopes
|
|
14
|
+
* *backward*, over entries already written.
|
|
15
|
+
*
|
|
16
|
+
* Two properties are deliberate and load-bearing:
|
|
17
|
+
*
|
|
18
|
+
* 1. **A uuid is not guaranteed unique across files.** `/branch` copies a
|
|
19
|
+
* transcript, so the same uuid can appear in several. Measured here: 102 uuids
|
|
20
|
+
* in two files each, 0 crossing a repository boundary. So a uuid resolving into
|
|
21
|
+
* more than one repo is `ambiguous`, never `foreign` — the purge must not delete
|
|
22
|
+
* on a coin flip that happens to be safe today.
|
|
23
|
+
* 2. **Unknown is not foreign.** A cursor absent from every transcript (2,065 here,
|
|
24
|
+
* from rotated or deleted files) and a cwd whose git identity cannot be read are
|
|
25
|
+
* both `unknown`. Under-recovering is the safe direction, the same choice
|
|
26
|
+
* `projectClaudeCodeRecords` documents.
|
|
27
|
+
*
|
|
28
|
+
* Requirements: turn-scoped-cost/AC-34, AC-43
|
|
29
|
+
* Design: design.md Part 0 (D0.1, D0.3, D0.4, D0.7)
|
|
30
|
+
*/
|
|
31
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
32
|
+
import { execFileSync } from 'node:child_process';
|
|
33
|
+
import { join, resolve } from 'node:path';
|
|
34
|
+
import { transcriptRoot } from './providers/claude-code.js';
|
|
35
|
+
/**
|
|
36
|
+
* A directory's git common dir, as an absolute path — the identity every worktree
|
|
37
|
+
* of one repository shares.
|
|
38
|
+
*
|
|
39
|
+
* Same expression as `sync.ts:repoCommonDir`, kept separate for the same reason
|
|
40
|
+
* that one is kept separate from `sessions.ts:repoIdentity`: `git rev-parse
|
|
41
|
+
* --git-common-dir` answers relatively from a primary checkout and absolutely from
|
|
42
|
+
* a linked worktree, so the `resolve` is required, and callers with the opposite
|
|
43
|
+
* requirement must not share it.
|
|
44
|
+
*/
|
|
45
|
+
export function repoCommonDir(cwd) {
|
|
46
|
+
try {
|
|
47
|
+
const out = execFileSync('git', ['rev-parse', '--git-common-dir'], {
|
|
48
|
+
cwd,
|
|
49
|
+
encoding: 'utf8',
|
|
50
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
51
|
+
}).trim();
|
|
52
|
+
return resolve(cwd, out);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The `cwd` a transcript was recorded in, read from its own contents.
|
|
60
|
+
*
|
|
61
|
+
* The directory name under `~/.claude/projects` is the cwd with separators
|
|
62
|
+
* flattened to dashes, which is lossy — a real directory containing a dash is
|
|
63
|
+
* indistinguishable from a separator — so the name cannot be reversed safely.
|
|
64
|
+
* The transcript records its cwd verbatim, so ask it.
|
|
65
|
+
*/
|
|
66
|
+
function transcriptCwd(lines) {
|
|
67
|
+
let scanned = 0;
|
|
68
|
+
for (const line of lines) {
|
|
69
|
+
if (line.trim() === '')
|
|
70
|
+
continue;
|
|
71
|
+
if (++scanned > 50)
|
|
72
|
+
break;
|
|
73
|
+
try {
|
|
74
|
+
const parsed = JSON.parse(line);
|
|
75
|
+
if (typeof parsed.cwd === 'string' && parsed.cwd !== '')
|
|
76
|
+
return parsed.cwd;
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Index every uuid in every local transcript to the repo identity of its file.
|
|
86
|
+
*
|
|
87
|
+
* One pass over the transcript root, because the alternative — resolving each
|
|
88
|
+
* cursor on demand — rescans every file per lookup. A transcript whose cwd or git
|
|
89
|
+
* identity cannot be read contributes its uuids under no identity at all, which
|
|
90
|
+
* makes them `unknown` rather than silently `foreign`.
|
|
91
|
+
*/
|
|
92
|
+
export function buildProvenanceIndex(env,
|
|
93
|
+
/**
|
|
94
|
+
* What to record per uuid. Defaults to the repo identity, which is what purging
|
|
95
|
+
* needs; re-derivation passes the file path instead, because a split has to open
|
|
96
|
+
* the transcript. One walk, two callers — the alternative was a second traversal
|
|
97
|
+
* that could disagree with this one about which file holds a uuid.
|
|
98
|
+
*/
|
|
99
|
+
valueOf = (_path, identity) => identity) {
|
|
100
|
+
const index = new Map();
|
|
101
|
+
const root = transcriptRoot(env);
|
|
102
|
+
if (!existsSync(root))
|
|
103
|
+
return index;
|
|
104
|
+
const identityCache = new Map();
|
|
105
|
+
const identityOf = (cwd) => {
|
|
106
|
+
if (!identityCache.has(cwd))
|
|
107
|
+
identityCache.set(cwd, repoCommonDir(cwd));
|
|
108
|
+
return identityCache.get(cwd) ?? null;
|
|
109
|
+
};
|
|
110
|
+
let dirs;
|
|
111
|
+
try {
|
|
112
|
+
dirs = readdirSync(root, { withFileTypes: true });
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return index;
|
|
116
|
+
}
|
|
117
|
+
for (const dir of dirs) {
|
|
118
|
+
if (!dir.isDirectory())
|
|
119
|
+
continue;
|
|
120
|
+
let files;
|
|
121
|
+
try {
|
|
122
|
+
files = readdirSync(join(root, dir.name));
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
for (const f of files) {
|
|
128
|
+
if (!f.endsWith('.jsonl'))
|
|
129
|
+
continue;
|
|
130
|
+
const path = join(root, dir.name, f);
|
|
131
|
+
let lines;
|
|
132
|
+
try {
|
|
133
|
+
lines = readFileSync(path, 'utf8').split('\n');
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
const cwd = transcriptCwd(lines);
|
|
139
|
+
// No cwd, or no readable git identity: uuids stay unattributed to any repo,
|
|
140
|
+
// so they read as `unknown` and are never purged.
|
|
141
|
+
const identity = cwd === null ? null : identityOf(cwd);
|
|
142
|
+
if (identity === null)
|
|
143
|
+
continue;
|
|
144
|
+
const value = valueOf(path, identity);
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
const t = line.trim();
|
|
147
|
+
if (t === '')
|
|
148
|
+
continue;
|
|
149
|
+
let entry;
|
|
150
|
+
try {
|
|
151
|
+
entry = JSON.parse(t);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
if (typeof entry.uuid !== 'string' || entry.uuid === '')
|
|
157
|
+
continue;
|
|
158
|
+
const set = index.get(entry.uuid);
|
|
159
|
+
if (set)
|
|
160
|
+
set.add(value);
|
|
161
|
+
else
|
|
162
|
+
index.set(entry.uuid, new Set([value]));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return index;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Classify one cursor against this repository.
|
|
170
|
+
*
|
|
171
|
+
* `null`/empty cursor is `unknown`: an entry with nothing to trace cannot be shown
|
|
172
|
+
* to be foreign. A cursor found under this repo's identity is `local` even if it
|
|
173
|
+
* also appears elsewhere — the local sighting is positive evidence that this repo
|
|
174
|
+
* produced it, which is exactly what a `/branch` copy looks like.
|
|
175
|
+
*/
|
|
176
|
+
export function classifyCursor(cursor, index, hereIdentity) {
|
|
177
|
+
if (cursor === null || cursor === '')
|
|
178
|
+
return 'unknown';
|
|
179
|
+
const identities = index.get(cursor);
|
|
180
|
+
if (identities === undefined || identities.size === 0)
|
|
181
|
+
return 'unknown';
|
|
182
|
+
if (hereIdentity !== null && identities.has(hereIdentity))
|
|
183
|
+
return 'local';
|
|
184
|
+
if (identities.size > 1)
|
|
185
|
+
return 'ambiguous';
|
|
186
|
+
return 'foreign';
|
|
187
|
+
}
|
|
188
|
+
/** Is this cursor safe to purge — i.e. positively shown to be another repo's? */
|
|
189
|
+
export function isPurgeable(origin) {
|
|
190
|
+
return origin === 'foreign';
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.js","sourceRoot":"","sources":["../../src/cost/provenance.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/cost/providers/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE/D,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAIvD;AAMD,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,eAAO,MAAM,kBAAkB,EAAE,
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/cost/providers/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE/D,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAIvD;AAMD,2EAA2E;AAC3E,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD;AAED,eAAO,MAAM,kBAAkB,EAAE,YA+HhC,CAAC"}
|
|
@@ -90,6 +90,17 @@ export const claudeCodeProvider = {
|
|
|
90
90
|
// everything; the recorder's coverage dedup handles the overlap.
|
|
91
91
|
let skipping = since !== null;
|
|
92
92
|
const all = [];
|
|
93
|
+
/*
|
|
94
|
+
* uuid → timestamp, for resolving each record's parent so a span can be
|
|
95
|
+
* measured (turn-scoped-cost/AC-19).
|
|
96
|
+
*
|
|
97
|
+
* A forward-only map is sufficient, and that is a measured fact rather than an
|
|
98
|
+
* assumption: across 13,886 usage records in this repo's transcripts, the
|
|
99
|
+
* parent appears earlier in the same file 100% of the time and never later. So
|
|
100
|
+
* this stays a single streaming pass — no full-file index, and memory holds one
|
|
101
|
+
* short string per record rather than the record itself.
|
|
102
|
+
*/
|
|
103
|
+
const stamps = new Map();
|
|
93
104
|
for await (const line of rl) {
|
|
94
105
|
const t = line.trim();
|
|
95
106
|
if (t === '')
|
|
@@ -102,6 +113,7 @@ export const claudeCodeProvider = {
|
|
|
102
113
|
continue;
|
|
103
114
|
}
|
|
104
115
|
const uuid = typeof entry.uuid === 'string' ? entry.uuid : null;
|
|
116
|
+
const parentUuid = typeof entry.parentUuid === 'string' ? entry.parentUuid : null;
|
|
105
117
|
const message = entry.message;
|
|
106
118
|
const usage = message?.usage;
|
|
107
119
|
const model = typeof message?.model === 'string' ? message.model : null;
|
|
@@ -117,12 +129,23 @@ export const claudeCodeProvider = {
|
|
|
117
129
|
cache_read_tokens: isCount(usage.cache_read_input_tokens) ? usage.cache_read_input_tokens : 0,
|
|
118
130
|
cache_write_tokens: isCount(usage.cache_creation_input_tokens) ? usage.cache_creation_input_tokens : 0,
|
|
119
131
|
};
|
|
120
|
-
|
|
132
|
+
// Span endpoints, never a duration — see UsageSegment.span. A parent whose
|
|
133
|
+
// timestamp is unknown (chain root, or a record the file does not contain)
|
|
134
|
+
// yields null rather than a zero-length span, so "unmeasured" stays
|
|
135
|
+
// distinguishable from "instantaneous".
|
|
136
|
+
const parentAt = parentUuid !== null ? stamps.get(parentUuid) : undefined;
|
|
137
|
+
const span = parentAt !== undefined && Date.parse(parentAt) <= Date.parse(at)
|
|
138
|
+
? { from: parentAt, to: at }
|
|
139
|
+
: null;
|
|
140
|
+
const seg = { at, units, cursor: uuid, span };
|
|
121
141
|
if (skipping)
|
|
122
142
|
all.push(seg);
|
|
123
143
|
else
|
|
124
144
|
segments.push(seg);
|
|
125
145
|
}
|
|
146
|
+
if (uuid !== null && typeof entry.timestamp === 'string') {
|
|
147
|
+
stamps.set(uuid, entry.timestamp);
|
|
148
|
+
}
|
|
126
149
|
if (skipping && uuid === since) {
|
|
127
150
|
// Found the cursor: everything collected so far precedes it — drop it.
|
|
128
151
|
skipping = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/cost/providers/claude-code.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../src/cost/providers/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger repair: remove usage that was never this repository's, and collapse
|
|
3
|
+
* coverage that is counted twice.
|
|
4
|
+
*
|
|
5
|
+
* Two passes, both driven by evidence already in the ledger rather than by a
|
|
6
|
+
* heuristic, and both going through `rewriteLedger` so a crash leaves either the
|
|
7
|
+
* old file or the new one.
|
|
8
|
+
*
|
|
9
|
+
* **Foreign purge** (turn-scoped-cost/AC-34, AC-43). An entry's `cursor` is the
|
|
10
|
+
* transcript uuid it was extracted from, so provenance is checkable. Measured on
|
|
11
|
+
* this repo: 711 entries / 262.5M tokens came from an unrelated project —
|
|
12
|
+
* `interactive-cli-menu` overstated by $131.67 and the whole of
|
|
13
|
+
* `release-blog-tag-deadlock`'s $58.42 was another repo's work. Only entries
|
|
14
|
+
* *positively shown* to be foreign are removed; `ambiguous` and `unknown` are
|
|
15
|
+
* kept, because under-recovering is the safe direction when the alternative is
|
|
16
|
+
* deleting real cost history.
|
|
17
|
+
*
|
|
18
|
+
* **Containment collapse** (turn-scoped-cost/AC-42). `applyPrecedence` reduces an
|
|
19
|
+
* entry's weight only by coverage of a *higher* fidelity rank, so two entries of
|
|
20
|
+
* the same session and fidelity where one window contains the other both keep
|
|
21
|
+
* weight 1. A bulk `metered` sweep that recorded a whole transcript therefore
|
|
22
|
+
* double-counts any narrower entry for the same session: verified minimally as
|
|
23
|
+
* counted 1100 against a truth of 1000. This is why the purge cannot simply
|
|
24
|
+
* delete foreign rows and stop — a nested entry for the surviving session waits in
|
|
25
|
+
* `unattributed.ndjson`, and recovering it would take the repaired $354.32 straight
|
|
26
|
+
* back up to $380.10.
|
|
27
|
+
*
|
|
28
|
+
* Requirements: turn-scoped-cost/AC-34, AC-42, AC-43, AC-45, AC-9
|
|
29
|
+
* Design: design.md Part 0 (D0.2, D0.6, D0.7, D0.8)
|
|
30
|
+
*/
|
|
31
|
+
import type { CostEntry } from './types.js';
|
|
32
|
+
import { type ProvenanceIndex } from './provenance.js';
|
|
33
|
+
import type { ProviderEnv } from './providers/provider.js';
|
|
34
|
+
export interface PurgeReport {
|
|
35
|
+
/** Entries removed as positively foreign, per ledger. */
|
|
36
|
+
foreignRemoved: Record<string, number>;
|
|
37
|
+
/** Entries removed as redundant same-session same-fidelity containment. */
|
|
38
|
+
containedRemoved: Record<string, number>;
|
|
39
|
+
/** Entries left alone because provenance was ambiguous or unknown. */
|
|
40
|
+
keptUnprovable: number;
|
|
41
|
+
/** Token totals before and after, so the delta is reported rather than asserted. */
|
|
42
|
+
tokensBefore: number;
|
|
43
|
+
tokensAfter: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Entries whose coverage is fully contained by another entry of the same session,
|
|
47
|
+
* fidelity and model — and strictly narrower, so the pair is never mutually
|
|
48
|
+
* eliminating.
|
|
49
|
+
*
|
|
50
|
+
* Model is part of the key on purpose. `capturePass` buckets per model, so two
|
|
51
|
+
* entries of one session can share a window while describing genuinely different
|
|
52
|
+
* tokens; collapsing those would delete real usage. Measured: 0 same-model
|
|
53
|
+
* containment pairs currently sit inside any ledger, so this pass is a guard
|
|
54
|
+
* against recovery reintroducing one rather than a cleanup of existing rows.
|
|
55
|
+
*/
|
|
56
|
+
export declare function containedEntries(entries: CostEntry[]): Set<number>;
|
|
57
|
+
/**
|
|
58
|
+
* Repair every ledger in the project.
|
|
59
|
+
*
|
|
60
|
+
* Idempotent by construction, and idempotent against a subsequent
|
|
61
|
+
* `aidlc cost sync` only because repo scoping landed first — without it, sync
|
|
62
|
+
* re-adds exactly what this removes (AC-45).
|
|
63
|
+
*/
|
|
64
|
+
export declare function purgeLedgers(projectRoot: string, env?: ProviderEnv, index?: ProvenanceIndex): PurgeReport;
|
|
65
|
+
//# sourceMappingURL=purge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purge.d.ts","sourceRoot":"","sources":["../../src/cost/purge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,WAAW,WAAW;IAC1B,yDAAyD;IACzD,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,sEAAsE;IACtE,cAAc,EAAE,MAAM,CAAC;IACvB,oFAAoF;IACpF,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAwBlE;AAkBD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,EACnB,GAAG,GAAE,WAA6B,EAClC,KAAK,CAAC,EAAE,eAAe,GACtB,WAAW,CA2Cb"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ledger repair: remove usage that was never this repository's, and collapse
|
|
3
|
+
* coverage that is counted twice.
|
|
4
|
+
*
|
|
5
|
+
* Two passes, both driven by evidence already in the ledger rather than by a
|
|
6
|
+
* heuristic, and both going through `rewriteLedger` so a crash leaves either the
|
|
7
|
+
* old file or the new one.
|
|
8
|
+
*
|
|
9
|
+
* **Foreign purge** (turn-scoped-cost/AC-34, AC-43). An entry's `cursor` is the
|
|
10
|
+
* transcript uuid it was extracted from, so provenance is checkable. Measured on
|
|
11
|
+
* this repo: 711 entries / 262.5M tokens came from an unrelated project —
|
|
12
|
+
* `interactive-cli-menu` overstated by $131.67 and the whole of
|
|
13
|
+
* `release-blog-tag-deadlock`'s $58.42 was another repo's work. Only entries
|
|
14
|
+
* *positively shown* to be foreign are removed; `ambiguous` and `unknown` are
|
|
15
|
+
* kept, because under-recovering is the safe direction when the alternative is
|
|
16
|
+
* deleting real cost history.
|
|
17
|
+
*
|
|
18
|
+
* **Containment collapse** (turn-scoped-cost/AC-42). `applyPrecedence` reduces an
|
|
19
|
+
* entry's weight only by coverage of a *higher* fidelity rank, so two entries of
|
|
20
|
+
* the same session and fidelity where one window contains the other both keep
|
|
21
|
+
* weight 1. A bulk `metered` sweep that recorded a whole transcript therefore
|
|
22
|
+
* double-counts any narrower entry for the same session: verified minimally as
|
|
23
|
+
* counted 1100 against a truth of 1000. This is why the purge cannot simply
|
|
24
|
+
* delete foreign rows and stop — a nested entry for the surviving session waits in
|
|
25
|
+
* `unattributed.ndjson`, and recovering it would take the repaired $354.32 straight
|
|
26
|
+
* back up to $380.10.
|
|
27
|
+
*
|
|
28
|
+
* Requirements: turn-scoped-cost/AC-34, AC-42, AC-43, AC-45, AC-9
|
|
29
|
+
* Design: design.md Part 0 (D0.2, D0.6, D0.7, D0.8)
|
|
30
|
+
*/
|
|
31
|
+
import { existsSync, readdirSync } from 'node:fs';
|
|
32
|
+
import { join } from 'node:path';
|
|
33
|
+
import { readEntries, rewriteLedger, ledgerPath, unattributedPath } from './ledger.js';
|
|
34
|
+
import { buildProvenanceIndex, classifyCursor, isPurgeable, repoCommonDir, } from './provenance.js';
|
|
35
|
+
function entryTokens(e) {
|
|
36
|
+
if (e.units === null || e.units.kind !== 'tokens')
|
|
37
|
+
return 0;
|
|
38
|
+
const u = e.units;
|
|
39
|
+
return u.input_tokens + u.output_tokens + u.cache_read_tokens + u.cache_write_tokens;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Entries whose coverage is fully contained by another entry of the same session,
|
|
43
|
+
* fidelity and model — and strictly narrower, so the pair is never mutually
|
|
44
|
+
* eliminating.
|
|
45
|
+
*
|
|
46
|
+
* Model is part of the key on purpose. `capturePass` buckets per model, so two
|
|
47
|
+
* entries of one session can share a window while describing genuinely different
|
|
48
|
+
* tokens; collapsing those would delete real usage. Measured: 0 same-model
|
|
49
|
+
* containment pairs currently sit inside any ledger, so this pass is a guard
|
|
50
|
+
* against recovery reintroducing one rather than a cleanup of existing rows.
|
|
51
|
+
*/
|
|
52
|
+
export function containedEntries(entries) {
|
|
53
|
+
const redundant = new Set();
|
|
54
|
+
for (let i = 0; i < entries.length; i++) {
|
|
55
|
+
const a = entries[i];
|
|
56
|
+
if (a.units === null || a.units.kind !== 'tokens')
|
|
57
|
+
continue;
|
|
58
|
+
const aFrom = Date.parse(a.coverage.from);
|
|
59
|
+
const aTo = Date.parse(a.coverage.to);
|
|
60
|
+
for (let j = 0; j < entries.length; j++) {
|
|
61
|
+
if (i === j || redundant.has(j))
|
|
62
|
+
continue;
|
|
63
|
+
const b = entries[j];
|
|
64
|
+
if (b.units === null || b.units.kind !== 'tokens')
|
|
65
|
+
continue;
|
|
66
|
+
if (a.session_id === null || a.session_id !== b.session_id)
|
|
67
|
+
continue;
|
|
68
|
+
if (a.fidelity !== b.fidelity)
|
|
69
|
+
continue;
|
|
70
|
+
if (a.units.model !== b.units.model)
|
|
71
|
+
continue;
|
|
72
|
+
const bFrom = Date.parse(b.coverage.from);
|
|
73
|
+
const bTo = Date.parse(b.coverage.to);
|
|
74
|
+
// `a` inside `b`, and strictly narrower so only one of the pair is dropped.
|
|
75
|
+
if (aFrom >= bFrom && aTo <= bTo && bTo - bFrom > aTo - aFrom) {
|
|
76
|
+
redundant.add(i);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return redundant;
|
|
82
|
+
}
|
|
83
|
+
/** Every ledger file in the project, instance ledgers plus unattributed. */
|
|
84
|
+
function ledgerFiles(projectRoot) {
|
|
85
|
+
const out = [];
|
|
86
|
+
const stateDir = join(projectRoot, '.aidlc', 'state');
|
|
87
|
+
if (existsSync(stateDir)) {
|
|
88
|
+
for (const d of readdirSync(stateDir, { withFileTypes: true })) {
|
|
89
|
+
if (!d.isDirectory())
|
|
90
|
+
continue;
|
|
91
|
+
const p = ledgerPath(projectRoot, d.name);
|
|
92
|
+
if (existsSync(p))
|
|
93
|
+
out.push(p);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const un = unattributedPath(projectRoot);
|
|
97
|
+
if (existsSync(un))
|
|
98
|
+
out.push(un);
|
|
99
|
+
return out;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Repair every ledger in the project.
|
|
103
|
+
*
|
|
104
|
+
* Idempotent by construction, and idempotent against a subsequent
|
|
105
|
+
* `aidlc cost sync` only because repo scoping landed first — without it, sync
|
|
106
|
+
* re-adds exactly what this removes (AC-45).
|
|
107
|
+
*/
|
|
108
|
+
export function purgeLedgers(projectRoot, env = { projectRoot }, index) {
|
|
109
|
+
const report = {
|
|
110
|
+
foreignRemoved: {},
|
|
111
|
+
containedRemoved: {},
|
|
112
|
+
keptUnprovable: 0,
|
|
113
|
+
tokensBefore: 0,
|
|
114
|
+
tokensAfter: 0,
|
|
115
|
+
};
|
|
116
|
+
const provenance = index ?? buildProvenanceIndex(env);
|
|
117
|
+
const here = repoCommonDir(projectRoot);
|
|
118
|
+
for (const file of ledgerFiles(projectRoot)) {
|
|
119
|
+
const entries = readEntries(file);
|
|
120
|
+
if (entries.length === 0)
|
|
121
|
+
continue;
|
|
122
|
+
const label = file.endsWith('unattributed.ndjson')
|
|
123
|
+
? 'unattributed'
|
|
124
|
+
: (file.split('/').slice(-2)[0] ?? file);
|
|
125
|
+
for (const e of entries)
|
|
126
|
+
report.tokensBefore += entryTokens(e);
|
|
127
|
+
const kept = [];
|
|
128
|
+
let foreign = 0;
|
|
129
|
+
for (const e of entries) {
|
|
130
|
+
const origin = classifyCursor(e.cursor, provenance, here);
|
|
131
|
+
if (isPurgeable(origin)) {
|
|
132
|
+
foreign++;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (origin !== 'local')
|
|
136
|
+
report.keptUnprovable++;
|
|
137
|
+
kept.push(e);
|
|
138
|
+
}
|
|
139
|
+
const redundant = containedEntries(kept);
|
|
140
|
+
const survivors = kept.filter((_, i) => !redundant.has(i));
|
|
141
|
+
for (const e of survivors)
|
|
142
|
+
report.tokensAfter += entryTokens(e);
|
|
143
|
+
if (foreign > 0)
|
|
144
|
+
report.foreignRemoved[label] = foreign;
|
|
145
|
+
if (redundant.size > 0)
|
|
146
|
+
report.containedRemoved[label] = redundant.size;
|
|
147
|
+
if (foreign > 0 || redundant.size > 0)
|
|
148
|
+
rewriteLedger(file, survivors);
|
|
149
|
+
}
|
|
150
|
+
return report;
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=purge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purge.js","sourceRoot":"","sources":["../../src/cost/purge.ts"],"names":[],"mappings":"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"}
|
package/dist/cost/recorder.d.ts
CHANGED
|
@@ -84,7 +84,27 @@ interface PhaseWindow {
|
|
|
84
84
|
/** Exclusive upper bound; Infinity for the current phase. */
|
|
85
85
|
to: number;
|
|
86
86
|
}
|
|
87
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Build phase windows for an instance from its transitions.log.
|
|
89
|
+
*
|
|
90
|
+
* This read was silently broken from the first commit: it took
|
|
91
|
+
* `t as unknown as { timestamp: string; ... }` and skipped any record without
|
|
92
|
+
* `rec.timestamp`, while `TransitionRecord` declares the field as `at`. Every
|
|
93
|
+
* transition was therefore skipped, the loop body never ran, and the function
|
|
94
|
+
* returned a single window covering all time — and since all four call sites seed
|
|
95
|
+
* `initialPhase` with `'implementation'`, **every priced record in the project was
|
|
96
|
+
* labelled `implementation`**. Measured: 18 of the 19 instances on the canonical
|
|
97
|
+
* field had 100% of their priced usage mislabelled, and the only correct ledgers
|
|
98
|
+
* were the three legacy instances the stale reader happened to match. The cast is
|
|
99
|
+
* what silenced the compile error that would have caught this, so it is gone
|
|
100
|
+
* (turn-scoped-cost/AC-1, AC-3).
|
|
101
|
+
*
|
|
102
|
+
* A record with `to: null` closes the preceding window without opening a new one:
|
|
103
|
+
* five instances end that way, so counting it would produce a phantom trailing
|
|
104
|
+
* phase (AC-41). `complete` is left as a legitimate label — it passes `PHASE_RE`
|
|
105
|
+
* and already appears in ledgers, so normalising it here would quietly move money
|
|
106
|
+
* between rows.
|
|
107
|
+
*/
|
|
88
108
|
export declare function phaseWindows(projectRoot: string, instance: string, initialPhase: string): PhaseWindow[];
|
|
89
109
|
/** All instances that have session events mentioning this session. */
|
|
90
110
|
export declare function instancesForSession(projectRoot: string, sessionId: string): string[];
|
|
@@ -107,5 +127,20 @@ export interface RecordOptions {
|
|
|
107
127
|
* firing lost to the lock is still captured — design §4.2).
|
|
108
128
|
*/
|
|
109
129
|
export declare function recordUsage(opts: RecordOptions): Promise<RecordResult | null>;
|
|
130
|
+
/**
|
|
131
|
+
* Total milliseconds covered by a set of intervals, counting overlap once.
|
|
132
|
+
*
|
|
133
|
+
* A union, not a sum, and the difference is not academic: records that share a
|
|
134
|
+
* parent produce overlapping spans, so summing them over-counts by 10.8% on this
|
|
135
|
+
* repo's corpus (27.76h summed against a 25.05h true union). Summing per-bucket
|
|
136
|
+
* unions still over-counts the global union by ~0.9%, because most residual overlap
|
|
137
|
+
* is *across* model buckets rather than within one — that residual is accepted and
|
|
138
|
+
* documented rather than hidden, since it is what keeps the stored value additive
|
|
139
|
+
* across phases and instances (turn-scoped-cost/AC-19, AC-44).
|
|
140
|
+
*/
|
|
141
|
+
export declare function unionMs(intervals: Array<{
|
|
142
|
+
from: number;
|
|
143
|
+
to: number;
|
|
144
|
+
}>): number;
|
|
110
145
|
export {};
|
|
111
146
|
//# sourceMappingURL=recorder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/cost/recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqBH,OAAO,EAAe,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../../src/cost/recorder.ts"],"names":[],"mappings":"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"}
|