Skip to content

Add branches and tags refs package with transparent authoring#82

Draft
hahn-kev-bot wants to merge 18 commits into
mainfrom
branches-and-tags
Draft

Add branches and tags refs package with transparent authoring#82
hahn-kev-bot wants to merge 18 commits into
mainfrom
branches-and-tags

Conversation

@hahn-kev-bot

Copy link
Copy Markdown
Collaborator

Summary

  • Adds the optional SIL.Harmony.Refs package with branch/tag entities, checkout-aware materialization, and RefsDataModel for checkout switching and ref lifecycle operations.
  • Introduces transparent authoring and post-apply roll-forward hooks in core DataModel via ICommitInterceptor and ICommitAppliedListener, so clients author/sync through DataModel while refs behavior is applied automatically.
  • Slims RefsDataModel to checkout + ref lifecycle only (CreateBranch/CreateTag/MoveTag/MergeBranch, plus ListBranches/ListTags), with comprehensive coverage moved under SIL.Harmony.Tests/Refs.

Test plan

  • dotnet test harmony.sln --filter "FullyQualifiedName!~Performance" (222 passed)
  • Review branch checkout views (main vs branch visibility and interleaving)
  • Review tag checkout and roll-forward after local apply and sync
  • Review merge-branch rematerialization behavior
  • Smoke-test downstream client migration to DataModel.AddChange + RefMetadata.SetAssignment

hahn-kev and others added 18 commits July 10, 2026 14:19
Co-authored-by: Cursor <cursoragent@cursor.com>
Lets optional refs later exclude commits from snapshots without changing sync storage or forking SnapshotWorker.

Co-authored-by: Cursor <cursoragent@cursor.com>
Lets apps opt in to Branch entities via AddHarmonyRefs without changing core Harmony for clients that do not need refs.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep Any CPU only and list Refs alongside the other projects without the x64/x86 platform churn from dotnet sln add.

Co-authored-by: Cursor <cursoragent@cursor.com>
RefsDataModel stamps immutable harmony.branchId from local checkout (overridable), and AddHarmonyRefs filters those commits out of main materialization until merge or a branch checkout view lands.

Co-authored-by: Cursor <cursoragent@cursor.com>
Switching RefsDataModel between main and a branch updates the materialization filter and regenerates snapshots so queries show main plus that branch only.

Co-authored-by: Cursor <cursoragent@cursor.com>
RefsDataModel now reads and updates filter.Checkout only, so authoring and materialization cannot diverge.

Co-authored-by: Cursor <cursoragent@cursor.com>
MergeBranchChange incorporates a branch on main; the checkout filter expands the apply window from the earliest branch commit so snapshots replay in HybridDateTime order without rewriting commit metadata.

Co-authored-by: Cursor <cursoragent@cursor.com>
…window.

Issue 12 follow-up: read merge entity ids from ChangeEntities via JSON ->>, then expand rematerialization from the first ordered commit without a second commits query.

Co-authored-by: Cursor <cursoragent@cursor.com>
Issue 13: Tag entities point at commits; tag checkout rematerializes as-of the tip (including branch tips), rejects authoring by default, and rolls forward with CheckoutChanged on local move or RefsDataModel.SyncWith.

Co-authored-by: Cursor <cursoragent@cursor.com>
Scope GetEntityIdsForChangeType to the repository's ignoreChangesAfter tip
by joining ChangeEntities to Commits with the same at-or-before-tip bound
ScopedDbContext applies (one query, null-tip guard keeps unscoped behaviour).

With that, CheckoutMaterializationFilter drops its per-commit as-of loop and
_tipBranchId: it holds a single _asOfTip commit and derives incorporated
branches via GetScopedRepository(tip).GetEntityIdsForChangeType.

Move AllowAuthoringOnTagToMain onto CrdtConfig; RefsDataModel now reads it
from options. Drop the CheckoutChanged event and RefCheckoutChangedEventArgs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a core, refs-agnostic ICommitInterceptor invoked once per
locally-authored commit at DataModel.NewCommit (the single author choke
point; sync-applied commits bypass it). DataModel resolves it optionally
from DI, mirroring ICommitMaterializationFilter.

Refs registers CheckoutCommitInterceptor, which stamps the current
checkout's branch id or rejects tag authoring — so clients can author via
DataModel.AddChange directly without the RefsDataModel wrapper. A public
RefMetadata.SetAssignment helper + harmony.branchAssigned marker carries an
explicit per-call override that the interceptor honours; RefsDataModel's own
assignment path now sets the marker so its commits skip re-derivation.

Implements ticket 04 of refs-transparent-authoring.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tors

The harmony.branchAssigned marker only needs to signal the authoring
interceptor at author time; it should not pollute stored/synced metadata.
The interceptor now consumes it (RefMetadata.ConsumeAssignment reads and
removes it) before the commit is persisted, and the marker key is private.

DataModel now resolves IEnumerable<ICommitInterceptor> (GetServices) and
invokes each in registration order, so multiple interceptors compose.

Adds tests ExplicitAssignmentMarkerIsNotPersisted and
AllRegisteredInterceptorsAreInvoked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Core defines a refs-agnostic ICommitAppliedListener, resolved lazily by
DataModel and fired after the apply transaction commits (and its lock is
released) in Add, AddManyChanges, and AddRangeFromSync — all genuine
applies, never in RegenerateSnapshots, so a listener that rematerializes
cannot re-enter. Notifying after the lock is released also avoids a
deadlock on persistent databases, whose apply lock is shared and
non-reentrant, when the listener's roll-forward opens its own repository.

The ticket-04 refs interceptor becomes CheckoutRefsHandler, now
implementing both extension points: as the interceptor it stamps the
checkout's branch assignment; as the listener it rolls an active tag
checkout forward when the tip moved. It resolves DataModel lazily via
IServiceProvider to break the roll-forward -> DataModel cycle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Authoring and sync now go through DataModel directly; the interceptor and post-apply listener own assignment stamping and tag roll-forward.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Use the new CreateBranch helper throughout refs-oriented coverage so tests exercise the public refs lifecycle surface instead of constructing branch changes directly.

Co-authored-by: Cursor <cursoragent@cursor.com>
Group refs-specific coverage under SIL.Harmony.Tests/Refs so the refs surface and behavior tests are easier to browse without mixing them into the core test root.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ab8f66b9-2610-43f3-9df7-9647353012f1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch branches-and-tags

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@myieye

myieye commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

I feel like a GH issue that provided some motivation for this big change would be worth adding as documentation.
FYI I have not reviewed the code at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants