# 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": "<claim>",
      "binding": { "type": "specific", "specificId": "<bank id>" } },
    { "slotId": "kp2", "kind": "key-point", "label": "<claim>",
      "binding": { "type": "abstrakt", "rationale": "<why abstract here>" } },
    { "slotId": "kp3", "kind": "key-point", "label": "<claim>",
      "binding": { "type": "ekstern", "source": "<research ref, optional>" } },
    { "slotId": "kp4", "kind": "key-point", "label": "<claim>",
      "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 `<serie>/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 "<abs>/linkedin/edition-state.json"   # exit 1 = BLOCK
node --import tsx src/cli.ts render-kilder    --edition "<abs>/linkedin/edition-state.json" \
                                              --out     "<abs>/linkedin/NN-kilder.md"
```

`--article <id>` overrides `currentArticle`; `--bank <path>` 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.
