release: promote beta to main#1700
Open
steilerDev wants to merge 50 commits into
Open
Conversation
…d duration to daily log (#1673) * feat(diary): add optional vendor and work start/end time with computed duration to daily log Extends daily_log diary entries with three new optional fields: vendor (via SearchPicker), work start time, and work end time (both HH:mm 24h inputs). The server resolves vendorName from vendorId for display. A computed duration (hours, 2 decimal places) is calculated client-side and shown inline between the time inputs. Cross-field validation rejects end ≤ start. DiaryMetadataSummary renders the new fields for saved entries. German translations and full unit + E2E test coverage included. Fixes #1672 Co-Authored-By: Claude dev-team-lead (Sonnet 4.6) <[email protected]> Co-Authored-By: Claude backend-developer (Haiku 4.5) <[email protected]> Co-Authored-By: Claude frontend-developer (Haiku 4.5) <[email protected]> Co-Authored-By: Claude translator (Sonnet 4.6) <[email protected]> Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <[email protected]> Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <[email protected]> * test(diary): add computeWorkDuration to formatters mock factories DiaryMetadataSummary now re-exports computeWorkDuration from formatters.js, so any test file that mocks formatters.js and transitively imports DiaryMetadataSummary must include the export or the suite fails with a SyntaxError. Add computeWorkDuration to the mock factories in DiaryPage.test.tsx and DiaryEntryDetailPage.area.test.tsx (matching the style of each file's existing computeActualDuration stub). Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <[email protected]> --------- Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…items (#1678) Previously, when auto-itemizing an invoice, line items where `includesVat` is `false` (net prices) were summed at their raw stored value without applying the applicable VAT rate. This caused the computed auto-itemize total to be ~19% lower than the actual gross amount, producing a false variance on the invoice and triggering a spurious `TOTAL_MISMATCH` error during itemized-sum validation. The fix introduces a shared helper `effectiveLineAmount(line)` in `@cornerstone/shared` that returns the gross-equivalent amount for any line: `amount * (1 + vatRate)` for net lines and `amount` for gross (includesVat=true) lines. All total-computation paths in `invoiceAutoItemizeService` now use this helper. Storage is unchanged — line amounts are still persisted as net; the VAT gross-up is applied only at aggregation time. Fixes #1677 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
#1684) Hoisted 52 inline `import()` type annotations to top-of-file `import type` declarations across 23 test and page-object files (14 client, 4 server, 5 e2e). No runtime behavior change — purely mechanical lint compliance. Fixes #1458 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…ollision (#1685) Add an exact-version override (10.3.0) for the `konva` package in the root `package.json` so the entire workspace tree hoists a single Konva copy. Without this override the root package had no Konva entry while `@cornerstone/client` depended on it directly, allowing npm to silently resolve two different Konva versions under certain install conditions and causing TypeScript type-collision errors. Also adds `scripts/check-single-dep-version.sh`, a guardrail script that asserts exactly one version of a given package is present across the `node_modules` tree. The script is wired into the Static Analysis job in `ci.yml` so that any future Konva version drift fails CI immediately. Fixes #1646 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…rlay (#1680) Replaces the hidden context-menu unlink action with a visible overlay button on LinkedDocumentCard that appears on hover/focus. Also fixes a bug where the unlink-confirmation modal's Cancel button rendered a raw i18n key instead of the translated string (was using `t('button.cancel')` without the required `common:` namespace prefix). Fixes #1680 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…re usable (#1688) (#1689) Fixes #1688 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…arnings (#1469) (#1690) Adds justified inline eslint-disable directives (with -- reason comments) and renames stale `react-hooks/exhaustive-deps` directives to the real rule `@eslint-react/exhaustive-deps` across 45 client/src/ files. All changes are comment-only or behavior-neutral dependency-array reformats; no logic or rendering behavior is altered. The inline disables are explicitly permitted by the issue's acceptance criteria where refactoring would require non-trivial state-model changes. Verified result: zero remaining set-state-in-effect errors, zero @eslint-react/exhaustive-deps errors, zero stale-rule "Definition for rule not found" errors, zero unused-disable directives. Net ESLint error count drops by 20 vs beta HEAD with no new errors introduced. Fixes #1469 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…-pattern (#1568) (#1686) * test(infra): fix per-render useNavigate jest.fn() anti-pattern in LinkedDocumentsSection Replace `useNavigate: () => jest.fn()` with a stable module-scope mock (`const mockNavigate = jest.fn()`) that is cleared in beforeEach. The per-render pattern allocates a new function object on every component render/re-render within a test, which inflates Jest worker heap over time when the test suite has many renders. The stable module-scope mock reuses the same function across all renders in a test run. This is Phase 4 from issue #1568 (Jest memory audit). Phases 2-3 (shared formatters mock factory via static import) were investigated but cannot be delivered: adding a static `import` before `jest.unstable_mockModule` in Jest 30 ESM VM mode causes the mock to fail to intercept the real module in CI (shards 1, 2), even though the factory itself is sound. The inline factory pattern is required for reliable mock registration in Jest ESM. Fixes #1568 Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <[email protected]> * chore(memory): document Jest ESM static-import mock constraint from issue #1568 investigation Co-Authored-By: Claude qa-integration-tester (Sonnet 4.6) <[email protected]> --------- Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude qa-integration-tester (Sonnet 4.6) <[email protected]>
…1463) (#1691) Replace `any` with `unknown` or precise types where the shape is known, and mark genuine boundary escape hatches (Fastify decorators, dynamic drizzle table rows, schema-erased DB handles, WebDAV inject verbs) with reasoned per-line eslint-disable comments. Type-only changes; no runtime or test-behavior changes. Fixes #1463 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude backend-developer (Haiku 4.5) <[email protected]>
Added a Node-scripts flat-config block in eslint.config.js (Node globals + no-console: off for scripts/**) ordered after the General rules block, clearing 171 no-undef/no-console problems in scripts/*.mjs. Real fixes in server/src (calendarIcal, diaryService: no-useless-assignment), shared/src (diary.ts: no-empty-object-type interface→type alias), and client/src (no-unused-vars, no-case-declarations, preserve-caught-error cause, IIFE-in-JSX extraction, useState setter renames). Justified inline disables in client/src where no stable id exists for keys, render-time `new Date()` is intentional, DOM-measurement useEffect/setState patterns are correct, and naming collisions exist in LocaleContext/ThemeContext. Test file disables cover error-boundaries/rules-of-hooks edge cases. Dead-variable removals in e2e/tests (no-useless-assignment, no-unused-vars, no-self-assign) with no behavior or assertion changes. Full-project `eslint .` now reports 0 errors and 0 warnings (down from 857 at the start of the #1455 tracking issue; all 16 child issues already closed). Fixes #1455 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…h, jsx-no-children-prop) (#1696) - Rename local `async function fetch()` in useTimeline.ts to `loadTimeline` to eliminate the false-positive @eslint-react/web-api-no-leaked-fetch warning (the function is not the Web Fetch API, but shares the name) - Add justified eslint-disable-next-line for LinkedDocumentsSection.tsx where `systemLinkedIds.fetch()` is a custom hook method, not the Web Fetch API — the rule cannot distinguish call sites by type - Move `children` from the React.createElement props object to the 3rd positional argument at two call sites in PhotoMetadataSidepanel.test.tsx to fix jsx-no-children-prop; behavior-identical refactor All changes are behavior-preserving. `eslint .` now reports 0 errors and 0 warnings across the full client workspace, completing the clean-lint baseline established by #1455. Ref #1455 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
… orientation metadata (#1674) Mobile-first photo upload: Take photo / Upload photo split on touch devices, per-photo metadata capture modal (description, hierarchical area, orientation) with non-blocking background upload queue, new user-configurable Orientation entity (settings CRUD + nullable photos.orientation_id FK, SET NULL on delete), OrientationPicker showing name + description, orientation field in the photo metadata sidepanel, and the orientation-selector empty-state hint. Fixes #1674. Fixes #1675.
#1681) Adds a Paperless-first invoice creation flow on Budget → Invoices: when Paperless + LLM are configured, "New Invoice" opens a document picker (searchable correspondent filter, hide-already-linked default ON, open-in-Paperless link, manual-entry escape). Selecting a document runs a stateless LLM auto-itemize preview (LLM picks the vendor from the app vendor list), and the invoice + document link + budget-line itemizations are created atomically only after human review. New endpoints: GET /api/paperless/correspondents, POST /api/invoices/auto-itemize/preview, POST /api/invoices/auto-itemize/commit (ADR-032). No DB schema changes. Fixes #1679
…1693) Bumps the github-actions group with 1 update: [github/codeql-action](https://github.com/github/codeql-action). Updates `github/codeql-action` from 4.36.1 to 4.36.2 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@87557b9...8aad20d) --- updated-dependencies: - dependency-name: github/codeql-action dependency-version: 4.36.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the dev-dependencies group with 7 updates: | Package | From | To | | --- | --- | --- | | [@eslint-react/eslint-plugin](https://github.com/Rel1cx/eslint-react/tree/HEAD/plugins/eslint-plugin) | `5.8.12` | `5.8.19` | | [concurrently](https://github.com/open-cli-tools/concurrently) | `10.0.1` | `10.0.3` | | [prettier](https://github.com/prettier/prettier) | `3.8.3` | `3.8.4` | | [semantic-release](https://github.com/semantic-release/semantic-release) | `25.0.3` | `25.0.5` | | [stylelint](https://github.com/stylelint/stylelint) | `17.12.0` | `17.13.0` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.60.1` | `8.61.0` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `25.9.1` | `25.9.3` | Updates `@eslint-react/eslint-plugin` from 5.8.12 to 5.8.19 - [Release notes](https://github.com/Rel1cx/eslint-react/releases) - [Changelog](https://github.com/Rel1cx/eslint-react/blob/main/CHANGELOG.md) - [Commits](https://github.com/Rel1cx/eslint-react/commits/v5.8.19/plugins/eslint-plugin) Updates `concurrently` from 10.0.1 to 10.0.3 - [Release notes](https://github.com/open-cli-tools/concurrently/releases) - [Commits](open-cli-tools/concurrently@v10.0.1...v10.0.3) Updates `prettier` from 3.8.3 to 3.8.4 - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](prettier/prettier@3.8.3...3.8.4) Updates `semantic-release` from 25.0.3 to 25.0.5 - [Release notes](https://github.com/semantic-release/semantic-release/releases) - [Commits](semantic-release/semantic-release@v25.0.3...v25.0.5) Updates `stylelint` from 17.12.0 to 17.13.0 - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](stylelint/stylelint@17.12.0...17.13.0) Updates `typescript-eslint` from 8.60.1 to 8.61.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.0/packages/typescript-eslint) Updates `@types/node` from 25.9.1 to 25.9.3 - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@eslint-react/eslint-plugin" dependency-version: 5.8.19 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: concurrently dependency-version: 10.0.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: semantic-release dependency-version: 25.0.5 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies - dependency-name: stylelint dependency-version: 17.13.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: typescript-eslint dependency-version: 8.61.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: dev-dependencies - dependency-name: "@types/node" dependency-version: 25.9.3 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: dev-dependencies ... Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
… 8 updates (#1695) * chore(deps): bump the prod-dependencies group with 8 updates Bumps the prod-dependencies group with 8 updates: | Package | From | To | | --- | --- | --- | | [ical-generator](https://github.com/sebbo2002/ical-generator) | `10.2.0` | `11.0.0` | | [sharp](https://github.com/lovell/sharp) | `0.34.5` | `0.35.1` | | [tar](https://github.com/isaacs/node-tar) | `7.5.15` | `7.5.16` | | [i18next](https://github.com/i18next/i18next) | `26.2.0` | `26.3.1` | | [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.7` | | [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.7` | | [react-konva](https://github.com/konvajs/react-konva) | `19.2.4` | `19.2.5` | | [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) | `7.15.1` | `7.17.0` | Updates `ical-generator` from 10.2.0 to 11.0.0 - [Release notes](https://github.com/sebbo2002/ical-generator/releases) - [Changelog](https://github.com/sebbo2002/ical-generator/blob/develop/CHANGELOG.md) - [Commits](sebbo2002/ical-generator@v10.2.0...v11.0.0) Updates `sharp` from 0.34.5 to 0.35.1 - [Release notes](https://github.com/lovell/sharp/releases) - [Commits](lovell/sharp@v0.34.5...v0.35.1) Updates `tar` from 7.5.15 to 7.5.16 - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](isaacs/node-tar@v7.5.15...v7.5.16) Updates `i18next` from 26.2.0 to 26.3.1 - [Release notes](https://github.com/i18next/i18next/releases) - [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md) - [Commits](i18next/i18next@v26.2.0...v26.3.1) Updates `react` from 19.2.6 to 19.2.7 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react) Updates `react-dom` from 19.2.6 to 19.2.7 - [Release notes](https://github.com/facebook/react/releases) - [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md) - [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom) Updates `react-konva` from 19.2.4 to 19.2.5 - [Release notes](https://github.com/konvajs/react-konva/releases) - [Commits](https://github.com/konvajs/react-konva/commits) Updates `react-router-dom` from 7.15.1 to 7.17.0 - [Release notes](https://github.com/remix-run/react-router/releases) - [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md) - [Commits](https://github.com/remix-run/react-router/commits/[email protected]/packages/react-router-dom) --- updated-dependencies: - dependency-name: ical-generator dependency-version: 11.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: prod-dependencies - dependency-name: sharp dependency-version: 0.35.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies - dependency-name: tar dependency-version: 7.5.16 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: i18next dependency-version: 26.3.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies - dependency-name: react dependency-version: 19.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: react-dom dependency-version: 19.2.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: react-konva dependency-version: 19.2.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: prod-dependencies - dependency-name: react-router-dom dependency-version: 7.17.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: prod-dependencies ... Signed-off-by: dependabot[bot] <[email protected]> * fix(deps): repair react override mismatch in prod-dependencies bump Dependabot's prod-dependencies bump updated the react/react-dom edges in client/ and docs/ to 19.2.7 but left the root package.json `overrides` pinned at 19.2.6. The override forced the top-level react node to 19.2.6 while workspaces requested 19.2.7, leaving duplicate React copies in the tree. This crashed the client bundle at runtime ("Cannot read properties of null (reading 'useRef')") and failed all E2E, and corrupted the tree such that `npm audit signatures` mis-resolved the @docusaurus/react-loadable alias (ETARGET [email protected]) — failing Static Analysis. Bump the overrides to 19.2.7 to match the workspace edges and regenerate the lockfile with a clean `npm install`. react and react-dom now dedupe to a single 19.2.7 across all workspaces. Co-Authored-By: Claude backend-developer (Haiku 4.5) <[email protected]> --------- Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude backend-developer (Haiku 4.5) <[email protected]>
…tTests (#1697) - Add `workerGracefulExitTimeout: 2000` to the top-level Jest config; the 500 ms default is too tight for jsdom/file-watcher cleanup in the resource-constrained sandbox and produces spurious force-kill warnings. - Add `test:collect` and `test:collect:json` npm scripts using Jest 30.4.0's `--collectTests` flag to enumerate all test suites and names without executing them. - Document `test:collect` in CLAUDE.md Common Commands table. Fixes #1573 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude qa-integration-tester (Sonnet 4.5) <[email protected]>
…) (#1698) OrientationsTab referenced undefined CSS module classes so orientation rows rendered completely unstyled. Mapped all class references to the existing defined classes used by TradesTab and other Manage tabs (itemsList/itemRow/itemInfo/itemDetails/itemSortOrder/itemActions/ editActions/saveButton) and restructured view-mode JSX to match TradesTab layout. Added 20 unit tests covering both view and edit modes of OrientationsTab, and a deep-link E2E test verifying the Orientations tab is selected when navigating directly to #orientations. Fixes #1687 Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude dev-team-lead (Sonnet 4.6) <[email protected]>
…1714) Adopt @floating-ui/[email protected] (ADR-033) for SearchPicker dropdown positioning, replacing the hand-rolled portal/getBoundingClientRect/rAF approach. useFloating fixed-strategy + offset/flip/shift/size + autoUpdate + FloatingPortal keeps the dropdown anchored to its input during mobile momentum scroll and soft-keyboard/visualViewport shifts — the cases the prior rAF fix (#1712) could not handle. FloatingPortal preserves the #1601 anti-clipping; an isPositioned gate avoids the first-frame flash. Drops the hide() middleware (it blanked the dropdown inside modals). Fixes #1708 Co-Authored-By: Claude frontend-developer (Haiku 4.5) <[email protected]> Co-Authored-By: Claude qa-integration-tester (Sonnet 4.5) <[email protected]> Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.5) <[email protected]> Co-Authored-By: Claude product-architect (Sonnet 4.5) <[email protected]>
Contributor
|
🎉 This PR is included in version 2.8.0-beta.25 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
chore: reconcile main into beta (recover from mis-targeted #1710 squash)
Contributor
|
🎉 This PR is included in version 2.8.0-beta.26 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Adds a required-status-check workflow that fails any pull request targeting 'main' whose head branch is not 'beta'. Mark the 'guard' job as a required check on the main ruleset to block out-of-band promotions (the #1710 class of incident, where a beta-based fix branch was squash-merged directly into main). Co-Authored-By: Claude Opus 4.8 <[email protected]>
ci: enforce that PRs into main originate from beta
Contributor
|
🎉 This PR is included in version 2.8.0-beta.27 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
…in CI (#1718) * fix(e2e): harden Scenario 14 against slow getDiaryEntry response in CI Register a page.waitForResponse for GET /api/diary-entries/:id BEFORE clicking the draft card, then await it after waitForURL completes. This ensures the heading/draftBadge assertions only fire after the API response has arrived, not after an arbitrary 15s wall-clock timeout. Also align both toBeVisible() timeouts to 45_000 (matching test.slow()'s 3× budget) so CI load spikes cannot exhaust the deadline. The previous { timeout: 15_000 } overrides bypassed test.slow()'s tripled expect.timeout and caused intermittent failures when the server response exceeded 15s under 8-worker CI load. Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <[email protected]> * fix(ci): install chrome-headless-shell for Playwright 1.60 and bump browser cache key Since Playwright 1.49+, `chrome-headless-shell` is a SEPARATE browser binary from `chromium` and must be explicitly installed. The previous install command (`npx playwright install chromium webkit`) omitted it, so every E2E test that uses the headless-shell channel failed with: browserType.launch: Executable doesn't exist at .../chromium_headless_shell-*/chrome-headless-shell-linux64/chrome-headless-shell Fix: add `chromium-headless-shell` to the warmup install step. The browser cache key is bumped from `playwright-v3` to `playwright-v4` (all four restore/save references) so any stale cached browser set that is missing the headless-shell binary is bypassed and a correct, complete set is re-seeded. The apt system-deps cache key (`apt-v3-playwright-*`) is intentionally left unchanged — only the `~/.cache/ms-playwright` browser cache key changes. Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <[email protected]> * fix(ci): add Playwright browser install-on-cache-miss fallback to smoke and shard jobs The E2E Cache Warmup job installs browsers and saves them under the `playwright-v4-{version}-{os}` cache key. However, the saved cache is not reliably visible to downstream jobs (e2e-smoke, e2e) — they receive "Cache not found for input keys: playwright-v4-..." and subsequently fail with "browserType.launch: Executable doesn't exist at .../chromium_headless_shell-1223/...". Changes: - Add `id: browser-cache` to the "Restore browser cache" step in both the smoke job and the shard matrix job (was already present in the warmup job). - After the "Install Playwright system dependencies" step in each of those two jobs, add a new conditional step that runs `npx playwright install chromium chromium-headless-shell webkit` only when `steps.browser-cache.outputs.cache-hit != 'true'`. This guarantees browsers are present regardless of cache visibility, eliminating the "Executable doesn't exist" failure class that causes entire shards to fail when the warmup cache is not populated or not accessible on the runner. Co-Authored-By: Claude e2e-test-engineer (Sonnet 4.6) <[email protected]> --------- Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude e2e-test-engineer (Sonnet 4.6) <[email protected]>
Contributor
|
🎉 This PR is included in version 2.8.0-beta.28 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
* docs: update documentation for v2.8.0 release Document Paperless-first invoice creation with auto-itemize, mobile-first photo capture with orientation tagging, diary daily-log vendor/work-hours, and the relocated document unlink action. Refresh README, RELEASE_SUMMARY, and add a new Capturing Photos guide. Co-Authored-By: Claude docs-writer (Sonnet 4.6) <[email protected]> * chore: add E2E test.slow() timeout-override lesson to implementation checklist Captures the v2.8.0 release lesson: test.slow() triples the project expect.timeout but an explicit per-assertion { timeout } override negates the tripling, causing intermittent CI failures (diary Scenario 14). Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude docs-writer (Sonnet 4.6) <[email protected]>
Contributor
|
🎉 This PR is included in version 2.8.0-beta.29 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
steilerDev
pushed a commit
that referenced
this pull request
Jun 16, 2026
The auto-fix bot pushed a [skip ci] commit to beta after the docs merge, advancing the v2.8.0 promotion PR #1700 HEAD to a commit with no CI runs. This clean-titled commit advances beta with a real (markdown-only) diff so CI fires and pull_request:synchronize re-runs on #1700. Co-Authored-By: Claude Opus 4.8 <[email protected]>
* chore: retrigger promotion CI (post-docs auto-fix skip-ci) The auto-fix bot pushed a [skip ci] commit to beta after the docs merge, advancing the v2.8.0 promotion PR #1700 HEAD to a commit with no CI runs. This clean-titled commit advances beta with a real (markdown-only) diff so CI fires and pull_request:synchronize re-runs on #1700. Co-Authored-By: Claude Opus 4.8 <[email protected]> * chore: nudge promotion CI synchronize Co-Authored-By: Claude Opus 4.8 <[email protected]> --------- Co-authored-by: Frank Steiler <[email protected]> Co-authored-by: Claude Opus 4.8 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release Summary
This release ships three user-facing features — Paperless-first invoice creation with LLM auto-itemize, a mobile-first photo capture flow with orientation metadata, and diary daily-log enhancements (vendor + work start/end time with computed duration) — alongside a substantial code-quality sweep (zero ESLint warnings, no
any, consistent type imports), dependency bumps, and test-infra hardening.Changes
Features
Orientationstab, picker component,0037_orientationsmigration)Fixes
includesVat=false) line items (fix(auto-itemize): add VAT to total for net (includesVat=false) line items #1678)Chores / Refactoring
@typescript-eslint/no-explicit-anywarnings (chore(types): eliminate @typescript-eslint/no-explicit-any warnings #1691)consistent-type-importserrors (chore(lint): resolve @typescript-eslint/consistent-type-imports errors (#1458) #1684)workerGracefulExitTimeout+--collectTests(chore(test): adopt Jest 30.4 workerGracefulExitTimeout + --collectTests scripts #1697)Change Inventory
Backend (
server/,shared/)routes/invoiceAutoItemize.ts,services/invoiceAutoItemizeService.ts,services/invoiceService.ts,shared/types/invoiceAutoItemize.tsroutes/paperless.ts,services/paperlessService.ts,routes/dav.ts,shared/types/paperless.tsroutes/photos.ts,services/photoService.ts,routes/orientations.ts,services/orientationService.ts, migrations0037_orientations.sql,0038_add_photo_orientation.sql,shared/types/photo.ts,shared/types/orientation.tsservices/diaryService.ts,shared/types/diary.ts,services/calendarIcal.tsservices/budgetExtraction/openAICompatibleProvider.ts,prompts.tsdb/schema.tsFrontend (
client/)components/invoices/InvoicePaperlessPickerModal.tsx, budget/invoice componentscomponents/photos/(PhotoUpload, PhotoMetadataModal, PhotoMetadataSidepanel, PhotoViewer, PhotoAnnotator, PhotoCard)components/OrientationPicker/components/diary/(DiaryEntryForm, DiaryFilterBar, DiaryMetadataSummary, DiaryEntryCard, Signature*)components/documents/(DocumentCard, LinkedDocumentCard, LinkedDocumentsSection, DocumentBrowser)E2E Tests (
e2e/)orientations.spec.ts,photo-capture-flow.spec.ts,invoices/paperless-first-invoice*.spec.ts,invoices/invoice-auto-itemize-page.spec.ts,diary/diary-daily-log-time-vendor.spec.ts,diary/diary-mobile-filters.spec.tsOrientationsPage,PaperlessInvoiceReviewPage,PaperlessPickerModal,DiaryEntryEditPage,InvoicesPageDocs / Config
CLAUDE.md,eslint.config.js,jest.config.ts, root + workspacepackage.json/ lockfile,scripts/check-single-dep-version.shManual Validation Checklist
Testing