@manyoars/oars 0.3.0 → 0.4.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/README.md +44 -29
- package/dist/cli.d.ts +4 -1
- package/dist/cli.js +102 -32
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +1 -1
- package/dist/gate/hook-main.js +13 -1
- package/dist/gate/hook-process.d.ts +11 -1
- package/dist/gate/hook-process.js +50 -2
- package/dist/gate/hook-record.d.ts +3 -0
- package/dist/gate/hook-record.js +8 -0
- package/dist/gate/hook.d.ts +2 -0
- package/dist/gate/hook.js +3 -0
- package/dist/gate/replay.js +2 -5
- package/dist/gate/report.js +1 -1
- package/dist/gate/transcripts.js +1 -1
- package/dist/hook-bin.js +27 -2
- package/dist/issuer.d.ts +7 -9
- package/dist/issuer.js +10 -32
- package/dist/main.js +3 -0
- package/dist/sessions/actions.js +78 -0
- package/dist/sessions/allow.d.ts +10 -1
- package/dist/sessions/allow.js +29 -9
- package/dist/sessions/baseline.d.ts +1 -1
- package/dist/sessions/baseline.js +6 -4
- package/dist/sessions/call-shape.d.ts +19 -0
- package/dist/sessions/call-shape.js +85 -0
- package/dist/sessions/cell-increments.d.ts +5 -1
- package/dist/sessions/cell-increments.js +84 -50
- package/dist/sessions/cells.d.ts +33 -3
- package/dist/sessions/cells.js +89 -9
- package/dist/sessions/codex.js +93 -27
- package/dist/sessions/command.d.ts +11 -1
- package/dist/sessions/command.js +64 -18
- package/dist/sessions/coverage.d.ts +19 -0
- package/dist/sessions/coverage.js +56 -0
- package/dist/sessions/cursor.js +2 -2
- package/dist/sessions/derive.js +72 -6
- package/dist/sessions/exclusion.d.ts +6 -0
- package/dist/sessions/exclusion.js +8 -0
- package/dist/sessions/extract.d.ts +4 -2
- package/dist/sessions/extract.js +58 -26
- package/dist/sessions/hook-calls.js +1 -1
- package/dist/sessions/hook-index.d.ts +14 -1
- package/dist/sessions/hook-index.js +10 -3
- package/dist/sessions/hooks.d.ts +5 -1
- package/dist/sessions/hooks.js +133 -22
- package/dist/sessions/identity.d.ts +8 -3
- package/dist/sessions/identity.js +45 -15
- package/dist/sessions/install.d.ts +18 -2
- package/dist/sessions/install.js +53 -8
- package/dist/sessions/mcp.d.ts +3 -2
- package/dist/sessions/mcp.js +8 -4
- package/dist/sessions/motif.d.ts +2 -1
- package/dist/sessions/motif.js +2 -2
- package/dist/sessions/opencode.d.ts +33 -0
- package/dist/sessions/opencode.js +319 -0
- package/dist/sessions/otel.d.ts +60 -0
- package/dist/sessions/otel.js +494 -0
- package/dist/sessions/package-books.d.ts +48 -0
- package/dist/sessions/package-books.js +120 -0
- package/dist/sessions/package-resolve.d.ts +2 -0
- package/dist/sessions/package-resolve.js +3 -1
- package/dist/sessions/pi.d.ts +36 -0
- package/dist/sessions/pi.js +353 -0
- package/dist/sessions/pool-books.d.ts +21 -0
- package/dist/sessions/pool-books.js +75 -0
- package/dist/sessions/pool-choices.d.ts +5 -0
- package/dist/sessions/pool-choices.js +11 -0
- package/dist/sessions/pool-command.d.ts +76 -5
- package/dist/sessions/pool-command.js +263 -136
- package/dist/sessions/pool-nightly-deps.d.ts +3 -0
- package/dist/sessions/pool-nightly-deps.js +11 -0
- package/dist/sessions/pool-nightly.d.ts +10 -0
- package/dist/sessions/pool-nightly.js +85 -0
- package/dist/sessions/pool-outbox.d.ts +15 -2
- package/dist/sessions/pool-outbox.js +79 -26
- package/dist/sessions/pool-print.d.ts +1 -1
- package/dist/sessions/pool-raw.d.ts +27 -0
- package/dist/sessions/pool-raw.js +68 -0
- package/dist/sessions/pool-replica.d.ts +35 -0
- package/dist/sessions/pool-replica.js +91 -0
- package/dist/sessions/pool-send-lock.d.ts +20 -0
- package/dist/sessions/pool-send-lock.js +87 -0
- package/dist/sessions/pool-sent.d.ts +4 -0
- package/dist/sessions/pool-sent.js +26 -0
- package/dist/sessions/pool-totals.d.ts +10 -0
- package/dist/sessions/pool-totals.js +21 -0
- package/dist/sessions/pool-wire.d.ts +240 -30
- package/dist/sessions/pool-wire.js +695 -215
- package/dist/sessions/public-vocabulary.d.ts +2 -3
- package/dist/sessions/public-vocabulary.js +2 -9
- package/dist/sessions/query.d.ts +16 -4
- package/dist/sessions/query.js +32 -10
- package/dist/sessions/read-cost.js +14 -3
- package/dist/sessions/read-recovery-edge.d.ts +2 -0
- package/dist/sessions/read-recovery-edge.js +26 -0
- package/dist/sessions/read.d.ts +8 -1
- package/dist/sessions/read.js +6 -3
- package/dist/sessions/recall-bundle.d.ts +12 -0
- package/dist/sessions/recall-bundle.js +33 -0
- package/dist/sessions/recall-frames.d.ts +18 -0
- package/dist/sessions/recall-frames.js +44 -0
- package/dist/sessions/recall-next.d.ts +145 -0
- package/dist/sessions/recall-next.js +241 -0
- package/dist/sessions/recall-object.d.ts +2 -0
- package/dist/sessions/recall-object.js +1 -0
- package/dist/sessions/recall-push.d.ts +2 -2
- package/dist/sessions/recall-push.js +3 -51
- package/dist/sessions/recall-reads.d.ts +7 -0
- package/dist/sessions/recall-reads.js +7 -0
- package/dist/sessions/recovery-calls.d.ts +21 -0
- package/dist/sessions/recovery-calls.js +25 -0
- package/dist/sessions/redact.d.ts +11 -0
- package/dist/sessions/redact.js +59 -0
- package/dist/sessions/schema.d.ts +59 -9
- package/dist/sessions/schema.js +22 -3
- package/dist/sessions/session-shape.d.ts +6 -3
- package/dist/sessions/session-shape.js +19 -6
- package/dist/sessions/sources.js +75 -1
- package/dist/sessions/store.d.ts +13 -1
- package/dist/sessions/store.js +36 -16
- package/dist/sessions/survival.d.ts +2 -0
- package/dist/sessions/survival.js +2 -2
- package/dist/sessions/transcript-tail.d.ts +14 -0
- package/dist/sessions/transcript-tail.js +64 -0
- package/dist/sessions/vscode-copilot.js +24 -7
- package/dist/telemetry/command.d.ts +8 -0
- package/dist/telemetry/command.js +85 -0
- package/dist/telemetry/consent.d.ts +17 -0
- package/dist/telemetry/consent.js +63 -0
- package/dist/telemetry/crash.d.ts +8 -0
- package/dist/telemetry/crash.js +52 -0
- package/dist/telemetry/emit.d.ts +31 -0
- package/dist/telemetry/emit.js +42 -0
- package/dist/telemetry/fields.d.ts +16 -0
- package/dist/telemetry/fields.js +26 -0
- package/dist/telemetry/health.d.ts +21 -0
- package/dist/telemetry/health.js +108 -0
- package/dist/telemetry/hook-emit.d.ts +4 -0
- package/dist/telemetry/hook-emit.js +18 -0
- package/dist/telemetry/measures.d.ts +32 -0
- package/dist/telemetry/measures.js +128 -0
- package/dist/telemetry/observe.d.ts +13 -0
- package/dist/telemetry/observe.js +51 -0
- package/dist/telemetry/read-events.d.ts +9 -0
- package/dist/telemetry/read-events.js +17 -0
- package/dist/telemetry/record.d.ts +17 -0
- package/dist/telemetry/record.js +26 -0
- package/dist/telemetry/report.d.ts +77 -0
- package/dist/telemetry/report.js +188 -0
- package/dist/telemetry/schema.d.ts +40 -0
- package/dist/telemetry/schema.js +187 -0
- package/dist/telemetry/send-main.d.ts +1 -0
- package/dist/telemetry/send-main.js +11 -0
- package/dist/telemetry/send.d.ts +36 -0
- package/dist/telemetry/send.js +172 -0
- package/dist/telemetry/spool.d.ts +17 -0
- package/dist/telemetry/spool.js +70 -0
- package/dist/telemetry/wire.d.ts +25 -0
- package/dist/telemetry/wire.js +76 -0
- package/package.json +2 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// One sender at a time per outbox (t884): the nightly task and `deposit --send` both take this lock, so a batch is never posted twice by two runs that overlap. The lock is a file created
|
|
2
|
+
// with `wx` beside `sent.log`, so it holds across processes as well as inside one. A run that finds it held waits; a lock older than `staleMs` belongs to a run that died, and is taken over by one waiter only, under a guard file. The holder touches the file while it runs, so a long send (a first night of raw parts) is never mistaken for a dead run, and it removes the file only if the file still names its own run.
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { mkdir, open, readFile, rm, stat, utimes } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
7
|
+
const DEFAULT_TIMES = { staleMs: 10 * 60 * 1000, waitMs: 2 * 60 * 1000, pollMs: 50 };
|
|
8
|
+
export class SendLockBusy extends Error {
|
|
9
|
+
constructor() {
|
|
10
|
+
super('Another oars run is sending from this outbox.');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
// EEXIST means another run holds the file. On Windows an open of a file whose delete is still pending (the holder just released it) answers EPERM or EACCES instead: the same contention, so retry within waitMs.
|
|
14
|
+
const contended = (error, platform) => {
|
|
15
|
+
if (!(error instanceof Error))
|
|
16
|
+
return false;
|
|
17
|
+
const code = Reflect.get(error, 'code');
|
|
18
|
+
return code === 'EEXIST' || (platform === 'win32' && (code === 'EPERM' || code === 'EACCES'));
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* A stale lock is removed under a takeover guard (`send.lock.takeover`, created with `wx`), so one waiter at a time reads the lock again and removes it only if it is still stale. A live lock is never moved
|
|
22
|
+
* or removed: a waiter that read a lock as stale, but meets a lock another run took over and refreshed in the meantime, finds it fresh under the guard and leaves it. A guard left by a taker that died is
|
|
23
|
+
* removed once it is older than `staleMs`.
|
|
24
|
+
*/
|
|
25
|
+
const takeOver = async (file, staleMs, fs) => {
|
|
26
|
+
const guard = `${file}.takeover`;
|
|
27
|
+
try {
|
|
28
|
+
await (await open(guard, 'wx')).close();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
const left = await stat(guard).catch(() => undefined);
|
|
32
|
+
if (left !== undefined && Date.now() - left.mtimeMs > staleMs)
|
|
33
|
+
await rm(guard, { force: true });
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
try {
|
|
37
|
+
const held = await fs.stat(file).catch(() => undefined);
|
|
38
|
+
if (held === undefined || Date.now() - held.mtimeMs <= staleMs)
|
|
39
|
+
return false;
|
|
40
|
+
await rm(file, { force: true });
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
await rm(guard, { force: true });
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
export const withSendLock = async (outbox, run, times = {}, fs = { stat }) => {
|
|
48
|
+
const { staleMs, waitMs, pollMs } = { ...DEFAULT_TIMES, ...times };
|
|
49
|
+
const file = join(outbox, 'send.lock');
|
|
50
|
+
const runId = randomUUID();
|
|
51
|
+
const create = fs.open ?? open;
|
|
52
|
+
const platform = fs.platform ?? process.platform;
|
|
53
|
+
await mkdir(outbox, { recursive: true });
|
|
54
|
+
const giveUp = Date.now() + waitMs;
|
|
55
|
+
for (;;) {
|
|
56
|
+
try {
|
|
57
|
+
const handle = await create(file, 'wx');
|
|
58
|
+
await handle.writeFile(runId);
|
|
59
|
+
await handle.close();
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!contended(error, platform))
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
const held = await fs.stat(file).catch(() => undefined);
|
|
67
|
+
// A takeover that cleared the lock goes straight back to taking it; any other outcome waits, and gives up once waitMs has passed.
|
|
68
|
+
if (held !== undefined && Date.now() - held.mtimeMs > staleMs && (await takeOver(file, staleMs, fs)))
|
|
69
|
+
continue;
|
|
70
|
+
if (Date.now() >= giveUp)
|
|
71
|
+
throw new SendLockBusy();
|
|
72
|
+
await sleep(pollMs);
|
|
73
|
+
}
|
|
74
|
+
const beat = setInterval(() => {
|
|
75
|
+
const now = new Date();
|
|
76
|
+
utimes(file, now, now).catch(() => undefined);
|
|
77
|
+
}, Math.max(1, Math.floor(staleMs / 4)));
|
|
78
|
+
try {
|
|
79
|
+
return await run();
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
clearInterval(beat);
|
|
83
|
+
// The file is ours only while it still names this run; a lock another run took over is theirs.
|
|
84
|
+
if ((await readFile(file, 'utf8').catch(() => undefined)) === runId)
|
|
85
|
+
await rm(file, { force: true });
|
|
86
|
+
}
|
|
87
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Each hash that was sent, with the time it was sent. A hash sent twice keeps its first time. */
|
|
2
|
+
export declare const sentLog: (outbox: string) => Promise<Map<string, string>>;
|
|
3
|
+
export declare const sentHashes: (outbox: string) => Promise<Set<string>>;
|
|
4
|
+
export declare const markSent: (outbox: string, hash: string, at: number) => Promise<void>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// What the nightly send has already sent, so a night after a failure sends only what was not taken: one line for each hash, in the outbox beside `shown.log`. A batch that is rebuilt hashes differently and so is sent again, which is what a deposit that changed should do.
|
|
2
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { isMissing } from './pool-outbox.js';
|
|
5
|
+
const sentFile = (outbox) => join(outbox, 'sent.log');
|
|
6
|
+
/** Each hash that was sent, with the time it was sent. A hash sent twice keeps its first time. */
|
|
7
|
+
export const sentLog = async (outbox) => {
|
|
8
|
+
const log = new Map();
|
|
9
|
+
try {
|
|
10
|
+
for (const line of (await readFile(sentFile(outbox), 'utf8')).split('\n')) {
|
|
11
|
+
const [hash = '', at = ''] = line.split(' ');
|
|
12
|
+
if (hash !== '' && !log.has(hash))
|
|
13
|
+
log.set(hash, at);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!isMissing(error))
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
return log;
|
|
21
|
+
};
|
|
22
|
+
export const sentHashes = async (outbox) => new Set((await sentLog(outbox)).keys());
|
|
23
|
+
export const markSent = async (outbox, hash, at) => {
|
|
24
|
+
await mkdir(outbox, { recursive: true });
|
|
25
|
+
await appendFile(sentFile(outbox), `${hash} ${new Date(at).toISOString()}\n`, 'utf8');
|
|
26
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface OutboxTotals {
|
|
2
|
+
/** Batches of the current stamp whose hash `sent.log` holds. */
|
|
3
|
+
sentBatches: number;
|
|
4
|
+
/** Raw copies of the current stamp whose hash `sent.log` holds. */
|
|
5
|
+
sentRaw: number;
|
|
6
|
+
/** Raw copies queued now, and the placeholders in their bodies: the values masked locally before anything is sent. */
|
|
7
|
+
rawCopies: number;
|
|
8
|
+
rawMasked: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const outboxTotals: (storeDir: string) => Promise<OutboxTotals>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// What the outboxes hold across every server, for `oars sessions verify`: how much of it was already sent, and how many values the raw copies masked. Counts only.
|
|
2
|
+
import { readdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { heldBatches } from './pool-outbox.js';
|
|
5
|
+
import { heldRaw } from './pool-raw.js';
|
|
6
|
+
import { sentHashes } from './pool-sent.js';
|
|
7
|
+
import { placeholders } from './redact.js';
|
|
8
|
+
export const outboxTotals = async (storeDir) => {
|
|
9
|
+
const root = join(storeDir, 'pool-outbox');
|
|
10
|
+
const totals = { sentBatches: 0, sentRaw: 0, rawCopies: 0, rawMasked: 0 };
|
|
11
|
+
for (const name of await readdir(root).catch(() => [])) {
|
|
12
|
+
const outbox = join(root, name);
|
|
13
|
+
const done = await sentHashes(outbox);
|
|
14
|
+
totals.sentBatches += (await heldBatches(outbox)).batches.filter(({ hash }) => done.has(hash)).length;
|
|
15
|
+
const { copies } = await heldRaw(outbox);
|
|
16
|
+
totals.sentRaw += copies.filter(({ hash }) => done.has(hash)).length;
|
|
17
|
+
totals.rawCopies += copies.length;
|
|
18
|
+
totals.rawMasked += copies.reduce((sum, { body }) => sum + placeholders(body), 0);
|
|
19
|
+
}
|
|
20
|
+
return totals;
|
|
21
|
+
};
|
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import { VOCAB_VERSION } from './public-vocabulary.js';
|
|
1
|
+
import { VOCAB_VERSION, type RepoSize } from './public-vocabulary.js';
|
|
2
|
+
import { type ArgClass, type TargetClass } from './call-shape.js';
|
|
2
3
|
import type { Cell } from './cells.js';
|
|
4
|
+
import type { Redactor } from './redact.js';
|
|
3
5
|
import type { Motif } from './motif.js';
|
|
4
6
|
import type { Read, ReadAsOf } from './read.js';
|
|
5
|
-
import { type
|
|
6
|
-
|
|
7
|
+
import { type RecoveryCalls } from './recovery-calls.js';
|
|
8
|
+
import { type PromptIntervention, type Frame, type FrameStack, type Harness, type LanguageShare, type PromptClass, type PromptObservation, type SessionObservation, type StepEdge, type StepObservation, type ToolObservation, type ToolStatus, type Usage } from './schema.js';
|
|
9
|
+
export declare const SKELETON_FORMAT = 3;
|
|
10
|
+
/**
|
|
11
|
+
* The version of the field list: every field name a batch can hold (`BATCH_FIELDS` in `pool-outbox.ts`). It moves with any field added, so a server told the version knows which names a batch may carry,
|
|
12
|
+
* and a test pins the list to it (`pool-wire-additive.test.ts`). A field is deprecated and left on the list, never removed (conclusion section 17, rule 3).
|
|
13
|
+
*/
|
|
14
|
+
export declare const FIELD_LIST_VERSION = 8;
|
|
7
15
|
export declare const BUNDLE_FORMAT = 1;
|
|
8
16
|
/** One constant: the pool serves only the vocabulary version the client holds. */
|
|
9
17
|
export { VOCAB_VERSION };
|
|
@@ -25,46 +33,118 @@ export declare const bucketOf: (kind: BucketKind, value: number) => number;
|
|
|
25
33
|
export declare const projectExplore: (stored: number | undefined) => number | null;
|
|
26
34
|
/** The lowest value of a bucket, which is what a derivation counts a bucketed value as: it never reads above what the sender held. */
|
|
27
35
|
export declare const floorOf: (kind: BucketKind, bucket: number) => number;
|
|
36
|
+
/** The closed list of how a step came about (`schema.ts` `StepEdge`). */
|
|
37
|
+
export declare const EDGE_KINDS: readonly ["next", "spawned", "retried", "after-error"];
|
|
38
|
+
/** One edge arriving at a step: its kind, and the position of the step it names, counted over the steps of one transcript in call order (the batch's own ordinal, never a call number). A `spawned` edge names a step of the spawning transcript. */
|
|
39
|
+
export interface SkeletonEdge {
|
|
40
|
+
/** `other` for a kind the reader does not know (see `OTHER`); it names no step the parser can check, so only its shape is held. */
|
|
41
|
+
kind: StepEdge['kind'] | typeof OTHER;
|
|
42
|
+
target: number;
|
|
43
|
+
}
|
|
28
44
|
/**
|
|
29
|
-
* A step without what a server can compute
|
|
30
|
-
* two buckets, never the exact counts. `parent` is the position of the spawning call in the
|
|
45
|
+
* A step without what a server can compute: `n` is its call's position, `seg` its place in the call (the array position), and `frameId` hashes a frame the skeleton holds. Its cost is
|
|
46
|
+
* two buckets, never the exact counts. `parent` is the position of the spawning call in the `tools` of the transcript its transcript's `spawnedIn` names (Section 1.2's `parent` ordinal).
|
|
31
47
|
*/
|
|
32
|
-
export type SkeletonStep = Omit<StepObservation, 'n' | 'seg' | 'frameId' | 'cost' | 'edges'> & {
|
|
48
|
+
export type SkeletonStep = Omit<StepObservation, 'n' | 'seg' | 'frameId' | 'cost' | 'edges' | 'status'> & {
|
|
49
|
+
/** The edges that arrive at this step, `retried` already decided by the client (the pool holds no raw key to compare); absent when none arrive. */
|
|
50
|
+
edges?: SkeletonEdge[];
|
|
51
|
+
/** `other` for a status the reader does not know (see `OTHER`). */
|
|
52
|
+
status: ToolStatus | typeof OTHER;
|
|
33
53
|
/** A `tokens` bucket of the step's tokens. */
|
|
34
54
|
tokens: number | null;
|
|
35
55
|
/** An `ms` bucket of the step's time. */
|
|
36
56
|
ms: number | null;
|
|
37
|
-
/**
|
|
38
|
-
|
|
57
|
+
/** True when `tokens` was divided among the calls of one response, not measured for this step; absent otherwise. */
|
|
58
|
+
allocated?: true;
|
|
59
|
+
/** A `tokens` bucket of the tokens the run spent after this step (spec Section 1.2): the bucket of the exact sum, never a sum of buckets, summed over the later steps that reported tokens (a lower bound). Null when steps follow and none reported tokens; 0 only when nothing follows or the later steps reported zero. */
|
|
60
|
+
remainingTokens: number | null;
|
|
39
61
|
/** The projected type of the subagent whose run holds the step, a built-in or `custom`; null on a main-run step. */
|
|
40
62
|
agentType: string | null;
|
|
63
|
+
/** The step's frame: a position in its transcript's `frames`, the frame of the call that made it, with that call's own model and harness version (t867). The parser refuses a position outside the list. */
|
|
64
|
+
frame: number;
|
|
65
|
+
/** The skill whose run the step's call sits in, the name after redaction or `private`; absent outside a run. The harness marks no end to a run but stops naming the skill on the next line, and a step carries the skill its call's line named. */
|
|
66
|
+
skill?: string;
|
|
41
67
|
};
|
|
42
68
|
/** A call's order is its position in `tools`, and its `prompt` is a position in the same transcript's `prompts`: ordinals inside the batch, never the session's own numbers. */
|
|
43
69
|
export interface SkeletonTool {
|
|
44
70
|
side: boolean;
|
|
45
71
|
prompt: number | null;
|
|
46
|
-
status: ToolStatus;
|
|
72
|
+
status: ToolStatus | typeof OTHER;
|
|
47
73
|
/** Exact, per tool: the one exact time on the wire, which W reads on `ledger` (Section 1.2, `durationMs`). A cell never reads it. */
|
|
48
74
|
durationMs: number | null;
|
|
75
|
+
/** The failed call's class, a member of `ERROR_CODES` (a user refusal, a policy denial, and a real failure are three codes); null on a call that did not fail and on one whose capture holds none. Never result text. */
|
|
76
|
+
errorCode: string | null;
|
|
77
|
+
/** For a failed call, what followed it: the actions of up to the next 5 calls of its prompt and whether an edit was among them. Absent on a call that did not fail. Never a signature, command, or text. */
|
|
78
|
+
recoveryCalls?: RecoveryCalls;
|
|
79
|
+
/** The call's input key names, sorted (t870): a public tool's from its pinned list in `TOOL_INPUT_KEYS`, any other tool's from the name gate, and none for a tool that went as `private`. Never a value. Absent when none is sent. */
|
|
80
|
+
keys?: string[];
|
|
81
|
+
/** A `count` bucket of the key names the call held that were not sent: off a public tool's pinned list, or kept `private` by the gate. Absent when none was dropped. */
|
|
82
|
+
keysDropped?: number;
|
|
83
|
+
/** The class of the call's path target, derived at capture from the target's base and suffix (`targetClassOf`): the base name itself does not go. Absent on a call captured before it. */
|
|
84
|
+
targetClass?: TargetClass | typeof OTHER;
|
|
85
|
+
/** The classes of the call's arguments as a sorted set, derived at capture (`argClassOf`); never a value. Absent on a call captured before it. */
|
|
86
|
+
argClass?: Array<ArgClass | typeof OTHER>;
|
|
49
87
|
steps: SkeletonStep[];
|
|
50
88
|
}
|
|
51
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* A prompt's usage as `tokens` buckets: `thinking` is a token count (the thinking tokens of the output), so it takes the same edges as the rest. A category the source
|
|
91
|
+
* never recorded is null, never the bucket of zero: a prompt with no counts at all sends five nulls, and a partial total sends a number only for the categories it observed.
|
|
92
|
+
*/
|
|
52
93
|
export type SkeletonUsage = {
|
|
53
|
-
[field in keyof Usage]: number;
|
|
94
|
+
[field in keyof Usage]: number | null;
|
|
54
95
|
};
|
|
55
96
|
/** A language of the stack with its share of the touched files (spec Section 7): one of four buckets, never a count. */
|
|
56
97
|
export interface LanguageShareEntry {
|
|
57
98
|
language: string;
|
|
58
|
-
languageShare: LanguageShare;
|
|
99
|
+
languageShare: LanguageShare | typeof OTHER;
|
|
59
100
|
}
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
101
|
+
/**
|
|
102
|
+
* The MCP servers, skills, and plugins in reach of a session, each the name after redaction or `private` (a plugin has no pinned list, so it is always `private`). `filled` says whether the harness recorded a
|
|
103
|
+
* `setup` or a `funnel` at all: an unfilled reach lists nothing and must not be read as a session with no tools.
|
|
104
|
+
*/
|
|
105
|
+
export interface Reach {
|
|
106
|
+
filled: boolean;
|
|
107
|
+
mcp: string[];
|
|
108
|
+
skills: string[];
|
|
109
|
+
plugins: string[];
|
|
110
|
+
}
|
|
111
|
+
/** How many people the operator's organization has (an operator's setting, read locally, never looked up). */
|
|
112
|
+
export declare const ORG_SIZES: readonly ["solo", "2-10", "11-100", "101-1000", "over-1000", "unknown"];
|
|
113
|
+
export type OrgSize = (typeof ORG_SIZES)[number];
|
|
114
|
+
/** Whether the repository's local git log shows one commit author or several (distinct authors, counted and then dropped). */
|
|
115
|
+
export declare const TEAMS: readonly ["solo", "team", "unknown"];
|
|
116
|
+
export type Team = (typeof TEAMS)[number];
|
|
117
|
+
/** Whether the repository is public or private (an operator's setting, read locally, never looked up). */
|
|
118
|
+
export declare const REPO_VISIBILITIES: readonly ["public", "private", "unknown"];
|
|
119
|
+
export type RepoVisibility = (typeof REPO_VISIBILITIES)[number];
|
|
120
|
+
/** What the pool can state about whom a deposit covers. It is not a filter: no read uses it. Anything not read locally is `unknown`. */
|
|
121
|
+
export interface Coverage {
|
|
122
|
+
orgSize: OrgSize;
|
|
123
|
+
team: Team;
|
|
124
|
+
repoVisibility: RepoVisibility;
|
|
125
|
+
}
|
|
126
|
+
export declare const NO_COVERAGE: Coverage;
|
|
127
|
+
/** The UTC hour of day, 0 to 23, of a timestamp, whatever offset it was written in; null when there is none or it does not parse. */
|
|
128
|
+
export declare const hourOf: (ts: string | null | undefined) => number | null;
|
|
129
|
+
/**
|
|
130
|
+
* The frame a skeleton holds: the stored frame, with the stack's shares beside its languages. A language whose share is not known is in `languages` and has no entry here. `reach`, `repoKey`, and the coverage bands
|
|
131
|
+
* are on the transcript's frame and the frames of its list, not on a prompt's. `hour` is the UTC hour beside `day` and joins no cell. Every one is optional: an absent field was not sent.
|
|
132
|
+
*/
|
|
133
|
+
export type SkeletonFrame = Omit<Frame, 'stack' | 'harness'> & {
|
|
134
|
+
harness: WireHarness;
|
|
135
|
+
stack: Omit<FrameStack, 'size'> & {
|
|
136
|
+
size: RepoSize | typeof OTHER | null;
|
|
63
137
|
languageShares: LanguageShareEntry[];
|
|
64
138
|
};
|
|
139
|
+
reach?: Reach;
|
|
140
|
+
repoKey?: string;
|
|
141
|
+
orgSize?: OrgSize | typeof OTHER;
|
|
142
|
+
team?: Team | typeof OTHER;
|
|
143
|
+
repoVisibility?: RepoVisibility | typeof OTHER;
|
|
144
|
+
hour?: number;
|
|
65
145
|
};
|
|
66
146
|
export interface SkeletonPrompt {
|
|
67
|
-
cls: PromptClass;
|
|
147
|
+
cls: PromptClass | typeof OTHER;
|
|
68
148
|
/** A `count` bucket. */
|
|
69
149
|
errors: number;
|
|
70
150
|
/** A `seconds` bucket. */
|
|
@@ -72,14 +152,22 @@ export interface SkeletonPrompt {
|
|
|
72
152
|
usage: SkeletonUsage;
|
|
73
153
|
/** A `calls` bucket of the prompt's steps that only look (`file.read`, `file.search`, `web.search`, `web.fetch`); null when the record holds no count. */
|
|
74
154
|
explore: number | null;
|
|
155
|
+
/** A `count` bucket of the responses that reported usage: what a partial `usage` sum covers. Absent only when the record predates the coverage (capture version 20). */
|
|
156
|
+
usageResponses?: number;
|
|
157
|
+
/** Whether a human stepped in after this prompt's work and how, one of the closed list (t882; docs/sessions-store.md "Prompt intervention"). Absent when the stored prompt predates the signal: absent means not computed, `unknown` means computed and not sayable. An outcome row, never a grade. */
|
|
158
|
+
intervention?: PromptIntervention | typeof OTHER;
|
|
75
159
|
frame: SkeletonFrame;
|
|
76
160
|
}
|
|
77
161
|
export interface SkeletonTranscript {
|
|
78
162
|
/** The transcript's Merkle root and the count of its lines it covers (Section 2, "Subagents"): one pair for each transcript, the main's first. */
|
|
79
163
|
merkleRoot: string;
|
|
80
164
|
leaves: number;
|
|
81
|
-
harness:
|
|
165
|
+
harness: WireHarness;
|
|
82
166
|
frame: SkeletonFrame;
|
|
167
|
+
/** The distinct frames the transcript's steps ran in, the transcript's own first; a step's `frame` is a position in it. */
|
|
168
|
+
frames: SkeletonFrame[];
|
|
169
|
+
/** The position, in the batch's `transcripts`, of the transcript that spawned this one; null for the main run, and for a subagent whose spawner the batch does not hold or the harness does not name. */
|
|
170
|
+
spawnedIn: number | null;
|
|
83
171
|
prompts: SkeletonPrompt[];
|
|
84
172
|
tools: SkeletonTool[];
|
|
85
173
|
}
|
|
@@ -93,15 +181,19 @@ export type DeltaMetric = 'callsPerSession' | 'thinking';
|
|
|
93
181
|
* always `private`), null when the field is named alone; `registry` is the package's registry and is null for a `private` name; `change` is the signed bucket of the metric's move, never the metric.
|
|
94
182
|
*/
|
|
95
183
|
export interface DeltaEntry {
|
|
96
|
-
deltaKind: DeltaKind;
|
|
97
|
-
field: DeltaField;
|
|
184
|
+
deltaKind: DeltaKind | typeof OTHER;
|
|
185
|
+
field: DeltaField | typeof OTHER;
|
|
98
186
|
name: string | null;
|
|
99
187
|
registry: string | null;
|
|
100
|
-
metric: DeltaMetric;
|
|
188
|
+
metric: DeltaMetric | typeof OTHER;
|
|
101
189
|
change: number;
|
|
102
190
|
}
|
|
103
191
|
export interface SessionSkeleton {
|
|
104
192
|
format: typeof SKELETON_FORMAT;
|
|
193
|
+
/** The vocabulary version the client built the batch under: stored with it, so a read can tell a batch of an older list from a current one. */
|
|
194
|
+
vocabVersion: string;
|
|
195
|
+
/** `FIELD_LIST_VERSION` as the client held it: the fields a batch of this version may carry. */
|
|
196
|
+
fieldsVersion: number;
|
|
105
197
|
/** A hash the client computes per account, so a redeposit replaces and two accounts' sessions cannot be joined. Never the session's own id. */
|
|
106
198
|
id: string;
|
|
107
199
|
/** The main transcript first, then each subagent's. */
|
|
@@ -144,7 +236,7 @@ export declare const sessionsOf: (store: {
|
|
|
144
236
|
prompts: readonly PromptObservation[];
|
|
145
237
|
tools: readonly ToolObservation[];
|
|
146
238
|
}, roots: ReadonlyMap<string, TranscriptRoot>) => SessionRecords[];
|
|
147
|
-
/** One command of a shell call as the projection reads it (`projectStoredShell`): a program, its subcommand, and its flags, each
|
|
239
|
+
/** One command of a shell call as the projection reads it (`projectStoredShell`): a program, its subcommand, and its flags, each the name after redaction or `private`. */
|
|
148
240
|
export interface ShellCommand {
|
|
149
241
|
program: string;
|
|
150
242
|
subcommand: string | null;
|
|
@@ -152,19 +244,42 @@ export interface ShellCommand {
|
|
|
152
244
|
}
|
|
153
245
|
/** Reads a stored shell call's commands in order. The client passes the projection; this file holds no vocabulary snapshot, so the Worker can bundle it. */
|
|
154
246
|
export type ShellReader = (tool: ToolObservation) => readonly ShellCommand[];
|
|
247
|
+
/** The most characters a name may hold on the wire. A longer value is not a name: it counts as redacted. */
|
|
248
|
+
export declare const NAME_MAX = 128;
|
|
249
|
+
/** Whether a value has the shape of a name (and so can be told from a command line, a path, or an email) and is within `NAME_MAX`. */
|
|
250
|
+
export declare const isWireName: (name: string) => boolean;
|
|
251
|
+
/** The shape of a pull's package name: a name, or a scope or module path with `/` in it. */
|
|
252
|
+
export declare const isWirePullName: (name: string) => boolean;
|
|
253
|
+
/** What the client holds against a value before it leaves: the redactor, and the exclusion terms the operator keeps. This is the one gate; the pool assigns every other class. */
|
|
254
|
+
export interface WireGate {
|
|
255
|
+
readonly redact: Redactor;
|
|
256
|
+
readonly terms: readonly string[];
|
|
257
|
+
}
|
|
258
|
+
/** No redaction and no terms: the name shape and the length limit still apply. A local read, which sends nothing, uses it. */
|
|
259
|
+
export declare const OPEN_GATE: WireGate;
|
|
260
|
+
/**
|
|
261
|
+
* A name as the wire holds it: the value itself, or `private` when it counts as redacted. A value counts as redacted when the redactor changes it, it holds an exclusion term, it fails the name shape, or it is over
|
|
262
|
+
* `NAME_MAX` characters, because a secret, an employer's name, or a mis-parsed command is not a name and nothing downstream can take it back. `keys` (t870) sends its names through this same function.
|
|
263
|
+
*/
|
|
264
|
+
export declare const wireName: (gate: WireGate, name: string, hasShape?: (name: string) => boolean) => string;
|
|
155
265
|
/**
|
|
156
|
-
* A stored tool's steps as the wire holds them: each shell step's identity is replaced by the projected command, and every name
|
|
157
|
-
*
|
|
266
|
+
* A stored tool's steps as the wire holds them: each shell step's identity is replaced by the projected command, and every long-tail name (a native name, MCP server, skill, host, program, or pull name) is
|
|
267
|
+
* sent as it is after the gate, or `private` when it counts as redacted. A `private` program holds no pull. The one place a deposit and a local read take it from.
|
|
158
268
|
*/
|
|
159
|
-
export declare const projectedSteps: (tool: ToolObservation, read: ShellReader, harness: Harness) => StepObservation[];
|
|
269
|
+
export declare const projectedSteps: (tool: ToolObservation, read: ShellReader, harness: Harness, gate?: WireGate) => StepObservation[];
|
|
160
270
|
/** The hash a batch's timing print is made with, over the durations in call order: the client's `contentHash` (D1's `hP`). */
|
|
161
271
|
export type Print = (durations: readonly number[]) => string;
|
|
162
272
|
/**
|
|
163
273
|
* The skeleton of a session; null when any record of it was captured before steps and frames, or a transcript of it has no root, which holds no closed reading to send. The batch holds the main
|
|
164
274
|
* transcript's run first, then each subagent's as its own run; its `id` is the main session's, and its one `timingPrint` is over the main transcript's calls alone.
|
|
165
275
|
*/
|
|
166
|
-
export declare const skeletonOf: (records: SessionRecords, id: string, read: ShellReader, print: Print, deltas?: readonly DeltaEntry[]) => SessionSkeleton | null;
|
|
167
|
-
/**
|
|
276
|
+
export declare const skeletonOf: (records: SessionRecords, id: string, read: ShellReader, print: Print, deltas?: readonly DeltaEntry[], gate?: WireGate, coverage?: Coverage) => SessionSkeleton | null;
|
|
277
|
+
/**
|
|
278
|
+
* The version bucket of a session that recorded none: Cursor, Gemini, and Grok Build keep no harness version in their local files, and neither does a VS Code Copilot Chat session whose requests carry no `agent.extensionVersion`, so their cells are
|
|
279
|
+
* `<harness>/unknown/<model>`. It is the one non-numeric word a bundle can be asked for, so those harnesses are served the cells they have.
|
|
280
|
+
*/
|
|
281
|
+
export declare const UNKNOWN_VERSION = "unknown";
|
|
282
|
+
/** A harness version a bundle can be asked for: public, so the request carries nothing private, or `unknown` for a harness with none on record. The admitted list replaces this shape rule when it ships. */
|
|
168
283
|
export declare const isBundleVersion: (version: string) => boolean;
|
|
169
284
|
/** Whether `name` is a harness the schema names. */
|
|
170
285
|
export declare const isHarness: (name: string) => name is Harness;
|
|
@@ -173,14 +288,48 @@ export interface Refusal {
|
|
|
173
288
|
field: string;
|
|
174
289
|
reason: string;
|
|
175
290
|
}
|
|
176
|
-
|
|
291
|
+
/** The value a reader gives an enumerated field whose value it does not know (conclusion section 17, rule 3). */
|
|
292
|
+
export declare const OTHER = "other";
|
|
293
|
+
/** The harness of a transcript or a frame: one the schema names, or `other` for one a newer client names. */
|
|
294
|
+
export type WireHarness = Harness | typeof OTHER;
|
|
295
|
+
/**
|
|
296
|
+
* What one parse sets aside: a field the reader does not know, a value it does not know, and a literal a client sent beside `other`. The bag is the stored form of these (the `extensions` column), the fields kept as sent and
|
|
297
|
+
* read by nothing that serves: no cell, read, or bundle is derived from it. `at` is the field's path, as a refusal names it.
|
|
298
|
+
*/
|
|
299
|
+
export interface Extension {
|
|
300
|
+
at: string;
|
|
301
|
+
kind: 'field' | 'value' | 'literal';
|
|
302
|
+
value: unknown;
|
|
303
|
+
}
|
|
304
|
+
/** The fields a client may send a literal beside (`<field>Literal`) when the field itself says `other`: the enumerated fields, whose values a closed list holds. */
|
|
305
|
+
export declare const ENUMERATED_FIELDS: ReadonlySet<string>;
|
|
306
|
+
/**
|
|
307
|
+
* The fields that may be absent at format 3, by the level of the batch that holds them. An absent one reads as null, or as empty for a list, exactly as a sent null does, so a batch with all of them left out is
|
|
308
|
+
* served from what remains. A field the cells need to be sound (a harness, a status, a bucket of tokens) is never here.
|
|
309
|
+
*/
|
|
310
|
+
export declare const OPTIONAL: {
|
|
311
|
+
readonly batch: readonly ["timingPrint", "deltas"];
|
|
312
|
+
readonly frame: readonly ["harnessVersion", "model", "effort", "day", "shell", "reach", "repoKey", "orgSize", "team", "repoVisibility", "hour"];
|
|
313
|
+
readonly stack: readonly ["size", "languageShares"];
|
|
314
|
+
readonly prompt: readonly ["wallSec", "explore", "usageResponses", "intervention"];
|
|
315
|
+
readonly tool: readonly ["prompt", "durationMs", "errorCode", "recoveryCalls", "keys", "keysDropped", "targetClass", "argClass"];
|
|
316
|
+
readonly step: readonly ["tokens", "ms", "allocated", "parent", "skill", "edges", "remainingTokens"];
|
|
317
|
+
readonly transcript: readonly ["spawnedIn"];
|
|
318
|
+
};
|
|
319
|
+
/** The most bytes (as JSON) one field this reader does not know, or one literal, may hold: an enumerated value or a literal never needs more, and a newer client's larger structure belongs in a new format version. The deposit's own cap is no part of this. */
|
|
320
|
+
export declare const MAX_EXTENSION_BYTES: number;
|
|
321
|
+
export declare const HARNESSES: readonly ["claude-code", "cursor", "codex", "copilot", "gemini", "grok", "opencode", "pi", "vscode-copilot", "otel"];
|
|
177
322
|
/** The registries a package comes from; a pull may also come from a skill, plugin, or MCP registry. */
|
|
178
323
|
export declare const PACKAGE_REGISTRIES: readonly ["npm", "pypi", "crates", "go", "rubygems", "homebrew"];
|
|
179
|
-
/**
|
|
180
|
-
export
|
|
324
|
+
/** A parsed batch: the skeleton every derivation reads, the bag of what this reader did not know, and the count of values it read as `other`. Only the skeleton is ever served from. */
|
|
325
|
+
export interface ParsedSkeleton {
|
|
181
326
|
ok: true;
|
|
182
327
|
skeleton: SessionSkeleton;
|
|
183
|
-
|
|
328
|
+
extensions: Extension[];
|
|
329
|
+
others: number;
|
|
330
|
+
}
|
|
331
|
+
/** The skeleton in `value`, rebuilt from the fields read, with the bag of what was set aside; else the first field that is a shape error, and why. */
|
|
332
|
+
export declare const parseSkeleton: (value: unknown) => ParsedSkeleton | Refusal;
|
|
184
333
|
/**
|
|
185
334
|
* One count of a stack stratum (spec Section 4, rule 3), across every harness version, so it is never joined to one. The two pairs hold two values each, joined by a slash:
|
|
186
335
|
* `languageShare` is `<language>/<share bucket>` and `repoFilesExplore` is `<stack size, xs to xl>/<explore calls bucket>`.
|
|
@@ -191,17 +340,78 @@ export interface StrataCell {
|
|
|
191
340
|
sessions: number;
|
|
192
341
|
clusters: number;
|
|
193
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* The floors a pool served the bundle at, stated so a client can print them and holds none of its own. `public` is the clusters a cell needs to be served and a read to count it, `disclosure` the clusters that must hold a signature's hash
|
|
345
|
+
* before its text may be requested, and `families` the read families that have a public floor of their own (a family not listed is at `public`). Both are the deploy's to set, so a client reads them here and never applies one.
|
|
346
|
+
*/
|
|
347
|
+
export interface BundleFloors {
|
|
348
|
+
public: number;
|
|
349
|
+
disclosure: number;
|
|
350
|
+
families?: FamilyFloors;
|
|
351
|
+
}
|
|
352
|
+
/** A floor per read family, keyed by the family's name as the pool states it. A client applies none and prints only the families it knows, so a name this version has never heard of (a family a later pool adds) is carried as stated and not refused. */
|
|
353
|
+
export interface FamilyFloors {
|
|
354
|
+
[family: string]: number;
|
|
355
|
+
}
|
|
356
|
+
/** A number the pool can state, or the plain statement that nothing measures it yet. `no source yet` is never a zero: a measured nothing and an unmeasured one must not read alike. */
|
|
357
|
+
export type Sourced = {
|
|
358
|
+
state: 'value';
|
|
359
|
+
value: number;
|
|
360
|
+
} | {
|
|
361
|
+
state: 'no source yet';
|
|
362
|
+
reason: string;
|
|
363
|
+
};
|
|
364
|
+
/**
|
|
365
|
+
* The set of four (direction conclusion, section 20 rule 1), as totals. Served cells and the below-floor backlog are totals over the cells this bundle derived from; the backlog is one number and names no
|
|
366
|
+
* tuple, week, or value. The panel is one account count and names no account. `demand` and `goal` hold a place each for a source a later brief adds. `floor`, the versions, and `asOf` are its lineage (section 17 rule 6).
|
|
367
|
+
*/
|
|
368
|
+
export interface Books {
|
|
369
|
+
floor: number;
|
|
370
|
+
format: typeof BUNDLE_FORMAT;
|
|
371
|
+
vocabVersion: string;
|
|
372
|
+
asOf: ReadAsOf;
|
|
373
|
+
served: {
|
|
374
|
+
total: number;
|
|
375
|
+
byWeek: {
|
|
376
|
+
week: string;
|
|
377
|
+
cells: number;
|
|
378
|
+
}[];
|
|
379
|
+
byTuple: {
|
|
380
|
+
tuple: string;
|
|
381
|
+
cells: number;
|
|
382
|
+
}[];
|
|
383
|
+
};
|
|
384
|
+
backlog: number;
|
|
385
|
+
panel: Sourced;
|
|
386
|
+
/** The UTC day the panel was counted: the pool reads its deposits once a day. */
|
|
387
|
+
panelDay: string | null;
|
|
388
|
+
demand: {
|
|
389
|
+
comparisonReadOwners: Sourced;
|
|
390
|
+
followOnReads: Sourced;
|
|
391
|
+
};
|
|
392
|
+
goal: {
|
|
393
|
+
readYield: Sourced;
|
|
394
|
+
costPerServedCell: Sourced;
|
|
395
|
+
yieldPerServedCell: Sourced;
|
|
396
|
+
};
|
|
397
|
+
}
|
|
194
398
|
/** One harness version's replica, as the server signs it. It names its harness, which the signature covers, so a bundle for one harness cannot stand in for another's. Nothing in it is keyed by stack. */
|
|
195
399
|
export interface Bundle {
|
|
196
400
|
format: typeof BUNDLE_FORMAT;
|
|
197
401
|
harness: Harness;
|
|
198
402
|
harnessVersion: string;
|
|
199
403
|
vocabVersion: string;
|
|
404
|
+
/** The public floor the pool applied (`floors.public`): every cell and read is at or above it except a family on a lower floor of its own, which states its floor on each read and in `floors.families`. */
|
|
405
|
+
floor: number;
|
|
200
406
|
asOf: ReadAsOf;
|
|
201
407
|
cells: Cell[];
|
|
202
408
|
motifs: Motif[];
|
|
203
409
|
reads: Read[];
|
|
204
410
|
strata: StrataCell[];
|
|
411
|
+
/** Additive: a bundle from a pool before the floors were bindings holds none, and a client that does not know the field ignores it. */
|
|
412
|
+
floors?: BundleFloors;
|
|
413
|
+
/** Absent in a bundle signed before the set of four existed, which `oars sessions books` reads as no pool books. */
|
|
414
|
+
books?: Books;
|
|
205
415
|
}
|
|
206
416
|
/** The signature covers these exact bytes, so nothing has to be canonicalized on either side. */
|
|
207
417
|
export interface SignedBundle {
|