feat(linkedin-studio): specifics-bank store — lived-specifics inventory (fix #2 slice 1)
Fix #2 (kilde-så-draft) slice 1: the deterministic STORE half of the lived-specifics bank — the operator's real, un-generatable raw material (measured number / named-but-real case / what broke / contrarian opinion / mind-change), so drafts start grounded instead of hollow (retning §3; dream-spec "Lived-Specifics Extraction", the single biggest missing upstream piece for the authenticity thesis). scripts/specifics-bank/ (sibling to contract-gate, same tsx convention): - src/types.ts — Specific/Bank schema (schemaVersion 1), un-generatable taxonomy - src/bank.ts — pure store: normalizeContent, content-hash id (= dedupe key), load/save, addSpecific (dedupe + topicTag union on re-capture), queryByTopic (active-only, ranked by tag overlap then recency) - src/cli.ts — query / add / list; default bank under ${LINKEDIN_STUDIO_DATA:-~/.claude/linkedin-studio}/specifics-bank/ so it survives plugin upgrades/reinstalls (M0 data-path seam) - tests/bank.test.ts — 15/15 green; tsc clean - README + .gitignore for node_modules/build Content is stored verbatim; never AI-generated. The elicitation interview (refuses vague answers; abstrakt/ekstern escape hatches) lands in slice 3 (/linkedin:newsletter Step 1.5). Forward-compatible with the profile-evolution / "second brain" architecture. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e26d9fb659
commit
b390b87ad5
9 changed files with 1239 additions and 0 deletions
65
scripts/specifics-bank/README.md
Normal file
65
scripts/specifics-bank/README.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# specifics-bank — the lived-specifics inventory (Fix #2, kilde-så-draft)
|
||||
|
||||
A deterministic, topic-tagged store of the operator's **real, un-generatable raw
|
||||
material** — the specific measured number, the named (anonymized-but-real) case, the
|
||||
thing that actually broke, the unfashionable opinion privately held, the moment they
|
||||
changed their mind. The point (retning §3, dream-spec «Lived-Specifics Extraction»):
|
||||
**sourcing, not styling, is where authenticity is won.** Drafts must draw from real
|
||||
inventory instead of inventing plausible filler, so every downstream voice gate polishes
|
||||
grounded content, not hollow content.
|
||||
|
||||
This is the **store half** (deterministic + tested). The **elicitation half** — a guided
|
||||
interview that refuses vague answers (escape hatches: mark a slot `abstrakt` or `ekstern`)
|
||||
— lives in the command layer (`/linkedin:newsletter` Step 1.5, slice 3). The bank never
|
||||
holds AI-generated lived experience; every `content` is the operator's own words.
|
||||
|
||||
## Where the bank lives
|
||||
|
||||
`${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/specifics-bank/specifics-bank.json`
|
||||
|
||||
It sits in the per-user data dir (M0 data-path convention), **outside** the plugin
|
||||
install, so it **survives plugin upgrades and reinstalls**. It is the first concrete
|
||||
tributary of the broader profile-evolution / "second brain" architecture.
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
cd scripts/specifics-bank && npm install
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
```bash
|
||||
# Surface inventory the operator already has for an edition's topics
|
||||
node --import tsx src/cli.ts query --tags "saksbehandling,produktivitet"
|
||||
|
||||
# Fold newly-elicited material back into the bank
|
||||
node --import tsx src/cli.ts add --type number \
|
||||
--content "Saksbehandleren sparte to dager i uka." \
|
||||
--tags "saksbehandling,produktivitet" --source "seres/05"
|
||||
|
||||
# Inspect the whole bank
|
||||
node --import tsx src/cli.ts list
|
||||
```
|
||||
|
||||
Flags: `--bank <path>` overrides the default location; `--json` emits machine output for
|
||||
`query`/`list`. `add` defaults `--verification` to `unverified` (numbers stay
|
||||
guilty-until-checked — regel 6/7) and `--source` to `manual`.
|
||||
|
||||
`--type` ∈ `number | named-case | what-broke | contrarian | mind-change | other`.
|
||||
|
||||
## Model
|
||||
|
||||
- **Dedupe key** = `sha256(normalizeContent(content)).slice(0,12)` (lowercase + trimmed +
|
||||
whitespace-collapsed). Re-capturing the same material under a new edition's topic does
|
||||
**not** add a second entry — its `topicTags` are unioned in, enriching the record.
|
||||
- **Query** returns active specifics whose tags overlap, ranked by overlap (desc) then
|
||||
recency (`capturedAt` desc); archived material is kept but never offered.
|
||||
- **Content is stored verbatim**; only the id is normalized.
|
||||
|
||||
## Test
|
||||
|
||||
```bash
|
||||
npm test # node:test, deterministic (callers supply capturedAt)
|
||||
npm run build # tsc — must stay clean
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue