…t of identity
putup's default child environment diverged from tup's default_env[] in two
ways that no requirement stated, so a reader diffing the two found them as
defects rather than decisions. A rule reading $HOME saw an empty string, and
a PATH change re-ran nothing.
HOME is now forwarded, under the set-non-empty rule #478 established for the
temporary-directory variables: the value when putup's own environment holds a
non-empty one, no entry at all when it is unset or empty, and no invented
default, since none is correct for a per-user directory. The Windows keep list
gains it too, so the requirement needs no platform scope; cmd and PowerShell
leave HOME unset and contribute nothing. What its absence breaks was measured
rather than assumed: `go build` refuses to run at all ("GOCACHE is not defined
and neither $XDG_CACHE_HOME nor $HOME are defined"), and dash - the /bin/sh a
putup command runs under on Debian-derived systems - leaves ~ unexpanded, so a
rule containing it failed under putup and succeeded in the shell that invoked
putup. The ccache motive the issue inherited turned out to be an inference:
the upstream commit adding HOME records no reason and ccache falls back to
getpwuid.
Neither HOME nor PATH joins command identity. Recording them was argued and
rejected: their values say where the invoking shell put things rather than
what a command produces, which is the axis REQ-ENV-IMPORTED and
REQ-ENV-TEMPDIR-IDENTITY already settled, and a recorded PATH would re-run
every command in a project whenever direnv, nvm, an IDE terminal or a CI job
composed PATH differently - putup's own 33-rule test runner first. The case a
sticky PATH exists to catch, the compiler you will actually run having
changed, is already reached by CONFIG_TRACKED_TOOLS: a bare tracked name is
resolved through putup's PATH and its path:size:mtime enters identity, so a
PATH change that shadows the tool re-runs its commands and one that does not
re-runs nothing - a distinction a recorded PATH string cannot draw. That
route was opt-in and unspecified; it is now a requirement, and its PATH branch
has a scenario for the first time. It stays opt-in, so in a default
configuration a PATH change that swaps the compiler still produces a stale
build with no diagnostic; that gap is stated in the requirement rather than
hidden, and is worth its own issue.
Five requirements in command-record.ears.md's env-values group now carry this:
REQ-ENV-PATH and REQ-ENV-HOME for what reaches the subprocess, REQ-ENV-TEMPDIR
unchanged but no longer noting HOME as an open divergence,
REQ-ENV-FORWARDED-IDENTITY replacing REQ-ENV-TEMPDIR-IDENTITY over the whole
forwarded set, and REQ-ENV-TRACKED-TOOLS for the compensating route. Every
discharge names a test that asserts its sentence. The two new unit tests and
the HOME-forwarding scenario were observed red before the change; the three
no-op pins and the PATH-default pin pass at HEAD, so each was shown able to
fail - `export HOME` and `export PATH` in the fixture re-run the command,
dropping CONFIG_TRACKED_TOOLS makes the shadowed-tool build a no-op, and a
changed literal breaks the PATH default.
A different-model review of the branch found the `/usr/bin:/bin` substitution
stated without platform scope, though only the POSIX backend performs it - the
Windows keep list copies a PATH that exists and synthesises none - and found
the PATH unit test asserting nothing on Windows where its two siblings each
carry an arm; both are corrected here. It also rejected two charges after
measuring them: REQ-ENV-PATH stays tup-conformant, since the file already
labels a requirement that way and records the narrow divergence in its
reference (REQ-SIG-RECORD does exactly this), and a PATH change that preserves
a tracked tool's resolution is already entailed by REQ-SIG-RECORD together
with REQ-ENV-TRACKED-TOOLS rather than left unspecified.
No record layout or content changes, so INDEX_VERSION is unchanged.
Ref: #480
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #480.
putup's default child environment diverged from tup's
default_env[]in two ways that no requirement stated, so a reader diffing the two found them as defects rather than decisions. A rule reading$HOMEsaw an empty string, and aPATHchange re-ran nothing.HOME is forwarded
HOMEjoins the forwarded-when-set cohort #478 established: the value when putup's own environment holds a non-empty one, no entry at all when it is unset or empty, and no invented default, since none is correct for a per-user directory. The Windows keep list gains it too, so the requirement needs no platform scope.What its absence breaks was measured rather than assumed:
go buildrefuses to run at all —build cache is required, but could not be located: GOCACHE is not defined and neither $XDG_CACHE_HOME nor $HOME are defineddash, the/bin/sha putup command runs under on Debian-derived systems, leaves~unexpanded, so a rule containing it failed under putup and succeeded in the shell that invoked putupThe ccache motive #480 inherited turned out to be an inference: the upstream commit adding
HOMErecords no reason, and ccache falls back togetpwuidwhenHOMEis unset.Neither HOME nor PATH joins identity
Recording them was argued and rejected. Their values say where the invoking shell put things rather than what a command produces — the axis
REQ-ENV-IMPORTEDandREQ-ENV-TEMPDIR-IDENTITYalready settled — and a recordedPATHwould re-run every command in a project whenever direnv, nvm, an IDE terminal or a CI job composedPATHdifferently, putup's own test runner first.The case a sticky
PATHexists to catch — the compiler you will actually run having changed — is already reached byCONFIG_TRACKED_TOOLS: a bare tracked name resolves through putup'sPATHand itspath:size:mtimeenters identity, so aPATHchange that shadows the tool re-runs its commands and one that does not re-runs nothing, a distinction a recordedPATHstring cannot draw. That route was opt-in and unspecified; it is now a requirement, and itsPATHbranch has a scenario for the first time.It stays opt-in, so in a default configuration a
PATHchange that swaps the compiler still produces a stale build with no diagnostic. That gap is stated in the requirement rather than hidden, and deserves its own issue.Spec
Five requirements in
command-record.ears.md's env-values group now carry this:REQ-ENV-PATHandREQ-ENV-HOMEfor what reaches the subprocess,REQ-ENV-TEMPDIRunchanged but no longer notingHOMEas an open divergence,REQ-ENV-FORWARDED-IDENTITYreplacingREQ-ENV-TEMPDIR-IDENTITYover the whole forwarded set, andREQ-ENV-TRACKED-TOOLSfor the compensating route.Verification
Scenario: HOME set for putup reaches every build commandwere observed red before the production edit (HOME=[]vs the set value).export HOME/export PATHin the fixture re-runs the command, droppingCONFIG_TRACKED_TOOLSmakes the shadowed-tool build a no-op, and a changed literal breaks thePATHdefault.make checkrc=0 — 946 test cases, 182,428 assertions, 32 e2e shards; spec-check 21 areas, 200 requirements, 0 gaps.clang-cl /W4 /WXagainst the xwin CRT, the check that would have caught Build commands get PATH only, so TMPDIR is dropped and GCC writes temporaries into the source tree when /tmp is read-only #478's CI failure.A different-model review found the
/usr/bin:/binsubstitution stated without platform scope (only the POSIX backend performs it) and thePATHunit test asserting nothing on Windows; both are corrected. It rejected two further charges after measuring them.No record layout or content changes, so
INDEX_VERSIONis unchanged.🤖 Generated with Claude Code
https://claude.ai/code/session_01StgwMENEyfBnEoe4pvAdtQ