Files
learnharness/tests/default-settings.test.ts
T
amosblomqvist 6b13583e96 wave 7: the prober reads its map — graph-context injection dies whole
The owner's zero-configuration ruling (2026-09-23): nothing configures
the graph beyond chat models. The prior-knowledge injection — its budget
dial, its runner, its marker part, its dock/dispatch entries — is
removed across all bands; the prober now reads the learner's persistent
knowledge map on demand through two gated tools instead:

- list_sessions: every birth session, names + kinds + counts + dates
  (graphSessionIndex, Platform's core seam)
- list_propositions(session): what was born there + the session's own
  latest understanding level + that evaluation's date
  (graphSessionPropositions) — names/levels/dating ONLY, no statement
  text (owner ruling: the map's organization is the prober's business,
  its prose is not)

Registered via createProberTools when chat-handler passes graphStore
(the graphToolsEnabled gate decided server-side, per-turn fresh); the
prober doctrine gains the map-review nudge at session start.

Also: runner's JobKind special-casing collapses (KIND_ROLE/KIND_RUNNERS
are plain records again), semantic-clusters.ts dies with its test, the
embedder dep's doc tells the wave-7 stub story, and ports.ts's
readClusterLabels/readNamingRuns surface stays untouched for Platform's
ledger-port interlude.

848/848 tests, typecheck/lint/build green.
2026-09-23 15:24:48 +03:00

55 lines
1.9 KiB
TypeScript

/**
* Tests for the shared settings-body parser, chat-section flavor
* (default-settings wave, 2026-09-18; record-backed 2026-09-19): the seam
* behind BOTH chat-settings routes — per-chat and the defaults alias.
*
* The record store, the legacy-file migration, and the record-backed
* default-settings facade are covered in tests/settings-store.test.ts
* (one fs owner per file — the test runner executes files in parallel).
*/
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { parseSettingsBody } from "../src/server/settings-body.ts";
describe("parseSettingsBody (shared by both settings routes)", () => {
it("an empty object parses to {} — the clear-overrides write", () => {
const r = parseSettingsBody({});
assert.ok(r.ok);
assert.deepEqual(r.ok ? r.settings : null, {});
});
it("a full valid body parses field-for-field", () => {
const r = parseSettingsBody({
model: { provider: "openrouter", id: "z-ai/glm-5.3-flash" },
thinkingLevel: "high",
});
assert.ok(r.ok);
assert.deepEqual(r.settings, {
model: { provider: "openrouter", id: "z-ai/glm-5.3-flash" },
thinkingLevel: "high",
});
});
it("partial bodies keep only the present overrides (replace-whole)", () => {
const r = parseSettingsBody({ thinkingLevel: "low" });
assert.ok(r.ok);
assert.deepEqual(r.settings, { thinkingLevel: "low" });
});
it("rejects non-object bodies", () => {
for (const body of ["junk", 42, [{}]]) {
const r = parseSettingsBody(body);
assert.equal(r.ok, false, JSON.stringify(body));
if (!r.ok) assert.match(r.error, /Invalid JSON body/);
}
});
it("rejects malformed model and non-string thinkingLevel", () => {
assert.equal(parseSettingsBody({ model: "nope" }).ok, false);
assert.equal(parseSettingsBody({ model: { provider: 1, id: "x" } }).ok, false);
assert.equal(parseSettingsBody({ thinkingLevel: 7 }).ok, false);
});
});