@deepwatch/dsh-trajectory 0.1.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.
@@ -0,0 +1,176 @@
1
+ /**
2
+ * Watch records registered into DeepSeek Harness's own event system.
3
+ *
4
+ * This is the seam the plan insists on. Watch does **not** build a second
5
+ * tracker: it registers a `ConversationNodeDefinition` into
6
+ * `ctx.conversationEvents` — the same registry Trajectory itself uses — and a
7
+ * view target into `ctx.conversationViews`. Both read the single session event
8
+ * log DSH already owns.
9
+ *
10
+ * What that buys is not tidiness. It means a Watch record and the Tool record
11
+ * it came from cannot disagree about when something happened, because they are
12
+ * two projections of the same event at the same sequence number. A separate
13
+ * Watch ledger would eventually drift, and the drift would be invisible.
14
+ *
15
+ * The Trajectory *contribution* union is closed in upstream's own package, so
16
+ * Watch rows cannot be injected into the existing Trajectory ledger without an
17
+ * upstream patch. Rather than take one, Watch registers its own view target
18
+ * over the same events — the arrangement upstream already uses for `chat` and
19
+ * `trajectory`, and additive by construction.
20
+ *
21
+ * @module @deepwatch/dsh-trajectory/definition
22
+ */
23
+ import { emptyProjection } from './projection.js';
24
+ import { isWatchTool, recordsFromToolResult, toolResultValue } from './events.js';
25
+ /** The view target Watch publishes. Distinct from `trajectory` and `chat`. */
26
+ export const WATCH_TARGET = 'watchEvidence';
27
+ function str(value) {
28
+ return typeof value === 'string' && value !== '' ? value : null;
29
+ }
30
+ function num(value) {
31
+ return typeof value === 'number' && Number.isFinite(value) ? value : null;
32
+ }
33
+ /**
34
+ * The Watch event Definition.
35
+ *
36
+ * Typed structurally rather than against upstream's exported generics: this
37
+ * package must build outside the DSH monorepo, where those types are reachable
38
+ * only through the packages the browser bundle is allowed to import. The shape
39
+ * is checked against the real contract by the round-trip tests, which run the
40
+ * same extraction over real event shapes.
41
+ */
42
+ export function watchTrajectoryDefinition(sessionId) {
43
+ return {
44
+ kind: 'watch-evidence',
45
+ target: WATCH_TARGET,
46
+ /**
47
+ * Claim the Watch tool calls and their results.
48
+ *
49
+ * Keyed by call id, so a call and its result assemble into one context the
50
+ * way every other business definition in DSH does.
51
+ */
52
+ match(event) {
53
+ if (event.type === 'tool/call') {
54
+ const callId = str(event.data['callId']);
55
+ return callId !== null && isWatchTool(event.data['name'])
56
+ ? { id: callId, role: 'start' }
57
+ : null;
58
+ }
59
+ if (event.type === 'tool/result') {
60
+ const message = event.data['message'];
61
+ const source = message?.['source'];
62
+ const callId = str(source?.['callId']);
63
+ return callId === null ? null : { id: callId, role: 'update' };
64
+ }
65
+ return null;
66
+ },
67
+ start(_context, match) {
68
+ const event = match.event;
69
+ const args = event.data['arguments'];
70
+ return {
71
+ callId: str(event.data['callId']) ?? '',
72
+ toolName: str(event.data['name']) ?? '',
73
+ turn: num(event.data['turn']),
74
+ step: num(event.data['step']),
75
+ correlationId: str(args?.['correlationId']),
76
+ records: [],
77
+ };
78
+ },
79
+ update(context, match) {
80
+ if (match.event.type !== 'tool/result')
81
+ return context.state;
82
+ const records = recordsFromToolResult(match.event, {
83
+ sessionId,
84
+ turn: context.state.turn,
85
+ step: context.state.step,
86
+ callId: context.state.callId,
87
+ toolName: context.state.toolName,
88
+ correlationId: context.state.correlationId,
89
+ }, toolResultValue(match.event));
90
+ return records.length === 0 ? context.state : { ...context.state, records };
91
+ },
92
+ /**
93
+ * Publish this context's records, or nothing.
94
+ *
95
+ * A Watch tool that produced no record — a refusal, an unreadable result —
96
+ * contributes no row at all. DSH's own Tool record already shows that the
97
+ * call happened and how it ended; adding an empty Watch row beside it
98
+ * would put a claim in the ledger that nothing backs.
99
+ */
100
+ buildViewNode(context) {
101
+ const state = context.state;
102
+ if (state === undefined || state.records.length === 0)
103
+ return null;
104
+ return {
105
+ key: context.key,
106
+ kind: context.kind,
107
+ id: context.id,
108
+ target: WATCH_TARGET,
109
+ anchorSeq: context.start?.event.seq ?? state.records[0]?.seq ?? 0,
110
+ data: { records: state.records },
111
+ };
112
+ },
113
+ };
114
+ }
115
+ /**
116
+ * The Watch view target's incremental builder.
117
+ *
118
+ * Rebuilds the whole projection on change rather than patching it. The record
119
+ * set for one session is small — tens of rows, not thousands — and a full fold
120
+ * is the same code path replay uses, so the live view and a reopened one
121
+ * cannot diverge. Patching would be faster and would introduce exactly the
122
+ * class of bug this whole design exists to rule out.
123
+ */
124
+ class WatchViewBuilder {
125
+ sessionId;
126
+ empty;
127
+ nodes = new Map();
128
+ constructor(sessionId) {
129
+ this.sessionId = sessionId;
130
+ this.empty = emptyProjection(sessionId);
131
+ }
132
+ replace(input) {
133
+ this.nodes = new Map(input.nodes.map(node => [node.key, node]));
134
+ return this.build();
135
+ }
136
+ patch(input) {
137
+ for (const node of input.nodes)
138
+ this.nodes.set(node.key, node);
139
+ return this.build();
140
+ }
141
+ build() {
142
+ const records = [...this.nodes.values()]
143
+ .flatMap(node => node.data.records)
144
+ .sort((a, b) => {
145
+ const bySeq = a.seq - b.seq;
146
+ return bySeq !== 0 ? bySeq : a.recordId.localeCompare(b.recordId);
147
+ });
148
+ const byEvidence = new Map();
149
+ const byRecord = new Map();
150
+ for (const record of records) {
151
+ byRecord.set(record.recordId, record);
152
+ for (const evidenceId of record.refs.evidenceIds) {
153
+ if (!byEvidence.has(evidenceId))
154
+ byEvidence.set(evidenceId, record);
155
+ }
156
+ }
157
+ return { sessionId: this.sessionId, records, byEvidence, byRecord };
158
+ }
159
+ }
160
+ /**
161
+ * Register the Watch definition and view target.
162
+ *
163
+ * Both registrations ride Cordis effects, so unloading the plugin removes them
164
+ * and the workspace returns to stock DSH with no Watch rows and no leftover
165
+ * target — which is the uninstall path the bundle promises.
166
+ */
167
+ export function registerWatchTrajectory(ctx, sessionId) {
168
+ const registries = ctx;
169
+ registries.conversationViews.register({
170
+ target: WATCH_TARGET,
171
+ create: () => new WatchViewBuilder(sessionId),
172
+ });
173
+ registries.conversationEvents.register(watchTrajectoryDefinition(sessionId));
174
+ }
175
+ export { WatchViewBuilder };
176
+ //# sourceMappingURL=definition.js.map
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Watch records, derived from DeepSeek Harness's own session event log.
3
+ *
4
+ * The single most important thing about this module is what it does *not* do:
5
+ * it does not store anything. DSH already records every Watch tool call and
6
+ * result in the session log it owns, and these are a projection over that log.
7
+ * There is one event store, and it is DSH's.
8
+ *
9
+ * That constraint is what keeps the authority boundaries honest. A second
10
+ * Watch-owned ledger for UI tracking would immediately become a place where
11
+ * evidence could be copied, then edited, then disagree with Watch Core — and
12
+ * the disagreement would be invisible, because both would look authoritative.
13
+ *
14
+ * So what a record carries is **stable foreign identifiers plus presentation
15
+ * metadata**, never a mutable evidence payload. An `evidenceId` is a handle
16
+ * that Watch Core resolves; the text of the evidence lives at Watch Core and
17
+ * is fetched when someone opens it.
18
+ *
19
+ * @module @deepwatch/dsh-trajectory/events
20
+ */
21
+ import type { Verdict } from '@deepwatch/dsh-contracts';
22
+ /**
23
+ * The Watch event family.
24
+ *
25
+ * Deliberately small and capability-driven. Each one exists because something
26
+ * in the vertical slice needs to select it, deep-link to it, or replay it.
27
+ */
28
+ export type WatchEventType =
29
+ /** A source was attached to this session. */
30
+ 'source.bound'
31
+ /** Watch looked at something and reported what it saw. */
32
+ | 'observation.created'
33
+ /** Watch Core minted an evidence record. */
34
+ | 'evidence.created'
35
+ /** A verification contract was submitted. */
36
+ | 'verification.requested'
37
+ /** A verdict came back. */
38
+ | 'verification.completed'
39
+ /** A browser action was sent to the page. */
40
+ | 'browser.action.dispatched'
41
+ /** A receipt settled for a browser action. */
42
+ | 'browser.action.receipt'
43
+ /** Memory was selected for a turn. */
44
+ | 'memory.context.injected'
45
+ /** A memory was corrected. */
46
+ | 'memory.record.corrected'
47
+ /** A memory was forgotten. */
48
+ | 'memory.record.forgotten';
49
+ /** Every event type, for exhaustive checks and registration. */
50
+ export declare const WATCH_EVENT_TYPES: readonly WatchEventType[];
51
+ /**
52
+ * Stable references a Watch record carries into Trajectory.
53
+ *
54
+ * All identifiers, no payloads. Every field here is a handle that resolves
55
+ * somewhere with its own authority: DSH owns the session and turn ids, Watch
56
+ * Core owns the source, evidence, verification and receipt ids, and Watch
57
+ * Memory owns the memory id.
58
+ */
59
+ export interface WatchRefs {
60
+ /** DSH session this happened in. */
61
+ readonly sessionId: string;
62
+ /** DSH turn, when the event happened inside one. */
63
+ readonly turn: number | null;
64
+ /** DSH step within the turn. */
65
+ readonly step: number | null;
66
+ /** The tool call this record came from. */
67
+ readonly callId: string | null;
68
+ /** Travels with the Bridge request; the same id appears in Core's logs. */
69
+ readonly correlationId: string | null;
70
+ readonly sourceId: string | null;
71
+ /** Which revision of the source. A source that changed is a different one. */
72
+ readonly sourceRevisionId: string | null;
73
+ readonly evidenceIds: readonly string[];
74
+ readonly verificationId: string | null;
75
+ readonly verdict: Verdict | null;
76
+ readonly receiptId: string | null;
77
+ /** Half-open range on the source's own clock, in milliseconds. */
78
+ readonly temporalRange: {
79
+ readonly startMs: number;
80
+ readonly endMs: number;
81
+ } | null;
82
+ /** Artifact handle, resolved by Watch Core when someone opens it. */
83
+ readonly artifactId: string | null;
84
+ readonly memoryIds: readonly string[];
85
+ }
86
+ /** An empty reference set, so a record never carries `undefined` fields. */
87
+ export declare const NO_REFS: WatchRefs;
88
+ /**
89
+ * One Watch record as Trajectory shows it.
90
+ *
91
+ * `summary` is the only free text, and it is presentation metadata: a short
92
+ * line a person reads in a ledger. It is derived, never authoritative, and
93
+ * nothing resolves anything from it.
94
+ */
95
+ export interface WatchTrajectoryRecord {
96
+ /** Stable within a session; what a deep link points at. */
97
+ readonly recordId: string;
98
+ readonly type: WatchEventType;
99
+ /** DSH log sequence, for ordering against every other Trajectory row. */
100
+ readonly seq: number;
101
+ /** Wall clock, in epoch milliseconds. */
102
+ readonly time: number;
103
+ readonly refs: WatchRefs;
104
+ /** One line for the ledger. Presentation only. */
105
+ readonly summary: string;
106
+ /**
107
+ * Whether this record's detail may be shown without further permission.
108
+ *
109
+ * Memory records about a person can be sensitive, and a ledger is a place
110
+ * people scroll past rather than read carefully. A redacted record still
111
+ * appears — hiding that memory influenced a turn would be worse — but its
112
+ * content is withheld until someone asks for it.
113
+ */
114
+ readonly redacted: boolean;
115
+ }
116
+ /** The minimum of a DSH session event this module reads. */
117
+ export interface SessionEventLike {
118
+ readonly type: string;
119
+ readonly seq: number;
120
+ readonly time: number;
121
+ readonly data: Record<string, unknown>;
122
+ }
123
+ /**
124
+ * Pull the JSON a Watch tool returned out of a `tool/result` event.
125
+ *
126
+ * Returns null on anything unexpected. A result this cannot read produces no
127
+ * Watch record at all, which is correct: an unreadable result is not evidence
128
+ * that something happened, and inventing a row for it would put a claim in the
129
+ * ledger that nothing backs.
130
+ */
131
+ export declare function toolResultValue(event: SessionEventLike): unknown;
132
+ /** Whether a tool name belongs to Watch. */
133
+ export declare function isWatchTool(name: unknown): boolean;
134
+ /** Everything one extraction needs from its surrounding DSH context. */
135
+ export interface ExtractionContext {
136
+ readonly sessionId: string;
137
+ readonly turn: number | null;
138
+ readonly step: number | null;
139
+ readonly callId: string | null;
140
+ readonly toolName: string;
141
+ readonly correlationId: string | null;
142
+ }
143
+ /**
144
+ * Derive Watch records from one Watch tool result.
145
+ *
146
+ * One tool call can produce several records — a query that returns evidence
147
+ * and a verification that returns a verdict are different things to select and
148
+ * to deep-link to, even when they arrived together.
149
+ */
150
+ export declare function recordsFromToolResult(event: SessionEventLike, context: ExtractionContext, value: unknown): readonly WatchTrajectoryRecord[];
151
+ /**
152
+ * Derive a Watch record from a memory event.
153
+ *
154
+ * Memory is *not* an evidence plane, and these records carry no memory text.
155
+ * What they establish is that memory influenced a turn and which record did
156
+ * it, so a person can follow the id to the Memory surface and correct it
157
+ * there. Sensitive records are marked redacted: the row still appears, because
158
+ * hiding that memory influenced a turn would be worse than showing a withheld
159
+ * one.
160
+ */
161
+ export declare function recordFromMemoryEvent(input: {
162
+ readonly kind: 'injected' | 'corrected' | 'forgotten';
163
+ readonly memoryId: string;
164
+ readonly sessionId: string;
165
+ readonly seq: number;
166
+ readonly time: number;
167
+ readonly turn?: number | null;
168
+ /** Why this memory was included. Presentation metadata, never the content. */
169
+ readonly reason?: string;
170
+ readonly sensitive?: boolean;
171
+ }): WatchTrajectoryRecord;
172
+ //# sourceMappingURL=events.d.ts.map
package/lib/events.js ADDED
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Watch records, derived from DeepSeek Harness's own session event log.
3
+ *
4
+ * The single most important thing about this module is what it does *not* do:
5
+ * it does not store anything. DSH already records every Watch tool call and
6
+ * result in the session log it owns, and these are a projection over that log.
7
+ * There is one event store, and it is DSH's.
8
+ *
9
+ * That constraint is what keeps the authority boundaries honest. A second
10
+ * Watch-owned ledger for UI tracking would immediately become a place where
11
+ * evidence could be copied, then edited, then disagree with Watch Core — and
12
+ * the disagreement would be invisible, because both would look authoritative.
13
+ *
14
+ * So what a record carries is **stable foreign identifiers plus presentation
15
+ * metadata**, never a mutable evidence payload. An `evidenceId` is a handle
16
+ * that Watch Core resolves; the text of the evidence lives at Watch Core and
17
+ * is fetched when someone opens it.
18
+ *
19
+ * @module @deepwatch/dsh-trajectory/events
20
+ */
21
+ /** Every event type, for exhaustive checks and registration. */
22
+ export const WATCH_EVENT_TYPES = [
23
+ 'source.bound',
24
+ 'observation.created',
25
+ 'evidence.created',
26
+ 'verification.requested',
27
+ 'verification.completed',
28
+ 'browser.action.dispatched',
29
+ 'browser.action.receipt',
30
+ 'memory.context.injected',
31
+ 'memory.record.corrected',
32
+ 'memory.record.forgotten',
33
+ ];
34
+ /** An empty reference set, so a record never carries `undefined` fields. */
35
+ export const NO_REFS = Object.freeze({
36
+ sessionId: '',
37
+ turn: null,
38
+ step: null,
39
+ callId: null,
40
+ correlationId: null,
41
+ sourceId: null,
42
+ sourceRevisionId: null,
43
+ evidenceIds: [],
44
+ verificationId: null,
45
+ verdict: null,
46
+ receiptId: null,
47
+ temporalRange: null,
48
+ artifactId: null,
49
+ memoryIds: [],
50
+ });
51
+ /** Watch tools whose results carry evidence, verdicts or receipts. */
52
+ const WATCH_TOOL_PREFIX = 'watch_';
53
+ /** Read a string field, or null. */
54
+ function str(value) {
55
+ return typeof value === 'string' && value !== '' ? value : null;
56
+ }
57
+ /** Read a plain object, or null. */
58
+ function obj(value) {
59
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
60
+ return null;
61
+ return value;
62
+ }
63
+ /** Read an array of ids, dropping anything that is not one. */
64
+ function ids(value) {
65
+ return Array.isArray(value)
66
+ ? value.map(str).filter((entry) => entry !== null)
67
+ : [];
68
+ }
69
+ /**
70
+ * Pull the JSON a Watch tool returned out of a `tool/result` event.
71
+ *
72
+ * Returns null on anything unexpected. A result this cannot read produces no
73
+ * Watch record at all, which is correct: an unreadable result is not evidence
74
+ * that something happened, and inventing a row for it would put a claim in the
75
+ * ledger that nothing backs.
76
+ */
77
+ export function toolResultValue(event) {
78
+ const message = obj(obj(event.data['message'])?.['content']);
79
+ const content = Array.isArray(obj(event.data['message'])?.['content'])
80
+ ? obj(event.data['message'])?.['content']
81
+ : null;
82
+ if (content === null)
83
+ return message;
84
+ const first = obj(content[0]);
85
+ const inner = first?.['content'];
86
+ const text = Array.isArray(inner)
87
+ ? inner.map(part => str(obj(part)?.['text'])).filter(Boolean).join('')
88
+ : str(inner);
89
+ if (text === null)
90
+ return null;
91
+ try {
92
+ return JSON.parse(text);
93
+ }
94
+ catch {
95
+ return null;
96
+ }
97
+ }
98
+ /** Whether a tool name belongs to Watch. */
99
+ export function isWatchTool(name) {
100
+ return typeof name === 'string' && name.startsWith(WATCH_TOOL_PREFIX);
101
+ }
102
+ /**
103
+ * Derive Watch records from one Watch tool result.
104
+ *
105
+ * One tool call can produce several records — a query that returns evidence
106
+ * and a verification that returns a verdict are different things to select and
107
+ * to deep-link to, even when they arrived together.
108
+ */
109
+ export function recordsFromToolResult(event, context, value) {
110
+ const payload = obj(value);
111
+ if (payload === null)
112
+ return [];
113
+ // A refusal is not a Watch record. It is a tool that did not do anything,
114
+ // and DSH's own tool row already shows that it failed.
115
+ if (payload['ok'] === false)
116
+ return [];
117
+ const base = {
118
+ seq: event.seq,
119
+ time: event.time,
120
+ redacted: false,
121
+ };
122
+ const refs = {
123
+ ...NO_REFS,
124
+ sessionId: context.sessionId,
125
+ turn: context.turn,
126
+ step: context.step,
127
+ callId: context.callId,
128
+ correlationId: context.correlationId,
129
+ };
130
+ const records = [];
131
+ const evidence = Array.isArray(payload['evidence']) ? payload['evidence'] : [];
132
+ if (evidence.length > 0) {
133
+ const first = obj(evidence[0]);
134
+ const range = obj(first?.['temporalRange']);
135
+ records.push({
136
+ ...base,
137
+ recordId: `${context.callId ?? String(event.seq)}:evidence`,
138
+ type: 'evidence.created',
139
+ summary: `${String(evidence.length)} evidence record(s)`,
140
+ refs: {
141
+ ...refs,
142
+ sourceId: str(first?.['sourceRevisionId']),
143
+ sourceRevisionId: str(first?.['sourceRevisionId']),
144
+ evidenceIds: evidence
145
+ .map(entry => str(obj(entry)?.['evidenceId']))
146
+ .filter((entry) => entry !== null),
147
+ temporalRange: range === null ? null : {
148
+ startMs: Number(range['startMs'] ?? 0),
149
+ endMs: Number(range['endMs'] ?? 0),
150
+ },
151
+ },
152
+ });
153
+ }
154
+ const verdict = str(payload['verdict']);
155
+ if (verdict !== null) {
156
+ records.push({
157
+ ...base,
158
+ recordId: `${context.callId ?? String(event.seq)}:verification`,
159
+ type: 'verification.completed',
160
+ // The verdict itself, verbatim. Never widened, never defaulted.
161
+ summary: verdict,
162
+ refs: {
163
+ ...refs,
164
+ verificationId: str(payload['verificationId']),
165
+ verdict: verdict,
166
+ evidenceIds: ids(payload['evidenceRefs']),
167
+ },
168
+ });
169
+ }
170
+ const receiptVerdict = str(payload['verdict'] ?? payload['status']);
171
+ if (str(payload['idempotencyKey']) !== null && verdict === null) {
172
+ records.push({
173
+ ...base,
174
+ recordId: `${context.callId ?? String(event.seq)}:receipt`,
175
+ type: 'browser.action.receipt',
176
+ summary: receiptVerdict ?? 'receipt',
177
+ refs: {
178
+ ...refs,
179
+ receiptId: str(payload['idempotencyKey']),
180
+ verdict: null,
181
+ },
182
+ });
183
+ }
184
+ const sources = Array.isArray(payload['sources']) ? payload['sources'] : [];
185
+ if (sources.length > 0) {
186
+ records.push({
187
+ ...base,
188
+ recordId: `${context.callId ?? String(event.seq)}:sources`,
189
+ type: 'source.bound',
190
+ summary: `${String(sources.length)} source(s)`,
191
+ refs: { ...refs, sourceId: str(obj(sources[0])?.['sourceId']) },
192
+ });
193
+ }
194
+ // An answer with no evidence is still an observation worth showing: it says
195
+ // Watch looked and found nothing to cite, which is different from Watch not
196
+ // having been asked.
197
+ if (records.length === 0 && str(payload['answer']) !== null) {
198
+ records.push({
199
+ ...base,
200
+ recordId: `${context.callId ?? String(event.seq)}:observation`,
201
+ type: 'observation.created',
202
+ summary: 'observation with no citations',
203
+ refs,
204
+ });
205
+ }
206
+ return records;
207
+ }
208
+ /**
209
+ * Derive a Watch record from a memory event.
210
+ *
211
+ * Memory is *not* an evidence plane, and these records carry no memory text.
212
+ * What they establish is that memory influenced a turn and which record did
213
+ * it, so a person can follow the id to the Memory surface and correct it
214
+ * there. Sensitive records are marked redacted: the row still appears, because
215
+ * hiding that memory influenced a turn would be worse than showing a withheld
216
+ * one.
217
+ */
218
+ export function recordFromMemoryEvent(input) {
219
+ const type = input.kind === 'injected'
220
+ ? 'memory.context.injected'
221
+ : input.kind === 'corrected'
222
+ ? 'memory.record.corrected'
223
+ : 'memory.record.forgotten';
224
+ const redacted = input.sensitive === true;
225
+ return {
226
+ recordId: `mem:${input.memoryId}:${String(input.seq)}`,
227
+ type,
228
+ seq: input.seq,
229
+ time: input.time,
230
+ refs: {
231
+ ...NO_REFS,
232
+ sessionId: input.sessionId,
233
+ turn: input.turn ?? null,
234
+ memoryIds: [input.memoryId],
235
+ },
236
+ summary: redacted
237
+ // Withheld, not omitted. The reason text can quote a preference, and a
238
+ // ledger is somewhere people scroll rather than read carefully.
239
+ ? 'memory used (details withheld)'
240
+ : input.reason ?? type,
241
+ redacted,
242
+ };
243
+ }
244
+ //# sourceMappingURL=events.js.map
package/lib/index.d.ts ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Watch records inside the DeepSeek Harness Trajectory.
3
+ *
4
+ * The authority boundaries this package exists to hold:
5
+ *
6
+ * - **DSH owns the session and its event log.** There is no Watch event store.
7
+ * Every record here is a projection over the events DSH already recorded.
8
+ * - **Watch Core owns evidence and verdicts.** A record carries the ids; the
9
+ * content is resolved from Core when someone opens it.
10
+ * - **Watch Memory stays separate from evidence.** Memory records show that
11
+ * memory influenced a turn and which record did it. They are not evidence
12
+ * and cannot be cited as any.
13
+ *
14
+ * @module @deepwatch/dsh-trajectory
15
+ */
16
+ export * from './events.js';
17
+ export * from './selection.js';
18
+ export * from './projection.js';
19
+ export * from './selection-store.js';
20
+ export * from './definition.js';
21
+ export * from './compare.js';
22
+ //# sourceMappingURL=index.d.ts.map
package/lib/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Watch records inside the DeepSeek Harness Trajectory.
3
+ *
4
+ * The authority boundaries this package exists to hold:
5
+ *
6
+ * - **DSH owns the session and its event log.** There is no Watch event store.
7
+ * Every record here is a projection over the events DSH already recorded.
8
+ * - **Watch Core owns evidence and verdicts.** A record carries the ids; the
9
+ * content is resolved from Core when someone opens it.
10
+ * - **Watch Memory stays separate from evidence.** Memory records show that
11
+ * memory influenced a turn and which record did it. They are not evidence
12
+ * and cannot be cited as any.
13
+ *
14
+ * @module @deepwatch/dsh-trajectory
15
+ */
16
+ export * from './events.js';
17
+ export * from './selection.js';
18
+ export * from './projection.js';
19
+ export * from './selection-store.js';
20
+ export * from './definition.js';
21
+ export * from './compare.js';
22
+ //# sourceMappingURL=index.js.map