Conversation
Contributor
lzrscg
commented
May 5, 2026
- chore: update review-adr workflow to renamed ADR-0004 filename
- chore: cleanup
- docs(adr-0004): tighten cleanup safety summary, spawn-failure cleanup, lazy env-snapshot errors
- chore: upgrade workflow
- docs(adr-0004): add project-root cwd and LOOPX_WORKFLOW_DIR
- docs(adr-0004): fix leak wording, absolute invocation path, §5.1 retarget
- docs(adr-0004): weaken JS/TS import.meta.url symlink equality, clarify path spelling and warning cardinality
- docs(adr-0004): resolve relative RunOptions.cwd, broaden symlink caveats to entry scripts
- docs(adr-0004): fix env rationale, snapshot inherited env, broaden symlink scope, tighten warning cardinality
- docs(adr-0004): clarify cwd spelling, PWD handling, partial tmpdir cleanup
- docs(adr-0004): resolve env/cleanup contradictions from review feedback
- docs(adr-0004): address remaining blockers from ADR-0001 review
- docs(adr-0004): address symlink, cleanup taxonomy, and error-path gaps from review
- docs(adr-0004): soften env name-validation claims and clarify cleanup timing
- docs(adr-0004): address review blockers on warning tokens, options ordering, and cleanup caveats
- docs(adr-0004): address remaining review blockers on abort precedence, pre-iteration error scoping, and CLI grammar
- docs(adr-0004): tighten pre-first-next carve-out, abort-after-final-yield, run -h, warning scoping, and invalid options
- docs(adr-0004): weaken Bash PWD claims, align version-check wording with SPEC, broaden env-tier rejection, clarify LOOPX_DELEGATED and hard-link semantics
- docs(adr-0004): fix abort-precedence contradiction, cleanup-token scoping, recursive-removal test, version-check-under-n0 example, and make cwd/envFile validation explicit
- docs(adr-0004): add scope-of-contract note, programmatic precedence summary, and LOOPX_DELEGATED role distinction
- docs(adr-0004): address review feedback on timing, signal-wins scope, -- grammar, §3.2, and cleanup-token escaping
- docs(adr-0004): fix token-escape contradiction, split runPromise env-snapshot timing, tighten impl-defined scope and CLI grammar terminology
- docs(adr-0004): address review blockers — signal/parser race, token scoping, tmpdir parent, option-first priority, duck-typed signal reentrancy
- docs(adr-0004): address pre-acceptance review feedback
- docs(adr-0004): tighten to minimal-but-thorough — drop over-specification
- docs(adr-0004): address pre-acceptance review — cancellation scope, race precedence, tmpdir hardening, §7.4
- chore: update loopx workflows
- docs(adr-0004): add §6 auto-install workflow npm dependencies during loopx install
- chore: update workflows
- docs(adr-0004): add .gitignore safeguard to §6 auto-install
- chore: update loopx workflows
- docs(adr-0004): tighten pre-acceptance review — .gitignore failure, §10.7/§10.9/§11.3, scope
- chore: update loopx workflows
- docs(adr-0004): update SPEC.md for script execution context, CLI grammar, and auto-install
- docs(adr-0004): apply post-acceptance feedback to SPEC.md
- docs(adr-0004): apply post-acceptance feedback to SPEC.md
- docs(adr-0004): apply post-acceptance feedback to SPEC.md
- docs(adr-0004): apply post-acceptance feedback to SPEC.md
- docs(adr-0004): apply post-acceptance feedback to SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- chore: update loopx workflows
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- chore(review-test-spec): scope review and SPEC-PROBLEMS to active ADR
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-01 / P-0004-02 and apply review feedback
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-03 and apply review feedback
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-04 and apply review feedback
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-07 and apply review feedback
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-08 (broken/cyclic symlinks during runtime discovery)
- docs(adr-0004): open P-0004-09 (project-root .loopx symlink failure modes)
- docs(adr-0004): resolve P-0004-09 (project-root .loopx failure modes)
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): clarify T-API-70 to avoid implying a fixed pre-iteration priority
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-10 and P-0004-11
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-12 and apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): open P-0004-13 and apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): resolve P-0004-13 and apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): apply post-acceptance feedback to TEST-SPEC.md
- docs(adr-0004): advance status to Test Specified
- chore: update loopx workflows
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…, lazy env-snapshot errors Address review feedback by: - Rewriting the Decision Summary cleanup bullet to match the detailed rules (symlink replacements are unlinked; only identity-matched directories are recursively removed). - Adding "child launch / spawn failure after tmpdir creation" as an explicit terminal outcome so the tmpdir guarantee covers cases like a discovered script being removed between discovery and spawn or an OS rejection of a RunOptions.env entry. - Clarifying that the shell env-var prefix on the CLI reuses the inherited-env tier and does not introduce a new override-precedence level above -e or global env. - Preserving SPEC §9.1's sync-never-throws guarantee when RunOptions.env is an exotic object (Proxy, throwing getter) by routing snapshot exceptions through the pre-iteration error path. - Spelling out the five-tier env precedence list in the §8 SPEC-update mapping and extending §7.2 to cover spawn-path failures. Status remains Proposed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Expands ADR-0004 with two new decisions that make scripts easier to write: - §3 Project-root cwd. Scripts run with LOOPX_PROJECT_ROOT as their child-process cwd instead of the workflow directory, superseding SPEC §6.1's current "workflow directory as cwd" rule. Eliminates the \$ROOT="\$LOOPX_PROJECT_ROOT" prefix boilerplate currently repeated in every workflow script. - §4 LOOPX_WORKFLOW_DIR injection. Absolute path to the currently-spawned script's workflow directory, refreshing per-spawn alongside LOOPX_WORKFLOW. Correct across intra-workflow goto, cross-workflow goto (destination sees its own dir, not caller's), deep chains, and loop reset. Gives scripts a one-token reference to workflow-local assets without dirname/import.meta.url tricks. Also corrects SPEC §3.3's stale claim that closer-node_modules/loopx precedence is "a natural consequence of running scripts with the workflow directory as cwd" — module resolution is file-relative, not cwd-relative. Renamed from 0004-tmpdir-and-env.md → 0004-script-execution-context.md to reflect the broader scope (now four decisions: LOOPX_TMPDIR, RunOptions.env, project-root cwd, LOOPX_WORKFLOW_DIR). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rget Apply review feedback: weaken the async-generator cleanup claim (no GC-based guarantee), make the absolute discovery-time invocation path a normative rule so $0 / import.meta.url equal LOOPX_WORKFLOW_DIR, list §5.1 in Affected SPEC Sections so its "non-zero exit" reference aligns with §7.2's new spawn-failure category, note that LOOPX_PROJECT_ROOT is symlink-preserving like LOOPX_WORKFLOW_DIR, drop src/env.ts and src/execution.ts implementation refs, and correct the "loopx env set" consequence to reflect its persistent-global role. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…y path spelling and warning cardinality Address review feedback pre-acceptance: - JS/TS dirname(fileURLToPath(import.meta.url)) equality with LOOPX_WORKFLOW_DIR is now non-normative under symlinks (Node canonicalizes the main module's URL by default; Bun's behavior is unspecified). Bash $(dirname \"\$0\") equality remains normative. LOOPX_WORKFLOW_DIR is authoritative for JS/TS code. - Replace \"path-spelling preserved\" prose with \"no extra canonicalization by loopx\" for LOOPX_PROJECT_ROOT, explicitly acknowledging that process.cwd() may canonicalize while RunOptions.cwd is used verbatim. - Normalize cleanup warning cardinality to one stderr warning per distinct anomaly, no aggregation or dedup; test-friendly. - Retarget \"§3.2 / §7.1 pre-iteration\" to §7.1 only; add §6.2 and §6.3 entries for the language-specific invocation-path consequences. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ats to entry scripts Closes the logical gap between "LOOPX_PROJECT_ROOT is absolute" and the prior "RunOptions.cwd used verbatim" wording: a relative cwd is now resolved via path.resolve(process.cwd(), options.cwd) at call time with no further realpath. Broadens the JS/TS import.meta.url equality and §3.3 module-resolution caveats to cover symlinked entry script files (not only symlinked workflow directories), matching SPEC §5.1's symlink policy on both. Adds a one-line note that OS-rejected RunOptions.env entries don't surface under maxIterations: 0 since no spawn occurs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mlink scope, tighten warning cardinality - Context: fix confused `.loopx/shared/` sentence (workflow-local paths break after cross-workflow goto because $LOOPX_WORKFLOW updates). - §2 RunOptions.env: add "inherited process.env snapshotted once per run" rule so deterministic env is a per-run property, not just a RunOptions.env property. - §1 warning cardinality: replace "any other distinct cleanup error surface" catch-all with a closed enumeration of three categories (leave-in-place, top-level recursive-removal failure, partial-dir cleanup failure on creation error). - §3 / §4 / Affected-SPEC / Tests: consistently frame JS/TS import.meta.url non-guarantee around any symlink in the absolute discovery-time entry path (workflow dir, entry script file, or intermediate component) rather than only the first two. Frame the loopx guarantee around what loopx controls (absolute invocation path + LOOPX_WORKFLOW_DIR). - Consequences: fix incorrect claim that `-e`/`loopx env set` reach "above env files" (`-e` is local env file tier; `loopx env set` writes the global env file tier). Replace RunOptions.env rationale: it exists as an in-memory per-call override layer that (a) avoids mutating process.env, (b) avoids writing a temp env file, and (c) layers on top of RunOptions.envFile — not because programmatic callers lack an -e equivalent (they have RunOptions.envFile). - Tests: add inherited-env snapshot test, intermediate-symlink scenario test, and updated warning-cardinality assertions to match the closed enumeration. Status remains Proposed.
…eanup Addresses review feedback on ADR-0004: - Distinguish effective-cwd (loopx-controlled) from cwd string spelling (runtime-reported); runtime APIs may canonicalize while LOOPX_PROJECT_ROOT preserves caller spelling. - Document that PWD is not a protocol variable; loopx neither sets nor unsets it, Bash regenerates $PWD on startup. - Specify partial tmpdir cleanup when identity capture fails: single non-recursive rmdir attempt, then leave-in-place + category-3 warning. - Make RunOptions.env shape validation explicit under maxIterations: 0. - Extend Affected SPEC Sections list with §5.1 symlink-path preservation and §12 tmpdir/spawn exit-code coverage; note envFile resolution under the new cwd semantics. - Soften "module resolution is unaffected by cwd" to apply specifically to script module resolution, not cwd-dependent tooling. - Scope byte-for-byte cwd test assertions to symlink-free fixtures; add filesystem-identity assertions for symlinked regimes. - Add Rejected / Deferred Alternatives section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix symbol-key contradiction in RunOptions.env shape validation (symbol-keyed entries are ignored, not invalid). Replace path.resolve with fs.realpath in the symlink-identity test convention (path.resolve is string-only and does not prove filesystem identity). Simplify warning cardinality to reflect that cleanup dispatches on a single top-level LOOPX_TMPDIR path, so each of the three categories fires at most once per cleanup and the three are mutually exclusive. Document the deliberate lazy-vs-call-time asymmetry between inherited process.env (lazy) and RunOptions.env / RunOptions.cwd (call-time), with a corresponding test recommendation. Clarify that RunOptions.envFile shares the local-env-file precedence tier with -e, and that invalid RunOptions.env shape / snapshot exceptions are pre-spawn failures that do not create a tmpdir. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fixes four internal inconsistencies flagged during review of ADR-0004: - Warning cardinality: categorize by cleanup routine (full safety vs. non-recursive rmdir), not by terminal-vs-creation outcome. Identity- captured creation-failure cleanup now correctly emits cat 1/2 rather than claiming mutually-exclusive-with-cat-3 while sharing a routine. - Closed-set language: switch to strict version — implementations emit no cleanup warnings outside the three categories; tests may assert their absence. - CLI symlink spelling: drop claim that CLI invocation through a symlink can preserve shell-side spelling. LOOPX_PROJECT_ROOT (CLI) is exactly process.cwd() at invocation; loopx does not consult \$PWD. Symlinked- project-root asymmetry reachable only via programmatic RunOptions.cwd. - Custom resolve hook: explicitly require the Node/tsx hook to preserve standard module resolution precedence via defaultResolve delegation, so workflow-local node_modules/loopx still wins after the cwd change. Also clarifies RunOptions.env inspection timing (synchronous at call time, errors deferred to pre-iteration) and notes that cleanup safety does not detect mount points inside \$LOOPX_TMPDIR. Status remains Proposed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s from review Fix contradictions and close gaps flagged in ADR-0001 review feedback: - Correct the relative-cwd symlink claim: symlinked components in a relative RunOptions.cwd are preserved by path.resolve(), so a symlink-preserving LOOPX_PROJECT_ROOT is not restricted to symlinked absolute cwd inputs. - Broaden cleanup warning category 2 from "Top-level recursive-removal failure" to "Top-level cleanup failure" covering lstat dispatch failure, top-level symlink unlink failure, and identity-matched recursive removal failure; preserves the at-most-one-warning model. - Make abort precedence across pre-iteration explicit: an already- aborted signal wins over validation, discovery, env loading, target resolution, version check, and tmpdir creation errors. - Document .loopx itself as a symlink: treated as an intermediate component of the absolute entry path with its spelling preserved. - Capture options.env getter exceptions through the lazy pre-iteration error path, like snapshot exceptions. - Tighten module-resolution hook language: any standard file-relative resolution wins over the CLI fallback, not only workflow-local. - Add SPEC §9.3 to Affected Sections; extend §7.2 bullet to cover tmpdir creation failure alongside other runtime error paths. - Add test recommendations for cleanup-internal failures, relative cwd with symlinked components, and symlinked .loopx directory entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… timing
Blocking fix: revise RunOptions.env malformed-name behavior. Node's
child_process does not reliably reject names containing "=" (a key like
"A=B" with value "C" may reach the child as A=B=C rather than a spawn
failure). Reframe runtime-level rejection around embedded NUL bytes as
the reliable case, note that other malformed-but-runtime-accepted names
have runtime-dependent child-observed behavior, and update the matching
test recommendation.
Also clarify: run() yields any final Output before the generator
settles, with cleanup guaranteed before { done: true } / abort
surfacing; abort precedence applies only once options.signal is
captured (a throwing signal getter is an ordinary snapshot error);
summary lists consumer-driven generator cancellation as a terminal
outcome; SPEC §3.3 update language uses "any standard file-relative
resolution of loopx wins over the CLI fallback" instead of the
workflow-local-implying "closer node_modules" phrasing; "OS rejection"
normalized to "runtime rejection" for consistency.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…dering, and cleanup caveats Incorporate review feedback into ADR-0004 ahead of acceptance: - Warning cardinality: each cleanup warning must contain exactly one of three bracketed category tokens ([leave-in-place-refusal], [top-level-cleanup-failure], [partial-directory-cleanup-failure]) so tests can assert category identity without matching implementation- defined prose. - Options snapshot ordering: options.signal is read before options.env / cwd / envFile / maxIterations, making the existing "abort wins over options-snapshot exceptions" rule reachable when combined with a throwing env getter. Each option field is read at most once per call. - Non-abort pre-iteration error priority is implementation-defined except where already specified (e.g., invalid env shape + missing .loopx/ may surface either error). - Identity-capture-failure regime: document that the single rmdir is best-effort and may remove an unrelated empty directory if a same-user process swaps the mkdtemp directory before cleanup; this remains outside the race-resistant guarantee, as a deliberate trade-off against leaking the partial directory on the common identity-capture- failure path. - Promote the run() final-yield cleanup caveat into the Decision Summary LOOPX_TMPDIR bullet: cleanup on normal completion is guaranteed only once the async generator is driven to settlement; the final yielded Output is not itself settlement. - Soften device/inode wording in normative text to behavioral identity language, retaining device/inode as one POSIX implementation strategy. Update Affected SPEC Sections and Test Recommendations to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…, pre-iteration error scoping, and CLI grammar - Extend AbortSignal precedence to cover target argument validation (non-string `target`) and target syntax validation (empty, bare colon, etc.) — both previously left ambiguous. - Add CLI signal precedence paragraph: SIGINT/SIGTERM during the CLI pre-iteration phase mirrors programmatic `AbortSignal` precedence. - Scope the implementation-defined non-abort pre-iteration priority rule to the programmatic API only; CLI retains SPEC §7.1's concrete ordering. - Narrow "each option field read at most once" to permit normal one-pass enumeration of `options.env` proxies (single `ownKeys` plus per-property traps as required by the JS enumeration algorithm); additional enumeration passes and getter retries remain forbidden. - Add explicit pre-first-`next()` consumer-cancellation carve-out: `.return()` / `.throw()` on a generator that has not yet had `next()` invoked settles per standard async-generator semantics without observing signal state, even when the captured signal is already aborted. `runPromise()` has no equivalent carve-out. - Clarify call-time option snapshot vs lazy pre-iteration sequence so the "`RunOptions.env` shape validation" placement is unambiguous. - Pin "no CLI named-argument syntax" as an explicit §4.1/§4.2 affected SPEC bullet so the decision is traceable from this ADR. - Make the cleanup-warning category-token taxonomy and at-most-one-warning-per-attempt cardinality an explicit stable public testing contract. - Update §7.3, §9.1/§9.2, and §9.3 affected-SPEC bullets to reflect the new carve-outs; add test recommendations covering them. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ield, run -h, warning scoping, and invalid options Addresses acceptance-level blockers raised in review: - Pre-first-next() consumer cancellation now explicitly wins over all captured call-time option snapshot errors (throwing option-field getters, invalid env shapes, invalid options values, invalid options.signal values), not only already-aborted signals. - Abort after the final yielded Output is explicitly spelled out as Option A — abort still wins until generator settlement; the final yield does not commit normal completion. - The "no CLI named-argument syntax" rule now explicitly preserves the existing SPEC §4.2 `run -h` / `--help` short-circuit, both in the decision summary and in the §4.1 / §4.2 affected-SPEC entry. - Cleanup-warning token requirement is scoped narrowly to LOOPX_TMPDIR cleanup warnings; other loopx warnings (version-check, unreadable package.json, invalid-entry, invalid env-file line, etc.) are outside the taxonomy and must not carry these tokens. - Invalid `options` (null, number, string, array, etc.) and invalid `options.signal` (non-AbortSignal-compatible values) are now defined: both are captured at call time and surfaced via the standard pre-iteration error path; a non-compatible signal does not enter the abort-precedence pathway. Also adds a timing-model terminology note at the start of §2 (call-time capture / pre-iteration surfacing / spawn-time runtime rejection) and corresponding test recommendations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ith SPEC, broaden env-tier rejection, clarify LOOPX_DELEGATED and hard-link semantics Review feedback blockers and clarifications: - Bash `$PWD` / bare `pwd` are no longer claimed to equal `LOOPX_PROJECT_ROOT` byte-for-byte in any regime. Per POSIX, Bash retains an inherited `PWD` that names the current directory through symlinks, so a symlinked-logical ancestor shell can leave the child with a `$PWD` that differs from even a canonical `LOOPX_PROJECT_ROOT`. Tests must use `pwd -P` / `/bin/pwd` or filesystem identity, not `$PWD` / bare `pwd`. - "version-check error" removed from pre-iteration error-priority lists in §1 abort precedence, CLI signal precedence, non-abort priority, and the §7.3 / §9.3 affected-SPEC sections and matching test recommendation. SPEC §3.2 defines version-check outcomes as non-fatal warnings, so version checking is not a competing terminal-outcome mode; the ADR now says so explicitly. - Spawn-time runtime rejection language broadened from "a `RunOptions.env` entry" to "any child environment entry from any env tier (inherited, env file, `RunOptions.env`)" in §1 Cleanup, §1 Timing-model phase 3, affected §7.2, §9.3, §12, and the matching test recommendation. - `LOOPX_DELEGATED` explicitly documented as remaining an internal delegation guard outside this ADR's script-protocol-variable tier; `RunOptions.env` and env files may supply it to children without a loopx-side per-spawn override. - Hard-link refusal clarified: case 3 applies to top-level path replacement only; recursive cleanup under case 4 may unlink hard-link entries inside the identity-matched tmpdir, as ordinary recursive deletion would. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ping, recursive-removal test, version-check-under-n0 example, and make cwd/envFile validation explicit - Abort precedence: open paragraph now leads with the "usable signal captured" qualifier; removes the contradictory listing of invalid options / invalid options.signal as items abort can displace (these cases capture no signal and are surfaced as ordinary options-snapshot errors). Ripple fix to the §9.3 Affected SPEC bullet. - Cleanup-token scoping: tests may now assert that known non-cleanup warnings lack the three bracketed tokens (previously forbidden by the "or lack" clause, which contradicted the normative scoping rule). - Recursive-removal failure test: split the three category-2 sub-cases so only the lstat-failure and symlink-unlink-failure cases claim "path left in place"; the recursive-removal-failure sub-case no longer promises an intact tmpdir, since partial deletion may have occurred. - Token-scoping "no-token run" example: replaced version-mismatch-under-maxIterations:0 (never emits, since SPEC §3.2 / §7.1 / §4.2 skip version checking under -n 0) with env-file invalid-line per SPEC §8.1. - Explicit validation for options.cwd / options.envFile / options.maxIterations values: new subsection defines the string-only requirement for cwd/envFile, captures non-string values at call time, and surfaces via the standard pre-iteration error path. Propagated to the pre-first-next() carve-out list, the non-abort priority enumeration, §9.1/§9.2, §9.3, §9.5 Affected SPEC bullets, and a new test recommendation. Status remains Proposed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ummary, and LOOPX_DELEGATED role distinction Addresses acceptance-blocker review feedback: scope the public-contract surface explicitly, separate startup-reserved from script-protocol-protected for LOOPX_DELEGATED, tighten runPromise inherited-env timing as implementation-defined, and make name=value target-validation plus CLI signal precedence for target syntax explicit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… -- grammar, §3.2, and cleanup-token escaping Incorporate reviewer's acceptance-blocker feedback without marking the ADR Accepted: - runPromise() inherited-env snapshot timing: make implementation-defined relative to return (may capture at sync setup OR async continuation), resolving the prior contradiction between "asynchronously after return" and the "either outcome is conforming" test license. - CLI signal-wins precedence: scope explicitly to after the run -h / --help short-circuit and usage-level argument parsing. Parser-level usage errors (no target, multiple positionals, duplicate -n/-e, unrecognized flags, etc.) remain parser-level and are not displaced by signal-wins. - `--` grammar: reject `--` in any position in `run` outside the help short-circuit. No POSIX end-of-options support either; added as a Rejected / Deferred Alternative. - §3.2 — Project Root: add to Affected SPEC Sections to make project-root derivation rules (CLI = own process.cwd() without $PWD/realpath; programmatic = resolved RunOptions.cwd or process.cwd() at call time) explicit. - Global env-file path resolution: align timing with env-file loading (first next() for run(), implementation-defined for runPromise()) so XDG_CONFIG_HOME / HOME lookup timing is unambiguous. - CLI inherited-env test: remove the misleading "concurrent process modifies loopx env" claim; make the per-run snapshot mutation test programmatic-only, since POSIX forbids external env mutation. - Cleanup-warning category tokens: require the token in a loopx-controlled prefix position AND require implementations to escape / quote user-controlled text so TMPDIR-influenced paths cannot introduce a second apparent token. Cardinality-of-one remains observable. Status stays Proposed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…snapshot timing, tighten impl-defined scope and CLI grammar terminology Address review-pass feedback. Narrow the "implementation-defined by default" sentence so it cannot be read as de-specifying existing SPEC guarantees outside this ADR's change surface. Rewrite the cleanup-warning "Token placement and user-controlled text" rule: the normative requirement is that user-controlled text cannot contribute an additional plain-text occurrence of any token; prefix placement alone is insufficient when paths are also rendered, and merely surrounding user-controlled text in quotes is not sufficient because a quoted string still contains the token substring. Rename the inherited-env subsection to "per-API split, not uniformly 'lazy'" so the text no longer simultaneously claims run()/runPromise() share lazy semantics while also allowing synchronous call-time capture under runPromise(); update cross-references in §2, §7.2, §9.1/§9.2 accordingly. Add an explicit RunOptions.env enumeration algorithm (Object.entries-equivalent semantics, with observable per-key getOwnPropertyDescriptor probes and captured snapshot errors on throwing probe traps), resolving the ambiguity between "non-enumerable own string keys are ignored" and "one-pass enumeration may invoke per-property traps." Split the CLI §4.1 / §4.2 test recommendation so target-validation failures (loopx run name=value) are not lumped under "usage errors"; tests may no longer require a usage-style diagnostic for that form. Add the throwing-addEventListener subcase to the invalid-options.signal rule and clarify that removeEventListener is not part of the compatibility contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…coping, tmpdir parent, option-first priority, duck-typed signal reentrancy - Fix internal contradiction in §1 "Scope of CLI signal-wins precedence" / §7.3 Affected: pre-handler-installation window no longer claims both "usage error surfaces regardless of signal" and "signals follow POSIX default disposition"; both outcomes are now explicitly conforming and tests must tolerate either. - Reword CLI signal-wins rule around handler observation rather than OS-level delivery, so implementations that run synchronous pre-iteration work are not required to poll / async-ify to meet the "signal wins" contract. - Loosen non-cleanup-warning token rule from "must not contain any of the three tokens" to "must not use them as loopx-controlled category markers", permitting incidental occurrences in user-controlled text (env-file lines, paths) and removing a sanitization burden on every non-cleanup warning site. - Add §1 "Parent directory selection" clarifying that os.tmpdir() is evaluated in the loopx process environment; env-file entries and RunOptions.env do not redirect LOOPX_TMPDIR parent selection. - Pin project-root-blocking / envFile-path-blocking option errors (non-string / throwing options.cwd / options.envFile) ahead of non-options pre-iteration failures in the programmatic-API priority rule; retain implementation-defined ordering for the remaining non-abort bucket. - Add §1 "Duck-typed signal reentrancy" rules: synchronous abort-listener invocation or observed-aborted during capture treats signal as aborted; already-aborted real AbortSignal must be observed as aborted; ordering between reading .aborted and registering listener is otherwise implementation-defined for duck-typed signals only. - Update Scope section to list new implementation-defined caveats (pre-handler-installation signal ordering, delivered-but-unobserved signal vs. synchronous pre-iteration failure, duck-typed signal latitude) and new pinned contract items (project-root-blocking option-error ordering, reserved-as-marker cleanup token scoping). - Update Test Recommendations to match all of the above. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tightening pass on ADR-0004 surfacing work:
- scope summary rule 5 and detailed non-abort priority section so the
pinned options.cwd / options.envFile ordering only beats the four
project-root-dependent failures; relative priority against target
argument / syntax validation is now explicitly implementation-defined
(resolves prior contradiction between summary and detailed text)
- carve the inherited-env snapshot timing and call-time option
snapshotting out of the "pre-iteration runs asynchronously after
return" rule for runPromise(), matching §2's per-API split
- add cleanup idempotence rule (at most one cleanup attempt per created
LOOPX_TMPDIR) so per-run warning cardinality is bounded to one across
racing terminal triggers
- reject function values in RunOptions.env shape, matching the options
parameter's existing function rejection
- simplify TMPDIR / runPromise() guidance to "before calling
runPromise()" since user code cannot mutate between call and return
- drop Deno references — SPEC §1 targets only Node.js and Bun
- clarify loopx run name=value grammar classification ("target, not
named argument" is stable) vs. observable outcome under §7.1, which
may surface a discovery error first in a project without .loopx/
Status remains Proposed pending separate acceptance.
…tion Per review feedback: the ADR was doing the work of an ADR plus a future SPEC patch plus a TEST-SPEC at once. Tightened to focus on the spec changes themselves so the ADR can fully drive the SPEC.md update and then retire from the working set. Specific changes (all per maintainer guidance on the four clarification points raised in review): - v1-scope `--` rejection on `loopx run`: framed as parser simplification arising from "no named-argument tail," not a permanent product stance. Future ADR may revisit alongside a named-argument surface. - Cleanup warning category tokens demoted to implementation-defined. Kept the normative behavior (at most one cleanup attempt per tmpdir, at most one warning per attempt) but dropped the public token contract, cardinality-by-token-match rules, and user-controlled-text escaping rules. Tests assert via provenance, not plain-text token matching. - `runPromise()` inherited-`process.env` snapshot pinned to call-time (synchronous, before return). Removes the previous "implementation- defined, bounded by no-later-than-first-spawn" latitude. `run()` retains lazy capture at first `next()`. Symmetric with `RunOptions.env` and `RunOptions.cwd` capture timing. - `RunOptions.env` one-pass enumeration / per-trap invocation pattern demoted to implementation-defined. Kept "each field read at most once per call, no retry after throws" as the SPEC-level guarantee. Other tightening: - Removed the ~900-word "Scope of this ADR" preamble that locked observable edge-case mechanics as stable contract. - Removed the standalone "Decision Summary" section (its content was duplicated by the §1-§4 decision sections themselves). - Trimmed Test Recommendations from ~95 bullets to ~9 high-risk edge cases. Per ADR-0001 the section is for cases easy to overlook, not an exhaustive test plan. - Promoted CLI grammar from a Decision-Summary bullet to a top-level §5 Decision section so the v1-scoping is obvious.
…ace precedence, tmpdir hardening, §7.4 - Broaden pre-first-next() .return()/.throw() carve-out to suppress all pre-iteration errors (invalid target, target syntax, discovery, env-file loading, target resolution, tmpdir creation) in addition to option-snapshot errors, and fix the "without observing signal state" wording that conflicted with call-time signal capture. - Add catch-all terminal-outcome precedence: first trigger observed by loopx wins among genuinely racing terminal triggers that no explicit precedence rule covers; idempotence and warning cardinality are independent of outcome selection. - Separate RunOptions.env shape validation (programmatic, surfaces under maxIterations: 0) from CLI -n 0 behavior (no RunOptions.env surface) so the "-n 0 validates env shape" claim is no longer misleading. - Pin tmpdir creation order as mkdtemp → identity capture → mode securing, and define per-step creation-failure cleanup (no-op / single rmdir / full cleanup-safety routine) in that order. - Snapshot the tmpdir parent (os.tmpdir() / TMPDIR / TEMP / TMP) on the same schedule as the inherited process.env snapshot: synchronous for runPromise(), at first next() for run(). Eliminates the runPromise() race where a post-return process.env.TMPDIR mutation could have silently affected the tmpdir parent. - Introduce a new §7.4 "Run-scoped temporary directory lifecycle" in the Affected SPEC Sections list, covering parent selection, location/ naming/mode, creation order, identity-fingerprint cleanup safety, renamed-away and mount-point behavior, race-resistance scope, absence of stale-tmpdir reaping, and settlement-based cleanup on run(). - Qualify the incorrect "no existing workflow script uses this pattern" claim: .loopx/shared/dispatch.sh uses cwd-relative ./send-*.sh and ./node_modules/.bin/tsx references that require migration. - Redefine LOOPX_WORKFLOW_DIR as the directory portion of the cached absolute discovery-time script path, making the Bash $(dirname "$0") equality robust to trailing slashes, symlinks, and lexical normalization without recomposing from $LOOPX_PROJECT_ROOT / .loopx / $LOOPX_WORKFLOW. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…loopx install New decision bundled into ADR-0004: loopx install spawns npm install post-commit in each committed workflow with a top-level package.json. Adds --no-install opt-out to install-scoped CLI (§4.2). Retires the existing §10.9 manual-install rule and adds a new §10.10. Rationale surfaced during analysis of how to optimize existing workflow flows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Re-cast T-INST-112n's mode-bit assertion via the
gitignore-make-unreadable;gitignore-lstat-fail seam composition so the
conformance anchor is a seam-set 000 mode rather than a source-derived
0644, matching SPEC 10.10's silence on install/copy phase mode-bit
preservation. Adds the same harness-side mode-restoration discipline
used by T-INST-112k and gates on process.getuid() !== 0.
- Add T-DISC-49i / T-DISC-49j / T-DISC-49k covering project-root .loopx
removal and real-directory replacement mid-run on the CLI and
programmatic surfaces, completing the {retargeting / removal /
replacement} × {CLI / run() / runPromise()} matrix for SPEC 5.1's
cache-clarification clause that previously only had retargeting
coverage via T-DISC-49g / T-DISC-49h.
- Add T-TMP-38b-run / T-TMP-38b2-run as run() generator-surface
counterparts to T-TMP-38b / T-TMP-38b2, closing the warning-cardinality
axis for the non-zero-exit-vs-abort race symmetrically across both
observation orders on the lazy-capture surface.
- Add T-API-61t5 covering the descriptor-enumeration half of SPEC 9.5's
"outer-object ownKeys / descriptor enumeration traps not invoked"
guarantee — observably distinct from the ownKeys axis already pinned
by T-API-61t3 / T-API-61t4. Also adds T-API-61t4 to the SPEC 9.5
appendix entry which had been missed previously.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- T-INST-112n: rewrite the "Mode-restoration division of responsibility"
paragraph to spell out the assertion-ordering sequence under mode 000
(lstat-only mode check before harness chmod; harness chmod; content-read
after harness chmod). The prior wording asserted that the harness chmod
ran after both (e) and (f) had read the on-disk content and mode bits,
but under non-root assertion (e) cannot read a mode-000 file before the
harness relaxes its mode bits. Annotate the matrix entry with a pointer
to the test entry's full ordering rationale.
- Open two ADR-0004-scoped SPEC-PROBLEMS entries:
- P-0004-10: .gitignore safeguard lstat-failure no-mutation guarantee
(SPEC 10.10 lstat-failure / write-failure bullet does not explicitly
say loopx makes no further changes to the .gitignore path; T-INST-112h
and T-INST-112n encode that natural-reading "no further changes" rule).
- P-0004-11: auto-install package.json validation timing — committed-
state vs. cached preflight result (SPEC 3.2 / 10.10 do not specify
whether the post-commit auto-install dispatch re-evaluates the
committed package.json or uses a preflight-cached result, while
T-INST-113i / 113j / 113k assume re-evaluation via the
package-json-replace-with-{symlink,fifo,socket}: seams).
Update Appendix A's "Tests covering SPEC ambiguities" preface and the
section 9 historical-resolutions preface to reflect the two newly opened
problems.
- Appendix A traceability matrix updates:
- 10.10 row: add T-INST-111d, T-INST-111e, T-INST-112a4, T-INST-112a5,
T-INST-55v3, T-INST-55x2 (each with short coverage descriptions).
- 10.11 row: add T-INST-55i2, T-INST-55i3, T-INST-55v3, T-INST-55x2,
T-INST-110h, T-INST-112a2, T-INST-112a3, T-INST-112a4, T-INST-112a5
to the front-of-row test list (previously mentioned only in trailing
prose).
- 9.1 row: split the ambiguous "T-API-64b–64e" range into explicit
"T-API-64b, T-API-64b2, T-API-64c, T-API-64d, T-API-64e" and add
T-API-65u2 / T-API-65u3 / T-API-68s2 / T-API-69r2 with descriptions.
- 9.5 row: split "T-API-64–64e" into explicit IDs including
T-API-64b2 and add T-API-65u2 / T-API-65u3 / T-API-68s2 / T-API-69r2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
P-0004-10 (.gitignore safeguard lstat-failure no-mutation guarantee) resolved by amending SPEC §10.10's lstat-failure / write-failure bullet to add explicit no-further-mutation wording; T-INST-112h and T-INST-112n become direct conformance pins. P-0004-11 (auto-install package.json validation timing) resolved by amending SPEC §3.2's "Install" warning-timing bullet (multi-evaluation- point framing) and SPEC §10.10's "Malformed package.json" bullet (committed-state dispatch); T-INST-113i / T-INST-113j / T-INST-113k become direct conformance pins. TEST-SPEC.md section 9 and Appendix A updated to record the resolutions; SPEC-PROBLEMS.md deleted as no entries remain. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address four coverage gaps identified during TEST-SPEC review:
- Add T-INST-113m and T-INST-113n with new section 1.4 seams
(`package-json-remove:`, `package-json-replace-with-valid:`) to pin
the SPEC §10.10 P-0004-11 "committed filesystem state at that moment,
not solely a source/preflight-cached validation result" rule in both
directions: committed-absent (skip) and committed-valid-after-malformed-
preflight (proceed).
- Add T-INST-112o with new section 1.4 seam
(`gitignore-partial-write-fail:`) to pin SPEC §10.10's "Any partial
filesystem effect already produced by a failed write is left for user
remediation" clause on the partial-bytes-on-disk branch, complementing
T-INST-112c's no-bytes-written coverage.
- Add T-API-10c7-c10 covering duck-typed signal × `maxIterations: 0` on
both run() and runPromise() — closing the {real-aborted /
duck-aborted-at-capture / duck-reentrant-listener-fires-only} ×
`maxIterations: 0` × {run() / runPromise()} matrix per SPEC §9.5
duck-signal abort treatment × SPEC §9.3 zero-iteration-short-circuit.
- Open SPEC-PROBLEMS P-0004-12 tracking the scope of SPEC §7.4's
"no stale-tmpdir reaping at startup" rule on programmatic surfaces.
T-TMP-32 (CLI surface) remains a direct conformance pin; T-TMP-32a /
T-TMP-32b are flagged observational pending SPEC clarification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…to TEST-SPEC.md Resolve SPEC-PROBLEMS P-0004-12 by amending SPEC §7.4's startup-non-reaping clause to enumerate the run-creation surfaces explicitly: "loopx does not reap stale tmpdirs during CLI startup, CLI \`loopx run\` setup, or any per-run setup performed for \`run()\` / \`runPromise()\`," with a normative second sentence specifying that a run setup creates only its own \`mkdtemp\` directory and does not scan / validate / remove pre-existing \`loopx-*\` entries under the parent. This is Resolution path (a) of the three resolution paths previously identified at SPEC-PROBLEMS P-0004-12 — matches the cross-surface tmpdir-creation parity already established at SPEC §9.1 / §9.2 / §7.4. Reclassify T-TMP-32a (\`runPromise()\`-surface) and T-TMP-32b (\`run()\`- surface) from observational coverage of the broad reading to direct conformance pins under the amended SPEC §7.4 clause; T-TMP-32 (CLI) was already a direct conformance pin under all three resolution paths. Move P-0004-12 from open-problem to the resolved/historical section in TEST-SPEC §9 and Appendix A. Delete SPEC-PROBLEMS.md since no ADR-0004- scoped problems remain open. Fix two editorial issues in T-TMP-12 prose flagged by the same review: (1) replace misleading "lazy first-\`next()\` snapshot under \`run()\`; eager call-site snapshot under \`runPromise()\`" wording — which conflated option-snapshot timing with inherited-env / tmpdir-parent snapshot timing — with explicit "option values captured at the call site for both surfaces; under \`run()\` the captured error is surfaced on first \`next()\`" framing; (2) update stale "seventeen distinct pre-iteration failure modes" sub-case counts in T-TMP-12 opening prose and T-TMP-12-cli prose to "twenty-five sub-cases," matching the closing summary's count. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…TEST-SPEC.md Open SPEC-PROBLEMS P-0004-13 tracking SPEC §10.11's underspecified behavior for selected install-source symlinks whose targets resolve inside the install source root but are neither regular files nor directories (FIFO, socket, block device, character device). The materialization clauses enumerate only file and directory targets, and the rejection clause enumerates only broken / cyclic / out-of-source failure classes — leaving in-source non-file / non-directory targets unspecified. The §10.11 "package.json source symlink precedence" paragraph has the same gap. Three resolution paths documented; preferred direction is to extend the rejection rule to cover in-source non-file / non-directory targets, mirroring the broken / cyclic / out-of-source rejection structure. Add three known-gap annotations to TEST-SPEC.md flagged by the review: - T-DISC-49-block-char-device (project-root `.loopx` block / character device — SPEC §5.1 "or other non-directory entry" enumeration at the project-root layer): added inline after T-DISC-49k and referenced in Appendix A's §5.1 row, mirroring the precedent set by T-TMP-45, T-INST-112-block-char-device, and T-VER-28-block-char-device for the same `mknod(2)` / `CAP_MKNOD` privilege requirement. - T-INST-116o-other-categories (SPEC §10.10 active-child × prior-failure -suppression × signal observed for prior-failure categories other than `npm install` non-zero exit — i.e., `.gitignore` safeguard failure and `npm install` spawn failure prior-failure categories not directly covered): the existing T-INST-116o "Representative-coverage scope" paragraph already explained the limitation but had not been formalized in the explicit known-gap inventory; this commit promotes it to a dedicated known-gap entry inline after T-INST-116o2 and adds a reference to Appendix A's §10.10 row. Deterministic coverage would require ordinal-targeted FAULT seam variants (e.g., `gitignore-write- fail-first`, `npm-spawn-fail-first`) to be added to section 1.4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…to TEST-SPEC.md
Extend SPEC §10.11 to reject install-source symlinks whose targets resolve
in-source to entries that are neither regular files nor directories
(FIFO, socket, block/character device, or other non-regular non-directory
entry), per Resolution A. Mirror the rejection in the `package.json`
source-symlink precedence paragraph. Add T-INST-55ze / T-INST-55zf /
T-INST-55zg as direct conformance pins (with a new section 1.4
`LOOPX_TEST_INSTALL_FAULT=source-target-replace-with-{fifo,socket}:`
seam since FIFOs/sockets aren't carried through git/tarball transports),
list the block/character device sub-cases as known gaps, and update
section 9 / Appendix A / section 1.3 to reflect P-0004-13's resolution.
Delete SPEC-PROBLEMS.md (no remaining open ADR-0004 problems).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add T-TMP-12-cli-missing-loopx (CLI counterpart for missing .loopx/ discovery failure not creating a tmpdir). - Add T-TMP-12-env-file-unreadable / T-TMP-12-cli-env-file-unreadable for the no-tmpdir-creation contract on EACCES local envFile failures (companions to the existing missing-file and global-env-unreadable sub-cases). - Add LOOPX_TEST_AUTOINSTALL_FAULT=package-json-make-unreadable seam and rewrite T-INST-113a / T-INST-113c2(i) / T-INST-113l(l-unreadable) to use it, so the unreadable-package.json failure mode is exercised on the SPEC §10.10 dispatch-time committed state rather than relying on source mode 000 surviving SPEC §10.7 stage-then-commit. - Add narrowed no-progress-indicator assertions to T-INST-119b and T-INST-119c so the failure-path coverage matches T-INST-119(c). - Extend T-INST-55l2 with cycle / out-of-source-file / out-of-source-directory variants so the SPEC §10.11 vs §10.10 precedence pin holds across all four failure classes for the special .gitignore filename. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Synchronize the high-level known-gap inventory in §1.3 and Appendix A §8.1 with the inline known-gap notes in §4.9 (global-env-file path-resolution × cross-iteration reuse) and §4.10 (T-INST-116o-other-categories — active-child × prior-failure-suppression for non-npm-non-zero categories). No SPEC change; no test removal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add static-duck-aborted carve-out variants (T-API-68v / T-API-69u), the non-`run` CLI startup non-reaping test (T-TMP-32c), programmatic parity tests for the no-warning symlink cleanup branches (T-TMP-34a/b top-level, T-TMP-37d/e nested), parameterize T-INST-120e across the five SPEC 3.2 malformed-`package.json` causes, and cross-reference T-INST-60q/r/s/t from T-INST-111c for matrix completeness. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Fix T-TMP-32c c-version sub-case to use `loopx version` only — `loopx --version` is not valid per SPEC §4.2 which defines `-h` / `--help` as the only recognized top-level flag. - Add c-parser-error sub-case to T-TMP-32c covering the SPEC §7.4 "CLI startup" non-reaping rule on the parser-error dispatch path (structurally distinct from the help / version / no-args success short-circuits), preserving the parser-error coverage that was implicit in the prior incorrect `loopx --version` invocation. - Update Appendix A §7.4 row to explicitly list T-TMP-32c, T-TMP-34a, T-TMP-34b, T-TMP-37d, T-TMP-37e (already covered in the body). - Update Appendix A §8.3 and §9.5 rows to explicitly list T-API-58b, T-API-58c, T-API-58d, T-API-58f, T-API-58f2 (previously only partially referenced in prose within neighbouring entries). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Relax over-specified diagnostic-category assertions in T-INST-55ze/zf/zg, T-VER-28, T-VER-28c, T-VER-28m, T-INST-113h, and T-TMP-12f5: SPEC requires rejection / warning behavior but does not normatively require category- distinct diagnostic wording. Add boolean / symbol / bigint primitive variants to RunOptions.env whole-env shape (T-API-53e/f/g) and outer options shape (T-API-61c2, T-API-61e2) so the matrix-completion claims hold across the typeof axis. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add four tests closing residual gaps in the ADR-0004 surface: - T-INST-55zj: source-root single-workflow script symlink rejected preflight when target is FIFO/socket; closes the SPEC §10.11 rejection-rule axis the existing in-workflow / multi-workflow alias / package.json / symlinked-ancestor tests left uncovered. - T-INST-55l3: bad source `.gitignore` symlink resolving in-source to FIFO/socket is rejected by §10.11 preflight before §10.10 safeguard pathway runs; pins the precedence invariant on the special filename for the FIFO/socket failure class to match T-INST-55l2's broken / cyclic / out-of-source coverage. - T-TERM-05: CLI surface, child-exit observed first, signal arrives before outcome dispatch — surfaced exit code reflects the script-failure outcome (1), not the second-observed signal (143); asserts cleanup-warning cardinality remains at most one. - T-INST-119d: byte-shape hardening for SPEC §10.10 npm-passthrough contract via leading/trailing whitespace, embedded tabs, no trailing newline, and multi-byte UTF-8 — catches trimming / line-normalization bugs that line-marker tests miss. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fix bookkeeping/wording issues raised in TEST-SPEC review:
- Extend P-0004-13 traceability in section 1.3, section 9, and Appendix
A's 10.11 row to include T-INST-55l3 and T-INST-55zj (now six axes
rather than four, with matching block/character device known-gap
entries).
- Clarify that the source-target-replace-with-{fifo,socket} seams in
section 1.4 must run before install-time workflow/script discovery
and §10.11 validation (not merely before a per-workflow validation
pass), and list T-INST-55zi/55l3/55zj as additional consumers.
- Add T-INST-119d to Appendix A's 10.10 row.
- Add the §7.4 sub-step 2 non-recursive rmdir guarantee to Appendix
A's 7.4 known-gap list for consistency with section 1.3 / 4.7.
- Fix T-VER-28ah's taxonomy phrase: a missing-script during qualified
goto resolution is its own §7.4 cleanup trigger, not a child-launch
failure.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Soften T-INST-119d to remove the overclaim that its byte-exact substring assertions catch final-newline-injection / tail-byte-mutation bugs. Under the test's existing scope note (auxiliary loopx output is admitted before/after the npm payload), a substring match cannot prove no byte was appended after the npm payload. Replace that bug-class with the line-buffered drop-partial-line bug class that the no-trailing-newline payload actually does catch, and add an explicit limitation note plus a matching index-row qualifier pointing to the future SPEC §10.10 exact-stream-equality clarification path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.