Skip to content

release: v2.0.0 - mark HoldMyTask default/alias export change as breaking - #7

Merged
Shinrai merged 31 commits into
masterfrom
next
Aug 9, 2026
Merged

release: v2.0.0 - mark HoldMyTask default/alias export change as breaking#7
Shinrai merged 31 commits into
masterfrom
next

Conversation

@cldmv-bot

@cldmv-bot cldmv-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🚀 What's Changed

💥 Breaking Changes

✨ Features

No new features

🐛 Bug Fixes

📦 Dependencies

🔧 Other Changes

👥 Contributors

coverage

Metric Coverage
Statements 79.7%
Branches 73.5%
Functions 71.2%
Lines 80.7%

Avg: 76.3% · b01514e · Node lts/*

Shinrai and others added 3 commits August 3, 2026 21:43
…coded master/main)

The concurrency group must never supersede release-relevant runs so the release
PR posts a green check. The base branch is now DERIVED the same way
resolve-release-base does — the CLDMV_RELEASE_BASE var, else the repo's
default_branch — instead of the hardcoded refs/heads/master || refs/heads/main.
next/hotfixes stay literal (the flow's fixed integration branches) and the
release-PR detection (github.head_ref == next/hotfixes) was already base-agnostic.

Mirrors the CLDMV/.github core-cicd ci.yml template.
@cldmv-bot cldmv-bot Bot added ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: patch This release contains only backwards-compatible bug fixes type: bug Something is broken or not behaving as expected labels Aug 4, 2026
@cldmv-bot

cldmv-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

🔒 Dependency Review

  • 0 vulnerable package(s)
  • 0 package(s) with incompatible licenses
  • 0 package(s) with invalid SPDX license definitions
  • 0 package(s) with unknown licenses
  • 0 denied package(s)
  • 0 package(s) with OpenSSF Scorecard score < 3

Full job summary

@cldmv-bot cldmv-bot Bot added type: ci Changes to CI workflows, actions, or build pipelines type: config Changes to repository or project configuration files type: dependencies Relates to dependency updates, version bumps, or package management labels Aug 4, 2026
Shinrai
Shinrai previously approved these changes Aug 4, 2026
Shinrai and others added 6 commits August 4, 2026 05:48
…n file

The "bypassed task still applies its own completion delay" test hangs to the
30s vitest timeout on the lts/* CI matrix job every time it runs there, while
the explicit 20/22/24 jobs (same Node binary) pass. Doesn't reproduce locally,
including under CPU throttling. Moving it out of HoldMyTask.test.vitest.mjs
(72 tests, ~34 of which never call destroy() on their queue instance) into its
own file isolates it from any state/timer accumulation earlier tests in that
file might leave behind, to see if that's a factor.
…-reschedule

_scheduleNextTick() only derived its next wake time from pendingHeap and
nextAvailableTime. If it ran at the exact moment nextAvailableTime had just
expired (a narrow race against schedulerTick's own timing) with pendingHeap
empty, nextTime fell through to Infinity, arming a ~24.8-day setTimeout and
stranding any task already sitting in readyHeap - a permanent hang, not a
slow test. This is what caused the bypassDelay + concurrency:1 + postDelay
tests to intermittently time out at exactly 30000ms on CI's lts/* job.
Reproduced locally via a stress loop (1 stall per ~6000 iterations); the
fix (accounting for a non-empty readyHeap when computing nextTime) ran
20000 iterations with zero stalls.
…inity

Addresses PR #8 review feedback: the prior fix forced nextTime = now
whenever readyHeap was non-empty, which degrades an active post-completion
delay into a 25ms setInterval poll loop instead of a single setTimeout.
Narrow the guard to only fire when nextTime would otherwise fall through
to Infinity - the actual stranded-ready-task case. Verified: 20000-iteration
stress run stays at 0 stalls, and a normal delayed task now arms a single
timeoutId (not intervalId) again.

Also addresses three test-file review comments: a stale "priority 2" code
comment, wrap the isolated test's assertions in try/finally with `once`
instead of `on` so q.destroy() always runs even on assertion failure, and
a grammar fix in the file header comment.
Bumps the minor group with 1 update: [prettier](https://github.com/prettier/prettier).


Updates `prettier` from 3.6.2 to 3.9.6
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](prettier/prettier@3.6.2...3.9.6)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.9.6
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.19.24 to 26.1.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.1.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps the minor group with 1 update:
[prettier](https://github.com/prettier/prettier).

Updates `prettier` from 3.6.2 to 3.9.6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.9.6</h2>
<h2>What's Changed</h2>
<ul>
<li>Preserve quotes for methods named <code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19621">prettier/prettier#19621</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</li>
<li>Support <code>import defer</code> in <code>typescript</code> parser
(<a
href="https://redirect.github.com/prettier/prettier/pull/19624">prettier/prettier#19624</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19675">prettier/prettier#19675</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</li>
<li>Added a new official plugin <a
href="https://github.com/prettier/prettier/tree/3.9.6/packages/plugin-yuku"><code>@prettier/plugin-yuku</code>
🚀</a> (<a
href="https://redirect.github.com/prettier/prettier/pull/19628">prettier/prettier#19628</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19629">prettier/prettier#19629</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.6/CHANGELOG.md#396">Changelog</a></p>
<h2>3.9.5</h2>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.5/CHANGELOG.md#395">Changelog</a></p>
<h2>3.9.4</h2>
<ul>
<li>Angular: Format <code>@content(name)</code> -&gt; <code>@content
(name)</code> to align with other block syntax (<a
href="https://redirect.github.com/prettier/prettier/pull/19499">#19499</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.4/CHANGELOG.md#394">Changelog</a></p>
<h2>3.9.3</h2>
<ul>
<li>Markdown: Fix unexpected removal of characters in liquid syntax (<a
href="https://redirect.github.com/prettier/prettier/pull/19489">prettier/prettier#19489</a>
by <a href="https://github.com/seiyab"><code>@​seiyab</code></a>)</li>
<li>TypeScript: Allow decorators to be used with declare on class fields
(<a
href="https://redirect.github.com/prettier/prettier/pull/19492">prettier/prettier#19492</a>
by <a
href="https://github.com/evoactivity"><code>@​evoactivity</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.3/CHANGELOG.md#393">Changelog</a></p>
<h2>3.9.1</h2>
<ul>
<li>CLI: Fix ignored file has been cached incorrectly (<a
href="https://redirect.github.com/prettier/prettier/pull/19483">#19483</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.1/CHANGELOG.md#391">Changelog</a></p>
<h2>3.9.0</h2>
<p><a
href="https://github.com/prettier/prettier/compare/3.8.5...3.9.0">diff</a></p>
<p>🔗 <a href="https://prettier.io/blog/2026/06/27/3.9.0">Prettier 3.9:
Major parser upgrades and Formatting improvements</a></p>
<h2>3.8.5</h2>
<ul>
<li>Fix Flow variance annotation print (<a
href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a>
by <a
href="https://github.com/marcoww6"><code>@​marcoww6</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.8.5/CHANGELOG.md#385">Changelog</a></p>
<h2>3.8.4</h2>
<ul>
<li>Markdown: Fix blank lines between list items and nested sub-lists
being removed in Markdown/MDX (<a
href="https://redirect.github.com/prettier/prettier/pull/17746">prettier/prettier#17746</a>
by <a
href="https://github.com/byplayer"><code>@​byplayer</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.8.4/CHANGELOG.md#384">Changelog</a></p>
<h2>3.8.3</h2>
<ul>
<li>SCSS: Prevent trailing comma in <code>if()</code> function (<a
href="https://redirect.github.com/prettier/prettier/pull/18471">prettier/prettier#18471</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.8.3/CHANGELOG.md#383">Changelog</a></p>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.9.6</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.9.5...3.9.6">diff</a></p>
<h4>TypeScript: Preserve quotes for methods named <code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19621">#19621</a>
by <a href="https://github.com/kovsu"><code>@​kovsu</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="tsx"><code>// Input
interface Container {
  &quot;new&quot;(id: string): number;
}
<p>// Prettier 3.9.5<br />
interface Container {<br />
new(id: string): number;<br />
}</p>
<p>// Prettier 3.9.6<br />
interface Container {<br />
&quot;new&quot;(id: string): number;<br />
}<br />
</code></pre></p>
<h4>TypeScript: Support <code>import defer</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19624">#19624</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19675">#19675</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="tsx"><code>// Input
import defer * as foo from &quot;foo&quot;;
<p>// Prettier 3.9.5<br />
import * as foo from &quot;foo&quot;;</p>
<p>// Prettier 3.9.6<br />
import defer * as foo from &quot;foo&quot;;<br />
</code></pre></p>
<h4>JavaScript: Added a new official plugin
<code>@prettier/plugin-yuku</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/19628">#19628</a>,
<a
href="https://redirect.github.com/prettier/prettier/pull/19629">#19629</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<p><code>@prettier/plugin-yuku</code> is powered by <a
href="https://yuku.fyi/">Yuku</a> (A high-performance
JavaScript/TypeScript compiler toolchain written in Zig).</p>
<p>This plugin includes two new parsers: <code>yuku</code> (JavaScript
syntax) and <code>yuku-ts</code> (TypeScript syntax).</p>
<p><strong>To use this plugin:</strong></p>
<ol>
<li>
<p>Install the plugin:</p>
<pre lang="bash"><code>yarn add --dev prettier @prettier/plugin-yuku
</code></pre>
</li>
</ol>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/prettier/prettier/commit/8f0c95057cc91d5836409466cd9d9af3bb901e84"><code>8f0c950</code></a>
Release 3.9.6</li>
<li><a
href="https://github.com/prettier/prettier/commit/e9107647d0497d8ff1cacbb0f970d4543df77c1c"><code>e910764</code></a>
Update changelog</li>
<li><a
href="https://github.com/prettier/prettier/commit/ec3f1c7bd74495992bc6954323a1a7fc8368808e"><code>ec3f1c7</code></a>
Update typescript-eslint to v8.65.0 (<a
href="https://redirect.github.com/prettier/prettier/issues/19675">#19675</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/73d2efc2c6cba6f579585c88ef171132d90834ec"><code>73d2efc</code></a>
Update Yuku parser to v0.7.0 (<a
href="https://redirect.github.com/prettier/prettier/issues/19664">#19664</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/dd5e24eabeab1f75ad573c79781e5fd408bcfad3"><code>dd5e24e</code></a>
Preserve quotes for <code>TSMethodSignature</code> nodes named
<code>new</code> (<a
href="https://redirect.github.com/prettier/prettier/issues/19621">#19621</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/c03ab4e71c23154d6b11537eee3c938f0d0f67d3"><code>c03ab4e</code></a>
Update dependency eslint-plugin-unicorn to v72 (<a
href="https://redirect.github.com/prettier/prettier/issues/19633">#19633</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/b74dd53076c7208291a6b2e585c310844b41d35f"><code>b74dd53</code></a>
Update Yuku parser to v0.6.5 (<a
href="https://redirect.github.com/prettier/prettier/issues/19654">#19654</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/f1b594ea1db1520c383d0e281d623551f671f824"><code>f1b594e</code></a>
Update dependency eslint-plugin-simple-import-sort to v14 (<a
href="https://redirect.github.com/prettier/prettier/issues/19655">#19655</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/0d9dfb61530986373000dd107ea58ceebb79e233"><code>0d9dfb6</code></a>
Update Yuku parser to v0.6.4 (<a
href="https://redirect.github.com/prettier/prettier/issues/19650">#19650</a>)</li>
<li><a
href="https://github.com/prettier/prettier/commit/3bbb8159eb55575d4042653aa99f5f92a1416c19"><code>3bbb815</code></a>
Remove <code>typescript-only</code> directory (<a
href="https://redirect.github.com/prettier/prettier/issues/19636">#19636</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/3.6.2...3.9.6">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new
releaser for prettier since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prettier&package-manager=npm_and_yarn&previous-version=3.6.2&new-version=3.9.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>
Shinrai added 8 commits August 7, 2026 11:55
index.mjs exported HoldMyTask, Queue, TaskManager, TaskQueue, QueueManager,
and TaskProcessor as async factory functions (createHoldMyTask() and
friends) rather than the actual HoldMyTask class, so `new QueueManager()`
etc. threw "QueueManager is not a constructor" - the entire
CommonAliases.test.vitest.mjs suite (35/36 tests) was failing and had been
worked around by skipping the whole file rather than fixed (#3).

index.cjs already assumed the ESM HoldMyTask export was the real class
(`module.exports = HoldMyTask`), and every README/example already used
`new HoldMyTask(...)` - the async-factory pattern was the actual bug, not
the tests or the CJS bridge.

Switches index.mjs to a static top-level import of the real HoldMyTask
class from @cldmv/holdmytask/main and re-exports it (and its aliases)
directly. The createHoldMyTask/createQueue/createTaskManager/
createTaskProcessor async factory functions are kept as-is for backward
compatibility, just simplified to use the now-eagerly-loaded class instead
of a fresh dynamic import per call.

Un-skips CommonAliases.test.vitest.mjs (all 36 tests now pass) and
regenerates types/index.d.mts via `npm run build:types` to match the new
export shapes.
Addresses PR #8 review feedback (suppressed comment on src/hold-my-task.mjs:1633):
no regression test covered the specific failure mode the fix addresses, so a
future refactor of _scheduleNextTick()/schedulerTick() could reintroduce the
24.8-day timeout fallback silently.

Uses the constructor's injectable `now` option to deterministically force the
exact race (a readyHeap task whose delay has just expired, with pendingHeap
empty) instead of relying on real wall-clock timing luck. Verified the test
fails against the pre-fix code (armed a ~2147483647ms setTimeout) and passes
with the fix (armed delay < 1000ms).
…yTask

Addresses PR #11 review feedback: the factory functions' JSDoc @returns
was Promise<object>, losing the actual return type now that HoldMyTask is
statically imported and in scope. Regenerated types/index.d.mts via
`npm run build:types`.
Addresses PR #11 review feedback: the PR's auto-generated changelog
claimed "No breaking changes", but cbc1ac7 changed the default export
(and the HoldMyTask/Queue/TaskManager/TaskQueue/QueueManager/TaskProcessor
named aliases) from an async factory function to the real HoldMyTask
class. Code that previously called these as functions - e.g.
`await HoldMyTask()`, or `await (await import("@cldmv/holdmytask")).default()`
- now gets "Class constructor HoldMyTask cannot be invoked without 'new'"
and must switch to `new HoldMyTask()` / `new QueueManager()` etc. instead.

This matches the already-documented `new HoldMyTask(options)` usage
throughout README and every example, and the existing CJS bridge
(index.cjs), which already assumed the ESM default export was the class -
only the previously-buggy async-factory calling convention on these
specific export names is removed.

BREAKING CHANGE: HoldMyTask, Queue, TaskManager, TaskQueue, QueueManager,
TaskProcessor, and the package default export are now the real HoldMyTask
class instead of an async factory function. Use `new HoldMyTask(options)`
(or `new QueueManager(options)`, etc.) instead of calling them as
functions. The createHoldMyTask/createQueue/createTaskManager/
createTaskProcessor named async factory functions are unchanged.
The devcheck/src-dist machinery was inherited from @cldmv/slothlet but
diverged in two ways that mattered for a normal module:

1. The /main export used the GENERIC `development` condition to route to
   src/, but the published package ships dist/ only (no src/). Any consumer
   running with `--conditions=development` (a common dev setting) therefore
   resolved @cldmv/holdmytask/main to ./src/hold-my-task.mjs, which isn't in
   the tarball -> ERR_MODULE_NOT_FOUND. This shipped in v1.6.2. Slothlet
   avoids it by namespacing its condition (`slothlet-dev`); do the same here
   with `holdmytask-dev` so a consumer's generic conditions can never route
   this package to a source tree it doesn't ship.

2. devcheck.mjs had its `!existsSync(dist)` guard commented out (so it would
   nag even after a build) and its installed-package guard checked only the
   immediate parent dir for "node_modules" — which never matches a SCOPED
   package (`node_modules/@cldmv/holdmytask`, parent is `@cldmv`). Restored
   the dist guard and fixed the check to detect a node_modules segment
   anywhere above the file (covers scoped + unscoped installs).

Also:
- Add `prepare: npm run build` so a fresh checkout's install produces dist/,
  keeping the package usable from a clone without setting the dev condition
  (build is a dependency-free ~0.25s file copy).
- Route the condition through CI (ci.yml test_environment -> holdmytask-dev)
  and vitest (resolve/ssr conditions include holdmytask-dev) so tests still
  exercise src/. Verified: with dist absent, the package entry resolves to
  src only via holdmytask-dev; a generic `development` condition no longer
  does.
- Add tests/DevCheck.test.vitest.mjs (7 cases) validating the guard across
  unbuilt-checkout, condition-set, dist-built, generic-condition, CI,
  scoped-install, and no-src scenarios.
Follow-up to the initial commit, correcting it against the established
normal-module devcheck fix in @cldmv/uuid (the repo that first solved the
generic-condition collision by namespacing to `uuid-dev`).

- devcheck.mjs: the warning is INTENTIONAL whenever src/ is present and the
  dev condition isn't set - a built checkout has both src/ and dist/, and the
  developer should be running from src/ via the condition, so flagging that
  they're silently on dist/ is the point. Removed the `!existsSync(dist)`
  guard added in the previous commit (which wrongly silenced it after a
  build). Also removed the node_modules/installed-package guard: the published
  package ships neither src/ nor devcheck.mjs, so index.mjs's
  `import("./devcheck.mjs")` just fails and is ignored - it never runs for
  consumers, so there's nothing to guard. Guard logic now mirrors uuid.
- Dropped the `prepare: npm run build` script - not part of the reference
  pattern (uuid has none); the nag model expects you to build or set the
  condition, not auto-build on install.
- vitest config: carry the condition into forked workers via
  `test.nodeOptions` + `test.env.NODE_ENV` (mirrors uuid) rather than relying
  on resolve/ssr conditions alone.
- Reverted the ci.yml `test_environment` change - uuid leaves it at the
  reusable-workflow default and lets the vitest config carry the condition.
- Updated DevCheck tests to the corrected behavior (notably: STILL nags when
  dist/ is present but the condition is unset).
…id's NODE_ENV logic

The previous commit over-corrected by mirroring @cldmv/uuid's devcheck
verbatim, which regressed the trigger to uuid's NODE_ENV-coupled form. That
form is wrong for what devcheck detects, because ONLY the
`--conditions=holdmytask-dev` condition selects src/ (NODE_ENV does not):

- NODE_ENV=development with no condition -> uuid stays silent, but the package
  is actually resolving to dist/ (false negative - the exact case to catch).
- condition set but NODE_ENV unset -> uuid nags even though you're correctly
  on src/ (false positive).

Restore the condition-only trigger, and additionally detect the condition in
process.execArgv, not just NODE_OPTIONS: node accepts `--conditions=` on the
CLI (landing in execArgv) and that's how vitest passes it to workers - a probe
showed NODE_OPTIONS is undefined in a worker while execArgv carries the flag,
so the NODE_OPTIONS-only check (both mine originally and uuid's) would have
spuriously fired inside the CommonAliases entry-import test and only avoided it
by racing devcheck's fire-and-forget import. Checking both makes it correct and
deterministic.

Kept from the reference direction: the nag stays on after a build (no
`!existsSync(dist)` guard). Kept my own additions uuid lacks: the scoped-aware
node_modules install guard (protects git/tarball-install consumers) and the
DevCheck test suite (now 9 cases, incl. execArgv form, NODE_ENV-doesn't-silence,
still-nags-after-build, and scoped-install skip).
…odule in ssr conditions

Addresses PR #12 Copilot review:

- devcheck.mjs: parse the actual `--conditions` values (from execArgv and
  NODE_OPTIONS, handling `=`/space/`-C`/comma forms) and match `holdmytask-dev`
  EXACTLY, instead of a substring `.includes()` that would false-positive on
  e.g. `--conditions=not-holdmytask-dev`. (Same fix as CLDMV/uuid#10.) Added
  regression tests: rejects a substring-containing condition; accepts
  holdmytask-dev among comma-separated conditions.
- .configs/vitest.config.mjs: removed the `test.env.NODE_ENV=holdmytask-dev`
  override - it doesn't select the conditional export (that's `--conditions`,
  carried via nodeOptions) and forcing a non-standard NODE_ENV can confuse deps
  keying off test/development/production. Added `module` to ssr.resolve.conditions
  so a dependency's `module`-keyed export resolves the same under Vitest's SSR
  pipeline as in the non-SSR resolver.
Shinrai and others added 4 commits August 8, 2026 10:03
The `./devcheck` -> `./devcheck.mjs` export pointed at a file not in the
published `files` allowlist (verified via npm pack: devcheck.mjs isn't in the
tarball), so `import "@cldmv/holdmytask/devcheck"` 404s for consumers.
devcheck is an internal dev-time guard that index.mjs loads via a relative
import, not the package export - nothing imports the subpath. Removing the
dead export makes package.json honest. (Copilot review on #12.)
… restore

Addresses the suppressed Copilot comment on PR #8
(BypassDelayCompletionTiming.test.vitest.mjs:130): the regression test called
setTimeoutSpy.mockRestore() unconditionally right after _scheduleNextTick(),
so a throw there would leak the global spy into later tests, and it read
mock.calls after restoring. Now wrap the _scheduleNextTick() call in
try/finally, capture the recorded calls into a local before restoring, and
restore the spy in the finally so cleanup is guaranteed.
Addresses the suppressed Copilot comment on PR #11 (index.mjs:23): the comment
claimed the devcheck "must happen before holdmytask imports", but the static
`import` of the core is hoisted and evaluated before the devcheck IIFE runs, so
that ordering isn't real. Reworded to state devcheck is a best-effort,
fire-and-forget dev-time warning that does NOT run before the core loads, and
why (running it strictly first needs top-level await, which breaks index.cjs's
synchronous require). Regenerated the types sourcemap (source positions shifted;
the .d.ts itself is unchanged).
@cldmv-bot cldmv-bot Bot added the area: tests Touches test files, fixtures, or test infrastructure label Aug 9, 2026
@cldmv-bot cldmv-bot Bot changed the title release: v1.6.3 - derive release base in never-supersede concurrency… release: v2.0.0 - mark HoldMyTask default/alias export change as breaking Aug 9, 2026
Shinrai and others added 5 commits August 8, 2026 17:07
…e split)

Addresses the second Copilot re-review on PR #12 (2 suppressed comments):

- devcheck.mjs: stop splitting condition values on `,`/`|`. Node treats each
  `--conditions` occurrence as ONE literal condition and does not split on comma
  or pipe (verified: `--conditions=holdmytask-dev,x` and
  `--conditions=holdmytask-dev|production` do NOT enable holdmytask-dev). The old
  split caused a false negative - `holdmytask-dev|production` would silence
  devcheck while Node actually resolved to dist/. Now collect each value whole
  and match exactly. Fixed the test that wrongly asserted comma-joined silences
  (now asserts it nags), and added pipe-joined-nag plus space-separated
  (`--conditions holdmytask-dev`) and repeated-flag silent cases.
- tests/DevCheck.test.vitest.mjs: added the standard project header block so it
  isn't an outlier vs the other test files.
Addresses the suppressed Copilot comment on PR #8
(BypassDelayCompletionTiming.test.vitest.mjs:68): the `drain` await sat OUTSIDE
the try/finally, so if drain is never emitted - the exact deadlock this file
exists to catch - the test would hang to vitest's 30s global timeout and never
run q.destroy(), leaking timers. Moved the wait inside the try and raced it
against a 5s timeout that rejects with a clear message, so the failure surfaces
fast and cleanup always runs.
Addresses the suppressed Copilot comment on PR #12
(.configs/vitest.config.mjs:17): the comment still mentioned `test.env` carrying
the dev condition into workers, but that override was removed earlier in this PR.
Comment now references only `test.nodeOptions`, which is what actually carries it.
…sleep

Addresses the suppressed Copilot comment on PR #8
(BypassDelayCompletionTiming.test.vitest.mjs:115): the regression test used a
hard-coded 120ms sleep to assume task1 had completed and task2 had reached
readyHeap, which is nondeterministic on slow/contended CI. Replaced it with a
bounded poll (2s deadline) on the observable condition - task1 in results and
task2 parked in readyHeap - and kept it inside the try so q.destroy() still runs
if it ever times out.
@cldmv-bot cldmv-bot Bot added area: core Touches core library / runtime source code semver: major This release includes breaking changes and bumps the major version and removed semver: patch This release contains only backwards-compatible bug fixes labels Aug 9, 2026
Shinrai and others added 4 commits August 8, 2026 20:16
…nvalid -C= form

Addresses the 2 suppressed comments on PR #12's latest review:

- devcheck.mjs: the space-form branch (`--conditions x` / `-C x`) consumed
  tokens[i+1] as the value but did not advance the loop index, so a value that
  itself looks like a flag (e.g. `--conditions --conditions=x`) was
  double-processed. Now increment i past the consumed value token.
- Dropped the `-C=` branch: Node rejects `-C=value` outright ("bad option"), so
  it can never appear in execArgv/NODE_OPTIONS - it was dead code. Valid forms
  are `--conditions=x`, `--conditions x`, and `-C x`.
- Added -C short-flag test coverage (space form; verified Node rejects `-C=`).
…om dist/"

Addresses the suppressed Copilot comment on PR #12 (devcheck.mjs:87): the
message asserted "holdmytask is loading from dist/", which isn't necessarily
true - when devcheck runs standalone (test fixtures) or in an unbuilt checkout,
dist/ may not exist at all. Reworded to describe default resolution behavior
("imports resolve to dist/ by default, or fail if it isn't built") rather than
asserting the current runtime is definitely on dist/.
@Shinrai
Shinrai merged commit d44cf85 into master Aug 9, 2026
37 checks passed
@cldmv-bot
cldmv-bot Bot deleted the next branch August 9, 2026 06:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: core Touches core library / runtime source code area: tests Touches test files, fixtures, or test infrastructure ! release → master v4 flow: persistent next → master release PR (carries the next feature release) release Marks a pull request as a pending release — merge to publish a new version semver: major This release includes breaking changes and bumps the major version type: bug Something is broken or not behaving as expected type: ci Changes to CI workflows, actions, or build pipelines type: config Changes to repository or project configuration files type: dependencies Relates to dependency updates, version bumps, or package management

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant