From e9e183ebb0401e1eb6155f6987f55e9e69a11636 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Fri, 26 Jun 2026 21:02:26 +0200 Subject: [PATCH] =?UTF-8?q?feat(linkedin-studio):=20brain=20Stage=201=20fi?= =?UTF-8?q?nish=20=E2=80=94=20title/description=20+=20pending-diff=20typed?= =?UTF-8?q?=20[skip-docs]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Completes the linkedin-studio in-scope Stage 1 (docs/okf-convergence-brief.md): - serializeProfile + operations.md seed gain the cheap recommended OKF fields `title` + `description` (timestamp/resource intentionally omitted — a timestamp would break the pure/deterministic serializer; resource is N/A internally). - renderDiffMd leads the transient pending-diff.md with `type: PendingDiff`, so the brain/ bundle passes okf-check even mid-propose. Verified: 2 new tests (okf-conform + consolidate-cli); full brain suite 134/134 (0 regressions); cross-tool — okr/scripts/okf-check.mjs validates brain/ exit 0 WITH a pending-diff present. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_011vmzxpsFpc8q19LaogAWLD --- scripts/brain/src/cli.ts | 2 +- scripts/brain/src/profile.ts | 2 ++ scripts/brain/src/scaffold.ts | 2 ++ scripts/brain/tests/consolidate-cli.test.ts | 10 ++++++++++ scripts/brain/tests/okf-conform.test.ts | 13 +++++++++++++ 5 files changed, 28 insertions(+), 1 deletion(-) diff --git a/scripts/brain/src/cli.ts b/scripts/brain/src/cli.ts index 2e121dd..f8add96 100644 --- a/scripts/brain/src/cli.ts +++ b/scripts/brain/src/cli.ts @@ -249,7 +249,7 @@ function runReconcile(_flags: Record): void { } function renderDiffMd(diff: ProfileDiff): string { - const lines = ["# Pending profile diff", "", "> Operator-gated. Review, then `brain consolidate --apply --diff brain/pending-diff.json --confirm`.", ""]; + const lines = ["---", "type: PendingDiff", "---", "", "# Pending profile diff", "", "> Operator-gated. Review, then `brain consolidate --apply --diff brain/pending-diff.json --confirm`.", ""]; const section = (title: string, items: string[]) => { lines.push(`## ${title} (${items.length})`, ""); for (const i of items) lines.push(`- ${i}`); diff --git a/scripts/brain/src/profile.ts b/scripts/brain/src/profile.ts index 0d86004..ae6346e 100644 --- a/scripts/brain/src/profile.ts +++ b/scripts/brain/src/profile.ts @@ -46,6 +46,8 @@ export function serializeProfile(doc: ProfileDoc): string { const lines: string[] = [ "---", "type: Profile", + "title: Profile", + "description: Two-layer semantic profile (static and dynamic) - the distilled who-you-are.", "---", "", "# Profile", diff --git a/scripts/brain/src/scaffold.ts b/scripts/brain/src/scaffold.ts index 4a60eb9..1c27b72 100644 --- a/scripts/brain/src/scaffold.ts +++ b/scripts/brain/src/scaffold.ts @@ -54,6 +54,8 @@ okf_version: 0.1 function operationsSeed(): string { return `--- type: Operations +title: Operations +description: Plans, ideas, and the current-direction anchor - the operations centre. --- # Operations diff --git a/scripts/brain/tests/consolidate-cli.test.ts b/scripts/brain/tests/consolidate-cli.test.ts index fdd3abd..d2744f1 100644 --- a/scripts/brain/tests/consolidate-cli.test.ts +++ b/scripts/brain/tests/consolidate-cli.test.ts @@ -59,6 +59,16 @@ describe("brain consolidate CLI (SC5)", () => { assert.equal(diff.additions.length, 1); }); + test("--propose writes pending-diff.md in OKF-compatible form (type: PendingDiff)", () => { + // The pending-diff is a transient operator-review artifact that lives in the + // brain/ bundle, so it must carry a type or okf-check fails the whole bundle + // mid-propose. (docs/okf-convergence-brief.md Stage-1 deferred item.) + runCli(root, ["consolidate", "--propose", "--candidates", candidatesFile(root, [validCand])]); + const block = readFileSync(pendingMd(root), "utf8").match(/^---\n([\s\S]*?)\n---\n/); + assert.ok(block, "pending-diff.md leads with a frontmatter block"); + assert.match(block![1], /^type:\s*PendingDiff\s*$/m, "pending-diff.md is type PendingDiff"); + }); + test("--propose REJECTS a malformed candidate (missing field), no write", () => { const { code } = runCli(root, ["consolidate", "--propose", "--candidates", candidatesFile(root, [{ key: "x", value: "y" }])]); assert.notEqual(code, 0, "non-zero exit on malformed candidate"); diff --git a/scripts/brain/tests/okf-conform.test.ts b/scripts/brain/tests/okf-conform.test.ts index f63eed7..8a68220 100644 --- a/scripts/brain/tests/okf-conform.test.ts +++ b/scripts/brain/tests/okf-conform.test.ts @@ -96,6 +96,19 @@ describe("brain/ bundle is OKF-compatible form (Stage 1)", () => { assert.equal(frontmatterType(text), "Operations"); }); + test("concept files carry the cheap recommended fields (title + description)", () => { + // OKF recommends title/description; they are free (constant) here and give a + // foreign agent a human label without a clock (timestamp/resource stay out — + // a timestamp would break the pure serializer; resource is N/A for an internal + // concept). okf-check still only REQUIRES type; these clear its warnings. + for (const sub of ["brain/profile.md", "brain/operations.md"]) { + const block = readFileSync(join(root, sub), "utf8").match(/^---\n([\s\S]*?)\n---\n/); + assert.ok(block, `${sub} has a frontmatter block`); + assert.match(block![1], /^title:\s*\S/m, `${sub} has a title`); + assert.match(block![1], /^description:\s*\S/m, `${sub} has a description`); + } + }); + test("each directory level under brain/ has its own index.md (progressive disclosure)", () => { assert.ok(existsSync(join(root, "brain/index.md")), "brain/index.md"); assert.ok(existsSync(join(root, "brain/journal/index.md")), "brain/journal/index.md");