Files
vac-optimizer/docs/bun-adoption.md
T
nessarandClaude Opus 5.5 c949480e49 docs(adr): propose Bun runtime and native tooling
Record the proposed decision to run project-owned JavaScript under Bun
with its native test runner, linter, formatter, type checker and HTTP
server, keeping Angular's standard build pipeline, plus the development
spec for the migration tickets.

Refs #289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:01:42 +02:00

12 KiB

Bun Runtime and Native Tooling — Development Spec

Status: local draft synthesized from the agreed individual decisions. Integration feasibility remains unverified; ADR 0009 remains proposed.

Problem Statement

The maintainer wants VacOptimizer to use Bun as its actual JavaScript runtime and adopt its native tooling wherever agreed, even without measurable performance gains. Today Bun installs dependencies, generates the language registry, and runs the deployed server, but development commands can launch Node-based CLIs, CI uses Node containers, and the Docker build explicitly installs Node.

The toolchain is also inconsistent: the local Bun installation is 1.3.14, CI pins 1.4.2, and Docker uses a floating Bun image. Merely prefixing commands with Bun does not establish which runtime executes their JavaScript.

Solution

Use Bun for project-owned JavaScript in development, CI, and production. Adopt Bun's native test runner, linter, formatter, standalone type checker, and HTTP server. Retain Angular and its standard compiler and build pipeline, running the JavaScript tooling under Bun.

Preserve the application's existing behavior and verification standards. The planner remains client-side: planning horizons, planning rules, leave placements, planning outcomes, plan statistics, and plan explanations retain their current meaning. Browser code and Web Workers continue to run in the user's browser.

User Stories

The following acceptance criteria define completion:

  1. Actual Bun execution. Development serving and watch mode, production builds, language generation, repository CI scripts, tests, and the production server execute their project-owned JavaScript under Bun, including spawned tools and test fixtures. A Node.js fallback does not satisfy this criterion.
  2. Reproducible setup. Development instructions, CI, and both Docker stages specify the same exact, verified Bun version. Frozen dependency installation succeeds from a clean checkout without changing the lockfile, and the production image installs only production dependencies.
  3. Native tests with preserved behavior. All existing functional and Angular component tests execute under bun test, preserving assertions, parameterized cases, clock control, global mocks, cleanup, isolation, and real worker integration. Tests cannot be dropped or weakened to make the migration pass.
  4. Preserved coverage. Functional tests retain coverage reporting and CI artifacts, including useful output when tests fail. Preserve the current production-code coverage scope and exclusion of the frozen engine baseline; report unsupported coverage capabilities or report formats as compatibility gaps rather than silently removing them.
  5. Native linting and formatting. Bun's native linter and formatter replace ESLint and Prettier, preserving the current rule severities, type-aware checks, unused-name exceptions, formatting options, and Angular-template formatting. CI continues to reject violations. Checks cover the same application, repository-script, and workflow content as before.
  6. Type checking alongside Angular. bun check checks application and test TypeScript. Angular's compiler retains its supported TypeScript 6 dependency and continues to check templates during builds. Type errors still fail the appropriate checks; successful standalone checking does not replace a successful Angular build.
  7. Native HTTP serving. Bun.serve replaces Express, preserving Angular's request-handler integration, configured rendering modes, static assets and cache behavior, configurable port, error handling, and container health check. Development and production routes continue to work, including direct visits to the benchmark page. The current catch-all route uses client rendering; this migration does not enable server rendering for that route.
  8. Existing CI guarantees. Policy and image-publication regression checks, security scans, production builds, artifact retention, and required checks continue to work. The separate required seven-scenario benchmark preserves its calibration protocol, warm-up, measured repetitions, determinism checks, timeouts, and performance budgets. A runtime change cannot justify weakening these gates.
  9. Honest completion. Fix incompatible required tooling before declaring the migration complete. If a fix proves infeasible, report the failing behavior, evidence, and remaining blocker. Local success must be distinguished from successful live Gitea checks.

Implementation Decisions

  • Agreed: runtime and native tools. Bun adoption is a requirement independent of speed gains. Use its native test runner, linter, formatter, standalone type checker, and HTTP server. Compatible Node API imports may remain when executed by Bun; rewriting every import is not required to satisfy the runtime goal.
  • Agreed: Angular boundary. Keep Angular's standard compiler, bundler, development server, and framework build support. Preserve the existing rendering configuration and browser-based planner, consistent with ADR 0002.
  • Agreed: TypeScript coexistence. Keep TypeScript 6 for Angular compilation and use Bun's TypeScript 7-based checker for standalone checking. An Angular upgrade is not required for this arrangement.
  • Agreed: tests and server integration. Adapt the Angular test compilation and setup, mocks, DOM environment, worker harnesses, and subprocess fixtures to the chosen runtime and runner. Use Angular's web request API with Bun's HTTP server, preserving its development/build handler contract and static-file protections.
  • Migration reach. Update package commands, test configuration and typings, generated executable fixtures, server entry and exports, container build and runtime stages, project-owned CI invocations, and development documentation. Remove superseded dependencies and configuration after checking their callers.
  • Proposed implementation order. Verify the Bun release, an Angular production build, representative Angular component tests, and native lint/format/type checks first. Extend that verified setup to the full suite, server, containers, and CI before removing the replaced tools.
  • Proposed version. Bun 1.4.3 is the initial candidate based on the researched native-tool documentation. Select the exact version only after verifying the required capabilities together.

Testing Decisions

  • Test observable behavior and failure outcomes, rather than configuration text or internal adapter shapes. Reuse the existing behavior-level tests and change harnesses only where the runtime or runner requires it.
  • Runtime and installation: exercise clean frozen installs, development and production commands, and project-owned subprocesses with Node unavailable to those commands. Verify actual execution by Bun, rather than relying on a command's name. Keep any CI-platform Node requirement separate from this check.
  • Angular and planning: use the existing TestBed-based component and service suites as prior art for compilation and DOM behavior. Retain the planning integration, property-based, migration, date-sensitive, and cancellation tests to check planning outcomes, saved inputs, and plan explanations.
  • Workers and subprocesses: preserve the existing real-worker tests for submitted-configuration isolation, outcome and explanation delivery, and worker cleanup. Run policy and publisher regression scripts with Bun, keeping their temporary Git repositories and fake Docker executable so verification remains independent of real registry writes.
  • Lint, format, and types: compare the current checks with the native tools. Use small representative invalid inputs to establish that unused variables, deprecated APIs, formatting violations, application/test type errors, and Angular template errors still fail the intended command. Verify formatting options and representative Angular templates without an unrelated reformat.
  • HTTP and containers: add focused HTTP behavior checks around the native server, since the explored test suite provides no equivalent server coverage. Exercise configured routes, direct navigation, static JavaScript/CSS assets, cache and content-type headers, missing assets, error responses, and traversal protection. Smoke-test the production container and its health check.
  • Coverage and benchmark: verify functional coverage artifacts, including failure-path uploads, and run the existing benchmark outside coverage. Keep the frozen-engine calibration and current budget assertions. Record Bun results as new measurements rather than claiming browser or phone speedups from them.
  • CI: use the existing policy/publisher regression scenarios as prior art for push, pull-request, fork, manual, and release-event behavior. Obtain successful required checks on the final PR revision; live publication and activation validation remain subject to the repository's existing Gitea process.

Out of Scope

  • Replacing Angular's build pipeline with Bun's bundler, rewriting the framework, or bypassing Angular's TypeScript support checks.
  • Moving leave planning to the server, changing planning rules or objectives, altering saved data, or adding accounts, synchronization, or backend services.
  • Changing configured rendering modes or treating Bun as the browser runtime.
  • Dropping tests, weakening lint rules or benchmark budgets, or silently using Node to complete otherwise incompatible project commands.
  • Replacing security scanners, changing registry publication policy, provisioning CI credentials, modifying branch protections or activation settings, creating releases, publishing this spec, or deploying the application.
  • Rewriting compatible Node API imports solely because their names mention Node.

Further Notes

This spec records the decisions made in the interview. The architecture record remains proposed, and no migration implementation or compatibility proof exists. The glossary receives no new terms because the choices concern general tooling, rather than new leave-planning concepts.

Remaining verification and unresolved requirements:

  • Angular compilation, test-resource loading, serializers, mocking, isolation, and the existing worker harnesses must work under the native Bun runner.
  • Standalone TypeScript 7 diagnostics must be checked alongside Angular's TypeScript 6 diagnostics; their coexistence is agreed, but project-specific differences have not been measured.
  • Current Istanbul reports include text, HTML, and Cobertura. Native coverage equivalence and report-format support have not been established; accepting a reduced capability or different downstream format has not been agreed.
  • Third-party Gitea checkout and artifact actions may impose their own Node requirement. Identify the actual platform constraint; no exception allowing project commands to fall back to Node has been agreed, and CI infrastructure changes beyond the migration require a separate decision.
  • The exact Bun release and container compatibility remain to be verified. The local installation currently lacks the documented native lint, format, and standalone type-check commands.

Research checked on 2026-10-17: