Skip to content

fix: bash-spec-renderer#72

Merged
satyaborg merged 1 commit into
mainfrom
fix/bash-spec-renderer
Jun 19, 2026
Merged

fix: bash-spec-renderer#72
satyaborg merged 1 commit into
mainfrom
fix/bash-spec-renderer

Conversation

@satyaborg

Copy link
Copy Markdown
Owner

Bash Spec Renderer

Generated by devloop --create-pr.

Problem

Devloop is intended to stay dependency-light, but the bundled devloop-spec skill currently ships and invokes skills/devloop-spec/scripts/render.py for Markdown-to-HTML companion files. That makes Python part of the spec-rendering path, contradicts the desired Bash/HTML/CSS boundary, and forces installer/tests/docs to preserve a non-shell renderer.

Outcome

The spec companion renderer is implemented in Bash. Rendering a Markdown spec still writes a sibling .html file, but no Python file or Python command is required. Specs without Mermaid produce static HTML/CSS only. Specs with mermaid fenced code blocks include a browser-side Mermaid v11 module import from jsDelivr so diagrams can render when the HTML is opened with network access.

Acceptance Criteria

AC1: skills/devloop-spec/scripts/render.py is removed or no longer installed, and no repository test, README example, or skill instruction invokes python3 ...render.py.
AC2: A Bash renderer exists under skills/devloop-spec/scripts/, is executable, accepts exactly one Markdown path argument, writes a sibling .html, and prints that path on success.
AC3: Running the renderer fixture in scripts/devloop_test.sh proves that regular specs generate light themed HTML, ## inside fenced code does not become a section, and HTML-sensitive fenced content is escaped.
AC4: A renderer fixture containing a mermaid fence produces <pre class="mermaid"> output and injects the Mermaid v11 ESM import exactly once.
AC5: A renderer fixture without a mermaid fence produces no Mermaid script tag.
AC6: Installed Codex and Claude skill copies contain the Bash renderer and do not contain the removed Python renderer.
AC7: bash scripts/devloop_test.sh passes.

Review Trail

Review rounds and the final report are posted as PR comments below.


Latest commit: b5ebdfc

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
devloop b5ebdfc Commit Preview URL

Branch Preview URL
Jun 18 2026, 04:28 AM

@satyaborg

Copy link
Copy Markdown
Owner Author

Devloop Review Round 1

  • Verdict: ACCEPT

Review 1

Verdict: ACCEPT

Acceptance matrix

Criterion Status Implementation evidence Test evidence
AC1 PASS render.py deleted (diff: skills/devloop-spec/scripts/render.py mode 100755 -> /dev/null); README.md:52, skills/devloop-spec/SKILL.md:19,165 now point at render.sh; no python3 invocation remains. git grep python3 returns none; devloop_test.sh:195 green command uses render.sh; absence asserted at devloop_test.sh:1182,1187.
AC2 PASS render.sh is new file mode 100755; arity guard render.sh:4 ([ "$#" -ne 1 ] -> exit 2); sibling output render.sh:18 (${src_base%.*}.html); atomic write + path print render.sh:403-405. devloop_test.sh:150 (-x check), :207-212 (0-arg and 2-arg both rejected), :213-214 (HTML created), :221-222 (output path equals expected sibling).
AC3 PASS Light theme CSS render.sh:259 (--bg: #ffffff); section split skips fenced lines render.sh:347-361 (in_fence gate before ^##); html_escape render.sh:44-50. devloop_test.sh:215 (light theme), :216 (fenced ## not a <summary>), :217 (&lt;/pre&gt;&lt;script&gt;...&amp; escaped), :218 (post-fence paragraph stays in section).
AC4 PASS render_code_block emits <pre class="mermaid"> render.sh:112-114; single import via has_mermaid flag render.sh:312-317, :395-397, print_mermaid_script v11 ESM render.sh:305-310. devloop_test.sh:250 (<pre class="mermaid">), :251-252 (escaped pass-through), :253 (count_occurrences ... == 1).
AC5 PASS Trailing script only printed when has_mermaid set render.sh:395-397; native <details> means no other script tag is emitted. devloop_test.sh:220 (not_contains "mermaid.esm.min.mjs" for the non-Mermaid fixture).
AC6 PASS Installer copies whole skill tree skill_helpers.sh:130 (cp -R "$source/.") and wipes dest first skill_helpers.sh:111 (rm -rf "$dest"), so deleted render.py cannot survive an upgrade. devloop_test.sh:1181-1182 (Codex copy has render.sh, lacks render.py), :1186-1187 (Claude copy same).
AC7 PASS n/a bash scripts/devloop_test.sh exits 0; full run ends with ok - 100% project function coverage.

Engineering quality matrix

Area Status Evidence
Correctness PASS html_escape orders & first render.sh:44-50, so entities are not double-escaped; fence state is tracked both in the section splitter (render.sh:347-361) and render_blocks (render.sh:146-191); atomic temp+mv write (render.sh:19,403). All fixtures render as asserted.
Test quality PASS Assertions verify rendered outcomes, not internals: light theme, fenced-heading safety, escaping, Mermaid <pre>, conditional import, exact import count, and output path. Arity failures and absence-of-Python are checked. Spec test plan fully covered.
Maintainability PASS awk is decomposed into small named functions (trim, html_escape, render_list, render_code_block, render_section); CSS is a single block. ~400 lines but readable.
Architecture boundaries PASS Renderer stays self-contained under skills/devloop-spec/scripts/; the main devloop runtime report path is untouched, matching the spec "Out" list.
Simplicity PASS Native <details>/<summary> removes the toggle JavaScript the Python version shipped; Mermaid handling is a single flag plus one print function.
Security PASS No eval; the spec path is passed as a quoted awk file operand; all body text and the source path are HTML-escaped before output; temp file is created beside the target (not in shared /tmp).
Operational safety PASS set -euo pipefail; output written to "$out_path.tmp.$$" then mv (atomic); trap cleanup EXIT removes the temp on failure; non-zero exits for bad arity (2) and missing file (1).

Review flags

  • Silent decision: absent - The Bash+awk choice, the rendered subset, native <details>, and Mermaid pass-through-after-escaping are all recorded in the track "Design tradeoffs" and match the spec Scope/Constraints.
  • Scope drift: absent - Changes are confined to the spec'd files (render.py, render.sh, SKILL.md, README.md, devloop_test.sh). The added count_occurrences test helper exists solely to satisfy AC4's exact-once assertion.
  • Missing test: absent - Every item in the spec test plan (renderer path, no installed render.py, conditional Mermaid injection, fenced-heading safety, HTML escaping) has a targeted assertion.

Findings

None.

Missing tests

None. (The spec test plan and all seven acceptance criteria have targeted assertions. See Notes for optional, non-blocking hardening.)

Fix instructions

None.

Notes

  • Scope: the renderer intentionally renders the spec subset and escapes inline text rather than formatting it. The spec Behavior happy path states the HTML shows "escaped text," and inline code/bold/italic/links are not in the Scope "In" list, so the loss of the Python renderer's inline styling is spec-sanctioned, not a regression against this spec. Practical consequence for the user: real specs that use `inline code`, **bold**, or [links](url) will now display the literal Markdown punctuation. If inline rendering is wanted later, it belongs in a follow-up spec.
  • Optional hardening (not required by this spec, not blocking): two spec Behavior edge cases have implementations but no assertions - missing-file (render.sh:10-13, exit 1) and unclosed-fence rendering (render_code_block render.sh:106-108). The arity edge case is tested; these two are not. A one-line negative test for the missing-file path would mirror the existing arity checks.
  • Trivial cleanup (not blocking): the standalone a { ... } CSS rule (render.sh:289) is now dead since no <a> is emitted (the footer uses plain <span>); the inline-specific parts of the code { ... } rule are likewise unused.
  • Upgrade safety verified: because devloop_install_skills_to_dir runs rm -rf "$dest" before copying (skill_helpers.sh:111), an existing user upgrading from 0.5.1 will have the old render.py removed, so AC6 holds on upgrade as well as on clean install.
  • Verification rerun this pass: bash scripts/devloop_test.sh -> exit 0 with ok - 100% project function coverage; git grep confirms no python3, no mermaid@10/mermaid.min.js, and no render.py invocation remain in tracked files.

@satyaborg

Copy link
Copy Markdown
Owner Author

Devloop Final Report

Field Value
Final status accepted
Pass count 1 / 5
Final verdict ACCEPT
PR URL #72
Branch fix/bash-spec-renderer

Acceptance Matrix Summary

Acceptance matrix

Criterion Status Implementation evidence Test evidence
AC1 PASS render.py deleted (diff: skills/devloop-spec/scripts/render.py mode 100755 -> /dev/null); README.md:52, skills/devloop-spec/SKILL.md:19,165 now point at render.sh; no python3 invocation remains. git grep python3 returns none; devloop_test.sh:195 green command uses render.sh; absence asserted at devloop_test.sh:1182,1187.
AC2 PASS render.sh is new file mode 100755; arity guard render.sh:4 ([ "$#" -ne 1 ] -> exit 2); sibling output render.sh:18 (${src_base%.*}.html); atomic write + path print render.sh:403-405. devloop_test.sh:150 (-x check), :207-212 (0-arg and 2-arg both rejected), :213-214 (HTML created), :221-222 (output path equals expected sibling).
AC3 PASS Light theme CSS render.sh:259 (--bg: #ffffff); section split skips fenced lines render.sh:347-361 (in_fence gate before ^##); html_escape render.sh:44-50. devloop_test.sh:215 (light theme), :216 (fenced ## not a <summary>), :217 (&lt;/pre&gt;&lt;script&gt;...&amp; escaped), :218 (post-fence paragraph stays in section).
AC4 PASS render_code_block emits <pre class="mermaid"> render.sh:112-114; single import via has_mermaid flag render.sh:312-317, :395-397, print_mermaid_script v11 ESM render.sh:305-310. devloop_test.sh:250 (<pre class="mermaid">), :251-252 (escaped pass-through), :253 (count_occurrences ... == 1).
AC5 PASS Trailing script only printed when has_mermaid set render.sh:395-397; native <details> means no other script tag is emitted. devloop_test.sh:220 (not_contains "mermaid.esm.min.mjs" for the non-Mermaid fixture).
AC6 PASS Installer copies whole skill tree skill_helpers.sh:130 (cp -R "$source/.") and wipes dest first skill_helpers.sh:111 (rm -rf "$dest"), so deleted render.py cannot survive an upgrade. devloop_test.sh:1181-1182 (Codex copy has render.sh, lacks render.py), :1186-1187 (Claude copy same).
AC7 PASS n/a bash scripts/devloop_test.sh exits 0; full run ends with ok - 100% project function coverage.

Engineering Quality Summary

Engineering quality matrix

Area Status Evidence
Correctness PASS html_escape orders & first render.sh:44-50, so entities are not double-escaped; fence state is tracked both in the section splitter (render.sh:347-361) and render_blocks (render.sh:146-191); atomic temp+mv write (render.sh:19,403). All fixtures render as asserted.
Test quality PASS Assertions verify rendered outcomes, not internals: light theme, fenced-heading safety, escaping, Mermaid <pre>, conditional import, exact import count, and output path. Arity failures and absence-of-Python are checked. Spec test plan fully covered.
Maintainability PASS awk is decomposed into small named functions (trim, html_escape, render_list, render_code_block, render_section); CSS is a single block. ~400 lines but readable.
Architecture boundaries PASS Renderer stays self-contained under skills/devloop-spec/scripts/; the main devloop runtime report path is untouched, matching the spec "Out" list.
Simplicity PASS Native <details>/<summary> removes the toggle JavaScript the Python version shipped; Mermaid handling is a single flag plus one print function.
Security PASS No eval; the spec path is passed as a quoted awk file operand; all body text and the source path are HTML-escaped before output; temp file is created beside the target (not in shared /tmp).
Operational safety PASS set -euo pipefail; output written to "$out_path.tmp.$$" then mv (atomic); trap cleanup EXIT removes the temp on failure; non-zero exits for bad arity (2) and missing file (1).

Implementation Summary

  • Final branch: fix/bash-spec-renderer
  • Final commit: b5ebdfc
  • Commit message: fix: bash-spec-renderer

Commit References

  • pass 1 b5ebdfc fix: bash-spec-renderer (README.md, scripts/devloop_test.sh, skills/devloop-spec/SKILL.md, skills/devloop-spec/scripts/render.py, skills/devloop-spec/scripts/render.sh)

Tests Run

  • Verification hook log: not configured
  • Review test evidence: see the acceptance matrix summary above.

Residual Risk

  • No blocking residual risk was recorded by the final review.

@satyaborg satyaborg marked this pull request as ready for review June 19, 2026 06:45
@satyaborg satyaborg merged commit ccfc0a6 into main Jun 19, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant