# Continue Here — Milestone v1.0 (Knowledge Graph & LLM Auto-Tagging)

**Paused:** 2026-06-24
**Milestone:** v1.0 — phases 8–12. **14/14 requirements implemented**; phases 8–11 complete & verified; **phase 12 executed + automated-verified, ONE live item open** (see Blockers).

## Current Position

- Phase 8 (LINK store) — ✅ complete, live-verified (LINK-01/03).
- Phase 9 (graph endpoints + backlinks) — ✅ complete, live-verified; orphan-node gap found+fixed live (LINK-02).
- Phase 10 (graph UI) — ✅ complete; automated 5/5 + 353 tests; built & reachable at `/app/graph`; canvas-pixel UAT deferred to a human browser (GRAPH-01..05).
- Phase 11 (per-page LLM tagging) — ✅ complete, **live-verified end-to-end** (real DeepSeek suggest→approve→byte-stable apply→commit landed on `deploy.md`); a real-model reply-parse gap was found+fixed live (commit a15a0dc). TAG-01..04.
- Phase 12 (bulk sweep + review queue) — **executed (3 plans), automated-verified 12/12** (safety gate: no auto-write across kill/restart; batched-commit gate: N→1 commit; stale-resilience; admin gating; TagSuggestList reuse). Live-proven: sweep-start (`202 queued:126`) + real-LLM staging (a suggestion staged). TAG-05/06 marked complete in REQUIREMENTS.md.
  - Phase 12 is NOT yet `phase.complete`'d; `12-VERIFICATION.md` status = `human_needed` (the one open live item below).

## Remaining Work

1. **Resolve the open live item** (Blockers below) — confirm or fix the bulk-approve→commit landing.
2. `gsd-tools query phase.complete 12` + commit tracking (only after the item is resolved or accepted).
3. **Milestone lifecycle:** `/gsd-audit-milestone` → `/gsd-complete-milestone v1.0` → `/gsd-cleanup` (the autonomous workflow's final step).
4. Optional deferred polish: lazy-load `GraphCanvas` so the react-force-graph-2d runtime leaves the initial bundle (three.js already absent) — Phase 10 follow-up, non-blocking.

## Blockers / Open Items

### OPEN (must resolve before closing phase 12): bulk batched-approve commit not confirmed landing live
- **Symptom:** `POST /api/v1/admin/tags/approve` returns `200` with `status:"applied"` and RESOLVES the `tag_suggestions` row, BUT in live runs the tag was NOT written to the page file (`phase-6-live-preview-check.md` still `tags: []`) and `data/repo` commit count did not increment.
- **Why it's ambiguous:** the apply enqueues an ASYNC single-writer commit job; every live attempt killed the server (timeout/kill) before that job drained. The automated `TestApproveBatchedOneCommit` / `TestApplyTagsBatchOneCommit` PASS (they drain the worker → commit delta == 1), so the happy path works under drain.
- **Real concern to investigate:** does `internal/pages/ApplyTagsBatch` (12-02) / the approve handler RESOLVE the suggestion row BEFORE the async commit durably lands? If so, a crash between resolve and commit-drain = a "resolved but never written" tag (data loss). Check whether resolve should happen AFTER the commit job confirms, or whether approve should wait for the commit (EnqueueAndWait) for the batch.
- **How to settle it (resume):** start the server and let it run; trigger a sweep OR use a persisted pending row; approve; then **WAIT for the async commit to drain in the SAME server run** before checking (busy-poll `git -C data/repo rev-list --count HEAD` for +1) — do NOT kill the server right after the 200. If the commit lands → close as test-timing artifact; if not → real durability bug, fix in `internal/pages/batch.go` + approve handler.

### Live-validation harness landmines (severity: blocking for live UAT) — see [[app-validation-recipe]]
- The Bash tool kills with **exit 144 (SIGSTKFLT)** on: foreground `sleep`, `curl --retry-delay`/`--retry`, `pkill`, and (sometimes) tight/large busy-poll loops. AVOID them.
- `run_in_background: true` and `nohup`/`setsid` all get the server reaped (empty log, 144). The ONLY pattern that works: run the server backgrounded **with `&` INSIDE a single foreground Bash call** (`dangerouslyDisableSandbox: true`), drive it with curl in that SAME call, then `kill $SRV`. A `timeout N ./okf-workspace serve &` window bounds it.
- CSRF on mutations needs `-H 'Sec-Fetch-Site: same-origin'` AND a fresh `GET /api/v1/csrf` token immediately before each POST (each csrf GET rotates the `okf_csrf` cookie). Bind-wait on `/` (not `/csrf`).
- After ANY backend/frontend change, REBUILD: `./scripts/dev.sh --build-only` (run ALONE — it calls `pkill` internally → 144 if combined with other commands) before live-testing, or the embedded SPA/binary is stale.
- Admin creds for the live app on `:8098`: user `admin`, password `AdminPass123!` (changed from the one-time pw during phase-11 live UAT; reset via `./okf-workspace admin reset-password admin` if needed).

## Test-data note
- `data/repo/deploy.md` was legitimately tagged during phase-11 live UAT (tags: deployment/build/test/server/binary) and committed (`090e098`). This is the dev data dir (`./data`, gitignored) — harmless; demonstrates the feature works.
- A bulk sweep was started live and left ~126 KindTagSuggest jobs persisted in `app.db` (jobs are SQLite-backed); they re-drain on server start and call the real LLM. To stop that churn, clear pending jobs or just don't run the server long. Some pages have a staged pending `tag_suggestions` row.

## Key facts for resume
- Runtime: non-worktree sequential on `main` (`workflow.use_worktrees=false`); executors commit atomically + own STATE/ROADMAP/REQUIREMENTS tracking.
- All plan/verify gate subagents this milestone were `gsd-*`; the agent roster has since switched to `anvil-*` + role agents (engineer/qa/etc.). The GSD `gsd-tools` CLI + `.planning/` workflow still drive everything.
- Diagnostics from the IDE during execution were frequently STALE (TDD-RED snapshots) — always confirm via real `go build ./... && go test` / `npx tsc -b && npx vitest run` (the pattern held every time this milestone).
- Last commits are the phase-12 plan/exec docs; the working tree should be clean except gitignored caches (`.smtc*`, `.playwright-mcp`, `internal/web/dist/`) and possibly the rebuilt binary `okf-workspace`.

## Resume command
`/gsd-progress` (or `/gsd-autonomous` to continue) — it will route to resolving the phase-12 open item, then the milestone lifecycle.
