Practice sessions (owner, 2026-10-04): the marker rides the record and
the normalized summary (absent field reads as teach — pre-practice
records never migrate); POST /api/chats accepts {kind: 'practice'}.
The agent branch, tools, and UI land in the following slices.
47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
/**
|
|
* SESSION-KIND PINS (practice sessions, owner 2026-10-04): ChatRecord.kind
|
|
* is ABSENT-BY-DEFAULT — absence reads as teach, so pre-practice records
|
|
* never migrate; "practice" marks an adaptive-practice session (the
|
|
* practice agent + its two tools from turn 1, no extraction, no graph
|
|
* writes). The store normalizes at the summary projection; createChat
|
|
* stamps the marker only for practice. Runs under an isolated LH_DATA_DIR
|
|
* (the chat-birth-stamp discipline: the seam is set before any
|
|
* config-loading import, so every app-module import is dynamic).
|
|
*/
|
|
|
|
import assert from "node:assert/strict";
|
|
import fs from "node:fs";
|
|
import * as os from "node:os";
|
|
import * as path from "node:path";
|
|
import { after, describe, it } from "node:test";
|
|
|
|
// ── the seam, BEFORE any config-loading import ──────────────────────────────
|
|
const TMP_DATA = fs.mkdtempSync(path.join(os.tmpdir(), "lh-chat-kind-"));
|
|
process.env.LH_DATA_DIR = TMP_DATA;
|
|
|
|
const { chatStore } = await import("../src/store/chats.ts");
|
|
|
|
after(() => {
|
|
fs.rmSync(TMP_DATA, { recursive: true, force: true });
|
|
});
|
|
|
|
describe("session kind (practice sessions, 2026-10-04)", () => {
|
|
it("createChat default carries NO kind field — absence reads as teach", () => {
|
|
const chat = chatStore.createChat("plain session");
|
|
assert.equal("kind" in chat, false, "teach records carry no kind marker");
|
|
});
|
|
|
|
it("createChat(kind: 'practice') stamps the marker on record + list", () => {
|
|
const chat = chatStore.createChat("practice session", "practice");
|
|
assert.equal(chat.kind, "practice");
|
|
const listed = chatStore.listChats().find((c) => c.id === chat.id);
|
|
assert.equal(listed?.kind, "practice");
|
|
});
|
|
|
|
it("the summary projection NORMALIZES: absent record field reads as teach", () => {
|
|
const chat = chatStore.createChat("another plain one");
|
|
const listed = chatStore.listChats().find((c) => c.id === chat.id);
|
|
assert.equal(listed?.kind, "teach");
|
|
});
|
|
});
|