@corenel/harness 0.5.0 → 0.5.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.
@@ -12,6 +12,27 @@ export interface BackendConfig {
12
12
  /** Injected so a test needs no network; defaults to the ambient fetch. */
13
13
  fetch?: typeof fetch;
14
14
  }
15
+ /**
16
+ * What the probe found -- INCLUDING whether it got an answer at all.
17
+ *
18
+ * An empty capability list has two completely different meanings, and reading
19
+ * them as one is what hid a probe asking the wrong path for as long as the
20
+ * feature existed: a backend that ANSWERS without `sessions` is a normal thing
21
+ * to be pointed at (prompd's gateway only runs models), while a 404, a timeout
22
+ * or an HTML error page means the question was never answered. The first is
23
+ * settled; the second is a URL to check. `url` is carried so whoever reports it
24
+ * can name what was asked.
25
+ */
26
+ export interface ProbeOutcome {
27
+ /** The URL the probe asked. */
28
+ url: string;
29
+ /** True only when the backend replied with JSON we could read. */
30
+ answered: boolean;
31
+ /** What it said it can do. Empty and `answered` is a real "no". */
32
+ capabilities: readonly string[];
33
+ /** Why it did not answer. Absent when it did. */
34
+ reason?: string;
35
+ }
15
36
  export interface Backend {
16
37
  readonly baseUrl: string;
17
38
  readonly client: CorenelApiClient;
@@ -21,6 +42,9 @@ export interface Backend {
21
42
  supports(capability: string): boolean;
22
43
  /** Ask the backend what it is. Safe to call more than once. */
23
44
  probe(): Promise<readonly string[]>;
45
+ /** The same question, with whether it was answered at all. Prefer this
46
+ * anywhere the result is REPORTED to a person. */
47
+ probeDetail(): Promise<ProbeOutcome>;
24
48
  }
25
49
  /**
26
50
  * Point at a backend, or at none.
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACrC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;4CACwC;IACxC,YAAY,IAAI,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACtC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CACrC;AAuDD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAG1E;AAED,sEAAsE;AACtE,wBAAgB,OAAO,IAAI,OAAO,GAAG,IAAI,CAExC;AAED;;6BAE6B;AAC7B,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3D"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,eAAO,MAAM,YAAY,aAAa,CAAC;AACvC,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,aAAa,cAAc,CAAC;AAEzC,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;IACrC,0EAA0E;IAC1E,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,kEAAkE;IAClE,QAAQ,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC;4CACwC;IACxC,YAAY,IAAI,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACtC,+DAA+D;IAC/D,KAAK,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;IACpC;sDACkD;IAClD,WAAW,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;CACtC;AA+ED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAG1E;AAED,sEAAsE;AACtE,wBAAgB,OAAO,IAAI,OAAO,GAAG,IAAI,CAExC;AAED;;6BAE6B;AAC7B,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE3D"}
@@ -75,32 +75,56 @@ class RemoteBackend {
75
75
  return this.caps.includes(capability);
76
76
  }
77
77
  probe() {
78
+ return this.probeDetail().then((r) => r.capabilities);
79
+ }
80
+ probeDetail() {
78
81
  if (this.probed)
79
82
  return this.probed;
83
+ const url = `${this.baseUrl}/meta`;
80
84
  this.probed = (async () => {
81
85
  try {
82
86
  // Unauthenticated on purpose: "what are you" must be answerable before a
83
87
  // credential is sorted out, or a signed-out machine could never discover
84
88
  // that signing in would be worth it.
85
- const res = await this.fetchImpl(`${this.baseUrl}/meta`);
89
+ const res = await this.fetchImpl(url);
90
+ // A 404 here is the classic wrong-path failure, and an API's 404 is an
91
+ // HTML page -- so it is a question nobody answered, not a capability
92
+ // list of zero.
86
93
  if (!res.ok)
87
- return [];
88
- const body = await res.json();
94
+ return { url, answered: false, capabilities: [], reason: `HTTP ${res.status}` };
95
+ let body;
96
+ try {
97
+ body = await res.json();
98
+ }
99
+ catch {
100
+ // 200 with an HTML page is what a proxy or a CDN returns. Reading that
101
+ // as "holds no sessions" is the reassuring-direction failure.
102
+ return { url, answered: false, capabilities: [], reason: 'the reply was not JSON' };
103
+ }
89
104
  this.caps = Array.isArray(body.capabilities)
90
105
  ? body.capabilities.filter((c) => typeof c === 'string')
91
106
  : [];
92
- return this.caps;
107
+ return { url, answered: true, capabilities: this.caps };
93
108
  }
94
- catch {
95
- // Unreachable, not JSON, or not a corenel backend at all. All of them
96
- // mean the same thing: do not use it for anything.
109
+ catch (err) {
110
+ // Unreachable, aborted, DNS, TLS. None of them is an answer.
97
111
  this.caps = [];
98
- return this.caps;
112
+ return { url, answered: false, capabilities: [], reason: reasonOf(err) };
99
113
  }
100
114
  })();
101
115
  return this.probed;
102
116
  }
103
117
  }
118
+ /** A one-line cause for a probe that never landed. Deliberately terse: it goes
119
+ * into a startup banner next to the URL, where the URL is the actionable half. */
120
+ function reasonOf(err) {
121
+ if (err instanceof Error) {
122
+ if (err.name === 'AbortError' || err.name === 'TimeoutError')
123
+ return 'no reply (timed out)';
124
+ return err.message || 'unreachable';
125
+ }
126
+ return 'unreachable';
127
+ }
104
128
  let current = null;
105
129
  /**
106
130
  * Point at a backend, or at none.
@@ -1 +1 @@
1
- {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,gBAAgB,EAAqB,MAAM,UAAU,CAAC;AAE/D;;eAEe;AACf,MAAM,CAAC,MAAM,YAAY,GAAG,UAAU,CAAC;AACvC,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,CAAC,MAAM,aAAa,GAAG,WAAW,CAAC;AAqBzC,MAAM,aAAa;IAOjB,YAAY,GAAkB;QANrB;;;;;WAAgB;QAChB;;;;;WAAyB;QAC1B;;;;mBAA0B,EAAE;WAAC;QAC7B;;;;mBAA4C,IAAI;WAAC;QACxC;;;;;WAAwB;QAGvC,IAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/C,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAiB;YAC9B,KAAK,EAAE,IAAI,CAAC,SAAS;YACrB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,QAAQ,EAAE,GAAG,CAAC,QAAQ;SACvB,CAAC;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,QAAQ,CAAC,UAAkB;QACzB,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QACpC,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE;YACxB,IAAI,CAAC;gBACH,yEAAyE;gBACzE,yEAAyE;gBACzE,qCAAqC;gBACrC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,OAAO,CAAC,CAAC;gBACzD,IAAI,CAAC,GAAG,CAAC,EAAE;oBAAE,OAAO,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAgC,CAAC;gBAC5D,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC;oBAC1C,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;oBACrE,CAAC,CAAC,EAAE,CAAC;gBACP,OAAO,IAAI,CAAC,IAAI,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,sEAAsE;gBACtE,mDAAmD;gBACnD,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;gBACf,OAAO,IAAI,CAAC,IAAI,CAAC;YACnB,CAAC;QACH,CAAC,CAAC,EAAE,CAAC;QACL,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;CACF;AAED,IAAI,OAAO,GAAmB,IAAI,CAAC;AAEnC;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAyB;IACxD,OAAO,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,OAAO;IACrB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;6BAE6B;AAC7B,MAAM,UAAU,eAAe,CAAC,UAAkB;IAChD,OAAO,OAAO,EAAE,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC;AAChD,CAAC"}
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../api/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /** The findings file, beside SESSION.jsonl in the room's own directory. */
2
+ export declare const FINDINGS_FILE = "FINDINGS.jsonl";
3
+ export declare const FINDING_KIND: "finding";
4
+ /** Per-finding length cap, in characters. The same number as `MAX_ROOM_BRIEF`
5
+ * on purpose: a finding is a decision stated once, at about the length a room's
6
+ * whole purpose takes to state. */
7
+ export declare const MAX_FINDING_TEXT = 500;
8
+ /** How many ACTIVE findings a room may hold at once.
9
+ *
10
+ * This is a per-turn cost multiplier, not a storage limit: the document is
11
+ * rendered into every participant's system prompt on every turn, so its size is
12
+ * paid once per turn per participant for the rest of the room. 16 x 500 chars
13
+ * is ~8K characters, roughly 2K tokens -- the same order as the transcript
14
+ * overhead a room already carries, and comfortably under what would start
15
+ * crowding out the conversation itself. It is also about the point past which a
16
+ * findings list stops being a document a person reads and becomes a log they
17
+ * skim: a room with seventeen live decisions has not converged.
18
+ *
19
+ * At the cap, recording is REFUSED (out loud, naming the cap) rather than
20
+ * silently dropping the oldest: a room that quietly loses its first decision to
21
+ * make room for its seventeenth is worse than one told to tidy up. Revising and
22
+ * withdrawing still work at the cap, so the room can always make space. */
23
+ export declare const MAX_ROOM_FINDINGS = 16;
24
+ export type FindingLine = {
25
+ k: typeof FINDING_KIND;
26
+ op: 'record';
27
+ id: string;
28
+ at: number;
29
+ by: string;
30
+ text: string;
31
+ } | {
32
+ k: typeof FINDING_KIND;
33
+ op: 'revise';
34
+ id: string;
35
+ at: number;
36
+ by: string;
37
+ text: string;
38
+ } | {
39
+ k: typeof FINDING_KIND;
40
+ op: 'withdraw';
41
+ id: string;
42
+ at: number;
43
+ by: string;
44
+ reason: string;
45
+ };
46
+ export interface Finding {
47
+ id: string;
48
+ text: string;
49
+ /** The participant id that first recorded it. */
50
+ by: string;
51
+ at: number;
52
+ /** Who last revised it, and when. Null for a finding nobody has corrected. */
53
+ revisedBy: string | null;
54
+ revisedAt: number | null;
55
+ /** Set once the room retired this finding. Kept rather than deleted: the
56
+ * document should be able to say what the room stopped believing. */
57
+ withdrawn: {
58
+ by: string;
59
+ at: number;
60
+ reason: string;
61
+ } | null;
62
+ }
63
+ /** One edit a participant (agent or human) asks for. Deliberately id-based for
64
+ * `revise`/`withdraw`: a positional edit would mean something different by the
65
+ * time it was applied. */
66
+ export type FindingEdit = {
67
+ kind: 'record';
68
+ text: string;
69
+ } | {
70
+ kind: 'revise';
71
+ id: string;
72
+ text: string;
73
+ } | {
74
+ kind: 'withdraw';
75
+ id: string;
76
+ reason: string;
77
+ };
78
+ export declare function encodeFindingLine(line: FindingLine): string;
79
+ /** Apply one line to a folded document. Exported because the engine applies a
80
+ * turn's edits one at a time and must plan each against the document as the
81
+ * PREVIOUS edit left it -- otherwise two records in one turn mint the same id. */
82
+ export declare function applyFindingLine(doc: readonly Finding[], line: FindingLine): Finding[];
83
+ /** Fold a FINDINGS.jsonl text into the document. Degrades, never throws: one
84
+ * malformed line must not take the whole document with it, and a line of any
85
+ * other kind (a file that ever ends up sharing this one) is simply not ours. */
86
+ export declare function foldFindings(text: string): Finding[];
87
+ /** The findings that still stand. What participants are shown, and what the cap
88
+ * counts -- a withdrawn finding costs nothing per turn and should not keep the
89
+ * room from recording a new one. */
90
+ export declare function activeFindings(doc: readonly Finding[]): Finding[];
91
+ /**
92
+ * Turn one requested edit into the line that would record it, or say why not.
93
+ *
94
+ * The ONE place an edit is validated, so the agent's tool, the human's facade
95
+ * call and the engine's apply step cannot drift into three different ideas of
96
+ * what a legal finding is. Pure: it writes nothing and mutates nothing.
97
+ */
98
+ export declare function planFindingEdit(doc: readonly Finding[], edit: FindingEdit, by: string, at: number): {
99
+ ok: true;
100
+ line: FindingLine;
101
+ } | {
102
+ ok: false;
103
+ problem: string;
104
+ };
105
+ /**
106
+ * Plan a WHOLE turn's worth of edits against one document, in order.
107
+ *
108
+ * Sequential and cumulative: each edit is planned against the document as the
109
+ * previous one left it, which is the only way two `record` calls in one turn
110
+ * can mint two different ids -- and the only way an edit that depends on an
111
+ * earlier one in the same turn (withdraw, then record in its place) can be
112
+ * judged against reality. A refused edit is SKIPPED with its reason collected,
113
+ * never fatal: one bad edit must not throw away the good ones beside it.
114
+ *
115
+ * Used by the participant's tool (to answer "what id will this get, and would
116
+ * it even be allowed") and by the engine (to actually write the lines), so the
117
+ * two can never disagree about what a turn's edits mean.
118
+ */
119
+ export declare function planFindingEdits(doc: readonly Finding[], edits: readonly FindingEdit[], by: string, at: number): {
120
+ lines: FindingLine[];
121
+ doc: Finding[];
122
+ problems: string[];
123
+ };
124
+ /**
125
+ * The findings as a participant reads them, ids included so a revision or a
126
+ * withdrawal can name one.
127
+ *
128
+ * Active only. A withdrawn finding is still in the file (and still on screen,
129
+ * marked, for the person in the room) but must never be rendered here: a
130
+ * participant shown a retired decision alongside the live ones has no way to
131
+ * tell them apart and will build on the wrong one.
132
+ */
133
+ export declare function renderFindings(doc: readonly Finding[]): string;
134
+ //# sourceMappingURL=findings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.d.ts","sourceRoot":"","sources":["../../rooms/findings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,262 @@
1
+ /* The room's living findings document.
2
+ *
3
+ * WHAT IT IS. A room's conclusions, recorded AS the room reaches them rather
4
+ * than recalled once at the end. A record written when a thing is agreed is
5
+ * accurate; an end-of-room synthesis is a lossy re-reading of prose, and it
6
+ * fails exactly when the room most needs it (a close that depends on a model
7
+ * call is a close that can fail).
8
+ *
9
+ * WHERE IT LIVES. Beside the transcript, at
10
+ * `<roomsRoot>/<roomId>/FINDINGS.jsonl` -- the same directory as SESSION.jsonl,
11
+ * never in the project tree. A room's conclusions belong to the room, not to
12
+ * whatever workspace happened to be open while it ran.
13
+ *
14
+ * WHY A LOG OF EDITS AND NOT A DOCUMENT BLOB. Two participants recording in the
15
+ * same room must not clobber each other. A whole-document overwrite makes that
16
+ * the default failure: the later writer's text replaces the earlier writer's,
17
+ * silently and completely. So the file is an append-only log of per-finding
18
+ * OPS -- `record`, `revise`, `withdraw` -- each naming ONE finding by id, and
19
+ * the document is the fold of them. Two participants recording concurrently
20
+ * append two independent `record` lines and the document holds both. The worst
21
+ * a genuine collision can do is two revisions of the SAME finding, where the
22
+ * later one wins and the earlier one is still in the log, which is the failure
23
+ * mode of a version history rather than of a lost write.
24
+ *
25
+ * WHY IT CAN SHRINK. A document that can only grow is a log, not a document.
26
+ * `revise` corrects a finding in place (the previous wording stays in the log);
27
+ * `withdraw` retires one with a stated reason, and a withdrawn finding is
28
+ * marked, never erased -- a reader of the file can still see what the room
29
+ * believed and when it stopped believing it. Only ACTIVE findings are rendered
30
+ * to participants, so a withdrawn decision is never re-read as current.
31
+ *
32
+ * WHO WRITES IT. Nothing here writes anything: this module is pure. The room
33
+ * engine is the single writer of a room's files, exactly as it is of
34
+ * SESSION.jsonl (see turn.ts) -- a participant's tool records its INTENT into
35
+ * `ctx.runState` and the engine applies it after the turn.
36
+ */
37
+ /** The findings file, beside SESSION.jsonl in the room's own directory. */
38
+ export const FINDINGS_FILE = 'FINDINGS.jsonl';
39
+ export const FINDING_KIND = 'finding';
40
+ /** Per-finding length cap, in characters. The same number as `MAX_ROOM_BRIEF`
41
+ * on purpose: a finding is a decision stated once, at about the length a room's
42
+ * whole purpose takes to state. */
43
+ export const MAX_FINDING_TEXT = 500;
44
+ /** How many ACTIVE findings a room may hold at once.
45
+ *
46
+ * This is a per-turn cost multiplier, not a storage limit: the document is
47
+ * rendered into every participant's system prompt on every turn, so its size is
48
+ * paid once per turn per participant for the rest of the room. 16 x 500 chars
49
+ * is ~8K characters, roughly 2K tokens -- the same order as the transcript
50
+ * overhead a room already carries, and comfortably under what would start
51
+ * crowding out the conversation itself. It is also about the point past which a
52
+ * findings list stops being a document a person reads and becomes a log they
53
+ * skim: a room with seventeen live decisions has not converged.
54
+ *
55
+ * At the cap, recording is REFUSED (out loud, naming the cap) rather than
56
+ * silently dropping the oldest: a room that quietly loses its first decision to
57
+ * make room for its seventeenth is worse than one told to tidy up. Revising and
58
+ * withdrawing still work at the cap, so the room can always make space. */
59
+ export const MAX_ROOM_FINDINGS = 16;
60
+ export function encodeFindingLine(line) {
61
+ return JSON.stringify(line) + '\n';
62
+ }
63
+ function str(v) { return typeof v === 'string' ? v.trim() : ''; }
64
+ /** Apply one line to a folded document. Exported because the engine applies a
65
+ * turn's edits one at a time and must plan each against the document as the
66
+ * PREVIOUS edit left it -- otherwise two records in one turn mint the same id. */
67
+ export function applyFindingLine(doc, line) {
68
+ if (line.op === 'record') {
69
+ if (doc.some((f) => f.id === line.id))
70
+ return [...doc];
71
+ return [...doc, {
72
+ id: line.id, text: line.text, by: line.by, at: line.at,
73
+ revisedBy: null, revisedAt: null, withdrawn: null,
74
+ }];
75
+ }
76
+ // A revision or a withdrawal of an id nothing recorded describes nothing:
77
+ // dropped, exactly as `foldRoom` drops a line written before its open.
78
+ const found = doc.find((f) => f.id === line.id);
79
+ if (!found)
80
+ return [...doc];
81
+ return doc.map((f) => {
82
+ if (f.id !== line.id)
83
+ return f;
84
+ if (line.op === 'revise')
85
+ return { ...f, text: line.text, revisedBy: line.by, revisedAt: line.at };
86
+ return { ...f, withdrawn: { by: line.by, at: line.at, reason: line.reason } };
87
+ });
88
+ }
89
+ function parseFindingLine(raw) {
90
+ const s = raw.trim();
91
+ if (!s)
92
+ return null;
93
+ let parsed;
94
+ try {
95
+ parsed = JSON.parse(s);
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ if (!parsed || typeof parsed !== 'object')
101
+ return null;
102
+ const o = parsed;
103
+ if (o.k !== FINDING_KIND)
104
+ return null;
105
+ const id = str(o.id);
106
+ const by = str(o.by);
107
+ const at = typeof o.at === 'number' && Number.isFinite(o.at) ? o.at : null;
108
+ if (!id || !by || at === null)
109
+ return null;
110
+ if (o.op === 'record' || o.op === 'revise') {
111
+ const text = str(o.text);
112
+ if (!text)
113
+ return null;
114
+ return { k: FINDING_KIND, op: o.op, id, at, by, text };
115
+ }
116
+ if (o.op === 'withdraw') {
117
+ const reason = str(o.reason);
118
+ if (!reason)
119
+ return null;
120
+ return { k: FINDING_KIND, op: 'withdraw', id, at, by, reason };
121
+ }
122
+ return null;
123
+ }
124
+ /** Fold a FINDINGS.jsonl text into the document. Degrades, never throws: one
125
+ * malformed line must not take the whole document with it, and a line of any
126
+ * other kind (a file that ever ends up sharing this one) is simply not ours. */
127
+ export function foldFindings(text) {
128
+ let doc = [];
129
+ for (const raw of text.split('\n')) {
130
+ const line = parseFindingLine(raw);
131
+ if (line)
132
+ doc = applyFindingLine(doc, line);
133
+ }
134
+ return doc;
135
+ }
136
+ /** The findings that still stand. What participants are shown, and what the cap
137
+ * counts -- a withdrawn finding costs nothing per turn and should not keep the
138
+ * room from recording a new one. */
139
+ export function activeFindings(doc) {
140
+ return doc.filter((f) => f.withdrawn === null);
141
+ }
142
+ /** The next id, never reusing one a withdrawn finding held: an id that comes
143
+ * back meaning something else makes the log unreadable. */
144
+ function nextFindingId(doc) {
145
+ let max = 0;
146
+ for (const f of doc) {
147
+ const n = /^f(\d+)$/.exec(f.id);
148
+ if (n)
149
+ max = Math.max(max, Number(n[1]));
150
+ }
151
+ return `f${max + 1}`;
152
+ }
153
+ function idList(doc) {
154
+ const active = activeFindings(doc).map((f) => f.id);
155
+ return active.length ? active.join(', ') : '(none)';
156
+ }
157
+ /**
158
+ * Turn one requested edit into the line that would record it, or say why not.
159
+ *
160
+ * The ONE place an edit is validated, so the agent's tool, the human's facade
161
+ * call and the engine's apply step cannot drift into three different ideas of
162
+ * what a legal finding is. Pure: it writes nothing and mutates nothing.
163
+ */
164
+ export function planFindingEdit(doc, edit, by, at) {
165
+ const author = str(by);
166
+ if (!author)
167
+ return { ok: false, problem: 'A finding must record who found it.' };
168
+ if (edit.kind === 'record') {
169
+ const text = str(edit.text);
170
+ if (!text)
171
+ return { ok: false, problem: 'A finding cannot be empty -- say what the room decided.' };
172
+ if (text.length > MAX_FINDING_TEXT) {
173
+ return {
174
+ ok: false,
175
+ problem: `That finding is ${text.length} characters; the maximum is ${MAX_FINDING_TEXT}. `
176
+ + 'State the decision, not the discussion that reached it.',
177
+ };
178
+ }
179
+ if (activeFindings(doc).length >= MAX_ROOM_FINDINGS) {
180
+ return {
181
+ ok: false,
182
+ problem: `This room already holds the maximum of ${MAX_ROOM_FINDINGS} findings. `
183
+ + 'Revise one that is now wrong, or withdraw one that no longer holds, and record this in its place.',
184
+ };
185
+ }
186
+ return { ok: true, line: { k: FINDING_KIND, op: 'record', id: nextFindingId(doc), at, by: author, text } };
187
+ }
188
+ const id = str(edit.id);
189
+ const found = doc.find((f) => f.id === id);
190
+ if (!found) {
191
+ return { ok: false, problem: `There is no finding "${id}" in this room. The findings are: ${idList(doc)}.` };
192
+ }
193
+ if (found.withdrawn) {
194
+ return {
195
+ ok: false,
196
+ problem: `Finding ${id} was withdrawn (${found.withdrawn.reason}) and cannot be changed. `
197
+ + 'Record a new finding instead.',
198
+ };
199
+ }
200
+ if (edit.kind === 'revise') {
201
+ const text = str(edit.text);
202
+ if (!text)
203
+ return { ok: false, problem: 'A revision cannot be empty -- withdraw the finding instead.' };
204
+ if (text.length > MAX_FINDING_TEXT) {
205
+ return {
206
+ ok: false,
207
+ problem: `That revision is ${text.length} characters; the maximum is ${MAX_FINDING_TEXT}.`,
208
+ };
209
+ }
210
+ return { ok: true, line: { k: FINDING_KIND, op: 'revise', id, at, by: author, text } };
211
+ }
212
+ const reason = str(edit.reason);
213
+ if (!reason) {
214
+ return { ok: false, problem: 'Withdrawing a finding needs a reason -- a decision that vanishes without one cannot be reviewed later.' };
215
+ }
216
+ return { ok: true, line: { k: FINDING_KIND, op: 'withdraw', id, at, by: author, reason } };
217
+ }
218
+ /**
219
+ * Plan a WHOLE turn's worth of edits against one document, in order.
220
+ *
221
+ * Sequential and cumulative: each edit is planned against the document as the
222
+ * previous one left it, which is the only way two `record` calls in one turn
223
+ * can mint two different ids -- and the only way an edit that depends on an
224
+ * earlier one in the same turn (withdraw, then record in its place) can be
225
+ * judged against reality. A refused edit is SKIPPED with its reason collected,
226
+ * never fatal: one bad edit must not throw away the good ones beside it.
227
+ *
228
+ * Used by the participant's tool (to answer "what id will this get, and would
229
+ * it even be allowed") and by the engine (to actually write the lines), so the
230
+ * two can never disagree about what a turn's edits mean.
231
+ */
232
+ export function planFindingEdits(doc, edits, by, at) {
233
+ let next = [...doc];
234
+ const lines = [];
235
+ const problems = [];
236
+ for (const edit of edits) {
237
+ const planned = planFindingEdit(next, edit, by, at);
238
+ if (!planned.ok) {
239
+ problems.push(planned.problem);
240
+ continue;
241
+ }
242
+ lines.push(planned.line);
243
+ next = applyFindingLine(next, planned.line);
244
+ }
245
+ return { lines, doc: next, problems };
246
+ }
247
+ /**
248
+ * The findings as a participant reads them, ids included so a revision or a
249
+ * withdrawal can name one.
250
+ *
251
+ * Active only. A withdrawn finding is still in the file (and still on screen,
252
+ * marked, for the person in the room) but must never be rendered here: a
253
+ * participant shown a retired decision alongside the live ones has no way to
254
+ * tell them apart and will build on the wrong one.
255
+ */
256
+ export function renderFindings(doc) {
257
+ const active = activeFindings(doc);
258
+ if (!active.length)
259
+ return 'Nothing has been recorded in this room yet.';
260
+ return active.map((f) => `${f.id} (${f.revisedBy ?? f.by}): ${f.text}`).join('\n');
261
+ }
262
+ //# sourceMappingURL=findings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"findings.js","sourceRoot":"","sources":["../../rooms/findings.ts"],"names":[],"mappings":"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"}