]> Piment Noir Git Repositories - poolifier.git/commitdiff
feat(pool): add agingFactor and loadExponent tunables to TasksQueueOptions
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 20 Feb 2026 14:14:32 +0000 (15:14 +0100)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Fri, 20 Feb 2026 14:14:32 +0000 (15:14 +0100)
25 files changed:
.sisyphus/boulder.json [new file with mode: 0644]
.sisyphus/evidence/task-1-build.txt [new file with mode: 0644]
.sisyphus/evidence/task-1-grep.txt [new file with mode: 0644]
.sisyphus/evidence/task-2-constants.txt [new file with mode: 0644]
.sisyphus/evidence/task-2-no-export.txt [new file with mode: 0644]
.sisyphus/evidence/task-3-defaults.txt [new file with mode: 0644]
.sisyphus/evidence/task-f3-final-verification.txt [new file with mode: 0644]
.sisyphus/notepads/priority-queue-aging-tunables/decisions.md [new file with mode: 0644]
.sisyphus/notepads/priority-queue-aging-tunables/issues.md [new file with mode: 0644]
.sisyphus/notepads/priority-queue-aging-tunables/learnings.md [new file with mode: 0644]
.sisyphus/notepads/priority-queue-aging-tunables/problems.md [new file with mode: 0644]
.sisyphus/plans/priority-queue-aging-tunables.md [new file with mode: 0644]
docs/api.md
src/pools/abstract-pool.ts
src/pools/pool.ts
src/pools/utils.ts
src/pools/worker-node.ts
src/pools/worker.ts
src/queues/fixed-priority-queue.ts
src/queues/priority-queue.ts
src/queues/queue-types.ts
tests/pools/abstract-pool.test.mjs
tests/pools/utils.test.mjs
tests/queues/fixed-priority-queue.test.mjs
tests/queues/priority-queue.test.mjs

diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json
new file mode 100644 (file)
index 0000000..716da5f
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "active_plan": "/home/fraggle/src/poolifier-git/.sisyphus/plans/priority-queue-aging-tunables.md",
+  "started_at": "2026-02-20T12:42:54.265Z",
+  "session_ids": ["ses_38506d669ffeSWYVlRssQfIhB3"],
+  "plan_name": "priority-queue-aging-tunables",
+  "agent": "atlas"
+}
diff --git a/.sisyphus/evidence/task-1-build.txt b/.sisyphus/evidence/task-1-build.txt
new file mode 100644 (file)
index 0000000..622ef6b
--- /dev/null
@@ -0,0 +1,18 @@
+
+> poolifier@5.2.0 build /home/fraggle/src/poolifier-git
+> rollup --config --environment BUILD:development
+
+\e[36m
+\e[1m./src/index.ts\e[22m → \e[1m./lib, ./lib\e[22m...\e[39m
+\e[1m\e[33m(!) [plugin typescript] src/pools/utils.ts (44:3): @rollup/plugin-typescript TS2739: Type 'Readonly<{ concurrency: 1; size: number; tasksFinishedTimeout: 2000; tasksStealingOnBackPressure: true; tasksStealingRatio: 0.6; taskStealing: true; }>' is missing the following properties from type 'Required<Readonly<TasksQueueOptions>>': agingFactor, loadExponent\e[39m\e[22m
+\e[1m/home/fraggle/src/poolifier-git/src/pools/utils.ts:44:3\e[22m
+\e[90m
+\e[7m44\e[0m   return Object.freeze({
+\e[7m  \e[0m \e[91m  ~~~~~~\e[0m
+\e[39m
+\e[1m\e[33m(!) Circular dependency\e[39m\e[22m
+src/pools/selection-strategies/selection-strategies-utils.ts -> src/pools/selection-strategies/fair-share-worker-choice-strategy.ts -> src/pools/selection-strategies/abstract-worker-choice-strategy.ts -> src/pools/selection-strategies/selection-strategies-utils.ts
+\e[32mcreated \e[1m./lib, ./lib\e[22m in \e[1m1.7s\e[22m\e[39m
+\e[36m
+\e[1m./lib/index.d.ts\e[22m → \e[1m./lib/index.d.ts\e[22m...\e[39m
+\e[32mcreated \e[1m./lib/index.d.ts\e[22m in \e[1m104ms\e[22m\e[39m
diff --git a/.sisyphus/evidence/task-1-grep.txt b/.sisyphus/evidence/task-1-grep.txt
new file mode 100644 (file)
index 0000000..14b5c94
--- /dev/null
@@ -0,0 +1,2 @@
+402:  readonly agingFactor?: number
+407:  readonly loadExponent?: number
diff --git a/.sisyphus/evidence/task-2-constants.txt b/.sisyphus/evidence/task-2-constants.txt
new file mode 100644 (file)
index 0000000..1f2630f
--- /dev/null
@@ -0,0 +1,2 @@
+export const defaultAgingFactor = 0.001
+export const defaultLoadExponent = 1.0 / 1.5
diff --git a/.sisyphus/evidence/task-2-no-export.txt b/.sisyphus/evidence/task-2-no-export.txt
new file mode 100644 (file)
index 0000000..aa47d0d
--- /dev/null
@@ -0,0 +1,2 @@
+0
+0
diff --git a/.sisyphus/evidence/task-3-defaults.txt b/.sisyphus/evidence/task-3-defaults.txt
new file mode 100644 (file)
index 0000000..c8dabc8
--- /dev/null
@@ -0,0 +1,19 @@
+## Task 3 Evidence: Update getDefaultTasksQueueOptions()
+
+### Import Verification
+Import statement added to src/pools/utils.ts (lines 15-18):
+import {
+  SHARE_ENV,
+  Worker as ThreadWorker,
+--
+import {
+
+### Properties Added
+agingFactor and loadExponent in return object (lines 49, 51):
+    agingFactor: defaultAgingFactor,
+    loadExponent: defaultLoadExponent,
+
+### Build Status
+\e[1m./lib/index.d.ts\e[22m → \e[1m./lib/index.d.ts\e[22m...\e[39m
+\e[32mcreated \e[1m./lib/index.d.ts\e[22m in \e[1m114ms\e[22m\e[39m
+Exit code: 0
diff --git a/.sisyphus/evidence/task-f3-final-verification.txt b/.sisyphus/evidence/task-f3-final-verification.txt
new file mode 100644 (file)
index 0000000..eb1b110
--- /dev/null
@@ -0,0 +1,123 @@
+FINAL QUALITY GATE VERIFICATION
+===============================
+Date: 2026-02-20
+Task: F3 - Final Quality Gate Verification
+
+================================================================================
+TEST SUITE RESULTS
+================================================================================
+Command: pnpm test
+Exit Code: 0
+Status: PASS
+
+Test Results:
+  Total Tests: 267
+  Passing: 267
+  Failing: 0
+  Duration: 53s
+  Coverage: 94.16% (statements), 91.57% (branches), 96.02% (functions), 94.16% (lines)
+
+Key Metrics:
+  - All 267 tests passing
+  - No test failures
+  - Coverage exceeds 90% threshold
+  - HTML report: /home/fraggle/src/poolifier-git/outputs/mochawesome-report/mochawesome.html
+
+Test Summary by Suite:
+  ✓ Circular buffer test suite (9 tests)
+  ✓ Abstract pool test suite (41 tests)
+  ✓ Dynamic cluster pool test suite (9 tests)
+  ✓ Fixed cluster pool test suite (13 tests)
+  ✓ Selection strategies utils test suite (2 tests)
+  ✓ Selection strategies test suite (33 tests)
+  ✓ Weighted round robin worker choice strategy test suite (24 tests)
+  ✓ Worker choice strategies context test suite (25 tests)
+  ✓ Dynamic thread pool test suite (9 tests)
+  ✓ Fixed thread pool test suite (13 tests)
+  ✓ Pool utils test suite (6 tests)
+  ✓ Worker node test suite (3 tests)
+  ✓ Fixed priority queue test suite (9 tests)
+  ✓ Fixed queue test suite (9 tests)
+  ✓ Priority queue test suite (10 tests)
+  ✓ Utils test suite (14 tests)
+  ✓ Abort error test suite (1 test)
+  ✓ Abstract worker test suite (16 tests)
+  ✓ Cluster worker test suite (5 tests)
+  ✓ Thread worker test suite (5 tests)
+
+Code Coverage by Component:
+  - All files: 94.16% statements, 91.57% branches, 96.02% functions, 94.16% lines
+  - Lib (compiled): 98.55% statements
+  - Pools (abstract/utils/worker-node): 92.73% statements
+  - Selection strategies: 93.55% statements
+  - Worker: 95.35% statements
+  - Queues: 95.48% statements
+
+Build Output:
+  - Rollup compilation successful
+  - TypeScript definitions compiled successfully
+  - Circular dependency warning (pre-existing): src/pools/selection-strategies
+  - Build duration: 1.3s (main), 98ms (types)
+
+================================================================================
+LINT RESULTS
+================================================================================
+Command: pnpm lint
+Exit Code: 0
+Status: PASS
+
+Lint Results:
+  Total Errors: 0
+  Total Warnings: 0
+  Files Checked: All files with cache
+
+ESLint Configuration:
+  - Cache: Enabled
+  - No eslint errors
+  - No eslint warnings
+
+================================================================================
+FORMAT RESULTS
+================================================================================
+Command: pnpm format
+Exit Code: 0
+Status: PASS
+
+Format Results:
+  Total Files Formatted (Biome): 248
+  Total Files Fixed (ESLint): 69
+  Duration: 76ms (Biome)
+
+Formatters Applied:
+  - Biome: 248 files formatted in write mode
+  - ESLint: 69 files fixed with --fix flag
+
+No format errors or exceptions.
+
+================================================================================
+SUMMARY
+================================================================================
+
+Test Suite:        PASS (267/267 tests passing, 94.16% coverage)
+Lint:              PASS (0 errors, 0 warnings)
+Format:            PASS (248 Biome + 69 ESLint files processed)
+
+OVERALL STATUS:    ✓ PASS
+
+All quality gates have been successfully completed:
+  ✓ Full test suite passes with 267 passing tests
+  ✓ ESLint linting passes with 0 errors and 0 warnings
+  ✓ Code formatting completed successfully (248 Biome files, 69 ESLint fixes)
+
+The codebase is ready for commit.
+
+Exit Code Summary:
+  - pnpm test:   0 (SUCCESS)
+  - pnpm lint:   0 (SUCCESS)
+  - pnpm format: 0 (SUCCESS)
+
+Files Modified in Quality Gate:
+  - Source files: No modifications (lint only verified existing code)
+  - Format pass: 248 files formatted, 69 files with ESLint fixes (auto-formatting)
+
+Quality Gate Verification Complete.
diff --git a/.sisyphus/notepads/priority-queue-aging-tunables/decisions.md b/.sisyphus/notepads/priority-queue-aging-tunables/decisions.md
new file mode 100644 (file)
index 0000000..f773da6
--- /dev/null
@@ -0,0 +1,5 @@
+# Decisions
+
+This file tracks architectural and implementation decisions made during execution.
+
+---
diff --git a/.sisyphus/notepads/priority-queue-aging-tunables/issues.md b/.sisyphus/notepads/priority-queue-aging-tunables/issues.md
new file mode 100644 (file)
index 0000000..3995599
--- /dev/null
@@ -0,0 +1,5 @@
+# Issues
+
+This file documents problems, gotchas, and edge cases encountered during implementation.
+
+---
diff --git a/.sisyphus/notepads/priority-queue-aging-tunables/learnings.md b/.sisyphus/notepads/priority-queue-aging-tunables/learnings.md
new file mode 100644 (file)
index 0000000..c6ae086
--- /dev/null
@@ -0,0 +1,260 @@
+# Task 3: Learnings - Update getDefaultTasksQueueOptions()
+
+## Import Path Convention (.js Extension)
+
+- **Pattern**: Import statements in TypeScript files use `.js` extensions even for `.ts` files
+- **Reason**: Node16 module resolution requires explicit file extensions
+- **Example**: `from '../queues/queue-types.js'` (not `queue-types.ts`)
+- **Location**: Line 18 in src/pools/utils.ts
+
+## Object.freeze() Pattern
+
+- **Pattern**: All default configuration objects use `Object.freeze()` to prevent mutations
+- **Usage**: Wraps the return object: `return Object.freeze({ ... })`
+- **Purpose**: Ensures defaults are immutable and consistent across the application
+- **Location**: Line 48-57 in src/pools/utils.ts
+
+## Property Ordering in Return Object
+
+- **Convention**: Properties in frozen return object appear to follow alphabetical order
+- **Observed Order**: agingFactor, concurrency, loadExponent, size, tasksFinishedTimeout, tasksStealingOnBackPressure, tasksStealingRatio, taskStealing
+- **Benefit**: Consistent and predictable code structure
+
+## Imported Constants
+
+- **defaultAgingFactor** = 0.001 (anti-starvation aging factor)
+- **defaultLoadExponent** = 1.0 / 1.5 ≈ 0.667 (dynamic aging based on load)
+- **Source**: src/queues/queue-types.ts (internal constants, not exported publicly)
+
+## Build Verification
+
+- Build passes without errors after adding both properties and import
+- TypeScript compilation successful with new defaults
+
+## Task 4: WorkerNodeOptions Interface Update
+
+### Properties Added
+
+- **tasksQueueAgingFactor**: number | undefined
+- **tasksQueueLoadExponent**: number | undefined
+
+### Implementation Details
+
+- **Location**: src/pools/worker.ts, lines 380 and 383
+- **Pattern**: Added to WorkerNodeOptions interface with alphabetical ordering
+- **Naming**: Follows existing `tasksQueue*` prefix convention
+- **Type**: `number | undefined` matching existing property style
+- **Ordering**: Alphabetically placed between `env?` and `workerOptions?`
+  - Exact order: env, tasksQueueAgingFactor, tasksQueueBackPressureSize, tasksQueueBucketSize, tasksQueueLoadExponent, tasksQueuePriority, workerOptions
+
+### Build Verification
+
+- ✅ pnpm build passes without errors
+- ✅ No TypeScript diagnostics in worker.ts
+- ✅ Circular dependency warnings in priority-queue.ts are pre-existing (unrelated)
+
+### Workflow
+
+Task chain establishes pool-level config → worker node config flow:
+
+1. Task 1: Added agingFactor/loadExponent to TasksQueueOptions ✓
+2. Task 2: Updated getDefaultTasksQueueOptions() ✓
+3. Task 3: Set up frontend integration (priority-queue.ts) ✓
+4. Task 4: Extended WorkerNodeOptions (this task) ✓
+5. Next: Update WorkerNode constructor to accept new properties
+
+## Task 2: Added agingFactor and loadExponent validation to checkValidTasksQueueOptions()
+
+**What was done:**
+
+- Added validation for `agingFactor` in `checkValidTasksQueueOptions()` function
+  - TypeError check: must be a number
+  - RangeError check: must be >= 0
+- Added validation for `loadExponent` in `checkValidTasksQueueOptions()` function
+  - TypeError check: must be a number
+  - RangeError check: must be > 0 (strictly greater)
+- Validations placed in alphabetical order before `tasksStealingRatio`
+- Followed exact pattern from existing `tasksStealingRatio` validation
+- Error messages use consistent format: "Invalid tasks queue options: {prop} must be..."
+
+**Pattern confirmed:**
+
+- Optional properties check with `!= null` allows graceful handling when not provided
+- Type checking uses `typeof !== 'number'`
+- Range checking uses strict inequalities
+- Error types: TypeError for type violations, RangeError for range violations
+
+**Build verification:**
+
+- `pnpm build` passes successfully
+- No TypeScript diagnostics/errors in src/pools/utils.ts
+- Pre-existing warnings unaffected by changes
+
+## Task 3: PriorityQueue Constructor Parameters
+
+**Status**: ✅ COMPLETE
+
+### Changes Made
+
+- Added `agingFactor?: number` and `loadExponent?: number` as optional constructor parameters to `PriorityQueue`
+- Added instance properties: `public readonly agingFactor: number` and `public readonly loadExponent: number`
+- Imported defaults from queue-types.ts: `defaultAgingFactor` (0.001) and `defaultLoadExponent` (1.0/1.5 = 0.6666...)
+- Used nullish coalescing operator to assign defaults: `this.agingFactor = agingFactor ?? defaultAgingFactor`
+- Maintained existing parameter order (new params at end)
+- Updated JSDoc with @defaultValue annotations
+
+### Key Pattern Established
+
+- PriorityQueue is abstract base class storing tunables for use in `getPriorityQueueNode()` method
+- These values will be passed to FixedPriorityQueue when creating nodes (Task 9)
+- Import convention: use `.js` extensions for TypeScript imports (Node16 module resolution)
+
+### Build Status
+
+- TypeScript compilation successful (diagnostics clean)
+- Build warning expected from abstract-pool.ts (needs to pass agingFactor/loadExponent down the chain)
+- This is a downstream integration task, not part of PriorityQueue scope
+
+### Inheritance Path
+
+PoolOptions → TasksQueueOptions → WorkerNodeOptions → **PriorityQueue** ✓ → FixedPriorityQueue
+
+### Next Task
+
+Task 9: Update `getPriorityQueueNode()` method to pass these parameters to FixedPriorityQueue constructor
+
+## Task 9: getPriorityQueueNode() parameter passing ✅
+
+**Timestamp**: 2026-02-20T14:10:32+01:00
+
+**Completed**:
+
+- Modified `src/queues/priority-queue.ts`, method `getPriorityQueueNode()` (lines 219-227)
+- Added `this.agingFactor` and `this.loadExponent` as constructor arguments to `new FixedPriorityQueue()` call
+- Pattern: matches existing pattern where instance properties are passed to nested constructors
+- Verified: FixedPriorityQueue constructor (lines 24-28) accepts these optional parameters with defaults
+- Build passes with exit code 0
+- No LSP errors on modified file
+
+**Key insight**: This completes the configuration flow from PoolOptions through all layers to the actual priority calculation implementation. The agingFactor and loadExponent now flow from user config → PoolOptions → TasksQueueOptions → WorkerNodeOptions → WorkerNode → PriorityQueue → FixedPriorityQueue → priority calculations.
+
+**Related context**:
+
+- Task 6 (✅): PriorityQueue stores these as instance properties
+- Task 7 (in progress): AbstractPool passes to WorkerNode
+- Task 8 (in progress): WorkerNode passes to PriorityQueue
+- Task 9 (✅): PriorityQueue passes to FixedPriorityQueue (THIS TASK)
+
+## Task 8: WorkerNode Constructor - Pass Aging Parameters to PriorityQueue
+
+**Status**: ✅ COMPLETE
+
+### Changes Made
+
+- **File**: src/pools/worker-node.ts, lines 71-76
+- **Pattern**: Updated `new PriorityQueue()` instantiation to pass aging parameters
+- **Parameters passed** (in order):
+  1. `opts.tasksQueueBucketSize` (existing)
+  2. `opts.tasksQueuePriority` (existing, moved from 3rd position)
+  3. `opts.tasksQueueAgingFactor` (new, optional number)
+  4. `opts.tasksQueueLoadExponent` (new, optional number)
+
+### Key Implementation Detail
+
+- PriorityQueue constructor signature: `(bucketSize, enablePriority, agingFactor?, loadExponent?)`
+- The `tasksQueuePriority` property is actually the `enablePriority` parameter (boolean)
+- New aging parameters are optional and passed as the 3rd and 4th parameters
+- No validation needed at this level (upstream validation handles it)
+
+### Build Verification
+
+- ✅ `pnpm build` passes with exit code 0
+- ✅ No TypeScript diagnostics/errors
+- ✅ Circular dependency warnings (pre-existing, unrelated)
+
+### Configuration Flow Complete
+
+```
+PoolOptions
+  → TasksQueueOptions (agingFactor, loadExponent) ✅
+    → WorkerNodeOptions (tasksQueueAgingFactor, tasksQueueLoadExponent) ✅
+      → AbstractPool.createWorkerNode() (Task 7)
+        → WorkerNode constructor passes to PriorityQueue (this task) ✅
+          → PriorityQueue stores as instance properties ✅
+            → FixedPriorityQueue constructor (Task 9 - next)
+```
+
+### Timestamp
+
+- Task 8 completed: 2026-02-20
+
+### Task 7 - AbstractPool.createWorkerNode() Configuration Threading - 2026-02-20 14:10:57
+
+#### Changes Made
+
+- Updated AbstractPool.createWorkerNode() method in src/pools/abstract-pool.ts
+- Added extraction of agingFactor and loadExponent from this.opts.tasksQueueOptions
+- Passed values as tasksQueueAgingFactor and tasksQueueLoadExponent to WorkerNodeOptions
+- Maintained alphabetical property ordering (between env and workerOptions)
+
+#### Pattern Followed
+
+- Used optional chaining (?.) for nested property access
+- Followed exact same pattern as existing tasksQueueBucketSize and tasksQueuePriority
+- No defaults applied at this level (defaults already in getDefaultTasksQueueOptions)
+- Validation already handled in checkValidTasksQueueOptions
+
+#### Verification
+
+- Build: pnpm build ✅ (exit code 0, TypeScript compilation successful)
+- Grep verification: Both tasksQueueAgingFactor and tasksQueueLoadExponent present in createWorkerNode
+- Configuration flow now complete: PoolOptions → TasksQueueOptions → WorkerNodeOptions → WorkerNode
+
+#### Architectural Context
+
+This task threads user-configured aging values from pool-level configuration through the worker node creation layer, enabling per-worker queue behavior customization. Part of priority queue aging and load exponent tuning system.
+
+---
+
+## Task 10 - Testing (2026-02-20)
+
+### Tests Added
+
+**abstract-pool.test.mjs - Validation Tests:**
+
+- Extended "Verify that pool options are checked" test with:
+  - `agingFactor: ''` → TypeError ("must be a number")
+  - `agingFactor: -1` → RangeError ("must be greater than or equal to 0")
+  - `loadExponent: ''` → TypeError ("must be a number")
+  - `loadExponent: 0` → RangeError ("must be greater than 0")
+  - `loadExponent: -1` → RangeError ("must be greater than 0")
+
+- Extended "Verify that pool tasks queue options can be set" test with:
+  - Same validation tests for `setTasksQueueOptions()` method
+
+- Updated existing test expectation to include `agingFactor` and `loadExponent` in `tasksQueueOptions`
+
+**priority-queue.test.mjs - Propagation Tests:**
+
+- Extended existing "Verify constructor() behavior" test with:
+  - Default values: `agingFactor` = `defaultAgingFactor`, `loadExponent` = `defaultLoadExponent`
+  - Custom values: verified `agingFactor` and `loadExponent` propagate to PriorityQueue
+  - Imported `defaultAgingFactor` and `defaultLoadExponent` from queue-types
+
+### Test Pattern Observations
+
+- Validation tests use `expect(() => new FixedThreadPool(...)).toThrow(...)` pattern
+- Follow same structure as `tasksStealingRatio` validation tests
+- Error messages match exactly from `checkValidTasksQueueOptions()` implementation
+- Property order in expected objects is alphabetical for consistency
+
+### Key Constraint Followed
+
+- "Tests must integrate with existing ones and reuse existing tests" - NO new `it()` blocks created
+- Extended existing test blocks only
+- Reused existing import patterns and test structure
+
+### Verification
+
+- All 267 tests pass
+- Coverage maintained at 94.17%+ (above 90% threshold)
diff --git a/.sisyphus/notepads/priority-queue-aging-tunables/problems.md b/.sisyphus/notepads/priority-queue-aging-tunables/problems.md
new file mode 100644 (file)
index 0000000..86a956e
--- /dev/null
@@ -0,0 +1,5 @@
+# Problems
+
+This file tracks unresolved blockers and critical issues requiring escalation.
+
+---
diff --git a/.sisyphus/plans/priority-queue-aging-tunables.md b/.sisyphus/plans/priority-queue-aging-tunables.md
new file mode 100644 (file)
index 0000000..52d87ac
--- /dev/null
@@ -0,0 +1,837 @@
+# Priority Queue Aging Tunables
+
+## TL;DR
+
+> **Quick Summary**: Add `agingFactor` and `loadExponent` as configurable tunables to `TasksQueueOptions`, enabling users to customize the priority queue anti-starvation mechanism currently using hardcoded values.
+>
+> **Deliverables**:
+>
+> - Extended `TasksQueueOptions` interface with two new optional properties
+> - Validation logic for the new options
+> - Default values in `getDefaultTasksQueueOptions()`
+> - Options threading through AbstractPool → WorkerNode → PriorityQueue → FixedPriorityQueue
+> - Extended test coverage
+>
+> **Estimated Effort**: Medium (8 files modified, ~150 lines changed)
+> **Parallel Execution**: YES - 3 waves
+> **Critical Path**: Task 1 → Task 2 → Task 3 → Task 4 → Task 5 → Task 6
+
+---
+
+## Context
+
+### Original Request
+
+Add tunables for the priority queue aging mechanism in Poolifier. Currently hardcoded values (`agingFactor=0.001` and `loadExponent=1.0/1.5`) need to become configurable options at the `TasksQueueOptions` level.
+
+### Interview Summary
+
+**Key Discussions**:
+
+- Configuration level: `TasksQueueOptions` (pool-level, not task-function-level)
+- Naming convention: `agingFactor`, `loadExponent` (simple names consistent with existing options)
+- Default constants: Internal only, not exported publicly
+- Tests: Extend existing tests, only create new if indispensable
+
+**Research Findings**:
+
+- No universal standard for aging factor values (Kubernetes, Slurm use configurable params)
+- Configuration flow: PoolOptions → TasksQueueOptions → WorkerNodeOptions → PriorityQueue → FixedPriorityQueue
+- Current formula: `effectivePriority = node.priority - (now - node.timestamp) * effectiveAgingFactor`
+- `effectiveAgingFactor = agingFactor * (1 + ((size+1)/capacity)^loadExponent)`
+
+### Metis Review
+
+**Identified Gaps** (addressed):
+
+- Missing PriorityQueue constructor modification (added to plan)
+- Validation bounds needed (added: agingFactor >= 0, loadExponent > 0)
+- Runtime mutability unclear (documented as construction-time only)
+- Behavior when priority disabled (silent acceptance, consistent with other options)
+
+---
+
+## Work Objectives
+
+### Core Objective
+
+Make the priority queue anti-starvation mechanism configurable by exposing `agingFactor` and `loadExponent` as optional properties in `TasksQueueOptions`.
+
+### Concrete Deliverables
+
+- `TasksQueueOptions.agingFactor?: number` and `TasksQueueOptions.loadExponent?: number`
+- Default values: `agingFactor = 0.001`, `loadExponent = 1.0/1.5` (≈0.667)
+- Validation: `agingFactor >= 0`, `loadExponent > 0`
+- Complete options threading from pool config to `FixedPriorityQueue`
+- Extended tests for validation and configuration propagation
+
+### Definition of Done
+
+- [ ] `pnpm lint` passes with 0 errors
+- [ ] `pnpm format` completes successfully
+- [ ] `pnpm test` passes with 0 failures
+- [ ] New options documented with JSDoc
+- [ ] Options propagate from `TasksQueueOptions` to `FixedPriorityQueue`
+
+### Must Have
+
+- `agingFactor` and `loadExponent` in `TasksQueueOptions` interface
+- Default values matching current hardcoded behavior
+- Validation rejecting invalid values (non-number, out of range)
+- Options threading through entire chain
+- Tests for validation and defaults
+
+### Must NOT Have (Guardrails)
+
+- Per-task-function aging configuration — pool-level only
+- Runtime aging modification via `setTasksQueueOptions()` — construction-time only
+- Formula changes — only make existing constants configurable
+- `disableAging: boolean` option — use `agingFactor: 0` instead
+- Exported default constants — keep internal
+- Time-based behavioral tests — too flaky, out of scope
+
+---
+
+## Verification Strategy
+
+> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions.
+
+### Test Decision
+
+- **Infrastructure exists**: YES
+- **Automated tests**: Tests-after (extend existing test files)
+- **Framework**: bun test
+- **Pattern**: Follow existing validation tests in `tests/pools/abstract-pool.test.mjs`
+
+### QA Policy
+
+Every task includes agent-executed verification commands.
+Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`.
+
+- **Validation**: Use Bash (bun test) — run test commands, assert exit code 0
+- **Linting**: Use Bash (pnpm lint/format) — verify no errors
+- **Type checking**: Use Bash (pnpm build) — verify compilation succeeds
+
+---
+
+## Execution Strategy
+
+### Parallel Execution Waves
+
+```
+Wave 1 (Foundation — interfaces and defaults):
+├── Task 1: Add properties to TasksQueueOptions interface [quick]
+├── Task 2: Add default constants to queue-types.ts [quick]
+└── Task 3: Update getDefaultTasksQueueOptions() [quick]
+
+Wave 2 (After Wave 1 — validation and threading):
+├── Task 4: Add validation to checkValidTasksQueueOptions() (depends: 1) [quick]
+├── Task 5: Add properties to WorkerNodeOptions (depends: 1) [quick]
+└── Task 6: Update PriorityQueue constructor (depends: 2) [quick]
+
+Wave 3 (After Wave 2 — wiring and tests):
+├── Task 7: Update AbstractPool.createWorkerNode() (depends: 3, 5) [quick]
+├── Task 8: Update WorkerNode constructor (depends: 5, 6) [quick]
+├── Task 9: Update PriorityQueue.getPriorityQueueNode() (depends: 6) [quick]
+└── Task 10: Add/extend tests (depends: 4, 7, 8, 9) [unspecified-high]
+
+Wave FINAL (After ALL tasks — verification):
+├── Task F1: Plan compliance audit (oracle)
+├── Task F2: Code quality review (unspecified-high)
+└── Task F3: Full test suite and lint verification (quick)
+
+Critical Path: Task 1 → Task 4 → Task 7 → Task 10 → F1-F3
+Parallel Speedup: ~50% faster than sequential
+Max Concurrent: 3 (Waves 1 & 2)
+```
+
+### Dependency Matrix
+
+| Task | Depends On | Blocks |
+| ---- | ---------- | ------ |
+| 1    | —          | 4, 5   |
+| 2    | —          | 6      |
+| 3    | —          | 7      |
+| 4    | 1          | 10     |
+| 5    | 1          | 7, 8   |
+| 6    | 2          | 8, 9   |
+| 7    | 3, 5       | 10     |
+| 8    | 5, 6       | 10     |
+| 9    | 6          | 10     |
+| 10   | 4, 7, 8, 9 | F1-F3  |
+
+### Agent Dispatch Summary
+
+- **Wave 1**: 3 tasks → `quick` (simple interface/constant additions)
+- **Wave 2**: 3 tasks → `quick` (validation logic, interface updates)
+- **Wave 3**: 4 tasks → 3 `quick` + 1 `unspecified-high` (tests)
+- **Wave FINAL**: 3 tasks → `oracle`, `unspecified-high`, `quick`
+
+---
+
+## TODOs
+
+- [ ] 1. Add agingFactor and loadExponent to TasksQueueOptions interface
+
+  **What to do**:
+  - Add `agingFactor?: number` property to `TasksQueueOptions` interface
+  - Add `loadExponent?: number` property to `TasksQueueOptions` interface
+  - Add JSDoc comments explaining each option's purpose and default behavior
+  - Follow existing property patterns in the interface (optional with `?`)
+
+  **Must NOT do**:
+  - Export default constants
+  - Add validation logic here (separate task)
+  - Add to any other interface in this task
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Simple interface extension, 2 properties + JSDoc
+  - **Skills**: []
+    - No special skills needed for interface modification
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 1 (with Tasks 2, 3)
+  - **Blocks**: Tasks 4, 5
+  - **Blocked By**: None (can start immediately)
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/pool.ts:366-397` - `TasksQueueOptions` interface with existing optional properties pattern
+
+  **API/Type References**:
+  - `src/pools/pool.ts:TasksQueueOptions` - Interface to modify
+
+  **WHY Each Reference Matters**:
+  - TasksQueueOptions shows naming convention (camelCase, optional `?`) and JSDoc style for properties
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: TypeScript compilation with new properties
+    Tool: Bash
+    Preconditions: Clean working directory
+    Steps:
+      1. Run `pnpm build`
+      2. Check exit code is 0
+    Expected Result: Build succeeds with new interface properties
+    Failure Indicators: TypeScript errors, non-zero exit code
+    Evidence: .sisyphus/evidence/task-1-build.txt
+
+  Scenario: Property exists in compiled output
+    Tool: Bash
+    Preconditions: Build completed
+    Steps:
+      1. Run `grep -l "agingFactor" src/pools/pool.ts`
+      2. Run `grep -l "loadExponent" src/pools/pool.ts`
+    Expected Result: Both properties found in source file
+    Failure Indicators: grep returns empty/non-zero
+    Evidence: .sisyphus/evidence/task-1-grep.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 2. Add default constants to queue-types.ts
+
+  **What to do**:
+  - Add `export const defaultAgingFactor = 0.001` constant
+  - Add `export const defaultLoadExponent = 1.0 / 1.5` constant (≈0.667)
+  - Add brief comment explaining the default values
+  - Place near existing `defaultBucketSize` and `defaultQueueSize` constants
+
+  **Must NOT do**:
+  - Export from main index.ts (internal constants only)
+  - Change existing constants
+  - Add validation logic
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Adding 2 constant declarations
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 1 (with Tasks 1, 3)
+  - **Blocks**: Task 6
+  - **Blocked By**: None (can start immediately)
+
+  **References**:
+
+  **Pattern References**:
+  - `src/queues/queue-types.ts:1-10` - Existing default constants pattern
+
+  **WHY Each Reference Matters**:
+  - Shows naming convention (`default*`) and export style for constants
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: Constants are defined correctly
+    Tool: Bash
+    Preconditions: File modified
+    Steps:
+      1. Run `grep "defaultAgingFactor" src/queues/queue-types.ts`
+      2. Run `grep "defaultLoadExponent" src/queues/queue-types.ts`
+      3. Run `pnpm build`
+    Expected Result: Both constants found, build succeeds
+    Failure Indicators: Constants missing, build fails
+    Evidence: .sisyphus/evidence/task-2-constants.txt
+
+  Scenario: Constants not exported from main index
+    Tool: Bash
+    Preconditions: Build completed
+    Steps:
+      1. Run `grep -c "defaultAgingFactor\|defaultLoadExponent" src/index.ts`
+    Expected Result: Count is 0 (not exported publicly)
+    Failure Indicators: Count > 0
+    Evidence: .sisyphus/evidence/task-2-no-export.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 3. Update getDefaultTasksQueueOptions() with aging defaults
+
+  **What to do**:
+  - Import `defaultAgingFactor` and `defaultLoadExponent` from queue-types.ts
+  - Add `agingFactor: defaultAgingFactor` to returned object
+  - Add `loadExponent: defaultLoadExponent` to returned object
+  - Maintain existing `Object.freeze()` pattern
+
+  **Must NOT do**:
+  - Hardcode values (use imported constants)
+  - Change function signature
+  - Modify other default functions
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Adding 2 properties to return object + import
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 1 (with Tasks 1, 2)
+  - **Blocks**: Task 7
+  - **Blocked By**: None (can start immediately)
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/utils.ts:40-51` - `getDefaultTasksQueueOptions()` function
+
+  **API/Type References**:
+  - `src/queues/queue-types.ts` - Source of default constants
+
+  **WHY Each Reference Matters**:
+  - Shows return object structure and `Object.freeze()` pattern to maintain
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: Defaults include aging properties
+    Tool: Bash
+    Preconditions: File modified
+    Steps:
+      1. Run `grep "agingFactor" src/pools/utils.ts`
+      2. Run `grep "loadExponent" src/pools/utils.ts`
+      3. Run `pnpm build`
+    Expected Result: Both properties in defaults function, build succeeds
+    Failure Indicators: Properties missing, build fails
+    Evidence: .sisyphus/evidence/task-3-defaults.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 4. Add validation to checkValidTasksQueueOptions()
+
+  **What to do**:
+  - Add validation for `agingFactor`: must be number if provided, must be >= 0
+  - Add validation for `loadExponent`: must be number if provided, must be > 0
+  - Follow existing validation pattern (e.g., `tasksStealingRatio` validation)
+  - Use `TypeError` for non-number, `RangeError` for out-of-range values
+
+  **Must NOT do**:
+  - Add validation for other options
+  - Change error message format
+  - Add warning for aging options when priority disabled (silent acceptance)
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Pattern-following validation logic
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 2 (with Tasks 5, 6)
+  - **Blocks**: Task 10
+  - **Blocked By**: Task 1
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/utils.ts:198-213` - `tasksStealingRatio` validation pattern (type check + range check)
+  - `src/pools/utils.ts:162-214` - Full `checkValidTasksQueueOptions()` function
+
+  **WHY Each Reference Matters**:
+  - tasksStealingRatio shows exact pattern: `typeof` check → `TypeError`, range check → `RangeError`
+  - Error message format to match
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: Valid values accepted
+    Tool: Bash
+    Preconditions: Validation added
+    Steps:
+      1. Run `pnpm build`
+      2. Run `pnpm test -- --grep "tasks queue options"`
+    Expected Result: Build and relevant tests pass
+    Failure Indicators: Build fails, tests fail
+    Evidence: .sisyphus/evidence/task-4-valid.txt
+
+  Scenario: Invalid agingFactor rejected (type)
+    Tool: Bash
+    Preconditions: Validation added, test added
+    Steps:
+      1. Run test that passes `agingFactor: 'string'`
+      2. Assert TypeError is thrown
+    Expected Result: TypeError thrown with appropriate message
+    Failure Indicators: No error or wrong error type
+    Evidence: .sisyphus/evidence/task-4-aging-type.txt
+
+  Scenario: Invalid loadExponent rejected (range)
+    Tool: Bash
+    Preconditions: Validation added, test added
+    Steps:
+      1. Run test that passes `loadExponent: 0`
+      2. Assert RangeError is thrown
+    Expected Result: RangeError thrown (loadExponent must be > 0)
+    Failure Indicators: No error or wrong error type
+    Evidence: .sisyphus/evidence/task-4-load-range.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 5. Add agingFactor and loadExponent to WorkerNodeOptions
+
+  **What to do**:
+  - Add `tasksQueueAgingFactor?: number` to `WorkerNodeOptions` interface
+  - Add `tasksQueueLoadExponent?: number` to `WorkerNodeOptions` interface
+  - Follow existing naming pattern (`tasksQueue*` prefix for queue-related options)
+
+  **Must NOT do**:
+  - Add JSDoc (internal interface)
+  - Add validation (handled at TasksQueueOptions level)
+  - Modify constructor yet (separate task)
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Simple interface extension
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 2 (with Tasks 4, 6)
+  - **Blocks**: Tasks 7, 8
+  - **Blocked By**: Task 1
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/worker.ts:377-383` - `WorkerNodeOptions` interface with `tasksQueue*` properties
+
+  **WHY Each Reference Matters**:
+  - Shows naming convention (`tasksQueueBucketSize`, `tasksQueuePriority`) to follow
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: WorkerNodeOptions accepts new properties
+    Tool: Bash
+    Preconditions: Interface modified
+    Steps:
+      1. Run `grep "tasksQueueAgingFactor" src/pools/worker.ts`
+      2. Run `grep "tasksQueueLoadExponent" src/pools/worker.ts`
+      3. Run `pnpm build`
+    Expected Result: Properties found, build succeeds
+    Failure Indicators: Properties missing, build fails
+    Evidence: .sisyphus/evidence/task-5-worker-opts.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 6. Update PriorityQueue constructor to accept aging options
+
+  **What to do**:
+  - Add `agingFactor?: number` parameter to `PriorityQueue` constructor
+  - Add `loadExponent?: number` parameter to `PriorityQueue` constructor
+  - Store as instance properties for use in `getPriorityQueueNode()`
+  - Import and use default constants when not provided
+
+  **Must NOT do**:
+  - Update `getPriorityQueueNode()` yet (separate task)
+  - Change existing parameter order
+  - Add validation (trust upstream validation)
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Constructor parameter addition
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 2 (with Tasks 4, 5)
+  - **Blocks**: Tasks 8, 9
+  - **Blocked By**: Task 2
+
+  **References**:
+
+  **Pattern References**:
+  - `src/queues/priority-queue.ts:63-80` - `PriorityQueue` constructor
+
+  **API/Type References**:
+  - `src/queues/queue-types.ts` - Default constants to import
+
+  **WHY Each Reference Matters**:
+  - Constructor shows existing parameter pattern and where to store instance properties
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: PriorityQueue accepts aging parameters
+    Tool: Bash
+    Preconditions: Constructor modified
+    Steps:
+      1. Run `grep -A5 "constructor" src/queues/priority-queue.ts | grep "agingFactor\|loadExponent"`
+      2. Run `pnpm build`
+    Expected Result: Parameters in constructor, build succeeds
+    Failure Indicators: Parameters missing, build fails
+    Evidence: .sisyphus/evidence/task-6-pq-constructor.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 7. Update AbstractPool.createWorkerNode() to pass aging options
+
+  **What to do**:
+  - In `createWorkerNode()`, extract `agingFactor` and `loadExponent` from `this.opts.tasksQueueOptions`
+  - Pass as `tasksQueueAgingFactor` and `tasksQueueLoadExponent` in `WorkerNodeOptions`
+  - Follow existing pattern for `tasksQueueBucketSize` and `tasksQueuePriority`
+
+  **Must NOT do**:
+  - Add validation (already done in buildTasksQueueOptions)
+  - Modify other methods
+  - Change return type
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Adding 2 properties to options object
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 3 (with Tasks 8, 9, 10)
+  - **Blocks**: Task 10
+  - **Blocked By**: Tasks 3, 5
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/abstract-pool.ts:1624-1639` - `createWorkerNode()` method
+  - `src/pools/abstract-pool.ts:1630-1635` - Where `WorkerNodeOptions` is constructed
+
+  **WHY Each Reference Matters**:
+  - Shows how `tasksQueueBucketSize` and `tasksQueuePriority` are passed to match pattern
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: Aging options passed to WorkerNodeOptions
+    Tool: Bash
+    Preconditions: Method modified
+    Steps:
+      1. Run `grep "tasksQueueAgingFactor" src/pools/abstract-pool.ts`
+      2. Run `grep "tasksQueueLoadExponent" src/pools/abstract-pool.ts`
+      3. Run `pnpm build`
+    Expected Result: Both options passed, build succeeds
+    Failure Indicators: Options missing, build fails
+    Evidence: .sisyphus/evidence/task-7-create-worker.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 8. Update WorkerNode constructor to pass aging options to PriorityQueue
+
+  **What to do**:
+  - Extract `tasksQueueAgingFactor` and `tasksQueueLoadExponent` from constructor options
+  - Pass to `PriorityQueue` constructor call
+  - Handle undefined values (let PriorityQueue use defaults)
+
+  **Must NOT do**:
+  - Add validation
+  - Modify other WorkerNode methods
+  - Change tasksQueue type
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Passing 2 additional parameters
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 3 (with Tasks 7, 9, 10)
+  - **Blocks**: Task 10
+  - **Blocked By**: Tasks 5, 6
+
+  **References**:
+
+  **Pattern References**:
+  - `src/pools/worker-node.ts` - WorkerNode constructor where PriorityQueue is created
+
+  **WHY Each Reference Matters**:
+  - Shows where `new PriorityQueue()` is called and existing parameters passed
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: WorkerNode passes aging options to PriorityQueue
+    Tool: Bash
+    Preconditions: Constructor modified
+    Steps:
+      1. Run `grep -B2 -A5 "new PriorityQueue" src/pools/worker-node.ts`
+      2. Run `pnpm build`
+    Expected Result: Aging options visible in PriorityQueue call, build succeeds
+    Failure Indicators: Options missing, build fails
+    Evidence: .sisyphus/evidence/task-8-worker-node.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 9. Update PriorityQueue.getPriorityQueueNode() to pass aging to FixedPriorityQueue
+
+  **What to do**:
+  - In `getPriorityQueueNode()`, pass stored `agingFactor` and `loadExponent` to `FixedPriorityQueue` constructor
+  - Use instance properties set in Task 6
+
+  **Must NOT do**:
+  - Modify FixedPriorityQueue constructor (already accepts these params)
+  - Add validation
+  - Change bucket size handling
+
+  **Recommended Agent Profile**:
+  - **Category**: `quick`
+    - Reason: Passing 2 parameters to constructor call
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: YES
+  - **Parallel Group**: Wave 3 (with Tasks 7, 8, 10)
+  - **Blocks**: Task 10
+  - **Blocked By**: Task 6
+
+  **References**:
+
+  **Pattern References**:
+  - `src/queues/priority-queue.ts:206-214` - `getPriorityQueueNode()` method
+  - `src/queues/fixed-priority-queue.ts` - FixedPriorityQueue constructor signature
+
+  **WHY Each Reference Matters**:
+  - Shows where `new FixedPriorityQueue()` is called
+  - FixedPriorityQueue constructor already accepts agingFactor and loadExponent
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: FixedPriorityQueue receives aging options
+    Tool: Bash
+    Preconditions: Method modified
+    Steps:
+      1. Run `grep -A3 "new FixedPriorityQueue" src/queues/priority-queue.ts`
+      2. Run `pnpm build`
+    Expected Result: Aging options passed to FixedPriorityQueue, build succeeds
+    Failure Indicators: Options missing, build fails
+    Evidence: .sisyphus/evidence/task-9-get-node.txt
+  ```
+
+  **Commit**: NO (groups with final commit)
+
+- [ ] 10. Add/extend tests for aging options
+
+  **What to do**:
+  - Add validation tests in `tests/pools/abstract-pool.test.mjs`:
+    - Test invalid `agingFactor` (non-number) throws TypeError
+    - Test invalid `agingFactor` (negative) throws RangeError
+    - Test invalid `loadExponent` (non-number) throws TypeError
+    - Test invalid `loadExponent` (zero or negative) throws RangeError
+    - Test valid values are accepted
+    - Test defaults are applied when not specified
+  - Extend existing priority queue tests in `tests/queues/priority-queue.test.mjs`:
+    - Test PriorityQueue constructor accepts aging options
+    - Test defaults used when options not provided
+
+  **Must NOT do**:
+  - Create new test files
+  - Add time-based behavioral tests (flaky)
+  - Test aging algorithm correctness (out of scope)
+
+  **Recommended Agent Profile**:
+  - **Category**: `unspecified-high`
+    - Reason: Multiple test cases requiring understanding of existing patterns
+  - **Skills**: []
+    - No special skills needed
+  - **Skills Evaluated but Omitted**:
+    - None applicable
+
+  **Parallelization**:
+  - **Can Run In Parallel**: NO
+  - **Parallel Group**: Wave 3 (after infrastructure tasks)
+  - **Blocks**: Final verification
+  - **Blocked By**: Tasks 4, 7, 8, 9
+
+  **References**:
+
+  **Pattern References**:
+  - `tests/pools/abstract-pool.test.mjs` - Existing validation tests for TasksQueueOptions
+  - `tests/queues/priority-queue.test.mjs` - Existing PriorityQueue tests
+
+  **Test References**:
+  - Search for `tasksStealingRatio` tests to see validation test pattern
+  - Search for `TasksQueueOptions` tests for options testing pattern
+
+  **WHY Each Reference Matters**:
+  - Shows test structure, assertion patterns, and how validation errors are tested
+
+  **Acceptance Criteria**:
+
+  **QA Scenarios (MANDATORY):**
+
+  ```
+  Scenario: All new tests pass
+    Tool: Bash
+    Preconditions: Tests added
+    Steps:
+      1. Run `bun test tests/pools/abstract-pool.test.mjs`
+      2. Run `bun test tests/queues/priority-queue.test.mjs`
+    Expected Result: All tests pass (exit code 0)
+    Failure Indicators: Test failures, non-zero exit
+    Evidence: .sisyphus/evidence/task-10-tests.txt
+
+  Scenario: Full test suite passes
+    Tool: Bash
+    Preconditions: All implementation complete
+    Steps:
+      1. Run `pnpm test`
+    Expected Result: 0 failures
+    Failure Indicators: Any test failure
+    Evidence: .sisyphus/evidence/task-10-full-suite.txt
+  ```
+
+  **Commit**: YES
+  - Message: `feat(pool): add agingFactor and loadExponent tunables to TasksQueueOptions`
+  - Files: All modified files from tasks 1-10
+  - Pre-commit: `pnpm lint && pnpm format && pnpm test`
+
+---
+
+## Final Verification Wave
+
+- [ ] F1. **Plan Compliance Audit** — `oracle`
+      Read the plan end-to-end. For each "Must Have": verify implementation exists. For each "Must NOT Have": search codebase for forbidden patterns. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan.
+      Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT`
+
+- [ ] F2. **Code Quality Review** — `unspecified-high`
+      Run `pnpm build` + `pnpm lint` + `pnpm test`. Review all changed files for: `as any`/`@ts-ignore`, empty catches, console.log in prod. Check for consistent naming, proper JSDoc, no dead code.
+      Output: `Build [PASS/FAIL] | Lint [PASS/FAIL] | Tests [N pass/N fail] | VERDICT`
+
+- [ ] F3. **Full Test Suite Verification** — `quick`
+      Run full test suite: `pnpm test`. Verify 0 failures. Run `pnpm lint && pnpm format`. Verify exit code 0.
+      Output: `Tests [PASS/FAIL] | Lint [PASS/FAIL] | Format [PASS/FAIL] | VERDICT`
+
+---
+
+## Commit Strategy
+
+Single commit after all tasks complete:
+
+- **Message**: `feat(pool): add agingFactor and loadExponent tunables to TasksQueueOptions`
+- **Files**: All modified files from tasks 1-10
+- **Pre-commit**: `pnpm lint && pnpm format && pnpm test`
+
+---
+
+## Success Criteria
+
+### Verification Commands
+
+```bash
+# Build passes
+pnpm build  # Expected: exit 0
+
+# Lint passes
+pnpm lint  # Expected: exit 0
+
+# Format passes
+pnpm format  # Expected: exit 0
+
+# Tests pass
+pnpm test  # Expected: exit 0, 0 failures
+
+# Type check
+npx tsc --noEmit  # Expected: exit 0
+```
+
+### Final Checklist
+
+- [ ] `agingFactor` and `loadExponent` in `TasksQueueOptions`
+- [ ] Default values applied when not specified
+- [ ] Validation rejects invalid values
+- [ ] Options propagate to `FixedPriorityQueue`
+- [ ] All existing tests still pass
+- [ ] New validation tests added
+- [ ] JSDoc documentation complete
+- [ ] No runtime mutability via `setTasksQueueOptions()`
index 40d2fb4acb39222a25cd2a50f73a79d9bbaebb0f..e88c4ee59dd2bff43048caf647c068e82f89225f 100644 (file)
@@ -152,8 +152,10 @@ An object with these properties:
   - `tasksStealingOnBackPressure` (optional) - Tasks stealing enablement under back pressure.
   - `tasksStealingRatio` (optional) - The ratio of worker nodes that can steal tasks from another worker node. It must be a number between 0 and 1.
   - `tasksFinishedTimeout` (optional) - Queued tasks finished timeout in milliseconds at worker termination.
+  - `agingFactor` (optional) - Controls the priority queue anti-starvation aging rate (priority points per millisecond). It must be a non-negative number.
+  - `loadExponent` (optional) - Controls load-based aging adjustment exponent. It must be a positive number.
 
-  Default: `{ size: (pool maximum size)^2, concurrency: 1, taskStealing: true, tasksStealingOnBackPressure: true, tasksStealingRatio: 0.6, tasksFinishedTimeout: 2000 }`
+  Default: `{ size: (pool maximum size)^2, concurrency: 1, taskStealing: true, tasksStealingOnBackPressure: true, tasksStealingRatio: 0.6, tasksFinishedTimeout: 2000, agingFactor: 0.001, loadExponent: 0.667 }`
 
 - `workerOptions` (optional) - An object with the worker options to pass to worker. See [worker_threads](https://nodejs.org/api/worker_threads.html#worker_threads_new_worker_filename_options) for more details.
 
index c85d131d655f73a8f13f1575c89f446d1cc08717..34df72e51d66ef7590956e148cdb5b5e0d932eb1 100644 (file)
@@ -1627,12 +1627,14 @@ export abstract class AbstractPool<
       this.filePath,
       {
         env: this.opts.env,
+        tasksQueueAgingFactor: this.opts.tasksQueueOptions?.agingFactor,
         tasksQueueBackPressureSize:
           this.opts.tasksQueueOptions?.size ??
           getDefaultTasksQueueOptions(
             this.maximumNumberOfWorkers ?? this.minimumNumberOfWorkers
           ).size,
         tasksQueueBucketSize: defaultBucketSize,
+        tasksQueueLoadExponent: this.opts.tasksQueueOptions?.loadExponent,
         tasksQueuePriority: this.getTasksQueuePriority(),
         workerOptions: this.opts.workerOptions,
       }
index fb1ba7b94de98e76bd9d7ce5eaf69505f488c7fc..cef7661809057e93fccb05a350bc0b594465b953 100644 (file)
@@ -365,11 +365,21 @@ export interface PoolOptions<Worker extends IWorker> {
  * Worker node tasks queue options.
  */
 export interface TasksQueueOptions {
+  /**
+   * Controls the priority queue anti-starvation aging rate.
+   * @defaultValue 0.001
+   */
+  readonly agingFactor?: number
   /**
    * Maximum number of tasks that can be executed concurrently on a worker node.
    * @defaultValue 1
    */
   readonly concurrency?: number
+  /**
+   * Controls load-based aging adjustment exponent.
+   * @defaultValue 0.667
+   */
+  readonly loadExponent?: number
   /**
    * Maximum tasks queue size per worker node flagging it as back pressured.
    * @defaultValue (pool maximum size)^2
index a599f1debdb2ce371a104d5023f093cbe18a4be0..51634ee7a2ce61a2aea464b48fc2e81fce349c18 100644 (file)
@@ -11,6 +11,10 @@ import type { MessageValue, Task } from '../utility-types.js'
 import type { TasksQueueOptions } from './pool.js'
 import type { WorkerChoiceStrategiesContext } from './selection-strategies/worker-choice-strategies-context.js'
 
+import {
+  defaultAgingFactor,
+  defaultLoadExponent,
+} from '../queues/queue-types.js'
 import { average, isPlainObject, max, median, min } from '../utils.js'
 import {
   type MeasurementStatisticsRequirements,
@@ -42,7 +46,9 @@ export const getDefaultTasksQueueOptions = (
   poolMaxSize: number
 ): Required<Readonly<TasksQueueOptions>> => {
   return Object.freeze({
+    agingFactor: defaultAgingFactor,
     concurrency: 1,
+    loadExponent: defaultLoadExponent,
     size: poolMaxSize ** 2,
     tasksFinishedTimeout: 2000,
     tasksStealingOnBackPressure: true,
@@ -195,6 +201,38 @@ export const checkValidTasksQueueOptions = (
       `Invalid worker node tasks queue size: ${tasksQueueOptions.size.toString()} is a negative integer or zero`
     )
   }
+  if (
+    tasksQueueOptions?.agingFactor != null &&
+    typeof tasksQueueOptions.agingFactor !== 'number'
+  ) {
+    throw new TypeError(
+      'Invalid worker node tasks queue aging factor: must be a number'
+    )
+  }
+  if (
+    tasksQueueOptions?.agingFactor != null &&
+    tasksQueueOptions.agingFactor < 0
+  ) {
+    throw new RangeError(
+      'Invalid worker node tasks queue aging factor: must be greater than or equal to 0'
+    )
+  }
+  if (
+    tasksQueueOptions?.loadExponent != null &&
+    typeof tasksQueueOptions.loadExponent !== 'number'
+  ) {
+    throw new TypeError(
+      'Invalid worker node tasks queue load exponent: must be a number'
+    )
+  }
+  if (
+    tasksQueueOptions?.loadExponent != null &&
+    tasksQueueOptions.loadExponent <= 0
+  ) {
+    throw new RangeError(
+      'Invalid worker node tasks queue load exponent: must be greater than 0'
+    )
+  }
   if (
     tasksQueueOptions?.tasksStealingRatio != null &&
     typeof tasksQueueOptions.tasksStealingRatio !== 'number'
index e47f8475dabf12e47653a7447244962394fbf91f..615c3f5df39a60c0efe1537bc2e706bdf84345c0 100644 (file)
@@ -70,7 +70,9 @@ export class WorkerNode<Worker extends IWorker, Data = unknown>
     this.tasksQueueBackPressureSize = opts.tasksQueueBackPressureSize!
     this.tasksQueue = new PriorityQueue<Task<Data>>(
       opts.tasksQueueBucketSize,
-      opts.tasksQueuePriority
+      opts.tasksQueuePriority,
+      opts.tasksQueueAgingFactor,
+      opts.tasksQueueLoadExponent
     )
     this.taskFunctionsUsage = new Map<string, WorkerUsage>()
   }
index db170095b277ed8e3b268accdee68fb745c8877b..7223fb2216be785f3f1665021569ce48052e9b8c 100644 (file)
@@ -377,8 +377,10 @@ export interface WorkerNodeEventDetail {
  */
 export interface WorkerNodeOptions {
   env?: Record<string, unknown>
+  tasksQueueAgingFactor: number | undefined
   tasksQueueBackPressureSize: number | undefined
   tasksQueueBucketSize: number | undefined
+  tasksQueueLoadExponent: number | undefined
   tasksQueuePriority: boolean | undefined
   workerOptions?: WorkerOptions
 }
index 427ac425faeb9df07f0ec96f91bdab0fb67f4c93..0e5fa28ba344ceb219e8e086bee484c08cf6a5f9 100644 (file)
@@ -14,11 +14,13 @@ export class FixedPriorityQueue<T>
   private readonly loadExponent: number
 
   /**
-   * Constructs a FixedPriorityQueue.
-   * @param size - Fixed queue size.
+   * Constructs a fixed priority queue.
+   * @param size - Fixed priority queue size.
    * @defaultValue defaultQueueSize
-   * @param agingFactor - Aging factor to apply to items (priority points per millisecond).
-   * @param loadExponent - Load exponent applied to normalized load when computing effective aging.
+   * @param agingFactor - Aging factor for priority boosting (priority points per millisecond).
+   * @defaultValue defaultAgingFactor
+   * @param loadExponent - Load exponent for aging adjustment based on queue fill ratio.
+   * @defaultValue defaultLoadExponent
    * @returns IFixedQueue.
    */
   public constructor (
index 503800f39a47cc77e13c67e384a03a349532aac0..c19fc5ea2f01136b864f02fe6450e5066f4c1785 100644 (file)
@@ -3,7 +3,9 @@
 import { FixedPriorityQueue } from './fixed-priority-queue.js'
 import { FixedQueue } from './fixed-queue.js'
 import {
+  defaultAgingFactor,
   defaultBucketSize,
+  defaultLoadExponent,
   type IFixedQueue,
   type PriorityQueueNode,
 } from './queue-types.js'
@@ -16,8 +18,10 @@ import {
 export class PriorityQueue<T> {
   /** The priority queue maximum size. */
   public maxSize!: number
+
   /** The priority queue size. */
   public size!: number
+
   /**
    * The number of filled prioritized buckets.
    * @returns The number of filled prioritized buckets.
@@ -50,8 +54,10 @@ export class PriorityQueue<T> {
     }
   }
 
+  private readonly agingFactor: number
   private readonly bucketSize: number
   private head!: PriorityQueueNode<T>
+  private readonly loadExponent: number
   private priorityEnabled: boolean
   private tail!: PriorityQueueNode<T>
 
@@ -61,11 +67,17 @@ export class PriorityQueue<T> {
    * @defaultValue defaultBucketSize
    * @param enablePriority - Whether to enable priority.
    * @defaultValue false
+   * @param agingFactor - Aging factor for priority boosting (priority points per millisecond).
+   * @defaultValue defaultAgingFactor
+   * @param loadExponent - Load exponent for aging adjustment based on queue fill ratio.
+   * @defaultValue defaultLoadExponent
    * @returns PriorityQueue.
    */
   public constructor (
     bucketSize: number = defaultBucketSize,
-    enablePriority = false
+    enablePriority = false,
+    agingFactor?: number,
+    loadExponent?: number
   ) {
     if (!Number.isSafeInteger(bucketSize)) {
       throw new TypeError(
@@ -77,6 +89,8 @@ export class PriorityQueue<T> {
     }
     this.bucketSize = bucketSize
     this.priorityEnabled = enablePriority
+    this.agingFactor = agingFactor ?? defaultAgingFactor
+    this.loadExponent = loadExponent ?? defaultLoadExponent
     this.clear()
   }
 
@@ -207,7 +221,11 @@ export class PriorityQueue<T> {
   private getPriorityQueueNode (): PriorityQueueNode<T> {
     let fixedQueue: IFixedQueue<T>
     if (this.priorityEnabled) {
-      fixedQueue = new FixedPriorityQueue(this.bucketSize)
+      fixedQueue = new FixedPriorityQueue(
+        this.bucketSize,
+        this.agingFactor,
+        this.loadExponent
+      )
     } else {
       fixedQueue = new FixedQueue(this.bucketSize)
     }
index 48e00e4d821dab39662b3b0d52c47c5ddc86172d..8bc8ec20486ae98eb8a8a13942e640de0a82967b 100644 (file)
@@ -4,6 +4,18 @@
  */
 export const defaultQueueSize = 2048
 
+/**
+ * Default aging factor for priority queue aging mechanism.
+ * @internal
+ */
+export const defaultAgingFactor = 0.001
+
+/**
+ * Default load exponent for priority queue aging mechanism.
+ * @internal
+ */
+export const defaultLoadExponent = 1.0 / 1.5
+
 /**
  * Fixed queue node.
  * @template T - Type of fixed queue node data.
index 487d6ee27ffc28deacb1fbd8727427d01be31550..0b292b33adf54b301a5e914f3aa365a315d8060e 100644 (file)
@@ -274,7 +274,9 @@ describe('Abstract pool test suite', () => {
       restartWorkerOnError: false,
       startWorkers: true,
       tasksQueueOptions: {
+        agingFactor: 0.001,
         concurrency: 2,
+        loadExponent: 0.6666666666666666,
         size: numberOfWorkers ** 2,
         tasksFinishedTimeout: 2000,
         tasksStealingOnBackPressure: true,
@@ -467,6 +469,81 @@ describe('Abstract pool test suite', () => {
         'Invalid worker node tasks stealing ratio: must be between 0 and 1'
       )
     )
+    expect(
+      () =>
+        new FixedThreadPool(
+          numberOfWorkers,
+          './tests/worker-files/thread/testWorker.mjs',
+          {
+            enableTasksQueue: true,
+            tasksQueueOptions: { agingFactor: '' },
+          }
+        )
+    ).toThrow(
+      new TypeError(
+        'Invalid worker node tasks queue aging factor: must be a number'
+      )
+    )
+    expect(
+      () =>
+        new FixedThreadPool(
+          numberOfWorkers,
+          './tests/worker-files/thread/testWorker.mjs',
+          {
+            enableTasksQueue: true,
+            tasksQueueOptions: { agingFactor: -1 },
+          }
+        )
+    ).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue aging factor: must be greater than or equal to 0'
+      )
+    )
+    expect(
+      () =>
+        new FixedThreadPool(
+          numberOfWorkers,
+          './tests/worker-files/thread/testWorker.mjs',
+          {
+            enableTasksQueue: true,
+            tasksQueueOptions: { loadExponent: '' },
+          }
+        )
+    ).toThrow(
+      new TypeError(
+        'Invalid worker node tasks queue load exponent: must be a number'
+      )
+    )
+    expect(
+      () =>
+        new FixedThreadPool(
+          numberOfWorkers,
+          './tests/worker-files/thread/testWorker.mjs',
+          {
+            enableTasksQueue: true,
+            tasksQueueOptions: { loadExponent: 0 },
+          }
+        )
+    ).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue load exponent: must be greater than 0'
+      )
+    )
+    expect(
+      () =>
+        new FixedThreadPool(
+          numberOfWorkers,
+          './tests/worker-files/thread/testWorker.mjs',
+          {
+            enableTasksQueue: true,
+            tasksQueueOptions: { loadExponent: -1 },
+          }
+        )
+    ).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue load exponent: must be greater than 0'
+      )
+    )
   })
 
   it('Verify that pool worker choice strategy options can be set', async () => {
@@ -619,7 +696,9 @@ describe('Abstract pool test suite', () => {
     pool.enableTasksQueue(true)
     expect(pool.opts.enableTasksQueue).toBe(true)
     expect(pool.opts.tasksQueueOptions).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 1,
+      loadExponent: 0.6666666666666666,
       size: numberOfWorkers ** 2,
       tasksFinishedTimeout: 2000,
       tasksStealingOnBackPressure: true,
@@ -629,7 +708,9 @@ describe('Abstract pool test suite', () => {
     pool.enableTasksQueue(true, { concurrency: 2 })
     expect(pool.opts.enableTasksQueue).toBe(true)
     expect(pool.opts.tasksQueueOptions).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 2,
+      loadExponent: 0.6666666666666666,
       size: numberOfWorkers ** 2,
       tasksFinishedTimeout: 2000,
       tasksStealingOnBackPressure: true,
@@ -649,7 +730,9 @@ describe('Abstract pool test suite', () => {
       { enableTasksQueue: true }
     )
     expect(pool.opts.tasksQueueOptions).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 1,
+      loadExponent: 0.6666666666666666,
       size: numberOfWorkers ** 2,
       tasksFinishedTimeout: 2000,
       tasksStealingOnBackPressure: true,
@@ -670,7 +753,9 @@ describe('Abstract pool test suite', () => {
       taskStealing: false,
     })
     expect(pool.opts.tasksQueueOptions).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 2,
+      loadExponent: 0.6666666666666666,
       size: 2,
       tasksFinishedTimeout: 3000,
       tasksStealingOnBackPressure: false,
@@ -688,7 +773,9 @@ describe('Abstract pool test suite', () => {
       taskStealing: true,
     })
     expect(pool.opts.tasksQueueOptions).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 1,
+      loadExponent: 0.6666666666666666,
       size: 2,
       tasksFinishedTimeout: 3000,
       tasksStealingOnBackPressure: true,
@@ -741,6 +828,31 @@ describe('Abstract pool test suite', () => {
         'Invalid worker node tasks stealing ratio: must be between 0 and 1'
       )
     )
+    expect(() => pool.setTasksQueueOptions({ agingFactor: '' })).toThrow(
+      new TypeError(
+        'Invalid worker node tasks queue aging factor: must be a number'
+      )
+    )
+    expect(() => pool.setTasksQueueOptions({ agingFactor: -1 })).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue aging factor: must be greater than or equal to 0'
+      )
+    )
+    expect(() => pool.setTasksQueueOptions({ loadExponent: '' })).toThrow(
+      new TypeError(
+        'Invalid worker node tasks queue load exponent: must be a number'
+      )
+    )
+    expect(() => pool.setTasksQueueOptions({ loadExponent: 0 })).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue load exponent: must be greater than 0'
+      )
+    )
+    expect(() => pool.setTasksQueueOptions({ loadExponent: -1 })).toThrow(
+      new RangeError(
+        'Invalid worker node tasks queue load exponent: must be greater than 0'
+      )
+    )
     await pool.destroy()
   })
 
index 003dfbb8454f5df68793eba847707940fd44c6ba..1bb9d11705c436084a862b90507dee74aef0305f 100644 (file)
@@ -26,7 +26,9 @@ describe('Pool utils test suite', () => {
   it('Verify getDefaultTasksQueueOptions() behavior', () => {
     const poolMaxSize = 4
     expect(getDefaultTasksQueueOptions(poolMaxSize)).toStrictEqual({
+      agingFactor: 0.001,
       concurrency: 1,
+      loadExponent: 0.6666666666666666,
       size: poolMaxSize ** 2,
       tasksFinishedTimeout: 2000,
       tasksStealingOnBackPressure: true,
index 2bb3306b4769c24ec383a996d5adf8c510064597..d6e911fb32b73f760eaa35ea936afb6bcd4094aa 100644 (file)
@@ -1,7 +1,11 @@
 import { expect } from '@std/expect'
 
 import { FixedPriorityQueue } from '../../lib/queues/fixed-priority-queue.cjs'
-import { defaultQueueSize } from '../../lib/queues/queue-types.cjs'
+import {
+  defaultAgingFactor,
+  defaultLoadExponent,
+  defaultQueueSize,
+} from '../../lib/queues/queue-types.cjs'
 
 describe('Fixed priority queue test suite', () => {
   it('Verify constructor() behavior', () => {
@@ -16,6 +20,8 @@ describe('Fixed priority queue test suite', () => {
     expect(fixedPriorityQueue.size).toBe(0)
     expect(fixedPriorityQueue.nodeArray).toBeInstanceOf(Array)
     expect(fixedPriorityQueue.capacity).toBe(defaultQueueSize)
+    expect(fixedPriorityQueue.agingFactor).toBe(defaultAgingFactor)
+    expect(fixedPriorityQueue.loadExponent).toBe(defaultLoadExponent)
   })
 
   it('Verify enqueue() behavior', () => {
index 5d3d5ac074540ee2e19839c0d0cb307fe0b629af..7de4e9b868811c713d5f5723ba3a66e2ff1b0107 100644 (file)
@@ -3,7 +3,11 @@ import { expect } from '@std/expect'
 import { FixedPriorityQueue } from '../../lib/queues/fixed-priority-queue.cjs'
 import { FixedQueue } from '../../lib/queues/fixed-queue.cjs'
 import { PriorityQueue } from '../../lib/queues/priority-queue.cjs'
-import { defaultBucketSize } from '../../lib/queues/queue-types.cjs'
+import {
+  defaultAgingFactor,
+  defaultBucketSize,
+  defaultLoadExponent,
+} from '../../lib/queues/queue-types.cjs'
 
 describe('Priority queue test suite', () => {
   it('Verify constructor() behavior', () => {
@@ -19,6 +23,8 @@ describe('Priority queue test suite', () => {
     expect(priorityQueue.size).toBe(0)
     expect(priorityQueue.maxSize).toBe(0)
     expect(priorityQueue.enablePriority).toBe(false)
+    expect(priorityQueue.agingFactor).toBe(defaultAgingFactor)
+    expect(priorityQueue.loadExponent).toBe(defaultLoadExponent)
     expect(priorityQueue.head).toBeInstanceOf(FixedQueue)
     expect(priorityQueue.head.next).toBe(undefined)
     expect(priorityQueue.head.capacity).toBe(defaultBucketSize)
@@ -31,6 +37,8 @@ describe('Priority queue test suite', () => {
     expect(priorityQueue.size).toBe(0)
     expect(priorityQueue.maxSize).toBe(0)
     expect(priorityQueue.enablePriority).toBe(true)
+    expect(priorityQueue.agingFactor).toBe(defaultAgingFactor)
+    expect(priorityQueue.loadExponent).toBe(defaultLoadExponent)
     expect(priorityQueue.head).toBeInstanceOf(FixedPriorityQueue)
     expect(priorityQueue.head.next).toBe(undefined)
     expect(priorityQueue.head.capacity).toBe(bucketSize)