# 0002 — Forgejo salvage plan

What to take from `~/references/forgejo` for quarry, what to rework, and how.
Companion to `0001-quarry-forge.md` (which records the verdict this document
executes: **parts and map, not chassis**). Informal working document.

## 0. Ground rules — the three modes of "take"

Forgejo's top-level LICENSE is GPLv3: post-fork code is GPL, Gitea-inherited
code is MIT. Every item below is tagged with its mode:

- **[COPY]** — lift code. Only from files whose lineage is MIT (exists in
  `go-gitea/gitea` upstream predating the fork) OR where we accept the GPL
  consequence for quarry. Default: take the *Gitea upstream* version of the
  file, not the forgejo one, and record it in a `third_party/PROVENANCE.md`
  ledger (path, source repo, commit, license). No exceptions to the ledger.
- **[DEP]** — import as a library. Verify the module's own license first
  (`gof3` ships separately from forgejo proper; check before v2).
- **[MAP]** — read for structure, reimplement fresh. Layouts, route taxonomy,
  UX decisions, empty-state wording. No code crosses; no license question.

Rework baseline: quarry keeps Go `html/template` so [MAP] items port with
their shapes intact, renders server-side, and uses Datastar for progressive
JS (0001 Principles 2–3: server-owned state, views usable without JS, live
features degrade to load-time state + refresh). We do NOT adopt forgejo's Vue
layer — they are mid-migration (jQuery-era + Vue + a start on htmx) and the
Vue components drag a build chain quarry doesn't want; any framework
exception beyond Datastar is made explicitly per 0001 Principle 2, never by
porting convenience.

## 1. The page inventory — what quarry v1/v2/v3 replicates

Route-by-route map from `templates/` and `routers/web/`. "Rework" states the
zit-semantic change, not cosmetics.

### v1 — read plane

| Forgejo source | Quarry page | Mode | Rework |
|---|---|---|---|
| `templates/explore/repos.tmpl`, `repo_list.tmpl`, `navbar.tmpl` | **Fleet page** (all repos, activity, search) | [MAP] | Data from quarry's derived indexes, not an authoritative DB; add cross-repo timeline (forgejo has none — this is our addition, fossil reasons 15-18). |
| `templates/repo/home.tmpl`, `header.tmpl`, `clone_buttons.tmpl`, `clone_script.tmpl` | Repo home / file browser | [MAP] | Clone box emits `zit clone` URL (quarry `/r/<repo>` fronting). No fork/PR buttons. Branch dropdown reads repostate branches (multiple-same-name branches are legal in zit — dropdown must disambiguate by tip hash, forgejo assumes unique names). |
| `templates/repo/commits.tmpl`, `commits_list.tmpl`, `commit_page.tmpl`, `commit_header.tmpl` | Timeline + check-in page | [MAP] | Check-in page shows tags/control-artifact history (amend overrides displayed with provenance — zit shows both original and override; forgejo has no concept). Timestamp links use #60 resolution. |
| `templates/repo/graph.tmpl`, `graph/*` + `web_src/js/features/repo-graph.js` | DAG graph view | [COPY] (js + svg container), [MAP] (page) | Feed it plink-equivalent rows from the index. Their renderer draws git DAGs; zit DAGs are the same shape. Verify lineage (predates fork — likely MIT). |
| `templates/repo/diff/section_split.tmpl`, `section_unified.tmpl`, `blob_excerpt.tmpl`, `whitespace_dropdown.tmpl`, `options_dropdown.tmpl` | Diff views (split/unified, expandable context) | [MAP] with structure kept close | Driven by zit's own diff output, not git's. Drop: comment forms, review machinery (that's v2 forum-anchored, different model). Keep: the expand-context UX (`blob_excerpt`), whitespace toggles. |
| `templates/repo/diff/image_diff.tmpl` + `web_src/js/features/imagediff.js` | Image diff (swipe/onion-skin) | [COPY] | Self-contained, excellent, rarely reimplemented well. Lineage check. |
| `templates/repo/diff/csv_diff.tmpl` + `modules/csv` | CSV diff | [COPY] | Small, agnostic. |
| `templates/repo/blame.tmpl` | Annotate view | [MAP] | zit `annotate` output; forgejo's chunk-coloring layout is the good part. |
| `templates/repo/wiki/view.tmpl`, `pages.tmpl`, `revision.tmpl` | Wiki render + history | [MAP] | Backing store inverts: forgejo wiki = a side git repo; quarry wiki = wiki artifacts with P-chain history. `revision.tmpl`'s history-list layout maps 1:1 onto the artifact chain. `new`/`edit` deferred to v2. |
| `templates/repo/search.tmpl`, `templates/explore/code.tmpl` | Search (FTS) | [MAP] | SQLite FTS5 behind it; keep their filter chrome. |
| `templates/repo/activity.tmpl`, `code_frequency.tmpl`, `contributors.tmpl` | Activity/stats pages | [MAP] | Computed in the SQL index (they compute in-process); charts can wait, tables first. |
| `templates/user/heatmap.tmpl` + `web_src/js/components/ActivityHeatmap.vue` | Activity heatmap | [MAP] — server-rendered SVG | ~150 lines server-side, no build chain, works without JS (0001 Principles 2–3). The Vue component is reference only. |
| `templates/status/*`, `templates/base/*` | Error pages, base layout, alerts | [MAP] | Base layout skeleton (head/nav/footer blocks) worth mirroring for the classes/structure; quarry ships its own CSS (see §3). |

### v2 — write plane

| Forgejo source | Quarry page | Mode | Rework |
|---|---|---|---|
| Issue list/detail templates (under `templates/repo/issue/`) | **Tickets** list/detail | [MAP] layout only | The storage inverts completely: forgejo issues are DB rows; quarry tickets are ticket artifacts (J-card field history). The list page (filters, labels, sort) and detail page (event timeline) layouts transfer; every data access reworks to index queries + artifact minting via the lease holder. Labels: zit has no label concept — map to ticket fields, render forgejo-style chips. |
| `templates/repo/diff/comment_form.tmpl`, `conversation.tmpl` | Forum threads / check-in discussion | [MAP] | Conversations anchor to artifacts (forum posts with I/P/G refs), not to diff line rows. Line-anchored review is explicitly OUT (fossil-model discussion, not GitHub-model review) — this is the biggest deliberate divergence; record it in the UI as "discuss this check-in" not "review". |
| `templates/user/auth/*`, `templates/user/settings/*` | Login, settings | [MAP] | Auth stack is NOT taken (§2). Screens only. |
| `templates/org/*` | Org/team pages | [MAP], mostly SKIP | v1 is single-org; take the member-list layouts when needed. |
| Wiki `new.tmpl`/editor | Wiki editing | [MAP] | Editor posts to artifact-minting endpoint; CodeMirror from their `web_src/css/codemirror` setup is [COPY]-able if we want in-browser editing sugar. |

### v3 — CI + fleet ops

| Forgejo source | Quarry page | Mode | Rework |
|---|---|---|---|
| `templates/repo/actions/*`, `web_src/js/components/ActionRunStatus.vue`, `ActionJobStep*.vue` | dagnats run views | [MAP] | Their run/step/log UI is the right shape; rebuild server-rendered + Datastar SSE (live steps stream in; without JS the page shows state-at-load and refresh works — 0001 Principle 3). The Vue components are reference only. `routers/web/events` (SSE plumbing) is worth [MAP]-reading for the endpoint shape. Runner protocol NOT taken (dagnats is the engine). |
| `templates/repo/commit_status.tmpl`, `commit_statuses.tmpl` | Status badges on timeline | [MAP] | Verdict source = tag artifacts + live dagnats state. |
| `templates/admin/*` | Fleet admin | [MAP] | Registry/leases/ingest health — mostly quarry-specific content in their layout skeleton. |

## 2. Code salvage list (beyond page-linked items above)

**Take:**

- `modules/markup/` — the crown jewel: `markdown/` (goldmark assembly:
  callouts, math, link resolution hooks), `common/`, `console/` (ANSI
  rendering), `asciicast/`, `file_preview.go`, `mdstripper/`. [COPY,
  lineage-check per file]. **Exception: the sanitizer is a cleanroom
  reimplementation**, not a copy from either lineage. Forgejo and Gitea have
  diverged on XSS fixes since the fork, so "take the MIT upstream version"
  can mean shipping holes the other lineage already closed, and cherry-picking
  across a GPL/MIT boundary is exactly the provenance mess the ledger exists
  to prevent. Strategy: write quarry's bluemonday policy fresh; treat the
  **union of both projects' sanitizer test vectors as a conformance corpus**
  (test inputs/expected outputs are data — recorded in the ledger with
  attribution, no policy code crosses); run the corpus in CI so we pass every
  XSS edge either lineage has ever caught; watch both projects' security
  advisories and fold new vectors into the corpus as they publish; add a fuzz
  target over the policy from day one. Rework:
  their link resolution resolves git refs/issues (`#123`, `!45`, commit SHAs)
  — replace the resolver hooks with zit resolution (artifact hashes, ticket
  ids via `HashTokenKind`, `[[wiki]]` interwiki per fossil convention).
- `modules/highlight/highlight.go` — thin chroma wrapper with sane fallbacks,
  plus `web_src/css/chroma/` themes. [COPY].
- `modules/avatar/` — identicon generation + processing. [COPY].
- `modules/charset/` — UTF-8 detection/BOM handling for rendering unknown
  files. [COPY].
- `modules/emoji/` — shortcode table. [COPY].
- `web_src/js/features/clipboard.js`, `repo-diff.js` (expand-context wiring)
  — small vanilla features. [COPY, trim].
- `code.forgejo.org/f3/gof3` — F3 interchange. [DEP, license-verify]. The
  quarry F3 importer (forgejo/gitea/github issues→ticket artifacts,
  comments→forum artifacts, wiki→wiki artifacts) is the migration weapon; v2.

**Explicitly do not take:**

- `models/` + XORM + `models/migrations/` (600+; the authoritative-DB
  architecture itself) — quarry's derived indexes + tiny litestream'd OLTP replace it.
- `services/` layer and `routers/` handlers — coupled to the above.
- Auth stack (`services/auth`, LDAP/OAuth internals) — entangled with their
  user model; quarry uses standalone libs when v2 arrives.
- Actions runner + protocol implementation — dagnats.
- Webhooks subsystem — their implementation is entangled with the models
  layer. Quarry builds its own: webhooks/SSE/websockets are the *supported*
  external async surface (0001 Principle 6 — users are never required to
  speak NATS), implemented as a dispatcher worker on the internal event
  stream. Their payload shapes are worth [MAP]-reading for ecosystem
  familiarity; no code crosses.
- `modules/git`, `modules/gitrepo`, LFS, githttp — git.
- `modules/activitypub`, `forgefed` — federation for quarry is zit sync
  (RFC §future); ForgeFed is git-shaped and drags the models layer.
- The Vue build chain wholesale; jQuery remnants; their ini config system;
  `modules/indexer` (bleve/ES adapters — the derived index plane replaces).

## 3. CSS / design system

[MAP] only. Take the *information* — spacing scale, the diff color semantics
(add/del/context in both themes), muted-vs-emphasis text hierarchy — and
write quarry's own small CSS with native vars + the artifact-design two-theme
discipline. Copying `base.css` (~their whole design system) imports a decade
of dead selectors and fights every layout we change. Exception: `chroma/`
syntax themes [COPY] since they pair with the highlight module.

## 4. Mechanics — how the salvage actually runs

1. **Ledger first.** `third_party/PROVENANCE.md` + a CI check that every
   file under `third_party/` (or carrying a salvage header) has a ledger row
   with source repo/commit/license. GPL-lineage code gets refused at review
   unless the row says we accepted it knowingly.
2. **Vendor the [COPY] modules as packages, not sprinkles**: `internal/markup`
   (forgejo markup + our resolver hooks + the cleanroom sanitizer per §2),
   `internal/highlight`, `internal/avatar`, etc. Each lands with its upstream
   tests ported — for the sanitizer, only the test vectors cross (as the
   conformance corpus), never the policy code.
3. **Resolver inversion is one seam.** All git-flavored reference resolution
   in markup goes through one `Resolver` interface (hash → link, ticket id →
   link, wiki name → link, `branch@date` per #60). Implement once against the
   index; markup stays upstream-diffable for future re-syncs of their XSS
   fixes.
4. **Templates are rewritten, looking at theirs.** Keep their DOM structure
   and class *shapes* where the layout is the thing being taken (diff
   sections, graph container, wiki history) so their JS features port
   unmodified; everything else is fresh.
5. **Per-page definition of done**: renders from derived-index data only (passes the
   0001 §11 disposability test), no git vocabulary in user-facing strings
   ("check-in" not "commit" — fossil's term, zit's term), both themes, keyboard
   focus states, usable with JS disabled (0001 Principle 3), and the page's
   capability exposed through the API (0001 Principle 5 — shared
   query/command layer, documented endpoint).
6. **Order of extraction** (matches quarry v1 build order): markup+highlight
   +charset first (everything renders through them) → base layout + fleet +
   repo home/files → timeline + check-in page → diff stack (incl. image/csv)
   → graph → wiki render → search → activity/stats → chat UI (no forgejo
   ancestor — fresh, notify Inbox patterns apply) → v2/v3 per §1.

## 5. What forgejo simply doesn't have (fresh builds, no salvage)

Cross-repo timeline; chat (their closest is nothing — fossil's chat and
notify's Inbox are the references); the ingest/index plane; sync fronting;
lease routing; the disposability harness; timestamp-resolution links (#60);
amend-provenance display; submanifest-aware tree browsing (S-card trees can
render lazily per subtree — a wide-repo browsing win forgejo can't express);
the #41 replay table as a repo settings page.
