@feigi/fleet-ctl 3.18.9 → 3.18.11
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/package.json +1 -1
- package/scripts/board.test.mjs +53 -14
- package/scripts/citation-sweep-prose.test.mjs +1 -1
- package/scripts/ledger.mjs +143 -147
- package/scripts/member-record.mjs +51 -53
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The member-telemetry adapter
|
|
1
|
+
// The member-telemetry adapter. ONE per-member
|
|
2
2
|
// record shape, TWO readers a tree walk chooses by content, never by
|
|
3
3
|
// caller-supplied config: board.mjs (the live spend panel) and
|
|
4
4
|
// member-outcomes.mjs (the scraper) build on the primitives here rather than
|
|
@@ -13,9 +13,8 @@
|
|
|
13
13
|
// — no pricing table exists in this repo, and inventing one is not this
|
|
14
14
|
// module's business.
|
|
15
15
|
//
|
|
16
|
-
// `thinking` is the harness-written level, blank when a hole is visible
|
|
17
|
-
//
|
|
18
|
-
// DISPATCHED AS — the agent DEFINITION the dispatch named, never the
|
|
16
|
+
// `thinking` is the harness-written level, blank when a hole is visible.
|
|
17
|
+
// `subagent_type` is what the member was DISPATCHED AS — the agent DEFINITION the dispatch named, never the
|
|
19
18
|
// member's own name: it is the only field that separates a deliberate
|
|
20
19
|
// alternate-tier pair from two members whose models already happened to
|
|
21
20
|
// differ, and both readers keep it because it is derived rather than
|
|
@@ -46,7 +45,7 @@ import { classifyRole, canonicalMemberName, CANONICAL_MEMBER_NAME_PREFIXES } fro
|
|
|
46
45
|
// (`.claude` -> `-.claude`); non-home paths are realpath-resolved (so `/tmp/x`,
|
|
47
46
|
// a symlink to `/private/tmp/x` on macOS, encodes under the resolved name)
|
|
48
47
|
// and double-dash-wrapped. Both forms are measured against real
|
|
49
|
-
// `~/.omp/agent/sessions/*` directory names
|
|
48
|
+
// `~/.omp/agent/sessions/*` directory names - a
|
|
50
49
|
// `~/dev/fleet-plugin`, `--private-tmp-fx685-scratch--` all exist on disk
|
|
51
50
|
// today.
|
|
52
51
|
export function encodeProjectDir(cwd, { home = process.env.HOME, realpath = realpathSync } = {}) {
|
|
@@ -81,7 +80,7 @@ export function normalizeModel(raw) {
|
|
|
81
80
|
|
|
82
81
|
// A member's name is the only place its unit of work is recorded — there is
|
|
83
82
|
// no dispatch sidecar at all (see ompMemberRecord). The one exception is a
|
|
84
|
-
// PR the member OPENED
|
|
83
|
+
// PR the member OPENED: an `impl-<ticket>` name can never carry it,
|
|
85
84
|
// so ompMemberRecord reads it off the member's own `gh pr create` result
|
|
86
85
|
// (createdPrNumbers) — this function still answers `pr: ""` for that name.
|
|
87
86
|
//
|
|
@@ -91,7 +90,7 @@ export function normalizeModel(raw) {
|
|
|
91
90
|
// members their join key to tier-outcomes.tsv. The fix-pr-<n> and
|
|
92
91
|
// review-pr-<n> families share the first pattern only because the infix is
|
|
93
92
|
// the same — they are NOT finisher spellings. `finisher-pr-<n>` is the
|
|
94
|
-
// canonical name run-team now fixes
|
|
93
|
+
// canonical name run-team now fixes; the other three stay matched
|
|
95
94
|
// because the runs that used them are already in the record.
|
|
96
95
|
//
|
|
97
96
|
// merge-bot-<n> is deliberately excluded: its number is a per-run dispatch
|
|
@@ -101,7 +100,7 @@ export function normalizeModel(raw) {
|
|
|
101
100
|
// re-dispatched member works the same unit. A trailing `-v<n>` (`-v2`,
|
|
102
101
|
// `-v10`, ...) is a DIFFERENT spelling of the same re-dispatch, used when a
|
|
103
102
|
// controller re-dispatches a finisher/reviewer against a PR whose head moved
|
|
104
|
-
// after label (
|
|
103
|
+
// after label (measured: ~67% of one finisher's tokens fell through
|
|
105
104
|
// to a blank pr column under the old letter-only regex); it is stripped for
|
|
106
105
|
// the same reason, not because it looks like a second-ticket suffix — no
|
|
107
106
|
// naming convention in this repo otherwise uses a literal `-v` + digits
|
|
@@ -120,28 +119,28 @@ export function normalizeModel(raw) {
|
|
|
120
119
|
// ticket the way `impl-<ticket>-<n>`'s can — there is only ever one PR per
|
|
121
120
|
// such name. A trailing `-\d+` there (`finisher-pr-1440-2`, `fix-pr-1281-2`)
|
|
122
121
|
// is the same re-dispatch retry the letter and `-v<n>` suffixes above
|
|
123
|
-
// already cover, and is now stripped for PR-shaped names only
|
|
124
|
-
// measured: 476,202 cache-create tokens across 7 real rows fell through to a
|
|
122
|
+
// already cover, and is now stripped for PR-shaped names only
|
|
123
|
+
// (measured: 476,202 cache-create tokens across 7 real rows fell through to a
|
|
125
124
|
// blank pr column this way — more than the 37,580 the `-v<n>` fix above
|
|
126
125
|
// addressed). The ticket-shaped `impl-<ticket>-<n>` family above is
|
|
127
126
|
// untouched: its second-ticket ambiguity is real, and a PR-shaped name's is
|
|
128
127
|
// not.
|
|
129
128
|
//
|
|
130
|
-
// `resolve` joins the `-pr-` alternation
|
|
129
|
+
// `resolve` joins the `-pr-` alternation: `resolve-pr-<n>` is a
|
|
131
130
|
// controller-dispatched conflict/rebase resolver against an already-open PR
|
|
132
|
-
// (measured session descriptions: "Resolve conflict on PR
|
|
133
|
-
// and resolve conflicts for PR
|
|
131
|
+
// (measured session descriptions: "Resolve conflict on PR <n>", "Rebase
|
|
132
|
+
// and resolve conflicts for PR #<n>") — the same shape as `fix-pr-<n>`'s
|
|
134
133
|
// applier and `review-pr-<n>`'s reviewer, just not a name run-team's own
|
|
135
134
|
// naming convention fixes, so it stays out of the canonical list in
|
|
136
135
|
// SKILL.md/member-lifecycle.md the same way `finish-<n>`/`finisher-<n>` do.
|
|
137
136
|
// Unrecognised, a `resolve-pr-<n>` member fell through to `{ticket:"",
|
|
138
137
|
// pr:""}`, losing its join key into tier-outcomes.tsv exactly the way an
|
|
139
|
-
// unmatched finisher spelling once did
|
|
138
|
+
// unmatched finisher spelling once did.
|
|
140
139
|
//
|
|
141
140
|
// Every pattern below is written against the lower-kebab spelling, so the
|
|
142
141
|
// name is first rewritten by `canonicalMemberName` (compute-spend.mjs), the
|
|
143
142
|
// same rewrite classifyRole applies: `Impl327` and `FixPr774` book the
|
|
144
|
-
// ticket and PR their kebab forms do instead of blanks
|
|
143
|
+
// ticket and PR their kebab forms do instead of blanks.
|
|
145
144
|
export function parseMemberName(name) {
|
|
146
145
|
const s = canonicalMemberName(name).replace(/-(?:[a-z]|v\d+)$/, "");
|
|
147
146
|
let m = /^(?:fix|review|finish(?:er)?|resolve)-pr-(\d+)(?:-\d+)?$/.exec(s);
|
|
@@ -161,7 +160,7 @@ export function parseMemberName(name) {
|
|
|
161
160
|
// lives in the DIRECTORY name, never per line; omp's envelope is
|
|
162
161
|
// `{type,id,parentId,timestamp,message}`. That is the structural signature
|
|
163
162
|
// this reader refuses on if it is ever absent — a validation CHECK inside
|
|
164
|
-
// this reader
|
|
163
|
+
// this reader: every root this module is ever handed is
|
|
165
164
|
// an omp `~/.omp/agent/sessions/**` tree, so a line failing this shape
|
|
166
165
|
// signals a corrupted or foreign file, not a harness to dispatch to.
|
|
167
166
|
//
|
|
@@ -185,7 +184,7 @@ function assertOmpShaped(d, filePath) {
|
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
186
|
|
|
188
|
-
// `openedPrs`
|
|
187
|
+
// `openedPrs` is every PR number the member's OWN `gh pr create`
|
|
189
188
|
// printed — the source of `pr` for a member whose name carries none, which is
|
|
190
189
|
// every implementer (`impl-<ticket>` names a ticket, never a PR). Chosen over
|
|
191
190
|
// the ledger's `impl-<N>=PR#M` settle token because that token is written by a
|
|
@@ -195,8 +194,8 @@ function assertOmpShaped(d, filePath) {
|
|
|
195
194
|
// transcripts printed a created PR from a `bash` toolCall whose result held
|
|
196
195
|
// gh's stdout — the URL on a line of its own — then omp's "Wall time"
|
|
197
196
|
// trailer. A create is also sometimes run via `eval` instead of `bash` —
|
|
198
|
-
// measured on impl-1113 (a Python subprocess, `gh pr create` printing PR
|
|
199
|
-
//
|
|
197
|
+
// measured on impl-1113 (a Python subprocess, `gh pr create` printing a PR
|
|
198
|
+
// URL) — and stays blank there too: `eval` is not read, because a cell
|
|
200
199
|
// that only READS transcripts (or `gh pr view`s) prints the very same URLs.
|
|
201
200
|
//
|
|
202
201
|
// Three filters keep a URL that is NOT a PR this member opened out:
|
|
@@ -205,7 +204,7 @@ function assertOmpShaped(d, filePath) {
|
|
|
205
204
|
// keyword, optionally through `rtk`/`env`/`command`/`timeout <n>`, a
|
|
206
205
|
// `NAME=value` prefix, or a path-qualified `.../gh` — a `gh pr view`/
|
|
207
206
|
// `gh pr list` result prints bare PR URLs too, and `gh pr create` quoted
|
|
208
|
-
// as text is no invocation (measured false-miss shapes
|
|
207
|
+
// as text is no invocation (measured false-miss shapes);
|
|
209
208
|
// - the URL must be a LINE of its own, the shape gh prints, never a URL
|
|
210
209
|
// inside prose;
|
|
211
210
|
// - a URL right after gh's "... already exists:" refusal is skipped: that PR
|
|
@@ -225,7 +224,7 @@ function assertOmpShaped(d, filePath) {
|
|
|
225
224
|
// `view` copy of an "already exists:" URL is not caught by the one-line-back
|
|
226
225
|
// skip above. Measured 0 real occurrences of any of these across the whole
|
|
227
226
|
// local `~/.omp/agent/sessions/**/*.jsonl` corpus and every filled `pr` in
|
|
228
|
-
// the committed TSV
|
|
227
|
+
// the committed TSV; accepted as known gaps rather than
|
|
229
228
|
// hand-rolling shell-quote/heredoc awareness into a single regex.
|
|
230
229
|
const GH_PR_CREATE_RE =
|
|
231
230
|
/(?:^|[;&|(\n]|\b(?:if|then|do|!)\s)\s*(?:(?:env|command|rtk|timeout\s+\S+)\s+|[A-Za-z_]\w*=\S*\s+)*(?:\S*\/)?gh\s+pr\s+create\b/;
|
|
@@ -253,22 +252,22 @@ function createdPrNumbers(text) {
|
|
|
253
252
|
// "cacheRead":0,"cacheWrite":0.0783,"total":0.0803}}}}
|
|
254
253
|
//
|
|
255
254
|
// `thinking` reads the harness-WRITTEN level, never the frontmatter — that
|
|
256
|
-
// is what makes
|
|
257
|
-
//
|
|
258
|
-
// record's `-`) when no `thinking_level_change` line exists, rather than
|
|
255
|
+
// is what makes a declared-vs-resolved comparison possible. It stays `null`
|
|
256
|
+
// here (ompMemberRecord turns that into the record's `-`) when no `thinking_level_change` line exists, rather than
|
|
259
257
|
// guessing the default: a member that is not a fleet definition genuinely
|
|
260
258
|
// has no recorded level, and the hole must stay visible.
|
|
261
259
|
//
|
|
262
260
|
// `session_init.task` is the closest thing to a dispatch sidecar this
|
|
263
261
|
// module has — there is no separate description file at all.
|
|
264
262
|
// ompMemberRecord below uses it, together with the transcript's own nesting
|
|
265
|
-
// depth AND the AgentId itself, as REAL classifyRole() signals.
|
|
266
|
-
//
|
|
267
|
-
// `
|
|
268
|
-
// `
|
|
269
|
-
// pair that names nothing
|
|
263
|
+
// depth AND the AgentId itself, as REAL classifyRole() signals. The AgentId
|
|
264
|
+
// is passed as `memberName` whatever its shape (the RULED paragraph below): a
|
|
265
|
+
// canonically-stemmed one (`impl-<n>`, `fix-pr-<n>`, `finisher-<n>`,
|
|
266
|
+
// `review-pr-<n>`, `merge-bot-<n>`) matches a name-driven branch, while a
|
|
267
|
+
// generated word pair that names nothing satisfies no hyphen-anchored or
|
|
268
|
+
// multi-word branch, so it falls through to the name-plus-description blend.
|
|
270
269
|
//
|
|
271
|
-
// `resolvedModelIdentity`
|
|
270
|
+
// `resolvedModelIdentity` is `session_init`'s OWN field, written at
|
|
272
271
|
// DISPATCH — before the member's first assistant turn exists, which is what
|
|
273
272
|
// makes it different from `model` above: a member still working folds to
|
|
274
273
|
// `model: null` (no assistant turn yet) but already carries
|
|
@@ -280,14 +279,14 @@ function createdPrNumbers(text) {
|
|
|
280
279
|
// per-turn value (which can in principle change mid-run) is the fact they
|
|
281
280
|
// want, not the dispatch-time identity.
|
|
282
281
|
//
|
|
283
|
-
// `agent`
|
|
282
|
+
// `agent` is `session_init`'s dispatch-time record of WHICH AGENT
|
|
284
283
|
// DEFINITION this member is. Measured 2026-09-12 across real
|
|
285
284
|
// `~/.omp/agent/sessions/**`: present on every one of the 1,191 transcripts
|
|
286
285
|
// carrying a `session_init` line (`fleet-implementer` 51,
|
|
287
286
|
// `fleet-implementer-alt` 17, the default `task` 220, plus the review
|
|
288
287
|
// fan-out's own definitions), absent only where the line itself is.
|
|
289
288
|
//
|
|
290
|
-
// `entries`
|
|
289
|
+
// `entries` is the per-agent tool stream compute-spend.mjs's
|
|
291
290
|
// attributeTools reads: `assistant`/`result` entries. Measured 2026-09-26
|
|
292
291
|
// across 5,085 real `~/.omp/agent/sessions/**/*.jsonl` files, the call is a
|
|
293
292
|
// block on the assistant message and the result a line of its own:
|
|
@@ -323,7 +322,7 @@ function createdPrNumbers(text) {
|
|
|
323
322
|
// reached the API its usage is all zero, and attributeTools books the batch
|
|
324
323
|
// before it at 0.
|
|
325
324
|
//
|
|
326
|
-
// `openedPrs`
|
|
325
|
+
// `openedPrs` folds the `bash` calls that invoke `gh pr create`
|
|
327
326
|
// against their own results, via createdPrNumbers above — distinct PR
|
|
328
327
|
// numbers in first-seen order.
|
|
329
328
|
export function foldOmpTranscript(jsonlText, filePath) {
|
|
@@ -342,7 +341,7 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
342
341
|
let d;
|
|
343
342
|
// A torn tail (transcript read mid-write) is dropped, and costs at most
|
|
344
343
|
// that one turn either way. A MIDDLE line failing the same parse is not
|
|
345
|
-
// a live write in progress — it is lost data, and
|
|
344
|
+
// a live write in progress — it is lost data, and it can desync
|
|
346
345
|
// a toolCall from its toolResult, not just a turn's totals, so it is
|
|
347
346
|
// counted, never for the last line.
|
|
348
347
|
try { d = JSON.parse(raw); }
|
|
@@ -404,7 +403,7 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
404
403
|
// One member record from one omp transcript's fold. `member` is the AgentId
|
|
405
404
|
// (the filename stem, e.g. `InstallVerifySearch`) — there is no separate
|
|
406
405
|
// display name, so `ticket`/`pr` extraction runs against it directly — except
|
|
407
|
-
// a `pr` the name cannot carry, read off the fold's `openedPrs
|
|
406
|
+
// a `pr` the name cannot carry, read off the fold's `openedPrs`.
|
|
408
407
|
//
|
|
409
408
|
// `role` is NEVER guessed off the bare AgentId ALONE — a generated CamelCase
|
|
410
409
|
// word pair names nothing classifyRole can read. FOUR real signals exist:
|
|
@@ -412,16 +411,16 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
412
411
|
// `session_init.task` (the dispatch prompt, when present), `spawnDepth` (the
|
|
413
412
|
// transcript's own nesting depth, supplied by readOmpSession from the walk —
|
|
414
413
|
// a fact about where the file lives, not a guess about what it is), and —
|
|
415
|
-
// per
|
|
414
|
+
// per the RULED paragraph below — the AgentId itself, handed to classifyRole as
|
|
416
415
|
// `memberName`. Depth matters on its own: classifyRole checks depth BEFORE
|
|
417
416
|
// any text match, specifically so a nested member whose task happens to
|
|
418
|
-
// read like a reviewer's ("Review PR
|
|
417
|
+
// read like a reviewer's ("Review PR <n> correctness") still books as the
|
|
419
418
|
// fan-out specialist it structurally is, not a reviewer. None present
|
|
420
419
|
// yields `"-"` — the same visible-hole spelling as `thinking`, never a
|
|
421
420
|
// default like "other", which only makes sense where a real dispatch record
|
|
422
421
|
// backs it.
|
|
423
422
|
//
|
|
424
|
-
// `agent` reaches classifyRole as its `agentDefinition
|
|
423
|
+
// `agent` reaches classifyRole as its `agentDefinition`. It
|
|
425
424
|
// is the same value the `subagent_type` column below already records, and
|
|
426
425
|
// withholding it here made classifyRole's FIRST branch — the one whose
|
|
427
426
|
// comment says memory-system work must "never land in review spend" —
|
|
@@ -431,7 +430,7 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
431
430
|
// definition (`fleet-review-verifier`) split across four buckets on nothing
|
|
432
431
|
// but how each prompt happened to read.
|
|
433
432
|
//
|
|
434
|
-
//
|
|
433
|
+
// The gap this closes: `memberName` used to be left unset here on the theory that
|
|
435
434
|
// the AgentId genuinely is not a name — a generated CamelCase word pair
|
|
436
435
|
// (`InstallVerifySearch`) names nothing the classifier can read. True for
|
|
437
436
|
// the ordinary case, but false for members dispatched under run-team's own
|
|
@@ -441,7 +440,7 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
441
440
|
// dispatched under the generic default `task` definition (`folded.agent` is
|
|
442
441
|
// `undefined`), so the definition-based fix above cannot reach them, and
|
|
443
442
|
// they fall through to prose classification of `folded.task` alone.
|
|
444
|
-
// Measured against docs/metrics/member-outcomes.tsv
|
|
443
|
+
// Measured against docs/metrics/member-outcomes.tsv: 478 omp rows
|
|
445
444
|
// carry such an AgentId, 52 of them booked `other` for want of this signal —
|
|
446
445
|
// 31 `fix-pr-*`, 9 `impl-*` and 12 `merge-bot-*` members whose dispatch
|
|
447
446
|
// prompt never happens to name the role.
|
|
@@ -452,9 +451,9 @@ export function foldOmpTranscript(jsonlText, filePath) {
|
|
|
452
451
|
// multi-word phrase ("implement ticket", "review pr"), so a stray generated
|
|
453
452
|
// word pair cannot coincidentally satisfy one; the one bare-word pattern,
|
|
454
453
|
// `finisher`, carries that risk today and has not fired on the 4,574
|
|
455
|
-
// sidecars measured
|
|
454
|
+
// sidecars measured. `OMP_CANONICAL_STEM_RE` below exists only to
|
|
456
455
|
// widen `hasRoleSignal` itself: a canonically-named member whose transcript
|
|
457
|
-
// predates
|
|
456
|
+
// predates `session_init` (no such line at all, so neither `task` nor
|
|
458
457
|
// `agent` exist) still holds a readable identity and must not fall back to
|
|
459
458
|
// the "-" hole. Measured 2026-09-16: zero such rows on disk today, but the
|
|
460
459
|
// gate exists so the design does not assume that stays true forever. Built
|
|
@@ -471,7 +470,7 @@ export function ompMemberRecord(folded, agentStem, spawnDepth = 0) {
|
|
|
471
470
|
const member = agentStem;
|
|
472
471
|
const { ticket, pr: namedPr } = parseMemberName(member);
|
|
473
472
|
// A name-carried PR (`fix-pr-<n>`, `finisher-<n>`, ...) is the member's unit
|
|
474
|
-
// of work by construction and wins. Otherwise
|
|
473
|
+
// of work by construction and wins. Otherwise the one PR its own
|
|
475
474
|
// `gh pr create` printed; none, or more than one (measured: impl-1578 opened
|
|
476
475
|
// its real PR plus a throwaway probe PR), stays blank — never a guess.
|
|
477
476
|
// `folded.openedPrs` is `foldOmpTranscript`'s own unconditional return
|
|
@@ -487,11 +486,11 @@ export function ompMemberRecord(folded, agentStem, spawnDepth = 0) {
|
|
|
487
486
|
role,
|
|
488
487
|
member,
|
|
489
488
|
model: folded.model,
|
|
490
|
-
// Additive only
|
|
489
|
+
// Additive only — `model` above stays the per-turn value
|
|
491
490
|
// board.mjs/member-outcomes.mjs already key cost/spend attribution on;
|
|
492
491
|
// this is the dispatch-time identity `session_init` wrote before any
|
|
493
|
-
// turn existed, `null` when the transcript
|
|
494
|
-
//
|
|
492
|
+
// turn existed, `null` when the transcript carries no `session_init`
|
|
493
|
+
// line at all (never guessed).
|
|
495
494
|
resolvedModelIdentity: folded.resolvedModelIdentity ?? null,
|
|
496
495
|
thinking: folded.thinking ?? "-",
|
|
497
496
|
// The dispatch record's own agent definition, `""` when the transcript
|
|
@@ -507,7 +506,7 @@ export function ompMemberRecord(folded, agentStem, spawnDepth = 0) {
|
|
|
507
506
|
|
|
508
507
|
// ompMemberRecord straight from the transcript text. board.mjs's live spend
|
|
509
508
|
// panel calls the two halves itself instead, because it needs the fold's tool
|
|
510
|
-
// stream
|
|
509
|
+
// stream beside the record, and folding the file twice for it would
|
|
511
510
|
// parse every transcript twice on every tick.
|
|
512
511
|
export function readOmpMember(jsonlText, filePath, agentStem, spawnDepth = 0) {
|
|
513
512
|
return ompMemberRecord(foldOmpTranscript(jsonlText, filePath), agentStem, spawnDepth);
|
|
@@ -515,7 +514,7 @@ export function readOmpMember(jsonlText, filePath, agentStem, spawnDepth = 0) {
|
|
|
515
514
|
|
|
516
515
|
// One omp session directory's member transcripts, as the walk both readers of
|
|
517
516
|
// that directory need it: readOmpSession below, and board.mjs's live spend
|
|
518
|
-
// panel
|
|
517
|
+
// panel, which folds each file itself so it can keep its own
|
|
519
518
|
// per-transcript skip tally. RECURSIVE: a member can itself dispatch further
|
|
520
519
|
// members (measured on disk — a research session's `Facts1303/` held seven
|
|
521
520
|
// more `.jsonl` files one level down), and `agent` is the path-relative stem
|
|
@@ -539,9 +538,8 @@ export function ompSessionTranscripts(sessionDir) {
|
|
|
539
538
|
//
|
|
540
539
|
// Deliberately NOT wrapped in a blanket try/catch around readOmpMember: the
|
|
541
540
|
// wrong-shape refusal (assertOmpShaped, inside foldOmpTranscript) must
|
|
542
|
-
// propagate all the way out of readMembers, uncaught
|
|
543
|
-
//
|
|
544
|
-
// ordinary per-member tolerance.
|
|
541
|
+
// propagate all the way out of readMembers, uncaught. Only the directory
|
|
542
|
+
// listing and the raw file read are given the ordinary per-member tolerance.
|
|
545
543
|
export function readOmpSession(sessionDir) {
|
|
546
544
|
let transcripts;
|
|
547
545
|
try { transcripts = ompSessionTranscripts(sessionDir); }
|
|
@@ -567,7 +565,7 @@ export function readOmpSession(sessionDir) {
|
|
|
567
565
|
// per-session directories, so `findOmpSessionDirs` recursing from the
|
|
568
566
|
// encoded-cwd dir hit the `.jsonl` test there first, returned the whole
|
|
569
567
|
// project as "one session", stamped every row `session=-dev-fleet-plugin`
|
|
570
|
-
// instead of the `<ISO>_<uuid>` name
|
|
568
|
+
// instead of the `<ISO>_<uuid>` name the row key is built on, and booked
|
|
571
569
|
// the controller's own top-level transcripts as members. Name-only matching
|
|
572
570
|
// costs nothing a real fixture needs: every fixture in this repo already
|
|
573
571
|
// names its session dir in the real shape.
|
|
@@ -595,7 +593,7 @@ function findOmpSessionDirs(root) {
|
|
|
595
593
|
|
|
596
594
|
// The adapter's public entry point. A root that resolves to no session
|
|
597
595
|
// directory anywhere is refused rather than silently skipped: silently
|
|
598
|
-
// returning no rows for a typo'd path is the blackout
|
|
596
|
+
// returning no rows for a typo'd path is the blackout this refusal exists
|
|
599
597
|
// to prevent.
|
|
600
598
|
export function readMembers(roots) {
|
|
601
599
|
const rows = [];
|