{ "intent": "Bring linux_configuration/scripts/single_use/install_joplin.sh under the 250-line cap, and establish the verified shell-split pattern for the remaining 83 files in that directory.", "scope": [ "linux_configuration/scripts/single_use/install_joplin.sh (299 -> 103)", "linux_configuration/scripts/single_use/lib/joplin_server.sh (new)", "docs/shell-split-recipes.md (the pattern this split established)", "Non-goal: no behaviour change; no installer step was executed" ], "changes": [ "Moved setup_duckdns and setup_joplin_server, the whole --with-server half, into lib/joplin_server.sh, sourced by the entry script before main runs.", "The lib carries a shebang and is executable, matching scripts/lib/common.sh, and deliberately omits set -euo pipefail: it is sourced, so it inherits the caller's strict mode, and repeating the boilerplate across many new libs is what feeds jscpd's duplication threshold.", "SCRIPT_DIR uses ${BASH_SOURCE[0]} rather than the repo's usual $0, because $0 is the sourcing script and breaks the moment an entry script is itself sourced. readlink -f is kept, since that is what makes the one symlinked script in the repo resolve correctly.", "Recorded in docs/shell-split-recipes.md: the enumeration of which scripts escape the repo (three copied to /usr/local/share/hosts-guard, one symlinked), the stubbed-run verification, and the lib shape that satisfies both shellcheck and the shebang-executable hook." ], "verification": [ { "command": "bash -n on the entry script and the lib; shellcheck on both", "result": "pass", "evidence": "Both clean. Recorded because these are NOT sufficient: they passed on the first version of this split, whose lib was unreachable at runtime." }, { "command": "stubbed run: copy entry + lib to a mktemp -d, sed the final `main` invocation into a `declare -F` probe, run it", "result": "fail then pass", "evidence": "First run failed with 'lib/joplin_server.sh: No such file or directory' - SCRIPT_DIR was computed from $0. Fixed to ${BASH_SOURCE[0]}; the probe then reported 'all functions defined; lib sourced correctly'. This executes the source lines and nothing else, so no installer step ran." }, { "command": "grep for the source line and resolve its path", "result": "pass", "evidence": "install_joplin.sh:74 sources $SCRIPT_DIR/lib/joplin_server.sh, which resolves to the file that exists." }, { "command": "pre-commit run --files ", "result": "fail then pass", "evidence": "check-shebang-scripts-are-executable rejected the lib, then shellcheck SC2148 rejected removing the shebang. Resolved by matching scripts/lib/common.sh (shebang + chmod +x), which is now recorded in the recipes doc so the next 83 splits do not rediscover it." }, { "command": "wc -l", "result": "pass", "evidence": "103 and 209 lines, both under the cap." } ], "risks": [ "install_joplin.sh is an installer that runs pacman/docker and writes to $HOME. It was never executed, per decision 6; the stubbed run only proves the functions are defined and the source line resolves. Whether the installer still works end-to-end is unverified and unverifiable without running it.", "The lib assumes the caller has defined info/warn/error and the JOPLIN_*/DUCKDNS_* variables. That holds because it is sourced after them, but it is an ordering dependency the file cannot enforce." ], "rollback": [ "git revert the commit; install_joplin.sh returns to 299 lines and the lib disappears.", "After rollback, re-run bash -n and shellcheck on the restored script." ] }