Skip to content

Commit 29f169f

Browse files
fix(clone): address PR #15 P1s — workflow detail GET + remap snapshot
- WorkflowPhase now does list → per-id GET → POST like other phases, so source_settings/destination_settings JSON blobs (carrying connector UUIDs) aren't dropped by stripped list serializers. - RemapTable.resolve_any iterates over a snapshot to avoid `dictionary changed size during iteration` against a concurrent record() from sibling workers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 876861f commit 29f169f

3 files changed

Lines changed: 23 additions & 2 deletions

File tree

src/unstract/clone/context.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ def resolve(self, entity: str, src_uuid: str) -> str | None:
7979
return self._table.get(entity, {}).get(src_uuid)
8080

8181
def resolve_any(self, src_uuid: str) -> str | None:
82-
for mapping in self._table.values():
82+
# Snapshot to avoid `RuntimeError: dictionary changed size during
83+
# iteration` when a concurrent record() inserts a new entity bucket.
84+
for mapping in list(self._table.values()):
8385
hit = mapping.get(src_uuid)
8486
if hit is not None:
8587
return hit

src/unstract/clone/phases/workflow.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,20 @@ def _clone_one(
127127
logger.info("[dry-run] would create workflow '%s' src=%s", name, src_id)
128128
return
129129
else:
130-
remapped = remap_uuids(src, self.ctx.remap)
130+
# List endpoints serve stripped payloads (e.g. AdapterListSerializer
131+
# omits adapter_metadata_b); workflow detail carries the JSON blobs
132+
# source_settings / destination_settings that embed connector UUIDs.
133+
try:
134+
src_detail = self.ctx.source.get_workflow(src_id)
135+
except Exception as e:
136+
logger.exception(
137+
"Failed to GET source workflow %s detail: %s", name, e
138+
)
139+
with lock:
140+
result.failed += 1
141+
result.errors.append(f"GET source detail {name}: {e}")
142+
return
143+
remapped = remap_uuids(src_detail, self.ctx.remap)
131144
payload = build_post_payload(remapped, self._writable)
132145
try:
133146
tgt = self.ctx.target.create_workflow(payload)

tests/clone/test_workflow_phase.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ def list_workflows(self, *, name: str | None = None):
5353
result = [w for w in result if w["workflow_name"] == name]
5454
return list(result)
5555

56+
def get_workflow(self, workflow_id: str) -> dict:
57+
for w in self.workflows:
58+
if w["id"] == workflow_id:
59+
return dict(w)
60+
raise KeyError(workflow_id)
61+
5662
def list_tool_instances(self, *, workflow_id: str | None = None) -> list[dict]:
5763
if workflow_id is None:
5864
return list(self.tool_instances)

0 commit comments

Comments
 (0)