# Slate seed build handover

## What this repo is now

Slate is the knowledge workspace spine: one self-hosted product for the family a Notion user and a Confluence user both arrive from. Its primary record is a page — a title, an icon, a cover, a byline and a body of blocks — in a tree inside a container, commented on in place, versioned, shared with named people and groups, and published to the anonymous web only by an explicit act.

The product contract is [CONTRACT.md](./CONTRACT.md), rewritten on 8 September 2026 from the accepted family synthesis in [research/spine.md](./research/spine.md), with the coverage authority in [research/matrix.md](./research/matrix.md) and the per-incumbent deltas in [research/editions/notion.md](./research/editions/notion.md) and [research/editions/confluence.md](./research/editions/confluence.md). [seed.json](./seed.json) maps every clause to a capability and validates against the shared SEED schema. The contract is written to the family, not to either product: Slate replaces Notion and Confluence, imports each one's own export, ships Notion's conventions as its defaults, and reaches Confluence's through eight named policies. Whiteboards, blogs, container calendars, company hubs, team profiles, meeting notes, folders and suggested edits are not in 1.0; each is named in an edition delta, and the not-in-1.0 list names the extension point each arrives on or says plainly that it has none.

**The consolidated code includes the converted rendering foundation, importer parsers and a UI component library; all 191 product contract journeys remain planned.** `maturity` in the manifest says so. The product-planning application has been deleted, not parked: briefs, plans, tasks, milestones, risks, the planning overview, the planning-era activity, template implementation and operator shell, the SPA entry and the retired planning schema are all gone, and `visual/` no longer holds screenshots of that product. What runs today is one Cloudflare Worker serving TanStack Start documents beside Hono's declared HTTP families over the knowledge schema's `workspaces`, `members` and `sessions` tables: the `HOME-001` owner identity plate at `/`, the sign-in surface at `/signin`, `/health` under `BASE-SECRET-002` gating, native `/api/auth/*` with an opaque-cookie session, a session-guarded `/app` whose empty workspace shell renders the member's identity server-side, and `/p/*` reserved for published pages. `deploy/REQUEST-OWNERSHIP.md` is the reviewed request-ownership table. `migrations/core/0001_knowledge_foundation.sql` is the only migration and no tag exists, so it may still be replaced rather than migrated away from.

Three properties of the running foundation are load-bearing and must survive the build stage. Local sample data is permitted only by the explicit Vite/Miniflare binding and only after loopback sign-in; it may create records only in an empty local D1 or upgrade the one known sample workspace, never a custom one, and it must never reach deployment configuration. A deployed runtime requires every manifest-required configuration value before an API, health, document or generated server-function request proceeds (`BASE-SECRET-002`). And a mutation, its operation receipt, its revision and its activity entry commit in one D1 batch, with an expired receipt key atomically reusable — the receipt, revision and activity tables are in the first migration and the feature lanes owe the batch.

## Rendering foundation and consolidation (2026-09-12)

The conversion through the accepted recipe
(`/Users/zemaj/.orchestrator/evidence/runeditrun/default-seed-on-tanstack-start-with-the-migration-recipe/MIGRATION.md`,
portably [TANSTACK-START-MIGRATION.md](https://github.com/runeditrun/seed-spec/blob/main/TANSTACK-START-MIGRATION.md))
has been carried out. TanStack Start owns `/`, `/signin`, `/app` and the
generated `/_serverFn/` transport; Hono owns only `/health`, `/api`, `/api/*` and
the reserved `/p/*`, and `src/server.ts` dispatches them in that order with the
native anonymous `/app` redirect as an explicit preflight. Prerendering is
configured and disabled, because this seed has no deployment-invariant page.
`deploy/REQUEST-OWNERSHIP.md` records the table and the reasoning; the
local-workerd acceptance evidence, including the `BASE-ACCESS-002` session
transport matrix over the emitted artifact, is at
`/Users/zemaj/.orchestrator/evidence/notion/knowledge-contract-and-1-0-deployed/start-migration/`.

The consolidation corrects runtime configuration gating across documents and generated transport, keys native session digests with `SESSION_SECRET`, and exercises missing, expired, revoked and valid sessions against the emitted Worker. The extension proof checks the first client commit and retained DOM nodes; private generated handlers authenticate before reading member data. Browser proofs and the emitted-artifact matrix are recorded under `/Users/zemaj/.orchestrator/evidence/notion/consolidate-outstanding-work/start/`.

The importer batch includes the committed Notion workspace, Confluence Cloud space and Google Docs exports, their provenance, and 30 passing Workers parser regressions. Those tests cover mapping and bounded extraction, including an allocation regression that fails the previous whole-input decompression path. They are explicitly classified as parser regressions and cannot satisfy full import clauses: persisted jobs, access, rollback and end-to-end product journeys are still owed. A genuine Word-produced fixture remains future acceptance work.

The consolidated UI batch is a component library driven by supplied props. Its 107 test stories passed 321 desktop, phone and dark-theme captures with no reported axe violations, console or page errors, or document overflow. Retained browser regressions cover rich-text metadata, caret and newline behavior, composition input, external value updates, field typing, refused page moves, and failed comment submission followed by explicit retry. It is not routed product behavior or evidence that page editing, sharing, search or other product workflows work. Earlier parked UI branches are retained as history; the selected component batch supersedes their overlapping implementation, rather than leaving multiple product shells active.

The existing batches are consolidated for main and future product work. A fresh checkout passed frozen-lockfile installation, `pnpm verify`, `pnpm test:browser`, `pnpm test:ui`, the extension hydration proof, and a 12-capture UI smoke run with interaction checks. The clean-checkout run exposed a missing direct `@types/react-dom` dependency; the pinned declaration is now restored. Evidence is under `/Users/zemaj/.orchestrator/evidence/notion/consolidate-outstanding-work/`. This checkpoint is not a deployment or release; no deploy or tag was performed.

The next product work inherits `mountFeatures(app)` in `src/core/app/mount-features.ts` for Hono routers under `/api/<feature>` and `src/routes/app.*` for documents. This seed declares no queue consumer, `scheduled`, `email`, Durable Object or Workflow export yet; a feature that needs one adds it to `src/server.ts`.

## The contract rewrite, 8 September 2026

191 clauses, from 104. Scope, clause families and vocabulary are the synthesis's: container rather than teamspace or space, record rather than entry, page body rather than block or element, member for the person the baseline calls an operator. The count by family is AI 17, PAGE 14, WORK 12, DB 12, BLOCK 10, SEARCH 9, CONT 9, SHARE 8, WEB 7, REV 7, PORT 7, LIFE 7, COMM 7, TMPL 6, SAVE 6, NAV 6, DEC 6, ARCH 6, TREE 5, STAT 5, IMP 5, AUTO 5, ACT 5, LINK 4, NOTIF 3, MAIL 2, HOME 1.

**Retired, with the product-planning scope they described.** `BRIEF-001`–`BRIEF-008`, `DECI-001`–`DECI-005`, `PLAN-001`–`PLAN-009`, `MILE-001`–`MILE-004`, `TASK-001`–`TASK-008`, `RISK-001`–`RISK-004` and `EVID-001`–`EVID-008`, plus `WORK-002` (equal operators with no roles — this family has levels, groups and guests), `WORK-004` (authenticated sharing only — this family publishes to the anonymous web), `WORK-005` (the planning overview) and `SAVE-007` (one long-text format, replaced by the block model). Fifty IDs are listed as retired at the foot of the contract and are never reused. No tag exists in this repository, so 0.1.0 never reached a buyer and 1.0 is the first release: `RELEASE.json` records the contract as new rather than carrying a `contractChanges` entry per retired ID, and the retired list is what keeps those IDs out of every later release.

**Kept and rewritten to pages,** as the plan's salvage list directs: `SAVE`, `REV`, `TMPL`, `COMM`, `SEARCH`, `LINK`, `PORT`, `ACT` and `AI`, plus `HOME`, `WORK`, `NOTIF` and `MAIL`.

**New for the spine:** `PAGE`, `TREE`, `BLOCK`, `LIFE`, `SHARE`, `WEB`, `STAT`, `ARCH`, `CONT`, `DB`, `AUTO`, `NAV`, `IMP` and `DEC`. The page, the tree, the block editor, structured records and sharing are a new build, not a merge.

**Lifted from Delta (`seeds/confluence`) by block:** content-hashed immutable revisions and stable citations (`SRC-003`, `SRC-004` → `REV-001`, `REV-005`); permanent URLs with tombstones and references that follow their target (`REC-001`, `REC-003` → `LINK-001`–`LINK-003`); archive and restore, and archive is not deletion (`ARCH-001`–`ARCH-004`, kept under the same IDs); search over retained text with default visibility and search without AI (`SEARCH-001`–`SEARCH-005` → `SEARCH-001`, `SEARCH-005`, `SEARCH-008`, `SEARCH-009`); connector sync as the chat notification connection with its lifecycle, credential handling and disconnect (`SYNC-002`, `SYNC-006`, `SYNC-009` → `NOTIF-003`); URL fetch safety (`SRC-009` → `BLOCK-009`, which the link-card row needs and Delta already specified); evidence verification, which only someone who opened the exact revision may assert (`EVID-004` → `STAT-003`); and the decision layer, now a layer over a page rather than its own record type (`DEC-001`–`DEC-008` → `DEC-001`–`DEC-006`, including Delta's editable proposal as `DEC-006`).

**The eight policies, all defaulting to Notion as the first-named incumbent.** Each is one clause naming both profiles and what each shows and hides, and each stores the whole superset under both values so a workspace can be switched without a migration.

| policy | clause | default | the other profile |
| --- | --- | --- | --- |
| `page.lifecycle.v1` | `LIFE-006` | `always-live` | `draft-then-publish` |
| `page.access.v1` | `SHARE-005` | `workspace-general`, all four levels | `container-general` |
| `page.public-access.v1` | `WEB-007` | `site` | `link` |
| `page.version.v1` | `REV-007` | `autosnapshot` | `labelled` |
| `page.status.v1` | `STAT-005` | `verification-only` | `open-vocabulary` |
| `record.page-parity.v1` | `DB-010` | `record-is-page` | `record-is-row` |
| `automation.scope.v1` | `AUTO-005` | `source` | `container`, `site` |
| `container.access.v1` | `CONT-008` | `class-led` | `grant-led` |

There is no ninth. The rewrite first carried `operator.management.v1` (`WORK-003`) and `ai.usage-budget.v1` (`AI-012`) beside the eight; the adversarial review cut both and it was right to. `WORK-003` and `AI-012` state those rules flatly, as `TMPL-005` already did with `template.capture.v1`; `overview.next-action.v1`, `brief.readiness.v1`, `brief.plan-creation.v1`, `plan.health.v1` and `plan.completion.v1` are gone with the clauses they served. Eight is the divergence count, the `AGENTS.md` guideline, and the synthesis's own number at once. The Confluence edition switches all eight and forks nothing.

**Three absolute guarantees are core clauses, in their stronger form, and no profile, role, tier or extension defeats them.** A draft is private whenever one exists (`LIFE-002`). Anonymous access takes two acts and a container administrator's veto over public links, anonymous access and guests is ungated (`WEB-001`, `CONT-007`) — where Notion badges those switches Upgrade to Enterprise, they simply work. A generated answer is produced only from what the asking member may read at that moment, and no cache, embedding or stored proposal re-exposes what was revoked (`AI-013`).

**Non-goals are the matrix's five out rows** — plan ladders, vendor chrome, a marketplace, coupling to one issue tracker, a bundled screen recorder — plus one workspace per deployment, no real-time co-editing, and no native mobile application — the touch client is the same responsive application and it edits (`NAV-006`). The edition rows are listed separately as not in 1.0, because "not yet, and here is the seam" is a different statement from "never", and the Scope paragraph now states both lists rather than flattening one into the other. Thirteen of the not-yet items name the extension point they arrive on; three — suggested edits, page locking, and per-agent budgets and model choice — have no seam in 1.0 and the contract says so rather than implying one.

**Labels ship.** `page-labels` is the only edition row the matrix flags table stakes, and putting it wholly in an edition would have made a Confluence buyer lose a table-stakes taxonomy irrecoverably at the moment of migration, which is the opposite of the discipline every other divergence follows — store the superset, expose it by profile, never discard on import. `PAGE-001` carries the label field, `PAGE-007` shows it, `IMP-003` imports it and `PORT-001` and `PORT-002` carry it through export and restore. Only the container filter is a Confluence-edition contribution.

**One importer per named incumbent, a 1.0 requirement.** `IMP-002` takes a Notion workspace export in its Markdown and CSV form; `IMP-003` takes a Confluence Cloud CSV-table or Server/Data Center XML space export plus a Word `.docx` and a Google Docs document downloaded as `.docx` or zipped HTML, Google Docs having no file form of its own. Each names its fixture as an export produced by the incumbent itself and committed with the test, because a synthetic fixture built from the author's own assumptions would pass while a real export failed, and the plan makes the importer the condition for a name appearing in `replaces[]`. `IMP-001` makes an import rolled back on failure, idempotent and reported construct by construct; `PORT-004` alone holds the searchable-before-Completed guarantee, which three clauses used to state.

## Questions the synthesis left to this contract, and how they were settled

- **Presence and conflict.** No capture shows two live cursors, so `SAVE-006` settles it: several members may edit different blocks at once, a second edit to one block is a 409 under `SAVE-003`, a page shows an avatar stack and nothing more, and a committed block reaches another open editor within 10 seconds. No CRDT, no shared cursors; this is also a declared non-goal.
- **What happens when verification lapses.** `STAT-004`: the page shows the status as lapsed rather than verified, the owner is notified once, nothing renews it and no AI action can (`AI-011`), and a lapsed verification never reads as current in search, content queries, answers or exports.
- **How review works without suggesting mode.** Comments only, as the synthesis says: `COMM-001`–`COMM-007`, with suggested edits named as a Notion edition contribution.
- **The container grant grid.** `CONT-009` states the principals, the levels and who may edit them, and `CONT-008`'s `grant-led` profile renders it. The Confluence capture never opens the matrix, so this is written from `SHARE-001` and `SHARE-002` rather than from a screen; the UI port should treat it as unevidenced.
- **How far the agent goes.** `AI-014` carries the agent object and says plainly that model choice, per-agent budgets and per-destination write levels do not ship.
- **Account recovery.** Left to the baseline: sign-in is `BASE-ACCESS-001`'s magic link, with an identity provider as an adapter (`WORK-015`). No password is stored, so there is no recovery path to specify. `spine.md`'s feature-complete section says "only Confluence captures recovery, so the spine takes its shape", which is foreclosed — taking that shape would mean superseding a baseline access clause — and the reason now sits in `WORK-015` itself rather than only here, so the next reader does not reopen it.
- **Trash retention.** Notion's 30-day note and Confluence's admin purge are both automatic-deletion shapes that `BASE-DATA-002` forbids. `ARCH-005` keeps a trash nothing leaves on a timer, and `ARCH-006` makes emptying it explicit and confirmed.
- **Indexing default.** No screen settles whether a published page is indexable at once. `WEB-005` turns indexing off until a member turns it on, because the recoverable mistake is the one a member can make deliberately.
- **The importer seam base left open.** `seeds/base/HANDOVER.md` asked whether an importer is a `replaces[]` field or something the agent looks up. Settled here as neither: an importer is a clause with a test (`IMP-002`, `IMP-003`) inside the `importers` capability, and `replaces[].name` implies it. A guarantee lives where it can be tested; a manifest field would duplicate a clause and drift from it.

## The adversarial review and how it closed, 8 September 2026

The rewritten contract was read against the manifest, both handovers, the synthesis, the matrix, the plan's Phase 3, the baseline, the base export, `CENTRALISE.md`, the Delta contract and both registries. Its verdict was revise, with fourteen findings and a low list, and every one of them is applied. Coverage, the manifest, the lifts and the three guarantees were found sound and are unchanged.

Six were sentence-level and five of those sat on the access model. `LIFE-002`'s draft link was an unbounded exception inside an absolute guarantee — it never said whether the link required a session, so it read either as anonymous access that took one act or as a reader with no grant; it is now a grant like every other. `SHARE-004` said "exactly one" and "its absence" in one sentence, which under `workspace-general` would have given a page in a personal container a workspace-wide grant, contradicting `CONT-005`. `SHARE-005` was the only one of the eight policy clauses without the switch-safety sentence and the only policy that can change effective access. `WEB-001`, read literally, made forbidding guests stop every public link resolving. `REV-001` had lost Delta's normalisation, leaving the hash the dedupe guarantee rests on undefined. `DEC-006` restores Delta's editable proposal, and `REV-001` names the decision record, which is the mechanism `DEC-003`'s immutability was missing.

Five were a clause edit each. `BLOCK-008` now supersedes `BASE-INPUT-003` on disposition and says so in the header — the contract had contradicted a baseline clause it named nowhere. Labels moved into core. `DB-002` keeps relation and keeps the rollup and formula columns but moves their evaluation to the Notion edition, which is the single largest build reduction available and costs no evidenced capability. The not-in-1.0 list names its seams. `IMP-002` and `IMP-003` require a real export as a fixture.

Three were repository hygiene. `research/matrix.md` is now in the seed: it is the authority this contract's coverage, non-goals and policy count are measured against, and `HANDOVER.md` cited it while it was uncheckable from inside the repository. The commit that withheld it stated a rule it simultaneously broke — that every Mobbin citation stays in the research repository — while copying 406 into `research/spine.md` and 88 into the editions. That stricter claim was wrong. The rule is that the reference screen set, the screen images and `matrix.json` stay in the research repository; a citation as text is a reference, not a screen, and it may be copied. And `spine.id` stays `knowledge`: `research/spines.json` is the registry the synthesis, matrix and reference set were produced under, the schema's `knowledge-workspace` is an illustrative example written from this very spine, and the disagreement was `repos.json`'s, which has been aligned in the container repository.

The two `research/editions/*.md` copies are no longer byte-identical to the research repository. They carry three factual corrections, and the research repository should take the same three: `notion.md` said the container veto covers export, which neither the union nor `CONT-007` carries; `notion.md` now records `DB-002`'s rollup and formula deferral where a reader of that edition will meet it; and `confluence.md`'s `page-labels` row now contributes the container filter alone, because core holds the field. `spine.md` and `matrix.md` are untouched copies.

## Decisions the build must preserve

- One workspace per deployment, with containers, groups, guests and four access levels. Access is a grant list on a page and on a container, inherited down the tree, and every check is server side.
- Every divergence is a policy over a superset model. Both profiles' columns — `draft` and `scheduled` states, published revision, ordinal and label, slug and theme, status vocabulary, record body and tree position, rule scope and run log, container visibility and grants — are in the first migration, whichever value is the default.
- A draft's privacy, the container veto and the answer boundary are core clauses, not policy values. A test for each must fail if a profile, a role or an extension can defeat it.
- Pages, revisions, containers, records, comment threads and templates keep one identifier and one URL for life. A revision is immutable and content-hashed; a citation resolves to the revision it names or to a content-free tombstone.
- Saves reflect durable commits, conflicts are caught at save at block grain, and nothing is merged automatically.
- Search, content queries, mentions, analytics, activity and AI answers all resolve against what the reader may read, and none of them may reveal that a record exists.
- Mail goes out only for sign-in links and invitations. Notifications are in app, with one optional chat destination that carries a link and never a body.
- AI is optional, budgeted, cited and reviewed; it holds no authority to publish, change access, verify, delete or manage members.
- Activity is append-only and commits with the mutation it describes.
- Nothing is discarded on import because 1.0 does not use it. A page's labels, a record's rollup and formula columns, a draft's state, an ordinal and a version label, a slug and a theme, a rule's scope and its run log all have storage whether or not the shipped surface reads them.
- A stored file's disposition depends on why it is requested, never on who requests it. Display is inline, everything else is a download, and access is checked identically either way (`BLOCK-008`).
- Product concept nouns come from one module, so an edition can relabel them: container, record, page body, member.

## What the build stage owes

Stage 2 of the task card. The three seam items, in the first pass because each is a migration or a contract change to retrofit: every divergence as a policy over a superset data model with the other profile's columns in the first migration; clauses written in spine terms with policy-controlled behaviour named as such; and an importer per named incumbent that imports a real export. One writing rule: product concept nouns come from one module. Nothing else from the edition design ships at 1.0 — no vocabulary map merge, no navigation as data, no defaults object, no feature set, no edition mount, no default edition.

The UI component port is underway against `research/spines/knowledge/reference.json` in the research repository, reading its 34 screens in place and never copying them here. Product acceptance still requires routed, persisted behavior, `pnpm verify` green from a clean clone, a separately authorized real Cloudflare deployment, and clause tests that pass with the default profile and with each alternative profile. [RELEASE.json](./RELEASE.json) is already written for this contract's first release: no tag precedes it, so every clause is new, `contractChanges` carries only `BLOCK-008`'s supersession of `BASE-INPUT-003`, and `agentUpdateInstructions` names the three absolute guarantees, the superset model behind the eight policies and the two rules that must not become policies again. Its migration list already names `migrations/core/0001_knowledge_foundation.sql`; the build stage owes it a `contractChanges` entry from the first tag onward for any clause whose meaning moves.

No complete product clause is claimed satisfied. The rendering foundation, native sessions, parser mappings and prop-driven UI components are completed foundation work; they do not replace the planned product journeys.

## Current verification

`pnpm verify` performs the checks that exist today: typechecking; contract, manifest, policy, baseline and package-manager consistency; the local D1 migration path; a Vite/Miniflare Worker journey and an emitted-artifact `workerd` journey over the converted surfaces, including the `BASE-ACCESS-002` session transport matrix; a production build; and the explicit TODO contract inventory. The product inventory remains `productContractBehavior: {satisfied: 0, planned: 191}`: every clause in this contract is a planned journey, and a policy clause owes one journey per profile value. The shared baseline pack still does not exist in this repo, and verify reports that rather than implying coverage. The combined clean-checkout verifier passed 21 checks with no failures and reports two baseline clauses satisfied and twenty planned. `pnpm test:browser`, `pnpm test:ui`, `node scripts/ext-client-proof.mjs`, the UI capture/interaction smoke run, and shared SEED/RELEASE schema validation also passed. Reproduction commands and results are in the consolidation evidence directory; the full visual run is in its `ui/` directory. Future work must keep planned product journeys separate from passing parser and component regressions.

Three clauses now owe a test the build stage cannot fake. `BLOCK-008` carries the replacement test for the baseline clause it supersedes, so a run that reports `BASE-INPUT-003` as broken rather than superseded is a failure. `IMP-002` and `IMP-003` require incumbent-produced fixtures and complete import journeys. The Notion, Confluence and Google Docs fixtures are committed; the Word-produced document is still missing.

As of 11 September 2026 `IMP-002` and `IMP-003` have most of those fixtures: a Notion workspace export, a Confluence Cloud space export and a Google Docs `.docx` download are committed unmodified under `tests/e2e/imports/fixtures/real/` with a `PROVENANCE.md`, and `tests/e2e/imports/real-exports.test.ts` asserts the mapping construct by construct against them. The Word-produced `.docx` `IMP-003` also names has still not been provided, so its fixture acceptance remains planned alongside the still-planned complete import journey, and `DIVERGENCE.md` item 15 records that the clause had to be reworded because Confluence Cloud exports CSV tables rather than the `entities.xml` the accepted clause named.

`DIVERGENCE.md` records where the planted shared documents and schemas fought this seed. Items 13 and 14 came from the adversarial review: `BASE-INPUT-003`'s download disposition, which any seed with an inline image supersedes, and `RELEASE.schema.json`'s missing first-release form for `contractChanges`. Item 11 also records that CENTRALISE's per-policy `why` has nowhere to live in `seed.json` today.
