Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
172 commits
Select commit Hold shift + click to select a range
0b97b33
Package store: event-sourced op log ⊥ projections
StachuDotNet Jul 12, 2026
9b0db39
Sync: native builtins for the op-log, blob, and conflict surface
StachuDotNet Jul 12, 2026
8edb33c
Sync: the Dark surface — engine, HTTP server, and CLI
StachuDotNet Jul 12, 2026
fae69e4
Sync: the test suite
StachuDotNet Jul 12, 2026
d6121c2
Fix `dark view`: syntaxHighlighting called a nonexistent List.collect
StachuDotNet Jul 12, 2026
41d7c3e
Sync: use Feriel throughout; drop the redundant Ocean account
StachuDotNet Jul 13, 2026
33dffb0
Seed: strip execution traces from the exported seed
StachuDotNet Jul 13, 2026
5273427
CLI: store login config next to the store, not CWD-relative
StachuDotNet Jul 13, 2026
e97ac29
Sync: a resolved conflict clears on the peer too, not just the resolver
StachuDotNet Jul 13, 2026
1365586
CLI: conflict list shows what each side set the name to, inline
StachuDotNet Jul 13, 2026
cc1ba00
cli: exit interactive views cleanly when stdin isn't a TTY
StachuDotNet Jul 13, 2026
0ba86a2
cli: conflict list/show renders the differing BODY with real names
StachuDotNet Jul 13, 2026
3232aa6
sync: re-apply resolution overlay after the incremental fold (fix div…
StachuDotNet Jul 13, 2026
2dc2189
sync: re-apply resolution overlay after the PULL's fold too (complete…
StachuDotNet Jul 13, 2026
5adf85a
cli: apps status shows running daemons, not just installed ones
StachuDotNet Jul 13, 2026
7c3681f
cli: show the committer in `dark log`
StachuDotNet Jul 13, 2026
54381ab
sync/tracing: default trace storage OFF in the shipped binary (fix un…
StachuDotNet Jul 13, 2026
c1531ad
tracing: OFF must be a true no-op — fix the second daemon disk-fill (…
StachuDotNet Jul 13, 2026
e20892f
tests: regressions for the two overnight fixes (divergence + daemon d…
StachuDotNet Jul 13, 2026
82c19dd
sync: surface the real per-peer pull error instead of "Couldn't reach"
StachuDotNet Jul 13, 2026
8222bd8
cleanup: make comments timeless (drop PR/incident narrative)
StachuDotNet Jul 13, 2026
f8c472c
conflicts: validate the keep target + report the real resolve result
StachuDotNet Jul 13, 2026
174e73d
sync: validate port/interval in the first-run dialog
StachuDotNet Jul 13, 2026
4875ac7
sync: index sync_conflicts(branch_id, location, status) for reapplyAll
StachuDotNet Jul 13, 2026
c03bffc
tests: AlphaNormalize — real idempotence check + match-binder-positio…
StachuDotNet Jul 13, 2026
b6188e9
cli: reconcile the store's Release on startup (upgrade path)
StachuDotNet Jul 13, 2026
88c314a
cli: migrate durable releases in place (preserve data), reseed only o…
StachuDotNet Jul 13, 2026
960c411
sync: surface unparseable peer ops instead of dropping them silently
StachuDotNet Jul 13, 2026
17e590e
tests: prove a durable Release migrates a store in place, preserving …
StachuDotNet Jul 13, 2026
84cecab
cli: carry the peer list forward across a reseed (upgrade papercut)
StachuDotNet Jul 13, 2026
1e8c6fe
sqlite: collapse the exec/query param split (4 builtins → 2)
StachuDotNet Jul 14, 2026
62a9eef
tests: drop the trivial EventLog testfile; rename sync-per-branch → s…
StachuDotNet Jul 14, 2026
dc27f38
PR review: reword command descriptions + tidy comments
StachuDotNet Jul 14, 2026
ba7858b
builtins: split the sync natives out of Libs/Sqlite.fs into Libs/Sync.fs
StachuDotNet Jul 14, 2026
7678107
cli: clarify the stdin non-TTY guard comment
StachuDotNet Jul 14, 2026
11df1aa
sync: route localDbPath/currentRelease through Darklang.Sync wrappers…
StachuDotNet Jul 14, 2026
e19b4e0
sync: rehome the op-log wrapper Stdlib.EventLog → Darklang.Sync.EventLog
StachuDotNet Jul 14, 2026
a586399
comments: drop the "ops ⊥ projections" branding
StachuDotNet Jul 14, 2026
954a7ef
libdb: give SQL params real names instead of one letters
StachuDotNet Jul 14, 2026
ca10ec9
libdb: trim Seed.fs comments
StachuDotNet Jul 14, 2026
ed19bad
libdb: tighten verbose comments in Inserts.fs + PackageOpPlayback.fs
StachuDotNet Jul 14, 2026
c08d926
PR review: reflow HttpClient socket comment, SQL param names in Relea…
StachuDotNet Jul 14, 2026
1a0ab39
cli: simplify store reconcile — collapse pretracking into the None pa…
StachuDotNet Jul 14, 2026
070a031
localexec: drop vestigial adoptLegacyDB from the migrator
StachuDotNet Jul 14, 2026
1ec1a97
libdb: de-dup the Release doc prose
StachuDotNet Jul 14, 2026
59bb386
builtins: fix stale Sqlite deferred-list note + tighten module doc
StachuDotNet Jul 14, 2026
692801c
builtins: return conflicts as a typed record, not an 8-string tuple
StachuDotNet Jul 14, 2026
d30ff96
builtins: trim the new registration section comments
StachuDotNet Jul 14, 2026
5f219f1
libdb: crisper Lww business case
StachuDotNet Jul 14, 2026
dd1054a
tests: split the multi-instance harness out of MultiInstance.Tests.fs
StachuDotNet Jul 14, 2026
b99687f
tests: name the three sync-test layers in SyncScenarios' doc
StachuDotNet Jul 14, 2026
d7a0dc9
tests: fold AlphaNormalize tests into Hashing, drop the branding
StachuDotNet Jul 14, 2026
b70b1d9
tests: drop the redundant sync-convergence tests from OpsProjections
StachuDotNet Jul 14, 2026
7cfd7e7
format: run scripts/formatting/format across the touched files
StachuDotNet Jul 14, 2026
13e209c
builtins: split the 599-line Sync.fs by concern
StachuDotNet Jul 14, 2026
d9a068e
tests: rewrite MultiInstance to flat root-level tests
StachuDotNet Jul 14, 2026
44d13b4
tests: flat root-level tests for Releases + OpsProjections
StachuDotNet Jul 14, 2026
bcafb18
tests: flat root-level tests for SyncScenarios
StachuDotNet Jul 14, 2026
40a4fdc
tests: de-nest Hashing — sub-groups to root-level lets
StachuDotNet Jul 14, 2026
18f3d92
format: fantomas the Sync split files
StachuDotNet Jul 14, 2026
56068c6
comments: strip noise across the branch
StachuDotNet Jul 14, 2026
36af89e
sync: fix ops lost when committed out of authoring order (across bran…
StachuDotNet Jul 14, 2026
1018531
sync: Release-4 durable migration for committed_seq (reach existing s…
StachuDotNet Jul 14, 2026
303f96d
Fix discard reverting a synced resolution (R1); harden equal-hash fol…
StachuDotNet Jul 14, 2026
cf725d0
Tighten sync review items: conflictId item_kind; linear pull-error li…
StachuDotNet Jul 15, 2026
525c4fa
tests: fail-fast on build errors; fix SyncE2E presync cursor for comm…
StachuDotNet Jul 15, 2026
6179d64
format: run scripts/formatting/format on the touched test files
StachuDotNet Jul 15, 2026
8ec7121
run-backend-tests: revert the eager up-front build
StachuDotNet Jul 15, 2026
3042304
conflicts: resolve by (location, item_kind) so one kind's resolution …
StachuDotNet Jul 15, 2026
f725d3c
sync: nudge about unreviewed conflicts on the pull line (U1)
StachuDotNet Jul 15, 2026
7aa8c96
sync: rename the `pull <url>` subcommand to `from <url>` (D2)
StachuDotNet Jul 15, 2026
3621952
rebase: `--status` distinguishes "up to date" from "behind but clean"…
StachuDotNet Jul 15, 2026
0229356
rebase: content-aware conflict detection, so a branch can't get perma…
StachuDotNet Jul 15, 2026
bb44685
compiler: airlift DarkCompiler into backend/src/LibCompiler (vendored…
StachuDotNet Jul 15, 2026
5e9534c
compiler: add guarded Builtins.Compiler as the 10th combine entry (bu…
StachuDotNet Jul 15, 2026
2afd01b
compiler: first light — compile+run pure-core from Dark, matching the…
StachuDotNet Jul 15, 2026
9d1bba7
compiler: PT->AST bridge — lower a ProgramTypes fn tree to native, no…
StachuDotNet Jul 15, 2026
d66c6bd
compiler: compile a REAL stored package fn via the bridge, matching t…
StachuDotNet Jul 15, 2026
dcc1c85
compiler: `compileFnCheck` (compilability, no run) + first ranked blo…
StachuDotNet Jul 15, 2026
14379c8
compiler: bridge whole pure call-graphs (EApply cross-fn calls)
StachuDotNet Jul 16, 2026
879f083
compiler: batch coverage sweep — the §4 bring-up loop in one process
StachuDotNet Jul 16, 2026
9dde3e0
compiler: bridge non-generic custom types (records + enums) — the 62%…
StachuDotNet Jul 16, 2026
d97688b
compiler: bridge pattern matching (EMatch) — enums become usable
StachuDotNet Jul 16, 2026
39e12ba
compiler: zero-value synthesis for record/enum params (accurate cover…
StachuDotNet Jul 16, 2026
bb50ad8
compiler: generics via monomorphization — the glue-layer gate
StachuDotNet Jul 16, 2026
841e929
compiler: bridge lists (TList / EList)
StachuDotNet Jul 16, 2026
90ed50b
compiler: bridge tuples (TTuple/ETuple) + tuple-destructuring lets
StachuDotNet Jul 16, 2026
174002d
compiler: bridge record-update + string interpolation
StachuDotNet Jul 16, 2026
016d8bc
compiler: bridge pipes (EPipe) + make type-fetch robust to non-type h…
StachuDotNet Jul 16, 2026
d1df30c
compiler: lambdas, higher-order apply, function types
StachuDotNet Jul 16, 2026
4eace84
compiler: bridge type aliases (inline to target) — big custom-type un…
StachuDotNet Jul 16, 2026
f188884
compiler: route pure builtins to the compiler's native stdlib (seam r…
StachuDotNet Jul 16, 2026
71fc01d
compiler: bridge ESelf recursion (+ thread a BridgeCtx)
StachuDotNet Jul 16, 2026
b45153d
compiler: bridge EValue — inline package constants (value closure)
StachuDotNet Jul 16, 2026
852cda6
compiler: bridge EStatement + non-variable lambda params
StachuDotNet Jul 16, 2026
40e3be7
compiler: runtime seam LIVE — compiled code invokes real builtins via…
StachuDotNet Jul 16, 2026
804a514
compiler: bridge routes effectful builtins through the host RPC seam
StachuDotNet Jul 16, 2026
b876eaf
compiler: effectful fns RUN via the daemon — full seam live end-to-end
StachuDotNet Jul 16, 2026
977b649
compiler: generalize effectful-builtin arg marshalling (Int/Bool via …
StachuDotNet Jul 16, 2026
f68f2f8
compiler: container-return marshalling — Option/Result effectful buil…
StachuDotNet Jul 16, 2026
b1842ea
compiler: arg-synthesis handles generic + recursive types (769 -> 962)
StachuDotNet Jul 16, 2026
305d336
compiler: bridge TBlob + EFloat; value closure bridges to a fixpoint …
StachuDotNet Jul 16, 2026
f355e52
compiler: widen the RPC seam to Int/Bool/Float wire types (973 -> 1038)
StachuDotNet Jul 16, 2026
b1920ee
compiler: carry Uuid/DateTime as host-opaque canonical strings (1038 …
StachuDotNet Jul 16, 2026
bec5b09
compiler: bridge bare function references as captureless closures
StachuDotNet Jul 16, 2026
a9e5561
compiler: wire-format primitives for general Dval marshalling (founda…
StachuDotNet Jul 16, 2026
dc20acf
compiler: bridge the remaining integer-literal widths
StachuDotNet Jul 16, 2026
e729a36
compiler: unify Dark Option/Result with the compiler's native types (…
StachuDotNet Jul 16, 2026
153b40a
compiler: general recursive container marshaller (Option/Result of an…
StachuDotNet Jul 16, 2026
74a6cc6
compiler: implement FileDelete (unlink) + opaque-handle model for com…
StachuDotNet Jul 16, 2026
b6d7958
compiler: daemon-side list primitives (build/walk lists via handles)
StachuDotNet Jul 16, 2026
6652f84
compiler: typed-element cons for handle lists (__listCons with type tag)
StachuDotNet Jul 16, 2026
e4ae322
compiler: route int-width + float builtins to the native stdlib (1105…
StachuDotNet Jul 16, 2026
d9cc8a6
compiler: extend native-stdlib routing — full Int64, bitwise/shift, C…
StachuDotNet Jul 16, 2026
f37903e
compiler: route Unit-arg effectful builtins through the seam (1267 ->…
StachuDotNet Jul 16, 2026
029f1ce
compiler: route Char-arg builtins through the seam (1308 -> 1314)
StachuDotNet Jul 16, 2026
5853a43
compiler: runnable-vs-compilable sweep (compile + RUN each fn, with t…
StachuDotNet Jul 16, 2026
7122822
compiler: escape newlines in run-sweep output (clean classification)
StachuDotNet Jul 16, 2026
4ad43d6
compiler: run-sweep does a differential interpreter check for scalar fns
StachuDotNet Jul 16, 2026
29068a9
compiler: run-sweep tags each line with the fn hash; normalize Unit/n…
StachuDotNet Jul 16, 2026
4b73bbf
compiler: diff-sweep skips non-deterministic fns (double-interp) + sh…
StachuDotNet Jul 16, 2026
be70e76
compiler: diff-sweep repr covers lists (match compiler's [a, b] print…
StachuDotNet Jul 16, 2026
d59db8c
compiler: arg-synthesis handles function-typed params (dummy lambda) …
StachuDotNet Jul 16, 2026
3b4db16
compiler: diff-sweep synthesizes record/enum/option zero args (broade…
StachuDotNet Jul 16, 2026
4ea0e0e
compiler: diff comparison tolerates float (0.0=0) + empty-container f…
StachuDotNet Jul 16, 2026
ca01f9e
compiler: re-enable List marshalling — the finger-tree "hang" was a h…
StachuDotNet Jul 16, 2026
547f855
compiler: perf-compare builtin + fib benchmark fixture
StachuDotNet Jul 16, 2026
9497f80
compiler: Darklang.Perf.compareEval — compile a fn value + benchmark …
StachuDotNet Jul 16, 2026
e75d622
compiler: dotted package-fn names unblock bare generic calls (1366 ->…
StachuDotNet Jul 16, 2026
af27da4
compiler: route Builtin.unwrap through to the compiler intrinsic (+12)
StachuDotNet Jul 16, 2026
0a34278
compiler: route blocked pure stdlib list fns to native equivalents (+…
StachuDotNet Jul 16, 2026
52836d5
compiler: lambda lifting can infer if-bodies and list/string bodies
StachuDotNet Jul 16, 2026
300db14
compiler: route int->float + sqrt to the compiler intrinsics
StachuDotNet Jul 16, 2026
b88d0af
compiler: applying a fn value unifies tvar params instead of demandin…
StachuDotNet Jul 16, 2026
9a5c722
compiler: fix silent corruption of every List returned by an effectfu…
StachuDotNet Jul 16, 2026
02ba43a
compiler: resolve sum-type variants scoped by their type (1678 -> 188…
StachuDotNet Jul 16, 2026
7062b08
compiler: String-keyed Dicts (the "Dict is Int64-keyed" gap was not r…
StachuDotNet Jul 16, 2026
cce571d
compiler: report WHY a package value did not bridge, + empty dict lit…
StachuDotNet Jul 16, 2026
0d4277f
compiler: record why the package-value/pipe fix cannot land yet
StachuDotNet Jul 17, 2026
be5af7d
compiler: lambda lifting can infer match-bodies (1921 -> 1977, +56)
StachuDotNet Jul 17, 2026
593dd87
compiler: a fn passed as a VALUE now resolves (1977 -> 1987)
StachuDotNet Jul 17, 2026
a92b569
compiler: dotted type names — "T_<hash>" was parsed as the type named…
StachuDotNet Jul 17, 2026
97a14e4
compiler: share package values as nullary fns, typed from their Dval
StachuDotNet Jul 17, 2026
3521045
compiler: equivalence harness — PROVE a compiled fn matches the inter…
StachuDotNet Jul 17, 2026
7870181
compiler: fix TInt args silently marshalling as STRINGS through the R…
StachuDotNet Jul 17, 2026
92fa77e
compiler: prove records + custom enums, and sample custom-type args
StachuDotNet Jul 17, 2026
90e4c5c
compiler: instantiate generic type defs when proving equivalence, and…
StachuDotNet Jul 17, 2026
1bb4f40
compiler: carry custom types INTO builtins through the RPC seam
StachuDotNet Jul 17, 2026
4fb1353
compiler: recursive serializer fns — JSON now crosses the seam
StachuDotNet Jul 17, 2026
ed7b075
compiler: un-route 3 String fns that were silently wrong on non-ASCII
StachuDotNet Jul 17, 2026
3b78cdb
compiler: Bytes through the seam — route stringToBlob, marshal TBytes…
StachuDotNet Jul 17, 2026
e5b17c4
compiler: equiv harness never emitted the RETURN type's marshaller
StachuDotNet Jul 17, 2026
d83e2af
compiler: floats cross the seam as exact bits, not as a lossy rendering
StachuDotNet Jul 17, 2026
9a8df1b
compiler: the seam truncated every multi-line ARG
StachuDotNet Jul 17, 2026
8e55b56
compiler: route Blob ARGS through the seam (+9)
StachuDotNet Jul 17, 2026
a0eb2cd
compiler: make the return decoder TOTAL — hard-fail instead of return…
StachuDotNet Jul 17, 2026
0e74a89
compiler: decode custom types in the RETURN direction (+129)
StachuDotNet Jul 17, 2026
89f10eb
compiler: Float.fromBits + lazy-safe decoders — recursive JSON now ro…
StachuDotNet Jul 17, 2026
a6b7ce1
compiler: Option/Result decoders were still If-based (+28)
StachuDotNet Jul 17, 2026
e0806d2
compiler: zeroLit emitted an unresolvable name — Bytes fns never comp…
StachuDotNet Jul 17, 2026
825511d
compiler: work around a record-literal SIGSEGV (List field + >=2-byte…
StachuDotNet Jul 17, 2026
bd26827
compiler: package values of Blob/Uuid type + Persistent blobs (+7)
StachuDotNet Jul 17, 2026
e317c2d
compiler: rtToMarshalable had no TTuple case — httpClientRequest unro…
StachuDotNet Jul 17, 2026
df5c7f7
compiler: bridge `if` without `else` as `else ()` (+4)
StachuDotNet Jul 17, 2026
5d54d87
compiler: bound the interpreter side of equivOne (priority 3, the 79 …
StachuDotNet Jul 17, 2026
dfa785b
compiler: run the interpreter's double-check BEFORE the compiled bina…
StachuDotNet Jul 17, 2026
96eee54
compiler: fix variant-tag miscompile — scope constructor + match tag …
StachuDotNet Jul 17, 2026
77b02a2
compiler: fix #26 SIGSEGV — HeapStore of a string literal clobbered RCX
StachuDotNet Jul 18, 2026
513b488
compiler: unsigned integer comparison + division/modulo (#22)
StachuDotNet Jul 18, 2026
4b4f0e4
compiler: fix float-arg miscompile — x64 FArgMoves ignored move cycles
StachuDotNet Jul 18, 2026
d153f92
compiler: route sized-int (Int8/16/32, UInt8/16/32/64) args through t…
StachuDotNet Jul 18, 2026
9f554e9
compiler: bind generic type args when synthesizing proof-harness args
StachuDotNet Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

8 changes: 6 additions & 2 deletions backend/migrations/incremental/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ order on top of `../schema.sql` and name-dedup'd via
When to add a file here vs editing `schema.sql`:

- **Edit `schema.sql`**: structural redesigns, adding a new table or
column where rebuilding from source is fine. The file is hashed +
kill-and-fill'd; data in the affected tables is lost.
column. The file is hashed; on a change the runtime does a
preserve-and-refold — it drops only the regenerable projection
tables and re-folds them from the op log, so the canonical op
log / blobs / branch+commit state survive. (A canonical-table
*shape* change still needs a Release migration — CREATE IF NOT
EXISTS can't alter an existing table.)
- **Add a file here**: data backfills, transforms, additive
alterations on populated dev/test DBs you don't want to nuke.

Expand Down
90 changes: 82 additions & 8 deletions backend/migrations/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-- final shape is what runs against an empty DB.
--
-- system_migrations_v0 (the legacy per-named-migration table) is the one
-- exception, since pre-cutover DBs are adopted via that table; created
-- exception, since legacy DBs are adopted via that table; created
-- here AND by Migrations.fs's adoptLegacyDB path.
--
-- Order: bookkeeping → branches → commits → ops → package projections →
Expand Down Expand Up @@ -58,6 +58,11 @@ CREATE TABLE IF NOT EXISTS branches (
-- (commits also references branches), but the rows are inserted in
-- dependency order at runtime; we don't add a FK constraint here.
base_commit_hash TEXT,
-- LWW stamp for base_commit_hash: the (origin_ts, op-id) of the CreateBranch/RebaseBranch that last set it.
-- Concurrent rebases of the same branch on two instances converge (later origin_ts wins, op-id breaks a tie)
-- instead of resolving by arrival order. merged_at/archived_at need no stamp — they're monotonic set-once.
base_ts TEXT NOT NULL DEFAULT '',
base_op TEXT NOT NULL DEFAULT '',

archived_at TIMESTAMP NULL, -- soft-delete; replaces hard delete
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now')),
Expand Down Expand Up @@ -89,13 +94,28 @@ CREATE INDEX IF NOT EXISTS idx_commits_branch

-- The source of truth for all package changes (branch-scoped).
CREATE TABLE IF NOT EXISTS package_ops (
id TEXT PRIMARY KEY,
id TEXT NOT NULL,
op_blob BLOB NOT NULL,
branch_id TEXT NOT NULL REFERENCES branches(id),
commit_hash TEXT REFERENCES commits(hash), -- NULL = WIP
applied INTEGER NOT NULL DEFAULT 0,
propagation_id TEXT NULL, -- direct lookup for PropagateUpdate ops
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now'))
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now')),
-- Authoring timestamp, PORTABLE across sync. A
-- locally-authored op self-stamps here at insert; a SYNCED op preserves its origin (the sync
-- receiver writes the peer's value), so every instance agrees on a given op's origin_ts and
-- max(origin_ts) picks the same divergence winner → no swap. Distinct from `created_at` (which
-- is local-insert time and differs per instance for the same op).
origin_ts TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
-- Monotonic COMMIT-order stamp (NULL while WIP), assigned when the op is committed or received. Sync reads
-- (`eventsSince`) page by this, NOT by rowid: rowid is authoring order, but an op becomes syncable only when
-- committed, which can be much later (WIP on one branch while another is committed + synced). Paging by
-- rowid would skip a late commit of an early-authored op forever; committed_seq can't.
committed_seq INTEGER,
-- Composite, not bare `id`: an identical op authored on two branches hashes equal (the id is the op's
-- content hash), so a bare-`id` INSERT OR IGNORE would drop the second and the fn would be invisible on
-- that branch. (id, branch_id) lets IGNORE catch only true within-branch repeats.
PRIMARY KEY (id, branch_id)
);
CREATE INDEX IF NOT EXISTS idx_package_ops_wip
ON package_ops(branch_id) WHERE commit_hash IS NULL;
Expand All @@ -112,9 +132,50 @@ CREATE TABLE IF NOT EXISTS branch_ops (
id TEXT PRIMARY KEY, -- content-addressed hash of the op
op_blob BLOB NOT NULL, -- serialized BranchOp
applied INTEGER NOT NULL DEFAULT 0, -- 0=pending, 1=applied (for crash recovery)
-- Authoring stamp, PORTABLE across sync (mirrors package_ops.origin_ts): a locally-authored op self-stamps,
-- a SYNCED op preserves the peer's, so a structural op (rebase) converges by CREATION time (LWW) rather than
-- by arrival order.
origin_ts TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now')),
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_branch_ops_created_at ON branch_ops(created_at);


--------------------
-- Sync conflicts + resolutions (the "LWW isn't silent" model)
--------------------
-- sync_conflicts: a LOCAL review log (NOT synced). A divergence auto-resolved by last-writer-wins at pull
-- time is recorded here so it can be reviewed + (optionally) overridden. Per-branch.
CREATE TABLE IF NOT EXISTS sync_conflicts (
id TEXT PRIMARY KEY, -- content-addressed (branch + location + candidate hashes)
branch_id TEXT NOT NULL,
location TEXT NOT NULL, -- owner.modules.name
item_kind TEXT NOT NULL, -- fn | type | value
local_hash TEXT NOT NULL, -- the content we had
incoming_hash TEXT NOT NULL, -- the content the peer sent
chosen_hash TEXT NOT NULL, -- which won (auto: last-writer-wins)
resolved_by TEXT NOT NULL, -- 'auto:last-writer-wins' | 'human'
status TEXT NOT NULL DEFAULT 'auto-resolved', -- auto-resolved | acknowledged | overridden
detected_at TIMESTAMP NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX IF NOT EXISTS idx_sync_conflicts_detected_at ON sync_conflicts(detected_at DESC);
-- markOverriddenByLocation (run per resolution on every reapplyAll, i.e. every grow/pull) filters on
-- (branch_id, location, status); without this it full-scans sync_conflicts once per stored resolution.
CREATE INDEX IF NOT EXISTS idx_sync_conflicts_branch_location
ON sync_conflicts(branch_id, location, status);

-- resolutions: SYNCED override overlay. A resolution binds a contested location to a chosen content,
-- competing in the same timestamp-LWW that orders bindings (by `at`). id is a wire-carried uuid (idempotent).
-- Effective binding = fold(package_ops)[LWW] -> apply resolutions[last-resolver-wins by `at`]. Per-branch.
CREATE TABLE IF NOT EXISTS resolutions (
id TEXT PRIMARY KEY, -- wire-carried uuid (INSERT OR IGNORE dedup)
branch_id TEXT NOT NULL,
location TEXT NOT NULL,
item_kind TEXT NOT NULL,
chosen_hash TEXT NOT NULL, -- the content this resolution binds the location to
resolved_by TEXT NOT NULL, -- 'auto:<policy>' | 'human'
at TEXT NOT NULL -- LWW stamp (same format as op origin_ts / locations)
);
CREATE INDEX IF NOT EXISTS idx_resolutions_at ON resolutions(at);


--------------------
Expand All @@ -127,23 +188,26 @@ CREATE TABLE IF NOT EXISTS package_types (
hash TEXT PRIMARY KEY,
pt_def BLOB NOT NULL,
rt_def BLOB NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
created_at TEXT NOT NULL DEFAULT (datetime('now')),
description TEXT NOT NULL DEFAULT '' -- plain-text doc comment for SQL package search
);

CREATE TABLE IF NOT EXISTS package_values (
hash TEXT PRIMARY KEY,
pt_def BLOB NOT NULL,
rt_dval BLOB, -- NULL until evaluated
value_type BLOB, -- for finding values of a given ValueType
created_at TEXT NOT NULL DEFAULT (datetime('now'))
created_at TEXT NOT NULL DEFAULT (datetime('now')),
description TEXT NOT NULL DEFAULT '' -- plain-text doc comment for SQL package search
);
CREATE INDEX IF NOT EXISTS idx_package_values_type ON package_values(value_type);

CREATE TABLE IF NOT EXISTS package_functions (
hash TEXT PRIMARY KEY,
pt_def BLOB NOT NULL,
rt_instrs BLOB NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
created_at TEXT NOT NULL DEFAULT (datetime('now')),
description TEXT NOT NULL DEFAULT '' -- plain-text doc comment for SQL package search
);

-- Content-addressed bytes (Blob refs). Dedup comes for free via PK
Expand All @@ -169,7 +233,17 @@ CREATE TABLE IF NOT EXISTS locations (
branch_id TEXT NOT NULL REFERENCES branches(id),
commit_hash TEXT REFERENCES commits(hash), -- NULL = WIP
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now')),
unlisted_at TIMESTAMP NULL -- set when a later row supersedes this one
unlisted_at TIMESTAMP NULL, -- set when a later row supersedes this one
-- The origin_ts of the op that set THIS binding — the name→authoring-time mapping that lets
-- playback order by CREATION, not arrival (timestamp-LWW). A SetName whose op was created
-- EARLIER than the current binding (an old op arriving late via sync) is stale: playback skips
-- the rebind, so the latest-by-creation name wins on every instance regardless of sync order.
origin_ts TEXT NULL,
-- What put this binding here: 'op' = the normal op-fold (incl. WIP authoring), 'resolution' = a
-- human/keep-local resolution OVERLAY. Both an overlay and a WIP binding have commit_hash NULL, so
-- without this marker `discard` (which deletes WIP by commit_hash IS NULL) would also sweep the
-- overlay and silently revert a synced resolution → divergence. `discard` excludes 'resolution'.
source TEXT NOT NULL DEFAULT 'op'
);
CREATE INDEX IF NOT EXISTS idx_locations_branch_lookup
ON locations(branch_id, owner, modules, name, item_type)
Expand Down
43 changes: 25 additions & 18 deletions backend/src/Builtins/Builtins.Cli/Libs/Stdin.fs
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,33 @@ let private readKeyOrPaste () : ConsoleKeyInfo * string option =
let isPrintable (k : ConsoleKeyInfo) =
k.KeyChar <> '\u0000' && not (Char.IsControl k.KeyChar)

let first = Console.ReadKey true
if not Console.KeyAvailable then
(first, None)
// Redirected stdin (pipe / file / `< /dev/null` / daemon) isn't a TTY, so `Console.ReadKey` throws
// InvalidOperation_ConsoleReadKeyOnFile mid-loop and crashes a full-screen view with a raw stack trace.
// Report Escape (every view treats it as "quit") so it exits cleanly instead.
if Console.IsInputRedirected then
(ConsoleKeyInfo('\u001b', ConsoleKey.Escape, false, false, false), None)
else
let sb = System.Text.StringBuilder()
let append (text : string) : unit =
sb.Append text |> ignore<System.Text.StringBuilder>
let mutable last = first
let mutable printableKey = if isPrintable first then Some first else None
pasteText first |> Option.iter append
while Console.KeyAvailable do
let k = Console.ReadKey true
last <- k
pasteText k |> Option.iter append
if isPrintable k then printableKey <- Some k
let pasted = sb.ToString()
if pasted = "" then
(last, None) // only control keys queued, e.g. a scroll

let first = Console.ReadKey true
if not Console.KeyAvailable then
(first, None)
else
(Option.defaultValue last printableKey, Some pasted)
let sb = System.Text.StringBuilder()
let append (text : string) : unit =
sb.Append text |> ignore<System.Text.StringBuilder>
let mutable last = first
let mutable printableKey = if isPrintable first then Some first else None
pasteText first |> Option.iter append
while Console.KeyAvailable do
let k = Console.ReadKey true
last <- k
pasteText k |> Option.iter append
if isPrintable k then printableKey <- Some k
let pasted = sb.ToString()
if pasted = "" then
(last, None) // only control keys queued, e.g. a scroll
else
(Option.defaultValue last printableKey, Some pasted)

let fns () : List<BuiltInFn> =
[ { name = fn "stdinReadKey" 0
Expand Down
Loading