# Fix #2 slice 2 — per-edition lived-specifics binding > **Kilde-så-draft.** Slice 1 built the global *store* (`scripts/specifics-bank`). > Slice 2 builds the per-EDITION *binding*: the bridge that ties one edition's > load-bearing claims to real material before any prose exists. Slice 3 wires it > into `/linkedin:newsletter` (Step 1.5 + the skeleton-gate); slice 4 touches the > maskinrommet contract. This doc is the design record slice 3 implements against. ## Why (retning §3, drømme-spec «Lived-Specifics Extraction» `[CORE]`) Sourcing, not styling, is where authenticity is won. A draft that starts from the operator's real number / named case / what-actually-broke is forwardable; a draft that invents plausible filler is hollow, and every downstream voice gate then polishes hollow content. So **before prose**, each load-bearing claim of an edition must be bound to real inventory — or the operator must *consciously* decide it does not need a concrete instance. The binding is that ledger; vagueness is rejected. ## The slot-map (`articles.NN.livedSpecifics` in `edition-state.json`) A per-article field, resolved at Step 1.5 (between brief and research). Each slot is one load-bearing key-point (`kind: "key-point"`) or, after the skeleton exists, a section (`kind: "section"` — the same shape serves both, no migration): ```jsonc "livedSpecifics": { "slots": [ { "slotId": "kp1", "kind": "key-point", "label": "", "binding": { "type": "specific", "specificId": "" } }, { "slotId": "kp2", "kind": "key-point", "label": "", "binding": { "type": "abstrakt", "rationale": "" } }, { "slotId": "kp3", "kind": "key-point", "label": "", "binding": { "type": "ekstern", "source": "" } }, { "slotId": "kp4", "kind": "key-point", "label": "", "binding": { "type": "unresolved" } } ], "status": "pending" // pending → bound (set by the command when the gate passes) } ``` ### The gate — `validateBinding(livedSpecifics, bank)` (drømme-spec G4, «vaghet avvises») Deterministic, pure (`scripts/specifics-bank/src/binding.ts`). **BLOCK** iff any slot: | reason | when | |--------|------| | `unresolved` | binding type is `unresolved` — the vagueness the gate exists to reject | | `dangling-specific` | a `specific` binding points at a `specificId` absent from the bank | | `unjustified-abstrakt` | an `abstrakt` escape with a blank rationale (= vagueness wearing an escape hatch) | Otherwise **PASS**. Escape hatches are legitimate: `abstrakt` (with a rationale) and `ekstern` (research-backed, not lived; `source` optional — Step 2 fills it). **WARN (does not block)** — regel 6/7: a slot backed by an **unverified `number`** specific surfaces as `unverified-number`. Numbers stay guilty-until-checked; Step 2 research must verify them before the draft asserts them as fact. `coverage` counts by binding TYPE (`total / specific / abstrakt / ekstern / unresolved`); a dangling specific still counts under `specific` (the binding type is `specific`, the *problem* is separately reported). Empty slot-map → PASS, total 0 — whether an edition *needs* ≥1 slot is the command layer's call (slice 3). ## The `NN-kilder.md` artifact Read-only, deterministically **rendered** from `livedSpecifics` + the bank (`scripts/specifics-bank/src/kilder.ts`, `renderKilder`) — regenerated like POST.html, never hand-edited. Lives at `/linkedin/NN-kilder.md`. Per load-bearing slot: binding type, the material (KTG's words, verbatim), provenance + capture date, topic tags, and the number-verification marker (`✓` / `⚠`); then a coverage block + a «Tall som må verifiseres (regel 6/7)» line. The coverage block and the number list are computed by `validateBinding`, so the artifact and the skeleton-gate can never disagree. (Golden-tested; pure + dateless on purpose.) ## CLI surface (the seam slice 3 calls) Run from the package dir (`tsx` lives there); pass absolute paths: ```bash cd "${CLAUDE_PLUGIN_ROOT}/scripts/specifics-bank" node --import tsx src/cli.ts validate-binding --edition "/linkedin/edition-state.json" # exit 1 = BLOCK node --import tsx src/cli.ts render-kilder --edition "/linkedin/edition-state.json" \ --out "/linkedin/NN-kilder.md" ``` `--article ` overrides `currentArticle`; `--bank ` overrides the default data-dir bank; `--json` emits machine output for `validate-binding`. A missing `livedSpecifics` field is treated as an empty slot-map (back-compat with older editions / the template default). ## Step 2 (research) re-scope spec — for slice 3 to wire Today Step 2 decomposes the edition's key points into scoped research sub-questions and triangulates verified notes. Once Step 1.5 + the slot-map exist, Step 2 is **scoped by the binding** rather than by the raw key-points: 1. **Fill the gaps, don't re-research the grounded.** Research targets slots bound `ekstern` (and any still `unresolved` at entry) — the claims that explicitly need an external source. Slots bound to a `specific` are already grounded in lived material and do **not** need their substance re-sourced (research may still corroborate, but it is not the gap). 2. **Verify KTG's own numbers (regel 6/7).** Every `unverified-number` warning from `validateBinding` is a research target: confirm the operator's own figure against a primary source where possible, then flip the bank specific `unverified → verified` (`cli.ts add`/a verify path). A number that cannot be verified stays `unverified` and is carried to the Step 5 fact-check sweep as 🟡 — never silently asserted. 3. **Re-render after research.** When research resolves an `ekstern` source or a number flips to verified, regenerate `NN-kilder.md` so the ledger stays current. Boundary: slice 2 ships the data model, the gate, the artifact renderer, and the CLI. Slice 3 adds Step 1.5 (the elicitation interview + `add` to the bank + populating the slot-map), wires `validate-binding` into the Step 2.5 skeleton-gate, applies this Step 2 re-scope, and bumps the pipeline 17 → 18 phases. ## Tests & verification `cd scripts/specifics-bank && npm test` (binding + kilder suites) and `npm run build` (tsc) stay clean. The gate's three BLOCK reasons + the number WARN + the golden `NN-kilder.md` render are all covered.