0?e.calculateAverage(a):void 0,totalTimeMs:o,iterations:r}}async runAll(t=[...g]){let n=[];for(let r of t){let t=await this.runSingle(`js-native`,r);n.push(t);let i=await this.runSingle(`bitonic`,r);i.speedupVsNative=e.calculateSpeedup(t.totalTimeMs,i.totalTimeMs),n.push(i);let a=await this.runSingle(`radix`,r);a.speedupVsNative=e.calculateSpeedup(t.totalTimeMs,a.totalTimeMs),n.push(a)}return n}static formatResults(e){let t=[];t.push(`| Algorithm | Size | Total Time (ms) | GPU Time (ms) | Speedup |`),t.push(`|-----------|------|-----------------|---------------|---------|`);for(let n of e){let e=n.speedupVsNative?n.speedupVsNative.toFixed(2)+`x`:`-`,r=n.gpuTimeMs===void 0?`-`:n.gpuTimeMs.toFixed(2);t.push(`| ${n.algorithm.padEnd(9)} | ${n.arraySize.toString().padStart(7)} | ${n.totalTimeMs.toFixed(2).padStart(15)} | ${r.padStart(13)} | ${e.padStart(7)} |`)}return t.join(`
+`)}destroy(){this.bitonicSorter&&=(this.bitonicSorter.destroy(),null),this.radixSorter&&=(this.radixSorter.destroy(),null)}},A=document.getElementById(`unsupported`),j=document.getElementById(`app`),M=document.getElementById(`algorithm`),N=document.getElementById(`arraySize`),P=document.getElementById(`iterations`),F=document.getElementById(`runBtn`),I=document.getElementById(`runAllBtn`),L=document.getElementById(`status`),R=document.getElementById(`statusText`),z=document.getElementById(`progressBar`),B=document.getElementById(`resultsCard`),V=document.getElementById(`resultsBody`),H=null,U=null;async function W(){if(!l.isSupported()){G();return}try{H=new l,await H.initialize({powerPreference:`high-performance`}),U=new k(H),te(),K(`Ready to run benchmarks`,`success`)}catch(e){G(),console.error(`Failed to initialize WebGPU:`,e)}}function G(){A.style.display=`block`,j.style.display=`none`}function K(e,t=`info`){L.classList.add(`visible`),L.classList.remove(`error`,`success`),t===`error`&&L.classList.add(`error`),t===`success`&&L.classList.add(`success`),R.textContent=e}function q(e){z.style.width=`${e}%`}function J(e){F.disabled=!e,I.disabled=!e}function Y(e){return e<1?`${(e*1e3).toFixed(2)} µs`:e<1e3?`${e.toFixed(2)} ms`:`${(e/1e3).toFixed(2)} s`}function X(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(0)}K`:e.toString()}function Z(e,t){let n=document.createElement(`tr`),r=t&&e.algorithm!==`js-native`?t/e.totalTimeMs:e.speedupVsNative,i=r&&r>1?`fast`:`slow`,a=r?`${r.toFixed(2)}x`:`-`;n.innerHTML=`
+ | ${e.algorithm} |
+ ${X(e.arraySize)} |
+ ${Y(e.totalTimeMs)} |
+ ${e.gpuTimeMs===void 0?`-`:Y(e.gpuTimeMs)} |
+ ${a} |
+ `,V.appendChild(n),B.style.display=`block`}function Q(){V.innerHTML=``,B.style.display=`none`}async function $(){if(!U||!H)return;let e=M.value,t=parseInt(N.value),n=parseInt(P.value);J(!1),Q(),q(0);try{K(`Running JavaScript native sort (${X(t)} elements)...`),q(10);let r=await U.runSingle(`js-native`,t,n);if(Z(r),q(30),e===`bitonic`||e===`both`){K(`Running Bitonic Sort (${X(t)} elements)...`),Z(await U.runSingle(`bitonic`,t,n),r.totalTimeMs),q(e===`both`?60:90);let i=k.generateRandomData(Math.min(t,_)),a=new v(H),o=await a.sort(i),s=m.validate(i,o.sortedData);a.destroy(),s.isValid||console.warn(`Bitonic sort validation failed:`,s.errors)}if(e===`radix`||e===`both`){K(`Running Radix Sort (${X(t)} elements)...`),Z(await U.runSingle(`radix`,t,n),r.totalTimeMs),q(90);let e=k.generateRandomData(Math.min(t,_)),i=new w(H),a=await i.sort(e),o=m.validate(e,a.sortedData);i.destroy(),o.isValid||console.warn(`Radix sort validation failed:`,o.errors)}q(100),K(`Benchmark complete!`,`success`)}catch(e){K(`Error: ${e instanceof Error?e.message:String(e)}`,`error`),console.error(e)}finally{J(!0)}}async function ee(){if(!U)return;let e=[...g],t=parseInt(P.value);J(!1),Q(),q(0);try{let n=e.length*3,r=0;for(let i of e){K(`Running JS sort (${X(i)} elements)...`);let e=await U.runSingle(`js-native`,i,t);Z(e),r++,q(r/n*100),K(`Running Bitonic Sort (${X(i)} elements)...`),Z(await U.runSingle(`bitonic`,i,t),e.totalTimeMs),r++,q(r/n*100),K(`Running Radix Sort (${X(i)} elements)...`),Z(await U.runSingle(`radix`,i,t),e.totalTimeMs),r++,q(r/n*100)}K(`Full benchmark suite complete!`,`success`)}catch(e){K(`Error: ${e instanceof Error?e.message:String(e)}`,`error`),console.error(e)}finally{J(!0)}}function te(){F.addEventListener(`click`,$),I.addEventListener(`click`,ee)}W();
\ No newline at end of file
diff --git a/docs/public/demo/index.html b/docs/public/playground/index.html
similarity index 99%
rename from docs/public/demo/index.html
rename to docs/public/playground/index.html
index d824908..8a38a13 100644
--- a/docs/public/demo/index.html
+++ b/docs/public/playground/index.html
@@ -237,7 +237,7 @@
}
}
-
+
diff --git a/openspec/.templates/design.md b/openspec/.templates/design.md
deleted file mode 100644
index fceb46a..0000000
--- a/openspec/.templates/design.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Design Document: {change-name}
-
-## Overview
-
-
-
-## Architecture Changes
-
-
-
-## Data Flow
-
-
-
-## API Changes
-
-
-
-## Database/Model Changes
-
-
-
-## Security Considerations
-
-
-
-## Performance Considerations
-
-
-
-## Migration Strategy
-
-
-
-## Testing Strategy
-
-
-
-## Rollback Plan
-
-
-
----
-
-**Created**: {date}
diff --git a/openspec/.templates/proposal.md b/openspec/.templates/proposal.md
deleted file mode 100644
index 4782737..0000000
--- a/openspec/.templates/proposal.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Change Proposal: {title}
-
-## Metadata
-
-| Field | Value |
-| ------------- | ----------- |
-| **Created** | {date} |
-| **Status** | Draft |
-| **Author** | {author} |
-| **Change ID** | {change-id} |
-
-## Intent
-
-
-
-## Scope
-
-
-
-### Affected Specs
-
-- [ ] `sorting/` - Sorting algorithm specifications
-- [ ] `infrastructure/` - WebGPU infrastructure specs
-- [ ] `quality/` - Quality and tooling specs
-- [ ] `_archived/` - Historical documents (rarely)
-
-### Affected Code
-
-- [ ] `src/sorting/` - Sorting implementations
-- [ ] `src/core/` - Core WebGPU infrastructure
-- [ ] `src/shaders/` - WGSL compute shaders
-- [ ] `src/benchmark/` - Benchmark utilities
-- [ ] `src/shared/` - Shared types and constants
-- [ ] `test/` - Test files
-
-## Approach
-
-
-
-## Alternatives Considered
-
-
-
-## Dependencies
-
-
-
-## Risks
-
-
-
-## Checklist
-
-- [ ] Specs updated in `openspec/changes/{change-id}/specs/`
-- [ ] Tasks defined in `tasks.md`
-- [ ] No conflicts with existing specs
-- [ ] Backward compatibility considered
-
----
-
-**Next Step**: Run `/opsx:apply` to begin implementation.
diff --git a/openspec/.templates/spec.md b/openspec/.templates/spec.md
deleted file mode 100644
index 7c113fb..0000000
--- a/openspec/.templates/spec.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# {Domain} Spec: {Feature Name}
-
-## Introduction
-
-
-
-## Glossary
-
-
-
-| Term | Definition |
-| ---- | ---------- |
-| ... | ... |
-
-## Requirements
-
-### Requirement 1: {Requirement Name}
-
-**User Story:** As a [role], I want [feature] so that [benefit].
-
-#### Acceptance Criteria
-
-1. WHEN [condition], THE [component] SHALL [behavior]
-2. IF [error condition], THEN THE [component] SHALL [error handling]
-3. ...
-
-### Requirement 2: {Next Requirement}
-
-**User Story:** As a [role], I want [feature] so that [benefit].
-
-#### Acceptance Criteria
-
-1. ...
-
-## Properties (for Property-Based Testing)
-
-### Property 1: {Property Name}
-
-_For any_ [input conditions], the [function/component] SHALL [expected behavior].
-
-**Validates:** Requirements X.Y
-
-### Property 2: {Property Name}
-
-_For any_ [input conditions], the [function/component] SHALL [expected behavior].
-
-**Validates:** Requirements X.Y
-
-## Error Handling
-
-| Error Scenario | Handling Approach |
-| -------------- | ----------------- |
-| ... | ... |
-
-## Notes
-
-
-
----
-
-**Last Updated**: {date}
diff --git a/openspec/.templates/tasks.md b/openspec/.templates/tasks.md
deleted file mode 100644
index da0aab7..0000000
--- a/openspec/.templates/tasks.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Implementation Tasks: {change-name}
-
-## Metadata
-
-| Field | Value |
-| ------------- | ----------- |
-| **Change ID** | {change-id} |
-| **Created** | {date} |
-| **Status** | In Progress |
-
----
-
-## Status Legend
-
-| Symbol | Meaning |
-| ------ | ----------- |
-| [ ] | Not started |
-| [~] | In progress |
-| [x] | Completed |
-| [!] | Blocked |
-
----
-
-## Phase 1: Spec Review
-
-- [ ] Review affected specs in `openspec/specs/`
-- [ ] Identify any spec conflicts or ambiguities
-- [ ] Update delta specs in `openspec/changes/{change-id}/specs/` if needed
-- [ ] Get spec review approval
-
-## Phase 2: Implementation
-
-- [ ] Create/update source files
-- [ ] Update TypeScript type definitions
-- [ ] Update constants (sync with WGSL if applicable)
-- [ ] Handle edge cases and error conditions
-
-## Phase 3: Testing
-
-- [ ] Write unit tests for new functionality
-- [ ] Write property-based tests for correctness properties
-- [ ] Update existing tests if behavior changed
-- [ ] Run full test suite: `npm run test`
-- [ ] Verify coverage meets thresholds
-
-## Phase 4: Documentation
-
-- [ ] Update API documentation (JSDoc comments)
-- [ ] Update `AGENTS.md` if workflow changes
-- [ ] Update user documentation in `docs/`
-- [ ] Update Chinese translations (`.zh.md` files)
-
-## Phase 5: Verification
-
-- [ ] All tests pass: `npm run test`
-- [ ] TypeScript compiles: `npm run typecheck`
-- [ ] ESLint passes: `npm run lint`
-- [ ] Build succeeds: `npm run build`
-- [ ] Manual testing completed
-
----
-
-## Dependencies
-
-
-
-## Notes
-
-
-
----
-
-**Created**: {date}
diff --git a/openspec/archive/.gitkeep b/openspec/archive/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/.openspec.yaml b/openspec/archive/2026-04-closeout-foundation-reset/.openspec.yaml
deleted file mode 100644
index 8b394c6..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/.openspec.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-schema: spec-driven
-created: 2026-04-23
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/design.md b/openspec/archive/2026-04-closeout-foundation-reset/design.md
deleted file mode 100644
index a10c6fd..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/design.md
+++ /dev/null
@@ -1,92 +0,0 @@
-## Context
-
-The repository already passes its core quality gates, but the project is not yet operating from a single trustworthy source of truth. OpenSpec exists, yet several repo documents still reference the legacy `specs/` layout, `openspec/config.yaml` contains placeholder repository metadata, AI/tooling guidance is fragmented, and the current automation mix favors breadth over signal. The user wants a deliberate closeout phase: aggressively normalize the repo, finish the important work, and leave behind a coherent project that can be maintained lightly.
-
-This change is cross-cutting because it touches specifications, docs, AI instruction files, engineering config, GitHub workflows, Pages, and repository metadata. It also explicitly allows selected machine-level global tooling setup when that meaningfully improves the project's finish-line workflow.
-
-## Goals / Non-Goals
-
-**Goals:**
-
-- Re-establish OpenSpec as the authoritative workflow and requirements layer.
-- Make documentation, instruction files, and repository metadata accurately reflect the real repo structure and project value.
-- Reduce automation noise so CI/hooks/Pages support closeout instead of creating churn.
-- Define a project-specific AI-assisted workflow for OpenSpec, review checkpoints, subagents, LSP, and selective MCP/plugin usage.
-- Keep the public project presentation polished and trustworthy without expanding the runtime API surface unnecessarily.
-
-**Non-Goals:**
-
-- Adding new sorting algorithms or broadening the public runtime API.
-- Introducing heavyweight infrastructure that increases maintenance burden without clear closeout value.
-- Preserving every existing doc/workflow/config file if it no longer serves a concrete purpose.
-- Treating all possible global tooling as mandatory; only high-value global setup is in scope.
-
-## Decisions
-
-### 1. Use one umbrella closeout change instead of many overlapping changes
-
-The work will be organized under a single OpenSpec change, `closeout-foundation-reset`, with ordered tasks.
-
-- **Why:** The repo needs coordinated normalization across many surfaces. A single umbrella change reduces drift between docs/specs/config and fits the desired “one longer autopilot run, minimal fleet usage” workflow.
-- **Alternative considered:** Multiple small changes. Rejected because the repo is already suffering from fragmentation and this would increase sequencing overhead.
-
-### 2. Treat repository governance and project presentation as first-class requirements
-
-The change will add a dedicated capability, `project-workflow-governance`, and extend the existing `quality` capability with new requirements around source-of-truth alignment, automation signal quality, and public presentation consistency.
-
-- **Why:** AGENTS/CLAUDE/Copilot/process guidance should not live only as informal prose. The closeout workflow needs a durable normative layer that later implementation can follow.
-- **Alternative considered:** Keep everything in docs only. Rejected because it would recreate the same “advice without contract” drift.
-
-### 3. Keep runtime behavior stable unless a closeout defect forces change
-
-The default implementation posture will be to normalize architecture, docs, workflows, and tooling without intentionally expanding the library API.
-
-- **Why:** The user wants a high-quality finish, not a new feature wave. Stability is more valuable than surface-area growth at this stage.
-- **Alternative considered:** Fold feature additions into the same pass. Rejected because it would blur the scope and delay closeout.
-
-### 4. Prefer repo-scoped defaults plus a minimal global-tooling layer
-
-Committed repository settings and docs remain the primary source of setup, but the implementation may also add carefully selected global guidance/configuration for Copilot, Claude/Codex, LSP, MCP, or shell workflows.
-
-- **Why:** The user explicitly wants global tooling included, but only where it materially improves execution. A minimal layered policy keeps the environment usable without overfitting it.
-- **Alternative considered:** Repo-only setup. Rejected because it would ignore the confirmed scope.
-- **Alternative considered:** Broad global tooling rollout. Rejected because it would create unnecessary context and maintenance cost.
-
-### 5. Simplify automation toward high-signal gates
-
-Hooks and workflows will be evaluated against one standard: they must materially protect the repo or improve release/public-site quality.
-
-- **Why:** Current automation includes low-signal PR commenting and non-enforcing audit behavior. Closeout work benefits from fewer, clearer gates.
-- **Alternative considered:** Preserve all existing workflows and just patch them. Rejected because the repo specifically needs normalization, not incremental accretion.
-
-### 6. Reframe GitHub Pages as the project front door
-
-Pages will be treated as a product/showcase surface that aligns with README and GitHub metadata, not as a detached brochure or a passive README mirror.
-
-- **Why:** A polished landing page can explain trust, value, and demo flow faster than README alone, especially for a project entering low-maintenance mode.
-- **Alternative considered:** Leave Pages mostly as-is. Rejected because the public narrative is one of the user’s core concerns.
-
-## Risks / Trade-offs
-
-- **[Broad scope may cause mixed concerns]** → Mitigation: keep a strict ordered task list and validate each phase against the OpenSpec artifacts.
-- **[Global tooling changes may be environment-specific]** → Mitigation: favor minimal, reversible setup and document clear rationale for every global recommendation.
-- **[Workflow simplification could remove something useful]** → Mitigation: preserve only checks with measurable protective value and verify remaining gates cover lint, type safety, tests, build, and Pages.
-- **[Pages redesign may over-promise performance or support claims]** → Mitigation: align public copy with validated repo evidence and current benchmark/support statements.
-- **[OpenSpec schema and current repo layout are slightly misaligned]** → Mitigation: use this change to move toward canonical, easier-to-automate spec organization instead of reinforcing the drift.
-
-## Migration Plan
-
-1. Normalize OpenSpec/config/spec references first.
-2. Rewrite project authority docs and instruction files.
-3. Rationalize workflows/hooks/config.
-4. Update Pages and public GitHub positioning.
-5. Apply GitHub-side metadata changes with `gh`.
-6. Finish by codifying the closeout workflow and archiving the change.
-
-Rollback is straightforward because the work is mostly file/config/docs based: individual commits can be reverted by phase if a simplification choice proves harmful.
-
-## Open Questions
-
-- Which global-tooling files can be safely standardized in this environment versus documented as optional local setup?
-- How aggressively should legacy/low-value docs be removed versus retained with redirects or brief stubs?
-- Should the final workflow keep a dedicated PR-check workflow at all, or collapse everything into CI + Pages + release/security only?
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/proposal.md b/openspec/archive/2026-04-closeout-foundation-reset/proposal.md
deleted file mode 100644
index fa601ba..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/proposal.md
+++ /dev/null
@@ -1,28 +0,0 @@
-## Why
-
-The repository works, but its source-of-truth layers have drifted apart: OpenSpec adoption is incomplete, key documents still describe obsolete structures, AI/tooling guidance is fragmented, and several engineering workflows create noise instead of confidence. This change is needed now to aggressively normalize the project into a coherent, closeout-ready state so the remaining work can be finished with less ambiguity and less maintenance burden.
-
-## What Changes
-
-- Normalize the repository around OpenSpec as the single authoritative workflow and repair stale structural references, config drift, and spec wording gaps.
-- Redesign top-level documentation, project instruction files, and closeout workflow guidance so they are specific to this project and useful for final-stage maintenance.
-- Rationalize hooks, CI/workflows, Pages build flow, and related engineering configuration to keep only high-signal automation.
-- Reposition GitHub Pages and repository metadata so the public project presentation clearly explains the library, its demo, and its quality signals.
-- Define a pragmatic AI-assisted development workflow for OpenSpec + Copilot + Claude/Codex, including review checkpoints, LSP guidance, and a minimal policy for MCP/plugin usage.
-- Fix repository issues uncovered during this normalization work when they materially block the closeout path.
-
-## Capabilities
-
-### New Capabilities
-
-- `project-workflow-governance`: Defines the repo-specific closeout workflow, AI tool collaboration model, review checkpoints, and repo/global tooling policy for finishing the project cleanly.
-
-### Modified Capabilities
-
-- `quality`: Tightens project quality requirements to cover OpenSpec alignment, documentation authority, workflow signal quality, Pages positioning, hooks, repository metadata, and engineering configuration consistency.
-
-## Impact
-
-- Affected areas include `openspec/`, top-level project docs, `.github/workflows/`, `.husky/`, `.vscode/`, Pages/site assets, AI instruction files, and selected build/tooling config files.
-- GitHub-side repository metadata will be updated via `gh` during implementation after local wording and positioning are finalized.
-- No intentional public runtime API expansion is planned; the main impact is repository structure, process clarity, engineering reliability, and public presentation quality.
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/specs/project-workflow-governance/spec.md b/openspec/archive/2026-04-closeout-foundation-reset/specs/project-workflow-governance/spec.md
deleted file mode 100644
index 9f40a9c..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/specs/project-workflow-governance/spec.md
+++ /dev/null
@@ -1,58 +0,0 @@
-## ADDED Requirements
-
-### Requirement: OpenSpec closeout workflow
-
-The repository SHALL define a lightweight OpenSpec-driven workflow for finish-line development so contributors can complete cross-cutting changes without branch drift or ambiguous process.
-
-#### Scenario: Starting a closeout change
-
-- **WHEN** a contributor begins a non-trivial repository change
-- **THEN** the documented workflow SHALL require creating or selecting an OpenSpec change before implementation begins
-
-#### Scenario: Implementing a closeout change
-
-- **WHEN** a contributor executes work from an approved OpenSpec change
-- **THEN** the documented workflow SHALL define a clear sequence for `/opsx:explore`, `/opsx:propose`, `/opsx:apply`, `/review`, and `/opsx:archive`
-
-#### Scenario: Minimizing branch drift
-
-- **WHEN** contributors work through a closeout task list
-- **THEN** the workflow SHALL prefer small serial merges and SHALL discourage long-lived or fragmented parallel branches by default
-
-### Requirement: AI tool collaboration model
-
-The repository SHALL document project-specific roles for AI tools and review steps so Copilot, Claude/Codex-style agents, subagents, and review passes are used intentionally rather than interchangeably.
-
-#### Scenario: Choosing an execution mode
-
-- **WHEN** a contributor decides between interactive work, autopilot, subagents, or review
-- **THEN** the repository guidance SHALL explain which mode is appropriate for this project and what checkpoints are required
-
-#### Scenario: Using review before merge
-
-- **WHEN** a contributor completes a meaningful implementation slice
-- **THEN** the workflow SHALL require or strongly prescribe a `/review` step before the slice is considered ready
-
-#### Scenario: Avoiding tool duplication
-
-- **WHEN** multiple AI tools can perform overlapping work
-- **THEN** the project guidance SHALL define preferred tool roles so contributors avoid redundant instructions, duplicated context, and unnecessary cost
-
-### Requirement: Tooling policy for local and global setup
-
-The repository SHALL provide a minimal, justified policy for repo-level and global tooling setup, including LSP, MCP, plugins, and instruction files, so contributors can assemble a consistent development environment without excessive complexity.
-
-#### Scenario: Defining required repo-level tooling
-
-- **WHEN** a tool or setting is necessary for reliable work on this repository
-- **THEN** it SHALL be represented in committed project files or project docs
-
-#### Scenario: Recommending global tooling
-
-- **WHEN** a global tool configuration is recommended
-- **THEN** the guidance SHALL explain why it is useful for this project and whether it is required, recommended, or optional
-
-#### Scenario: Evaluating context-heavy integrations
-
-- **WHEN** MCP servers, plugins, or similar integrations are considered
-- **THEN** the repository guidance SHALL prefer the lowest-complexity option that still delivers clear value for this project
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/specs/quality/spec.md b/openspec/archive/2026-04-closeout-foundation-reset/specs/quality/spec.md
deleted file mode 100644
index 4df8528..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/specs/quality/spec.md
+++ /dev/null
@@ -1,53 +0,0 @@
-## ADDED Requirements
-
-### Requirement: Repository source-of-truth alignment
-
-The project SHALL keep its OpenSpec configuration, repository metadata references, and core documentation aligned with the actual repository structure so contributors do not encounter conflicting authority layers.
-
-#### Scenario: Referencing specifications
-
-- **WHEN** top-level docs or contributor guidance reference project specifications
-- **THEN** they SHALL point to the canonical `openspec/` structure used by the repository
-
-#### Scenario: Declaring repository identity
-
-- **WHEN** project configuration or governance files declare repository metadata
-- **THEN** they SHALL use the real repository URL, branch expectations, and authoritative project locations instead of placeholders or stale paths
-
-### Requirement: High-signal engineering automation
-
-The project SHALL maintain a small set of high-value hooks and GitHub workflows that protect code quality, build health, release flow, and public-site integrity without relying on noisy or low-trust automation.
-
-#### Scenario: Validating pull requests and pushes
-
-- **WHEN** contributors open pull requests or push protected branch updates
-- **THEN** the automation SHALL cover linting, type checking, tests, and build verification through clearly scoped workflows
-
-#### Scenario: Handling low-signal checks
-
-- **WHEN** an automated check only comments, warns without enforcement, or duplicates stronger protections
-- **THEN** the project SHALL remove it or replace it with a more actionable safeguard
-
-#### Scenario: Maintaining Pages and release flows
-
-- **WHEN** Pages or release automation is kept
-- **THEN** its responsibilities SHALL be explicit, deterministic, and consistent with the repository's closeout-ready maintenance posture
-
-### Requirement: Consistent public project positioning
-
-The project SHALL present a consistent narrative across README, documentation entrypoints, GitHub Pages, and GitHub repository metadata so users can quickly understand the library, demo, and trust signals.
-
-#### Scenario: Presenting the project to new users
-
-- **WHEN** a user lands on README, GitHub Pages, or the repository About section
-- **THEN** the messaging SHALL consistently describe what the project does, why it is useful, and where to try the demo or read docs
-
-#### Scenario: Linking public entrypoints
-
-- **WHEN** public-facing docs or metadata link to project resources
-- **THEN** those links SHALL resolve to maintained documentation, demo, spec, or repository locations
-
-#### Scenario: Curating documentation for closeout readiness
-
-- **WHEN** low-value, redundant, stale, or generic documents are identified
-- **THEN** the project SHALL remove, consolidate, or rewrite them so the remaining document set stays purposeful and specific
diff --git a/openspec/archive/2026-04-closeout-foundation-reset/tasks.md b/openspec/archive/2026-04-closeout-foundation-reset/tasks.md
deleted file mode 100644
index 04ba373..0000000
--- a/openspec/archive/2026-04-closeout-foundation-reset/tasks.md
+++ /dev/null
@@ -1,36 +0,0 @@
-## 1. Repository truth reset
-
-- [x] 1.1 Audit and fix stale references to legacy `specs/` paths, placeholder repository metadata, and obsolete structure descriptions across OpenSpec config and authority docs
-- [x] 1.2 Normalize the canonical spec/doc layout so `openspec/` is the unambiguous source of truth for future changes
-- [x] 1.3 Tighten the quality and workflow-governance source docs so later implementation work has clear project-specific guidance
-
-## 2. Core documentation redesign
-
-- [x] 2.1 Rewrite `README.md` and `README.zh.md` to align project positioning, public links, and actual repository structure
-- [x] 2.2 Rewrite `PROJECT_OVERVIEW.md`, `docs/README.md`, and related entrypoint docs to remove stale, redundant, or generic content
-- [x] 2.3 Consolidate `CONTRIBUTING.md`, `CHANGELOG.md`, and other closeout-facing docs into a lower-noise, project-specific document set
-
-## 3. AI guidance and tooling workflow
-
-- [x] 3.1 Redesign `AGENTS.md` around this repository's actual architecture, OpenSpec workflow, and closeout-oriented contribution model
-- [x] 3.2 Add a project `CLAUDE.md` and generate/refine `copilot-instructions.md` so AI instructions are complementary and non-duplicative
-- [x] 3.3 Document the preferred usage model for Copilot, Claude/Codex-style agents, `/review`, subagents, autopilot, and minimal `/fleet` usage
-- [x] 3.4 Define repo-level and global-tooling guidance for LSP, MCP, plugins, and optional local setup with explicit value/cost trade-offs
-
-## 4. Engineering surface rationalization
-
-- [x] 4.1 Simplify Husky hooks and workspace/editor settings so they enforce only the protections this repo actually needs
-- [x] 4.2 Rationalize GitHub workflows for CI, PR checks, Pages, release, and security into a smaller high-signal automation set
-- [x] 4.3 Fix concrete engineering issues uncovered during normalization, including current lint warnings and configuration inconsistencies in touched areas
-
-## 5. Public presentation and repository metadata
-
-- [x] 5.1 Redesign the GitHub Pages content and supporting build flow so the site acts as a polished project showcase and demo funnel
-- [x] 5.2 Align README, docs entrypoints, and Pages messaging so public claims, trust signals, and navigation stay consistent
-- [x] 5.3 Update GitHub repository description, homepage/about, and topic curation with `gh` after the local messaging and Pages direction are finalized
-
-## 6. Closeout workflow finalization
-
-- [x] 6.1 Codify a lightweight finish-line workflow for OpenSpec propose/apply/review/archive cycles with small serial merges
-- [x] 6.2 Validate the final repo setup with the existing lint, typecheck, test, and build commands plus any remaining closeout-specific checks
-- [x] 6.3 Review the completed change against its specs, capture any follow-up gaps, and prepare it for archive
diff --git a/openspec/archive/2026-04-closeout-refactor/proposal.md b/openspec/archive/2026-04-closeout-refactor/proposal.md
deleted file mode 100644
index 182f056..0000000
--- a/openspec/archive/2026-04-closeout-refactor/proposal.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Proposal: Closeout Refactor
-
-## Summary
-
-Comprehensive refactoring of the WebGPU Sorting project to achieve "closeout-ready" status, fixing all identified bugs, improving code quality, and completing documentation.
-
-## Motivation
-
-The project needs to reach a stable, maintainable state before handoff to GLM model for final maintenance. This requires:
-
-1. Fixing all critical code issues
-2. Improving code quality metrics
-3. Completing OpenSpec coverage
-4. Ensuring documentation completeness
-
-## Scope
-
-### In Scope
-
-- GPU context initialization improvements
-- Bitonic Sort boundary condition fixes
-- Radix Sort resource cleanup improvements
-- GPUTimeoutError implementation
-- Error handling standardization
-- Test coverage threshold increase
-- Random number generation improvement
-- Empty directory cleanup
-- Infrastructure spec creation
-- Documentation updates
-
-### Out of Scope
-
-- npm publishing (kept disabled, documented)
-- Major feature additions
-- Architecture changes
-
-## Impact
-
-### Code Changes
-
-- `src/core/GPUContext.ts` - Device limits and loss handling
-- `src/core/BufferManager.ts` - Error formatting
-- `src/core/timeout.ts` - New timeout utility
-- `src/sorting/BitonicSorter.ts` - Boundary conditions
-- `src/sorting/RadixSorter.ts` - Resource cleanup with try-finally
-- `src/benchmark/Benchmark.ts` - crypto.getRandomValues
-- `vitest.config.ts` - Coverage thresholds
-
-### Documentation Changes
-
-- `CONTRIBUTING.md` - npm publishing documentation
-- `examples/README.en.md` - English version
-- `PROJECT_OVERVIEW.md` - Updated code areas
-- `openspec/specs/infrastructure/gpu-context.md` - New spec
-
-### Deleted
-
-- `docs/assets/` - Empty directory
-- `site/docs/en/`, `site/docs/zh/`, `site/templates/` - Empty directories
-
-## Success Criteria
-
-- [ ] All TypeScript/ESLint errors resolved
-- [ ] All tests passing (61 tests)
-- [ ] Build succeeds
-- [ ] Test coverage thresholds increased to 30%+
-- [ ] All critical bugs fixed
-- [ ] OpenSpec specs complete for infrastructure
-- [ ] Documentation complete and bilingual
-
-## Timeline
-
-Completed in single session: ~2 hours
-
-## Risk Assessment
-
-| Risk | Probability | Mitigation |
-| ---------------------------- | ----------- | ------------------------------------------ |
-| Test failures from changes | Low | Incremental verification after each change |
-| Type errors from refactoring | Low | TypeScript strict mode catches early |
-| Coverage threshold too high | Medium | Set reasonable 30% target |
-
-## Dependencies
-
-None - all changes are self-contained within the project.
-
-## Handoff Notes
-
-After this change:
-
-1. Project is ready for GLM model handoff
-2. All validation commands pass: `npm run typecheck && npm run lint && npm run test && npm run build`
-3. Consider running `npm run test:coverage` to verify coverage meets new thresholds
diff --git a/openspec/archive/2026-04-closeout-refactor/tasks.md b/openspec/archive/2026-04-closeout-refactor/tasks.md
deleted file mode 100644
index d7977b4..0000000
--- a/openspec/archive/2026-04-closeout-refactor/tasks.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# Tasks: Closeout Refactor
-
-## Phase 1: Critical Code Fixes
-
-- [x] 1.1 Fix GPU device lost Promise handling in GPUContext.ts
-- [x] 1.2 Add boundary condition checks in BitonicSorter.ts
-- [x] 1.3 Implement try-finally resource cleanup in RadixSorter.ts
-- [x] 1.4 Implement GPUTimeoutError and withTimeout utility
-- [x] 1.5 Add device limits requests in GPUContext.ts
-
-## Phase 2: Code Quality Improvements
-
-- [x] 2.1 Increase test coverage thresholds (15-25% → 30-45%)
-- [x] 2.2 Standardize error handling in catch blocks
-- [x] 2.3 Verify large dataset validation optimization
-- [x] 2.4 Replace Math.random with crypto.getRandomValues
-
-## Phase 3: Architecture Cleanup
-
-- [x] 3.1 Verify .gitignore coverage
-- [x] 3.2 Delete empty directories
-- [x] 3.3 Update PROJECT_OVERVIEW.md
-- [x] 3.4 Create infrastructure spec
-
-## Phase 4: Documentation
-
-- [x] 4.1 Create English version of examples README
-- [x] 4.2 Add npm publishing documentation to CONTRIBUTING.md
-
-## Phase 5: OpenSpec
-
-- [x] 5.1 Create change proposal
-- [x] 5.2 Create tasks document
-
-## Verification
-
-All tasks verified with:
-
-```bash
-npm run typecheck && npm run lint && npm run test && npm run build
-```
-
-Results:
-
-- TypeScript: ✅ No errors
-- ESLint: ✅ No errors
-- Tests: ✅ 61 passed
-- Build: ✅ Success
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/.openspec.yaml b/openspec/archive/2026-05-demo-benchmark-orchestration/.openspec.yaml
deleted file mode 100644
index 4a1c677..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/.openspec.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-schema: spec-driven
-created: 2026-05-22
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/design.md b/openspec/archive/2026-05-demo-benchmark-orchestration/design.md
deleted file mode 100644
index e157aeb..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/design.md
+++ /dev/null
@@ -1,39 +0,0 @@
-## Context
-
-The current demo path spans `src/main.ts` and `src/benchmark/Benchmark.ts`, but the seam is shallow. `Benchmark` owns both pure math and stateful execution, while `main.ts` owns DOM lookup, status updates, progress, validation, and direct sorter construction.
-
-This change deepens the orchestration path by making execution and presentation explicit modules with narrow interfaces.
-
-## Goals / Non-Goals
-
-**Goals:**
-
-- Make benchmark execution unit-testable without DOM or real WebGPU.
-- Make demo UI flow unit-testable without `document`.
-- Keep `main.ts` as a thin bootstrap file.
-
-**Non-Goals:**
-
-- Redesign `GPUContext` again; that lands in `injectable-gpu-runtime`.
-- Change benchmark outputs or visible UI behavior.
-- Extract radix prefix-sum in this change.
-
-## Decisions
-
-### 1. Split pure benchmark helpers from execution
-
-Keep `Benchmark` for `calculateSpeedup`, `calculateAverage`, and `formatResults`. Move `runSingle` and `runAll` into `BenchmarkRunner`.
-
-### 2. Add a `DemoController` seam
-
-Move run-button and run-all orchestration, progress updates, validation, and error handling into a controller with injected dependencies.
-
-### 3. Isolate DOM access behind `DomView`
-
-Create a concrete adapter for DOM reads/writes so tests can drive orchestration with fake views.
-
-## Risks / Trade-offs
-
-- **More files** -> Accept smaller modules to gain locality and test seams.
-- **Public benchmark API churn** -> Preserve helper exports and document runner extraction in the change.
-- **Controller/view split may feel verbose** -> The leverage is deterministic tests and a thinner bootstrap.
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/proposal.md b/openspec/archive/2026-05-demo-benchmark-orchestration/proposal.md
deleted file mode 100644
index 4cd85de..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/proposal.md
+++ /dev/null
@@ -1,27 +0,0 @@
-## Why
-
-`main.ts` and `Benchmark` still braid DOM wiring, benchmark sequencing, sorter lifecycle, validation, and presentation into shallow modules. That makes the demo flow hard to unit-test and keeps UI/runtime knowledge spread across multiple call sites.
-
-## What Changes
-
-- Extract benchmark execution into a dedicated `BenchmarkRunner` seam with injected sorter factory, random data provider, and clock.
-- Extract demo orchestration into a `DemoController` seam with a `DomView` adapter for DOM reads/writes.
-- Shrink `main.ts` to bootstrap only and keep `Benchmark` focused on pure formatting/math helpers.
-- Add unit tests for orchestration, progress/status flow, validation flow, and error handling without requiring real WebGPU.
-
-## Capabilities
-
-### New Capabilities
-
-- `demo-orchestration`: Deep orchestration seam for demo and benchmark flows, separating controller logic from DOM adapters and benchmark execution.
-
-### Modified Capabilities
-
-- `sorting`: Benchmark execution moves behind an injected runner while preserving existing benchmark behavior.
-
-## Impact
-
-- **Affected code:** `src/main.ts`, `src/benchmark/Benchmark.ts`, new `src/benchmark/BenchmarkRunner.ts`, new `src/demo/` files, browser/unit tests
-- **Affected APIs:** `Benchmark` likely loses execution methods; orchestration moves into new modules.
-- **Dependencies:** No new packages.
-- **Systems:** Demo UI, benchmark execution, validation flow, and public benchmark surface.
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/specs/demo-orchestration/spec.md b/openspec/archive/2026-05-demo-benchmark-orchestration/specs/demo-orchestration/spec.md
deleted file mode 100644
index dbbd627..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/specs/demo-orchestration/spec.md
+++ /dev/null
@@ -1,24 +0,0 @@
-## ADDED Requirements
-
-### Requirement: Demo orchestration uses injected seams
-
-The demo benchmark flow SHALL execute through controller and view seams so orchestration can be tested without direct DOM or WebGPU dependencies.
-
-#### Scenario: Controller drives benchmark execution
-
-- **WHEN** a user starts a single benchmark or the full suite
-- **THEN** the controller SHALL coordinate progress, status, validation, and result reporting through injected runner and view interfaces
-
-#### Scenario: DOM access stays in the view adapter
-
-- **WHEN** the demo needs to read controls or update status, progress, and results
-- **THEN** those DOM operations SHALL be isolated behind a concrete view adapter
-
-### Requirement: Benchmark execution is a separate runner
-
-Benchmark execution SHALL live behind a runner seam distinct from pure formatting and math helpers.
-
-#### Scenario: Runner executes benchmark cases
-
-- **WHEN** benchmark execution is requested
-- **THEN** the runner SHALL use injected sorter factories, random data providers, and clocks to produce benchmark results
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/specs/sorting/spec.md b/openspec/archive/2026-05-demo-benchmark-orchestration/specs/sorting/spec.md
deleted file mode 100644
index 53e6feb..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/specs/sorting/spec.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## MODIFIED Requirements
-
-### Requirement: Performance Benchmarking
-
-The benchmark system SHALL preserve its existing timing and reporting behavior while executing through a dedicated runner seam rather than the formatting helper module.
-
-#### Scenario: Runner preserves benchmark behavior
-
-- **WHEN** a caller runs a single benchmark or the default suite
-- **THEN** the system SHALL still measure native and GPU paths, average timings, and report speedups as before
-
-#### Scenario: Formatting stays available independently
-
-- **WHEN** code needs to format benchmark results
-- **THEN** it SHALL be able to do so without instantiating the execution runner
diff --git a/openspec/archive/2026-05-demo-benchmark-orchestration/tasks.md b/openspec/archive/2026-05-demo-benchmark-orchestration/tasks.md
deleted file mode 100644
index 62e1d73..0000000
--- a/openspec/archive/2026-05-demo-benchmark-orchestration/tasks.md
+++ /dev/null
@@ -1,17 +0,0 @@
-## 1. Test-first orchestration seams
-
-- [ ] 1.1 Add failing unit tests for `BenchmarkRunner` execution with injected sorter factory and random provider
-- [ ] 1.2 Add failing unit tests for `DemoController` progress, validation, and error flow with a fake view
-
-## 2. Implementation
-
-- [ ] 2.1 Extract pure helpers into a slim `Benchmark` module
-- [ ] 2.2 Add `BenchmarkRunner` and move benchmark execution there
-- [ ] 2.3 Add `DemoController` and `DomView`, then shrink `main.ts` to bootstrap only
-
-## 3. Validation
-
-- [ ] 3.1 Run `npm run typecheck`
-- [ ] 3.2 Run `npm run lint`
-- [ ] 3.3 Run `npm run test`
-- [ ] 3.4 Run `npm run build`
diff --git a/openspec/archive/2026-05-doc-implementation-sync/proposal.md b/openspec/archive/2026-05-doc-implementation-sync/proposal.md
deleted file mode 100644
index ac68c55..0000000
--- a/openspec/archive/2026-05-doc-implementation-sync/proposal.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Change Proposal: Documentation-Implementation Synchronization
-
-## Metadata
-
-| Field | Value |
-| ------------- | ----------------------- |
-| **Created** | 2026-05-14 |
-| **Status** | Draft |
-| **Author** | Claude |
-| **Change ID** | doc-implementation-sync |
-
-## Intent
-
-The documentation in `docs/api.md` and `docs/performance.md` references features that don't exist in the implementation: `SortOptions` interface with `validate` and `timing` options, and `sortAsync()` method. This creates confusion for users. This change either implements these features or removes them from documentation to ensure consistency.
-
-## Scope
-
-### Affected Specs
-
-- [ ] `sorting/` - Sorting algorithm specifications
-- [ ] `infrastructure/` - WebGPU infrastructure specs
-- [ ] `quality/` - Quality and tooling specs
-- [ ] `_archived/` - Historical documents
-
-### Affected Code
-
-- [ ] `src/sorting/BitonicSorter.ts` - Implement SortOptions (optional)
-- [ ] `src/sorting/RadixSorter.ts` - Implement SortOptions (optional)
-- [x] `docs/api.md` - Fix documentation
-- [x] `docs/performance.md` - Fix documentation
-- [ ] `src/shared/types.ts` - Add SortOptions (if implementing)
-
-## Discrepancies Found
-
-| Documented Feature | Actual Implementation | Resolution |
-| ------------------------------------ | --------------------- | ------------------------------------------ |
-| `SortOptions { validate?: boolean }` | Not implemented | Implement (useful feature) |
-| `SortOptions { timing?: boolean }` | Not implemented | Implement (useful feature) |
-| `sorter.sort(data, options)` | `sort(data)` only | Add options parameter |
-| `sortAsync()` method | Not implemented | Remove from docs (sort() is already async) |
-| `preallocate()` method | Not implemented | Separate change (buffer-preallocation) |
-
-## Approach
-
-### Option A: Implement Documented Features (Recommended)
-
-1. **Add SortOptions interface**
-
- ```typescript
- interface SortOptions {
- validate?: boolean; // Verify output is sorted
- timing?: boolean; // Measure GPU time (default: true)
- }
- ```
-
-2. **Modify sort() signature**
-
- ```typescript
- async sort(data: Uint32Array, options?: SortOptions): Promise
- ```
-
-3. **Implement validate option**
- - Use existing Validator class internally
- - Add validation result to SortResult or throw on failure
-
-4. **Implement timing option**
- - Already tracked internally
- - Skip timing if `timing: false`
-
-5. **Remove sortAsync() from docs**
- - Method is redundant (sort() returns Promise)
-
-### Option B: Remove from Documentation
-
-Remove all references to unimplemented features. Simpler but less valuable.
-
-## Dependencies
-
-- `buffer-preallocation` change handles `preallocate()` separately
-
-## Risks
-
-| Risk | Mitigation |
-| ----------------------------------------- | ----------------------------------------- |
-| Breaking change if users expected options | API is additive, backward compatible |
-| Performance impact of validation | Default to false, only run when requested |
-
-## Checklist
-
-- [ ] Specs updated in `openspec/changes/doc-implementation-sync/specs/`
-- [ ] Tasks defined in `tasks.md`
-- [ ] No conflicts with existing specs
-- [x] Backward compatibility considered
-
----
-
-**Next Step**: Run `/opsx:apply` to begin implementation.
diff --git a/openspec/archive/2026-05-doc-implementation-sync/tasks.md b/openspec/archive/2026-05-doc-implementation-sync/tasks.md
deleted file mode 100644
index cb50adb..0000000
--- a/openspec/archive/2026-05-doc-implementation-sync/tasks.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Implementation Tasks: Documentation-Implementation Synchronization
-
-## Metadata
-
-| Field | Value |
-| ------------- | ----------------------- |
-| **Change ID** | doc-implementation-sync |
-| **Created** | 2026-05-14 |
-| **Status** | In Progress |
-
----
-
-## Status Legend
-
-| Symbol | Meaning |
-| ------ | ----------- |
-| [ ] | Not started |
-| [~] | In progress |
-| [x] | Completed |
-| [!] | Blocked |
-
----
-
-## Phase 1: Type Definitions
-
-- [x] Add `SortOptions` interface to `src/shared/types.ts`
-- [x] Update JSDoc for SortOptions
-- [x] Consider extending `SortResult` with validation info (optional) - not needed
-
-## Phase 2: BitonicSorter Implementation
-
-- [x] Update `sort()` signature to accept `SortOptions`
-- [x] Implement `validate` option using Validator class
-- [x] Implement `timing` option (skip timing if false) - not implemented, timing always on
-- [x] Handle backward compatibility (options is optional)
-
-## Phase 3: RadixSorter Implementation
-
-- [x] Update `sort()` signature to accept `SortOptions`
-- [x] Implement `validate` option using Validator class
-- [x] Implement `timing` option (skip timing if false) - not implemented, timing always on
-- [x] Handle backward compatibility (options is optional)
-
-## Phase 4: Documentation Updates
-
-- [x] Remove `sortAsync()` from `docs/api.md`
-- [x] Remove `sortAsync()` from `docs/performance.md`
-- [x] Verify `SortOptions` documentation matches implementation
-- [x] Verify `preallocate()` docs are handled in separate change
-- [x] Add code examples for new SortOptions
-- [ ] Update Chinese translations if applicable
-
-## Phase 5: Testing
-
-- [ ] Add tests for sort with `{ validate: true }` - requires browser
-- [ ] Add tests for sort with `{ timing: false }` - not implemented
-- [x] Add tests for sort with no options (backward compat) - existing tests cover this
-- [ ] Test validation throws/fails correctly - requires browser
-- [x] Run full test suite: `npm run test`
-
-## Phase 6: Verification
-
-- [x] All tests pass: `npm run test`
-- [x] TypeScript compiles: `npm run typecheck`
-- [x] ESLint passes: `npm run lint` (warnings only)
-- [x] Build succeeds: `npm run build`
-- [ ] Manual browser testing completed
-
----
-
-## Dependencies
-
-- None
-
-## Notes
-
-- `validate` option is useful for debugging and testing
-- `timing: false` can save minimal overhead if user doesn't need timing
-- Keep backward compatibility: `sort(data)` must still work
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/archive/2026-05-injectable-gpu-runtime/.openspec.yaml b/openspec/archive/2026-05-injectable-gpu-runtime/.openspec.yaml
deleted file mode 100644
index 4a1c677..0000000
--- a/openspec/archive/2026-05-injectable-gpu-runtime/.openspec.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-schema: spec-driven
-created: 2026-05-22
diff --git a/openspec/archive/2026-05-injectable-gpu-runtime/design.md b/openspec/archive/2026-05-injectable-gpu-runtime/design.md
deleted file mode 100644
index 36740ce..0000000
--- a/openspec/archive/2026-05-injectable-gpu-runtime/design.md
+++ /dev/null
@@ -1,63 +0,0 @@
-## Context
-
-`GPUContext` currently owns both the interface and the browser-specific implementation for support checks, adapter acquisition, device creation, limits mapping, and device-loss subscription. Tests can only reach most branches by stubbing browser globals, which keeps the interface shallow and the implementation hard to move.
-
-The goal of this change is to deepen `GPUContext`, not replace it. Callers should still use one lifecycle module, but the browser runtime becomes an adapter behind a seam.
-
-## Goals / Non-Goals
-
-**Goals:**
-
-- Keep `GPUContext` as the public lifecycle module.
-- Introduce an injectable runtime interface for support checks and adapter acquisition.
-- Preserve `new GPUContext()` as the default browser path.
-- Make initialization, failure, loss, and recovery paths unit-testable without browser globals.
-
-**Non-Goals:**
-
-- Refactor demo/benchmark orchestration in this change.
-- Add non-browser production adapters yet.
-- Change sorting algorithms or shader ownership.
-
-## Decisions
-
-### 1. Add a `GPURuntime` seam under `src/core/runtime/`
-
-Create an interface that owns:
-
-- support detection
-- adapter acquisition
-
-Add `browserGPURuntime` as the default adapter that wraps `navigator.gpu`.
-
-**Why:** Browser-global access is the shallow part. Moving it behind one seam gives `GPUContext` leverage and keeps future adapters possible.
-
-**Alternative:** Keep static browser-global checks and only inject requestAdapter. Rejected because support detection and acquisition belong to the same runtime adapter.
-
-### 2. Keep `GPUContext` as the public module
-
-`GPUContext` constructor accepts an optional runtime adapter, defaulting to `browserGPURuntime`. `initialize()` and `recover()` continue to define lifecycle semantics and error shaping.
-
-**Why:** Callers keep one familiar interface. The seam changes implementation ownership, not the high-level API shape.
-
-**Alternative:** Replace `GPUContext` with factories or free functions. Rejected because it would increase churn before the orchestration seam lands.
-
-### 3. Export runtime types, not extra orchestration
-
-Export the runtime interface and browser adapter from `src/index.ts` so tests and advanced consumers can inject them directly.
-
-**Why:** Constructor injection without exported types keeps the seam half-hidden.
-
-**Alternative:** Keep runtime files internal. Rejected because public constructor injection needs a public type.
-
-### 4. Rewrite `GPUContext` tests around fake runtimes
-
-Use injected fake runtimes/adapters/devices for initialization branches, limits mapping, recovery, and device-loss callbacks. Keep only small browser-global tests for the default static support path.
-
-**Why:** The interface is the test surface. The fake runtime gives locality for failure-path testing without browser globals.
-
-## Risks / Trade-offs
-
-- **Public API surface grows slightly** -> Limit it to runtime interface + default browser adapter.
-- **Fake GPU objects can drift from WebGPU reality** -> Keep browser E2E smoke tests and only fake branches that do not need real hardware.
-- **Future adapters may want more hooks** -> Start with the smallest seam: support detection + adapter acquisition.
diff --git a/openspec/archive/2026-05-injectable-gpu-runtime/proposal.md b/openspec/archive/2026-05-injectable-gpu-runtime/proposal.md
deleted file mode 100644
index 305c968..0000000
--- a/openspec/archive/2026-05-injectable-gpu-runtime/proposal.md
+++ /dev/null
@@ -1,27 +0,0 @@
-## Why
-
-`GPUContext` still hard-codes `navigator.gpu`, adapter acquisition, and device-loss wiring inside one shallow module. That blocks deterministic unit tests, leaks browser globals into call sites, and makes future runtime adapters impossible without editing the implementation in place.
-
-## What Changes
-
-- Add an injectable GPU runtime seam so `GPUContext` acquires adapters and support checks through an adapter interface instead of browser globals.
-- Keep `GPUContext` as the public lifecycle module, but move browser-global access into a dedicated browser adapter.
-- Expand unit coverage for adapter absence, device request failure, limits mapping, device-loss callbacks, and recovery using fake runtimes.
-- Export the runtime types needed for external injection while keeping the default browser path intact.
-
-## Capabilities
-
-### New Capabilities
-
-- None.
-
-### Modified Capabilities
-
-- `infrastructure`: GPU context initialization must support injected runtime adapters while preserving the default browser runtime path.
-
-## Impact
-
-- **Affected code:** `src/core/GPUContext.ts`, new `src/core/runtime/` files, `src/index.ts`, `test/core/GPUContext.test.ts`
-- **Affected APIs:** `GPUContext` constructor gains an optional runtime adapter; runtime interface/types become importable.
-- **Dependencies:** No new packages.
-- **Systems:** Core runtime initialization, lifecycle handling, and unit-test seams.
diff --git a/openspec/archive/2026-05-injectable-gpu-runtime/specs/infrastructure/spec.md b/openspec/archive/2026-05-injectable-gpu-runtime/specs/infrastructure/spec.md
deleted file mode 100644
index 38341f2..0000000
--- a/openspec/archive/2026-05-injectable-gpu-runtime/specs/infrastructure/spec.md
+++ /dev/null
@@ -1,25 +0,0 @@
-## MODIFIED Requirements
-
-### Requirement: GPU Context Initialization
-
-The GPUContext SHALL initialize through an injectable runtime adapter while preserving the default browser runtime path and existing lifecycle guarantees.
-
-#### Scenario: Default browser runtime remains available
-
-- **WHEN** a caller constructs `GPUContext` without providing a runtime adapter
-- **THEN** the context SHALL use the browser runtime adapter for support detection and adapter acquisition
-
-#### Scenario: Injected runtime drives initialization
-
-- **WHEN** a caller constructs `GPUContext` with a runtime adapter
-- **THEN** `initialize()` SHALL use that adapter instead of reading browser globals directly
-
-#### Scenario: Injected runtime failure is surfaced as typed errors
-
-- **WHEN** the injected runtime reports no adapter or device creation fails
-- **THEN** GPUContext SHALL preserve the existing typed error semantics for adapter and device failures
-
-#### Scenario: Injected runtime remains compatible with recovery and loss callbacks
-
-- **WHEN** device loss occurs and `recover()` is called on a context using an injected runtime
-- **THEN** the context SHALL reset state, reacquire a device through the same runtime adapter, and continue notifying registered callbacks
diff --git a/openspec/archive/2026-05-injectable-gpu-runtime/tasks.md b/openspec/archive/2026-05-injectable-gpu-runtime/tasks.md
deleted file mode 100644
index 550e47e..0000000
--- a/openspec/archive/2026-05-injectable-gpu-runtime/tasks.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## 1. OpenSpec and test setup
-
-- [x] 1.1 Finalize infrastructure delta spec for injected GPU runtime behavior
-- [x] 1.2 Add failing `GPUContext` tests for injected runtime initialization, failure paths, limits mapping, and recovery/loss callbacks
-
-## 2. Runtime seam implementation
-
-- [x] 2.1 Add `src/core/runtime/` runtime interface and default browser adapter
-- [x] 2.2 Refactor `GPUContext` to use injected runtime adapters while preserving `new GPUContext()` as the default path
-- [x] 2.3 Export runtime seam types from `src/index.ts`
-
-## 3. Validation
-
-- [x] 3.1 Update `GPUContext` tests to remove unnecessary browser-global stubbing from non-browser paths
-- [x] 3.2 Run `npm run typecheck`
-- [x] 3.3 Run `npm run lint`
-- [x] 3.4 Run `npm run test`
-- [x] 3.5 Run `npm run build`
diff --git a/openspec/archive/2026-05-scan-module-extraction/.openspec.yaml b/openspec/archive/2026-05-scan-module-extraction/.openspec.yaml
deleted file mode 100644
index 4a1c677..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/.openspec.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-schema: spec-driven
-created: 2026-05-22
diff --git a/openspec/archive/2026-05-scan-module-extraction/design.md b/openspec/archive/2026-05-scan-module-extraction/design.md
deleted file mode 100644
index 88ccf47..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/design.md
+++ /dev/null
@@ -1,39 +0,0 @@
-## Context
-
-The repository already moved radix prefix-sum onto the GPU, but the implementation stayed embedded in `RadixSorter`. That gives callers no scan seam, couples shader ownership to radix sorting, and leaves scan behavior hard to test independently.
-
-This change extracts the scan path into a deep module that RadixSorter can consume.
-
-## Goals / Non-Goals
-
-**Goals:**
-
-- Give GPU prefix-sum its own module, shader ownership, and tests.
-- Reduce `RadixSorter` to histogram/scatter orchestration plus scan consumption.
-- Align docs/specs with actual GPU prefix-sum behavior.
-
-**Non-Goals:**
-
-- Change radix sort user-facing behavior.
-- Refactor demo/benchmark orchestration here.
-- Build a general-purpose GPU algorithm framework.
-
-## Decisions
-
-### 1. Add `src/sorting/scan/`
-
-Create a scan module with its own interface, initialization, dispatch, and teardown.
-
-### 2. Split shader ownership
-
-Move Blelloch scan kernels out of `radix.wgsl` into scan-owned WGSL so shader locality matches module ownership.
-
-### 3. Keep RadixSorter as a consumer
-
-RadixSorter will request exclusive prefix sums through a narrow interface and keep radix-specific buffers/passes local.
-
-## Risks / Trade-offs
-
-- **Shader split churn** -> Accept one-time movement for better locality and reuse.
-- **Extra module lifecycle** -> Keep scan interface narrow and explicit.
-- **Spec/doc drift risk** -> Update stable sorting specs as part of the change.
diff --git a/openspec/archive/2026-05-scan-module-extraction/proposal.md b/openspec/archive/2026-05-scan-module-extraction/proposal.md
deleted file mode 100644
index 80066a4..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/proposal.md
+++ /dev/null
@@ -1,27 +0,0 @@
-## Why
-
-`RadixSorter` still owns histogram, scatter, and GPU prefix-sum orchestration inside one shallow module. The scan pipeline has real leverage on its own, but today its interface is trapped inside `RadixSorter` and its shader kernels are mixed into `radix.wgsl`.
-
-## What Changes
-
-- Extract GPU prefix-sum into a dedicated scan module with its own initialization, dispatch, and cleanup.
-- Split scan WGSL kernels from radix-only kernels.
-- Update RadixSorter to depend on the scan seam instead of owning scan pipeline details directly.
-- Add dedicated scan tests and align specs/docs with GPU-based prefix-sum ownership.
-
-## Capabilities
-
-### New Capabilities
-
-- `gpu-prefix-sum-module`: Dedicated scan module for GPU exclusive prefix sums with reusable runtime ownership.
-
-### Modified Capabilities
-
-- `sorting`: Radix sort shall consume the standalone scan module instead of embedding scan orchestration directly.
-
-## Impact
-
-- **Affected code:** `src/sorting/RadixSorter.ts`, new `src/sorting/scan/` files, `src/shaders/radix.wgsl`, new scan shader file(s), related tests/docs/specs
-- **Affected APIs:** New scan module surface; RadixSorter internal orchestration changes.
-- **Dependencies:** Likely overlaps conceptually with existing `gpu-prefix-sum` implementation history but should land as a new architectural extraction change.
-- **Systems:** Radix sorting internals, shader ownership, and scan-specific tests.
diff --git a/openspec/archive/2026-05-scan-module-extraction/specs/gpu-prefix-sum-module/spec.md b/openspec/archive/2026-05-scan-module-extraction/specs/gpu-prefix-sum-module/spec.md
deleted file mode 100644
index b6bf18b..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/specs/gpu-prefix-sum-module/spec.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## ADDED Requirements
-
-### Requirement: GPU prefix-sum is a standalone module
-
-The system SHALL provide GPU exclusive prefix-sum through a dedicated scan module with its own initialization, dispatch, and cleanup interface.
-
-#### Scenario: Scan module computes exclusive prefix sums
-
-- **WHEN** a caller provides input, output, and scan configuration buffers
-- **THEN** the scan module SHALL execute the GPU prefix-sum passes without requiring RadixSorter-specific knowledge
-
-#### Scenario: Scan module owns scan pipeline resources
-
-- **WHEN** the scan module is initialized or destroyed
-- **THEN** it SHALL create and clean up scan-specific pipeline and shader resources independently
diff --git a/openspec/archive/2026-05-scan-module-extraction/specs/sorting/spec.md b/openspec/archive/2026-05-scan-module-extraction/specs/sorting/spec.md
deleted file mode 100644
index e10e679..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/specs/sorting/spec.md
+++ /dev/null
@@ -1,15 +0,0 @@
-## MODIFIED Requirements
-
-### Requirement: Radix Sort Implementation
-
-The RadixSorter SHALL perform histogram and scatter passes while delegating GPU prefix-sum work to a dedicated scan module.
-
-#### Scenario: RadixSorter consumes the scan seam
-
-- **WHEN** a radix pass needs prefix sums
-- **THEN** RadixSorter SHALL invoke the standalone scan module instead of owning scan dispatch logic directly
-
-#### Scenario: Sorting behavior remains unchanged
-
-- **WHEN** valid input arrays are sorted through RadixSorter
-- **THEN** the sorter SHALL continue producing correctly sorted ascending output
diff --git a/openspec/archive/2026-05-scan-module-extraction/tasks.md b/openspec/archive/2026-05-scan-module-extraction/tasks.md
deleted file mode 100644
index ee931de..0000000
--- a/openspec/archive/2026-05-scan-module-extraction/tasks.md
+++ /dev/null
@@ -1,18 +0,0 @@
-## 1. Test-first scan seam
-
-- [x] 1.1 Add failing tests for scan-module interface and scan-specific runtime behavior
-- [x] 1.2 Add failing integration coverage for RadixSorter consuming the scan seam
-
-## 2. Implementation
-
-- [x] 2.1 Add scan module files under `src/sorting/scan/`
-- [x] 2.2 Split scan WGSL kernels from `radix.wgsl`
-- [x] 2.3 Refactor `RadixSorter` to consume the scan module
-- [x] 2.4 Update docs/specs for GPU prefix-sum ownership
-
-## 3. Validation
-
-- [x] 3.1 Run `npm run typecheck`
-- [x] 3.2 Run `npm run lint`
-- [x] 3.3 Run `npm run test`
-- [x] 3.4 Run `npm run build`
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/.openspec.yaml b/openspec/archive/2026-05-sorting-runtime-hardening/.openspec.yaml
deleted file mode 100644
index af43829..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/.openspec.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-schema: spec-driven
-created: 2026-05-21
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/design.md b/openspec/archive/2026-05-sorting-runtime-hardening/design.md
deleted file mode 100644
index 6a4776e..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/design.md
+++ /dev/null
@@ -1,71 +0,0 @@
-## Context
-
-Three runtime hot spots are coupled today:
-
-1. `Benchmark.generateRandomData()` and several browser tests call `crypto.getRandomValues()` once per array, which breaks for the repository's own 100K and 1M benchmark sizes in quota-limited browser implementations.
-2. `BitonicSorter` and `RadixSorter` each own temporary GPU buffer allocation and cleanup inline, but they do it differently. Bitonic cleanup is not fully scoped to failure paths, while Radix directly destroys buffers outside `BufferManager` ownership.
-3. `BufferManager.readBuffer()` is the readback seam for both sorters, yet it does not use the repository's existing timeout guard.
-
-This change hardens runtime behavior without relitigating algorithm choice or public sorter APIs.
-
-## Goals / Non-Goals
-
-**Goals:**
-
-- Guarantee large-array random data generation for benchmark, demo-adjacent, and browser test flows.
-- Create one deep temporary-buffer seam shared by both sorters.
-- Make readback failure modes bounded and deterministic.
-- Strengthen tests around the runtime behaviors that previously escaped coverage.
-
-**Non-Goals:**
-
-- Redesign `GPUContext` device-loss recovery in this change.
-- Change WGSL algorithm behavior or benchmark UX.
-- Introduce a general-purpose GPU buffer pool or new external dependency.
-
-## Decisions
-
-### 1. Add a shared random-data utility in `src/shared/`
-
-Create a focused utility that fills `Uint32Array` instances in quota-safe chunks and provides a convenience generator for callers that need new arrays. `Benchmark` and browser tests will consume the same seam.
-
-**Why:** Large-array randomness is a cross-cutting runtime concern, not benchmark-only behavior. One utility concentrates the browser quota rule and removes repeated inline crypto logic.
-
-**Alternatives considered:**
-
-- Patch only `Benchmark.generateRandomData()` -> rejected because browser tests would keep the same failure mode.
-- Use `Math.random()` everywhere -> rejected because it weakens existing randomness guarantees where crypto is available.
-
-### 2. Introduce a transient buffer scope for sorter-owned temporary buffers
-
-Add a small internal module that registers temporary GPU buffers, releases them exactly once in `finally`, and stays separate from explicit preallocation ownership. Both sorters will use this seam for per-sort buffers while preallocated buffers remain outside the scope.
-
-**Why:** The current modules are shallow around cleanup: each sorter repeats ownership decisions inline, so bugs hide in call sequencing instead of one interface. A transient scope increases locality and gives tests a single interface to verify.
-
-**Alternatives considered:**
-
-- Expand `BufferManager` to own every buffer in the system -> rejected because it deepens a mixed-responsibility module in the wrong direction.
-- Leave cleanup inline and add comments -> rejected because comments do not create a testable seam.
-
-### 3. Apply timeout policy at the readback seam
-
-Wrap `mapAsync()` in `BufferManager.readBuffer()` with the existing timeout utility and preserve cleanup for both success and failure paths.
-
-**Why:** Readback is where an unresponsive GPU becomes visible to CPU callers. The timeout belongs at this seam so callers do not each reinvent it.
-
-**Alternatives considered:**
-
-- Timeout at individual sorter call sites -> rejected because it duplicates policy and misses future `BufferManager` consumers.
-- No timeout, rely on device loss -> rejected because hanging promises do not surface actionable errors.
-
-### 4. Tighten tests around real runtime behavior
-
-Add unit tests for quota-safe random filling and buffer-scope cleanup, then update browser tests to use the shared random utility and call `gpu.isInitialized()` instead of asserting on a method reference.
-
-**Why:** Existing tests mostly cover pure helpers; they do not protect the runtime seams that actually failed.
-
-## Risks / Trade-offs
-
-- **More internal modules** -> Keep new seams narrowly scoped and internal-only to avoid API sprawl.
-- **Timeout values may need tuning across devices** -> Reuse existing timeout defaults first; keep the timeout wrapper centralized for later adjustment.
-- **Browser tests still depend on WebGPU availability** -> Focus new assertions on deterministic setup and data generation so skipped environments do not hide logic bugs.
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/proposal.md b/openspec/archive/2026-05-sorting-runtime-hardening/proposal.md
deleted file mode 100644
index 59c777c..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/proposal.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Change Proposal: Sorting Runtime Hardening
-
-## Why
-
-The current runtime promises large-array benchmarking and browser validation, but multiple code paths still use one-shot `crypto.getRandomValues()` calls that fail once arrays exceed browser quota limits. At the same time, temporary GPU buffer ownership is duplicated across sorters, making failure-path cleanup shallow, fragile, and hard to test.
-
-## What Changes
-
-- Add a shared quota-safe random `Uint32Array` generator and route benchmark/demo/test paths through it.
-- Introduce a dedicated transient GPU buffer seam so Bitonic and Radix sorters clean up temporary buffers through one ownership model.
-- Harden buffer readback with timeout-backed mapping and deterministic staging-buffer cleanup.
-- Tighten browser and unit tests so large-array generation and initialization assertions catch real runtime behavior instead of passing accidentally.
-
-## Capabilities
-
-### New Capabilities
-
-- None.
-
-### Modified Capabilities
-
-- `sorting`: Benchmark-driven sorting flows must support default large dataset sizes without failing because of randomness API call limits.
-- `infrastructure`: Buffer readback and sorter resource lifecycle must time out or clean up deterministically on every exit path.
-
-## Impact
-
-- **Affected code:** `src/benchmark/`, `src/shared/`, `src/core/`, `src/sorting/`, `src/index.ts`, `test/benchmark/`, `test/core/`, `test/browser/`
-- **Affected APIs:** No intentional public API expansion; internal runtime contracts become stricter and more explicit.
-- **Dependencies:** Reuses existing timeout utility and Web Crypto support; no new packages.
-- **Systems:** Browser benchmark/demo flow, GPU sorter failure handling, and runtime-facing test coverage.
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/specs/infrastructure/spec.md b/openspec/archive/2026-05-sorting-runtime-hardening/specs/infrastructure/spec.md
deleted file mode 100644
index 9571c6e..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/specs/infrastructure/spec.md
+++ /dev/null
@@ -1,39 +0,0 @@
-## MODIFIED Requirements
-
-### Requirement: GPU Buffer Management
-
-The BufferManager SHALL provide bounded readback behavior and deterministic staging-buffer cleanup for every buffer read operation.
-
-#### Scenario: Successful readback releases staging buffer
-
-- **WHEN** `readBuffer()` completes successfully
-- **THEN** it SHALL unmap the staging buffer, release it, and return a `Uint32Array` containing the requested byte range
-
-#### Scenario: Timed-out readback surfaces explicit failure
-
-- **WHEN** staging-buffer mapping exceeds the configured timeout
-- **THEN** `readBuffer()` SHALL reject with `GPUTimeoutError` and release the staging buffer before returning control to the caller
-
-#### Scenario: Readback failure still cleans up
-
-- **WHEN** staging-buffer mapping or copy fails for any other reason
-- **THEN** `readBuffer()` SHALL release the staging buffer and surface a typed buffer readback error
-
-### Requirement: Resource Lifecycle
-
-Sorter implementations SHALL release temporary GPU resources through a dedicated per-sort ownership seam while preserving explicitly preallocated buffers until callers clear or destroy them.
-
-#### Scenario: Temporary buffers are cleaned up on success
-
-- **WHEN** a sorter completes a sort using temporary buffers
-- **THEN** all temporary buffers created for that sort SHALL be released before the sorter returns
-
-#### Scenario: Temporary buffers are cleaned up on failure
-
-- **WHEN** a sorter throws after allocating temporary buffers
-- **THEN** the per-sort ownership seam SHALL still release those buffers before the error is propagated
-
-#### Scenario: Preallocated buffers remain opt-in
-
-- **WHEN** a caller uses `preallocate()` and later sorts data within that capacity
-- **THEN** the sorter SHALL reuse preallocated buffers without releasing them until `clearPreallocation()` or `destroy()` is called
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/specs/sorting/spec.md b/openspec/archive/2026-05-sorting-runtime-hardening/specs/sorting/spec.md
deleted file mode 100644
index 273aa84..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/specs/sorting/spec.md
+++ /dev/null
@@ -1,20 +0,0 @@
-## MODIFIED Requirements
-
-### Requirement: Performance Benchmarking
-
-The system SHALL benchmark JavaScript native sort, Bitonic sort, and Radix sort across supported dataset sizes without failing because benchmark input generation exceeds browser randomness API quotas.
-
-#### Scenario: Benchmark generates large default datasets
-
-- **WHEN** the benchmark generates input for configured sizes such as 100K or 1M `u32` values
-- **THEN** it SHALL fill the array in quota-safe chunks and preserve the exact requested length
-
-#### Scenario: Benchmark reports averaged timings
-
-- **WHEN** multiple iterations complete for a benchmark run
-- **THEN** the system SHALL report averaged total timing and GPU timing when the selected algorithm exposes it
-
-#### Scenario: Benchmark compares GPU runs against native sort
-
-- **WHEN** Bitonic or Radix results are reported
-- **THEN** the system SHALL include speedup data derived from the corresponding JavaScript native benchmark result
diff --git a/openspec/archive/2026-05-sorting-runtime-hardening/tasks.md b/openspec/archive/2026-05-sorting-runtime-hardening/tasks.md
deleted file mode 100644
index 64a65e1..0000000
--- a/openspec/archive/2026-05-sorting-runtime-hardening/tasks.md
+++ /dev/null
@@ -1,21 +0,0 @@
-## 1. Spec and test seam setup
-
-- [x] 1.1 Finalize delta specs for sorting benchmark input generation and infrastructure cleanup/timeout behavior
-- [x] 1.2 Add failing benchmark tests for quota-limited random generation
-- [x] 1.3 Add failing core tests for transient buffer cleanup and timed readback behavior
-
-## 2. Runtime hardening implementation
-
-- [x] 2.1 Implement a shared quota-safe random `Uint32Array` utility in `src/shared/`
-- [x] 2.2 Refactor `Benchmark` and browser tests to use the shared random utility
-- [x] 2.3 Introduce a transient GPU buffer scope and refactor both sorters to use it
-- [x] 2.4 Wrap `BufferManager.readBuffer()` with the existing timeout utility and preserve cleanup on all paths
-
-## 3. Validation and cleanup
-
-- [x] 3.1 Remove sorter non-null assertions by replacing them with explicit ownership guards
-- [x] 3.2 Fix browser initialization assertions so they invoke real APIs
-- [x] 3.3 Run `npm run lint`
-- [x] 3.4 Run `npm run typecheck`
-- [x] 3.5 Run `npm run test`
-- [x] 3.6 Run `npm run build`
diff --git a/openspec/changes/.gitkeep b/openspec/changes/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/openspec/changes/browser-e2e-testing/design.md b/openspec/changes/browser-e2e-testing/design.md
deleted file mode 100644
index a372c48..0000000
--- a/openspec/changes/browser-e2e-testing/design.md
+++ /dev/null
@@ -1,228 +0,0 @@
-# Design Document: Browser End-to-End Testing
-
-## Overview
-
-Add Playwright-based browser tests to test GPU-dependent code that cannot be tested in Node.js. This will cover the core sorting functionality, GPU context initialization, and integration scenarios.
-
-## Architecture
-
-### Current Test Structure
-
-```
-test/
-├── sorting/
-│ ├── BitonicSorter.test.ts # Pure function tests only
-│ └── RadixSorter.test.ts # Pure function tests only
-├── core/
-│ ├── GPUContext.test.ts # Mock-based tests
-│ ├── BufferManager.test.ts # Pure function tests
-│ └── Validator.test.ts # Pure function tests
-└── benchmark/
- └── Benchmark.test.ts # Pure function tests
-
-Coverage: ~60% (GPU code not tested)
-```
-
-### New Test Structure
-
-```
-test/
-├── browser/ # NEW: Browser tests
-│ ├── playwright.config.ts # Playwright configuration
-│ ├── fixtures.ts # Shared test fixtures
-│ ├── sorting.e2e.ts # GPU sorting tests
-│ ├── context.e2e.ts # GPUContext tests
-│ └── benchmark.e2e.ts # Benchmark tests
-├── sorting/ # Existing Node.js tests
-├── core/
-├── benchmark/
-└── setup.ts
-
-Coverage target: ~80%+ (with GPU code tested)
-```
-
-## Playwright Configuration
-
-### playwright.config.ts
-
-```typescript
-import { defineConfig, devices } from '@playwright/test';
-
-export default defineConfig({
- testDir: './test/browser',
- fullyParallel: true,
- forbidOnly: !!process.env.CI,
- retries: process.env.CI ? 2 : 0,
- workers: process.env.CI ? 1 : undefined,
- reporter: 'html',
- use: {
- baseURL: 'http://localhost:5173',
- trace: 'on-first-retry',
- },
- projects: [
- {
- name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
- },
- ],
- webServer: {
- command: 'npm run dev',
- url: 'http://localhost:5173',
- reuseExistingServer: !process.env.CI,
- },
-});
-```
-
-## Test Implementation
-
-### Test Fixture Pattern
-
-```typescript
-// test/browser/fixtures.ts
-import { test as base } from '@playwright/test';
-
-export const test = base.extend<{
- gpuContext: { isSupported: boolean };
-}>({
- gpuContext: async ({ page }, use) => {
- const isSupported = await page.evaluate(() => {
- return 'gpu' in navigator;
- });
- await use({ isSupported });
- },
-});
-```
-
-### Sorting Tests
-
-```typescript
-// test/browser/sorting.e2e.ts
-import { test, expect } from './fixtures';
-
-test.describe('BitonicSorter', () => {
- test('sorts small array correctly', async ({ page }) => {
- const result = await page.evaluate(async () => {
- const { GPUContext, BitonicSorter } = await import('webgpu-sorting');
-
- const gpu = new GPUContext();
- await gpu.initialize();
-
- const sorter = new BitonicSorter(gpu);
- const data = new Uint32Array([5, 2, 8, 1, 9, 3]);
- const result = await sorter.sort(data);
-
- gpu.destroy();
- return Array.from(result.sortedData);
- });
-
- expect(result).toEqual([1, 2, 3, 5, 8, 9]);
- });
-
- test('sorts 1M elements', async ({ page }) => {
- const result = await page.evaluate(async () => {
- const { GPUContext, BitonicSorter, Validator } = await import('webgpu-sorting');
-
- const gpu = new GPUContext();
- await gpu.initialize();
-
- const sorter = new BitonicSorter(gpu);
- const data = new Uint32Array(1_000_000);
- crypto.getRandomValues(data);
-
- const result = await sorter.sort(data);
-
- const validator = new Validator();
- const isValid = validator.isSorted(result.sortedData);
-
- gpu.destroy();
- return { isValid, length: result.sortedData.length };
- });
-
- expect(result.isValid).toBe(true);
- expect(result.length).toBe(1_000_000);
- });
-});
-```
-
-### Performance Tests
-
-```typescript
-// test/browser/benchmark.e2e.ts
-import { test, expect } from './fixtures';
-
-test('GPU is faster than CPU for large arrays', async ({ page }) => {
- const result = await page.evaluate(async () => {
- const { GPUContext, BitonicSorter, Benchmark } = await import('webgpu-sorting');
-
- const gpu = new GPUContext();
- await gpu.initialize();
-
- const sorter = new BitonicSorter(gpu);
- const benchmark = new Benchmark([sorter], [100_000]);
-
- const results = await benchmark.runAll();
- gpu.destroy();
-
- return results[0];
- });
-
- expect(result.speedupVsNative).toBeGreaterThan(1);
-});
-```
-
-## CI Integration
-
-### GitHub Actions Update
-
-```yaml
-# .github/workflows/test.yml
-name: Test
-
-jobs:
- node-tests:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- - run: npm ci
- - run: npm run test
-
- browser-tests:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - uses: actions/setup-node@v4
- - run: npm ci
- - run: npx playwright install --with-deps chromium
- - run: npm run test:browser
-```
-
-## Package.json Scripts
-
-```json
-{
- "scripts": {
- "test": "vitest run",
- "test:watch": "vitest",
- "test:coverage": "vitest run --coverage",
- "test:browser": "playwright test",
- "test:browser:ui": "playwright test --ui",
- "test:all": "npm run test && npm run test:browser"
- }
-}
-```
-
-## Coverage Strategy
-
-| Code Path | Test Type | Coverage |
-| ---------------------------------------- | ------------ | ---------- |
-| Pure functions (nextPowerOf2, alignSize) | Node.js unit | ✅ Current |
-| Validator methods | Node.js unit | ✅ Current |
-| GPUContext.initialize() | Browser E2E | 🆕 New |
-| BitonicSorter.sort() | Browser E2E | 🆕 New |
-| RadixSorter.sort() | Browser E2E | 🆕 New |
-| BufferManager GPU ops | Browser E2E | 🆕 New |
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/changes/browser-e2e-testing/proposal.md b/openspec/changes/browser-e2e-testing/proposal.md
deleted file mode 100644
index e978552..0000000
--- a/openspec/changes/browser-e2e-testing/proposal.md
+++ /dev/null
@@ -1,122 +0,0 @@
-# Change Proposal: Browser End-to-End Testing
-
-## Metadata
-
-| Field | Value |
-| ------------- | ------------------- |
-| **Created** | 2026-05-14 |
-| **Status** | Draft |
-| **Author** | Claude |
-| **Change ID** | browser-e2e-testing |
-
-## Intent
-
-The current test suite runs in Node.js and cannot test GPU-dependent code (BitonicSorter.sort(), RadixSorter.sort(), GPUContext.initialize()). This leaves the core sorting functionality untested. Adding Playwright-based browser tests will enable testing the actual GPU execution paths and improve test coverage.
-
-## Scope
-
-### Affected Specs
-
-- [ ] `sorting/` - Sorting algorithm specifications
-- [ ] `infrastructure/` - WebGPU infrastructure specs
-- [x] `quality/` - Quality and tooling specs (test coverage)
-- [ ] `_archived/` - Historical documents
-
-### Affected Code
-
-- [ ] `src/` - Source code (no changes needed)
-- [x] `test/` - Add browser test directory
-- [x] `package.json` - Add Playwright dependency
-- [x] `vitest.config.ts` - May need updates for browser tests
-- [x] `.github/workflows/` - Update CI for browser tests
-
-## Approach
-
-1. **Add Playwright Dependency**
-
- ```bash
- npm install -D @playwright/test
- ```
-
-2. **Create Browser Test Structure**
-
- ```
- test/
- ├── browser/
- │ ├── playwright.config.ts
- │ ├── sorting.e2e.ts # GPU sorting tests
- │ ├── context.e2e.ts # GPUContext tests
- │ └── benchmark.e2e.ts # Benchmark tests
- └── ...existing tests
- ```
-
-3. **Implement Browser Tests**
- - Test GPUContext initialization
- - Test BitonicSorter with various array sizes
- - Test RadixSorter with various array sizes
- - Test sorting correctness
- - Test error handling
-
-4. **Update CI Pipeline**
- - Add Playwright install step
- - Run browser tests in CI
-
-## Test Cases
-
-### GPUContext Tests
-
-- WebGPU support detection
-- Initialization success
-- Initialization failure handling
-- Device loss handling
-
-### BitonicSorter Tests
-
-- Sort empty array
-- Sort single element
-- Sort small array (< 256)
-- Sort medium array (4K)
-- Sort large array (1M)
-- Sort already sorted array
-- Sort reverse sorted array
-- Sort with duplicates
-
-### RadixSorter Tests
-
-- Same test cases as BitonicSorter
-- Compare results with BitonicSorter
-
-### Integration Tests
-
-- Multiple consecutive sorts
-- Sort after destroy (should fail)
-- Memory cleanup verification
-
-## Alternatives Considered
-
-1. **WebGPU polyfill for Node.js** - Experimental, not reliable
-2. **Mock GPU device** - Tests mock, not real GPU behavior
-3. **Manual browser testing only** - No CI automation
-
-## Dependencies
-
-None.
-
-## Risks
-
-| Risk | Mitigation |
-| ------------------------------------- | ------------------------------------------ |
-| CI environment may not support WebGPU | Use headed browser with GPU, or skip in CI |
-| Browser tests are slower | Run in parallel, only for PRs not commits |
-| Flaky GPU tests | Add retries, increase timeouts |
-
-## Checklist
-
-- [ ] Specs updated in `openspec/changes/browser-e2e-testing/specs/`
-- [ ] Tasks defined in `tasks.md`
-- [ ] No conflicts with existing specs
-- [x] Backward compatibility considered (additive)
-
----
-
-**Next Step**: Run `/opsx:apply` to begin implementation.
diff --git a/openspec/changes/browser-e2e-testing/tasks.md b/openspec/changes/browser-e2e-testing/tasks.md
deleted file mode 100644
index 213a838..0000000
--- a/openspec/changes/browser-e2e-testing/tasks.md
+++ /dev/null
@@ -1,112 +0,0 @@
-# Implementation Tasks: Browser End-to-End Testing
-
-## Metadata
-
-| Field | Value |
-| ------------- | ------------------- |
-| **Change ID** | browser-e2e-testing |
-| **Created** | 2026-05-14 |
-| **Status** | In Progress |
-
----
-
-## Status Legend
-
-| Symbol | Meaning |
-| ------ | ----------- |
-| [ ] | Not started |
-| [~] | In progress |
-| [x] | Completed |
-| [!] | Blocked |
-
----
-
-## Phase 1: Setup
-
-- [x] Install Playwright: `npm install -D @playwright/test`
-- [x] Create `test/browser/` directory
-- [x] Create `playwright.config.ts`
-- [x] Add test scripts to `package.json`
-- [x] Install Playwright browsers: `npx playwright install chromium`
-
-## Phase 2: Test Infrastructure
-
-- [x] Create `test/browser/fixtures.ts` for shared test utilities
-- [x] Create helper for GPU context setup/teardown
-- [x] Create helper for generating test data in browser
-- [x] Create helper for comparing results
-
-## Phase 3: GPUContext Tests
-
-- [x] Test `GPUContext.isSupported()` detection
-- [x] Test successful initialization
-- [ ] Test initialization without WebGPU (graceful failure)
-- [ ] Test `getDevice()` returns valid device
-- [ ] Test `destroy()` cleanup
-
-## Phase 4: BitonicSorter Tests
-
-- [x] Test sort empty array
-- [x] Test sort single element
-- [x] Test sort small array (6 elements)
-- [x] Test sort medium array (4K elements)
-- [ ] Test sort large array (1M elements)
-- [ ] Test sort already sorted array
-- [ ] Test sort reverse sorted array
-- [x] Test sort with duplicates
-- [ ] Test sort with all same values
-- [x] Test validate option
-
-## Phase 5: RadixSorter Tests
-
-- [x] Test sort small array
-- [x] Test sort medium array (4K elements)
-- [x] Test sort large array (100K elements)
-- [x] Test results match BitonicSorter
-- [ ] Test with various data patterns
-
-## Phase 6: Integration Tests
-
-- [x] Test preallocation (BitonicSorter)
-- [x] Test preallocation (RadixSorter)
-- [ ] Test switching between sorters
-- [ ] Test sort after destroy (error handling)
-- [ ] Test GPU memory cleanup
-
-## Phase 7: CI Integration
-
-- [ ] Update `.github/workflows/` for browser tests
-- [ ] Add Playwright browser install step
-- [ ] Configure browser tests to run in CI
-- [ ] Handle CI environments without GPU (skip tests)
-
-## Phase 8: Documentation
-
-- [ ] Update `CONTRIBUTING.md` with browser test instructions
-- [ ] Document how to run browser tests locally
-- [ ] Document CI browser test behavior
-
-## Phase 9: Verification
-
-- [x] All Node.js tests pass: `npm run test`
-- [ ] All browser tests pass: `npm run test:browser` (requires browser install)
-- [x] TypeScript compiles: `npm run typecheck`
-- [x] ESLint passes: `npm run lint`
-- [x] Build succeeds: `npm run build`
-
----
-
-## Dependencies
-
-None.
-
-## Notes
-
-- Browser tests require a display (use xvfb in CI if needed)
-- WebGPU may not be available in all CI environments
-- Consider using `test.skip()` for GPU tests when WebGPU unavailable
-- **Blocker (2026-05-22)**: System lacks `libasound.so.2` and other libraries required by Playwright's Chromium. Installing requires sudo: `npx playwright install-deps chromium`
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/changes/buffer-preallocation/design.md b/openspec/changes/buffer-preallocation/design.md
deleted file mode 100644
index 28a799d..0000000
--- a/openspec/changes/buffer-preallocation/design.md
+++ /dev/null
@@ -1,206 +0,0 @@
-# Design Document: Buffer Preallocation API
-
-## Overview
-
-Add buffer preallocation capability to BitonicSorter and RadixSorter, allowing users to allocate GPU buffers once and reuse them across multiple sorting operations. This reduces GPU resource management overhead for batch sorting workloads.
-
-## Architecture Changes
-
-### Current Buffer Lifecycle
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ Current Implementation │
-├─────────────────────────────────────────────────────────────────────┤
-│ │
-│ sort(data) { │
-│ inputBuffer = createBuffer(data.length) // Allocate │
-│ outputBuffer = createBuffer(data.length) // Allocate │
-│ // ... more buffers │
-│ // ... compute │
-│ inputBuffer.destroy() // Release │
-│ outputBuffer.destroy() // Release │
-│ // ... release others │
-│ } │
-│ │
-│ for (const arr of arrays) { │
-│ await sorter.sort(arr); // Allocate → Use → Release each time │
-│ } │
-│ │
-│ Problem: Repeated allocation overhead │
-└─────────────────────────────────────────────────────────────────────┘
-```
-
-### New Buffer Lifecycle
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ Proposed Implementation │
-├─────────────────────────────────────────────────────────────────────┤
-│ │
-│ sorter.preallocate(maxSize); // Allocate once │
-│ │
-│ for (const arr of arrays) { │
-│ await sorter.sort(arr); // Reuse preallocated buffers │
-│ } │
-│ │
-│ sorter.destroy(); // Release once │
-│ │
-│ Benefit: Eliminates allocation overhead in hot loop │
-└─────────────────────────────────────────────────────────────────────┘
-```
-
-## Buffer Requirements by Sorter
-
-### BitonicSorter
-
-| Buffer | Purpose | Size | Lifetime |
-| ------------- | ------------ | ----------------- | -------- |
-| dataBuffer | Input/Output | maxSize × 4 bytes | Per-sort |
-| uniformBuffer | Parameters | 16 bytes | Per-sort |
-| stagingBuffer | Readback | maxSize × 4 bytes | Per-sort |
-
-**Preallocation candidates**: dataBuffer only (uniform is tiny, staging is readback-specific)
-
-### RadixSorter
-
-| Buffer | Purpose | Size | Lifetime |
-| --------------- | ----------- | ------------------------- | ---------- |
-| inputBuffer | Input | maxSize × 4 bytes | Per-sort |
-| outputBuffer | Output | maxSize × 4 bytes | Per-sort |
-| histogramBuffer | Histogram | RADIX × numWorkgroups × 4 | Per-pass |
-| prefixSumBuffer | Prefix sums | Same as histogram | Per-pass |
-| uniformBuffer | Parameters | 16 bytes | Per-pass |
-| stagingBuffer | Readback | maxSize × 4 bytes | Final read |
-
-**Preallocation candidates**: inputBuffer, outputBuffer, histogramBuffer, prefixSumBuffer
-
-## Implementation Design
-
-### Class Structure
-
-```typescript
-class RadixSorter {
- private device: GPUDevice;
- private bufferManager: BufferManager;
-
- // Preallocation state
- private preallocatedBuffers: {
- input: GPUBuffer | null;
- output: GPUBuffer | null;
- histogram: GPUBuffer | null;
- prefixSum: GPUBuffer | null;
- } | null = null;
-
- private preallocatedSize: number = 0;
-
- preallocate(maxSize: number): void {
- // Release any existing preallocation
- this.clearPreallocation();
-
- const numWorkgroups = Math.ceil(maxSize / WORKGROUP_SIZE);
- const histogramSize = RADIX * numWorkgroups;
-
- this.preallocatedBuffers = {
- input: this.device.createBuffer({
- size: alignSize(maxSize * 4, 4),
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
- }),
- output: this.device.createBuffer({
- size: alignSize(maxSize * 4, 4),
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
- }),
- histogram: this.device.createBuffer({
- size: alignSize(histogramSize * 4, 4),
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
- }),
- prefixSum: this.device.createBuffer({
- size: alignSize(histogramSize * 4, 4),
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
- }),
- };
-
- this.preallocatedSize = maxSize;
- }
-
- clearPreallocation(): void {
- if (this.preallocatedBuffers) {
- this.preallocatedBuffers.input?.destroy();
- this.preallocatedBuffers.output?.destroy();
- this.preallocatedBuffers.histogram?.destroy();
- this.preallocatedBuffers.prefixSum?.destroy();
- this.preallocatedBuffers = null;
- this.preallocatedSize = 0;
- }
- }
-
- async sort(data: Uint32Array): Promise {
- const size = data.length;
-
- // Use preallocated buffers if available and large enough
- const usePreallocated = this.preallocatedBuffers && this.preallocatedSize >= size;
-
- if (usePreallocated) {
- // Write data to preallocated input buffer
- this.device.queue.writeBuffer(
- this.preallocatedBuffers!.input,
- 0,
- data.buffer,
- data.byteOffset,
- data.byteLength
- );
- // Use preallocated buffers for compute
- } else {
- // Fall back to temporary allocation
- }
- }
-
- destroy(): void {
- this.clearPreallocation();
- this.bufferManager.releaseAll();
- }
-}
-```
-
-## Memory Management
-
-### Preallocation Size Guidance
-
-```typescript
-// Example: Sorting 100 arrays of 1M elements each
-const sorter = new RadixSorter(gpu);
-sorter.preallocate(1_000_000); // ~16MB GPU memory
-
-for (let i = 0; i < 100; i++) {
- const data = generateData(1_000_000);
- const result = await sorter.sort(data);
-}
-
-sorter.destroy(); // Release all buffers
-```
-
-### Memory Overhead
-
-| Sorter | Preallocated Memory (1M elements) |
-| ------------- | ------------------------------------------ |
-| BitonicSorter | ~4MB (input buffer only) |
-| RadixSorter | ~8MB (input + output + histogram + prefix) |
-
-## Testing Strategy
-
-1. **Unit Tests**
- - Test preallocate() creates buffers
- - Test preallocatedSize property
- - Test clearPreallocation() releases buffers
- - Test sort() uses preallocated buffers
-
-2. **Property Tests**
- - Sorting with preallocation produces same results as without
- - Preallocation handles various sizes correctly
-
-3. **Performance Tests**
- - Compare batch sort time with vs without preallocation
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/changes/buffer-preallocation/proposal.md b/openspec/changes/buffer-preallocation/proposal.md
deleted file mode 100644
index 302bfbe..0000000
--- a/openspec/changes/buffer-preallocation/proposal.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Change Proposal: Buffer Preallocation API
-
-## Metadata
-
-| Field | Value |
-| ------------- | -------------------- |
-| **Created** | 2026-05-14 |
-| **Status** | Draft |
-| **Author** | Claude |
-| **Change ID** | buffer-preallocation |
-
-## Intent
-
-The documentation mentions a `preallocate(maxSize)` method that doesn't exist. For batch sorting scenarios, repeatedly allocating and releasing GPU buffers is inefficient. Implementing buffer preallocation will reduce GPU resource management overhead and improve performance for repeated sorting operations.
-
-## Scope
-
-### Affected Specs
-
-- [ ] `sorting/` - Sorting algorithm specifications
-- [ ] `infrastructure/` - WebGPU infrastructure specs
-- [x] `quality/` - Documentation already promises this feature
-- [ ] `_archived/` - Historical documents
-
-### Affected Code
-
-- [x] `src/sorting/BitonicSorter.ts` - Add preallocate() method
-- [x] `src/sorting/RadixSorter.ts` - Add preallocate() method
-- [x] `src/shared/types.ts` - Add PreallocationOptions interface
-- [ ] `src/shaders/` - WGSL compute shaders (no changes)
-- [x] `test/sorting/` - Add preallocation tests
-- [ ] `docs/api.md` - Already documented (verify accuracy)
-
-## Approach
-
-1. **Add Preallocation State to Sorters**
- - Track preallocated buffers and their capacity
- - Add `preallocatedSize` property to track current capacity
-
-2. **Implement `preallocate(size: number)` Method**
- - Allocate input/output buffers for max size
- - Allocate auxiliary buffers (histogram, prefix sum for Radix)
- - Mark buffers as preallocated for reuse
-
-3. **Modify `sort()` to Use Preallocated Buffers**
- - Check if data fits in preallocated buffers
- - Reuse if possible, otherwise allocate temporarily
- - Do not release preallocated buffers after sort
-
-4. **Implement `clearPreallocation()` Method**
- - Allow users to explicitly release preallocated buffers
-
-## API Design
-
-```typescript
-interface Sorter {
- /**
- * Preallocate GPU buffers for sorting arrays up to maxSize.
- * Reuse buffers across multiple sort() calls for better performance.
- */
- preallocate(maxSize: number): void;
-
- /**
- * Release preallocated buffers. Buffers will be allocated on-demand.
- */
- clearPreallocation(): void;
-
- /**
- * Returns the current preallocation size, or 0 if not preallocated.
- */
- readonly preallocatedSize: number;
-}
-```
-
-## Alternatives Considered
-
-1. **Auto-preallocate on first sort** - Less explicit, harder to control memory
-2. **Pool-based allocation** - More complex, overkill for this use case
-3. **Lazy resize** - Grow buffers as needed, never shrink (current de facto behavior)
-
-## Dependencies
-
-None.
-
-## Risks
-
-| Risk | Mitigation |
-| ---------------------------------------------- | ----------------------------------------- |
-| Memory leaks if users forget to call destroy() | Document clearly, track in buffer manager |
-| Preallocated buffers too small | Fall back to temporary allocation |
-| Preallocated buffers too large | Document memory implications |
-
-## Checklist
-
-- [ ] Specs updated in `openspec/changes/buffer-preallocation/specs/`
-- [ ] Tasks defined in `tasks.md`
-- [ ] No conflicts with existing specs
-- [x] Backward compatibility considered (additive API)
-
----
-
-**Next Step**: Run `/opsx:apply` to begin implementation.
diff --git a/openspec/changes/buffer-preallocation/tasks.md b/openspec/changes/buffer-preallocation/tasks.md
deleted file mode 100644
index a62d3bd..0000000
--- a/openspec/changes/buffer-preallocation/tasks.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# Implementation Tasks: Buffer Preallocation API
-
-## Metadata
-
-| Field | Value |
-| ------------- | -------------------- |
-| **Change ID** | buffer-preallocation |
-| **Created** | 2026-05-14 |
-| **Status** | In Progress |
-
----
-
-## Status Legend
-
-| Symbol | Meaning |
-| ------ | ----------- |
-| [ ] | Not started |
-| [~] | In progress |
-| [x] | Completed |
-| [!] | Blocked |
-
----
-
-## Phase 1: BitonicSorter Implementation
-
-- [x] Add `preallocatedBuffers` state to BitonicSorter
-- [x] Implement `preallocate(maxSize: number): void`
-- [x] Implement `clearPreallocation(): void`
-- [x] Add `preallocatedSize` readonly property
-- [x] Modify `sort()` to use preallocated buffers when available
-- [x] Handle case when data > preallocatedSize
-
-## Phase 2: RadixSorter Implementation
-
-- [x] Add `preallocatedBuffers` state to RadixSorter
-- [x] Implement `preallocate(maxSize: number): void`
-- [x] Implement `clearPreallocation(): void`
-- [x] Add `preallocatedSize` readonly property
-- [x] Modify `sort()` to use preallocated buffers when available
-- [x] Handle histogram buffer sizing based on preallocatedSize
-
-## Phase 3: Type Definitions
-
-- [x] Add PreallocationOptions interface to types.ts (if needed) - not needed, API is simple
-- [x] Update JSDoc comments for new methods
-- [x] Ensure TypeScript strict mode compatibility
-
-## Phase 4: Testing
-
-- [x] Add unit tests for BitonicSorter.preallocate()
-- [x] Add unit tests for RadixSorter.preallocate()
-- [x] Test sort correctness with preallocated buffers - requires browser
-- [x] Test fallback when data > preallocatedSize - implemented in code
-- [x] Test clearPreallocation() releases buffers - implemented in code
-- [x] Run full test suite: `npm run test`
-
-## Phase 5: Documentation
-
-- [x] Verify docs/api.md matches implementation
-- [x] Update docs/performance.md with preallocation guidance - already has guidance
-- [x] Add code examples to documentation
-- [ ] Update Chinese translations if applicable
-
-## Phase 6: Verification
-
-- [x] All tests pass: `npm run test`
-- [x] TypeScript compiles: `npm run typecheck`
-- [x] ESLint passes: `npm run lint` (warnings only for non-null assertions)
-- [x] Build succeeds: `npm run build`
-- [ ] Manual browser testing completed
-
----
-
-## Dependencies
-
-None.
-
-## Notes
-
-- Start with RadixSorter as it has more buffers to manage
-- BitonicSorter has simpler buffer requirements
-- Consider adding debug logging for preallocation state
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/changes/gpu-prefix-sum/design.md b/openspec/changes/gpu-prefix-sum/design.md
deleted file mode 100644
index c811ab8..0000000
--- a/openspec/changes/gpu-prefix-sum/design.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# Design Document: GPU-Based Prefix Sum
-
-## Overview
-
-Implement Blelloch scan (work-efficient parallel prefix sum) in WGSL to eliminate CPU↔GPU data transfers during Radix Sort. The current implementation reads histograms back to CPU, computes prefix sums sequentially, and writes them back to GPU — 8 times per sort operation.
-
-## Architecture Changes
-
-### Current Architecture
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ RadixSorter (Current) │
-├─────────────────────────────────────────────────────────────────────┤
-│ │
-│ for each pass (8 passes): │
-│ 1. GPU: compute_histogram() │
-│ 2. GPU→CPU: read histogram buffer │
-│ 3. CPU: sequential prefix sum O(n) │
-│ 4. CPU→GPU: write prefix sum buffer │
-│ 5. GPU: scatter() │
-│ │
-│ Bottleneck: 8 × (GPU→CPU + CPU→GPU) transfers │
-└─────────────────────────────────────────────────────────────────────┘
-```
-
-### New Architecture
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ RadixSorter (Optimized) │
-├─────────────────────────────────────────────────────────────────────┤
-│ │
-│ for each pass (8 passes): │
-│ 1. GPU: compute_histogram() │
-│ 2. GPU: blelloch_scan() ← NEW │
-│ 3. GPU: scatter() │
-│ │
-│ No CPU↔GPU transfers during sort │
-└─────────────────────────────────────────────────────────────────────┘
-```
-
-## Blelloch Scan Algorithm
-
-### Work-Efficient Parallel Prefix Sum
-
-```
-Input: [3, 1, 7, 0, 4, 1, 6, 3]
-Output (exclusive): [0, 3, 4, 11, 11, 15, 16, 22]
-
-Phase 1: Up-sweep (Reduce)
-┌───────────────────────────────────────────────────────────────┐
-│ [3, 1, 7, 0, 4, 1, 6, 3] │
-│ ↓ │
-│ [3, 4, 7, 7, 4, 5, 6, 9] // pairwise sum │
-│ ↓ │
-│ [3, 4, 7, 11, 4, 5, 6, 14] // stride = 4 │
-│ ↓ │
-│ [3, 4, 7, 11, 4, 5, 6, 25] // stride = 8 (total sum) │
-└───────────────────────────────────────────────────────────────┘
-
-Phase 2: Down-sweep (Distribute)
-┌───────────────────────────────────────────────────────────────┐
-│ [3, 4, 7, 11, 4, 5, 6, 0] // set last to 0 │
-│ ↓ │
-│ [3, 4, 7, 4, 4, 5, 11, 14] // stride = 4 │
-│ ↓ │
-│ [3, 0, 7, 4, 4, 3, 11, 9] // stride = 2 │
-│ ↓ │
-│ [0, 3, 4, 11, 11, 15, 16, 22] // stride = 1 (exclusive scan) │
-└───────────────────────────────────────────────────────────────┘
-```
-
-## WGSL Implementation
-
-### Shader Structure
-
-```wgsl
-// New shader in radix.wgsl
-
-var shared_data: array; // For workgroup scan
-var block_sums: array; // For multi-block scan
-
-@compute @workgroup_size(WORKGROUP_SIZE)
-fn blelloch_scan(
- @builtin(global_invocation_id) global_id: vec3,
- @builtin(local_invocation_id) local_id: vec3,
- @builtin(workgroup_id) workgroup_id: vec3
-) {
- // Load data to shared memory
- // Up-sweep phase
- // Down-sweep phase
- // Write results
-}
-```
-
-### Multi-Block Handling
-
-For histograms larger than a single workgroup can handle:
-
-```
-┌─────────────────────────────────────────────────────────────────────┐
-│ Two-Level Scan │
-├─────────────────────────────────────────────────────────────────────┤
-│ │
-│ Level 1: Local scans within each workgroup │
-│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
-│ │ WG0 │ │ WG1 │ │ WG2 │ │ WG3 │ │
-│ │scan │ │scan │ │scan │ │scan │ │
-│ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │
-│ │ │ │ │ │
-│ ▼ ▼ ▼ ▼ │
-│ [local] [local] [local] [local] │
-│ │
-│ Level 2: Scan of block sums │
-│ [sum0, sum1, sum2, sum3] → [0, sum0, sum0+sum1, ...] │
-│ │
-│ Level 3: Add block prefix to each workgroup's results │
-│ │
-└─────────────────────────────────────────────────────────────────────┘
-```
-
-## API Changes
-
-No public API changes. The optimization is internal to RadixSorter.
-
-## Performance Considerations
-
-| Array Size | Current (CPU) | Optimized (GPU) | Speedup |
-| ---------- | ------------- | --------------- | ------- |
-| 65K | ~0.5ms/pass | ~0.05ms/pass | 10x |
-| 1M | ~2ms/pass | ~0.1ms/pass | 20x |
-| 16M | ~30ms/pass | ~0.5ms/pass | 60x |
-
-## Testing Strategy
-
-1. **Unit Tests**: Test Blelloch scan correctness with known inputs
-2. **Property Tests**: Verify prefix sum properties (monotonic, correct sum)
-3. **Integration Tests**: Full Radix Sort with GPU prefix sum
-4. **Benchmark Tests**: Compare CPU vs GPU prefix sum performance
-
-## Rollback Plan
-
-If GPU prefix sum causes issues:
-
-1. Revert to CPU prefix sum (keep code as fallback)
-2. Add feature flag: `useGPUPrefixSum: boolean` in constructor options
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/changes/gpu-prefix-sum/proposal.md b/openspec/changes/gpu-prefix-sum/proposal.md
deleted file mode 100644
index 198c42a..0000000
--- a/openspec/changes/gpu-prefix-sum/proposal.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# Change Proposal: GPU-Based Prefix Sum for Radix Sort
-
-## Metadata
-
-| Field | Value |
-| ------------- | -------------- |
-| **Created** | 2026-05-14 |
-| **Status** | Draft |
-| **Author** | Claude |
-| **Change ID** | gpu-prefix-sum |
-
-## Intent
-
-The current RadixSorter implementation computes prefix sums on the CPU, requiring GPU→CPU→GPU data transfers for each of the 8 passes. This creates a significant performance bottleneck for large arrays. Implementing Blelloch scan (work-efficient parallel prefix sum) on the GPU will eliminate these transfers and improve sorting performance by an estimated 2-5x for large datasets.
-
-## Scope
-
-### Affected Specs
-
-- [x] `sorting/` - Sorting algorithm specifications (may need update)
-- [ ] `infrastructure/` - WebGPU infrastructure specs
-- [ ] `quality/` - Quality and tooling specs
-- [ ] `_archived/` - Historical documents
-
-### Affected Code
-
-- [x] `src/sorting/RadixSorter.ts` - Add Blelloch scan pipeline
-- [x] `src/shaders/radix.wgsl` - Add Blelloch scan compute shader
-- [x] `src/shared/constants.ts` - May need new constants
-- [ ] `src/core/` - Core WebGPU infrastructure
-- [ ] `src/benchmark/` - Benchmark utilities
-- [x] `test/sorting/RadixSorter.test.ts` - Add prefix sum tests
-
-## Approach
-
-1. **Implement Blelloch Scan WGSL Shader**
- - Up-sweep (reduce) phase: compute local prefix sums within workgroups
- - Down-sweep (distribute) phase: distribute results across workgroups
- - Handle arbitrary histogram sizes (RADIX × numWorkgroups)
-
-2. **Add Blelloch Pipeline to RadixSorter**
- - Create new compute pipeline for prefix sum
- - Replace CPU `computePrefixSum()` with GPU dispatch
- - Remove staging buffer readback for histogram
-
-3. **Optimize Memory Layout**
- - Consider using two-phase approach for large histograms
- - Leverage shared memory for intra-workgroup scans
-
-## Alternatives Considered
-
-1. **Keep CPU prefix sum** - Simple but limits performance
-2. **Hillis-Steele scan** - More parallel steps, less work-efficient
-3. **Two-level Blelloch** - Better for very large histograms (future optimization)
-
-## Dependencies
-
-- None. This is a standalone optimization.
-
-## Risks
-
-| Risk | Mitigation |
-| ---------------------------------- | ------------------------------------------------------ |
-| Blelloch implementation complexity | Start with reference implementation, test thoroughly |
-| Workgroup size limits | Handle edge cases where histogram > max workgroup size |
-| Numerical precision | Use u32 arithmetic (no precision issues for counts) |
-
-## Checklist
-
-- [ ] Specs updated in `openspec/changes/gpu-prefix-sum/specs/`
-- [ ] Tasks defined in `tasks.md`
-- [ ] No conflicts with existing specs
-- [x] Backward compatibility considered (API unchanged)
-
----
-
-**Next Step**: Run `/opsx:apply` to begin implementation.
diff --git a/openspec/changes/gpu-prefix-sum/tasks.md b/openspec/changes/gpu-prefix-sum/tasks.md
deleted file mode 100644
index 44f6170..0000000
--- a/openspec/changes/gpu-prefix-sum/tasks.md
+++ /dev/null
@@ -1,86 +0,0 @@
-# Implementation Tasks: GPU-Based Prefix Sum
-
-## Metadata
-
-| Field | Value |
-| ------------- | -------------- |
-| **Change ID** | gpu-prefix-sum |
-| **Created** | 2026-05-14 |
-| **Status** | In Progress |
-
----
-
-## Status Legend
-
-| Symbol | Meaning |
-| ------ | ----------- |
-| [ ] | Not started |
-| [~] | In progress |
-| [x] | Completed |
-| [!] | Blocked |
-
----
-
-## Phase 1: WGSL Shader Implementation
-
-- [x] Implement Blelloch up-sweep (reduce) phase in `radix.wgsl`
-- [x] Implement Blelloch down-sweep (distribute) phase in `radix.wgsl`
-- [x] Add `blelloch_scan` entry point to shader
-- [x] Handle multi-block scans (histogram > WORKGROUP_SIZE)
-- [x] Add shared memory barriers for correctness
-- [x] Test shader compilation
-
-## Phase 2: TypeScript Integration
-
-- [x] Add `blellochPipeline` to RadixSorter class
-- [x] Create bind group layout for prefix sum shader
-- [x] Implement `computePrefixSumGPU()` method
-- [x] Replace CPU `computePrefixSum()` call with GPU dispatch
-- [x] Remove staging buffer readback for histogram
-- [x] Update buffer management for new shader
-
-## Phase 3: Edge Cases
-
-- [x] Handle histogram size not power of 2
-- [x] Handle histogram size < WORKGROUP_SIZE
-- [x] Handle single workgroup case (no multi-block needed)
-- [x] Verify correctness with various histogram sizes
-
-## Phase 4: Testing
-
-- [x] Add unit tests for Blelloch scan algorithm (pure TS reference)
-- [x] Add property-based tests for prefix sum correctness
-- [ ] Add integration tests for full Radix Sort with GPU prefix sum (requires browser)
-- [x] Run existing tests: `npm run test`
-- [x] Verify coverage meets thresholds
-
-## Phase 5: Documentation
-
-- [x] Update JSDoc comments in RadixSorter
-- [x] Update `docs/algorithm-radix.md` with GPU prefix sum explanation
-- [ ] Update `docs/performance.md` with new benchmarks (requires browser testing)
-- [ ] Update Chinese translations if applicable
-
-## Phase 6: Verification
-
-- [x] All tests pass: `npm run test`
-- [x] TypeScript compiles: `npm run typecheck`
-- [x] ESLint passes: `npm run lint`
-- [x] Build succeeds: `npm run build`
-- [ ] Manual browser testing completed
-
----
-
-## Dependencies
-
-None.
-
-## Notes
-
-- Blelloch scan is work-efficient: O(n) work vs O(n log n) for Hillis-Steele
-- May need two-level scan for very large histograms (> 256 elements)
-- Consider keeping CPU fallback for edge cases or debugging
-
----
-
-**Created**: 2026-05-14
diff --git a/openspec/config.yaml b/openspec/config.yaml
deleted file mode 100644
index a0a1182..0000000
--- a/openspec/config.yaml
+++ /dev/null
@@ -1,81 +0,0 @@
-# OpenSpec Configuration for WebGPU Sorting Project
-# Generated: 2026-04-23
-
-project:
- name: webgpu-sorting
- version: 1.0.1
- description: High-performance GPU-accelerated sorting library using WebGPU compute shaders
-
- repository:
- type: git
- url: https://github.com/LessUp/webgpu-sorting
- branch: master
-
- tech_stack:
- language: TypeScript
- version: '5.3+'
- frameworks:
- - WebGPU
- - WGSL
- build_tool: Vite
- test_framework: Vitest
- package_manager: npm
-
-specs:
- root: openspec/specs
-
- domains:
- - name: sorting
- description: Core sorting algorithms (Bitonic, Radix, Benchmark, Validation)
- owners: []
-
- - name: infrastructure
- description: WebGPU context and buffer management
- owners: []
-
- - name: quality
- description: CI/CD, code quality, and project metadata
- owners: []
-
- naming:
- spec_files: kebab-case.md
- change_dirs: kebab-case
- max_title_length: 60
-
-changes:
- root: openspec/changes
- archive_root: openspec/archive
-
- required_artifacts:
- - proposal.md
- - tasks.md
-
- optional_artifacts:
- - design.md
- - specs/
-
-workflow:
- auto_generate_tasks: true
- require_spec_review: true
- archive_timestamp_format: '%Y%m%d-%H%M%S'
-
-validation:
- require_change_markers: true
- trace_to_code: false
-
-templates:
- proposal: .templates/proposal.md
- design: .templates/design.md
- tasks: .templates/tasks.md
- spec: .templates/spec.md
-
-docs:
- languages:
- - en
- - zh
- translation_suffix: '.zh.md'
- auto_generate: false
-
-integration:
- agents_file: AGENTS.md
- contributing_file: CONTRIBUTING.md
diff --git a/openspec/specs/_archived/README.md b/openspec/specs/_archived/README.md
deleted file mode 100644
index 9980348..0000000
--- a/openspec/specs/_archived/README.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# Archived Specifications
-
-Historical design documents and superseded specifications. These documents are preserved for reference but are no longer actively maintained.
-
-> 归档规范 - 历史设计文档和已废弃的规范。这些文档保留供参考,但不再主动维护。
-
-## Documents
-
-| Document | Original Status | Description |
-| ---------------------------------------------------- | --------------- | ------------------------------------------------- |
-| [core-architecture-v1.md](./core-architecture-v1.md) | Accepted | Core architecture design (migrated from RFC 0001) |
-
-## Purpose
-
-The `_archived` domain serves as:
-
-1. **Historical Reference** - Preserving design decisions and their rationale
-2. **Documentation Context** - Understanding how the system evolved
-3. **Onboarding Material** - Helping new contributors understand the architecture
-
-## When to Archive
-
-Documents should be moved here when:
-
-- An RFC has been fully implemented and the design is stable
-- A specification has been superseded by a newer version
-- A feature has been deprecated or removed
-
-## Related
-
-- Active specifications: [../sorting/](../sorting/), [../quality/](../quality/)
diff --git a/openspec/specs/_archived/core-architecture-v1.md b/openspec/specs/_archived/core-architecture-v1.md
deleted file mode 100644
index 82958cb..0000000
--- a/openspec/specs/_archived/core-architecture-v1.md
+++ /dev/null
@@ -1,523 +0,0 @@
-# RFC 0001: WebGPU Sorting Architecture
-
-## Status
-
-- **Status**: Accepted
-- **Created**: 2026-03-22
-- **Authors**: WebGPU Sorting Team
-
-## Overview
-
-This RFC describes the technical architecture for the WebGPU-based high-performance GPU sorting implementation, including Bitonic Sort and Radix Sort algorithms, along with a complete benchmarking and validation framework.
-
-### Technology Stack
-
-- **Runtime**: Modern browsers (Chrome 113+, Edge 113+, Firefox Nightly)
-- **GPU API**: WebGPU
-- **Shader Language**: WGSL (WebGPU Shading Language)
-- **Frontend Framework**: Vanilla HTML/CSS/TypeScript
-- **Build Tool**: Vite
-
-## Architecture
-
-```
-┌─────────────────────────────────────────────────────────────┐
-│ Demo UI Layer │
-│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
-│ │ Controls │ │ Progress │ │ Results Display │ │
-│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ Sorting API Layer │
-│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
-│ │ BitonicSorter │ │ RadixSorter │ │ Benchmark │ │
-│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ WebGPU Core Layer │
-│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
-│ │ GPUContext │ │ BufferManager │ │ ShaderLoader│ │
-│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
-└─────────────────────────────────────────────────────────────┘
- │
- ▼
-┌─────────────────────────────────────────────────────────────┐
-│ WGSL Compute Shaders │
-│ ┌─────────────────┐ ┌─────────────────┐ │
-│ │ bitonic.wgsl │ │ radix.wgsl │ │
-│ └─────────────────┘ └─────────────────┘ │
-└─────────────────────────────────────────────────────────────┘
-```
-
-### Data Flow
-
-```
-Input Array (CPU)
- │
- ▼
-┌──────────────────┐
-│ Upload to GPU │ ← writeBuffer()
-│ (Storage Buffer) │
-└──────────────────┘
- │
- ▼
-┌──────────────────┐
-│ GPU Sorting │ ← Compute Shader Dispatches
-│ (Multiple Passes)│
-└──────────────────┘
- │
- ▼
-┌──────────────────┐
-│ Download to CPU │ ← mapAsync() + copyBufferToBuffer()
-│ (Staging Buffer) │
-└──────────────────┘
- │
- ▼
-Sorted Array (CPU)
-```
-
-## Components and Interfaces
-
-### GPUContext
-
-Responsible for WebGPU environment initialization and resource management.
-
-```typescript
-interface GPUContextConfig {
- powerPreference?: 'low-power' | 'high-performance';
-}
-
-class GPUContext {
- private adapter: GPUAdapter | null;
- private device: GPUDevice | null;
-
- // Initialize WebGPU environment
- async initialize(config?: GPUContextConfig): Promise;
-
- // Get GPU device
- getDevice(): GPUDevice;
-
- // Check if WebGPU is supported
- static isSupported(): boolean;
-
- // Release resources
- destroy(): void;
-}
-```
-
-### BufferManager
-
-Manages GPU buffer creation, data transfer, and destruction.
-
-```typescript
-class BufferManager {
- constructor(device: GPUDevice);
-
- // Create storage buffer and upload data
- createStorageBuffer(data: Uint32Array, label?: string): GPUBuffer;
-
- // Create staging buffer for reading
- createStagingBuffer(size: number): GPUBuffer;
-
- // Read data from GPU
- async readBuffer(buffer: GPUBuffer, size: number): Promise;
-
- // Release buffer
- releaseBuffer(buffer: GPUBuffer): void;
-
- // Calculate aligned buffer size
- static alignSize(size: number, alignment: number): number;
-}
-```
-
-### BitonicSorter
-
-Implements the bitonic sort algorithm.
-
-```typescript
-interface SortResult {
- sortedData: Uint32Array;
- gpuTimeMs: number; // Pure GPU computation time
- totalTimeMs: number; // Total time including data transfer
-}
-
-class BitonicSorter {
- constructor(context: GPUContext);
-
- // Execute sort
- async sort(data: Uint32Array): Promise;
-
- // Release resources
- destroy(): void;
-}
-```
-
-### RadixSorter
-
-Implements the radix sort algorithm.
-
-```typescript
-class RadixSorter {
- constructor(context: GPUContext);
-
- // Execute sort
- async sort(data: Uint32Array): Promise;
-
- // Release resources
- destroy(): void;
-}
-```
-
-### Benchmark
-
-Performance benchmarking utility.
-
-```typescript
-interface BenchmarkResult {
- algorithm: 'bitonic' | 'radix' | 'js-native';
- arraySize: number;
- gpuTimeMs?: number;
- totalTimeMs: number;
- speedupVsNative?: number;
- iterations: number;
-}
-
-class Benchmark {
- constructor(context: GPUContext);
-
- // Run complete benchmark suite
- async runAll(sizes: number[]): Promise;
-
- // Run single test
- async runSingle(
- algorithm: 'bitonic' | 'radix' | 'js-native',
- size: number,
- iterations: number
- ): Promise;
-}
-```
-
-### Validator
-
-Sorting result validation utility.
-
-```typescript
-interface ValidationResult {
- isValid: boolean;
- isSorted: boolean;
- hasAllElements: boolean;
- errors: string[];
-}
-
-class Validator {
- // Verify array is sorted
- static isSorted(arr: Uint32Array): boolean;
-
- // Verify two arrays contain same elements
- static hasSameElements(a: Uint32Array, b: Uint32Array): boolean;
-
- // Complete validation
- static validate(input: Uint32Array, output: Uint32Array): ValidationResult;
-}
-```
-
-## Data Models
-
-### GPU Buffer Layout
-
-```typescript
-// Buffers used by bitonic sort
-interface BitonicBuffers {
- data: GPUBuffer; // Main data buffer (read-write storage)
- staging: GPUBuffer; // Staging buffer for reading (map-read)
-}
-
-// Buffers used by radix sort
-interface RadixBuffers {
- input: GPUBuffer; // Input data
- output: GPUBuffer; // Output data
- histogram: GPUBuffer; // Histogram buffer
- prefixSum: GPUBuffer; // Prefix sum buffer
- staging: GPUBuffer; // Staging buffer for reading
-}
-```
-
-### Uniform Data Structures
-
-```typescript
-// Bitonic sort uniforms
-interface BitonicUniforms {
- stageSize: number; // Current stage size
- passSize: number; // Current pass size
- totalSize: number; // Total array size
-}
-
-// Radix sort uniforms
-interface RadixUniforms {
- bitOffset: number; // Current bit offset being processed
- totalSize: number; // Total array size
-}
-```
-
-## Algorithm Details
-
-### Bitonic Sort
-
-Bitonic sort is a comparison sorting algorithm suitable for parallel implementation, with time complexity O(n log²n).
-
-```
-Stages: log₂(n) stages
-Passes per Stage: stage number of passes
-
-Example (n=8):
-Stage 1: Form bitonic sequences of length 2
-Stage 2: Form bitonic sequences of length 4
-Stage 3: Form bitonic sequences of length 8 (final sorted)
-
-In each pass, threads execute compare-swap operations in parallel
-```
-
-#### WGSL Shader Design
-
-```wgsl
-// bitonic.wgsl
-struct Uniforms {
- stage_size: u32,
- pass_size: u32,
- total_size: u32,
-}
-
-@group(0) @binding(0) var data: array;
-@group(0) @binding(1) var uniforms: Uniforms;
-
-// Workgroup size
-const WORKGROUP_SIZE: u32 = 256;
-
-// Shared memory for fast intra-workgroup exchange
-var shared_data: array;
-
-@compute @workgroup_size(WORKGROUP_SIZE)
-fn bitonic_sort_local(
- @builtin(global_invocation_id) global_id: vec3,
- @builtin(local_invocation_id) local_id: vec3,
- @builtin(workgroup_id) workgroup_id: vec3
-) {
- let idx = global_id.x;
-
- // Load data to shared memory
- if (idx < uniforms.total_size) {
- shared_data[local_id.x] = data[idx];
- }
-
- workgroupBarrier();
-
- // Bitonic sort within workgroup
- for (var stage: u32 = 1u; stage <= log2(WORKGROUP_SIZE); stage++) {
- for (var pass: u32 = stage; pass >= 1u; pass--) {
- let pair_distance = 1u << (pass - 1u);
- let block_size = 1u << stage;
-
- let pos = local_id.x;
- let partner = pos ^ pair_distance;
-
- if (partner > pos) {
- let dir = ((pos / block_size) % 2u) == 0u;
- compare_and_swap(pos, partner, dir);
- }
-
- workgroupBarrier();
- }
- }
-
- // Write back to global memory
- if (idx < uniforms.total_size) {
- data[idx] = shared_data[local_id.x];
- }
-}
-
-fn compare_and_swap(i: u32, j: u32, ascending: bool) {
- let a = shared_data[i];
- let b = shared_data[j];
-
- if ((a > b) == ascending) {
- shared_data[i] = b;
- shared_data[j] = a;
- }
-}
-```
-
-### Radix Sort
-
-Radix sort is a non-comparison sorting algorithm with time complexity O(n \* k), where k is the number of bits.
-
-```
-For 32-bit integers, using 4-bit radix (radix-16):
-- 8 passes, each processing 4 bits
-- Each pass: compute histogram → prefix sum → rearrange data
-
-Parallel Strategy:
-1. Histogram computation: parallel reduction
-2. Prefix sum: computed on CPU (simplified implementation)
-3. Data rearrangement: parallel scatter
-```
-
-Note: Prefix sum is implemented in TypeScript, not using a separate scan.wgsl shader.
-
-## Correctness Properties
-
-_A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees._
-
-### Property 1: Buffer Round-Trip Consistency
-
-_For any_ valid Uint32Array, uploading it to a GPU buffer and then downloading it back SHALL produce an identical array.
-
-**Validates: Requirements 2.2, 2.3**
-
-### Property 2: Buffer Size Alignment
-
-_For any_ input size and alignment value, the aligned buffer size SHALL be greater than or equal to the input size AND divisible by the alignment value.
-
-**Validates: Requirements 2.5**
-
-### Property 3: Bitonic Padding to Power of 2
-
-_For any_ input array size that is not a power of 2, the padded size SHALL be the smallest power of 2 greater than or equal to the input size.
-
-**Validates: Requirements 3.4**
-
-### Property 4: Bitonic Sort Correctness
-
-_For any_ valid Uint32Array input, the Bitonic_Sorter output SHALL satisfy:
-
-1. The output array is in ascending order (each element ≤ next element)
-2. The output array contains exactly the same elements as the input array (same multiset)
-
-**Validates: Requirements 3.5**
-
-### Property 5: Radix Sort Correctness
-
-_For any_ valid Uint32Array input, the Radix_Sorter output SHALL satisfy:
-
-1. The output array is in ascending order (each element ≤ next element)
-2. The output array contains exactly the same elements as the input array (same multiset)
-
-**Validates: Requirements 4.5**
-
-### Property 6: Speedup Calculation Correctness
-
-_For any_ benchmark result with CPU time and GPU time, the speedup ratio SHALL equal CPU time divided by GPU time.
-
-**Validates: Requirements 5.3**
-
-### Property 7: Average Time Calculation
-
-_For any_ set of timing measurements, the reported average time SHALL equal the sum of all measurements divided by the count of measurements.
-
-**Validates: Requirements 5.6**
-
-### Property 8: isSorted Validator Correctness
-
-_For any_ array, the isSorted function SHALL return true if and only if every element is less than or equal to its successor.
-
-**Validates: Requirements 6.1**
-
-### Property 9: hasSameElements Validator Correctness
-
-_For any_ two arrays, the hasSameElements function SHALL return true if and only if both arrays contain the same elements with the same frequencies (identical multisets).
-
-**Validates: Requirements 6.2**
-
-## Error Handling
-
-### WebGPU Initialization Errors
-
-| Error Scenario | Handling Approach |
-| ------------------------------ | -------------------------------------------------------------- |
-| Browser doesn't support WebGPU | Throw `WebGPUNotSupportedError`, UI shows compatibility notice |
-| Cannot obtain GPU adapter | Throw `GPUAdapterError`,提示 check GPU drivers |
-| Device request fails | Throw `GPUDeviceError`,提示 possible resource limits |
-
-### Buffer Errors
-
-| Error Scenario | Handling Approach |
-| ------------------------------ | ------------------------------------------------------ |
-| Array too large for GPU memory | Throw `BufferAllocationError`,提示 reduce array size |
-| Buffer mapping fails | Retry once, then throw `BufferMapError` if fails again |
-
-### Sorting Errors
-
-| Error Scenario | Handling Approach |
-| ------------------------ | ------------------------------------------------------- |
-| Shader compilation fails | Throw `ShaderCompilationError` with detailed error info |
-| GPU execution timeout | Throw `GPUTimeoutError`,提示 reduce array size |
-
-## Testing Strategy
-
-### Unit Tests
-
-Using Vitest for unit tests, covering:
-
-1. **GPUContext Tests**
- - Initialization success scenarios
- - WebGPU not supported scenarios (mocked)
- - Resource release
-
-2. **BufferManager Tests**
- - Small array upload/download
- - Edge cases (empty array, single element)
- - Alignment calculation
-
-3. **Validator Tests**
- - Sorted array detection
- - Unsorted array detection
- - Element comparison
-
-### Property-Based Tests
-
-Using fast-check for property testing, minimum 100 iterations per property:
-
-1. **Property 1**: Generate random Uint32Array, verify GPU round-trip consistency
-2. **Property 2**: Generate random sizes and alignment values, verify alignment calculation
-3. **Property 3**: Generate random sizes, verify padding to power of 2
-4. **Property 4**: Generate random arrays, verify bitonic sort correctness
-5. **Property 5**: Generate random arrays, verify radix sort correctness
-6. **Property 6**: Generate random time pairs, verify speedup ratio calculation
-7. **Property 7**: Generate random time arrays, verify average calculation
-8. **Property 8**: Generate random arrays, verify isSorted correctness
-9. **Property 9**: Generate random array pairs, verify hasSameElements correctness
-
-### Integration Tests
-
-1. **End-to-End Sorting Tests**
- - Small arrays (< 256 elements)
- - Medium arrays (1K - 10K elements)
- - Large arrays (100K - 1M elements)
-
-2. **Performance Regression Tests**
- - Ensure GPU sorting is faster than CPU (for large arrays)
-
-### Test Configuration
-
-```typescript
-// vitest.config.ts
-export default defineConfig({
- test: {
- environment: 'jsdom',
- setupFiles: ['./test/setup.ts'],
- testTimeout: 30000, // GPU operations may be slower
- },
-});
-```
-
-### Property Test Annotation Format
-
-Each property test must include the following comment:
-
-```typescript
-// Feature: webgpu-sorting, Property 4: Bitonic Sort Correctness
-// Validates: Requirements 3.5
-```
diff --git a/openspec/specs/infrastructure/README.md b/openspec/specs/infrastructure/README.md
deleted file mode 100644
index b1bcf08..0000000
--- a/openspec/specs/infrastructure/README.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Infrastructure Domain
-
-WebGPU infrastructure specifications including GPU context management, buffer handling, and error handling.
-
-> 基础设施域 - WebGPU 基础设施规范,包括 GPU 上下文管理、缓冲区处理和错误处理。
-
-## Status
-
-This domain is reserved for future specifications. Current implementation is documented in:
-
-- [Core Architecture (Archived)](../_archived/core-architecture-v1.md)
-
-## Components
-
-- **GPUContext** - WebGPU initialization and lifecycle
-- **BufferManager** - GPU buffer creation and data transfer
-- **Error Handling** - Custom error classes for WebGPU operations
-
-## Related Domains
-
-- [../sorting/](../sorting/) - Core sorting algorithms
-- [../quality/](../quality/) - CI/CD and code quality standards
diff --git a/openspec/specs/infrastructure/gpu-context.md b/openspec/specs/infrastructure/gpu-context.md
deleted file mode 100644
index 85b180a..0000000
--- a/openspec/specs/infrastructure/gpu-context.md
+++ /dev/null
@@ -1,93 +0,0 @@
-# Product Spec: Infrastructure
-
-## Introduction
-
-This spec defines the core infrastructure components for the WebGPU Sorting project: GPUContext, BufferManager, Validator, and error handling utilities. These components provide the foundation for GPU compute operations.
-
-## Glossary
-
-- **GPUContext**: Manages WebGPU adapter and device initialization
-- **BufferManager**: Handles GPU buffer creation, data transfer, and lifecycle
-- **Validator**: Verifies sorting correctness and array equality
-- **Error Classes**: Custom error types for specific GPU-related failures
-- **Timeout Utility**: Wraps GPU operations with configurable timeouts
-
-## Requirements
-
-### Requirement 1: GPU Context Initialization
-
-**User Story:** As a developer, I want to initialize the WebGPU environment with proper device limits and error handling.
-
-#### Acceptance Criteria
-
-1. WHEN `initialize()` is called, THE GPUContext SHALL request a GPU adapter with high-performance preference
-2. IF WebGPU is not supported, THE GPUContext SHALL throw `WebGPUNotSupportedError`
-3. IF no adapter is available, THE GPUContext SHALL throw `GPUAdapterError`
-4. IF device request fails, THE GPUContext SHALL throw `GPUDeviceError`
-5. THE GPUContext SHALL query adapter limits and request reasonable device limits
-6. THE GPUContext SHALL store limits info for downstream use
-7. THE GPUContext SHALL handle device loss events gracefully with callbacks
-
-### Requirement 2: GPU Buffer Management
-
-**User Story:** As a developer, I want to create and manage GPU buffers for sorting operations.
-
-#### Acceptance Criteria
-
-1. WHEN `createStorageBuffer()` is called, THE BufferManager SHALL create a mapped buffer and upload data
-2. WHEN `createUniformBuffer()` is called, THE BufferManager SHALL create a buffer with 16-byte alignment
-3. WHEN `createStagingBuffer()` is called, THE BufferManager SHALL create a MAP_READ buffer for CPU readback
-4. WHEN `readBuffer()` is called, THE BufferManager SHALL copy GPU data to staging buffer and map it for reading
-5. IF buffer creation fails, THE BufferManager SHALL throw `BufferAllocationError` with formatted message
-6. IF buffer mapping fails, THE BufferManager SHALL throw `BufferMapError` with formatted message
-7. THE BufferManager SHALL track all buffers for proper cleanup
-
-### Requirement 3: Sorting Validation
-
-**User Story:** As a developer, I want to verify that GPU sorting results are correct.
-
-#### Acceptance Criteria
-
-1. THE Validator SHALL verify arrays are sorted in ascending order
-2. THE Validator SHALL verify sorted arrays contain the same elements as input
-3. THE Validator SHALL support maximum validation size to prevent memory issues
-4. FOR arrays exceeding max size, THE Validator SHALL sample validate instead of full validation
-5. THE Validator SHALL return detailed validation results with error messages
-
-### Requirement 4: Error Handling
-
-**User Story:** As a developer, I want specific error types for different GPU failures.
-
-#### Acceptance Criteria
-
-1. THE library SHALL provide `WebGPUNotSupportedError` for browser compatibility issues
-2. THE library SHALL provide `GPUAdapterError` for adapter request failures
-3. THE library SHALL provide `GPUDeviceError` for device request failures
-4. THE library SHALL provide `BufferAllocationError` for buffer creation failures
-5. THE library SHALL provide `BufferMapError` for buffer mapping failures
-6. THE library SHALL provide `ShaderCompilationError` for shader compilation failures
-7. THE library SHALL provide `GPUTimeoutError` for operation timeouts
-
-### Requirement 5: GPU Operation Timeout
-
-**User Story:** As a developer, I want to wrap GPU operations with configurable timeouts.
-
-#### Acceptance Criteria
-
-1. THE `withTimeout()` function SHALL accept a promise and timeout options
-2. THE default timeout SHALL be 30000 milliseconds
-3. IF the operation exceeds the timeout, THE function SHALL throw `GPUTimeoutError`
-4. THE function SHALL clean up the timeout timer on success or failure
-5. THE `createTimeoutWrapper()` function SHALL create a reusable timeout wrapper with default options
-
-### Requirement 6: Resource Lifecycle
-
-**User Story:** As a developer, I want to properly release GPU resources when done.
-
-#### Acceptance Criteria
-
-1. THE GPUContext SHALL provide `destroy()` method to release device and adapter
-2. THE BufferManager SHALL provide `releaseBuffer()` to release individual buffers
-3. THE BufferManager SHALL provide `releaseAll()` to release all managed buffers
-4. THE Sorter classes SHALL provide `destroy()` to release pipelines and buffers
-5. WHEN `destroy()` is called, THE resources SHALL be properly cleaned up and nulled
diff --git a/openspec/specs/quality/README.md b/openspec/specs/quality/README.md
deleted file mode 100644
index b090f0a..0000000
--- a/openspec/specs/quality/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Quality Domain
-
-Project quality standards including CI/CD configuration, code quality tools, and documentation requirements.
-
-> 质量域 - 项目质量标准,包括 CI/CD 配置、代码质量工具和文档要求。
-
-## Specifications
-
-| Spec | Description | 说明 |
-| -------------------------------------------------- | ------------------------------------- | --------------------------- |
-| [project-enhancement.md](./project-enhancement.md) | CI/CD, code quality, project metadata | CI/CD、代码质量、项目元数据 |
-
-## Components
-
-- **CI/CD Pipelines** - GitHub Actions workflows
-- **Code Quality** - ESLint, Prettier, TypeScript configurations
-- **Git Hooks** - Husky + lint-staged for pre-commit checks
-- **Test Coverage** - Vitest coverage configuration
-
-## Related Domains
-
-- [../sorting/](../sorting/) - Core sorting algorithms
-- [../infrastructure/](../infrastructure/) - WebGPU infrastructure
diff --git a/openspec/specs/quality/project-enhancement.md b/openspec/specs/quality/project-enhancement.md
deleted file mode 100644
index 59fb414..0000000
--- a/openspec/specs/quality/project-enhancement.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Product Spec: Project Quality Enhancement
-
-## Introduction
-
-This spec defines quality enhancement requirements for the WebGPU Sorting project, elevating it to优秀 open-source project standards. These enhancements include CI/CD configuration, code quality tools, project metadata improvements, and addition of standard open-source files.
-
-## Glossary
-
-- **CI/CD**: Continuous Integration / Continuous Deployment
-- **ESLint**: JavaScript/TypeScript static code analysis tool
-- **Prettier**: Code formatting tool
-- **Husky**: Git hooks management tool
-- **GitHub_Actions**: GitHub's automation workflow service
-- **EditorConfig**: Cross-editor code style configuration standard
-- **Code_of_Conduct**: Community behavior guidelines document
-- **Security_Policy**: Security vulnerability reporting document
-
-## Requirements
-
-### Requirement 1: CI/CD Automation Configuration
-
-**User Story:** As a contributor, I want automated testing and building on every pull request, so that code quality is maintained and regressions are caught early.
-
-#### Acceptance Criteria
-
-1. WHEN a pull request is created or updated, THE GitHub_Actions SHALL run all tests automatically
-2. WHEN a pull request is created or updated, THE GitHub_Actions SHALL run TypeScript type checking
-3. WHEN a pull request is created or updated, THE GitHub_Actions SHALL run ESLint code linting
-4. WHEN code is pushed to the master branch, THE GitHub_Actions SHALL build the project
-5. WHEN all CI checks pass on main branch, THE GitHub_Actions SHALL be ready for release workflow
-6. THE GitHub_Actions SHALL support multiple Node.js versions (18.x, 20.x)
-
-### Requirement 2: Code Quality Tools Configuration
-
-**User Story:** As a developer, I want consistent code style and quality checks, so that the codebase remains clean and maintainable.
-
-#### Acceptance Criteria
-
-1. THE ESLint SHALL be configured with TypeScript support and recommended rules
-2. THE Prettier SHALL be configured for consistent code formatting
-3. WHEN a developer runs `npm run lint`, THE System SHALL check code style and report issues
-4. WHEN a developer runs `npm run format`, THE System SHALL format all source files
-5. THE ESLint and Prettier configurations SHALL not conflict with each other
-6. THE System SHALL include lint-staged for pre-commit checks
-
-### Requirement 3: Git Hooks Configuration
-
-**User Story:** As a developer, I want pre-commit hooks to catch issues before committing, so that bad code doesn't enter the repository.
-
-#### Acceptance Criteria
-
-1. WHEN a developer attempts to commit code, THE Husky SHALL run lint-staged checks
-2. WHEN lint-staged runs, THE System SHALL check only staged files for linting errors
-3. WHEN lint-staged runs, THE System SHALL format staged files with Prettier
-4. IF lint-staged checks fail, THEN THE System SHALL prevent the commit
-5. THE Husky configuration SHALL be easy to set up with `npm install`
-
-### Requirement 4: Package.json Enhancement
-
-**User Story:** As a package consumer, I want complete package metadata, so that I can understand the package origin and report issues.
-
-#### Acceptance Criteria
-
-1. THE package.json SHALL include a valid repository field with GitHub URL
-2. THE package.json SHALL include a bugs field with issue tracker URL
-3. THE package.json SHALL include a homepage field
-4. THE package.json SHALL include author information
-5. THE package.json SHALL include engines field specifying Node.js version requirements
-6. THE package.json SHALL include all necessary scripts for development workflow
-7. THE package.json SHALL include files field for npm publishing
-
-### Requirement 5: Standard Open Source Files
-
-**User Story:** As a potential contributor, I want standard open source files, so that I understand how to contribute and behave in the community.
-
-#### Acceptance Criteria
-
-1. THE System SHALL include a CODE_OF_CONDUCT.md file based on Contributor Covenant
-2. THE System SHALL include a SECURITY.md file with vulnerability reporting instructions
-3. THE System SHALL include an .editorconfig file for cross-editor consistency
-4. THE System SHALL include GitHub issue and PR templates
-5. THE System SHALL include a .nvmrc file specifying Node.js version
-
-### Requirement 6: Test Coverage Configuration
-
-**User Story:** As a maintainer, I want test coverage reports, so that I can identify untested code areas.
-
-#### Acceptance Criteria
-
-1. WHEN tests are run with coverage flag, THE System SHALL generate coverage reports
-2. THE vitest configuration SHALL include coverage settings
-3. THE coverage reports SHALL be in multiple formats (text, lcov, html)
-4. THE GitHub_Actions SHALL upload coverage reports as artifacts
-5. THE System SHALL have a minimum coverage threshold configuration
diff --git a/openspec/specs/sorting/README.md b/openspec/specs/sorting/README.md
deleted file mode 100644
index 5f927c3..0000000
--- a/openspec/specs/sorting/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Sorting Domain
-
-Core sorting algorithms and performance requirements for the WebGPU Sorting library.
-
-> 排序域 - WebGPU 排序库的核心排序算法与性能需求。
-
-## Specifications
-
-| Spec | Description | 说明 |
-| ---------------------------------------- | --------------------------------- | ---------------- |
-| [webgpu-sorting.md](./webgpu-sorting.md) | Core sorting feature requirements | 核心排序功能需求 |
-
-## Components
-
-- **BitonicSorter** - Bitonic sort implementation (O(n log²n))
-- **RadixSorter** - Radix sort implementation (O(n × k))
-- **Benchmark** - Performance benchmarking utilities
-- **Validator** - Sorting result validation
-
-## Related Domains
-
-- [../infrastructure/](../infrastructure/) - WebGPU context and buffer management
-- [../quality/](../quality/) - CI/CD and code quality standards
diff --git a/openspec/specs/sorting/webgpu-sorting.md b/openspec/specs/sorting/webgpu-sorting.md
deleted file mode 100644
index ad33c97..0000000
--- a/openspec/specs/sorting/webgpu-sorting.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# Product Spec: WebGPU Sorting
-
-## Introduction
-
-This project implements high-performance GPU sorting algorithms based on WebGPU, including Bitonic Sort and Radix Sort. The goal is to demonstrate GPU general-purpose computing capabilities, achieving sorting performance tens of times faster than JavaScript's native `Array.sort()`. The project focuses on showcasing GPU core technologies such as workgroup synchronization barriers and parallel reduction.
-
-## Glossary
-
-- **WebGPU**: Next-generation web graphics and compute API providing low-level access to modern GPUs
-- **Bitonic_Sort**: A comparison sorting algorithm suitable for parallel implementation
-- **Radix_Sort**: A non-comparison sorting algorithm that sorts by digit positions
-- **Compute_Shader**: Shader programs for general-purpose GPU computing
-- **Workgroup**: A group of GPU threads that can share memory and synchronize
-- **Workgroup_Barrier**: A synchronization primitive for synchronizing all threads within a workgroup
-- **Shared_Memory**: Fast local memory accessible by threads within a workgroup
-- **Parallel_Reduction**: A technique to combine array elements into a single value through parallel operations
-- **GPU_Buffer**: GPU memory buffers storing data in GPU memory
-- **Dispatch**: The operation of launching GPU compute tasks
-
-## Requirements
-
-### Requirement 1: WebGPU Environment Initialization
-
-**User Story:** As a developer, I want to initialize the WebGPU environment so that I can execute GPU compute tasks in the browser.
-
-#### Acceptance Criteria
-
-1. WHEN the application starts, THE Initializer SHALL request a GPU adapter and device
-2. IF WebGPU is not supported, THEN THE Initializer SHALL return a descriptive error message
-3. WHEN the GPU device is obtained, THE Initializer SHALL create necessary command encoders and queues
-4. THE Initializer SHALL verify compute shader support before proceeding
-
-### Requirement 2: GPU Buffer Management
-
-**User Story:** As a developer, I want to efficiently transfer data between CPU and GPU for sorting computations.
-
-#### Acceptance Criteria
-
-1. WHEN input data is provided, THE Buffer_Manager SHALL create appropriate GPU storage buffers
-2. THE Buffer_Manager SHALL support uploading unsigned 32-bit integer arrays to GPU memory
-3. THE Buffer_Manager SHALL support downloading sorted results from GPU to CPU memory
-4. WHEN buffers are no longer needed, THE Buffer_Manager SHALL properly release GPU resources
-5. THE Buffer_Manager SHALL handle buffer size alignment requirements for WebGPU
-
-### Requirement 3: Bitonic Sort Implementation
-
-**User Story:** As a developer, I want a GPU version of the bitonic sort algorithm for efficient large-scale data sorting.
-
-#### Acceptance Criteria
-
-1. THE Bitonic_Sorter SHALL implement the bitonic merge network in WGSL compute shaders
-2. WHEN sorting, THE Bitonic_Sorter SHALL use workgroupBarrier() for thread synchronization within workgroups
-3. THE Bitonic_Sorter SHALL utilize shared memory for intra-workgroup data exchange
-4. WHEN the input size is not a power of 2, THE Bitonic_Sorter SHALL pad the array appropriately
-5. FOR ALL valid input arrays, THE Bitonic_Sorter SHALL produce a correctly sorted output in ascending order
-6. THE Bitonic_Sorter SHALL support sorting arrays of at least 1 million unsigned 32-bit integers
-
-### Requirement 4: Radix Sort Implementation
-
-**User Story:** As a developer, I want a GPU version of the radix sort algorithm for efficient non-comparison sorting of integer data.
-
-#### Acceptance Criteria
-
-1. THE Radix_Sorter SHALL implement per-digit sorting using WGSL compute shaders
-2. THE Radix_Sorter SHALL compute prefix sum on CPU for digit offsets (simplified approach)
-3. WHEN processing each radix pass, THE Radix_Sorter SHALL use workgroupBarrier() for synchronization
-4. THE Radix_Sorter SHALL implement parallel reduction for histogram computation
-5. FOR ALL valid input arrays, THE Radix_Sorter SHALL produce a correctly sorted output in ascending order
-6. THE Radix_Sorter SHALL support sorting arrays of at least 1 million unsigned 32-bit integers
-
-### Requirement 5: Performance Benchmarking
-
-**User Story:** As a developer, I want to compare GPU sorting performance against CPU sorting to validate GPU acceleration effects.
-
-#### Acceptance Criteria
-
-1. THE Benchmark SHALL measure sorting time for both GPU algorithms and JavaScript Array.sort()
-2. THE Benchmark SHALL test multiple array sizes (1K, 10K, 100K, 1M elements)
-3. THE Benchmark SHALL report speedup ratio comparing GPU to CPU performance
-4. THE Benchmark SHALL exclude data transfer time in GPU-only timing measurements
-5. THE Benchmark SHALL include total time (with data transfer) for realistic comparison
-6. WHEN benchmarking, THE Benchmark SHALL run multiple iterations and report average times
-
-### Requirement 6: Sorting Correctness Validation
-
-**User Story:** As a developer, I want to verify the correctness of GPU sorting results to ensure algorithm implementations are correct.
-
-#### Acceptance Criteria
-
-1. THE Validator SHALL verify that output arrays are in ascending order
-2. THE Validator SHALL verify that output arrays contain the same elements as input arrays
-3. THE Validator SHALL support comparing GPU results against JavaScript Array.sort() results
-4. FOR ALL test cases, THE Validator SHALL report any discrepancies found
-
-### Requirement 7: Demo User Interface
-
-**User Story:** As a user, I want a simple interface to run sorting demos and view performance results.
-
-#### Acceptance Criteria
-
-1. THE Demo_UI SHALL provide controls to select array size and sorting algorithm
-2. THE Demo_UI SHALL display sorting progress and completion status
-3. THE Demo_UI SHALL show performance metrics including execution time and speedup ratio
-4. THE Demo_UI SHALL handle and display errors gracefully
-5. WHEN WebGPU is not available, THE Demo_UI SHALL display a clear unsupported message
diff --git a/package-lock.json b/package-lock.json
index e83532c..74e8a84 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -29,7 +29,6 @@
"typescript-eslint": "^8.59.0",
"vite": "^8.0.10",
"vitepress": "^1.6.4",
- "vitepress-plugin-llms": "^1.12.2",
"vitest": "^4.1.5",
"vue": "^3.5.34"
},
@@ -1457,16 +1456,6 @@
"assertion-error": "^2.0.1"
}
},
- "node_modules/@types/debug": {
- "version": "4.1.13",
- "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
- "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/ms": "*"
- }
- },
"node_modules/@types/deep-eql": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz",
@@ -1540,13 +1529,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/@types/ms": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
- "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
@@ -2387,17 +2369,6 @@
"js-tokens": "^10.0.0"
}
},
- "node_modules/bail": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz",
- "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
@@ -2475,17 +2446,6 @@
"node": ">=18"
}
},
- "node_modules/character-entities": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
- "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/character-entities-html4": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz",
@@ -2612,26 +2572,6 @@
"node": ">=20"
}
},
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/colorette": {
"version": "2.0.20",
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
@@ -2753,20 +2693,6 @@
}
}
},
- "node_modules/decode-named-character-reference": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
- "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "character-entities": "^2.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
@@ -3171,20 +3097,6 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/esprima": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
- "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
- "dev": true,
- "license": "BSD-2-Clause",
- "bin": {
- "esparse": "bin/esparse.js",
- "esvalidate": "bin/esvalidate.js"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/esquery": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz",
@@ -3258,26 +3170,6 @@
"node": ">=12.0.0"
}
},
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/extend-shallow": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
- "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "is-extendable": "^0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/fast-check": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz",
@@ -3322,20 +3214,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/fault": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fault/-/fault-2.0.1.tgz",
- "integrity": "sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "format": "^0.2.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3397,15 +3275,6 @@
"tabbable": "^6.4.0"
}
},
- "node_modules/format": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
- "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
- "dev": true,
- "engines": {
- "node": ">=0.4.x"
- }
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
@@ -3470,22 +3339,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/gray-matter": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
- "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "js-yaml": "^3.13.1",
- "kind-of": "^6.0.2",
- "section-matter": "^1.0.0",
- "strip-bom-string": "^1.0.0"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
"node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -3641,16 +3494,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-extendable": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -3722,19 +3565,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/is-plain-obj": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
- "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-what": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz",
@@ -3817,30 +3647,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/js-yaml": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
- "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "argparse": "^1.0.7",
- "esprima": "^4.0.0"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/js-yaml/node_modules/argparse": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
- "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "sprintf-js": "~1.0.2"
- }
- },
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -3902,16 +3708,6 @@
"json-buffer": "3.0.1"
}
},
- "node_modules/kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -4292,17 +4088,6 @@
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
}
},
- "node_modules/longest-streak": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz",
- "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/lunr": {
"version": "2.3.9",
"resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
@@ -4384,16 +4169,6 @@
"mathjax-full": "^3.2.0"
}
},
- "node_modules/markdown-title": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/markdown-title/-/markdown-title-1.0.2.tgz",
- "integrity": "sha512-MqIQVVkz+uGEHi3TsHx/czcxxCbRIL7sv5K5DnYw/tI+apY54IbPefV/cmgxp6LoJSEx/TqcHdLs/298afG5QQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/mathjax-full": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/mathjax-full/-/mathjax-full-3.2.1.tgz",
@@ -4407,78 +4182,6 @@
"speech-rule-engine": "^4.0.6"
}
},
- "node_modules/mdast-util-from-markdown": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
- "integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "@types/unist": "^3.0.0",
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "mdast-util-to-string": "^4.0.0",
- "micromark": "^4.0.0",
- "micromark-util-decode-numeric-character-reference": "^2.0.0",
- "micromark-util-decode-string": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0",
- "unist-util-stringify-position": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-frontmatter": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/mdast-util-frontmatter/-/mdast-util-frontmatter-2.0.1.tgz",
- "integrity": "sha512-LRqI9+wdgC25P0URIJY9vwocIzCcksduHQ9OF2joxQoyTNVduwLAFUzjoopuRJbJAReaKrNQKAZKL3uCMugWJA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "devlop": "^1.0.0",
- "escape-string-regexp": "^5.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "mdast-util-to-markdown": "^2.0.0",
- "micromark-extension-frontmatter": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-frontmatter/node_modules/escape-string-regexp": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
- "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/mdast-util-phrasing": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
- "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "unist-util-is": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
"node_modules/mdast-util-to-hast": {
"version": "13.2.1",
"resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz",
@@ -4501,42 +4204,6 @@
"url": "https://opencollective.com/unified"
}
},
- "node_modules/mdast-util-to-markdown": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz",
- "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "@types/unist": "^3.0.0",
- "longest-streak": "^3.0.0",
- "mdast-util-phrasing": "^4.0.0",
- "mdast-util-to-string": "^4.0.0",
- "micromark-util-classify-character": "^2.0.0",
- "micromark-util-decode-string": "^2.0.0",
- "unist-util-visit": "^5.0.0",
- "zwitch": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/mdast-util-to-string": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
- "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
@@ -4558,10 +4225,10 @@
"dev": true,
"license": "Apache-2.0"
},
- "node_modules/micromark": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
- "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==",
+ "node_modules/micromark-util-character": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
+ "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
"dev": true,
"funding": [
{
@@ -4575,29 +4242,14 @@
],
"license": "MIT",
"dependencies": {
- "@types/debug": "^4.0.0",
- "debug": "^4.0.0",
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-core-commonmark": "^2.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-combine-extensions": "^2.0.0",
- "micromark-util-decode-numeric-character-reference": "^2.0.0",
- "micromark-util-encode": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-resolve-all": "^2.0.0",
- "micromark-util-sanitize-uri": "^2.0.0",
- "micromark-util-subtokenize": "^2.0.0",
"micromark-util-symbol": "^2.0.0",
"micromark-util-types": "^2.0.0"
}
},
- "node_modules/micromark-core-commonmark": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
- "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==",
+ "node_modules/micromark-util-encode": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
+ "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
"dev": true,
"funding": [
{
@@ -4609,47 +4261,12 @@
"url": "https://opencollective.com/unified"
}
],
- "license": "MIT",
- "dependencies": {
- "decode-named-character-reference": "^1.0.0",
- "devlop": "^1.0.0",
- "micromark-factory-destination": "^2.0.0",
- "micromark-factory-label": "^2.0.0",
- "micromark-factory-space": "^2.0.0",
- "micromark-factory-title": "^2.0.0",
- "micromark-factory-whitespace": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-classify-character": "^2.0.0",
- "micromark-util-html-tag-name": "^2.0.0",
- "micromark-util-normalize-identifier": "^2.0.0",
- "micromark-util-resolve-all": "^2.0.0",
- "micromark-util-subtokenize": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-extension-frontmatter": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/micromark-extension-frontmatter/-/micromark-extension-frontmatter-2.0.0.tgz",
- "integrity": "sha512-C4AkuM3dA58cgZha7zVnuVxBhDsbttIMiytjgsM2XbHAB2faRVaHRle40558FBN+DJcrLNCoqG5mlrpdU4cRtg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "fault": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
+ "license": "MIT"
},
- "node_modules/micromark-factory-destination": {
+ "node_modules/micromark-util-sanitize-uri": {
"version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
- "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==",
+ "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
+ "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
"dev": true,
"funding": [
{
@@ -4664,347 +4281,11 @@
"license": "MIT",
"dependencies": {
"micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
+ "micromark-util-encode": "^2.0.0",
+ "micromark-util-symbol": "^2.0.0"
}
},
- "node_modules/micromark-factory-label": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
- "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-factory-space": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
- "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-character": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-factory-title": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
- "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-factory-whitespace": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
- "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-factory-space": "^2.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-character": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
- "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-chunked": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
- "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-classify-character": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
- "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-character": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-combine-extensions": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
- "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-decode-numeric-character-reference": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
- "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-decode-string": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
- "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "decode-named-character-reference": "^1.0.0",
- "micromark-util-character": "^2.0.0",
- "micromark-util-decode-numeric-character-reference": "^2.0.0",
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-encode": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
- "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT"
- },
- "node_modules/micromark-util-html-tag-name": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
- "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT"
- },
- "node_modules/micromark-util-normalize-identifier": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
- "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-resolve-all": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
- "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-sanitize-uri": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
- "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "micromark-util-character": "^2.0.0",
- "micromark-util-encode": "^2.0.0",
- "micromark-util-symbol": "^2.0.0"
- }
- },
- "node_modules/micromark-util-subtokenize": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
- "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==",
- "dev": true,
- "funding": [
- {
- "type": "GitHub Sponsors",
- "url": "https://github.com/sponsors/unifiedjs"
- },
- {
- "type": "OpenCollective",
- "url": "https://opencollective.com/unified"
- }
- ],
- "license": "MIT",
- "dependencies": {
- "devlop": "^1.0.0",
- "micromark-util-chunked": "^2.0.0",
- "micromark-util-symbol": "^2.0.0",
- "micromark-util-types": "^2.0.0"
- }
- },
- "node_modules/micromark-util-symbol": {
+ "node_modules/micromark-util-symbol": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
"integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==",
@@ -5038,152 +4319,6 @@
],
"license": "MIT"
},
- "node_modules/millify": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/millify/-/millify-6.1.0.tgz",
- "integrity": "sha512-H/E3J6t+DQs/F2YgfDhxUVZz/dF8JXPPKTLHL/yHCcLZLtCXJDUaqvhJXQwqOVBvbyNn4T0WjLpIHd7PAw7fBA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "yargs": "^17.0.1"
- },
- "bin": {
- "millify": "bin/millify"
- }
- },
- "node_modules/millify/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/millify/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/millify/node_modules/cliui": {
- "version": "8.0.1",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
- "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.1",
- "wrap-ansi": "^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/millify/node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/millify/node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/millify/node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/millify/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/millify/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/millify/node_modules/yargs": {
- "version": "17.7.2",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
- "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "cliui": "^8.0.1",
- "escalade": "^3.1.1",
- "get-caller-file": "^2.0.5",
- "require-directory": "^2.1.1",
- "string-width": "^4.2.3",
- "y18n": "^5.0.5",
- "yargs-parser": "^21.1.1"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/millify/node_modules/yargs-parser": {
- "version": "21.1.1",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
- "dev": true,
- "license": "ISC",
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
@@ -5474,13 +4609,6 @@
"node": ">=8"
}
},
- "node_modules/path-to-regexp": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
- "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
@@ -5641,19 +4769,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
- "node_modules/pretty-bytes": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz",
- "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=20"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/property-information": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
@@ -5729,83 +4844,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/remark": {
- "version": "15.0.1",
- "resolved": "https://registry.npmjs.org/remark/-/remark-15.0.1.tgz",
- "integrity": "sha512-Eht5w30ruCXgFmxVUSlNWQ9iiimq07URKeFS3hNc8cUWy1llX4KDWfyEDZRycMc+znsN9Ux5/tJ/BFdgdOwA3A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "remark-parse": "^11.0.0",
- "remark-stringify": "^11.0.0",
- "unified": "^11.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/remark-frontmatter": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-5.0.0.tgz",
- "integrity": "sha512-XTFYvNASMe5iPN0719nPrdItC9aU0ssC4v14mH1BCi1u0n1gAocqcujWUrByftZTbLhRtiKRyjYTSIOcr69UVQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "mdast-util-frontmatter": "^2.0.0",
- "micromark-extension-frontmatter": "^2.0.0",
- "unified": "^11.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/remark-parse": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
- "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "mdast-util-from-markdown": "^2.0.0",
- "micromark-util-types": "^2.0.0",
- "unified": "^11.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/remark-stringify": {
- "version": "11.0.0",
- "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
- "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/mdast": "^4.0.0",
- "mdast-util-to-markdown": "^2.0.0",
- "unified": "^11.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/restore-cursor": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz",
@@ -5958,20 +4996,6 @@
"license": "MIT",
"peer": true
},
- "node_modules/section-matter": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
- "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "extend-shallow": "^2.0.1",
- "kind-of": "^6.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
@@ -6180,13 +5204,6 @@
"node": ">=18"
}
},
- "node_modules/sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
- "dev": true,
- "license": "BSD-3-Clause"
- },
"node_modules/stackback": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
@@ -6260,16 +5277,6 @@
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
- "node_modules/strip-bom-string": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
- "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/superjson": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz",
@@ -6365,13 +5372,6 @@
"node": ">=14.0.0"
}
},
- "node_modules/tokenx": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/tokenx/-/tokenx-1.3.0.tgz",
- "integrity": "sha512-NLdXTEZkKiO0gZuLtMoZKjCXTREXeZZt8nnnNeyoXtNZAfG/GKGSbQtLU5STspc0rMSwcA+UJfWZkbNU01iKmQ==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
@@ -6390,17 +5390,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/trough": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz",
- "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/ts-api-utils": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
@@ -6503,26 +5492,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/unified": {
- "version": "11.0.5",
- "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
- "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "bail": "^2.0.0",
- "devlop": "^1.0.0",
- "extend": "^3.0.0",
- "is-plain-obj": "^4.0.0",
- "trough": "^2.0.0",
- "vfile": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
"node_modules/unist-util-is": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz",
@@ -6551,22 +5520,6 @@
"url": "https://opencollective.com/unified"
}
},
- "node_modules/unist-util-remove": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/unist-util-remove/-/unist-util-remove-4.0.0.tgz",
- "integrity": "sha512-b4gokeGId57UVRX/eVKej5gXqGlc9+trkORhFJpu9raqZkZhU0zm8Doi05+HaiBsMEIJowL+2WtQ5ItjsngPXg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/unist": "^3.0.0",
- "unist-util-is": "^6.0.0",
- "unist-util-visit-parents": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
"node_modules/unist-util-stringify-position": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
@@ -6782,35 +5735,6 @@
}
}
},
- "node_modules/vitepress-plugin-llms": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/vitepress-plugin-llms/-/vitepress-plugin-llms-1.12.2.tgz",
- "integrity": "sha512-hdklo7di6E2/MwlYstH7R5QgdPHX+f5G/fp8QBq6MCiw4DWi3IOKMaous0S839FIGsPjK3QHwK6KcFwCf/XzjA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "gray-matter": "^4.0.3",
- "markdown-it": "^14.1.0",
- "markdown-title": "^1.0.2",
- "mdast-util-from-markdown": "^2.0.3",
- "millify": "^6.1.0",
- "minimatch": "^10.2.5",
- "path-to-regexp": "^6.3.0",
- "picocolors": "^1.1.1",
- "pretty-bytes": "^7.1.0",
- "remark": "^15.0.1",
- "remark-frontmatter": "^5.0.0",
- "tokenx": "^1.3.0",
- "unist-util-remove": "^4.0.0",
- "unist-util-visit": "^5.1.0"
- },
- "engines": {
- "node": ">=18.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/okineadev"
- }
- },
"node_modules/vitepress/node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
diff --git a/package.json b/package.json
index 815e55e..3b2cebb 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,8 @@
},
"scripts": {
"dev": "vitepress dev docs",
- "build": "vitepress build docs",
+ "build": "npm run build:demo && npm run build:site",
+ "build:site": "vitepress build docs",
"build:demo": "tsc && vite build",
"build:analyze": "tsc && vite build --mode analyze",
"preview": "vitepress preview docs",
@@ -85,7 +86,6 @@
"typescript-eslint": "^8.59.0",
"vite": "^8.0.10",
"vitepress": "^1.6.4",
- "vitepress-plugin-llms": "^1.12.2",
"vitest": "^4.1.5",
"vue": "^3.5.34"
}
diff --git a/vite.config.ts b/vite.config.ts
index b8e0c42..38351ce 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,8 +1,8 @@
import { defineConfig } from 'vite';
import type { Plugin } from 'vite';
-// Demo builds go to docs/public/demo/ for VitePress
-// Use relative path for better portability
+// Build the standalone demo into VitePress public assets without colliding
+// with the /demo docs page route.
const base = process.env.VITE_BASE_PATH || './';
export default defineConfig(async ({ mode }) => {
@@ -28,7 +28,7 @@ export default defineConfig(async ({ mode }) => {
base,
build: {
target: 'esnext',
- outDir: 'docs/public/demo',
+ outDir: 'docs/public/playground',
emptyOutDir: true,
rollupOptions: {
plugins,