feat(okr): onboarding skriver OKF-frontmatter paa org-profil (SC6)
compose-org-profile.mjs prepender top-level OKF-noekler (type: Organisasjonsprofil/resource/timestamp) over den nestede org-profilen i ETT frontmatter-blokk, pipes til write-org-profile.mjs (uendret). Kun de tre trygge noeklene top-level; FORBID nye top-level navn/id/fase/domene/ sektor som ville skygge nestede verdier hooken leser. oppsett.md (begge profil-skriv-sites) + template oppdatert. Test: compose->pip->readback + inject-roundtrip (4), full suite 51->55. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SFW5scLL7oEwWWTv1fPQG6
This commit is contained in:
parent
9701c81158
commit
5219d50d4b
4 changed files with 233 additions and 9 deletions
65
scripts/compose-org-profile.mjs
Normal file
65
scripts/compose-org-profile.mjs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
// compose-org-profile.mjs
|
||||
// Purpose: wrap the NESTED org-profile YAML body (organisasjon:/program: ...,
|
||||
// read from stdin) in an OKF-compatible frontmatter document, prepending the
|
||||
// three top-level OKF keys the second-brain "Documents/kb" layout expects on a
|
||||
// concept file: type / resource / timestamp. Emits the full document to stdout,
|
||||
// meant to be piped into write-org-profile.mjs (which writes it atomically to
|
||||
// the reinstall-surviving home path ~/.claude/okr/org/profil.md).
|
||||
//
|
||||
// Why a dedicated composer (not lib/frontmatter.mjs writeFrontmatter): the org
|
||||
// profile is NESTED (organisasjon: { navn, type }, program: { ... }). The flat
|
||||
// writeFrontmatter would flatten/destroy that structure. We instead keep the
|
||||
// caller's nested YAML verbatim and only PREPEND OKF keys above it.
|
||||
//
|
||||
// Why ONLY type/resource/timestamp top-level: the home profile is read by the
|
||||
// flat parser (lib/frontmatter.mjs) in inject-okr-context.mjs via
|
||||
// get('navn')/get('id')/get('domene')/... A NEW top-level key colliding with
|
||||
// any of those (navn/name/id/fase/domene/sektor) would be matched FIRST and
|
||||
// shadow the nested value, breaking org/cycle resolution (the Critical risk).
|
||||
// type/resource/timestamp are read by NO consumer, so they are safe to prepend.
|
||||
// The nested organisasjon.type ("offentlig") is untouched and still unread.
|
||||
//
|
||||
// Single-block invariant: the OKF keys and the nested body MUST live in ONE
|
||||
// frontmatter block. A stray intermediate '---' would truncate the block the
|
||||
// flat parser reads (dropping organisasjon: -> get('navn') === null -> no
|
||||
// injection), so any fences the caller already put around the body are stripped
|
||||
// before re-wrapping.
|
||||
//
|
||||
// Testable clock seam: OKR_NOW (ISO-8601) overrides the wall clock so the
|
||||
// emitted timestamp is deterministic under test.
|
||||
//
|
||||
// Zero npm dependencies (node: builtins only). ASCII-clean identifiers.
|
||||
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
// OKF resource pointer: where the canonical org profile lives. A bare string
|
||||
// pointer (OKF: "URL/path to the source"); no consumer reads it.
|
||||
const RESOURCE = '~/.claude/okr/org/profil.md';
|
||||
|
||||
let body = '';
|
||||
try {
|
||||
body = readFileSync(0, 'utf8');
|
||||
} catch {
|
||||
body = '';
|
||||
}
|
||||
|
||||
// Strip a leading/trailing frontmatter fence if the caller already wrapped the
|
||||
// body, so the result is exactly one frontmatter block (see single-block note).
|
||||
body = body.replace(/^\s*---\s*\r?\n/, '');
|
||||
body = body.replace(/\r?\n---\s*\r?\n?\s*$/, '\n');
|
||||
body = body.replace(/\s+$/, '');
|
||||
|
||||
const timestamp = process.env.OKR_NOW || new Date().toISOString();
|
||||
|
||||
const lines = [
|
||||
'---',
|
||||
'type: Organisasjonsprofil',
|
||||
`resource: ${RESOURCE}`,
|
||||
`timestamp: '${timestamp}'`,
|
||||
];
|
||||
if (body) lines.push(body);
|
||||
lines.push('---', '');
|
||||
|
||||
process.stdout.write(lines.join('\n'));
|
||||
Loading…
Add table
Add a link
Reference in a new issue