diff --git a/docs/superpowers/evidence/pre-commit-prettier-isolated-scope-2026-05-14.json b/docs/superpowers/evidence/pre-commit-prettier-isolated-scope-2026-05-14.json new file mode 100644 index 0000000..c553442 --- /dev/null +++ b/docs/superpowers/evidence/pre-commit-prettier-isolated-scope-2026-05-14.json @@ -0,0 +1,27 @@ +{ + "intent": "Isolate the pre-push prettier check in its own systemd-run scope so prettier's Node memory budget is independent of the outer 4 GB pre-push cgroup's accumulated page cache from pytest/mypy/pylint/bandit. Eliminates the SIGTERM that aborted force-pushes despite a tightened file scope.", + "scope": [ + "scripts/run_prettier_capped.sh (new wrapper)", + "meta/.pre-commit-config.yaml prettier hook (mirrors-prettier -> local language: system)", + "Non-goal: changing prettier's check semantics or coverage on first-party files" + ], + "changes": [ + "Added scripts/run_prettier_capped.sh that wraps `prettier --check` in `systemd-run --user --scope --collect -p MemoryMax=1G -p MemorySwapMax=0` with NODE_OPTIONS=--max-old-space-size=768, falling back to a direct invocation if systemd-run is unavailable.", + "Replaced the mirrors-prettier repo hook with a `repo: local` hook calling the wrapper; same types_or/exclude as before so coverage is unchanged." + ], + "verification": [ + { + "command": "scripts/run_prettier_capped.sh README.md", + "result": "pass", + "evidence": "`Checking formatting...\\nAll matched files use Prettier code style!` exit=0 from inside a fresh systemd-run scope." + } + ], + "risks": [ + "Requires prettier on PATH (currently provided by the user's global nvm install); CI must install prettier separately or fall back path executes.", + "If systemd-run is unavailable on a contributor's machine, the wrapper still runs prettier directly without the memory cap." + ], + "rollback": [ + "git revert restores the mirrors-prettier repo hook.", + "Delete scripts/run_prettier_capped.sh if no longer referenced." + ] +} diff --git a/meta/.pre-commit-config.yaml b/meta/.pre-commit-config.yaml index 42bc7bc..1123261 100644 --- a/meta/.pre-commit-config.yaml +++ b/meta/.pre-commit-config.yaml @@ -326,13 +326,16 @@ repos: # =========================================================================== # CHECK JSON/YAML/TOML formatting (runs on push only — slow Node.js startup) # =========================================================================== - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v4.0.0-alpha.8 + - repo: local hooks: - id: prettier + name: prettier (capped scope) + # Wrapper runs prettier inside its own systemd-run scope so its + # memory budget is independent of the outer pre-push cgroup that + # has already accumulated page cache from pytest/mypy/pylint. + entry: scripts/run_prettier_capped.sh + language: system types_or: [yaml, json, markdown] - # Skip vendored/mirrored content and large generated reports so the - # pre-push Node heap stays well under the cgroup memory cap. exclude: >- (?x)^( Bash/.*| diff --git a/scripts/run_prettier_capped.sh b/scripts/run_prettier_capped.sh new file mode 100755 index 0000000..4df89e4 --- /dev/null +++ b/scripts/run_prettier_capped.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# Run prettier --check inside its own systemd-run scope so its memory +# budget is independent of the outer pre-push cgroup (which has already +# accumulated page-cache footprint from pytest/mypy/pylint/bandit). +# +# Falls back to a direct invocation when systemd-run is unavailable +# (CI / containers without systemd user instance). +set -euo pipefail + +if [ $# -eq 0 ]; then + exit 0 +fi + +# Cap Node heap on top of the cgroup limit for belt-and-braces safety. +export NODE_OPTIONS="${NODE_OPTIONS:-} --max-old-space-size=768" + +if command -v systemd-run >/dev/null 2>&1 \ + && systemctl --user is-active --quiet default.target 2>/dev/null \ + || command -v systemd-run >/dev/null 2>&1; then + exec systemd-run --user --scope --quiet --collect \ + -p MemoryMax=1G \ + -p MemorySwapMax=0 \ + -- prettier --check "$@" +fi + +exec prettier --check "$@"