Skip to content

fix(casting): repair handwritten casting registries under lock with dry-run support [2/4] - #2252

Merged
tamirdresher merged 3 commits into
tamirdresher-microsoft-stack-1-client-adaptersfrom
tamirdresher-microsoft-stack-2-casting-repair
Oct 22, 2026
Merged

tamirdresher merged 3 commits into
tamirdresher-microsoft-stack-1-client-adaptersfrom
tamirdresher-microsoft-stack-2-casting-repair

Conversation

@tamirdresher

Copy link
Copy Markdown
Collaborator

Summary (Stack Layer 2 of 4 — splits #2239)

Adds repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam so repos with hand-authored .squad/casting/registry.json files normalize cleanly into the canonical committed registry/history pair.

Review fixes included in Layer 2

  • Acquires acquireCastingRegistryLock (with lstatSync symlink guards on .squad and .squad/casting) before reading registry.json, history.json, registry-history.commit.json, or team.md.
  • Writes no .handwritten.bak files by default (keepBackup is opt-in).
  • Restores exact pre-repair bytes and rethrows if commitCastingRegistryPair fails (never falls back to a fresh cast).
  • Leaves valid canonical registries and registries with existing cast history untouched.
  • Supports squad upgrade --dry-run on handwritten registries via in-memory validation without mutating disk or failing preflight.

@github-actions

Copy link
Copy Markdown
Contributor

🟡 Impact Analysis — PR #2252

Risk tier: 🟡 MEDIUM

📊 Summary

Metric Count
Files changed 7
Files added 2
Files modified 5
Files deleted 0
Modules touched 4
Critical files 2

🎯 Risk Factors

  • 7 files changed (6-20 → MEDIUM)
  • 4 modules touched (2-4 → MEDIUM)
  • Critical files touched: packages/squad-sdk/src/casting/index.ts, packages/squad-sdk/src/index.ts

📦 Modules Affected

root (1 file)
  • .changeset/squad-2-0-multi-host-clients.md
squad-cli (2 files)
  • packages/squad-cli/src/cli/core/init.ts
  • packages/squad-cli/src/cli/core/upgrade.ts
squad-sdk (3 files)
  • packages/squad-sdk/src/casting/handwritten-registry.ts
  • packages/squad-sdk/src/casting/index.ts
  • packages/squad-sdk/src/index.ts
tests (1 file)
  • test/casting-handwritten-repair.test.ts

⚠️ Critical Files

  • packages/squad-sdk/src/casting/index.ts
  • packages/squad-sdk/src/index.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 1753d7a

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 2 item(s) to address before review

Status Check Details
❌ Single commit 3 commits — consider squashing before review
✅ Not in draft Ready for review
✅ Branch up to date Up to date with tamirdresher-microsoft-stack-1-client-adapters
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean No .squad/ or docs/proposals/ files
✅ No merge conflicts No merge conflicts
✅ Copilot threads resolved 0 active Copilot thread(s) resolved (5 outdated skipped)
✅ CI passing All checks passing

Files Changed (7 files, +2029 −9)

File +/−
.changeset/squad-2-0-multi-host-clients.md +1 −1
packages/squad-cli/src/cli/core/init.ts +17 −2
packages/squad-cli/src/cli/core/upgrade.ts +59 −6
packages/squad-sdk/src/casting/handwritten-registry.ts +932 −0
packages/squad-sdk/src/casting/index.ts +16 −0
packages/squad-sdk/src/index.ts +17 −0
test/casting-handwritten-repair.test.ts +987 −0

Total: +2029 −9


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

Authoritative evidence: base-controlled pull_request_target reporter.

⚠️ Architectural review: 3 warning(s).

Severity Category Finding Files
🟡 warning bootstrap-area 4 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/clients.ts, packages/squad-cli/src/cli/core/command-help.ts, packages/squad-cli/src/cli/core/init.ts, packages/squad-cli/src/cli/core/upgrade.ts
🟡 warning export-surface Package entry point(s) modified with 114 new/changed export(s). New public API surface requires careful review for backward compatibility. packages/squad-sdk/src/index.ts
🟡 warning sweeping-refactor This PR touches 24 files (24 modified/added, 0 deleted). Large PRs are harder to review — consider splitting if possible. —

Automated architectural review — informational only.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Identity preservation, history integrity, and archive symlink handling remain unresolved.

5 open issues
What changed in this PR

Adds handwritten casting-registry recovery to the SDK and upgrade flow as layer 2 of the Squad 2.0 stack.

Changes:

  • Adds locked, transactional repair and roster backfill with archives and dry-run validation.
  • Integrates recovery into upgrade and prevents init prompts in non-interactive sessions.
  • Adds regression coverage and release notes.
File Description
test/​casting-handwritten-repair.test.ts Tests normalization, recovery, backfill, and dry runs.
packages/​squad-sdk/​src/​index.ts Exports repair APIs.
packages/​squad-sdk/​src/​casting/​index.ts Exposes casting repair utilities.
packages/​squad-sdk/​src/​casting/​handwritten-registry.ts Implements normalization, transactional repair, and backfill.
packages/​squad-cli/​src/​cli/​core/​upgrade.ts Integrates repair and preview reporting.
packages/​squad-cli/​src/​cli/​core/​init.ts Guards interactive prompts.
.changeset/​squad-2-0-multi-host-clients.md Documents recovery behavior.

Review effort: Balanced

tamirdresher pushed a commit that referenced this pull request Oct 20, 2026
… repair

- Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key
- Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting
- Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key
- Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair
- Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives

Refs #2239
Refs #2252

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
Copilot and others added 3 commits October 21, 2026 00:27
…m team.md (Layer 2)

Carves Layer 2 of #2239 targeting tamirdresher-microsoft-stack-1-client-adapters and applies all Layer 2 review fixes:
- Acquire the casting writer lock (with symlink/lstat guards) BEFORE reading registry.json, history.json, or registry-history.commit.json in repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam
- Do not leave *.handwritten.bak clutter in .squad/casting/ by default (only when options.keepBackup === true is explicitly passed)
- Restore the exact in-memory pre-repair snapshot to disk and rethrow if commitCastingRegistryPair fails (never fall back to writing a fresh cast or deleting registry-history.commit.json)
- Never touch or rewrite valid canonical registries or registries with existing cast history
- Validate handwritten registry repair in memory during `squad upgrade --dry-run` so dry-run previews succeed without mutating disk while still failing closed on corrupt/unrepairable registries
- Guard interactive prompts in `squad init` via `isInteractiveSession()`

Refs #2239

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
… backfill ids, roll-forward-safe rollback

- H3: normalize handwritten registries per record — records that already parse as valid provenance records are preserved verbatim (all fields, timestamps, per-record universe); only incomplete records get missing fields synthesized. Preserve and bump the registry revision instead of resetting it. Archive pre-repair originals under handwritten-archive-<sha256>/ by default (keepBackup: false opts out) and report backupPath.
- H4: backfillCastingRegistryFromTeam derives agent ids from the team.md Charter column (.squad/agents/<id>/charter.md) or a charter whose ## Identity name matches; rows with no provable folder fail the backfill closed with a dropped list. Fix the test that expected "b-elanna" for the belanna folder.
- M8: wrapper-less shapes only accept record values carrying name/persistent_name/display_name/role; bare-string values and non-agent metadata are reported instead of guessed. Non-Latin names, duplicate names and id collisions no longer drop silently — RepairResult.dropped is populated and the repair fails closed; squad upgrade prints the reason and each dropped entry.
- M7: commitPairWithRollback only restores the pre-repair snapshot when the commit failed before its journal became durable (never on CastingCommitInDoubtError or after a successful commit), restores via temp+fsync+rename, and attaches restore failures as cause. recoverCastingRegistryTransaction runs under the lock before the snapshot so pending journals roll forward first.
- M9: single exported hasExistingCastHistory (empty arrays/objects are not history) replaces the CLI copy; a history.json holding one Init Mode snapshot consistent with the handwritten registry is normalized instead of blocking the repair. squad upgrade --dry-run previews the team.md backfill.
- Low: strip UTF-8 BOM before JSON.parse; anchor the team.md universe regex to a line start / table cell and fail the backfill closed instead of inventing one; recommit of a manifest-mismatched pair bumps the revision and requires a readable history object.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
… repair

- Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key
- Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting
- Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key
- Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair
- Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives

Refs #2239
Refs #2252

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
@tamirdresher
tamirdresher force-pushed the tamirdresher-microsoft-stack-2-casting-repair branch from ed9b3f7 to 1753d7a Compare October 20, 2026 21:32
@tamirdresher
tamirdresher merged commit 2b75e82 into dev Oct 22, 2026
17 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.

2 participants