@ascenda-one/history-import 0.1.24 → 0.1.26

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/README.md CHANGED
@@ -152,6 +152,47 @@ line that closes the turn. The rule is in
152
152
  [`src/interruptedRuns.ts`](./src/interruptedRuns.ts), and the desktop app's
153
153
  importer counts by the same one.
154
154
 
155
+ A cut counts in the session you pressed Escape in, and in no other. Resuming
156
+ a session copies the history it inherits, markers included, so before this
157
+ rule every resume in a lineage reported its ancestors' interruptions as
158
+ well — a fifth of the counted total on the store this was measured against.
159
+ The same ownership rule as the minutes (`minutesBasis: owned_lines`).
160
+
161
+ ### When two files both say a line is theirs
162
+
163
+ Most copies keep the session id the line was written with, which is how the
164
+ import tells a copy from the real thing. Some rewrite it to the file the copy
165
+ now sits in, keeping the line's own id and its original timestamp — so the
166
+ test that settles every other copy answers "written here" in both places, and
167
+ both sessions counted the line. Nothing on the line says which of the two
168
+ wrote it: the two records are identical apart from the fields the copy
169
+ rewrote.
170
+
171
+ Where the line sits is what settles it. A line two files claim is contested.
172
+ Inside a file, the run of contested lines at the top is the history it
173
+ inherited, and it ends at the first line that file claims and nobody else
174
+ does — from there on, what it holds it wrote. So a contested line belongs to
175
+ the file still holding it after its own history has started.
176
+
177
+ Not simply the first file the import reaches, which would be the easy rule and
178
+ the wrong one: on the store this was measured against it would hand two fifths
179
+ of these lines to the copy instead, which is the error this whole rule exists
180
+ to remove.
181
+
182
+ **What that leaves.** A lineage whose earliest file the 30-day cleanup has
183
+ already taken has no file that wrote those lines — every one still holding
184
+ them holds them in its inherited head, and nothing left on disk says which
185
+ session did the work. The line is still counted once, by the first file the
186
+ import reaches, the same answer any orphaned line gets. The total is right and
187
+ the session it lands on is a guess. That was 16.1% of contested lines here.
188
+
189
+ Sizes, on the same store: 3.7% of the lines claiming their own file were
190
+ claimed by two of them, and counting each once takes 3.9% off the summed
191
+ active minutes. **Your week doesn't move** — the union of your active time
192
+ holds to a minute, because a line counted twice was one minute counted twice.
193
+ Hands-on shifts a little more than that: a span changes sides when the lines
194
+ around it move, so the unioned hands-on figure moved by 19 minutes in 6,734.
195
+
155
196
  ### What counts as a prompt
156
197
 
157
198
  `promptCount` on a Claude Code session counts the prompts you typed. Claude
@@ -170,9 +211,6 @@ Code also writes `user` lines on your behalf, and none of these count:
170
211
  variant.
171
212
 
172
213
  Each session carries `syntheticPromptLines`, the number of lines it left out.
173
- The handoff stamps `promptBasis: "typed"`. A handoff without the stamp counted
174
- every `user` line that wasn't a tool result, so its prompt counts run higher for
175
- the same week. The schema number doesn't move.
176
214
 
177
215
  These lines aren't you, and they aren't the agent, so they don't start or end a
178
216
  hands-on span. Prompt events, after-hours prompts and quick re-prompts all
@@ -180,6 +218,72 @@ follow the same count. The desktop app's importer declines the same lines; the
180
218
  test is `isTypedPromptLine` in
181
219
  [`src/interruptedRuns.ts`](./src/interruptedRuns.ts).
182
220
 
221
+ Two more rules need the whole store, so the extractor reads every transcript
222
+ once before it folds any session ([`src/promptLedger.ts`](./src/promptLedger.ts)):
223
+
224
+ - **Each line belongs to one session.** Resuming or forking a session writes a
225
+ new transcript that copies the history it inherited, line ids and timestamps
226
+ included. Each copy has one owner: the transcript the line's `sessionId`
227
+ names, or, where the purge took that file, the first in the walk's sorted
228
+ order. The owner counts the prompt, and the owner's timeline carries the
229
+ instant — so `activeMinutes`, the hands-on split, the day slices and
230
+ `startedAt` describe the session you resumed rather than everything behind
231
+ it. Two files can both name themselves on one line, which "When two files
232
+ both say a line is theirs" above settles. A line with no id is counted
233
+ wherever it appears; on the reference store that's `queue-operation` lines
234
+ and nothing else.
235
+ - **A chip's prompt isn't typed.** A session launched from a `spawn_task` chip
236
+ opens on the chip's prompt. When a line's text, wrappers stripped, matches a
237
+ chip that some session in the store offered, it counts in
238
+ `dispatchedPromptLines`, not `promptCount`. The agent still runs on it, so an
239
+ interrupt during that first turn is still a cut-short run. Only hashes of
240
+ chip prompts are kept, and only for the run. If the store's cleanup has
241
+ already removed the session that offered the chip, there's nothing to match
242
+ and the opener counts as typed.
243
+
244
+ The handoff stamps `promptBasis: "typed_once"`. `"typed"` means the rules above
245
+ the list, with every resumed copy counted again and chip prompts counted as
246
+ typed. A handoff without the stamp counted every `user` line that wasn't a tool
247
+ result. Prompt counts for the same week run highest under that rule and lowest
248
+ under `typed_once`. The schema number doesn't move.
249
+
250
+ Beside it, `minutesBasis: "owned_lines"` says the minutes were cut the same
251
+ way. `"every_line"` — and an absent stamp — means a transcript's whole
252
+ contents counted there, inherited history included. Gate on this before
253
+ comparing minutes across two handoffs: a store's figures drop when it changes,
254
+ and nothing else in the file says so.
255
+
256
+ ### How much history a resume carries
257
+
258
+ Enough to matter, which is why the rule above covers the minutes and not only
259
+ the counts. On one real store of 984 transcripts, 151 carried inherited lines:
260
+ 275,801 of them, 29% of every dated line in the store. They held the whole of
261
+ the gap between what the sessions claimed and what the clock allowed. Both
262
+ columns are the same 983 sessions, read from one snapshot:
263
+
264
+ | | Every line | Owned lines |
265
+ |---|---|---|
266
+ | Summed active minutes | 70,212 | 53,600 |
267
+ | Summed hands-on minutes | 12,238 | 8,006 |
268
+ | Union of every active interval | 25,078 | 25,077 |
269
+ | Exact-duplicate spans | 262,500 of 873,599 | 21,982 of 635,126 |
270
+ | Sessions apparently spanning over a day | 158 | 154 |
271
+
272
+ The union is the control. It holds to the minute, so no work anyone did was
273
+ dropped: what went was the copy of it. Duplicate spans fell from 30% of the
274
+ store to 3.5%, which matters to any count of how many agents were running at
275
+ once, since a duplicate reads as a second agent. 127 sessions now start when
276
+ they were resumed, 13 of them more than an hour later than they used to.
277
+
278
+ That 3.5% was not the floor, and it was not coincidence: four fifths of it was
279
+ the copy path settled above. On a later and slightly larger snapshot of the
280
+ same store, the duplicate spans go from 21,982 to 4,087 once contested lines
281
+ are settled.
282
+
283
+ An earlier reading of this exposure put it at 0.72% of sessions. It counted
284
+ repeated `sessionRef`s, and a resumed transcript carries a fresh one, so it saw
285
+ three sessions where 151 transcripts were affected.
286
+
183
287
  ### Autonomy bands
184
288
 
185
289
  `permissionMode` is on the transcript's human-prompt lines and nowhere else —