"""Export must not carry the stale inline output.files snapshot when a workspace exists. output.files is frozen at creation (v1); the agent edits land on disk (v2). serialize() used to ship the v1 snapshot alongside the v2 disk copy, so an imported app reverted every edited file (new files survived since they were never in the snapshot). With a workspace, disk is the single source of truth; only true flat apps (no workspace) still carry the inline copy.""" import uuid import pytest from backend.apps.outputs import workspace_io from backend.apps.outputs.models import Output from backend.apps.swarm.entities import apps as apps_mod from backend.apps.swarm.entities.apps import AppExportable class P_Ctx: pass @pytest.fixture def p_ws_root(tmp_path, monkeypatch): root = tmp_path / "ws" root.mkdir() out = tmp_path / "out" out.mkdir() monkeypatch.setattr(apps_mod, "OUTPUTS_WORKSPACE_DIR", str(root)) monkeypatch.setattr(workspace_io, "DATA_DIR", str(out)) return root def p_make_app(ws_root, *, workspace: bool) -> str: wsid = uuid.uuid4().hex if workspace else None if wsid: folder = ws_root / wsid folder.mkdir() (folder / "app.py").write_text("print('v1')\n") o = Output( name="Demo", description="", icon="view_quilt", input_schema={"type": "object", "properties": {}, "required": []}, files={"app.py": "print('v1')\n"}, workspace_id=wsid, session_id=None, ) workspace_io.save(o) return o.id def test_workspace_app_export_omits_stale_inline_files(p_ws_root): oid = p_make_app(p_ws_root, workspace=True) o = workspace_io.load_output(oid) folder = p_ws_root / o.workspace_id # agent edit -> v2 on disk: modify app.py + add new.py (output.files stays v1) (folder / "app.py").write_text("print('v2 EDITED')\n") (folder / "new.py").write_text("print('v2 NEW')\n") exp = AppExportable.load(oid) payload = exp.serialize(P_Ctx()) disk = exp.files() # the stale v1 snapshot must NOT ride along assert payload["files"] == {}, "workspace app must not export the frozen output.files snapshot" # disk (v2) is what travels, both the edit and the new file assert disk["workspace/app.py"] == b"print('v2 EDITED')\n" assert disk["workspace/new.py"] == b"print('v2 NEW')\n" def test_flat_app_without_workspace_still_carries_inline_files(p_ws_root): oid = p_make_app(p_ws_root, workspace=False) exp = AppExportable.load(oid) payload = exp.serialize(P_Ctx()) # no workspace -> inline files ARE the source, must survive export assert payload["files"] == {"app.py": "print('v1')\n"}