Skip to content

Commit ca6d644

Browse files
Implement notion-md v-next sync surface
1 parent ecefeec commit ca6d644

39 files changed

Lines changed: 927 additions & 390 deletions

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ All notable changes to this project will be documented in this file.
1616

1717
- **CI / Nix packages**: Refresh the stale `genie`, `megarepo`, `notion-md`, and `tui-stories` pnpm fixed-output hashes after the schema-first OTEL contract change updated the workspace dependency closure.
1818

19+
- **@overeng/notion-md**: Move the v-next public CLI to `track` / `status` / `sync`: `track` is now the only page-id bootstrap command, `sync`/`status` operate on local self-describing files, write-capable paths support `--dry-run`, and `sync --watch` routes through the same source-aware reconcile engine as one-shot sync.
20+
1921
- **CI / Nix packages**: Refresh the stale `workflow-report` pnpm fixed-output hash so the Storybook preview reporting step can build `#workflow-report` again after the branch rebase updated the workspace dependency closure.
2022

2123
- **@overeng/restate-effect**: Made `Restate.run`'s type HONEST. A durable `ctx.run` step carries NO catchable typed failure: the inner effect runs via `Runtime.runPromise` inside `ctx.run`, so a typed `Effect.fail` only REJECTS the step (Restate retries; a give-up maps to a `RestateError` DEFECT) and never reaches the outer failure channel — the old `run<A, E, R>(…): Effect<A, E, …>` advertised a typed `E` that `catchTag`/`catchAll` would typecheck against but that could never fire. `run` is now `run<A, R>(name, effect: Effect<A, never, R>, options?): Effect<A, never, …>`, and `runExit` is `runExit<A, R>(…): Effect<Exit<A>, never, …>` — the honest OBSERVATION form, whose failure channel is `never` (an observed failure is a defect/interrupt `Cause`, not a phantom typed `E`). Domain errors now belong in the HANDLER body (classify the step's result there) or are encoded as VALUES inside the step; to force a durable retry, DIE inside the step. A passed typed-`E` inner effect is now a COMPILE error (negative-type assertion in `capability-inference.types.ts`). Callers reconciled: the saga integration test's failing `pay` step `Effect.die`s (was `Effect.fail`), and `examples/12-self-reschedule.ts`'s `pollComposedSource` returns a tagged VALUE with `E = never` (classified in the cycle body, unchanged). `examples/14-http-error-classification.ts` already used the die-the-step / classify-in-body strategies; only its prose was corrected. VRS: decision 0003 (#4 — corrects the earlier "keep the inner `E` flowing through `run`"), 03-effect-runtime / 04-error-boundary specs, the guide handbook, and a DEFERRED typed-failure-transport `run` note (an encoded `fail(E)` journaled via an error schema). No dependency changes.

packages/@overeng/notion-datasource-sync/docs/vrs/capability-gaps.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ public `INSERT INTO changes` is not part of the current e2e acceptance surface.
8989

9090
### G. Multi-data-source databases
9191

92-
| Operation | Support | Guard if blocked | Promotion criteria (if fail-closed) |
93-
| ------------------------------------------------------------------------ | ----------- | ---------------------------- | ------------------------------------------------------------------------------- |
94-
| `sync --from-notion` against a database with multiple child data sources | FAIL-CLOSED | `MultiDataSourceUnsupported` | Per-data-source file naming scheme + cross-DS query/relation semantics modeled. |
92+
| Operation | Support | Guard if blocked | Promotion criteria (if fail-closed) |
93+
| ----------------------------------------------------------- | ----------- | ---------------------------- | ------------------------------------------------------------------------------- |
94+
| `track` against a database with multiple child data sources | FAIL-CLOSED | `MultiDataSourceUnsupported` | Per-data-source file naming scheme + cross-DS query/relation semantics modeled. |
9595

9696
## Current Fail-Closed Boundaries
9797

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Track is the adoption verb
2+
3+
Initial adoption of an existing Notion data source into a local SQLite workspace
4+
uses `notion db track <data-source-id-or-database-url> <workspace-root>`.
5+
Established reconciliation uses `notion db sync <workspace-root>`.
6+
7+
## Status
8+
9+
accepted
10+
11+
## Considered Options
12+
13+
- `sync --from-notion`: fewer top-level verbs, but makes `sync` accept both
14+
remote identities and established local workspace roots.
15+
- `establish`: precise, but uncommon as a CLI verb and inconsistent with
16+
NotionMD.
17+
- `track`: names the durable relationship, keeps adoption separate from
18+
established reconciliation, and aligns with NotionMD.
19+
20+
## Consequences
21+
22+
`track` is remote-to-local only and never mutates Notion. `sync` operates only on
23+
established local workspaces and preserves the local-capture-first invariant.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Init, pull, and push are internal phases
2+
3+
Datasource sync exposes adoption (`track`), inspection (`status`), reconciliation
4+
(`sync` / `sync --watch`), export, conflict resolution, forget, restore, and
5+
doctor commands. Init, pull, and push remain implementation phases inside the
6+
reconcile engine, not public commands.
7+
8+
## Status
9+
10+
accepted
11+
12+
## Considered Options
13+
14+
- Public `init`/`pull`/`push`: exposes mechanical phases, but asks users to pick
15+
a direction and makes partial bindings/product states easier to create.
16+
- Public `sync` only for established reconciliation: keeps the normal workflow on
17+
the guarded local-capture-first loop.
18+
19+
## Consequences
20+
21+
Public writes flow through `sync`, `sync --watch`, conflict resolution, forget,
22+
restore, or adoption. Phase-level behavior stays observable through progress,
23+
structured output, spans, and dry-run plans.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Authority is surface and event based
2+
3+
Datasource sync does not use NotionMD's `source: local | remote | shared`
4+
frontmatter model. Its authority model is per surface and event based: Notion is
5+
fresh observed remote state, the SQLite event log is durable local authority for
6+
accepted intents/outbox/conflicts/tombstones, and public replica tables are
7+
intent-entry and projection surfaces.
8+
9+
## Status
10+
11+
accepted
12+
13+
## Considered Options
14+
15+
- Import NotionMD Mirror/Shared terminology: consistent naming across packages,
16+
but incorrectly suggests single-source overwrite modes for a bidirectional
17+
SQLite control plane.
18+
- Keep datasource-specific authority vocabulary: matches the event log, outbox,
19+
guarded materialization, and no-silent-LWW requirements.
20+
21+
## Consequences
22+
23+
The CLI can share verbs such as `track`, `status`, `sync`, and `sync --watch`
24+
with NotionMD, but datasource-sync keeps its own authority vocabulary. Public
25+
docs must explain authority through surfaces, observations, intents, events,
26+
outbox commands, and guarded materialization rather than source modes.

packages/@overeng/notion-datasource-sync/docs/vrs/glossary.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ row-membership or deletion authority; projected read-only as `debug_*`.
2727

2828
## Sync surfaces and identity
2929

30+
**Authority model**:
31+
The cross-cutting rule for where each fact's authority lives. Datasource-sync
32+
authority is per surface and event based, not a file-level source mode. Notion is
33+
fresh observed remote state; the SQLite event log is durable local authority for
34+
accepted local facts; public replica tables are intent-entry/projection surfaces;
35+
materialization is guarded output.
36+
_Avoid_: importing NotionMD `source: local | remote | shared` semantics.
37+
3038
**Surface**:
3139
The smallest independently-hashed unit a write targets — a single property value,
3240
a page body, or the schema. Conflicts and base hashes are per-surface.

packages/@overeng/notion-datasource-sync/docs/vrs/intuition.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ decision.
2424
Notion database
2525
shared human workspace
2626
|
27-
| notion db sync --from-notion
27+
| notion db track
2828
v
2929
<database-id>.sqlite
3030
local working copy
@@ -147,7 +147,7 @@ unit of local state for one Notion database.
147147
Start by establishing the local replica:
148148

149149
```sh
150-
notion db sync --from-notion <database-url-or-data-source-id> ./notion-workspace
150+
notion db track <database-url-or-data-source-id> ./notion-workspace
151151
```
152152

153153
Inspect the data:

0 commit comments

Comments
 (0)