Skip to content

refactor(reconcile): extract provider-agnostic core primitive (#20) - #38

Merged
lex00 merged 1 commit into
mainfrom
refactor/reconcile-core
Jun 19, 2026
Merged

lex00 merged 1 commit into
mainfrom
refactor/reconcile-core

Conversation

@lex00

@lex00 lex00 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Re #20. Does the in-repo abstraction now (the substantive engineering); the cross-repo lift into @intentius/chant is the remaining mechanical step (see note below).

What

Extracts the GitHub-agnostic reconcile machinery into src/reconcile/core.ts — the provider-agnostic primitive #20 describes:

  • Change-set model (ChangeKind, FieldChange, ChangeSetEntry, ChangeSet, DiffOptions)
  • Generic diffing: deepEqual, diffFields, and diffCollection — the selective-by-omission + ownership-gated-delete pattern that every keyed-collection diff shared
  • Summary/render: summarizeChangeSet, renderChangeSet
  • Guardrail framework: resolveRenames, removalDeltaCap, runGuardrailChecks (pluggable checks)

diff.ts and guardrails.ts now consume and re-export core (public API unchanged — all existing imports keep resolving). The GitHub-specific layer stays put: the diff() entry point, Live* types, the bespoke object/embedded-child diffs, and the member-aware guardrails (adminFloor/requiredAdmins/requireSelf).

Consolidation

The uniform collection diffs — members, team-members, team-repos, rulesets, environments, secrets, variables — are rewritten on diffCollection, net-removing ~430 lines of near-duplicate iterate/create/update/ownership-delete code. Bespoke diffs (org-settings, repo-security, repos/teams with embedded children, dependabot, repo-baseline, token sweeps) keep their shapes but use the core helpers.

Why this, and not the chant move

The chant repo is checked out locally but outside this task's working directories, and adding a ./reconcile subpath there means touching another package + cutting a release for warden to consume via its ^0.8.2 dep. That's a cross-boundary, hard-to-reverse step I'm not taking unprompted. This PR makes that lift mechanical (copy core.ts into chant, swap warden's imports) by isolating the seam now. #20 stays open for the actual cross-repo extraction.

Verification

  • npx tsc --noEmit clean
  • npm test green (468 tests; +18 in core.test.ts; all pre-existing tests unchanged and passing)
  • Action bundle rebuilt for the CI freshness check

🤖 Generated with Claude Code

Pulls the GitHub-agnostic reconcile machinery into src/reconcile/core.ts:
change-set model, generic diffFields + diffCollection (selective-by-
omission + ownership-gated deletes), summarize/render, and the guardrail
framework (resolveRenames, removalDeltaCap, runGuardrailChecks). diff.ts
and guardrails.ts now consume + re-export it (public API unchanged);
the uniform collection diffs (members, team members/repos, rulesets,
environments, secrets, variables) are rewritten on diffCollection,
net-removing ~430 lines of duplication. core surface exported from index.

This is the seam to lift into @intentius/chant's ./reconcile subpath when
a second git-host warden exists; until then warden consumes it locally.

+18 core unit tests (468 total). Action bundle rebuilt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lex00
lex00 merged commit 61cd864 into main Jun 19, 2026
2 checks passed
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.

1 participant