coulomb-social/docs/architecture/spike-checklist.md

206 lines
7.8 KiB
Markdown
Raw Normal View History

# Spike checklist — content plane & assets
| Field | Value |
|-------|--------|
| Blueprint | [ArchitectureBlueprint.md](./ArchitectureBlueprint.md) |
| Goal | Falsify or confirm options A/B/C and asset extraction before ADR-0003/0004 |
| Time box | Prefer ≤23 working days per major spike; stop when decision quality is enough |
Scoring legend for each spike: **Pass** / **Partial** / **Fail** / **Skip** with one-line evidence.
---
## Spike 0 — Shared page document fixture
**Owner:** coulomb-social
**Depends on:** none
- [ ] Define one **stage-1 page** markdown fixture:
- frontmatter: `id`, `type`, `title`, `abstract`, `visual`, `space`
- body: short markdown
- backmatter: e.g. `relations` or provenance stub
- [ ] Define one **space** container convention (page-type vs directory).
- [ ] Define **export package** layout (`pages/**`, `assets/**`, `MANIFEST.json`).
- [ ] Commit fixtures under `docs/space-fixtures/` or `docs/architecture/fixtures/`.
**Pass when:** fixture is stable enough that all later spikes use the same bytes.
---
## Spike 1 — markitect-tool as structure lib
**Owner:** coulomb-social (+ markitect-tool if API gaps)
**Depends on:** Spike 0
- [ ] From Python in coulomb (or throwaway script): parse fixture with markitect-tool public API.
- [ ] Round-trip serialize without losing title/abstract/visual fields.
- [ ] Validate required frontmatter fields (even minimal schema).
- [ ] Note missing APIs (backmatter support, field maps) as markitect-tool gaps.
**Pass when:** coulomb can treat markitect-tool as dependency for read/write structure without shelling out to `mkt` for the happy path.
**Fail when:** only CLI works or public API cannot preserve frontmatter stably.
---
## Spike 2 — Thin folder/git store (Option A)
**Owner:** coulomb-social
**Depends on:** Spike 01
- [ ] Layout: `spaces/<slug>/pages/<page>.md` + `assets/`.
- [ ] Implement throwaway PageOps: list, get, put, copy, transfer (filesystem).
- [ ] Reindex card projection into SQLite/Postgres (title, abstract, visual path, space).
- [ ] Export = tar/zip of tree; reimport without DB.
- [ ] Measure: copy/transfer LOC and failure modes (broken links, name collision).
**Pass when:** stage-1 verbs work on files alone; export/import demonstrated.
**Decision input:** Is A enough for 36 months without federation?
---
## Spike 3 — shard-wiki thin slice (Option B)
**Owner:** coulomb-social + shard-wiki
**Depends on:** Spike 0
- [ ] Boot one InformationSpace with **single** FolderAdapter or native engine shard.
- [ ] Ingest/edit stage-1 page; read via headless API (no UI).
- [ ] Implement or map: list, get, put; prototype copy/transfer (engine op or app-level).
- [ ] Attach **fake Actor** from static OIDC-like subject; confirm authz hooks exist or gap list.
- [ ] Document API surface coulomb would depend on (count endpoints/concepts).
- [ ] Stress “structure tax”: can card UI ignore federation/overlays entirely?
**Pass when:** thin slice delivers page CRUD without coulomb importing federation UX concepts.
**Fail when:** product code must understand multi-shard resolution for basic CRUD.
**Decision input:** structure surface area vs future multi-shard value.
---
## Spike 4 — kontextual-engine page + markdown SoR (Option C)
**Owner:** coulomb-social + kontextual-engine
**Depends on:** Spike 01
- [ ] Create `KnowledgeAsset` for stage-1 page; store **source** representation as markdown bytes (BlobStorage).
- [ ] Put title/abstract/visual in metadata and/or inside markdown frontmatter (document which is authoritative for export).
- [ ] Get content stream; reconstruct `.md` file bit-identical (or document lossiness).
- [ ] Run markitect-tool adapter on stored markdown (existing boundary tests as reference).
- [ ] Prototype copy = new asset + blob refs; transfer = metadata/relationship change to space context entity.
- [ ] Export package: write assets + markdown to filesystem from engine API.
**Pass when:** user-visible export is clean markdown+assets; engine IDs are additive not mandatory for reuse.
**Fail when:** content is only queryable as opaque registry rows without faithful markdown export.
**Decision input:** governance/lineage value vs stage-1 complexity.
---
## Spike 5 — NetKingdom / PolicyGateway wiring
**Owner:** coulomb + kontextual (and/or flex-auth)
**Depends on:** Spike 3 or 4
- [ ] Map live or mocked OIDC claims → `Actor(external_ref=issuer|sub, groups=...)`.
- [ ] Implement **deny-by-default** PolicyGateway stub that allows only same-tenant resource metadata.
- [ ] Optional: call flex-auth `check` with coulomb vocabulary (if service available).
- [ ] Prove fail-closed: missing policy → no content bytes.
- [ ] Document gap list for production adapter ownership.
**Pass when:** written design + failing/passing test for cross-tenant deny.
**Fail when:** only AllowAll can run the stack.
---
## Spike 6 — Asset / Visual path
**Owner:** coulomb (+ kontextual or extracted store)
**Depends on:** Spike 2 or 4
- [ ] Store a cover image via content-addressed put; reference from page frontmatter `visual: sha256:…` or `asset:…`.
- [ ] Serve image for card UI (signed URL, app proxy, or static mount — pick one).
- [ ] GC/unreferenced dry-run once.
- [ ] Compare effort: in-process kontextual BlobStorage vs copy port to shared package.
**Pass when:** card shows visual without storing image bytes in Postgres.
**Decision input for extraction:** is a second consumer ready? If no → keep in kontextual for now.
---
## Spike 7 — Asset-store extraction feasibility
**Owner:** platform / kontextual
**Depends on:** Spike 6
- [ ] Inventory kontextual `BlobStorage` + adapters (fs/s3/memory) public surface.
- [ ] Inventory markitect-main `markitect/assets/` for **ideas only** (dedupe, packaging); do not port wholesale.
- [ ] Draft package name + repo boundary: bytes only vs registry.
- [ ] Estimate extraction PR: move port+adapters, leave KnowledgeAsset in kontextual.
- [ ] List consumers: coulomb, kontextual, shard-wiki (optional).
**Pass when:** one-page extraction proposal with “extract now / later / never” recommendation.
**Default bias:** **later** until two consumers need it.
---
## Spike 8 — Cross-option decision workshop
**Owner:** founder + implementers
**Depends on:** Spikes 16 results
- [ ] Fill scorecard (below).
- [ ] Choose primary content plane for stage 1 + migration path.
- [ ] Choose asset strategy (in-kontextual vs extract vs folder-only).
- [ ] File ADR-0003 (page model + SoR) and ADR-0004 (content plane).
- [ ] Update `docs/capability/model-v0.yaml` feature wording if PageOps replaces Forgejo-centric features.
### Scorecard (15, higher better)
| Criterion | A thin store | B shard-wiki | C kontextual |
|-----------|:------------:|:------------:|:------------:|
| Markdown export fidelity | | | |
| Stage-1 speed | | | |
| Structure tax (inverse) | | | |
| Copy/transfer naturalness | | | |
| Visual/blob readiness | | | |
| NetKingdom/authz fit | | | |
| Multi-shard / federation later | | | |
| Multi-format / ECM later | | | |
| Railiance operability | | | |
| Aligns with fleet layers | | | |
| **Total** | | | |
---
## Suggested order
```text
0 fixture → 1 markitect → 2 thin store (always, baseline)
├→ 3 shard-wiki thin
└→ 4 kontextual page+blob
→ 5 authz on winner(s)
→ 6 visual
→ 7 extraction feasibility
→ 8 decision / ADRs
```
Spike 2 is the **control experiment**: even if B or C wins, A defines the export contract users feel.
---
## Exit criteria for this checklist
Stop spiking when:
1. One primary content plane is chosen for stage 1 with explicit residuals, and
2. Asset strategy is chosen (where Visual bytes live), and
3. NetKingdom policy gap is owned (who implements PolicyGateway adapter), and
4. ADR-0003/0004 drafts exist or are scheduled.