docs: revise thesis argument and verify Python walkthrough
This commit is contained in:
@@ -6,6 +6,86 @@
|
||||
urldate = {2026-09-07}
|
||||
}
|
||||
|
||||
@online{n8n-publish-2026,
|
||||
title = {Save and publish workflows},
|
||||
author = {{n8n}},
|
||||
year = {2026},
|
||||
url = {https://docs.n8n.io/build/understand-workflows/save-and-publish-workflows.md},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{n8n-executions-2026,
|
||||
title = {View executions for a single workflow},
|
||||
author = {{n8n}},
|
||||
year = {2026},
|
||||
url = {https://docs.n8n.io/build/understand-workflows/understand-executions/view-executions-for-a-single-workflow.md},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{zapier-versions-2026,
|
||||
title = {Create Zap drafts and versions},
|
||||
author = {{Zapier}},
|
||||
year = {2026},
|
||||
url = {https://help.zapier.com/hc/en-us/articles/9693520498445-Create-Zap-drafts-and-versions},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{zapier-history-2026,
|
||||
title = {View and manage your Zap history},
|
||||
author = {{Zapier}},
|
||||
year = {2026},
|
||||
url = {https://help.zapier.com/hc/en-us/articles/8496291148685-View-and-manage-your-Zap-history},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{zapier-connections-2026,
|
||||
title = {Manage your app connections},
|
||||
author = {{Zapier}},
|
||||
year = {2026},
|
||||
url = {https://help.zapier.com/hc/en-us/articles/8496290788109-Manage-your-app-connections},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{n8n-data-2026,
|
||||
title = {Understand n8n's data structure},
|
||||
author = {{n8n}},
|
||||
year = {2026},
|
||||
url = {https://docs.n8n.io/build/work-with-data/understand-n8ns-data-structure.md},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{n8n-order-2026,
|
||||
title = {Understand execution order},
|
||||
author = {{n8n}},
|
||||
year = {2026},
|
||||
url = {https://docs.n8n.io/build/flow-logic/understand-execution-order.md},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{n8n-wait-2026,
|
||||
title = {Wait},
|
||||
author = {{n8n}},
|
||||
year = {2026},
|
||||
url = {https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.wait/},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{zapier-mapping-2026,
|
||||
title = {Send data between steps by mapping fields},
|
||||
author = {{Zapier}},
|
||||
year = {2026},
|
||||
url = {https://help.zapier.com/hc/en-us/articles/8496343026701-Send-data-between-steps-by-mapping-fields},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{langgraph-interrupts-2026,
|
||||
title = {Interrupts},
|
||||
author = {{LangChain}},
|
||||
year = {2026},
|
||||
url = {https://docs.langchain.com/oss/python/langgraph/interrupts},
|
||||
urldate = {2026-09-11}
|
||||
}
|
||||
|
||||
@online{zapier-paths-2026,
|
||||
title = {Add branching logic to Zap workflows with Paths},
|
||||
author = {{Zapier}},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,13 @@
|
||||
"path": ".",
|
||||
"module": "ops",
|
||||
"registry": "registry"
|
||||
},
|
||||
{
|
||||
"kind": "python",
|
||||
"id": "local.report_runtime",
|
||||
"path": ".",
|
||||
"module": "ops",
|
||||
"registry": "registry"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
"""Execute the thesis's Python session, substituting only its transport setup."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import ast
|
||||
import re
|
||||
from collections.abc import Coroutine
|
||||
from pathlib import Path
|
||||
from typing import Any, cast
|
||||
|
||||
import pytest
|
||||
|
||||
from wf_client import App, Deployment, Run
|
||||
from wf_client.protocols import WorkflowClientPort
|
||||
from wf_config import load_workflow_config
|
||||
from wf_server.config import build_workflow_server_from_workflow_config
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
THESIS = ROOT / "docs/thesis/system-design-implementation.md"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_thesis_python_session_preserves_report_and_repair(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
||||
) -> None:
|
||||
"""Catch broken displayed bindings, client calls, and missing saved results.
|
||||
|
||||
Execute trusted repository Markdown, not submitted workflow/user text.
|
||||
No operations or persistence are mocked: only the displayed HTTP connection
|
||||
is replaced by the real API in process. This does not test the HTTP adapter.
|
||||
"""
|
||||
config = load_workflow_config(ROOT / "examples/report_workflow/wf.config.json")
|
||||
config.server.store.root = tmp_path / "store"
|
||||
server = build_workflow_server_from_workflow_config(config)
|
||||
app = App._from_port(cast(WorkflowClientPort, server.api))
|
||||
monkeypatch.chdir(ROOT)
|
||||
|
||||
manuscript = THESIS.read_text(encoding="utf-8")
|
||||
chapter = manuscript.split("# Case Study: Deterministic Report Workflow\n", 1)[1]
|
||||
chapter = chapter.split("\n# Evaluation\n", 1)[0]
|
||||
blocks = re.findall(r"^```python\n(.*?)^```", chapter, re.MULTILINE | re.DOTALL)
|
||||
assert blocks, "The case study must contain an executable Python session"
|
||||
session = "\n".join(blocks)
|
||||
connection = 'app = App.from_http_jsonrpc("http://127.0.0.1:8771/rpc")'
|
||||
assert session.count(connection) == 1, (
|
||||
"Review the documented transport substitution"
|
||||
)
|
||||
session = session.replace(connection, "app = supplied_app")
|
||||
namespace: dict[str, Any] = {"supplied_app": app}
|
||||
# The session does not import future annotations; do not inherit this file's
|
||||
# compiler flags and accidentally change Pydantic's model construction.
|
||||
code = compile(
|
||||
session,
|
||||
str(THESIS),
|
||||
"exec",
|
||||
flags=ast.PyCF_ALLOW_TOP_LEVEL_AWAIT,
|
||||
dont_inherit=True,
|
||||
)
|
||||
await cast(Coroutine[Any, Any, None], eval(code, namespace))
|
||||
|
||||
run = namespace["run"]
|
||||
assert isinstance(run, Run)
|
||||
assert run.status == "completed"
|
||||
deployment = namespace["deployment"]
|
||||
assert isinstance(deployment, Deployment)
|
||||
assert deployment.bindings["local.report"] == "local.report_runtime"
|
||||
stored = await server.api.inspect_run(run_id=run.run_id)
|
||||
output = stored["output"]
|
||||
assert output is not None
|
||||
assert output["report"]["title"] == "Weekly Project Update"
|
||||
assert len(output["report"]["action_items"]) == 3
|
||||
assert output["markdown"].startswith("# Weekly Project Update")
|
||||
diagnostic = capsys.readouterr().out
|
||||
assert "invalid_source_path" in diagnostic
|
||||
assert "output[0].path" in diagnostic
|
||||
assert namespace["trace"].frames
|
||||
Reference in New Issue
Block a user