--- id: ADR-0004 title: Thin git content plane, PageOps, and supported upgrades status: accepted date: 2026-08-13 deciders: bernd related: - ADR-0001 - ADR-0002 - ADR-0003 - docs/architecture/ArchitectureBlueprint.md workplans: - CSOC-WP-0004 - CSOC-WP-0006 --- # ADR-0004 — Thin git content plane, PageOps, and supported upgrades ## Status **Accepted** (2026-08-13). Pairs with **ADR-0003** (what a page is and how authors work). This ADR decides **where content lives**, how the app talks to it, and how the plane may grow. ## Context Content needs a store that: - keeps **user data as files** in **git**, - starts **simple** for stage-1 transfer, - can later gain wiki federation or ECM-class power **without rewriting** the product UI or stranding exports. Candidates considered: | Option | Role | |--------|------| | **A** Thin directory + markdown + git | Start here | | **B** shard-wiki | Wiki orchestration / multi-shard later | | **C** kontextual-engine | Scale, rich media, governed assets later | Also: shared **asset-store** extraction, and who owns content-plane PolicyGateway. ## Decision ### 1. Default content plane (stage-1 and near term) **Start thin (A):** - A **directory tree** of markdown pages and assets. - Tree is **secured in git** (commits via product, operator, or linked remote). - Illustrative layout: ```text spaces// pages/.md assets/… ``` Exact layout may evolve; the invariant is **files + git**, not “opaque DB rows for prose.” **Forgejo / remote git** (including ADR-0002-style bindings) may host or mirror the tree; they are **transports/remotes**, not a second product ontology. ### 2. PageOps boundary All product code accesses content through a **narrow PageOps** façade (names illustrative): | Op | Purpose | |----|---------| | list/get/put/archive page | CRUD | | copy / transfer page | Stage-1 must features | | explode / implode | Outline-editor flexibility (ADR-0003) | | resolve_view | Live includes/derived for display | | pin / unpin / refresh_pinned | Explicit freeze + stale workflow | | project_field / regenerate / lock | Title/abstractor/visual lifecycle | | put_visual / get_asset | Binaries | **Rule:** UI and product services **must not** call shard-wiki, kontextual, or Forgejo APIs ad hoc from templates — only PageOps. Swapping the content-plane **adapter** upgrades the backend without rewriting cards and flows. ### 3. Supported upgrade path ```text A thin dir + git (+ markitect-tool) │ │ when wiki / federation / multi-shard matters ▼ B shard-wiki adapter (same markdown as shard material) │ │ when scale / rich multi-format media / heavy governance ▼ C kontextual-engine upgrade (migration tooling; markdown remains portable) ``` | Upgrade | When | Invariant | |---------|------|-----------| | **→ shard-wiki** | Wiki features, multi-shard, overlays become product-relevant | Exportable markdown tree remains valid; markitect still structures docs | | **→ kontextual** | Ambitious structure, scale, rich media, audit/lineage | Supported **upgrade of the information base**; user export of markdown+assets still required where content is document-shaped | Upgrades are **planned migrations**, not emergency rewrites. Feasibility should be re-checked with export/import sketches when approaching B or C. ### 4. Assets 1. **Now:** assets live **beside** markdown in the content tree (paths or simple digests in frontmatter `visual` / refs). 2. **Later:** extract a shared **asset-store** (seed from kontextual BlobStorage ideas) when a **second fleet consumer** needs the same API — **not** a stage-1 gate. 3. Do **not** adopt markitect-main’s large assets package as runtime. ### 5. Authorization ownership 1. **Authn** remains NetKingdom OIDC (ADR-0001). 2. **Do not** create a long-lived coulomb-specific PolicyGateway ownership stream. Prefer **NetKingdom consolidation** so authorization decisioning for app resources is the obvious platform path (flex-auth / NK as one story). 3. **Until consolidation lands:** coulomb enforces coarse product authz (authenticated session, `tenant_id`, SpaceMembership). Content plane fails closed if a PDP is configured and denies or is required but unavailable for sensitive ops. 4. Content-plane engines (shard-wiki, kontextual) must accept **external** principal identity (e.g. issuer/subject + groups), not their own user directories. ### 6. markitect-tool on every plane Regardless of A/B/C: - parse, validate, query, **live include**, explode/implode, and future derived-slot tooling live in **markitect-tool**; - the plane stores and serves files (or equivalent); markitect does not host multi-user product sessions. ## Consequences ### Positive - Fastest path to stage-1 with true user-owned files and git history. - Clear upgrade story reduces fear of “too simple forever” without overbuilding. - PageOps keeps UI stable across backend generations. - Authz consolidation direction avoids duplicate IAM mini-platforms. ### Negative / costs - Thin plane must still implement solid git/write, conflict, and cache-bust behavior for a good product feel. - Copy/transfer/explode semantics are coulomb+markitect work on the tree. - Upgrade tooling to B/C is real future cost (accepted as supported path). - NK authz consolidation is a **platform dependency** outside this repo’s sole control. ### Neutral - ADR-0002 Forgejo demo path can remain for public raw fixtures and optional remotes. - asset-store extraction is explicit **later** work (possible ADR-0005). ## Non-goals - Implementing full shard-wiki or kontextual integration in stage-1. - Bundling a wiki UI or ECM UI in coulomb (headless planes only). - Replacing NetKingdom with app-local accounts. - Making Postgres the content SoR. ## Implementation guidance (non-normative) 1. Define a `ContentPlane` / PageOps port in coulomb; ship **Filesystem+Git** adapter first. 2. Index cards into Postgres on write and on git pull/webhook. 3. Wire markitect live `resolve_includes` on view/export. 4. Prototype explode/implode in product against the same tree. 5. Document export: zip/tar of tree without DB dump. 6. When approaching B/C: migration runbook + round-trip tests from a real space tree. ## References - `docs/architecture/ArchitectureBlueprint.md` (D1–D4) - `docs/architecture/spike-checklist.md` (A chosen; B/C upgrade sketches) - ADR-0003 (page model, live/pin, authoring) - ADR-0002 (Forgejo vertical slice; demoted as exclusive SoR) - shard-wiki INTENT (Coulomb as intended consumer) - kontextual-engine (upgrade target; blob port for later asset-store)