From b0c2f28e13a3c04c896b34f11f02d1f28565e1c1 Mon Sep 17 00:00:00 2001 From: Wanja Krah Date: Thu, 29 Oct 2026 19:35:10 +0100 Subject: [PATCH] specs --- docs/gitea-ci.md | 13 +- docs/s4-validation.md | 138 ++++++++-- specs/README.md | 8 +- specs/S3_define-coding-standards-to-fe | 0 ...oyment-gitea-action-to-test-and-production | 0 specs/S7_define-coding-standards-to-be | 0 .../S1_School-JSON-import-export.md | 2 +- .../S4_create-build-pipeline-at-gitea | 58 ++-- specs/refined/S2_implement-eslint-for-fe | 218 +++++++++++++++ specs/refined/S5_renovate-bot-in-container | 255 ++++++++++++++++++ specs/refined/S8_palentir-formatting-be | 198 ++++++++++++++ 11 files changed, 839 insertions(+), 51 deletions(-) create mode 100644 specs/S3_define-coding-standards-to-fe create mode 100644 specs/S6_Deployment-gitea-action-to-test-and-production create mode 100644 specs/S7_define-coding-standards-to-be rename specs/{review => implemented}/S1_School-JSON-import-export.md (99%) rename specs/{in_progress => implemented}/S4_create-build-pipeline-at-gitea (79%) create mode 100644 specs/refined/S2_implement-eslint-for-fe create mode 100644 specs/refined/S5_renovate-bot-in-container create mode 100644 specs/refined/S8_palentir-formatting-be diff --git a/docs/gitea-ci.md b/docs/gitea-ci.md index 0aed11c..6b2d3e7 100644 --- a/docs/gitea-ci.md +++ b/docs/gitea-ci.md @@ -3,7 +3,9 @@ De workflow staat in `.gitea/workflows/build.yaml`. Elke branchpush bouwt en test backend en frontend, bouwt twee images en draait Playwright tegen die containers. Alleen `main` mag daarna images publiceren. Er vindt geen deployment plaats. -Tagpushes en aparte pull-requestevents starten geen extra workflow. +Tagpushes en aparte pull-requestevents starten geen extra workflow. Een auteur +kan een branchbuild bewust overslaan met een door Gitea ondersteunde markering, +zoals `[skip ci]`; dit is expliciet toegestaan. ## Java-bronbestanden uitvoeren @@ -92,9 +94,9 @@ Runner en containers moeten de Synology en internetdownloads kunnen bereiken. Repository: `wanjakrah/agiledancers`, hoofdbranch: `main`. Actions staat voor deze repository al aan. Controleer zo nodig op de Synology `app.ini` onder `[actions]` de instelling `ENABLED = true` en de Actions-feature -onder repositoryinstellingen. Stel `SKIP_WORKFLOW_STRINGS` leeg in als ook commits met teksten als `[skip ci]` -verplicht moeten draaien, zoals de afspraak elke branchpush vereist. -Wijzig serverconfiguratie alleen indien nodig. +onder repositoryinstellingen. De standaard `SKIP_WORKFLOW_STRINGS`, waaronder `[skip ci]`, mogen blijven staan: +bewust overslaan is door de maintainer toegestaan. Iedere gewone branchpush start +een pipeline. Er hoeft daarvoor geen serverinstelling te worden gewijzigd. Stel bij repository **Settings → Actions** in: @@ -129,7 +131,8 @@ runnerregistratietoken naar tokenwaarden. Voor handmatige inrichting kun je dat registratietoken uit de repository-instellingen halen en in hetzelfde bestand plaatsen. -Controleer de artifactretentie op de server: een workflow vraagt veertien dagen +De bevestigde Gitea 1.25.4-configuratie heeft geen `[actions]`-sectie: de defaults +zijn negentig dagen voor artifacts en 365 dagen voor logs. Een workflow vraagt veertien dagen via `retention-days: 14`. Een kortere serverlimiet of het vroegtijdig verwijderen van workflowruns mag die periode niet inkorten. Artifactretentie geldt voor testdiagnostiek; gepubliceerde containerimages worden niet automatisch verwijderd. diff --git a/docs/s4-validation.md b/docs/s4-validation.md index 10c8560..2d65209 100644 --- a/docs/s4-validation.md +++ b/docs/s4-validation.md @@ -1,8 +1,10 @@ # S4 verification evidence -Date: 2026-10-28. Status: repository implementation and local container verification -passed; Gitea and runner configuration are operational. Main publication is -awaiting approval to merge PR #1. S4 is **not complete**. +Updated: 2026-10-29. S4 is **complete**. Main publication/pullback passed in run +#7. Real registry recovery, rerun and stale-main checks passed against isolated +validation image repositories. Server defaults are confirmed from the maintainer's +configuration report and Gitea 1.25.4 documentation; explicit skip markers are an +accepted exception to branchpush triggering. ## Verified locally @@ -51,18 +53,21 @@ Local image IDs (not registry digests): - Backend: `sha256:bd77a46e3dbdcaea9662d21c608098999fe17dfdf241cd28a24a935f47401f61`. - Frontend: `sha256:ce8e6ab21fb8f9cbee280ac2c4d7b4ca24a30e899a457382f1e45c6baf99dfb6`. -## Remaining operational acceptance +## Operational acceptance - [x] Synology architecture confirmed by the maintainer: `x86_64`, `linux/amd64`; repository variable `TARGET_PLATFORM=linux/amd64` configured. - [x] Activate and verify the Docker Desktop HTTP-registry setting. - [x] Repository `REGISTRY_USER`/`REGISTRY_TOKEN` secrets configured using the supplied token files. A temporary Docker login with the registry token - succeeded; actual publication still awaits a main-branch merge. + succeeded; actual main publication and pullback are now confirmed below. - [x] Runner ID 1 (`agiledancers-mini-pc`) registered, service started and online in Gitea. Real feature/failure jobs ran on this runner. -- [ ] Confirm server settings permit every branchpush (including messages with - skip strings) and retain uploaded diagnostic artifacts for fourteen days. +- [x] The maintainer reports no `[actions]` section in app.ini. Gitea 1.25.4 + therefore uses the documented artifact/log defaults of 90/365 days; the + workflow explicitly requests fourteen days for diagnostic artifacts. + The maintainer accepts intentional `[skip ci]`-style opt-outs. No server + change or SSH access was required. - [x] [Feature run #1](http://192.168.2.28:3000/wanjakrah/agiledancers/actions/runs/1), API run ID 2, commit `74a5aa12377d4a62cdebe1dcd6e8a8e1443b33fb`: succeeded, two container E2E tests passed, publication skipped. Diagnostic ZIP was @@ -73,14 +78,16 @@ Local image IDs (not registry digests): backend test; imagebuild/publication did not run. Diagnostic ZIP was downloaded and verified (15 files). The probe is absent from the real featurebranch. -- [ ] Real main run: record URL/run ID, both full-SHA images, successful pullback, - registry digests and the two `main` aliases. -- [ ] Real rerun/partial-publication recovery and stale-main evidence: record - run IDs and unchanged existing commit digests. +- [x] Main run #7 (API run/job ID 8) published both full-SHA images, pulled + them back and updated/pulled both `main` aliases; digests are recorded below. +- [x] Real publication-code probes against the Synology registry passed: + partial recovery preserves the first image, reruns preserve both commit + digests, and an older commit cannot move current main aliases. Details and + evidence are recorded below. The isolated publication tests provide automated control-flow coverage; they do -not substitute for real authenticated registry/Gitea acceptance runs. No application -images have been published and no application has been deployed by this work. +not substitute for real authenticated registry/Gitea acceptance runs. Application +images have now been published by main; no application deployment is performed. Gitea 1.25 does not populate `gitea.run_attempt`; the workflow generates a unique @@ -90,21 +97,21 @@ were verified by downloading the run-page archive URLs. This is separate from artifact availability and does not require a server upgrade. -## Ready for review; main merge not authorized +## Historical review state before the main merge -[PR #1](http://192.168.2.28:3000/wanjakrah/agiledancers/pulls/1) remains open at -the maintainer's explicit request. No main merge or application image publication -was performed. +[PR #1](http://192.168.2.28:3000/wanjakrah/agiledancers/pulls/1) was initially left open at +the maintainer's explicit request. Main merge and publication were postponed at +that stage; the maintainer has since merged it. [Feature run #3](http://192.168.2.28:3000/wanjakrah/agiledancers/actions/runs/3), API run/job ID 4, commit `834584dae06b5976936a5e739871f1164cf81bcd`, succeeded. The two container E2E tests passed and diagnostics were uploaded as `diagnostics-4-20261028164607460012324`, confirming unique attempt names work. -The main branch currently contains only its initial commit. PR #1 therefore +Before this merge, main contained only its initial commit. PR #1 therefore includes the prior application history from `feature/setup` as well as S4. Its -scope is documented in the PR description. A main merge needs explicit approval; -only then can real main publication/pullback/rerun acceptance be completed. +scope is documented in the PR description. The maintainer subsequently merged that full history. Publication and pullback +are confirmed below; the remaining acceptance evidence is still tracked above. ## Java 25 helper migration @@ -113,5 +120,92 @@ CI orchestration, setup and behavior tests now run through `java ci/Ci.java`. The shell/Python helpers have been removed. The source launcher compiles helper classes in memory without external dependencies or preview flags. Fifteen Java behavior tests pass, including JSON/configuration preservation, publication gates, -partial recovery and process deadlines. A real feature run validates this revision -before updating the existing open PR; no merge to main is authorized. +partial recovery and process deadlines. Feature run #6 passed for the Java implementation before the maintainer merged +PR #1 into main. + + +## Main publication confirmed after merge + +[Main run #7](http://192.168.2.28:3000/wanjakrah/agiledancers/actions/runs/7), API +run/job ID 8, completed successfully for commit +`2356a31aa612c8b0ce4b386a0a65da6589e23285`. + +Downloaded and inspected artifact `diagnostics-8-20261029144539933186842`. +Its verified-commit marker, publication log and digest files confirm publication +and pullback of both commit tags and both moving main aliases: + +| Image | Digest for the full-SHA tag and main alias | +| --- | --- | +| `192.168.2.28:3000/wanjakrah/agiledancers-backend` | `sha256:483f4593716f94d1c6a7851519b80399b40600e9e49db5b656abed14b4552e93` | +| `192.168.2.28:3000/wanjakrah/agiledancers-frontend` | `sha256:f9be998187751e13a81cbed809938837a3b80fdbfdd122c2126c9792c4320077` | + +This closed the original merge/publication blocker. The remaining acceptance +checks have since been completed as recorded below. + + +## Final acceptance: recovery, rerun and stale-main protection + +Completed on 2026-10-29. These were real command-line publication probes using the +production `Pipeline`/`Commands` implementation against the Synology registry, +not a second full Gitea workflow run. The test adapter redirects Docker write +references to dedicated validation repositories and refuses application-image +pushes. Main-head checks use the actual Gitea API. + +The verified images from main run #7 were used as the current source. The older +images came from the previously successful feature run #6. The main commit is +`2356a31aa612c8b0ce4b386a0a65da6589e23285`; the older commit is +`aea792307c5d3be43e17c11db3b9f5845dbd5f14`. + +Test repositories: + +- `192.168.2.28:3000/wanjakrah/s4-validation-1793286292474-backend` +- `192.168.2.28:3000/wanjakrah/s4-validation-1793286292474-frontend` + +Evidence/results: + +1. Publication was deliberately stopped after backend publication and before + frontend publication. The operation failed; the backend tag existed and the + frontend tag did not. +2. Recovery published the missing frontend image and retained the backend digest. +3. A repeat publication retained both full-SHA digests and pushed only the two + moving validation aliases. No immutable commit tag was pushed again. +4. The older source images were published to the same isolated repositories. + The real Gitea main-head check detected the newer commit. No moving-alias write + was attempted, and before/after manifest hashes remained identical. +5. Application `main` manifests were compared before and after the probes and + remained unchanged. + +The backend and frontend immutable digests match the run #7 digests recorded +above. Manifest comparison hashes for the validation main aliases: + +| Alias | Before and after SHA-256 of inspected manifest | +| --- | --- | +| Backend main | `b4438f0d32eae92632e1f3c106ca9c4538c87d61d6feda9e0184dd8749b46d8c` | +| Frontend main | `3d2bebc8da4297c54eebeb43ce0f00e61a61e9216dde27c81f08be69cd6c7335` | + +Raw local evidence is retained under `ci/artifacts/s4-final-acceptance/`, including +`results.json`, `partial-publication.log`, `recovery.log`, `rerun.log`, +`confirmed-rerun.log` and `stale-main.log`. The isolated validation images remain +available as acceptance artifacts; they are not deployed application instances. + +A temporary registry-login timeout interrupted the first stale-run probe. It +failed visibly and cleaned up temporary login state. Retrying the remaining +checks succeeded; the already-passed recovery/rerun evidence was retained. + +## Server configuration closure + +The maintainer inspected the Synology-hosted Gitea configuration and confirmed +that `[actions]` is absent. Gitea 1.25.4 defaults are: + +- Artifact retention: 90 days by default; the workflow's artifact upload requests + fourteen days explicitly. +- Job log retention: 365 days by default. +- Intentional skip strings such as `[skip ci]` are recognized by default. + +The maintainer explicitly approved documenting these skip strings as exceptions: +ordinary branchpushes trigger CI, while an author can intentionally opt out with +an existing supported marker. No Gitea configuration change or broad NAS access +is necessary. This is the agreed interpretation of the trigger criterion. + +Sources: [Gitea 1.25 Actions settings](https://docs.gitea.com/1.25/administration/config-cheat-sheet/#actions-actions), +[installed-version defaults](https://github.com/go-gitea/gitea/blob/v1.25.4/modules/setting/actions.go). diff --git a/specs/README.md b/specs/README.md index 2d96b97..d255b48 100644 --- a/specs/README.md +++ b/specs/README.md @@ -1,4 +1,10 @@ # Specifications Store feature specifications, requirements and agreed design decisions here. -Use descriptive Markdown filenames, for example `school-json-import-export.md`. +Use descriptive Markdown filenames, prefixed with a unique S# reference, for example `S1_school-json-import-export.md`. +Each spec-file will get a Status with either the values: NEW, REFINED, IN PROGRESS, IN REVIEW, IMPLEMENTED, REJECTED. +Each spec-file that is refined with the grill-me skill, or manually, will be moved to the refined-folder, and its status-field will be set to REFINED. +When a spec-file gets implemented, at first, the spec-file will be moved to the in_progress-folder, and its status-field will be set to IN_PROGRESS. +When a spec-file is fully implemented, the spec-file will be moved to the in_review-folder, and its status-field will be set to IN_REVIEW. +When a spec-file is reviewed, the spec-file will be moved to the implemented-folder, and its status-field will be set to IMPLEMENTED. +When a spec-file is rejected, the spec-file will be moved to the rejected-folder, and its status-field will be set to REJECTED. diff --git a/specs/S3_define-coding-standards-to-fe b/specs/S3_define-coding-standards-to-fe new file mode 100644 index 0000000..e69de29 diff --git a/specs/S6_Deployment-gitea-action-to-test-and-production b/specs/S6_Deployment-gitea-action-to-test-and-production new file mode 100644 index 0000000..e69de29 diff --git a/specs/S7_define-coding-standards-to-be b/specs/S7_define-coding-standards-to-be new file mode 100644 index 0000000..e69de29 diff --git a/specs/review/S1_School-JSON-import-export.md b/specs/implemented/S1_School-JSON-import-export.md similarity index 99% rename from specs/review/S1_School-JSON-import-export.md rename to specs/implemented/S1_School-JSON-import-export.md index 0b8fba6..a1c432a 100644 --- a/specs/review/S1_School-JSON-import-export.md +++ b/specs/implemented/S1_School-JSON-import-export.md @@ -1,6 +1,6 @@ # S1 — School JSON import and export -Status: agreed after the grill-me review. +Status: implemented ## User story diff --git a/specs/in_progress/S4_create-build-pipeline-at-gitea b/specs/implemented/S4_create-build-pipeline-at-gitea similarity index 79% rename from specs/in_progress/S4_create-build-pipeline-at-gitea rename to specs/implemented/S4_create-build-pipeline-at-gitea index 106d5c2..3fa6d1a 100644 --- a/specs/in_progress/S4_create-build-pipeline-at-gitea +++ b/specs/implemented/S4_create-build-pipeline-at-gitea @@ -1,6 +1,6 @@ # S4 — Build and publish pipelines in Gitea -Status: IN_PROGRESS +Status: IMPLEMENTED Agreed after the grill-me review; shared understanding confirmed. @@ -45,7 +45,8 @@ References: - Enable Actions as needed at instance and repository level, configure Docker on the mini-PC, and install, register and configure its runner. - Build and test both backend and frontend for every push to every branch, - including newly created branches. Separate tag and pull-request event workflows + including newly created branches, except when the author intentionally uses a + supported skip marker such as `[skip ci]`. Separate tag and pull-request event workflows are not required; branch pushes also check changes used in pull requests. - Build two runnable Docker images: backend and frontend. - Run end-to-end tests against those built containers before publication. @@ -68,7 +69,9 @@ References: ## Build and verification behavior -1. Every branch push runs backend and frontend builds and their existing tests. +1. Every ordinary branch push runs backend and frontend builds and their existing + tests. Explicit Gitea-supported skip markers are an accepted maintainer-approved + opt-out. 2. Backend verification includes the existing unit, integration/system and architecture tests. Current entry point: `mvn clean verify` using Java 25. 3. Frontend verification uses the lockfile (`npm ci`), unit tests (`npm test`) and @@ -130,30 +133,31 @@ References: ## Acceptance criteria -- [ ] A push to any branch, including a new branch, starts a pipeline. -- [ ] Backend and frontend build and all existing tests, including architecture +- [x] A push to any branch, including a new branch, starts a pipeline, except for + an explicit supported skip marker chosen by the author. +- [x] Backend and frontend build and all existing tests, including architecture and Playwright end-to-end tests, pass before publication is permitted. -- [ ] Every branch builds both Docker images; end-to-end tests exercise those +- [x] Every branch builds both Docker images; end-to-end tests exercise those images through the frontend and its `/api` forwarding. -- [ ] A failing build or test fails the pipeline without publishing images. -- [ ] A successful feature-branch pipeline publishes no application images. -- [ ] A successful `main` pipeline publishes both images to the Synology registry +- [x] A failing build or test fails the pipeline without publishing images. +- [x] A successful feature-branch pipeline publishes no application images. +- [x] A successful `main` pipeline publishes both images to the Synology registry with the full commit SHA; both images can be pulled back. -- [ ] Published commit images are preserved on rerun; partial publication can be +- [x] Published commit images are preserved on rerun; partial publication can be completed without overwriting an existing commit image. -- [ ] Moving `main` tags are updated only after both commit images are available, +- [x] Moving `main` tags are updated only after both commit images are available, and an older pipeline cannot move them backwards. -- [ ] Publication or pull-verification failure makes the pipeline fail, even if +- [x] Publication or pull-verification failure makes the pipeline fail, even if some images have already been uploaded. -- [ ] Available failure diagnostics are retained for fourteen days, and temporary +- [x] Available failure diagnostics are retained for fourteen days, and temporary test containers are cleaned up on success and failure. -- [ ] The runner operates on the existing mini-PC, with Gitea and the registry on +- [x] The runner operates on the existing mini-PC, with Gitea and the registry on the existing Synology; no additional hardware is needed. -- [ ] The single target architecture is established and the images are tested on +- [x] The single target architecture is established and the images are tested on that architecture using the existing hardware. -- [ ] A management guide records setup, external settings, secrets, image usage +- [x] A management guide records setup, external settings, secrets, image usage and recovery, including the need to keep the mini-PC/runner available. -- [ ] Actual pipeline runs demonstrate successful main-branch publication, +- [x] Actual pipeline runs demonstrate successful main-branch publication, feature-branch checks without publication, and failure blocking publication. ## Implementation handoff @@ -171,8 +175,8 @@ Repository implementation and local Docker verification are available. See [validation evidence](../../docs/s4-validation.md). Backend verification (20 tests), frontend verification (14 tests), both runtime -image builds and both Playwright tests against the containers passed. Eleven -isolated CI publication/configuration tests pass. The runner binary and user-service +image builds and both Playwright tests against the containers passed. Fifteen +Java CI publication/configuration tests pass. The runner binary and user-service configuration are installed on the mini-PC. The maintainer confirmed the Synology as `x86_64` / `linux/amd64`. Gitea secrets @@ -181,6 +185,16 @@ online. Registry login succeeded. Real feature runs #1 and #3 passed, including container E2E; deliberate failure run #2 blocked the build/publication path and provided downloadable diagnostics. -PR #1 is open. The maintainer explicitly declined merging it for now. Main image -publication, pullback and rerun acceptance therefore remain pending. The spec -stays IN_PROGRESS until those requirements are met. +PR #1 was subsequently merged by the maintainer. Main run #7 succeeded for +commit `2356a31aa612c8b0ce4b386a0a65da6589e23285`, publishing and pulling both +full-SHA images and both main aliases. Registry digests are recorded in the +validation evidence. + +The final real-registry probes confirmed partial-publication recovery, immutable +commit-tag preservation on rerun and stale-main protection in isolated validation +repositories. Application manifests remained unchanged. The maintainer confirmed +that the Synology app.ini has no actions section, so Gitea 1.25.4's documented +90-day artifact and 365-day log defaults apply; the workflow requests fourteen +days for diagnostic artifacts. Explicit skip markers are accepted by the +maintainer. All acceptance criteria are met; see the validation evidence for +probe details, digests and the distinction from full Gitea workflow reruns. diff --git a/specs/refined/S2_implement-eslint-for-fe b/specs/refined/S2_implement-eslint-for-fe new file mode 100644 index 0000000..eef877f --- /dev/null +++ b/specs/refined/S2_implement-eslint-for-fe @@ -0,0 +1,218 @@ +# S2 — ESLint for the frontend + +Status: REFINED + +Agreed after the grill-me review; shared understanding confirmed. + +## User story + +As a frontend maintainer, I want automated lint checks during development and in +CI, so that likely bugs and Angular/TypeScript problems are caught before changes +are accepted or application images are published. + +I also want a fast local commit hook where feasible, without losing control of +which changes are included in my commit. + +## Scope and boundary with S3 + +### In scope + +- Install and configure compatible ESLint, TypeScript and Angular lint tooling. +- Apply the recommended JavaScript, TypeScript and Angular rules, including + recommended type-aware checks for TypeScript. +- Lint maintained frontend application code, external and inline Angular HTML + templates, unit tests, Playwright tests and applicable frontend configuration + files. +- Fix all existing violations of the agreed rules and verify that the application + still builds and its tests pass. +- Provide local check and autofix commands, mandatory pipeline enforcement, + editor support and documentation. +- Introduce a staged-file commit hook only if it meets the agreed performance + and change-preservation requirements. + +### Out of scope + +- Additional opinionated coding conventions or stricter rule sets beyond the + agreed recommended baseline. These belong in S3. +- Backend or Java CI-helper linting. +- Linting dependencies, generated output or generated files such as + `package-lock.json`. +- A new mandatory Prettier check in CI. Prettier remains the formatting tool; + this spec adds its local commit-hook use only when the timing budget permits. + +## Existing environment + +The reviewed frontend uses Angular 22.2.3, Angular CLI/build 22.2.4, TypeScript +6.0.3 and Prettier 3.9.10. TypeScript strict mode and Angular strict-template +checking are already enabled. Prettier configuration already exists. + +No ESLint configuration, lint command or active Git commit hook was present at +review. The frontend package is in `agiledancers-fe/`, below the Git root. +Implementation must account for that layout when installing repository hooks. + +Choose versions compatible with the installed Angular CLI and TypeScript. Use +supported configuration for those versions rather than copying incompatible +examples or changing framework versions merely to introduce linting. + +## Lint commands and rule behavior + +- `npm run lint`, executed from `agiledancers-fe/`, checks the entire maintained + frontend scope without changing files. +- A lint error or warning causes a nonzero exit status. A successful check means + there are no outstanding ESLint errors or warnings. +- `npm run lint:fix` is an explicit local command that applies supported ESLint + autofixes. Developers review its changes and resolve any remaining findings. +- CI uses the checking command only and must not repair, format, stage or commit + source changes itself. +- Keep formatting under the existing Prettier configuration. Do not introduce + conflicting ESLint formatting rules or redefine formatting conventions in S2. +- Narrow exceptions are permitted when a rule is demonstrably unsuitable. Each + suppression has a concrete explanation and the smallest applicable scope. + Do not broadly disable rules merely to avoid investigating existing findings. +- Start with a clean baseline: do not introduce a legacy-violation allowance, + warning backlog or ignored maintained files to make the initial check pass. +- Fixes preserve application behavior; builds and tests must still pass. + +## Pipeline integration + +Every branch pipeline must run `npm run lint` immediately after frontend +`npm ci`, before frontend tests, frontend builds and container end-to-end tests. + +A failed lint check fails the pipeline and prevents image publication. Its +concrete findings must be visible in the job log and retained in the existing +pipeline diagnostics. The local hook never replaces the full pipeline check. + +Integrate this into the existing Java-based pipeline orchestration. Repository +hook installation is skipped during CI and Docker package installation. + +## Editor support + +Recommend the ESLint extension in the existing VS Code project recommendations. +Do not require automatic fixing or formatting on save. Document how developers +can see findings while editing and run the same check as CI. + +## Local commit hook + +### File selection and tools + +- Only process maintained frontend files staged for the current commit. +- Skip frontend checks for commits without applicable staged frontend changes. +- ESLint only checks; it does not autofix in the hook. Errors and warnings block + the commit if ESLint is part of the selected hook configuration. +- Prettier may format maintained frontend TypeScript, JavaScript, HTML, CSS and + JSON configuration files and stage the formatting result automatically. +- Exclude dependencies, build output and generated files such as + `package-lock.json`. +- If both tools are included, format with Prettier before checking the result + with ESLint. Do not run modifying operations concurrently on overlapping files. + +### Preserve the intended commit + +- Support partially staged files: format the version intended for the commit + while preserving unrelated unstaged changes. +- Automatically staging formatting must not include unrelated local edits or + change which unrelated files are committed. +- On any hook failure, including an ESLint failure after successful formatting, + abort the commit and restore the original staged and unstaged state. +- A conflict while reconciling formatting with unstaged edits also aborts the + commit and restores the original state. +- Report a concrete cause when the hook fails. Do not leave partial formatter, + staging or temporary-state changes behind. +- Use tooling that supports this behavior with its state-preservation protections + enabled; the specific hook manager/staged-file runner is an implementation + choice. + +### Three-second performance budget + +The budget covers the entire additional hook duration, including file selection, +backup/state handling, tool startup, formatting/checking, restaging and cleanup. +It is a combined budget, not three seconds per tool. + +Measure the actual complete hook on the existing development mini-PC for: + +1. A single applicable staged frontend file. +2. A mixed commit containing applicable frontend file types. +3. All maintained frontend files staged together. + +Use a newly started process and no tool cache for each measured execution, +including cold tool starts. Every measured execution must finish within three +seconds. Record the machine/environment, exact staged scope, commands and timing +results in the implementation evidence. Do not claim the budget based only on +warm cached executions or timings of an individual tool. + +Choose the hook configuration from those measurements: + +1. Include Prettier and ESLint if the combined complete hook meets the budget. +2. Otherwise omit ESLint from the hook and measure the complete Prettier-only + hook against the same budget and scenarios. +3. If Prettier-only also fails the budget, do not install an active commit hook. + +Do not enforce the budget by killing a writing formatter mid-operation. It is an +acceptance criterion for selecting the hook configuration, not a hard runtime +interrupt that risks incomplete changes. The full type-aware ESLint check remains +mandatory in CI regardless of the selected local hook configuration. + +### Installation and operation + +If a hook configuration meets the budget, set it up automatically during local +`npm ci`. Skip installation in CI and Docker builds. Document the selected tools, +installation behavior and how a developer can disable the local hook. + +If no hook configuration meets the budget, document that result and its timing +evidence. Local lint commands and mandatory pipeline enforcement still apply. + +## Documentation + +Add an explanation to the root `README.md` for both `npm run lint` and +`npm run lint:fix`, including: + +- Run the commands from `agiledancers-fe/`. +- What each command checks or changes and the difference between checking and + autofixing. +- That errors and warnings fail the checking command, and autofix may leave + findings requiring manual changes. +- That the pipeline runs the check and blocks publication on failure. +- The selected hook behavior, its measured performance and any omitted checks. +- Automatic local installation, exclusion from CI/Docker installation, and local + opt-out instructions if a hook is installed. +- Prettier formatting/restaging and preservation of partially staged files, + including restoration on hook failure, when applicable. + +The frontend README may link to the root explanation to keep instructions +consistent. Record the performance evidence with the implementation documentation. + +## Acceptance criteria + +- [ ] Compatible tooling checks maintained application TypeScript/JavaScript, + Angular templates, unit tests, Playwright tests and applicable frontend + configuration using the agreed recommended and type-aware rules. +- [ ] All existing violations are fixed; there is no legacy baseline allowance. + Frontend builds, unit tests and container end-to-end tests still pass. +- [ ] `npm run lint` checks the full scope without modifications and fails on + either errors or warnings. +- [ ] `npm run lint:fix` offers explicit local autofixes; CI does not modify source. +- [ ] Formatting remains under Prettier, without conflicting ESLint rules. +- [ ] Any necessary rule suppressions are narrow and concretely justified. +- [ ] Every branch pipeline runs lint immediately after frontend `npm ci` and + before frontend tests/builds and container E2E; lint failure prevents + publication and leaves actionable diagnostic output. +- [ ] VS Code recommends ESLint without mandatory fix/format-on-save settings. +- [ ] Complete-hook measurements cover the agreed single-file, mixed-file and + all-maintained-files cases with fresh processes and no tool cache. +- [ ] The measured three-second budget determines combined tools, Prettier-only + or no active hook; no writing formatter is forcibly interrupted to meet it. +- [ ] If installed, the hook processes only applicable staged frontend files, + applies Prettier formatting before any ESLint check, and preserves unrelated + files and unstaged edits, including partially staged files. +- [ ] A failed installed hook restores the original staged and unstaged state and + blocks the commit with a concrete explanation. +- [ ] Hook installation is automatic for local `npm ci` when applicable, skipped + in CI/Docker, and has documented local opt-out instructions. +- [ ] Root `README.md` explains `npm run lint`, `npm run lint:fix`, CI enforcement + and the selected hook behavior; measurement evidence is included. + +## Implementation handoff + +This specification records agreed behavior. It does not install ESLint, change +application code, modify the pipeline, install a hook or update command usage in +the README yet. Those changes and the timing measurements are implementation work. diff --git a/specs/refined/S5_renovate-bot-in-container b/specs/refined/S5_renovate-bot-in-container new file mode 100644 index 0000000..8f22975 --- /dev/null +++ b/specs/refined/S5_renovate-bot-in-container @@ -0,0 +1,255 @@ +# S5 — Renovate bot in a container + +Status: REFINED + +Agreed after the grill-me review; shared understanding confirmed. + +## User story + +As a developer, I want a containerized Renovate bot to check the repositories on +our Gitea server and propose dependency updates through pull requests, so that +frontend, backend and build infrastructure dependencies remain maintainable and +we reduce risks from outdated versions. + +I want external release age and project compatibility to constrain those +proposals. I retain control over merging and can upgrade dependencies manually +when I deliberately choose to act outside the bot's waiting period. + +## Environment and scope + +- Gitea and its container registry run on the existing Synology. Renovate runs in + a container on that same Synology; no additional hardware is required. +- The established Synology target platform is `linux/amd64`. +- Discover all repositories on this Gitea instance for which the dedicated bot + account has the necessary access. Support explicit repository exclusions. +- Before dependency PRs are proposed for a newly discovered repository, create an + onboarding/configuration PR. A maintainer must approve and merge that + configuration first. +- This project contains a `renovate.json` with its agreed compatibility and update + boundaries. Other onboarded repositories have their own reviewed configuration. +- Use a dedicated bot account/token with the access required for repository + discovery, branches, PRs, dashboards and dependency metadata lookup. Keep + credential values outside Git and logs. + +### Dependency surfaces + +Cover supported maintained dependency declarations, including: + +- Frontend dependencies and development dependencies, compilers and test tools. +- Backend dependencies, Maven parents/BOMs, plugins and version properties. +- Docker base images and maintained container-image references. +- Pinned workflow actions, including version/digest references. +- The Renovate container's own version declaration. +- Related lockfile changes and separate lockfile maintenance. + +Detection must include relevant maintained references outside ordinary manifests, +for example the Playwright image reference in the Java CI helper. Where related +references must match, update and validate them together. The Playwright package +and browser image must stay aligned. + +One explicit manual boundary remains: the runner binary download version and its +binary SHA-256 checksum in the CI setup helper are maintained manually. Document +this boundary. Do not generate a partial runner update, leave an obsolete +checksum, or confuse a Git commit SHA with the binary's SHA-256. + +Unsupported dependency references or missing required metadata must be visible as +limitations/blockers, rather than silently counted as successfully managed. + +## Schedule and execution + +- Run daily at **06:00 in `Europe/Amsterdam`**. The schedule/timezone are + configurable and the default is recorded in the deployment configuration. +- Provide the actual scheduler/container setup on the Synology; adding an image + declaration alone does not make the periodic execution operational. +- The Synology can perform dependency checks while the development mini-PC is + off. Project CI jobs still depend on their existing runner availability. +- The daily run can discover candidates, maintain eligible PRs and propose new + eligible updates within the agreed limits. It does not merge updates. + +## Seven-day release-age policy + +### Universal bot policy + +- A release must be at least **seven days old** before Renovate proposes that + version in a dependency PR. +- Apply this to all bot-proposed dependency updates, including internal libraries, + security updates, infrastructure dependencies and the bot's own image update. + There is no internal-library or security-update exception. +- Apply the same check when an existing PR is updated to a newer version. An + existing eligible PR must not gain an ineligible new version through refresh. +- Missing or unreliable release timestamps block the affected proposal until its + age is demonstrable. Do not treat missing metadata as proof of sufficient age. +- Show the concrete blocker in the repository dashboard, with useful diagnostics. + A dependent/coherent update group cannot be partially proposed in an invalid + combination to work around an age blocker. +- Enforce the policy centrally across onboarded repositories. Repository-local + configuration, security-update defaults or bot retry/approval mechanisms must + not silently relax the waiting period or timestamp requirement. +- A maintainer may choose to upgrade earlier **manually**, outside Renovate. That + does not authorize Renovate to bypass its policy. + +### Lockfiles and transitives + +The waiting period also applies to newly introduced or changed transitive +versions in bot-generated lockfile changes. Determine those changes relative to +the repository base revision used by the proposal. + +- Validate the age of those versions before the PR is created or updated. +- Unknown ages block the affected proposal, just as they do for direct updates. +- Existing unchanged versions in the base revision are not newly introduced by + the bot; the policy is not a requirement to rewrite all historical lock entries. +- Additional validation is part of S5 where Renovate's native behavior cannot + establish this guarantee. Do not assume a package-manager cutoff covers every + fallback path. +- A failing validator must actually prevent PR creation/update. A command that + fails but only adds an artifact error or failed status to an already-created + ineligible PR does not satisfy this requirement. + +### Metadata limitations + +Not every datasource/registry supplies usable release timestamps. This includes +some container-image sources. Such updates remain blocked and visible unless +reliable metadata support is implemented and validated; manual maintenance is +possible outside the bot. + +For example, the npm release timestamp of Playwright is not proof of the release +age of its separately published container image. Both references must satisfy +applicable policy before their coordinated bot proposal is offered. + +## Compatibility and upgrade boundaries + +### Project-owned boundaries + +- The official Angular compatibility table is the reference for Angular's Node.js, + TypeScript and RxJS compatibility: . +- Project maintainers encode and maintain the applicable ranges in + `renovate.json`, including supported Node majors and TypeScript minor ranges. +- Renovate must stay within those explicit ranges and must not independently + widen the policy to make a proposed version eligible. +- Boundaries must reflect the actual installed framework/tooling metadata where + relevant. Remaining in the same dependency major is not sufficient if Angular + requires a narrower range. +- Node.js, TypeScript and RxJS updates, including major updates, may be proposed + when the explicit project boundaries allow them and they remain compatible with + the project's Angular version. + +### Angular upgrades + +- Angular major upgrades are performed manually through a separate specification. +- Libraries/tooling whose major numbering follows Angular are upgraded to a new + major with Angular, also through that manual specification. +- Renovate proposes only minor and patch updates for Angular and that aligned + family, maintaining a coherent compatible combination. +- Runtime/compiler dependencies that require matching versions stay aligned. + Do not assume unrelated Angular tooling repositories must all have identical + patch numbers merely because their majors align. +- Group related changes where necessary to preserve compatibility. TypeScript and + RxJS proposals still obey their own explicit allowed ranges. + +### Declared versions versus installed software + +Maintain coherent repository declarations where a dependency appears in multiple +places, such as Node requirements in manifests, version files, Docker definitions +and setup checks. A bot PR does not install a new Node version on the mini-PC or +replace a running container. Those are documented manual management actions. + +## Branches, PRs and limits + +- Use the branch prefix `renovate/`. +- Use `renovate/major/` for eligible major updates. +- Use `renovate/minor-patch/` for eligible minor/patch updates. +- Each independent dependency has its own update PR. Related packages from one + upstream project may be grouped to maintain a coherent update. +- Keep major-update proposals separate from minor/patch proposals. Necessary + companion changes belong with the coherent upgrade they support; unrelated + smaller updates are not mixed into a major PR. +- Maintain at most **five open dependency PRs per repository**, including the + separate lockfile-maintenance PR when one exists. +- Queue additional eligible updates for a later daily round after slots become + available. There is no dynamic sixth/seventh overflow PR or custom overflow + bundling requirement. +- Onboarding/configuration PRs are outside this dependency-PR limit and precede + ordinary dependency proposals. +- Renovate creates and updates proposals only. Maintainers review the change and + CI result and merge manually; automerge is disabled. + +## Lockfile maintenance + +- Ordinary manifest updates include the matching lockfile changes in the same + PR, so reproducible installation remains valid. +- Separately maintain lockfiles within the existing manifest boundaries on a + branch such as `renovate/minor-patch/lockfile-maintenance`. +- Keep that maintenance PR separate from ordinary dependency-update PRs and count + it within the five-PR limit. +- Apply the same seven-day checks to newly resolved/changed versions in that PR. +- Do not split a normal manifest update from the lockfile required by that update + into separately mergeable, inconsistent proposals. + +## Maintaining existing PRs + +During daily execution, Renovate may refresh existing bot proposals and rebase +them when the base branch changes. Refreshed candidates must again pass age and +compatibility checks. + +Do not overwrite manual changes on bot branches. If manual edits or conflicts +prevent safe maintenance, preserve those edits and show that maintainer action is +required in the dashboard. + +## Visibility and management + +- Provide a Dependency Dashboard issue per onboarded repository for pending, + open and blocked updates and relevant failures. +- Explain age, missing metadata and compatibility blockers concretely. +- Preserve execution logs and the result of each scheduled run for **thirty days**, + with rotation/retention configured and secret values omitted/redacted. +- Retain operational failure information on the Synology even if startup or Gitea + connectivity fails before repository processing can update a dashboard. +- Provide a management guide covering bot access and secret locations, repository + discovery/exclusions and onboarding, schedule/timezone, manual execution, + dashboards/logs, configuration validation and recovery. +- Document project compatibility maintenance, the manual runner version/checksum + boundary, blocked unsupported metadata, manual host/runtime updates and applying + an approved Renovate-image version to the running installation. + +## Acceptance criteria + +- [ ] A working Renovate container and daily 06:00 Europe/Amsterdam schedule run + on the existing linux/amd64 Synology. +- [ ] Discovery covers authorized Gitea repositories, respects exclusions and + requires onboarding/configuration approval before dependency proposals. +- [ ] This project has a reviewed `renovate.json` with explicit framework and + dependency boundaries; compatible managed dependency surfaces are detected. +- [ ] Direct, security and new/changed transitive lockfile versions younger than + seven days cannot enter new or refreshed bot PRs. +- [ ] Unknown release ages block proposals visibly; internal dependencies do not + bypass the waiting period. +- [ ] Validation proves repository overrides, security defaults and error/fallback + paths cannot create or update an ineligible PR. +- [ ] Node.js, TypeScript and RxJS updates stay inside the maintainer-controlled + Angular compatibility bounds, including any permitted major upgrades. +- [ ] Angular and Angular-major-aligned library major upgrades are not proposed; + compatible minor/patch changes and coupled package/image references remain + coherent. +- [ ] Independent proposals and permitted coherent groups use the agreed + renovate/major/... and renovate/minor-patch/... branch conventions. +- [ ] Major proposals remain separate from unrelated minor/patch updates. +- [ ] No more than five dependency PRs are open per repository, including lockfile + maintenance; remaining candidates wait rather than form overflow PRs. +- [ ] Normal manifest PRs include matching lockfiles; separate lockfile maintenance + stays within manifest ranges and satisfies the same age policy. +- [ ] Daily maintenance preserves manual branch edits and reports conflicts; + merging and actual host/container upgrades remain manual. +- [ ] The runner binary version/checksum is explicitly documented as manual, with + no partial or incorrect automated checksum updates. +- [ ] Dashboards expose repository-level state; thirty-day logs also expose + failures before repository processing without disclosing secrets. +- [ ] Management documentation and real execution/PR evidence demonstrate the + operational setup and enforcement. Configuration files alone are insufficient. + +## Implementation handoff + +This specification records agreed behavior. It does not create the bot account, +configure credentials, deploy a container, install a schedule or create PRs/issues. +Those actions, any necessary additional age validation and the operational evidence +are implementation work. S5 is complete only when its behavior has been proven on +the working installation. diff --git a/specs/refined/S8_palentir-formatting-be b/specs/refined/S8_palentir-formatting-be new file mode 100644 index 0000000..f1cb0e9 --- /dev/null +++ b/specs/refined/S8_palentir-formatting-be @@ -0,0 +1,198 @@ +# S8 — Palantir formatting for Java + +Status: REFINED + +Agreed after the grill-me review; shared understanding confirmed. + +## User story + +As a developer, I want maintained Java code formatted using Palantir Java Format +through the Maven workflow, so that local development and CI use consistent, +reproducible formatting without unnecessary build overhead. + +## Scope + +### In scope + +- Backend Java production code and Java tests. +- Maintained Java CI/source-launcher helpers under `ci/`, despite those files + being outside ordinary Maven source roots. +- Integration with local Maven builds, CI checking and standalone format/check + commands. +- A separate initial formatting commit, performance measurements and README + instructions. + +### Out of scope + +- Generated code and build output. +- Frontend formatting, which remains under Prettier. +- Additional coding conventions, naming rules, structural checks or refactorings. + Those belong in S7. + +## Formatter and integration + +- Use the **actual Palantir Java Format engine** and its Palantir style. +- OpenRewrite is the preferred integration route. S8 includes the custom + Palantir adapter/recipe and bootstrap required to make that route work. +- OpenRewrite's own `AutoFormat` is not an equivalent replacement for Palantir + and must not be substituted silently. +- Spotless is not the agreed default: the maintainer has experienced unacceptable + slowness with it. Do not choose it merely because a native integration exists. +- Pin the formatter, plugin and adapter dependencies to explicit versions in + Maven configuration. Local development and CI use the same pinned engine. +- Formatter/integration updates are reviewed through PRs and include any resulting + formatting changes. Do not implicitly resolve the newest formatter at build time. +- Include Palantir's import ordering and unused-import removal. Do not add + separate import policies or unrelated code transformations. +- Leave optional extra Javadoc reformatting disabled for the initial adoption. + +## Maven behavior + +### Local builds + +Local builds apply formatting before compilation, so the compiled and tested +sources are the formatted sources. Early lifecycle integration means ordinary +`mvn compile`, `mvn test`, `mvn verify` and `mvn install` may format maintained +Java files. + +Binding only to `install` does not satisfy this specification: the existing CI +verification uses `mvn clean verify` and would not reach that phase. + +Provide standalone commands to: + +- Apply formatting without performing the complete application build. +- Check formatting without modifying maintained sources or performing the complete + application build. + +The concrete commands/profile names are implementation work and must be documented. + +### CI + +- CI runs the check-only mode before compilation and fails if formatting differs + from the committed source. +- CI must not repair or rewrite maintained Java source files automatically. +- Use the same pinned Palantir engine, configuration and file scope locally and + in CI; only apply versus check behavior differs. +- Integrate the checking invocation into the existing Java-based CI orchestration. +- Show actionable diagnostics identifying the files that need formatting and how + to apply the formatter locally. +- A formatting failure prevents successful verification and image publication. + Demonstrate that the check leaves maintained source files unchanged on failure. + +## Clean-checkout bootstrap + +Normal Maven commands from the repository root must work from a clean checkout +without first requiring a developer to compile or install a custom recipe artifact +by hand. + +The custom recipe/adapter must be available before it is needed to format the +application sources. Placing it in ordinary backend source code and assuming that +it has already been compiled is not a valid bootstrap solution. + +Prove bootstrap behavior with no previously installed project-specific recipe +artifact. Normal dependency resolution is allowed; any extra tooling module or +bootstrap must be included in the implementation and documentation. + +## Correctness and Java 25 + +- Demonstrate support for every Java construct actually used in the maintained + backend, tests and CI helpers on the project's JDK 25. +- Running the formatter on JDK 25 is not, by itself, proof that its parser supports + every possible Java 25 construct. Record relevant limitations of the chosen + pinned version. +- An unprocessable file or formatter error fails the operation/build with its + path and a concrete cause. Do not silently skip it or exclude it merely to + obtain a successful build or faster measurement. +- The adapter must preserve source paths and encoding and avoid corrupting files. +- Formatting is deterministic and idempotent: applying it again produces no + further source differences. Check-only and apply mode agree on the result. +- Application behavior remains unchanged; builds and tests must pass after the + initial formatting and subsequent formatter changes. + +## Initial adoption and commit separation + +Apply the chosen formatting to all existing maintained Java files in scope. +Record this initial mass formatting in a separate **formatting-only commit**, +without functional changes. Keep integration/configuration changes separate so +reviewers can distinguish tooling changes from the mechanical source rewrite. + +Native import ordering/removal is part of that formatting commit. Do not combine +it with unrelated cleanup or refactoring. + +## Performance requirements + +The integration must be measured rather than selected on an unverified claim that +one wrapper is faster than another. + +- A repeated ordinary build with no Java-source changes may incur at most + **three seconds of additional formatting-related overhead**. +- Include the required integration/recipe/bootstrap overhead in that comparison; + do not report only time spent inside the Palantir formatting function. +- Compare otherwise equivalent builds with and without the formatting integration + under the same environment/cache conditions. +- Also measure a build after changing a maintained Java file and a `clean verify` + run. Record these timings; the agreed three-second threshold specifically + applies to the repeated unchanged-build case. +- Report one-time dependency downloads separately, rather than disguising ongoing + overhead as first-time setup or counting downloads as formatter execution. +- Record the machine, JDK/Maven/tool versions, commands, file scope, cache state + and results with the implementation evidence. + +The time threshold is an acceptance criterion, not a hard interrupt that kills a +formatter while it is writing source files. If the selected integration cannot +meet the threshold, report the measurements and obtain agreement before choosing +an alternative integration or relaxing the bound. Do not silently skip formatting, +switch engines, choose Spotless or weaken the criterion. + +## README and editor integration + +Explain in the root `README.md`: + +- The formatter, pinned versions/configuration and maintained file scope. +- The standalone apply and check commands. +- Which local Maven lifecycle commands can rewrite files and when that occurs. +- The CI check-only invocation and how to reproduce and resolve a failure locally. +- Clean-checkout bootstrap behavior and any included tooling artifact/module. +- Available supported IDE integration and how to keep its result consistent with + the project's pinned formatter. +- The performance evidence and any relevant Java 25 syntax limitations. + +Maven is the authoritative formatting path regardless of editor. Do not require +format-on-save or an IDE plugin. An IDE integration must not redefine the agreed +style or silently take precedence over the Maven result. + +## Acceptance criteria + +- [ ] The actual Palantir engine formats all maintained backend Java sources, + Java tests and `ci/*.java`; generated code is excluded. +- [ ] OpenRewrite integration, custom adapter/recipe and bootstrap are implemented + and reproducible from a clean checkout without manual recipe installation. +- [ ] Plugin, formatter and adapter dependencies are pinned, with matching local + and CI configuration. +- [ ] Local Maven builds apply formatting before compilation; `compile`, `test`, + `verify` and `install` reach the intended integration. +- [ ] Standalone apply and check commands work without the full application build. +- [ ] CI checks only, leaves maintained sources unchanged, reports formatting + differences and fails before image publication. +- [ ] Import ordering and unused-import removal follow Palantir; optional extra + Javadoc reformatting remains disabled and no unrelated refactoring is added. +- [ ] All currently used Java 25 syntax is handled, or causes an explicit failure + requiring resolution rather than silent exclusion. +- [ ] Apply/check results agree and a second apply produces no differences. +- [ ] Initial formatting is isolated in a formatting-only commit; application + builds and tests remain green. +- [ ] Equivalent repeated unchanged-build measurements demonstrate at most three + seconds of additional integration overhead. Changed-file and clean-build + measurements and one-time downloads are reported separately. +- [ ] Failure to meet the performance bound is reported before changing the route + or bound; a writing formatter is not killed to force compliance. +- [ ] README instructions cover local and CI commands, bootstrap, optional IDE + use, authoritative Maven formatting and verification evidence. + +## Implementation handoff + +This specification records agreed behavior. It does not install a formatter, +create an adapter, change Maven/CI behavior or reformat source files. Recipe loading, +Java 25 compatibility and performance must be demonstrated during implementation; +there is no pre-existing project benchmark establishing the preferred route's +performance.