Commit Graph
305 Commits
Author SHA1 Message Date
nessarandClaude Opus 5.5 31cb4a499c fix(planning): recalibrate the duration estimate to the faster engine
CI / validate (push) Successful in 36s
CI / build (push) Successful in 23s
CI / validate (pull_request) Successful in 25s
CI / benchmark (push) Successful in 1m29s
CI / security (push) Successful in 1m10s
CI / build (pull_request) Successful in 23s
CI / test (push) Successful in 2m16s
CI / security (pull_request) Successful in 1m0s
CI / images (push) Successful in 59s
CI / required (push) Successful in 1s
CI / images (pull_request) Successful in 53s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 20s
CI / policy (pull_request) Successful in 8s
CI / benchmark (pull_request) Successful in 1m27s
CI / test (pull_request) Successful in 2m6s
Rendered waits after #302, in throttled headless Chromium, were well
below the shown ranges: two years waited 1.9 s against 3-24 s, three
years 4.5 s against 11-68 s, and the loaded year 4.0 s against 4-26 s.
The prior keeps its structure with refitted, rounded constants,
400 + 250 x (D/365.25)^0.5 x (P/30)^1.5 x R, which stays within about
1.2 times of all six measured configurations. Five years with 30 days
per year now shows 6-37 s instead of 44-265 s. Local refinement is
unchanged.

The 4x CPU throttle slows only the main thread, not the planning
worker, so phones can still wait longer than these desktop samples.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 23:31:28 +02:00
nessarandClaude Opus 5.5 75320da685 docs(benchmark): compare engines by hand before each frozen-engine rebuild
A standing "no worse than the previous engine" check is not added to
CI: the differential check already fails on unintended changes, and a
fixed acceptance threshold would need renegotiating with every
deliberate change. Instead, the rebuild procedure now runs the
comparison while the frozen engine is still the previous one, and
records it with the change. The runner compares against the frozen
engine by default and takes `calibration` to reproduce the #302 record.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 22:12:50 +02:00
nessarandClaude Opus 5.5 fe705fe618 fix(planning): keep counterfactual moves off the shared final plan
CI / validate (push) Successful in 46s
CI / build (push) Successful in 25s
CI / validate (pull_request) Successful in 26s
CI / benchmark (push) Successful in 1m28s
CI / security (push) Successful in 1m11s
CI / build (pull_request) Successful in 23s
CI / test (push) Successful in 2m27s
CI / security (pull_request) Successful in 1m0s
CI / required (push) Successful in 1s
CI / images (pull_request) Successful in 54s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 28s
CI / policy (pull_request) Successful in 7s
CI / benchmark (pull_request) Successful in 1m33s
CI / images (push) Successful in 1m0s
CI / test (pull_request) Successful in 2m6s
Since assigning a date shares unchanged activations with the parent
state, counterfactual analysis edited an activation it shared with the
final plan, so a later alternative date could inherit an earlier one's
dates and be judged eligible. It now replaces the moved activation.
Every counterfactual over seeds 280000-289999 matches the engine before
the sharing step again.

When every one of several obligation solutions fails earned-entitlement
chronology, the planner again reports the obligation conflict, as when
every preview failed. No seeded request reaches that path, so the
frozen engine is unchanged.

Also marks the ranking's known limit as a shortcut and fixes stale
documentation found in review.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:49:55 +02:00
nessarandClaude Opus 5.5 676ea24410 test(benchmark): tighten the relative gate to the measured speed
After #302, the development machine's protocol takes about 41 seconds
instead of 232. The budget multipliers now add about 1.5 times headroom
to the new ratios (0.1 for typed obligations, which leaves room for
runner jitter), and the hang guard drops from 600 to 240 seconds, with
a 210-second test timeout: about three times the expected run on
srvhome, which is about 1.9 times slower than nessar-desktop.

Part of #286 and #302. The gate still needs a passing CI benchmark on
two runners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:36:37 +02:00
nessarandClaude Opus 5.5 6c9ff4ae34 test(planning): rebuild the frozen engine from the obligation ranking
The frozen engine of the differential check is rebuilt from 8168137,
which plans from the best-ranked obligation solution, with the
documented build command. The check passes again, including its
cancelled asynchronous comparisons and generator-coverage assertions.
The calibration engine stays at a871f8f.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:18:40 +02:00
nessarandClaude Opus 5.5 8168137cd5 perf(planning): plan from the best-ranked obligation solution
With several obligation solutions, the planner ran the whole preference
chain on candidate solutions as previews: every solution after a
complete enumeration, or the eight best-ranked after a truncated window
search. It now orders all solutions by the existing pre-preference
ranking (active objectives, then tie-breaks, of each obligation-only
plan; equal ranks keep enumeration order) and runs the preference
stages once, on the first. If that run ends with earned leave available
only after its final merged time-off period, the stages restart on the
next solution, so a request that planned before never becomes a
conflict.

The loaded year drops from 43 to 5.5 seconds and typed obligations from
3.3 to 0.1 seconds, with byte-identical benchmark plans. Over the 5,000
seeded requests, 23 plans become worse (9 on a real objective) and 1
better; over 50 loaded-year-sized requests, 4 become worse on a real
objective. ADR 0010 records the decision; docs/benchmark/issue-302.md
records the comparison and the opt-in runner that reproduces it.

The frozen-engine check fails until the frozen engine is rebuilt from
this commit in the next one.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 21:18:06 +02:00
nessarandClaude Opus 5.5 aa6a0c6f1b perf(planning): copy only the debited balance when assigning a date
Assigning a date copied every balance and every earned activation.
Balances and activations are only edited right after a state copies
them, so the new state now shares them with its parent, except the
balance it debits. Placement copying is unchanged.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 20:08:12 +02:00
nessarandClaude Opus 5.5 9d9404c3db perf(planning): validate each optimization configuration once
Every objective evaluation revalidated its optimization configuration.
Rule normalization already validates each configuration once per
calculation and keeps its own copy, the presets are constant, and the
summed variant of a valid configuration stays valid, so the core now
scores them without revalidating. evaluateOptimization still validates
for other callers.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 20:03:22 +02:00
nessarandClaude Opus 5.5 b7ec411c92 perf(planning): yield between asynchronous slices without a timer
Each slice of the asynchronous adapter waited for a zero-delay timer:
about 1.1 ms in Bun, and at least 4 ms in browsers once timers nest.
Browsers now yield through a message-channel task. Bun runs port
messages ahead of timers and incoming worker messages, which starved
cancellation and heartbeats, so it yields with setImmediate. Both still
let queued cancellation and heartbeat tasks run between slices.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:58:40 +02:00
nessarandClaude Opus 5.5 2fcba758c8 perf(planning): retain the best valid plan more cheaply
Retaining a better valid plan reconciled its optimization provenance,
which evaluated every active objective once per credited placement with
that placement released. Only the credited objectives are compared, so
the released plan now evaluates just those and skips observing the
others. Retention also stops computing quality metrics that nothing
read. The retained plan and what Cancel returns are unchanged.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:50:58 +02:00
nessarandClaude Opus 5.5 0b0bb8f9a8 perf(planning): reuse the donor ranking across public-holiday weeks
The holiday-week stage ranked every placement as a donor once per
public-holiday week, although the ranking depends only on the plan. The
weeks of one plan now share each placement's released objectives; each
week still skips its own dates and walks the placements in the same
order with the same yields.

Part of #302.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:45:21 +02:00
nessarandClaude Opus 5.5 b356117263 test(benchmark): keep the a871f8f engine as a fixed calibration engine
The differential check's frozen bundle will be rebuilt for #302; the
relative gate keeps timing the unchanged a871f8f bundle so its ratios
stay comparable with the recorded history.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 19:14:28 +02:00
nessar ba05fe88b3 chore(deps): update node.js to v24.22.0
CI / build (push) Successful in 34s
CI / validate (push) Successful in 2m4s
CI / security (push) Successful in 1m33s
CI / benchmark (push) Successful in 4m34s
CI / test (push) Successful in 4m49s
CI / required (push) Successful in 1s
CI / policy (push) Successful in 10s
CI / images (push) Successful in 2m19s
2026-10-18 13:32:24 +02:00
nessarandClaude Opus 5.5 cc3664454a docs(ci): note the Node 24.22.0 job containers
CI / validate (push) Successful in 32s
CI / security (push) Successful in 57s
CI / test (push) Successful in 3m29s
CI / build (push) Successful in 2m57s
CI / benchmark (push) Successful in 5m4s
CI / security (pull_request) Successful in 1m37s
CI / validate (pull_request) Successful in 7m13s
CI / build (pull_request) Successful in 4m55s
CI / required (push) Successful in 1s
CI / images (pull_request) Successful in 1m23s
CI / required (pull_request) Successful in 2s
CI / policy (push) Successful in 8s
CI / policy (pull_request) Successful in 9s
CI / test (pull_request) Successful in 3m26s
CI / images (push) Successful in 1m8s
CI / benchmark (pull_request) Successful in 7m33s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 13:15:53 +02:00
renovate Bot c70339972a chore(deps): update node.js to v24.22.0 2026-10-18 13:15:53 +02:00
nessar 711c9e00c3 chore(deps): update https://gitea.com/actions/checkout action to v7
CI / build (push) Successful in 35s
CI / security (push) Successful in 1m46s
CI / test (push) Successful in 3m44s
CI / validate (push) Successful in 4m19s
CI / benchmark (push) Successful in 5m15s
CI / required (push) Successful in 5s
CI / policy (push) Successful in 8s
CI / images (push) Successful in 1m25s
2026-10-18 13:15:21 +02:00
renovate Bot f56b66e10c chore(deps): update https://gitea.com/actions/checkout action to v7
CI / build (push) Successful in 34s
CI / security (push) Successful in 1m44s
CI / validate (push) Successful in 2m25s
CI / validate (pull_request) Successful in 55s
CI / test (push) Successful in 5m14s
CI / build (pull_request) Successful in 24s
CI / benchmark (push) Successful in 5m43s
CI / security (pull_request) Successful in 1m4s
CI / required (push) Successful in 2s
CI / images (pull_request) Successful in 1m18s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 9s
CI / policy (pull_request) Successful in 10s
CI / test (pull_request) Successful in 3m30s
CI / images (push) Successful in 2m22s
CI / benchmark (pull_request) Successful in 5m56s
2026-10-18 13:03:56 +02:00
nessar 5ee95fe9ca chore(deps): update https://gitea.com/actions/upload-artifact action to v7
CI / validate (push) Successful in 34s
CI / security (push) Successful in 55s
CI / build (push) Successful in 3m22s
CI / test (push) Failing after 4m57s
CI / benchmark (push) Successful in 8m0s
CI / required (push) Failing after 2s
CI / policy (push) Successful in 16s
CI / images (push) Skipped
2026-10-18 00:07:18 +02:00
renovate Bot 389f6eb7e2 chore(deps): update https://gitea.com/actions/upload-artifact action to v7
CI / validate (push) Successful in 23s
CI / test (push) Successful in 4m39s
CI / security (push) Successful in 1m48s
CI / validate (pull_request) Successful in 35s
CI / benchmark (push) Successful in 7m10s
CI / build (pull_request) Successful in 51s
CI / security (pull_request) Successful in 1m51s
CI / build (push) Successful in 10m40s
CI / images (push) Successful in 1m15s
CI / required (push) Successful in 2s
CI / images (pull_request) Successful in 2m29s
CI / required (pull_request) Successful in 2s
CI / policy (push) Successful in 8s
CI / policy (pull_request) Successful in 11s
CI / test (pull_request) Successful in 3m30s
CI / benchmark (pull_request) Successful in 5m4s
2026-10-17 23:45:07 +02:00
nessar 880efe4e90 chore(deps): update angular-cli monorepo to v22.2.3
CI / validate (push) Successful in 36s
CI / security (push) Successful in 55s
CI / build (push) Successful in 6m46s
CI / benchmark (push) Successful in 7m56s
CI / test (push) Successful in 12m52s
CI / required (push) Successful in 3s
CI / policy (push) Successful in 17s
CI / images (push) Successful in 2m4s
2026-10-17 23:44:49 +02:00
nessarandClaude Opus 5.5 c59d75e526 chore(deps): update angular-cli monorepo to v22.2.3
CI / validate (push) Successful in 49s
CI / security (push) Successful in 1m0s
CI / test (push) Successful in 3m7s
CI / validate (pull_request) Successful in 1m56s
CI / build (push) Successful in 4m45s
CI / build (pull_request) Successful in 1m6s
CI / security (pull_request) Successful in 1m4s
CI / benchmark (push) Successful in 7m57s
CI / required (push) Successful in 3s
CI / images (pull_request) Successful in 2m8s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 10s
CI / policy (pull_request) Successful in 8s
CI / test (pull_request) Successful in 5m23s
CI / images (push) Successful in 1m17s
CI / benchmark (pull_request) Successful in 5m30s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 23:31:52 +02:00
nessar b086f1ffc8 fix(deps): update angular monorepo to v22.2.3
CI / build (push) Successful in 33s
CI / validate (push) Successful in 1m17s
CI / security (push) Successful in 1m48s
CI / test (push) Successful in 3m12s
CI / benchmark (push) Successful in 5m54s
CI / required (push) Successful in 2s
CI / policy (push) Successful in 13s
CI / images (push) Successful in 1m39s
2026-10-17 23:27:45 +02:00
renovate Bot 813d9b4d7f fix(deps): update angular monorepo to v22.2.3
CI / validate (push) Successful in 37s
CI / build (push) Successful in 35s
CI / security (push) Successful in 1m38s
CI / validate (pull_request) Successful in 37s
CI / test (push) Successful in 3m53s
CI / benchmark (push) Successful in 5m15s
CI / security (pull_request) Successful in 1m5s
CI / build (pull_request) Successful in 5m47s
CI / required (push) Successful in 2s
CI / images (pull_request) Successful in 1m17s
CI / required (pull_request) Successful in 2s
CI / policy (push) Successful in 13s
CI / policy (pull_request) Successful in 7s
CI / test (pull_request) Successful in 5m5s
CI / images (push) Successful in 1m59s
CI / benchmark (pull_request) Successful in 7m58s
2026-10-17 23:07:08 +02:00
nessar 9158966982 chore(deps): update docker docker tag to v29.9.1
CI / validate (push) Successful in 1m58s
CI / build (push) Successful in 2m31s
CI / security (push) Successful in 1m3s
CI / benchmark (push) Successful in 5m5s
CI / test (push) Successful in 8m8s
CI / required (push) Successful in 3s
CI / policy (push) Successful in 11s
CI / images (push) Successful in 1m0s
2026-10-17 23:05:22 +02:00
nessarandClaude Opus 5.5 d9c7f72461 docs(ci): note the Docker 29.9.1 image
CI / build (push) Successful in 40s
CI / security (push) Successful in 1m44s
CI / test (push) Successful in 3m6s
CI / validate (pull_request) Successful in 39s
CI / benchmark (push) Successful in 9m44s
CI / build (pull_request) Successful in 1m33s
CI / security (pull_request) Successful in 1m1s
CI / validate (push) Successful in 11m34s
CI / images (pull_request) Successful in 2m42s
CI / required (pull_request) Successful in 1s
CI / required (push) Successful in 5s
CI / policy (push) Successful in 8s
CI / policy (pull_request) Successful in 10s
CI / test (pull_request) Successful in 5m18s
CI / benchmark (pull_request) Successful in 7m56s
CI / images (push) Successful in 1m25s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:24:11 +02:00
renovate Bot 1636355920 chore(deps): update docker docker tag to v29.9.1 2026-10-17 21:23:53 +02:00
nessar 85fc4561fd build: run the project on Bun 1.4.3
CI / validate (push) Successful in 38s
CI / build (push) Successful in 24s
CI / security (push) Successful in 1m42s
CI / test (push) Successful in 2m48s
CI / benchmark (push) Successful in 4m48s
CI / required (push) Successful in 1s
CI / policy (push) Successful in 19s
CI / images (push) Successful in 58s
close #289, close #291, close #292

See pull request #299
2026-10-17 18:28:42 +02:00
nessarandClaude Opus 5.5 282d9c6787 fix: report line-only coverage honestly and tighten Bun test helpers
CI / validate (push) Successful in 41s
CI / build (push) Successful in 36s
CI / validate (pull_request) Successful in 32s
CI / security (push) Successful in 1m3s
CI / test (push) Successful in 3m3s
CI / build (pull_request) Successful in 23s
CI / security (pull_request) Successful in 57s
CI / benchmark (push) Successful in 5m19s
CI / images (push) Successful in 1m20s
CI / required (push) Successful in 3s
CI / images (pull_request) Successful in 54s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 7s
CI / policy (pull_request) Successful in 10s
CI / test (pull_request) Successful in 3m25s
CI / benchmark (pull_request) Successful in 4m48s
The generated HTML and Cobertura reports no longer show unmeasured
branch and function coverage as 100%. Poll and waitFor deadlines use
performance.now so frozen dates cannot make them loop forever, the
malformed-configuration test covers undefined again next to the empty
array, compose health checks honor PORT, and the migration spec lists
only what is still open.

Refs #291, #292, #293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 16:10:29 +02:00
nessarandClaude Opus 5.5 dfe6d28d2b test(planning): make the checkpoint cancellation test deterministic
The cancelled stage takes about a millisecond, so under load the worker
could finish it before the cancel message arrived and report it as
completed. The real-worker harness now holds the worker after reporting
that stage until the cancel is delivered, keeping every assertion.

Refs #291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 15:57:33 +02:00
nessarandClaude Opus 5.5 ac69a41fc8 ci: run development, quality checks and CI on Bun 1.4.3
Pin Bun 1.4.3 with packageManager, and force every bun run script onto
the Bun runtime through bunfig so ng, ESLint and Prettier never fall
back to an installed Node. Type checking uses bun check for the
application and test projects, next to the Angular build.

CI jobs install the pinned release from a checksum-verified download
instead of npm and run project steps in a shell without Node on PATH,
which stays available only for the checkout and upload actions. The
image test's fake docker runs on Bun.

Refs #290, #293

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 14:25:46 +02:00
nessarandClaude Opus 5.5 f74d744f9b feat(server): serve the client-only build with Bun
Angular's server build needs Node loader hooks that Bun does not apply,
and every route is client-rendered, so Angular now builds a client-only
bundle and a small Bun.serve server delivers it: hashed assets with the
one-year cache, index.html revalidated, extension-less routes falling
back to index.html, missing assets 404, traversal and malformed paths
rejected, and other methods 405. Express, @angular/ssr and the unused
hydration provider are removed. Both Docker stages use the pinned
oven/bun:1.4.3-alpine image without Node, and the health checks use
Bun's fetch.

Refs #292

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:50:05 +02:00
nessarandClaude Opus 5.5 94d57add2c test: run the suite and benchmark with Bun's native test runner
Replace Vitest with bun test across the whole suite. A preload compiles
components through Angular's JIT transform with inlined templates, sets
up jsdom, TestBed and zoneless change detection, and a small shim covers
the Vitest APIs bun:test lacks. Files run isolated, real-worker specs
spawn the running Bun, and line coverage from lcov is converted to the
existing HTML and Cobertura reports. The CI benchmark replaces its heap
cap with a container memory limit. Vitest, Jest, Nx and their Vite
configuration are removed.

Refs #291

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 13:40:42 +02:00
nessarandClaude Opus 5.5 558c70aa24 docs(adr): record Bun 1.4.3 verification results and decisions
Stable Bun 1.4.3 runs installs, the development server, standalone type
checks, the native test runner and a Bun.serve static server. Native
lint/fmt are canary-only, and Angular's server build needs Node loader
hooks Bun does not apply, so the spec now keeps ESLint/Prettier until a
stable release, builds Angular client-only behind a Bun static server,
converts line coverage from lcov, and replaces the heap cap with a
container memory limit.

Refs #289

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 12:49:17 +02:00
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
nessar 752c8b7a99 refactor(planning): consolidate calculation, projection and worker ownership
CI / validate (push) Successful in 57s
CI / build (push) Successful in 57s
CI / security (push) Successful in 1m1s
CI / test (push) Successful in 3m12s
CI / benchmark (push) Successful in 7m13s
CI / required (push) Successful in 1s
CI / policy (push) Successful in 11s
CI / images (push) Successful in 1m10s
close #274, close #275, close #276, close #277

See pull request #298
2026-10-17 11:53:19 +02:00
nessarandClaude Opus 5.5 cee67ce3df refactor(calendar): drop the unused projection horizon
CI / validate (push) Successful in 1m2s
CI / build (push) Successful in 1m27s
CI / security (push) Successful in 1m12s
CI / validate (pull_request) Successful in 1m21s
CI / benchmark (push) Successful in 4m10s
CI / test (push) Successful in 4m19s
CI / security (pull_request) Successful in 1m3s
CI / build (pull_request) Successful in 34s
CI / required (push) Successful in 3s
CI / images (pull_request) Successful in 1m56s
CI / required (pull_request) Successful in 2s
CI / policy (push) Successful in 7s
CI / policy (pull_request) Successful in 11s
CI / test (pull_request) Successful in 3m23s
CI / images (push) Successful in 1m34s
CI / benchmark (pull_request) Successful in 7m13s
No caller read CalendarProjection.horizon, and with fixed months it no
longer described the listed months.

Refs #276

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:36:19 +02:00
nessarandClaude Opus 5.5 a472347a5e fix(calendar): keep declaration-entry months fixed while editing
Declaring a date at the edge of the planning period widened the
projection and inserted a disabled month above the grid. Declaration
entry now lists only the planning period's months, while selections
keep the connected-period widening.

Refs #276

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:29:31 +02:00
nessarandClaude Opus 5.5 feb651148e fix(planning): react only to calculations started by the mounted calendar
Re-mounting the calendar no longer records a duration sample or
announces the previous result, explanation or rejected explanation.
Starting a calculation during a cancellation announces loading and
keeps focus where it is. Only rejected explanation deliveries are
announced, as before. Replacement tests now replace a real plan.

Refs #275, #274

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:22:38 +02:00
nessarandClaude Opus 5.5 43677ff434 refactor(planning): drop the unreachable late worker message guard
release() already clears the worker handlers, so the released checks
inside them could never run. The lifetime test now states what it
checks: no handler is left for late messages.

Refs #277

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:22:38 +02:00
nessarandClaude Opus 5.5 502d561f6f refactor(calendar): encapsulate calendar projection and selection ranges
CalendarService.project returns the covered months together with the
projected selections, so month enumeration and selected-day rendering
share one projection horizon. SelectedDates is built once from the
complete range list and groups connected periods internally, exposing
read-only selection, boundary and day-type queries.

In declaration entry, months reached by adjacent declared or
non-working days are now shown, matching the projected selections.

Refs #276

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:18:33 +02:00
nessarandClaude Opus 5.5 5cb0b93339 refactor(planning): give planning calculations one state owner
PlanningCalculationService now builds the submitted request, owns the
pending and accepted calculation state, and delivers explanations for
the accepted calculation only. The duration estimator reads the same
request. The calendar and leave-balance summary consume the accepted
outcome instead of coordinating writable state on the input service.

Refs #275

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:11:37 +02:00
nessarandClaude Opus 5.5 b69b3c3690 refactor(planning): give planning workers one lifetime owner
Planning, counterfactual analysis and checkpoint explanation now share
one internal worker-job owner for creation, handler cleanup,
termination and supersession, and one request/response message
contract between the coordinator and the worker. Job-specific progress,
checkpoint recovery and completion rules stay explicit.

Refs #277

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:11:37 +02:00
nessarandClaude Opus 5.5 7fc2b33587 refactor(planning): remove the unused remaining-balance mirror
The summary and details already read the displayed plan's remaining
balances, so the writable mirror, its legacy conversion and the VacDay
classification/reason fields it alone populated are removed.

Refs #274

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 11:05:51 +02:00
nessar 40a11c245a perf(planning): incremental exact scoring for the loaded year
CI / validate (push) Successful in 57s
CI / build (push) Successful in 1m1s
CI / security (push) Successful in 54s
CI / test (push) Successful in 3m9s
CI / benchmark (push) Successful in 7m25s
CI / required (push) Successful in 1s
CI / policy (push) Successful in 6s
CI / images (push) Successful in 1m10s
close #280

See pull request #287
2026-10-17 02:18:27 +02:00
nessarandClaude Opus 5.5 3bbe989eca test(benchmark): print a readable summary table
CI / validate (push) Successful in 1m5s
CI / build (push) Successful in 1m38s
CI / security (push) Successful in 1m19s
CI / test (push) Successful in 3m29s
CI / validate (pull_request) Successful in 1m42s
CI / benchmark (push) Successful in 4m13s
CI / security (pull_request) Successful in 56s
CI / build (pull_request) Successful in 1m42s
CI / required (push) Successful in 1s
CI / images (pull_request) Successful in 1m11s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 7s
CI / policy (pull_request) Successful in 10s
CI / test (pull_request) Successful in 3m8s
CI / images (push) Successful in 1m15s
CI / benchmark (pull_request) Successful in 3m37s
Print the calibration and a Markdown table with one aligned row per
scenario as soon as it finishes: both planning times, mean, budget, ratio,
multiplier, outcome, placements, determinism and budget status. Write
directly to stdout so Vitest adds no per-line headers. The complete TSV
report still follows the table.

Refs #281, #285

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 02:09:54 +02:00
nessarandClaude Opus 5.5 cfdb28c90a ci(benchmark): size the hang guard for the slowest runner
CI / validate (push) Successful in 53s
CI / build (push) Successful in 1m18s
CI / security (push) Successful in 1m12s
CI / validate (pull_request) Successful in 1m18s
CI / benchmark (push) Successful in 3m56s
CI / test (push) Successful in 4m6s
CI / build (pull_request) Successful in 36s
CI / security (pull_request) Successful in 1m5s
CI / required (push) Successful in 1s
CI / images (pull_request) Successful in 1m50s
CI / required (pull_request) Successful in 1s
CI / policy (push) Successful in 6s
CI / policy (pull_request) Successful in 9s
CI / test (pull_request) Successful in 3m2s
CI / images (push) Successful in 1m15s
CI / benchmark (pull_request) Successful in 7m18s
The first PR run landed on srvhome, about 1.9 times slower than
nessar-desktop. The fixed 300-second timeout killed its protocol during the
loaded year, although every completed scenario was within its relative
budget. Raise the CI timeout to 600 seconds and the test timeout to 570
seconds so they only guard against hangs, and record the first CI-runner
ratios.

Refs #285

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 01:40:41 +02:00
nessarandClaude Opus 5.5 63b50c4311 docs(benchmark): record the remaining gap to the speed target
CI / validate (push) Successful in 1m1s
CI / build (push) Successful in 1m27s
CI / security (push) Successful in 1m16s
CI / validate (pull_request) Successful in 1m34s
CI / benchmark (push) Successful in 4m31s
CI / test (push) Successful in 4m36s
CI / build (pull_request) Successful in 39s
CI / security (pull_request) Successful in 1m11s
CI / required (push) Successful in 1s
CI / images (pull_request) Skipped
CI / required (pull_request) Failing after 2s
CI / policy (push) Successful in 6s
CI / policy (pull_request) Successful in 9s
CI / test (pull_request) Successful in 3m24s
CI / images (push) Successful in 1m16s
CI / benchmark (pull_request) Failing after 6m0s
The exact optimizations bring the loaded year from 66.0 s to 44.1 s, but the
target of 10 s for the loaded year and 3 s for the other scenarios is not
reached for the loaded year, typed obligations and three years. Record the
gap and the remaining profile, keep the relative-gate multipliers and the
300-second hang guard unchanged, and note that ADR 0003's five-second target
should be revisited together with a decision on search changes.

Refs #286

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:45:28 +02:00
nessarandClaude Opus 5.5 acdb19352a ci(benchmark): gate scenario speed relative to the runner
Before the protocol, time the frozen engine on the two-year scenario, best
of three, and fail any scenario whose mean planning time exceeds its
multiplier times that calibration. Multipliers come from development-machine
ratios with about 1.5x headroom until #286 tightens them. The 300-second
timeout stays only as a hang guard. The benchmark keeps running on push and
pull_request events because the push run gates image publication.

This replaces the absolute 300-second acceptance protocol named in #78.

Refs #285

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:45:28 +02:00
nessarandClaude Opus 5.5 68a9e33de6 perf(planning): prune candidates that cannot beat the protected prefix
Finalizing a candidate never moves or retypes a placement, so preference
results and calendar optimizations already have their final values before
it, and leave-balance optimizations do too when nothing can be earned.
Reject a candidate before finalizing when the first differing such
objective of the protected prefix is worse than the baseline. Leave-placement
objectives and earning contexts stop the walk.

The frozen-engine check now also compares cancelled asynchronous runs,
including checkpoints and retained incumbents. The loaded year drops from
48.5 s to 44.3 s; outcomes, explanations and final states are unchanged.

Refs #284

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 00:45:28 +02:00
nessarandClaude Opus 5.5 7890a03a74 perf(planning): update plan observations incrementally
Cache an immutable occupancy per placements map and derive a candidate's
time-off period groups, holiday-week completeness and placement tie key
from its parent when one date is added or removed. The from-scratch
computation stays as the test oracle and an opt-in shadow mode. A
fast-check property test compares both after every operation.

The loaded year drops from 66.5 s to 48.5 s and the protocol from 262.0 s
to 193.7 s. Outcomes, explanations and final states stay identical.

Refs #283

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