Decisions - barocss/barocss-hub GitHub Wiki
Format: D-NNN title / context / decision / evidence / date.
- Context: A node is deleted on one replica while it is concurrently moved on another (#4, Repository-Semantics §2.5).
- Decision: Option A. The concurrent move revives the node out of TRASH, and a conflict is recorded so the delete's intent stays visible. A delete that causally follows the move still wins, as usual.
- Evidence: The Kleppmann et al. move-op convergence proof carries over (Discussion #6). Option B (delete wins) loses that proof. A also fits "never silently discard concurrent intent".
- Decided by: human (2026-09-26), on the Planner's recommendation.
-
Context: Projection disambiguates name collisions as
name~shortid(Repository-Semantics §1.5, #8/#9). A later sibling may take a name equal to an existing suffixed form. - Decision: Option A. User-chosen names always win. The suffixed node falls back to the long form. Names matching the suffix pattern are not rejected.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Whether projection should treat names that differ only in case or Unicode normalization as colliding.
- Decision: Option A. Projection compares names byte-exact. Case and Unicode-normalization clashes are handled at checkout time, per OS, in a future checkout Issue.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Version model v0 (#11, Repository-Semantics §3.4 and the §3.2 "merge commit" wording). Does barocss-hub have a user-facing commit concept, and what does it mean?
-
Decision: Option B. A commit is a checkpoint with a message: a named label
{name/message, frontier, author, note}on a version. Ops keep replicating live, and a commit does not make op groups atomic. - Rejected: A (checkpoints only, no commit concept). C (commit = atomic transaction), which would require redesigning the op model.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: How versions are identified to users (#11, §3.4).
- Decision: Option A. Frontier-based version ids are shown to users as short ids, like git short SHAs, alongside checkpoint names.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Sync model (#14, escalation E-1). Do checkpoints replicate to peers automatically?
- Decision: Option b. Checkpoints are private by default. Sharing needs an explicit publish step.
- Decided by: human (2026-09-26), in the Hub Compute session.
- Context: Sync model (#14, escalation E-2). Can checkpoints be removed or renamed?
- Decision: Option c. Checkpoints themselves are never removed or renamed. Movable named refs (like branches) are added as a separate concept.
- Decided by: human (2026-09-26), in the Hub Compute session.
- Context: Sync model (#14, escalation E-3). What happens to ops rejected on receipt and their causally stuck descendants?
- Decision: Option b. Rejected ops and their stuck descendants show a visible warning naming the peer.
- Decided by: human (2026-09-26), in the Hub Compute session.
- Context: Ref model (#15, E-4).
- Decision: Refs can be deleted. Deletion is a replicated ref record, so it converges like moves.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Ref model (#15, E-5).
- Decision: New refs are local by default. Publishing is explicit, consistent with D-006.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Ref model (#15, E-6).
-
Decision: A ref-move conflict is shown as a warning in
hub status, like D-008's surfaced warnings. - Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Ref model (#15, E-7).
- Decision: Published refs allow fast-forward moves only. A move to a version that isn't a descendant of the current target is rejected locally, and history already published isn't dropped.
- Decided by: human (2026-09-26), in the Hub Planner session.
- Context: Ref model (#15, E-8).
-
Decision: On a name clash the local ref wins for the bare name, and the published ref is addressed as
published/<name>(like git'sorigin/main). - Decided by: human (2026-09-26), in the Hub Planner session.
- Context: File content v0 (#18). A file is deleted on one replica while its content is concurrently edited on another.
- Decision: Option B. The concurrent content edit revives the trashed file, consistent with D-001. A conflict is recorded so the delete's intent stays visible. The exact behavior of an edit that causally follows the delete is left to the spec.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: Ref model (E-9).
- Decision: A published ref name that was deleted can only be recreated fast-forward from its last value before the delete, so delete-then-recreate can't bypass D-012.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: Ref model (E-10).
-
Decision: Publishing local ref
nwhenpublished/nexists is a fast-forward move ofpublished/n, and a non-FF publish is rejected. The local ref is kept after publishing. - Decided by: human (2026-09-27), in the Hub Planner session.
- Context: Ref model (E-11).
-
Decision: Local ref names starting with
published/are invalid. - Decided by: human (2026-09-27), in the Hub Planner session.
- Context: D-012 while a published ref has several concurrent heads.
- Decision: A move must be fast-forward against ALL heads (its target ⊇ the merge of all head targets), so no published target is silently dropped.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: Checkout (#19), refining D-003. Names that differ only by case on a case-insensitive filesystem.
- Decision: Checkout skips only the clashing file(s), marks them "unmaterialized" (shown in status), and materializes the rest. It does not refuse the whole checkout.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: Checkout (#19). Recording changes from an older checked-out version.
-
Decision: Stays refused.
recordand mutating commands require the working directory to be at head. Recording from an older version waits for the refs/branch model and is designed together with sync. - Decided by: human (2026-09-27), in the Hub Planner session.
- Context: #21.
- Decision: CorruptBlob and DuplicateReplica are D-008 warning reasons, shown in the same warning surface.
- Decided by: human (2026-09-27), in the Hub Planner session.
-
Context: #21. Two replicas share an id (for example a copied
.hub/). - Decision: Stop syncing with that replica and tell the user to give it a new replica id. Don't keep accepting its ops.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: E-12, following D-014. A concurrent edit revives a file whose parent folder was deleted.
- Decision: The whole folder is revived (its other children return too), and a conflict is recorded. This matches the current behavior.
- Decided by: human (2026-09-27), in the Hub Planner session.
- Context: #22. Fixing a copied repo that shares a replica id.
-
Decision:
hub reidfixes a copied repo only before it has recorded under the shared id. The docs say "reid before recording". There is no re-author tool in v0. - Decided by: human (2026-09-27), in the Hub Planner session.
-
Refined by D-049 (#49): ops already recorded under the shared id can now be recovered with
barocss-hub reid --rescue(Repository-Semantics 4.13). Plainreidis still "before recording".
- Context: #22, D-022.
-
Decision: A successful reid automatically clears that repo's saved DuplicateReplica warnings. It's implemented behind
sync::REID_CLEARS_DUPLICATE_WARNINGS = true. - Decided by: human (2026-09-27), in the Hub Planner session.
After #24 (.hubignore) comes a local automatic mode, hub watch: detect file changes → auto-record → auto-sync with configured local peers. It comes before network sync and refs.
- Context: Scale work (#27, Performance).
-
Decision: Per repo: 100k files, 10 GB total, files up to 1 GB, 1M ops. 100 replicas, 20 concurrent editors.
hub status/hub record≤ 1 s. Sync after 1 week offline ≤ 1 min. - Decided by: human (2026-09-28), in the Hub Compute session.
-
Context: #28.
evaluateandcausal_pastin hub-core are O(n²). - Decision: They may be reimplemented for performance, provided observable semantics are unchanged. The old implementation is kept as a test-only oracle with an equivalence proptest.
- Decided by: human (2026-09-28), in the Hub Compute session.
- Context: develop exists only locally. Should it be pushed as a backup before core changes?
- Decision: No. develop is not backed up or pushed between releases; the user accepts the local-loss risk. Pushes happen only at release.
- Decided by: human (2026-09-28), in the Hub Planner session.
- Context: 1M-op open/status is still ~5.9 s after #31, above D-026.
-
Decision: One format bump introduces both:
- State snapshots: open reads the latest valid snapshot plus the ops after it.
- Per-batch commit markers: an op batch counts only once its commit marker is durable; an incomplete trailing batch is ignored on open.
- Migration: v0 repos are migrated automatically and crash-safely on first open by a v1 binary. A v0 binary refuses v1 repos with a clear message.
- Decided by: human (2026-09-29), in the Hub Planner session, as recommended.
- Context: The dense version-vector memory question from #28/#30.
- Decision: After the snapshot work (D-029), re-run the 100-replica scale measurement.
- Decided by: human (2026-09-29), in the Hub Planner session, as recommended.
- Context: Preparing for an alpha release.
-
Decision: MIT. Set
license = "MIT"workspace-wide in Cargo.toml, and add a LICENSE file at the repo root. - Decided by: human (2026-09-29), in the Hub Planner session.
- Context: Distribution for the alpha.
- Decision: One standard package-manager command per OS (brew on macOS, apt/deb on Linux, winget on Windows), plus prebuilt binaries and a one-line install script. Users don't need a Rust toolchain. The exact channel list and the timing per stage go in the alpha plan.
-
Open: the binary name (
hubcollides with GitHub's legacy hub CLI). - Decided by: human (2026-09-29), in the Hub Planner session.
-
Context:
hubcollides with GitHub's legacy hub CLI (open item from D-032). -
Decision: The product, package and binary name is
barocss-hub. That applies to the crate, Homebrew, winget, apt and the CLI command, replacinghub. - Decided by: human (2026-09-29), in the Hub Planner session.
- Context: Alpha scope.
-
Decision: The alpha includes a VS Code extension MVP:
- a status bar (synced, behind, conflicts)
- a conflict list with a diff of the losing side
- checkpoints in the Timeline
- watch start/stop
- a notice when an incoming change hits a file with unsaved edits
-
Prerequisites (editor core, before the extension): built-in ignore defaults for editor temp files; save-pattern tests for vim, VS Code and JetBrains;
--jsonoutput. - Decided by: human (2026-09-29), in the Hub Planner session.
- Context: #34 (sync blob transfer) and the D-030 100-replica run. Storing one file per blob costs ~140 µs per file create, ~10M files per topology.
- Decision: A blob pack format (one pack plus index per sync; a format change) is DEFERRED, to be revisited later. #34 keeps one file per blob.
- Interim (197d86a): only lacking blobs are sent, one barrier per side. Per Repository-Semantics A.2.8, blobs named by a committed op are trusted via one readdir, and only unreferenced files are hash-verified. The R=50 star pass went from 551 s to 296 s.
- Known gap: the receiver no longer detects bit rot in its own committed blobs at sync time (a decision-proposal in A.2.8).
- Consequence: D-030's full 100 × 100k star+ring run can't fit in 60 min, so D-030 stays partial until packs exist.
- Decided by: human (2026-09-29), in the Hub Compute session.
-
Context: After the rename to
barocss-hub(D-033), should the repository directory and the ignore file be renamed to match? -
Decision: No. The repository directory stays
.hub/and the ignore file stays.hubignore. There is no format migration. This closes the open item under D-033. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: Moving from local-only sync to remote sync.
-
Decision: The spec defines the §4 message exchange independently of transport and covers both SSH and HTTP. SSH is implemented first, git-like:
barocss-hub remote add origin ssh://host/path, thenbarocss-hub sync origin, with the remote side runningbarocss-hub serve --stdio. HTTP comes later. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: Remote sync topology.
- Decision: An always-on server holds a regular barocss-hub repo, and everyone syncs with it (like a git server). P2P is deferred.
- Decided by: human (2026-09-30), in the Hub Planner session.
-
Context: Automatic operation beyond
watch. - Decision: A background service that starts at login (launchd/systemd) runs watch plus remote sync for registered repos. It ships together with remote sync.
- Decided by: human (2026-09-30), in the Hub Planner session.
- Context: VS Code extension (D-034), after the real-install test (#41).
-
Decision: The extension's
autoStartWatchsetting defaults to true. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: Remote sync spec (#42, E-R1). Local peers and remotes overlapped.
-
Decision: Peers are merged into remotes. The
peercommand is removed, and same-machine folders are added withremote add <name> file://…. Existing.hub/peersis migrated automatically. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: #42, E-R2. Layout of a server-side repo with no working directory.
-
Decision: A bare repo is
<dir>/.hub/, the same as a normal repo but without a working directory. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: #42, E-R4.
-
Decision:
serve --read-onlyships in the alpha. It refuses all pushes withforbidden. - Decided by: human (2026-09-30), in the Hub Planner session.
- Context: #42, E-R5. Relation to D-039 and D-040.
- Decision: Remote sync runs automatically whenever a repo has a remote, for both the background service and the VS Code auto-start. Adding a remote is the opt-in.
- Open: E-R3 (HTTP auth).
- Decided by: human (2026-09-30), in the Hub Planner session.
- Context: #45. Rejected ops (D-008) during remote sync.
-
Decision:
syncexits with a dedicated non-zero code when the server rejects ops. watch, the background service and VS Code show a warning. - Decided by: human (2026-10), see #45.
- Context: #45. Where the remote trust store lives.
-
Decision:
~/Library/Application Support/barocss-hub/on macOS,$XDG_CONFIG_HOME/barocss-hub/on Linux. - Decided by: human (2026-10), see #45.
-
Context: #45. Review reproduced an attack through untrusted
file://remotes, reversing the earlier proposal. -
Decision:
file://remotes are trust-gated. The trust key is the canonical local repo plus the target. Peers migrated by D-041 start untrusted. - Decided by: human (2026-10), see #45.
- Context: Product direction review after Anthropic's Scion post (2026-10-13). See #47.
- Decision: Direction B. The server is the authoritative always-on replica. Clients hold only what they need and send ops in real time. The CRDT/convergence model stays: no merge, no merge queue. Short disconnects are buffered.
- Rejected: A (offline-first full replicas). C (server-side merge, like Scion).
- Spec: Online-First (Repository-Semantics §6, #47).
- Follow-up: spec Issues #47 (architecture) and #48 (text content CRDT, so concurrent edits to the same file merge). #44 (background service) is held for re-scoping under this decision.
- Decided by: human (2026-10), see #47.
- Context: #46 detects a copied repo whose ops under the shared replica id were rejected. Until now it could only exit 3 repeatedly. Refines D-024 ("reid only before recording").
-
Decision: Add
barocss-hub reid --rescue. The copied repo takes a fresh replica id and re-authors its lost edits as NEW ops under that id, on top of the server's version. Nothing is lost and the repeated exit 3 stops. - Issue: #49 (after #46, before #47/#48).
- Decided by: human (2026-10-14), in the Hub Planner session.
- Reconciled: the user first answered differently in the Hub Compute session ("suppress repeat reports only"). After reconciling, they chose both; see D-050. The Compute-session answer is superseded.
-
Spec (#49, decision-proposals for Review): re-author by effect (not op replay); intended tree = the working directory including unrecorded edits, at head; rescue set from saved equivocation warnings and reported rejections, confirmed by one sync when online; counters floored above the removed ops; staged and crash-safe with a backup in
.hub/rescue/<ts>/. See Repository-Semantics 4.13.
- Context: Under D-045, the same rejected ops would warn and exit 3 on every sync. Decided in addition to D-049.
-
Decision: Local
.hubkeeps a per-peer memory of already-reported rejected OpIds. A rejection reported once isn't re-warned and doesn't exit 3 again; only NEW rejections are reported.- The match is on the exact (OpId, rejected-payload hash, reason), so a new equivocation is never hidden.
-
warningslists suppressed rejections, andwarnings --clear-reportedresets them. -
reid --rescueclears the entries it resolves.
- Reconciled: this supersedes the earlier Hub Compute session answer ("suppress repeat reports only, no re-author"). The user chose both D-049 and D-050.
- Issue: #49.
- Decided by: human (2026-10-14), reconciled in the Hub Planner session.
- Context: #46 R2. Detecting silent divergence of copied repos (D-049) needs a content digest in Have, without breaking D-026.
-
Decision: Full-replica sync uses a per-author SHA-256 sequence digest over the shared down-closure K, in
<order, in 16,384-op chunks. It is collision-resistant, so it isn't exposed to Wagner's attack, and it stays within D-026. - Reserved: LtHash16 (BLAKE3 XOF elements, n=1024 u16) is implemented but reserved for partial replicas (#47, D_r(B)+D_r(W)). It goes on the wire later, behind its own Hello feature.
- Not done: no D-026 exception, and no on-disk LtHash cache.
-
New dependency:
blake3 =1.8.2(pinned). - Decided by: human (2026-10-14), in the Hub Compute session.
- Context: Online-First §6.12, spec #47 (direction B, D-048). All decided as recommended.
- E-B1 HTTP authentication: tokens + SSH-key login. Supersedes the E-R3 open question.
- E-B2 Offline limit: 100k ops / 1 GiB / 7 days, then refuse new records.
-
E-B3 Cache and sparse defaults:
cache_max= min(2 GiB, 10 % free disk); default sparse set = whole tree. -
E-B4 Full replicas (
hydrate, today's clone) remain supported for users, opt-in. - E-B5 Exactly one server per repo (no promotable/failover servers).
-
E-B6 No virtual checkout in the alpha; a VS Code
FileSystemProvidercomes first, later. - E-B7 Latency target: p50 ≤ 150 ms / p99 ≤ 300 ms on LAN.
-
E-B8 The HTTP API may not write without a
base. - E-B9 API history answers show the principal.
- Decided by: human (2026-10-15), in the Hub Planner session.
- Context: Text-CRDT §7.14, spec #48. All decided as recommended.
- E-T1 Line-level text CRDT in the alpha.
-
E-T2
concurrent-editnotice on by default; identical concurrent edits are not flagged. -
E-T3 Overrides via
.hubattributeswithtext/binary. - E-T4 Text size cap 8 MiB, longest-line cap 64 KiB; hard cap 64 MiB for forced text.
- E-T5 Lazy one-way format v2 upgrade at the first text op; pre-#48 binaries then refuse the repo. Meets the #33 bar.
-
E-T6 A server with text ops refuses clients without
text(upgrade-required), including their pushes. -
E-T8 No line-ending normalization;
eol=lfavailable via attributes. - E-T7: held here, then decided in D-056.
- Decided by: human (2026-10-15), in the Hub Planner session.
- Context: Online-First §6.8 / open question for #51, under direction B.
-
Decision:
file://remotes between clients remain supported. When a server exists, the guidance (docs, hints) routes users through the server. - Decided by: human (2026-10-15), in the Hub Planner session.
- Context: Text-CRDT proposed amending Repository-Semantics §1.2 (content granularity).
-
Decision: Accepted. Text files are edited per edit with a separate
TextEditop. Everything else stays whole-fileSetContent. - Decided by: human (2026-10-15), in the Hub Planner session.
- Context: Text-CRDT §7.5.3 / §7.14 E-T7, held in D-053 because answers conflicted across sessions. Reconciled by the user: as the spec proposes.
-
Decision:
checkout/watchfirst record a dirty text file as aTextEditagainstV_wd, then materialize the merged result.- The dirty bytes are durable ops before anything is written; the write is the usual atomic replace.
- Flip exception: if the file's head epoch is bytes or the dirty content isn't text, nothing is auto-recorded and checkout refuses as today. Bytes keep the #19/#26 rule.
- Acceptance: the implementation must pass kill -9 at every step with no edit loss (the #33 bar).
- Decided by: human (2026-10-15), reconciled in the Hub Planner session.