# Obsidian Back-Reference (shared SSOT)

Single source of truth for the **idempotent back-reference snippet** that `/prd` writes
into the user's Obsidian spec note. Two phases call this module; both target the SAME
marker block keyed on the slug, so the later write **replaces the earlier one in place** —
the note never accumulates duplicates.

| Phase | Caller | Mode | Trigger |
|---|---|---|---|
| Provisional | `discovery-phase.md` Step 1 point 2 | `PROVISIONAL` | right after the note is detected — the PRD has only just started |
| Final | `validation-phase.md` Step 7.6 | `FINAL` | after the merge succeeds — paths, card IDs, branch, SHA are now final |

**Why two phases (v4.27.0).** A PRD can be paused or abandoned mid-flow (e.g. parked at the
UI-design step, worktree never merged). The FINAL write is gated on a successful merge, so
without a provisional write the note would stay empty for every incomplete PRD — even
though detection already happened at Step 1. The provisional write makes the note reflect
"a PRD was started here" immediately; the FINAL write upgrades it to the full,
queryable payload once the run completes.

## Marker contract

The block is delimited by HTML-comment markers keyed on `<slug>`:

```
<!-- BALDART:prd:<slug> START -->
…block…
<!-- BALDART:prd:<slug> END -->
```

**Write procedure (identical for both modes):**
1. Read the current note content at the absolute `path:` from state `## Obsidian Spec Note`.
2. If both markers are present → REPLACE everything between them (inclusive) with the new block.
3. If markers are absent → APPEND the new block at the end of the note, preceded by one blank line.
4. Write the note back to `path:`.

The note lives in the user's **vault, outside the worktree and outside git** — it is a
plain filesystem write to the absolute `path:`, NEVER staged or committed.

## Skip conditions (each logged, NEVER fatal — both phases)

- `## Obsidian Spec Note / status` is `none` (no note was given) → skip silently.
- `path:` is `none`/empty (vault root never resolved at Step 1) → skip with a one-line note.
- The file at `path:` does not exist or is not writable → skip with a one-line warning.

The back-reference is a convenience index, never a gate. Any failure logs
`"Obsidian back-reference: SKIPPED (<reason>)"` and the run continues.

## Mode: PROVISIONAL — `discovery-phase.md` Step 1 point 2

**Known here:** `<slug>`, the deterministic branch `prd/<slug>` (the name `worktree-manager
nw-docs` always uses), the planned PRD path, `git.trunk_branch`, the detection timestamp.
**Not yet known:** epic/card IDs (Step 5), the merge SHA/PR (Step 7), the full Canonical
Sources list (Step 4). Write the lighter block:

````markdown
<!-- BALDART:prd:<slug> START -->
## 🛠 Sviluppo BALDART — <slug>

```yaml
feature: <slug>
prd: ${paths.prd_dir}/<slug>/PRD.md   # path pianificato — il file viene scritto a Step 4
branch: prd/<slug>
trunk_branch: <git.trunk_branch>
started: <ISO-8601 UTC>
status: drafting   # drafting | planned | done
```

- **Stato:** PRD in stesura sul branch `prd/<slug>`. Lo snippet verrà completato al merge.

_Avviato da `/prd` il <date>. Questo blocco si aggiorna automaticamente con card, merge e sorgenti canoniche quando il PRD viene mergiato._
<!-- BALDART:prd:<slug> END -->
````

After the write, set `## Obsidian Spec Note / status: provisional-written` in the state file.

## Mode: FINAL — `validation-phase.md` Step 7.6

Runs AFTER the merge (Step 7 item 9). All identifiers are final. Write the full block,
REPLACING the provisional one in place:

````markdown
<!-- BALDART:prd:<slug> START -->
## 🛠 Sviluppo BALDART — <slug>

```yaml
feature: <slug>
prd: ${paths.prd_dir}/<slug>/PRD.md
epic: FEAT-XXXX-00-<slug>-epic
cards:
  - FEAT-XXXX-01-<sub-slug>
  - FEAT-XXXX-02-<sub-slug>
resources:        # other Canonical Sources from the PRD (mockups, ADRs, ref docs, research)
  - ${paths.prd_dir}/<slug>/design.html      # omit if no design
  - <ssot-registry entry / ADR path / research link>
branch: prd/<slug>
merge_commit: <SHA from state ## Validation>
pr: <PR number, or n/a for local-push>
trunk_branch: <git.trunk_branch>
date: <ISO-8601 UTC>
status: planned   # drafting | planned | done
```

- **PRD:** `${paths.prd_dir}/<slug>/PRD.md`
- **Cards:** FEAT-XXXX-00 (epic) · FEAT-XXXX-01 · FEAT-XXXX-02 …
- **Merge:** `<SHA>` su `<git.trunk_branch>`<!-- · PR #N -->

_Generato da `/prd` il <date>. Aggiorna `status:` a `done` quando la feature è in produzione._
<!-- BALDART:prd:<slug> END -->
````

Fill the `yaml` from the final state: `<slug>`, the real epic + child card IDs created in
Step 5, the merge SHA written under `## Validation` (Step 7 item 8), the PR number from the
`mw-docs` return (or `n/a`), and the Canonical Sources the PRD already assembled
(`prd-writing-phase.md` Step 4 point 3) for `resources:`. The inner ```yaml``` block is
fenced, NOT real top-of-file frontmatter — it is the queryable payload Claude reads back
when asked about the feature later.

After the write, set `## Obsidian Spec Note / status: back-reference-written` in the state
file. (The state file is already committed; this is a local marker for a possible resume —
do NOT re-commit just for this field.)
