chore: a readable version, a readable run, and one subject per file - #14
Merged
Conversation
added 5 commits
September 11, 2026 23:50
Generating a project handed the terminal several minutes of a package manager's progress bars, through which the one line that mattered β which application is being generated β never appeared at all. It now prints six step lines and ends with the commands to run next. The technique is pnpm_install's, which has captured its own output and shown it only on failure since it was written; run_quietly is that, named, so the adapter generators, post-generate hooks and service drivers can use it too. A failing step still prints everything. SCAFFOLD_VERBOSE=1 passes output through for a run that hangs rather than fails, where there is otherwise nothing to look at.
It carried the pnpm workspace, ADR-0017's supply-chain policy, the config_roots manifest, the GitHub account, the project name rule and the git commit β 545 lines whose only relation was being needed by `scaffold new`. lib/pnpm.sh takes the workspace and the policy; lib/manifest.sh takes config_roots, the CI matrix derived from it and the build targets derived from the applications. project.sh keeps what a project is made of and how it is finished, at 264 lines. cmd_new's all-typescript/mixed branch becomes join_typescript_workspace and keep_apps_standalone. It was an if/else long enough that the condition and its consequence never appeared on screen together; the decision is now eleven lines. The pair carries <rel>:<adapter> because the second branch asks the adapter whether it is typescript β 'does it have a package.json' is a different question with a different answer, and laravel-inertia is where the two part company. No behaviour change intended: both branches were exercised end to end against real generations before and after.
Capturing the generators' output moved the invocation, and three tests were reading the old text rather than the guarantee behind it. cli.bats now asserts the negative as well: no value may be handed to a shell directly, and one script runs both through mise exec. That survives the shape being rearranged, which it has now been once. service.bats asserts the failure names the service and the family β the actual requirement, since a bare 'a driver failed' sends the reader to the wrong one of eight β instead of one sentence that run_quietly rephrased.
The body check lived in ci.yml, which runs on opened and synchronize. A body that fails it is fixed by editing the body β which ci.yml does not run on β so the check stayed red for a fix that had already been made. Observed on this branch's own pull request. Its own workflow rather than adding `edited` to ci.yml: that would re-run the integration lane, twenty minutes, every time somebody touched a description.
Moving the body check to its own workflow was safe; renaming the job to `body` in the same commit was not. main requires a status check called pull-request-body, and a required check that never reports blocks every merge β including the pull request carrying the rename, which is how this was found. The name is now commented as load-bearing. Nothing in this repository records that setting, which is exactly what ADR-0004 says about the one guardrail that is not a file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Three things from the review that were left over. None blocked using the toolbox; all three were paid for on every use.
1. A version people can read.
git tagreturned nothing, soscaffold --versionanswered with a bare sha and every.scaffold.tomlrecorded one. CONTRIBUTING now says when a tag is cut and why tagging stays manual: there is no package to publish, and what a tag buys is a readable answer in--versionand in every manifest written after it β not a distribution channel.v0.1.0gets tagged on merge.2. A readable run.
scaffold newhanded the terminal several minutes of a package manager's progress bars, through which the one line that mattered β which application is being generated β never appeared at all. It now prints this:The technique is
pnpm_install's, which has captured its own output and shown it only on failure since it was written;run_quietlyis that, named, so the adapter generators, post-generate hooks and service drivers can use it too. A failing step still prints everything β there is a test for exactly that, because hiding output is only acceptable if failure shows all of it.SCAFFOLD_VERBOSE=1passes output through for a run that hangs rather than fails, where there is otherwise nothing to look at.3. One subject per file.
lib/project.shcarried the pnpm workspace, ADR-0017's supply-chain policy, theconfig_rootsmanifest, the GitHub account, the project name rule and the git commit β 545 lines whose only relation was being needed byscaffold new.lib/pnpm.shβ the workspace and the policylib/manifest.shβconfig_roots, the CI matrix derived from it, the build targets derived from the applicationslib/project.shβ what a project is made of and how it is finished, now 264 linescmd_new's all-typescript/mixed branch becomesjoin_typescript_workspaceandkeep_apps_standalone. It was an if/else long enough that the condition and its consequence never appeared on screen together; the decision is eleven lines now.One detail worth the reviewer's eye: the pair passed to those two functions is
<rel>:<adapter>, not just the path, because the second branch asks the adapter whether it is TypeScript. "Does it have apackage.json" is a different question with a different answer βlaravel-inertiahas one, for vite, and is not TypeScript β and substituting it would have been a silent behaviour change inside a refactor.How it was verified
packages/typesjoined, per-app lockfiles gone, two images built from context.) and a single-adapter one.lib/project.shfor a moved function now sources the file that has it, rather thanproject.shquietly re-exporting its siblings β the dependency is the point of the split.cli.batschecks the negative too (no value handed to a shell directly, one script runs both throughmise exec), andservice.batschecks that a driver failure names the service and the family, which is the actual requirement β a bare "a driver failed" sends the reader to the wrong one of eight.mise run lintandmise run test-unitgreen locally; the lanes run here.Checklist
mise run lintpassesmise run test-runnerpasses