Repository navigation
Define stable Squad agent identity provenance - #2066
Conversation
🛫 PR Readiness Check
PR Scope: 📦🔧 Mixed (product + infrastructure)
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 20 commits — consider squashing before review |
| ✅ | Not in draft | Ready for review |
| ❌ | Branch up to date | dev is 6 commit(s) ahead — rebase recommended |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | Changeset file found |
| ✅ | Scope clean | |
| ✅ | No merge conflicts | No merge conflicts |
| ✅ | Copilot threads resolved | 0 active Copilot thread(s) resolved (2 outdated skipped) |
| ✅ | CI passing | All checks passing |
Files Changed (53 files, +9030 −481)
| File | +/− |
|---|---|
.changeset/agent-identity-provenance.md |
+25 −0 |
.changeset/reject-legacy-revision-tokens.md |
+5 −0 |
.changeset/strict-casting-durability.md |
+6 −0 |
.changeset/strict-casting-readers.md |
+5 −0 |
.squad-templates/casting-registry.json |
+4 −0 |
.squad/casting/registry.json |
+22 −18 |
docs/src/content/docs/concepts/agent-identity-provenance.md |
+188 −0 |
docs/src/navigation.ts |
+1 −0 |
packages/squad-cli/src/cli/commands/doctor.ts |
+10 −4 |
packages/squad-cli/src/cli/commands/export.ts |
+8 −7 |
packages/squad-cli/src/cli/commands/health.ts |
+4 −5 |
packages/squad-cli/src/cli/commands/import.ts |
+92 −20 |
packages/squad-cli/src/cli/core/cast.ts |
+189 −50 |
packages/squad-cli/src/cli/core/upgrade.ts |
+43 −30 |
packages/squad-cli/templates/casting-registry.json |
+4 −0 |
packages/squad-sdk/src/casting/agent-provenance.ts |
+704 −0 |
packages/squad-sdk/src/casting/durable-registry.ts |
+1498 −0 |
packages/squad-sdk/src/casting/index.ts |
+55 −11 |
packages/squad-sdk/src/config/init.ts |
+40 −19 |
packages/squad-sdk/src/config/team-capabilities.ts |
+35 −15 |
packages/squad-sdk/src/presets/index.ts |
+291 −72 |
packages/squad-sdk/src/presets/scaffold.ts |
+373 −80 |
packages/squad-sdk/src/tools/index.ts |
+1 −3 |
packages/squad-sdk/templates/casting-registry.json |
+4 −0 |
scripts/check-agent-binding.mjs |
+361 −6 |
scripts/validate-gh-aw-cast.mjs |
+289 −7 |
templates/casting-registry.json |
+4 −0 |
test/agent-provenance.test.ts |
+498 −0 |
test/cast-parser.test.ts |
+122 −1 |
test/casting-durable-registry.test.ts |
+970 −0 |
test/casting-registry-template.test.ts |
+34 −0 |
test/casting.test.ts |
+76 −1 |
test/check-agent-binding.test.ts |
+89 −2 |
test/cli/doctor.test.ts |
+28 −1 |
test/cli/export-import.test.ts |
+203 −8 |
test/cli/health-command.test.ts |
+79 −9 |
test/cli/init-upgrade-parity.test.ts |
+20 −2 |
test/cli/state-mcp.test.ts |
+11 −7 |
test/cli/upgrade.test.ts |
+30 −9 |
test/fixtures/agent-provenance/cases.json |
+232 −0 |
test/gh-aw-activation-artifact-integrity.test.ts |
+166 −2 |
test/gh-aw-bootstrap-workflow.test.ts |
+50 −2 |
test/gh-aw-cast-validator.test.ts |
+447 −4 |
test/gh-aw-quality.test.ts |
+4 −2 |
test/init-scaffolding.test.ts |
+10 −8 |
test/init-sdk.test.ts |
+3 −3 |
test/presets.test.ts |
+1142 −2 |
test/state-backend.test.ts |
+15 −9 |
test/team-capabilities-lifecycle.test.ts |
+153 −5 |
test/template-sync.test.ts |
+53 −27 |
| ... | +3 more files |
Total: +9030 −481
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
🔴 Impact Analysis — PR #2066Risk tier: 🔴 CRITICAL 📊 Summary
🎯 Risk Factors
📦 Modules Affecteddocs (2 files)
root (8 files)
scripts (2 files)
squad-cli (7 files)
squad-sdk (9 files)
squad-state (1 file)
templates (1 file)
tests (23 files)
|
🏗️ Architectural Review
Automated architectural review — informational only. |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The SDK provenance parser is currently more permissive than the documented/validated v1 contract (required fields and avatar path confinement), which can lead to consumers silently accepting malformed producer state.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (2)
What changed in this PR
This PR introduces a versioned, producer-owned “agent identity provenance” contract in .squad/casting/registry.json, aiming to make agent IDs stable across renames/recasts, support retirement tombstones, and add optional avatar references while wiring validation through SDK/CLI and GH-AW workflows.
Changes:
- Define and enforce
squad-agent-provenance/v1registry shape (schema/version, revision, timestamps, stable IDs, lifecycle/status, optional avatars). - Add SDK parsing/reconciliation APIs and wire them into CLI cast + SDK scaffold/presets.
- Add fixtures/docs and expand tests + GH-AW validators to cover the new contract.
| File | Description |
|---|---|
| workflows/squad.md | Updates cast validator SHA and documents the new provenance registry semantics. |
| workflows/squad-bootstrap.md | Updates validator SHA and bootstrap contract text to reference v1 provenance requirements. |
| workflows/shared/squad-cast-validator.mjs | Tightens registry validation to require v1 provenance fields and avatar path constraints. |
| test/gh-aw-quality.test.ts | Updates expected embedded validator SHA in the compiled workflow security contract test. |
| test/gh-aw-cast-validator.test.ts | Updates fixtures and expectations to match v1 provenance registry + SHA changes. |
| test/gh-aw-bootstrap-workflow.test.ts | Updates bootstrap workflow fixtures to emit v1 provenance registry shape. |
| test/fixtures/agent-provenance/cases.json | Adds fixture cases for valid/partial/unsupported provenance registries (including avatar). |
| test/cast-parser.test.ts | Adds coverage ensuring IDs are preserved across display-name changes and revision increments. |
| test/agent-provenance.test.ts | Adds SDK-level contract tests for parsing/reconciliation behavior and collision rules. |
| templates/casting-registry.json | Updates template registry to include v1 provenance root fields. |
| scripts/validate-gh-aw-cast.mjs | Mirrors GH-AW registry validation updates for local validation tooling. |
| packages/squad-sdk/templates/casting-registry.json | Updates SDK-shipped template registry to v1 provenance root fields. |
| packages/squad-sdk/src/presets/scaffold.ts | Switches preset scaffolding to reconcile via provenance registry API (and fail on malformed JSON). |
| packages/squad-sdk/src/casting/index.ts | Exposes provenance APIs/types from the SDK casting entrypoint. |
| packages/squad-sdk/src/casting/agent-provenance.ts | Implements the v1 provenance parser/reconciler and associated types/errors. |
| packages/squad-cli/templates/casting-registry.json | Updates CLI template registry to include v1 provenance root fields. |
| packages/squad-cli/src/cli/core/cast.ts | Wires CLI casting to reconcile provenance registry, preserve stable IDs, and tombstone/move retired agents. |
| docs/src/content/docs/concepts/agent-identity-provenance.md | Adds consumer-facing contract documentation for agent identity provenance v1. |
| .squad-templates/casting-registry.json | Updates canonical Squad templates registry to include v1 provenance root fields. |
| .changeset/agent-identity-provenance.md | Adds changeset bumping SDK/CLI minor versions for the new provenance contract and APIs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const displayName = typeof value.display_name === 'string' | ||
| ? value.display_name.trim() | ||
| : typeof value.persistent_name === 'string' | ||
| ? value.persistent_name.trim() | ||
| : ''; | ||
| const persistentName = typeof value.persistent_name === 'string' | ||
| ? value.persistent_name.trim() | ||
| : displayName; | ||
| const role = typeof value.role === 'string' ? value.role.trim() : ''; | ||
| const universe = typeof value.universe === 'string' ? value.universe.trim() : ''; | ||
| const status = value.status; | ||
| const createdAt = value.created_at; | ||
| const updatedAt = value.updated_at ?? value.created_at; |
| Avatar references are optional and restricted to `.squad/agents/`. When the | ||
| field is absent, stale, inaccessible, or malformed, render no avatar. Do not |
|
Refs bradygaster/squadcaster#45 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes bradygaster/squadcaster#45 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Refs #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
0098d10 to
e9a2b17
Compare
|
Revision ready for fresh independent rereview at The revision closes the three blockers: concurrency-safe atomic preset registry updates with conflict retry; complete fail-closed Validation: 620 focused tests pass; SDK/CLI typecheck and builds pass; docs lint passes. Full suite: 9,161 passed with nine unrelated known worktree/external-state or compiled-baseline failures. @copilot review |
|
Exact-current-head rereview requested for frozen SHA This head adds commits Exact-head validation: SDK build and SDK/CLI typecheck pass; 689 focused tests pass; GitHub required full test and gh-aw strict compile checks pass. No further push or merge pending review. @copilot review |
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The final tree retains the independently validated ABA-safe lock and roll-forward pair transaction implementation. Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Harden legacy casting generation proof, validate pair commits before mutation, and report structured preset rollback uncertainty. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Reject outgoing history references to unknown registry agents before mutation and capture exact scaffold-written bytes for rollback comparison. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use the registry candidates' immutable normalized IDs in preset history snapshots and cover noncanonical agent basenames. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Closes #2066 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
squad init and team casting failed on Windows with "EPERM: operation not permitted, fsync" (regression from github#2066). - flushDirectory() fsynced directory handles after each rename, which Windows rejects. Skip it on win32; the file-level fsync already ran. - The lock publishes by renaming a candidate dir onto registry.lock. Windows reports a rename onto an existing directory as EPERM, not ENOTEMPTY/EEXIST, so a contended lock crashed instead of waiting. Treat win32 EPERM as contention in the sync and async acquirers, and name the last publish error in the timeout so a real permission problem isn't blamed on a phantom writer. - Lock release retries the quarantine rename on transient win32 EPERM/EACCES/EBUSY (antivirus holding a fresh owner.json) for up to 1s, since a leftover registry.lock.recovery blocks every later writer. Deleting the already-quarantined copy is best-effort on win32. - A blocked quarantine delete could leave registry.lock.released-* folders in .squad/casting/ with no later cleanup. Release now sweeps abandoned lock quarantines while holding the recovery guard; guard quarantines are swept only once older than the stale-lock age. Tests: an emulated-Windows suite runs on any host, including the ubuntu-only CI; each fix turns it red when reverted. The retry and delete tests run for EPERM, EACCES and EBUSY. Child-process tests import the module via a file:// URL so the existing durability suite also runs on Windows. Closes github#2106 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
squad init and team casting failed on Windows with "EPERM: operation not permitted, fsync" (regression from #2066). - flushDirectory() fsynced directory handles after each rename, which Windows rejects. Skip it on win32; the file-level fsync already ran. - The lock publishes by renaming a candidate dir onto registry.lock. Windows reports a rename onto an existing directory as EPERM, not ENOTEMPTY/EEXIST, so a contended lock crashed instead of waiting. Treat win32 EPERM as contention in the sync and async acquirers, and name the last publish error in the timeout so a real permission problem isn't blamed on a phantom writer. - Lock release retries the quarantine rename on transient win32 EPERM/EACCES/EBUSY (antivirus holding a fresh owner.json) for up to 1s, since a leftover registry.lock.recovery blocks every later writer. Deleting the already-quarantined copy is best-effort on win32. - A blocked quarantine delete could leave registry.lock.released-* folders in .squad/casting/ with no later cleanup. Release now sweeps abandoned lock quarantines while holding the recovery guard; guard quarantines are swept only once older than the stale-lock age. Tests: an emulated-Windows suite runs on any host, including the ubuntu-only CI; each fix turns it red when reverted. The retry and delete tests run for EPERM, EACCES and EBUSY. Child-process tests import the module via a file:// URL so the existing durability suite also runs on Windows. Closes #2106 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Tamir Dresher <tamir.dresher@gmail.com> Co-authored-by: Brady Gaster <41929050+bradygaster@users.noreply.github.com>


Summary
.squad/casting/registry.jsonas the producer-ownedsquad-agent-provenance/v1contractConsumer contract
Squadcaster should use the registry object key as stable agent ID and
display_namefor presentation.persistent_nameremains an equal compatibility alias. Missing or malformed provenance means identity is unavailable; do not infer from owner, assignee, author, reviewer, actor, branch, or roster display. Optional avatars require a separate repository content fetch and must remain under.squad/agents/{id}/.Validation
Refs bradygaster/squadcaster#45