From 07a036926294e3b47d6c9fb45c8421f18ab17304 Mon Sep 17 00:00:00 2001 From: Hisenberg Date: Wed, 16 Sep 2026 10:54:33 +0200 Subject: [PATCH] feat: Move internal files to .pyro/ Render plan, dependencies, scenarios and requirement lists move out of the project root and plain_module/tests into .pyro/, one subfolder per module so later modules no longer overwrite earlier requirement lists. plain_sections.py --output now creates missing parent folders. Co-Authored-By: Claude Fable 5.1 --- .gitignore | 1 + README.md | 1 + skills/render-spec/SKILL.md | 27 ++++++++++---------- skills/render-spec/scripts/plain_sections.py | 12 ++++++--- tests/run_plain_sections_tests.py | 8 +++++- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 58ac1fe..036fb42 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ **/conformance_tests/ **/dist **/__pycache__/ +**/.pyro/ diff --git a/README.md b/README.md index 51b7fa7..035d2e9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ in dependency order, and writes: * intermediate implementation code to `plain_module/code/` * conformance tests to `plain_module/tests/` * the target module's output to `dist/` +* internal working files (render plan, dependencies, scenarios, requirement lists) to `.pyro/` ## Installation diff --git a/skills/render-spec/SKILL.md b/skills/render-spec/SKILL.md index 129e9c8..c9a4d86 100644 --- a/skills/render-spec/SKILL.md +++ b/skills/render-spec/SKILL.md @@ -45,9 +45,10 @@ Inputs artifacts are: * specs of and the modules it requires or imports, including referenced files inside the specs. Generated artifacts are: -* :RenderPlan: is a table listing all the modules for rendering and current render state. :RenderPlan: lives in `./render-plan.md`. +* :RenderPlan: is a table listing all the modules for rendering and current render state. :RenderPlan: lives in `./.pyro/render-plan.md`. * :plainImplementationCode: lives under `./plain_module/code`. Every module is rendered into this same folder, each building on top of the previously rendered ones. * :ConformanceTests: are living under `./plain_module/tests`. +* Internal working files (dependencies, per-module scenarios and requirements) live under `./.pyro`. ### Available tools and paths @@ -84,16 +85,16 @@ Gather all :plainImplementationReqs: and :plainTestReqs: from all specs of the m * ` "/scripts/plain_sections.py" --include-filename impl-reqs ` * ` "/scripts/plain_sections.py" --include-filename test-reqs ` -Write a list of all the required dependencies for implementation and for tests into `dependencies.md` file. Verify all the all the dependendencies are present and update the list. +Write a list of all the required dependencies for implementation and for tests into `.pyro/dependencies.md` file. Verify all the all the dependendencies are present and update the list. -Report with a message showing the `dependencies.md`. +Report with a message showing the `.pyro/dependencies.md`. ## Step 4: Rendering Render every module yourself - never delegate any module to a subagent, Agent/Task tool or workflow. -Before rendering the first module, create the folders `plain_module/code` and `plain_module/tests` (skip any that already exist). +Before rendering the first module, create the folders `plain_module/code`, `plain_module/tests` and `.pyro` (skip any that already exist). Load the :RenderPlan: and for every module follow precisely the steps: @@ -104,27 +105,27 @@ Run the command with helper script, where are the module's spec followed ` "/scripts/plain_sections.py" all ` The output of this command are all the necessary specs for succesfully rendering this module. -Write exhaustive conformance test scenarios for every :plainFunctionality: of the 's spec into `plain_module/tests/scenarios-.md`. +Write exhaustive conformance test scenarios for every :plainFunctionality: of the 's spec into `.pyro//scenarios.md`. * Scenarios should exhaustively test every :plainFunctionality: and should include :AcceptanceTests:. * Get the 's :AcceptanceTests: with ` "/scripts/plain_sections.py" acc-tests ` and cover every one of them. Write the lists of requirements using the helper script, where are module's spec plus the specs of its imported modules: -* impl. reqs: ` "/scripts/plain_sections.py" impl-reqs --output plain_module/tests/impl-reqs.md` -* test reqs: ` "/scripts/plain_sections.py" test-reqs --output plain_module/tests/test-reqs.md` +* impl. reqs: ` "/scripts/plain_sections.py" impl-reqs --output .pyro//impl-reqs.md` +* test reqs: ` "/scripts/plain_sections.py" test-reqs --output .pyro//test-reqs.md` Both lists hold the requirements verbatim - never paraphrase, reorder or drop any of them. ### Step 4.2: Implement code and tests Report with a message "Step 4.2: Implementation of ". -All the implementation code must be put in the self-contained `plain_module/code` folder. Nothing outside of `plain_module` folder can be touched during this step. +All the implementation code must be put in the self-contained `plain_module/code` folder. Nothing outside of `plain_module` and `.pyro` folders can be touched during this step. -Implement all :plainFunctionality: of specs while respecting all the requirements written in `plain_module/tests/impl-reqs.md`. +Implement all :plainFunctionality: of specs while respecting all the requirements written in `.pyro//impl-reqs.md`. Implement :UnitTests:. Implement :ConformanceTests: covering all test scenarios: -* Read all test scenarios from `plain_module/tests/scenarios-.md`. -* Read test requirements in `plain_module/tests/test-reqs.md`. +* Read all test scenarios from `.pyro//scenarios.md`. +* Read test requirements in `.pyro//test-reqs.md`. * Implement the conformance tests covering all test scenarios and respecting test requirements into the `plain_module/tests` folder. ### Step 4.3: Tests verification @@ -137,11 +138,11 @@ If any tests are failing, go back to the implementation step (4.2), debug it and ### Step 4.4: Reqs verification Report with a message "Step 4.4: Reqs verification of ". -Read the list `plain_module/tests/impl-reqs.md` and for every item: +Read the list `.pyro//impl-reqs.md` and for every item: * Review if the implementation respects it. * Add checkbox with checked/unchecked status to the item. -Read the list `plain_module/tests/test-reqs.md` and for every item: +Read the list `.pyro//test-reqs.md` and for every item: * Review if the conformance tests respect it. * Add checkbox with checked/unchecked status to the item. diff --git a/skills/render-spec/scripts/plain_sections.py b/skills/render-spec/scripts/plain_sections.py index b94b91a..7f2b8c3 100644 --- a/skills/render-spec/scripts/plain_sections.py +++ b/skills/render-spec/scripts/plain_sections.py @@ -15,10 +15,11 @@ # section's own marker so the sections stay distinguishable. `>` comment lines are always # dropped. With --include-filename each body is preceded by a "## " heading. # -# --output (or --output=) writes the result to instead of stdout, so -# callers never need shell redirection. Windows PowerShell 5.1 writes UTF-16LE for `>` and -# `>>`, which corrupts files that later steps read back, so redirecting here rather than in -# the calling shell keeps the output UTF-8/LF on every platform. Warnings stay on stderr. +# --output (or --output=) writes the result to instead of stdout, creating +# missing parent folders, so callers never need shell redirection. Windows PowerShell 5.1 +# writes UTF-16LE for `>` and `>>`, which corrupts files that later steps read back, so +# redirecting here rather than in the calling shell keeps the output UTF-8/LF on every +# platform. Warnings stay on stderr. # # Portability: the standard library only, Python 3.8+, no shell and no awk - so the same # command line works from sh, PowerShell and cmd alike. Everything is written as bytes to @@ -303,6 +304,9 @@ def main(argv): handle = None else: try: + parent = os.path.dirname(out) + if parent and not os.path.isdir(parent): + os.makedirs(parent) handle = open(out, "wb") except (IOError, OSError): error("cannot write %s" % out) diff --git a/tests/run_plain_sections_tests.py b/tests/run_plain_sections_tests.py index d08774c..030d60e 100644 --- a/tests/run_plain_sections_tests.py +++ b/tests/run_plain_sections_tests.py @@ -81,8 +81,14 @@ def run_suite(tmp): ok("--output= matches stdout byte for byte") else: bad("--output= matches stdout byte for byte") + via_nested = os.path.join(tmp, "no", "such", "dir", "x") + assert_rc("--output creates missing parent folders", 0, "--output", via_nested, "all", SAMPLE) + if read(via_nested) == via_stdout: + ok("--output into new folders matches stdout byte for byte") + else: + bad("--output into new folders matches stdout byte for byte") assert_rc("--output to unwritable path exits 1", 1, - "--output", os.path.join(tmp, "no", "such", "dir", "x"), "defs", SAMPLE) + "--output", os.path.join(via_nested, "y"), "defs", SAMPLE) # 5b. The written file is UTF-8 with LF endings on every platform. This is the reason # --output exists: PowerShell's own `>` would hand later steps UTF-16LE with CRLF.