docs: revise thesis argument and verify Python walkthrough

This commit is contained in:
lda
2026-09-11 15:12:08 +07:00 Verified
parent 04c182ba7c
commit c2cfbdcb25
4 changed files with 619 additions and 296 deletions
+80
View File
@@ -6,6 +6,86 @@
urldate = {2026-09-07} 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, @online{zapier-paths-2026,
title = {Add branching logic to Zap workflows with Paths}, title = {Add branching logic to Zap workflows with Paths},
author = {{Zapier}}, author = {{Zapier}},
File diff suppressed because it is too large Load Diff
+7
View File
@@ -27,6 +27,13 @@
"path": ".", "path": ".",
"module": "ops", "module": "ops",
"registry": "registry" "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