Skip to content

Document the child_process spawn contract for components - #634

Draft
kriszyp wants to merge 6 commits into
mainfrom
kris/626-spawn-contract
Draft

Document the child_process spawn contract for components#634
kriszyp wants to merge 6 commits into
mainfrom
kris/626-spawn-contract

Conversation

@kriszyp

@kriszyp kriszyp commented Aug 22, 2026

Copy link
Copy Markdown
Member

Documents the child_process substitution contract that Harper applies to component code: which loaders and import forms receive the constrained module, which of Node's functions are usable, how applications.allowedSpawnCommands matching actually works, the mandatory name PID-file lock at <rootPath>/pids/<name>.pid, the integer-only version replacement semantics, and the narrow ExistingProcessWrapper that every caller except the lock winner receives. Closes #626.

Also corrects two adjacent errors found while verifying the contract against core: applications.moduleLoader's documented default was vm (it is vm-current-context), and both reference/configuration/options.md and the v5 migration guide listed exec as an allowlisted spawn function when exec cannot be called through the substitute at all.

For the human reviewer

The page documents defects, not just contract. Verifying the issue's claims against security/jsLoader.ts turned up several behaviors that are bugs rather than design, and I chose to describe them rather than write the contract as intended and leave readers to discover them:

  • exec is unreachable. The substitute forwards (command, args, options, callback) positionally into Node's exec(command[, options][, callback]), so the idiomatic two-argument call fails the mandatory-name check and the shifted form throws ERR_INVALID_ARG_TYPE (confirmed empirically against Node, not just read).
  • The version replacement path can leave two processes running: the outgoing child's exit handler unlinks the PID file by path rather than by PID, so it can delete the lock the replacement just wrote. The page steers readers away from in-place replacement because of this.
  • unref() on the wrapper clears the only liveness interval, which is also the only source of its 'exit' event — so the two members are mutually exclusive.
  • name is interpolated into the lock path unsanitized and is not namespaced per component.

If the team would rather fix these in core than publish them, the corresponding paragraphs should come out; that is the main judgment call here. Issue #626 also offered a second option — declare the contract internal and point components at a supported once-per-node primitive. I took the "document it" branch because the gap is live today either way, but that is a product call, not a docs call.

Scope decisions worth a second opinion. The section lives inside reference/components/javascript-environment.md rather than a dedicated page (it is now ~95 lines on a page otherwise about globals). It sanctions if (child.spawnargs) as the way to tell a real ChildProcess from the wrapper, which is a duck-typed discriminator core never promised. And the version option carries <VersionBadge version="v5.0.2" /> — a patch version, which deviates from AGENTS.md's vX.Y.0 convention, but the option genuinely shipped in a patch and rounding it to v5.0.0 would be wrong.

Not addressed here: the core defects above are not filed as issues yet, and applications.lockdown's documented default (freeze) also disagrees with the migration guide (freeze-after-load) — left alone as unrelated to this change.

Verification

Every behavioral claim was traced to harper security/jsLoader.ts and components/ApplicationScope.ts on origin/main (v5.2.4), and the exec failure was reproduced directly against Node 24 rather than inferred. npm run build is clean — the two broken anchors it reports are pre-existing on main (backups/overview, release-notes/v5-lincoln/5.1) and unrelated. npx prettier --check is clean on the changed files. The rendered page was inspected in build/ to confirm the new tables and anchors resolve.

Complexity: medium

Review-Coverage: authored=claude; ran=codex,gemini; declined=cursor-grok,cursor-composer,domain; rounds=6 @ c0883b7

Human-Review-Need: 4 @ c0883b7

@kriszyp
kriszyp requested a review from dawsontoth August 22, 2026 01:01

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the documentation for Harper's child process spawning mechanism, adding a detailed section on child processes in the JavaScript environment reference, updating configuration options to reflect the new default vm-current-context module loader, and revising the v5 migration guide. The review feedback highlights a few documentation improvements, including correcting the version badge format in the environment reference, fixing a typo in the configuration options, and addressing grammatical errors in the migration guide.

Comment thread reference/components/javascript-environment.md
Comment thread reference/configuration/options.md Outdated
Comment thread release-notes/v5-lincoln/v5-migration.md Outdated
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-634

This preview will update automatically when you push new commits.

@github-actions
github-actions Bot temporarily deployed to pr-634 August 22, 2026 01:05 Inactive
@github-actions

Copy link
Copy Markdown

🚀 Preview Deployment

Your preview deployment is ready!

🔗 Preview URL: https://preview.harper-documentation.harperfabric.com/pr-634

This preview will update automatically when you push new commits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant