@polydeukes/core 0.4.0 → 0.5.0

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * fail-policy — the failure-kind → fail-mode policy table (CORE-03).
2
+ * fail-policy — the failure-kind → fail-mode policy table.
3
3
  *
4
4
  * Pure and total: classifying a failure and mapping it to an exit code never
5
5
  * performs I/O and never throws. The single source of truth for "which failures
@@ -8,7 +8,7 @@
8
8
  /** How a failure resolves: 'open' passes the call through, 'closed' blocks it. */
9
9
  export type FailMode = 'open' | 'closed';
10
10
  /**
11
- * The registered failure kinds (PRD §4.1). Gate-integrity failures
11
+ * The registered failure kinds. Gate-integrity failures
12
12
  * (evidence-absence / input-parse / undecidable-structure) fail closed;
13
13
  * observability failures fail open so measurement loss never holds work hostage.
14
14
  */
@@ -16,14 +16,14 @@ export type FailureKind = 'evidence-absence' | 'input-parse' | 'undecidable-stru
16
16
  /**
17
17
  * Resolve a failure kind to its {@link FailMode} via the policy table.
18
18
  *
19
- * fail-closed default (PRD §5.2): any unregistered kind — including '' and
20
- * prototype-pollution keys — resolves to 'closed'. "Cannot classify" means
21
- * block. Pure and total (PRD §7): never throws, no I/O, no logging.
19
+ * fail-closed default: any unregistered kind — including '' and prototype-pollution
20
+ * keys — resolves to 'closed'. "Cannot classify" means block. Pure and total: never
21
+ * throws, no I/O, no logging.
22
22
  */
23
23
  export declare function resolveFailMode(kind: string): FailMode;
24
24
  /**
25
- * Map a {@link FailMode} to the covenant protocol's exit code (PRD §4.2):
25
+ * Map a {@link FailMode} to the covenant protocol's exit code:
26
26
  * 'open' → {@link EXIT_UPHOLD}, 'closed' → {@link EXIT_BREAK_BLOCKING}.
27
- * Reuses CORE-01's constants — no independent numeric literals here.
27
+ * Reuses the protocol's constants — no independent numeric literals here.
28
28
  */
29
29
  export declare function failModeToExitCode(mode: FailMode): 0 | 2;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * fail-policy — the failure-kind → fail-mode policy table (CORE-03).
2
+ * fail-policy — the failure-kind → fail-mode policy table.
3
3
  *
4
4
  * Pure and total: classifying a failure and mapping it to an exit code never
5
5
  * performs I/O and never throws. The single source of truth for "which failures
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { EXIT_BREAK_BLOCKING, EXIT_UPHOLD } from './exit-codes.js';
9
9
  /**
10
- * Policy table (PRD §4.1). Null-prototype so lookups can never reach
10
+ * Policy table. Null-prototype so lookups can never reach
11
11
  * Object.prototype members ('__proto__', 'toString', …) — those must resolve
12
12
  * to the fail-closed default, not to an inherited function.
13
13
  */
@@ -20,17 +20,17 @@ const FAIL_POLICY = Object.assign(Object.create(null), {
20
20
  /**
21
21
  * Resolve a failure kind to its {@link FailMode} via the policy table.
22
22
  *
23
- * fail-closed default (PRD §5.2): any unregistered kind — including '' and
24
- * prototype-pollution keys — resolves to 'closed'. "Cannot classify" means
25
- * block. Pure and total (PRD §7): never throws, no I/O, no logging.
23
+ * fail-closed default: any unregistered kind — including '' and prototype-pollution
24
+ * keys — resolves to 'closed'. "Cannot classify" means block. Pure and total: never
25
+ * throws, no I/O, no logging.
26
26
  */
27
27
  export function resolveFailMode(kind) {
28
28
  return FAIL_POLICY[kind] ?? 'closed';
29
29
  }
30
30
  /**
31
- * Map a {@link FailMode} to the covenant protocol's exit code (PRD §4.2):
31
+ * Map a {@link FailMode} to the covenant protocol's exit code:
32
32
  * 'open' → {@link EXIT_UPHOLD}, 'closed' → {@link EXIT_BREAK_BLOCKING}.
33
- * Reuses CORE-01's constants — no independent numeric literals here.
33
+ * Reuses the protocol's constants — no independent numeric literals here.
34
34
  */
35
35
  export function failModeToExitCode(mode) {
36
36
  return mode === 'open' ? EXIT_UPHOLD : EXIT_BREAK_BLOCKING;
package/dist/index.d.ts CHANGED
@@ -1,13 +1,12 @@
1
1
  /**
2
2
  * @polydeukes/core — the thin, domain- and agent-agnostic core.
3
3
  *
4
- * Pre-alpha. The covenant protocol (CORE-01) landed first, then the ROI telemetry
5
- * collector (CORE-02) and the config loader (CONFIG-01). Pure types and functions,
6
- * except telemetry's confined I/O functions (appendRecord / readRecords /
7
- * appendRecordFailOpen — the fail-open wrapper promoted by CORE-05).
4
+ * Alpha. Carries the covenant protocol, the ROI telemetry collector, and the config
5
+ * schema. Pure types and functions, except telemetry's confined I/O functions
6
+ * (appendRecord / readRecords / appendRecordFailOpen).
8
7
  * See https://github.com/huskyhoochu/polydeukes
9
8
  */
10
- export { ConfigValidationError, DEFAULT_TELEMETRY_LOG_PATH, type DisciplineEntry, type DisciplineForbid, defineConfig, type LanguageProfile, type PolydeukesConfig, type ResolvedConfig, type ResolvedLanguageProfile, } from './config.js';
9
+ export { ConfigValidationError, DEFAULT_TELEMETRY_LOG_PATH, type DisciplineDraft, type DisciplineEntry, type DisciplineForbid, defineConfig, type EnforceLevel, type LanguageProfile, type PolydeukesConfig, type ResolvedConfig, type ResolvedLanguageProfile, } from './config.js';
11
10
  export { EXIT_BREAK_BLOCKING, EXIT_BREAK_NON_BLOCKING, EXIT_UPHOLD, } from './exit-codes.js';
12
11
  export { type FailMode, type FailureKind, failModeToExitCode, resolveFailMode, } from './fail-policy.js';
13
12
  export { isPlainObject } from './is-plain-object.js';
@@ -15,7 +14,7 @@ export { normalizeProtectedPaths } from './protected-paths.js';
15
14
  export { aggregateGain, appendRecord, appendRecordFailOpen, formatRecordLine, type GainSummary, parseRecordLine, readRecords, runGain, type TelemetryEvent, type TelemetryRecord, } from './telemetry.js';
16
15
  export { type CanonicalTranscript, noopTranscript, type SubagentInvocation, type TranscriptToolCall, type TranscriptUserMessage, transcriptFromInput, } from './transcript.js';
17
16
  /**
18
- * `FileChange` — one file's mutation evidence around the judged call (CORE-06 §4.1).
17
+ * `FileChange` — one file's mutation evidence around the judged call.
19
18
  *
20
19
  * Agent-neutral, discriminated by `kind`: a deletion is first-class evidence rather
21
20
  * than an unrepresentable case, and impossible states (a deletion with resulting
@@ -39,14 +38,13 @@ export type FileChange = {
39
38
  pre?: string;
40
39
  };
41
40
  /**
42
- * `CovenantInput` — the agent-neutral input IR a covenant judges (PRD §4.2).
41
+ * `CovenantInput` — the agent-neutral input IR a covenant judges.
43
42
  *
44
43
  * Adapters up-translate their own agent payloads into this shape and pipe it as
45
44
  * stdin-JSON. The vocabulary carries no agent/tool literals; concrete tool or
46
45
  * subagent names are *values* an adapter fills in, never part of the core's type.
47
- * Evidence has exactly one home the call element it belongs to (CORE-06 §4.1):
48
- * `fileChange` absent means "this call is unproven", and no sibling call's evidence
49
- * can stand in for it.
46
+ * Evidence has exactly one home, the call element it belongs to: `fileChange` absent
47
+ * means "this call is unproven", and no sibling call's evidence can stand in for it.
50
48
  */
51
49
  export type CovenantInput = {
52
50
  toolCalls: {
@@ -62,7 +60,7 @@ export type CovenantInput = {
62
60
  }[];
63
61
  };
64
62
  /**
65
- * `CovenantVerdict` — the result a covenant body produces (PRD §4.3).
63
+ * `CovenantVerdict` — the result a covenant body produces.
66
64
  *
67
65
  * Either the promise was upheld, or it was broken with a human-readable reason.
68
66
  * Maps to an exit code via {@link verdictToExitCode}.
@@ -76,7 +74,7 @@ export type CovenantVerdict = {
76
74
  /**
77
75
  * Deserialize stdin-JSON into a {@link CovenantInput} (the protocol's reverse direction).
78
76
  *
79
- * fail-closed (PRD §5.2): this never throws. Any failure — unparseable JSON, an empty
77
+ * fail-closed: this never throws. Any failure — unparseable JSON, an empty
80
78
  * payload, a parsed value that is not an object, or a missing required collection —
81
79
  * resolves to a blocking `{ ok: false, exitCode: 2 }`. "Cannot judge" means block,
82
80
  * so an unjudgeable input can never be mistaken for a valid one.
@@ -89,7 +87,7 @@ export declare function parseInput(stdinJson: string): {
89
87
  exitCode: 2;
90
88
  };
91
89
  /**
92
- * Flatten every call's evidence into one array in call order (CORE-06 §4.1).
90
+ * Flatten every call's evidence into one array in call order.
93
91
  *
94
92
  * The one traversal for consumers that need no attribution (discipline scope, delta
95
93
  * judging): calls without evidence are skipped, never substituted for.
@@ -98,7 +96,7 @@ export declare function allFileChanges(input: CovenantInput): FileChange[];
98
96
  /**
99
97
  * Map a {@link CovenantVerdict} to an exit code (the protocol's forward direction).
100
98
  *
101
- * Responsibility boundary (PRD §4.1): the body emits `0` when upheld and `1` when
99
+ * Responsibility boundary: the body emits `0` when upheld and `1` when
102
100
  * broken — never the blocking `2`. Translating `1` into `2` is the wrapper's policy.
103
101
  */
104
102
  export declare function verdictToExitCode(verdict: CovenantVerdict): 0 | 1;
package/dist/index.js CHANGED
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * @polydeukes/core — the thin, domain- and agent-agnostic core.
3
3
  *
4
- * Pre-alpha. The covenant protocol (CORE-01) landed first, then the ROI telemetry
5
- * collector (CORE-02) and the config loader (CONFIG-01). Pure types and functions,
6
- * except telemetry's confined I/O functions (appendRecord / readRecords /
7
- * appendRecordFailOpen — the fail-open wrapper promoted by CORE-05).
4
+ * Alpha. Carries the covenant protocol, the ROI telemetry collector, and the config
5
+ * schema. Pure types and functions, except telemetry's confined I/O functions
6
+ * (appendRecord / readRecords / appendRecordFailOpen).
8
7
  * See https://github.com/huskyhoochu/polydeukes
9
8
  */
10
9
  import { EXIT_BREAK_BLOCKING, EXIT_BREAK_NON_BLOCKING, EXIT_UPHOLD } from './exit-codes.js';
@@ -19,7 +18,7 @@ export { noopTranscript, transcriptFromInput, } from './transcript.js';
19
18
  /**
20
19
  * Deserialize stdin-JSON into a {@link CovenantInput} (the protocol's reverse direction).
21
20
  *
22
- * fail-closed (PRD §5.2): this never throws. Any failure — unparseable JSON, an empty
21
+ * fail-closed: this never throws. Any failure — unparseable JSON, an empty
23
22
  * payload, a parsed value that is not an object, or a missing required collection —
24
23
  * resolves to a blocking `{ ok: false, exitCode: 2 }`. "Cannot judge" means block,
25
24
  * so an unjudgeable input can never be mistaken for a valid one.
@@ -44,7 +43,7 @@ export function parseInput(stdinJson) {
44
43
  return { ok: true, value: candidate };
45
44
  }
46
45
  /**
47
- * Flatten every call's evidence into one array in call order (CORE-06 §4.1).
46
+ * Flatten every call's evidence into one array in call order.
48
47
  *
49
48
  * The one traversal for consumers that need no attribution (discipline scope, delta
50
49
  * judging): calls without evidence are skipped, never substituted for.
@@ -60,7 +59,7 @@ export function allFileChanges(input) {
60
59
  /**
61
60
  * Map a {@link CovenantVerdict} to an exit code (the protocol's forward direction).
62
61
  *
63
- * Responsibility boundary (PRD §4.1): the body emits `0` when upheld and `1` when
62
+ * Responsibility boundary: the body emits `0` when upheld and `1` when
64
63
  * broken — never the blocking `2`. Translating `1` into `2` is the wrapper's policy.
65
64
  */
66
65
  export function verdictToExitCode(verdict) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `isPlainObject` — the workspace's single canonical plain-object predicate.
3
3
  *
4
- * Promoted by CORE-05 from per-package copies: typeof `object`, non-null, not an array.
4
+ * typeof `object`, non-null, not an array.
5
5
  */
6
6
  export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * `isPlainObject` — the workspace's single canonical plain-object predicate.
3
3
  *
4
- * Promoted by CORE-05 from per-package copies: typeof `object`, non-null, not an array.
4
+ * typeof `object`, non-null, not an array.
5
5
  */
6
6
  export function isPlainObject(value) {
7
7
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Protected-path normalization — the `protectedPaths` list normalized into the literal
3
- * path strings the dispatcher contract expects (CONFIG-02). Pure string transformation —
4
- * zero file I/O, no glob expansion, no path resolution (PRD §4.2).
3
+ * path strings the dispatcher contract expects. Pure string transformation — zero file
4
+ * I/O, no glob expansion, no path resolution.
5
5
  */
6
6
  /**
7
- * Normalize the protection surface from a config-shaped spec (PRD §4.2).
7
+ * Normalize the protection surface from a config-shaped spec.
8
8
  *
9
9
  * Processing order: trim each entry → strip a leading `./` → strip a trailing `/` → drop
10
10
  * empty-equivalent entries → dedupe on the normalized value, keeping the first occurrence.
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Protected-path normalization — the `protectedPaths` list normalized into the literal
3
- * path strings the dispatcher contract expects (CONFIG-02). Pure string transformation —
4
- * zero file I/O, no glob expansion, no path resolution (PRD §4.2).
3
+ * path strings the dispatcher contract expects. Pure string transformation — zero file
4
+ * I/O, no glob expansion, no path resolution.
5
5
  */
6
6
  /**
7
- * Normalize the protection surface from a config-shaped spec (PRD §4.2).
7
+ * Normalize the protection surface from a config-shaped spec.
8
8
  *
9
9
  * Processing order: trim each entry → strip a leading `./` → strip a trailing `/` → drop
10
10
  * empty-equivalent entries → dedupe on the normalized value, keeping the first occurrence.
@@ -1,11 +1,9 @@
1
1
  /**
2
- * ROI telemetry — the single shared collector and its `gain` aggregation (CORE-02).
2
+ * ROI telemetry — the single shared collector and its `gain` aggregation.
3
3
  *
4
- * One record is one line of 4-field TSV (PRD §4.1); one append is one write call
5
- * (PRD §4.2). I/O is confined to exactly two functions — {@link appendRecord} (the
6
- * only write) and {@link readRecords} (the only read). Formatting, parsing, and
7
- * aggregation are pure. This is the sole collector: later work calls this API rather
8
- * than building its own logger.
4
+ * One record is one line of 4-field TSV; one append is one write call. I/O is confined to
5
+ * exactly two functions — {@link appendRecord} (the only write) and {@link readRecords}
6
+ * (the only read). Formatting, parsing, and aggregation are pure.
9
7
  */
10
8
  /**
11
9
  * The six telemetry events. `witnessed` is a first-class event, not a flag on `passed`:
@@ -21,7 +19,7 @@
21
19
  */
22
20
  export type TelemetryEvent = 'passed' | 'blocked' | 'witnessed' | 'advised' | 'skipped' | 'unattributed';
23
21
  /**
24
- * `TelemetryRecord` — one measured covenant outcome (PRD §4.1).
22
+ * `TelemetryRecord` — one measured covenant outcome.
25
23
  *
26
24
  * `subject` is the judged target (a file path, etc.); `-` is the documented sentinel
27
25
  * for "no subject", carried round-trip like any other value.
@@ -54,13 +52,13 @@ export declare function formatRecordLine(record: TelemetryRecord): string;
54
52
  */
55
53
  export declare function parseRecordLine(line: string): TelemetryRecord | null;
56
54
  /**
57
- * Append one record to the log at `path` — the only write I/O (PRD §4.2).
55
+ * Append one record to the log at `path` — the only write I/O.
58
56
  *
59
57
  * Exactly one {@link appendFileSync} call per record, writing {@link formatRecordLine}
60
58
  * verbatim. Relying on POSIX `O_APPEND` single-write semantics, concurrent appends do
61
59
  * not interleave lines.
62
60
  *
63
- * fail-open (PRD §4.3): any fs failure — bad path, permissions, disk — returns
61
+ * fail-open: any fs failure — bad path, permissions, disk — returns
64
62
  * `{ ok: false }` and never throws. This is deliberately the opposite direction of the
65
63
  * covenant path's fail-closed: the worst outcome of telemetry is a missing datum, never
66
64
  * a blocked workflow.
@@ -69,16 +67,16 @@ export declare function appendRecord(path: string, record: TelemetryRecord): {
69
67
  ok: boolean;
70
68
  };
71
69
  /**
72
- * Append one telemetry record fail-open, timestamping it here (CORE-05).
70
+ * Append one telemetry record fail-open, timestamping it here.
73
71
  *
74
- * This layer lives above the deliberately mkdir-free {@link appendRecord} (COVENANT-01b:
75
- * an absent directory is a fail-open `{ ok: false }` for `appendRecord` itself), so this
76
- * wrapper carries the parent-directory guarantee. The mkdir and the append share one try
77
- * block, and a failure of either never alters the caller's verdict and never propagates.
72
+ * {@link appendRecord} is deliberately mkdir-free for it an absent directory is just a
73
+ * fail-open `{ ok: false }` so this wrapper carries the parent-directory guarantee. The
74
+ * mkdir and the append share one try block, and a failure of either never alters the
75
+ * caller's verdict and never propagates.
78
76
  */
79
77
  export declare function appendRecordFailOpen(telemetryPath: string, record: Omit<TelemetryRecord, 'timestamp'>): void;
80
78
  /**
81
- * Read every record from the log at `path` — the only read I/O (PRD §4.4).
79
+ * Read every record from the log at `path` — the only read I/O.
82
80
  *
83
81
  * fail-open: an absent file or any read error returns `{ records: [], skipped: 0 }`
84
82
  * (an absent log means "nothing collected yet"), never throwing. Corrupt lines
@@ -90,14 +88,14 @@ export declare function readRecords(path: string): {
90
88
  skipped: number;
91
89
  };
92
90
  /**
93
- * Aggregate records into per-label event counts (PRD §4.4, pure).
91
+ * Aggregate records into per-label event counts (pure).
94
92
  *
95
93
  * Each label gets its own counter across all six events, so a corrupt or missing
96
94
  * event never bleeds counts between labels.
97
95
  */
98
96
  export declare function aggregateGain(records: TelemetryRecord[]): GainSummary;
99
97
  /**
100
- * `gain` entry point — read the log at `path`, aggregate, and render (PRD §4.4).
98
+ * `gain` entry point — read the log at `path`, aggregate, and render.
101
99
  *
102
100
  * Composes {@link readRecords} + {@link aggregateGain} + a pure renderer. An absent or
103
101
  * empty log yields `no telemetry collected`; a corrupt line is skipped upstream, reported
package/dist/telemetry.js CHANGED
@@ -1,11 +1,9 @@
1
1
  /**
2
- * ROI telemetry — the single shared collector and its `gain` aggregation (CORE-02).
2
+ * ROI telemetry — the single shared collector and its `gain` aggregation.
3
3
  *
4
- * One record is one line of 4-field TSV (PRD §4.1); one append is one write call
5
- * (PRD §4.2). I/O is confined to exactly two functions — {@link appendRecord} (the
6
- * only write) and {@link readRecords} (the only read). Formatting, parsing, and
7
- * aggregation are pure. This is the sole collector: later work calls this API rather
8
- * than building its own logger.
4
+ * One record is one line of 4-field TSV; one append is one write call. I/O is confined to
5
+ * exactly two functions — {@link appendRecord} (the only write) and {@link readRecords}
6
+ * (the only read). Formatting, parsing, and aggregation are pure.
9
7
  */
10
8
  import { appendFileSync, mkdirSync, readFileSync } from 'node:fs';
11
9
  import { dirname } from 'node:path';
@@ -22,15 +20,15 @@ const VALID_EVENTS = [
22
20
  * The event name `witnessed` was written under before the rename — a read-only migration
23
21
  * seam, never a value this module emits.
24
22
  *
25
- * It exists because the collected log predates the rename: those rows are the sample the
26
- * milestone journal round argues from, and dropping them as corrupt would delete the
27
- * measurement instead of migrating it. Compatibility runs one way only {@link
28
- * formatRecordLine} has no path back to this name and the match is the exact literal, so
29
- * a genuinely corrupt field is still rejected rather than coerced into a fabricated record.
23
+ * A log written before the rename still carries the old name, and rejecting those rows as
24
+ * corrupt would discard the measurement rather than migrate it. Compatibility runs one way —
25
+ * {@link formatRecordLine} has no path back to this nameand the match is the exact
26
+ * literal, so a genuinely corrupt field is still rejected rather than coerced into a
27
+ * fabricated record.
30
28
  */
31
29
  const LEGACY_WITNESSED_EVENT = 'bypassed';
32
30
  /**
33
- * Replace tab/newline/carriage-return with single spaces (PRD §4.1 line integrity).
31
+ * Replace tab/newline/carriage-return with single spaces.
34
32
  *
35
33
  * Without this, a tab or newline inside a field would fabricate extra TSV fields or
36
34
  * extra lines — a record is always exactly one line.
@@ -73,13 +71,13 @@ export function parseRecordLine(line) {
73
71
  return { timestamp, event: resolved, label, subject };
74
72
  }
75
73
  /**
76
- * Append one record to the log at `path` — the only write I/O (PRD §4.2).
74
+ * Append one record to the log at `path` — the only write I/O.
77
75
  *
78
76
  * Exactly one {@link appendFileSync} call per record, writing {@link formatRecordLine}
79
77
  * verbatim. Relying on POSIX `O_APPEND` single-write semantics, concurrent appends do
80
78
  * not interleave lines.
81
79
  *
82
- * fail-open (PRD §4.3): any fs failure — bad path, permissions, disk — returns
80
+ * fail-open: any fs failure — bad path, permissions, disk — returns
83
81
  * `{ ok: false }` and never throws. This is deliberately the opposite direction of the
84
82
  * covenant path's fail-closed: the worst outcome of telemetry is a missing datum, never
85
83
  * a blocked workflow.
@@ -94,12 +92,12 @@ export function appendRecord(path, record) {
94
92
  }
95
93
  }
96
94
  /**
97
- * Append one telemetry record fail-open, timestamping it here (CORE-05).
95
+ * Append one telemetry record fail-open, timestamping it here.
98
96
  *
99
- * This layer lives above the deliberately mkdir-free {@link appendRecord} (COVENANT-01b:
100
- * an absent directory is a fail-open `{ ok: false }` for `appendRecord` itself), so this
101
- * wrapper carries the parent-directory guarantee. The mkdir and the append share one try
102
- * block, and a failure of either never alters the caller's verdict and never propagates.
97
+ * {@link appendRecord} is deliberately mkdir-free for it an absent directory is just a
98
+ * fail-open `{ ok: false }` so this wrapper carries the parent-directory guarantee. The
99
+ * mkdir and the append share one try block, and a failure of either never alters the
100
+ * caller's verdict and never propagates.
103
101
  */
104
102
  export function appendRecordFailOpen(telemetryPath, record) {
105
103
  try {
@@ -111,7 +109,7 @@ export function appendRecordFailOpen(telemetryPath, record) {
111
109
  }
112
110
  }
113
111
  /**
114
- * Read every record from the log at `path` — the only read I/O (PRD §4.4).
112
+ * Read every record from the log at `path` — the only read I/O.
115
113
  *
116
114
  * fail-open: an absent file or any read error returns `{ records: [], skipped: 0 }`
117
115
  * (an absent log means "nothing collected yet"), never throwing. Corrupt lines
@@ -143,7 +141,7 @@ export function readRecords(path) {
143
141
  return { records, skipped };
144
142
  }
145
143
  /**
146
- * Aggregate records into per-label event counts (PRD §4.4, pure).
144
+ * Aggregate records into per-label event counts (pure).
147
145
  *
148
146
  * Each label gets its own counter across all six events, so a corrupt or missing
149
147
  * event never bleeds counts between labels.
@@ -169,7 +167,7 @@ export function aggregateGain(records) {
169
167
  * Render a {@link GainSummary} into human-readable lines (pure).
170
168
  *
171
169
  * Each label is mentioned with its passed/blocked/witnessed/advised/skipped/unattributed
172
- * counts; each is a distinct column, never folded into another (PRD §4.4). A non-zero
170
+ * counts; each is a distinct column, never folded into another. A non-zero
173
171
  * corrupt-line count is reported rather than hidden — silent skipping would mask log
174
172
  * corruption.
175
173
  *
@@ -191,7 +189,7 @@ function renderGain(summary, skipped) {
191
189
  return lines.join('\n');
192
190
  }
193
191
  /**
194
- * `gain` entry point — read the log at `path`, aggregate, and render (PRD §4.4).
192
+ * `gain` entry point — read the log at `path`, aggregate, and render.
195
193
  *
196
194
  * Composes {@link readRecords} + {@link aggregateGain} + a pure renderer. An absent or
197
195
  * empty log yields `no telemetry collected`; a corrupt line is skipped upstream, reported
@@ -1,11 +1,10 @@
1
1
  /**
2
- * `CanonicalTranscript` — the agent-neutral session-query seam (CORE-04).
2
+ * `CanonicalTranscript` — the agent-neutral session-query seam.
3
3
  *
4
- * Layering (PRD §1): this seam does not replace `CovenantInput`. The IR (CORE-01) is
5
- * the *data* a covenant judges; `CanonicalTranscript` is the *behavioral seam* that
6
- * queries session data CORE-04 sits on top of CORE-01, and the IR is one source it
7
- * can wrap. Concrete transcript formats stay in adapters; the core knows only the
8
- * query vocabulary. Pure types and functions, zero I/O.
4
+ * This seam does not replace `CovenantInput`. The IR is the *data* a covenant judges;
5
+ * `CanonicalTranscript` is the *behavioral seam* that queries session data, and the IR is
6
+ * one source it can wrap. Concrete transcript formats stay in adapters; the core knows only
7
+ * the query vocabulary. Pure types and functions, zero I/O.
9
8
  */
10
9
  import type { CovenantInput } from './index.js';
11
10
  /** One subagent invocation observed in the session. `kind` is an adapter-supplied value. */
@@ -13,7 +12,7 @@ export type SubagentInvocation = {
13
12
  kind: string;
14
13
  };
15
14
  /**
16
- * One user message observed in the session (PRD §4.1).
15
+ * One user message observed in the session.
17
16
  *
18
17
  * `timestampMs` is epoch milliseconds. Its absence means the source cannot prove
19
18
  * freshness — the fail-closed signal a witness consumer must treat as "not fresh".
@@ -23,10 +22,10 @@ export type TranscriptUserMessage = {
23
22
  timestampMs?: number;
24
23
  };
25
24
  /**
26
- * One tool call observed in the session (COVENANT-13 §4.2). `name` and `args` are
27
- * adapter-supplied values — the core knows the query vocabulary, never a tool's name.
25
+ * One tool call observed in the session. `name` and `args` are adapter-supplied values —
26
+ * the core knows the query vocabulary, never a tool's name.
28
27
  *
29
- * `succeeded` is three-valued (COVENANT-13b §4.1): `true` = it ran and reported success,
28
+ * `succeeded` is three-valued: `true` = it ran and reported success,
30
29
  * `false` = it ran and reported an error, was blocked, or was refused, and absent = the
31
30
  * provider cannot observe results at all. A consumer that treats the call as evidence
32
31
  * accepts only `true`, so the latter two share a disposition while staying diagnosable.
@@ -37,7 +36,7 @@ export type TranscriptToolCall = {
37
36
  succeeded?: boolean;
38
37
  };
39
38
  /**
40
- * `CanonicalTranscript` — what a covenant may ask about the session (PRD §4.1).
39
+ * `CanonicalTranscript` — what a covenant may ask about the session.
41
40
  *
42
41
  * Synchronous by design (covenant bodies are short-lived CLI processes) and
43
42
  * verdict-free: the seam carries facts only; TTL filtering and token matching belong
@@ -52,13 +51,13 @@ export type CanonicalTranscript = {
52
51
  findToolCalls(name?: string): TranscriptToolCall[];
53
52
  };
54
53
  /**
55
- * The injection-absent default (PRD §4.2): every query answers "nothing happened".
54
+ * The injection-absent default: every query answers "nothing happened".
56
55
  * A witness consumer naturally converges to fail-closed — no evidence, no skip — and
57
56
  * so does a precedent consumer (no evidence, gate stays shut).
58
57
  */
59
58
  export declare const noopTranscript: CanonicalTranscript;
60
59
  /**
61
- * Wrap a {@link CovenantInput} as a {@link CanonicalTranscript} (PRD §4.2).
60
+ * Wrap a {@link CovenantInput} as a {@link CanonicalTranscript}.
62
61
  *
63
62
  * Exposes `subagentSpawns` as invocations (filtered when a kind is given) and
64
63
  * `userMessages` with `timestampMs` omitted — the bare IR cannot prove freshness,
@@ -66,11 +65,9 @@ export declare const noopTranscript: CanonicalTranscript;
66
65
  * Order preserved; the input is never mutated, and every query returns fresh
67
66
  * objects so consumers never hold live aliases into the shared IR.
68
67
  *
69
- * `findToolCalls` projects each call down to `{ name, args }` only: since CORE-06 a
70
- * call element also carries `fileChange` evidence, and evidence is judgment input, not
71
- * session history — the two vocabularies stay separate (COVENANT-13 §4.2). `succeeded`
72
- * stays absent for the same reason it is left three-valued: these calls are the ones
73
- * being judged right now, so they have not run, and a call can never be its own
74
- * precedent (COVENANT-13b §4.1).
68
+ * `findToolCalls` projects each call down to `{ name, args }` only: a call element also
69
+ * carries `fileChange` evidence, and evidence is judgment input, not session history — the
70
+ * two vocabularies stay separate. `succeeded` stays absent because these calls are the ones
71
+ * being judged right now: they have not run, and a call can never be its own precedent.
75
72
  */
76
73
  export declare function transcriptFromInput(input: CovenantInput): CanonicalTranscript;
@@ -1,14 +1,13 @@
1
1
  /**
2
- * `CanonicalTranscript` — the agent-neutral session-query seam (CORE-04).
2
+ * `CanonicalTranscript` — the agent-neutral session-query seam.
3
3
  *
4
- * Layering (PRD §1): this seam does not replace `CovenantInput`. The IR (CORE-01) is
5
- * the *data* a covenant judges; `CanonicalTranscript` is the *behavioral seam* that
6
- * queries session data CORE-04 sits on top of CORE-01, and the IR is one source it
7
- * can wrap. Concrete transcript formats stay in adapters; the core knows only the
8
- * query vocabulary. Pure types and functions, zero I/O.
4
+ * This seam does not replace `CovenantInput`. The IR is the *data* a covenant judges;
5
+ * `CanonicalTranscript` is the *behavioral seam* that queries session data, and the IR is
6
+ * one source it can wrap. Concrete transcript formats stay in adapters; the core knows only
7
+ * the query vocabulary. Pure types and functions, zero I/O.
9
8
  */
10
9
  /**
11
- * The injection-absent default (PRD §4.2): every query answers "nothing happened".
10
+ * The injection-absent default: every query answers "nothing happened".
12
11
  * A witness consumer naturally converges to fail-closed — no evidence, no skip — and
13
12
  * so does a precedent consumer (no evidence, gate stays shut).
14
13
  */
@@ -18,7 +17,7 @@ export const noopTranscript = {
18
17
  findToolCalls: () => [],
19
18
  };
20
19
  /**
21
- * Wrap a {@link CovenantInput} as a {@link CanonicalTranscript} (PRD §4.2).
20
+ * Wrap a {@link CovenantInput} as a {@link CanonicalTranscript}.
22
21
  *
23
22
  * Exposes `subagentSpawns` as invocations (filtered when a kind is given) and
24
23
  * `userMessages` with `timestampMs` omitted — the bare IR cannot prove freshness,
@@ -26,12 +25,10 @@ export const noopTranscript = {
26
25
  * Order preserved; the input is never mutated, and every query returns fresh
27
26
  * objects so consumers never hold live aliases into the shared IR.
28
27
  *
29
- * `findToolCalls` projects each call down to `{ name, args }` only: since CORE-06 a
30
- * call element also carries `fileChange` evidence, and evidence is judgment input, not
31
- * session history — the two vocabularies stay separate (COVENANT-13 §4.2). `succeeded`
32
- * stays absent for the same reason it is left three-valued: these calls are the ones
33
- * being judged right now, so they have not run, and a call can never be its own
34
- * precedent (COVENANT-13b §4.1).
28
+ * `findToolCalls` projects each call down to `{ name, args }` only: a call element also
29
+ * carries `fileChange` evidence, and evidence is judgment input, not session history — the
30
+ * two vocabularies stay separate. `succeeded` stays absent because these calls are the ones
31
+ * being judged right now: they have not run, and a call can never be its own precedent.
35
32
  */
36
33
  export function transcriptFromInput(input) {
37
34
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polydeukes/core",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Polydeukes core — covenant protocol, config loader, and transcript interface. Domain- and agent-agnostic. Alpha.",
5
5
  "license": "MIT",
6
6
  "repository": {