Skip to content

Commit 38c44ef

Browse files
committed
fix(sync): dedupe ID-seeded skill exports by effective slug
1 parent 0ebf294 commit 38c44ef

2 files changed

Lines changed: 44 additions & 5 deletions

File tree

tests/unit/test_workspace_sync_acceptance_contract.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
TABLE_RESOURCE_ADAPTER,
7272
WORKSPACE_RESOURCE_ADAPTERS,
7373
)
74+
from tracecat.workspace_sync.adapters.base import ResourceDependencyRefs
7475
from tracecat.workspace_sync.enums import SyncResourceType, VcsProvider
7576
from tracecat.workspace_sync.importer import WorkspaceResourceImportService
7677
from tracecat.workspace_sync.resources import workflow_references
@@ -1039,6 +1040,45 @@ async def test_skill_projection_rejects_ambiguous_legacy_slugs(
10391040
}
10401041

10411042

1043+
@pytest.mark.anyio
1044+
async def test_id_seeded_skill_projection_deduplicates_effective_slugs(
1045+
session: AsyncSession,
1046+
svc_role: Role,
1047+
) -> None:
1048+
"""ID-seeded partial export deduplicates expand-window effective slugs."""
1049+
workspace_id = svc_role.workspace_id
1050+
assert workspace_id is not None
1051+
exact_owner = Skill(
1052+
workspace_id=workspace_id,
1053+
slug="foo",
1054+
name="Exact owner",
1055+
description="Canonical description",
1056+
)
1057+
legacy = Skill(
1058+
workspace_id=workspace_id,
1059+
slug=None,
1060+
name="foo",
1061+
description="Legacy description",
1062+
)
1063+
session.add_all([exact_owner, legacy])
1064+
await session.flush()
1065+
1066+
projection = await SKILL_RESOURCE_ADAPTER.project_dependency_refs(
1067+
WorkspaceSyncService(session=session, role=svc_role),
1068+
ResourceDependencyRefs(local_ids={exact_owner.id, legacy.id}),
1069+
)
1070+
1071+
matching_specs = [
1072+
spec
1073+
for spec in projection.specs.values()
1074+
if isinstance(spec, SkillResourceSpec) and spec.slug == "foo"
1075+
]
1076+
assert len(matching_specs) == 1
1077+
assert matching_specs[0].name == "Exact owner"
1078+
assert matching_specs[0].description == "Canonical description"
1079+
assert [resource.local_id for resource in projection.resources] == [exact_owner.id]
1080+
1081+
10421082
async def _add_preset_version_skill_binding(
10431083
session: AsyncSession,
10441084
*,

tracecat/workspace_sync/adapters/skill.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -359,11 +359,10 @@ async def project_dependency_refs(
359359
else:
360360
stmt = stmt.where(effective_slug.in_(slugs))
361361
skills = list((await workspace_service.session.execute(stmt)).scalars().all())
362-
if slugs:
363-
skills = self._dedupe_skills_by_effective_slug(
364-
skills,
365-
requested_slugs=slugs,
366-
)
362+
skills = self._dedupe_skills_by_effective_slug(
363+
skills,
364+
requested_slugs=slugs or None,
365+
)
367366
versions_by_slug: dict[str, set[int]] = defaultdict(set)
368367
for slug, version in refs.versioned_slugs:
369368
versions_by_slug[slug].add(version)

0 commit comments

Comments
 (0)