From 73a4eac4644a220046e321f22714543ee3f8af6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Dinis=20Ferreira?= Date: Sat, 11 Jul 2026 21:46:53 +0200 Subject: [PATCH] docs: skill review trims and staleness fixes Applies the adversarially-verified findings of the skill review (13-agent Opus panel over the stacked #1453+#1461 state; 25 confirmed findings): Cuts: duplicate string-decision list in 00-decisions; duplicated commit-message fence in multi-file-batch; four known-pitfalls rows that were verbatim checklist echoes; copyright restatements reduced to pointers (formatting-and-commit stays canonical). Staleness/contradictions: one-file-conversion step 8 and the checklist final invariant now teach the two-step rename+translate scheme; stale hard-coded rule counts dropped; overview slice branch now based on upstream/master; import order stated once (java.* -> org.* -> com.*, junit inside org, static block separate) and aligned in rule 11 and the pitfalls row; == equality rule gains the primitive-operand carve-out (enums stay object-form); rollback recipe corrected for two-step slices (reset --hard HEAD~N / revert both shas, never -m 1) and stated once; SKILL.md lambda cheat-sheet aligned with 07 (expression form); Pairs guidance defers to the no-xbase.lib pitfall; dead "ledger's Method 1" pointer removed. Small additions: trailing-\s trap noted at point of use in 4.3; stable-rule-ID legend in the checklist header; overview Step 0 leads with the bash listing; examples no longer claim their whitespace WAS verified (they illustrate; real migrations must verify) and use the PMD-safe explicit StringBuilder capacity. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_018ANGM7L3BaEGfGUmPVKRt4 --- .agents/skills/xtend-to-java/SKILL.md | 6 ++--- .../examples/00-basic-generator.md | 2 +- .../examples/01-template-with-for-loop.md | 6 ++--- .../xtend-to-java/rules/00-decisions.md | 8 +------ .../rules/01-imports-and-package.md | 16 ++++++------- .../xtend-to-java/rules/04-templates.md | 6 ++++- .../rules/08-operator-overloads.md | 1 + .../xtend-to-java/rules/09-misc-syntax.md | 2 +- .../workflow/formatting-and-commit.md | 7 ++++++ .../xtend-to-java/workflow/known-pitfalls.md | 12 ++++------ .../workflow/multi-file-batch.md | 10 +++----- .../workflow/one-file-conversion.md | 2 +- .../skills/xtend-to-java/workflow/overview.md | 24 +++++++++---------- .../workflow/validation-checklist.md | 10 +++++--- 14 files changed, 57 insertions(+), 55 deletions(-) diff --git a/.agents/skills/xtend-to-java/SKILL.md b/.agents/skills/xtend-to-java/SKILL.md index 73fe174164..aa6b8589b9 100644 --- a/.agents/skills/xtend-to-java/SKILL.md +++ b/.agents/skills/xtend-to-java/SKILL.md @@ -105,15 +105,15 @@ Use this table for quick mechanical transforms. Full details in the rule files. | `obj?.method()` | `obj != null ? obj.method() : null` (or guard clause) | | `x ?: default` | `x != null ? x : default` | | `===` / `!==` (identity) | `==` / `!=` | -| `==` / `!=` (equality) | `.equals()` / `!Objects.equals(a, b)` | +| `==` / `!=` (equality, object operands) | `.equals()` / `!Objects.equals(a, b)` — primitives keep `==`/`!=` (see [`rules/08`](rules/08-operator-overloads.md) §8.1) | | `a..b` (range) | `IntStream.rangeClosed(a, b)` | ### Lambdas and collections | Xtend | Java | |-------|------| -| `[param \| body]` | `(param) -> { return body; }` | -| `[body]` (implicit `it`) | `(it) -> { return body; }` — name the parameter explicitly | +| `[param \| body]` | `(param) -> body` (braces + `return` only for multi-statement) | +| `[body]` (implicit `it`) | `(it) -> body` — name the parameter explicitly | | `list.filter[condition]` | `list.stream().filter(x -> condition).toList()` | | `list.map[transform]` | `list.stream().map(x -> transform).toList()` | | `list.forEach[action]` | `list.forEach(x -> action)` (or `for` loop) | diff --git a/.agents/skills/xtend-to-java/examples/00-basic-generator.md b/.agents/skills/xtend-to-java/examples/00-basic-generator.md index 7859716ff9..00c7ded08e 100644 --- a/.agents/skills/xtend-to-java/examples/00-basic-generator.md +++ b/.agents/skills/xtend-to-java/examples/00-basic-generator.md @@ -101,4 +101,4 @@ public class MyGenerator { - **Template → StringBuilder** (tier 4) because the template has `«IF»` and `«FOR»` control flow. - **`it` parameter renamed** to `model` (descriptive name). - **`Iterables.filter(iter, Type.class)`** kept as Guava — genuinely more concise for type-safe filtering. -- **Whitespace verified against `xtend-gen/`** — the template output was confirmed by reading the generated code. +- **Whitespace must be verified against `xtend-gen/`** — for a real migration, confirm the template output by reading the generated code (this example illustrates the shape). diff --git a/.agents/skills/xtend-to-java/examples/01-template-with-for-loop.md b/.agents/skills/xtend-to-java/examples/01-template-with-for-loop.md index d0790024ca..42b4b2367f 100644 --- a/.agents/skills/xtend-to-java/examples/01-template-with-for-loop.md +++ b/.agents/skills/xtend-to-java/examples/01-template-with-for-loop.md @@ -16,7 +16,7 @@ When the body is a simple expression, use `Collectors.joining()`: ```java public CharSequence renderArgs(final List args) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("("); builder.append(args.stream() .map(a -> a.getType() + " " + a.getName()) @@ -32,7 +32,7 @@ When the body has multi-statement logic, use a flag: ```java public CharSequence renderArgs(final List args) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(512); builder.append("("); boolean first = true; for (final Argument a : args) { @@ -52,4 +52,4 @@ public CharSequence renderArgs(final List args) { - The `«FOR … SEPARATOR ", "»` block became either a stream with `Collectors.joining(", ")` or a boolean flag. - The `«a.type»` and `«a.name»` interpolations became `a.getType()` and `a.getName()`. - The trailing newline (implicit `\n` at end of template `'''`) is preserved by explicit `"\n"`. -- **Whitespace was verified against `xtend-gen/`** — the template starts with `(` directly (no leading newline because the first `'''` line has content after the opening mark). +- **Whitespace must be verified against `xtend-gen/`** — note the template starts with `(` directly (no leading newline because the first `'''` line has content after the opening mark). diff --git a/.agents/skills/xtend-to-java/rules/00-decisions.md b/.agents/skills/xtend-to-java/rules/00-decisions.md index 9bb3d23645..47e0582be3 100644 --- a/.agents/skills/xtend-to-java/rules/00-decisions.md +++ b/.agents/skills/xtend-to-java/rules/00-decisions.md @@ -44,7 +44,7 @@ Use Java standard library for collections and streams. Keep Guava only where it ## String building — 4-tier decision tree -Choose the most readable Java idiom based on the template pattern: +Choose the most readable Java idiom based on the template pattern (evaluate top-down, first match wins): | # | Template pattern | Java idiom | |---|---|---| @@ -53,12 +53,6 @@ Choose the most readable Java idiom based on the template pattern: | 3 | Interpolation, no control flow | `.formatted()` (text block if multi-line, literal if single-line) | | 4 | Control flow (`«IF»`, `«FOR»`) | `StringBuilder` with explicit `if`/`for` | -**Decision rules — in order:** -1. **No interpolation, single line** → string literal -2. **No interpolation, multi-line** → text block -3. **Interpolation, no control flow** → `.formatted()` (on text block if multi-line, on literal if single-line) -4. **Control flow** → `StringBuilder` — always - **`.formatted()` limitations — fall back to concatenation ONLY when:** - The interpolated expression is glued to adjacent text with no whitespace/delimiter boundary, making `%s` ambiguous (e.g., `"pre" + expr + "suf"` where `"pre%ssuf"` is confusing) - The template contains literal `%` characters (would need escaping as `%%`) diff --git a/.agents/skills/xtend-to-java/rules/01-imports-and-package.md b/.agents/skills/xtend-to-java/rules/01-imports-and-package.md index 5324acb0d3..0c15298958 100644 --- a/.agents/skills/xtend-to-java/rules/01-imports-and-package.md +++ b/.agents/skills/xtend-to-java/rules/01-imports-and-package.md @@ -16,23 +16,23 @@ Keep identical. Add a trailing semicolon if missing. ## 1.3 Import order convention -Follow the project's Eclipse import order — **standard/framework first, project-specific second**: +Canonical order (ground truth from migrated files): **`java.*` → `org.*` → `com.*`**, one blank +line between groups, alphabetical by full path within each group. `javax.*` sorts with `java.*`; +`junit.*` sorts inside `org.*` (it is `org.junit.*`). Static imports form their own block. ```java -// Group 1: org.*, java.*, javax.*, junit.* (standard/framework) -import org.eclipse.xtext.testing.InjectWith; -import org.junit.jupiter.api.Test; +// Group 1: java.* / javax.* import java.util.List; -// Blank line separator +// Group 2: org.* (incl. org.junit.*) +import org.eclipse.xtext.testing.InjectWith; +import org.junit.jupiter.api.Test; -// Group 2: com.* (project-specific: com.avaloq.*, com.google.*, etc.) +// Group 3: com.* (com.avaloq.* before com.google.*) import com.avaloq.tools.ddk.check.core.test.util.CheckTestUtil; import com.google.inject.Inject; ``` -Within each group, imports are sorted alphabetically. There is always exactly one blank line between the two groups. - ## 1.4 Class declaration - Xtend classes are `public` by default. Make this explicit in Java. diff --git a/.agents/skills/xtend-to-java/rules/04-templates.md b/.agents/skills/xtend-to-java/rules/04-templates.md index 58233cab13..1553404e8d 100644 --- a/.agents/skills/xtend-to-java/rules/04-templates.md +++ b/.agents/skills/xtend-to-java/rules/04-templates.md @@ -162,6 +162,10 @@ The `\` suppresses the line terminator. Place the closing `"""` at column 0 to p **When to use this pattern:** check the `xtend-gen/` output. If the original string starts with `\n` and does NOT end with `\n`, the `\` escape is the correct approach. +Text blocks also strip trailing whitespace on every content line; if `xtend-gen/` shows +significant trailing spaces, preserve them with the `\s` escape. See +[`workflow/known-pitfalls.md`](../workflow/known-pitfalls.md) (text-block row). + ## 4.4 Return type Methods that return templates should return `CharSequence` (matches `StringBuilder`). @@ -241,4 +245,4 @@ these source-verified semantics decide what is safe: **Verification:** each coalesced run must be proven byte-identical with an executable old-vs-new harness over an input battery (empty / single-line / multi-line / newline-terminated / `%`-bearing -values), per the ledger's Method 1. +values). diff --git a/.agents/skills/xtend-to-java/rules/08-operator-overloads.md b/.agents/skills/xtend-to-java/rules/08-operator-overloads.md index 0bae086929..ae1c3a71ed 100644 --- a/.agents/skills/xtend-to-java/rules/08-operator-overloads.md +++ b/.agents/skills/xtend-to-java/rules/08-operator-overloads.md @@ -5,6 +5,7 @@ - `===` (Xtend identity-equals) → `==` (Java) - `!==` (Xtend identity-not-equals) → `!=` (Java) - `==` in Xtend is `.equals()` — convert to `.equals()` or `Objects.equals()` (use `Objects.equals()` when either operand could be null). +- **Applies to object/boxed operands.** `==`/`!=` between primitive-typed operands (int, long, short, byte, char, float, double, boolean) compile to Java `==`/`!=`, not `.equals()` — check operand types in `xtend-gen/` first. (Enums are NOT primitives: enum `==` follows the object form shown in `xtend-gen/`.) ## 8.2 Null-safe navigation `?.` diff --git a/.agents/skills/xtend-to-java/rules/09-misc-syntax.md b/.agents/skills/xtend-to-java/rules/09-misc-syntax.md index 1abebd4453..5ec9596658 100644 --- a/.agents/skills/xtend-to-java/rules/09-misc-syntax.md +++ b/.agents/skills/xtend-to-java/rules/09-misc-syntax.md @@ -155,7 +155,7 @@ Rules: - **Multiple return paths**: Xtend implicitly returns the last expression. Add explicit `return` on **every** non-void path. - **`class` keyword as literal**: `SomeClass` used as a class literal → `SomeClass.class`. - **Static method reference `::`**: `ClassName::methodName` → `ClassName.methodName()` (or keep as a Java method reference where the receiving API accepts one). -- **Pairs**: `key -> value` (in pair-construction context) → `Pair.of(key, value)` or `Map.entry(key, value)`. +- **Pairs**: `key -> value` compiles to `org.eclipse.xtext.xbase.lib.Pair` — never keep it in migrated Java. Use a small `private record` (nulls OK) or `Map.entry` (rejects null); see [`workflow/known-pitfalls.md`](../workflow/known-pitfalls.md) (xbase.lib row). - **`^keyword`** (escaped reserved word in Xtend): Drop the `^` — most Xtend escapes aren't Java keywords. ## 9.9 Guice DI diff --git a/.agents/skills/xtend-to-java/workflow/formatting-and-commit.md b/.agents/skills/xtend-to-java/workflow/formatting-and-commit.md index 33ea532fd7..e70167a835 100644 --- a/.agents/skills/xtend-to-java/workflow/formatting-and-commit.md +++ b/.agents/skills/xtend-to-java/workflow/formatting-and-commit.md @@ -106,3 +106,10 @@ refactor: drop Xtend build infrastructure from # when applicable The rename commit body must state that it is a pure `git mv` and intentionally non-compiling. PR title: `refactor: migrate Xtend to Java - `. + +## Rollback + +Undo the whole slice: `git reset --hard HEAD~N` where N = commits in the slice (2, or 3 with +infra). Plain `HEAD~1` reverts only the translate and strands the pure-`git mv` rename commit — +a `.java` holding Xtend that won't compile. If already pushed: `git revert +` — not `-m 1` (the rebase-merged commits are not merge commits). diff --git a/.agents/skills/xtend-to-java/workflow/known-pitfalls.md b/.agents/skills/xtend-to-java/workflow/known-pitfalls.md index 27ed1c7857..16fa0cde31 100644 --- a/.agents/skills/xtend-to-java/workflow/known-pitfalls.md +++ b/.agents/skills/xtend-to-java/workflow/known-pitfalls.md @@ -11,12 +11,9 @@ Consolidated table of common mistakes and their fixes. Review before and after e | **Implicit returns** | Xtend methods return the last expression. The compiler catches missing returns but not wrong ones. | | **Property access vs getter** | Xtend `obj.name` may call `getName()`. In Java, write `obj.getName()` explicitly. Check `xtend-gen/` if unsure. | | **`CoreException` handling** | Xtend silently wraps checked exceptions. Java doesn't. Add explicit `try/catch` — the `xtend-gen/` file shows what was generated. | -| **`val` leaks** | Never use `var`. Use the explicit type. | | **Invented Javadoc** | Never add **class/member Javadoc** that wasn't in the original. This is a migration, not a rewrite. (The file copyright header is the one exception — see next row — it is always normalised, not preserved.) | | **Generated supertypes live in `src-gen/`, not `xtend-gen/`** | When the class extends/overrides a generated `Abstract*` base (Module/Setup/runtime/UI), read that base in `src-gen/` (committed, present without a build — unlike `xtend-gen/`) for inherited constructor signatures, the real `@Override` targets, and the return types Xtend inferred. Don't guess the supertype API. | -| **Copyright header ≠ "preserve original"** | The file MUST start with the Avaloq banner header, **replacing** whatever the source had — including a `/* generated by Xtext x.y */` stub marker or a `/** … */` Javadoc-style copyright block (these are the easy ones to wrongly "preserve", especially on IDE module/setup stubs). Normalising to the banner is required, not inventing. Match a sibling `.java` in the module. | -| **Missing `@throws` tags** | When Java migration adds `throws` and method already has Javadoc, Checkstyle requires `@throws`. Add it; don't create Javadoc just for the tag. | -| **Duplicate string literals** | Checkstyle flags strings appearing 2+ times. In tests, extract to constants. In generators, use `CHECKSTYLE:CONSTANTS-OFF/ON`. | +| **Copyright header ≠ "preserve original"** | Always normalise to the Avaloq banner, replacing whatever the source had — see [`formatting-and-commit.md`](./formatting-and-commit.md) §Copyright header. | | **`@Data` / `@Accessors`** | These generate code at compile time. The `xtend-gen/` output shows exactly what — copy equals/hashCode/toString/getters from there. | | **`@Tag` fields must not be `final`** | `TagExtension` assigns tag values via `Field.setInt()` at runtime. `Field.setInt()` on a `final` field fails on Java 9+ even after `setAccessible(true)`. IDE formatters and save-actions silently add `final` to `int` fields — always strip it from `@Tag` fields. See [`rules/09-misc-syntax.md`](../rules/09-misc-syntax.md) §9.6. | | **`BasicEList` in generic code** | Needs explicit type parameter — `new BasicEList()`. | @@ -24,14 +21,13 @@ Consolidated table of common mistakes and their fixes. Review before and after e | **Non-parameterized logging** | Xtend files often have `"msg" + x` in log calls. Fix to `{}` placeholders. | | **PMD missing type-resolution** | Always `compile` before `pmd:check` or you'll miss `MissingOverride`, `LooseCoupling` etc. | | **`--fail-at-end` hides failures** | Check the final BUILD line, not intermediate output. | -| **Dispatch method names** | Keep underscores. Suppress with `@SuppressWarnings`. Never rename. | | **IDE save actions** | "Organize Imports" in Eclipse may trigger save actions that auto-convert string concatenation to text blocks. Auto-conversion produces wrong results. Review `git diff` after any IDE action. | -| **Import order** | Two groups (blank line between, no wildcards): framework (`java.*`/`javax.*`/`org.*`) first, then `com.*` alphabetically — so `com.avaloq.*` precedes `com.google.*`. Not enforced by checkstyle (no `ImportOrder` module); wrong order is diff churn only. | +| **Import order** | See [`rules/01-imports-and-package.md`](../rules/01-imports-and-package.md) for the canonical order. Not enforced by checkstyle (no `ImportOrder` module); wrong order is diff churn only — `com.avaloq.*` precedes `com.google.*`. | | **Eclipse CLI formatter** | Does NOT organize imports — only code formatting. Import order must be correct from the start. | | **IllegalCatch / IllegalThrows** | checkstyle `IllegalCatch` bans `catch (Exception/Throwable/RuntimeException)` — use the specific type, or a multi-catch (`catch (BadLocationException \| TemplateException e)`) re-thrown as `new IllegalStateException(e)`. `IllegalThrows` bans `throws Throwable/RuntimeException/Error` (plain `throws Exception` IS allowed — acceptable on a `@Test` when the JUnit-invoked API declares it; otherwise narrow to the actual checked type). Don't suppress `PMD.AvoidCatchingGenericException`. | -| **Rollback** | If already pushed: `git revert -m 1 `. If local only: `git reset --hard HEAD~1`. After reverting, build and test. | +| **Rollback** | A slice is 2-3 commits — plain `HEAD~1` strands the rename commit. Use the recipe in [`formatting-and-commit.md`](./formatting-and-commit.md) §Rollback. After reverting, build and test. | | **`ByteArrayInputStream.close()`** | It's a no-op. Safe to remove entirely. | -| **`==` in Xtend** | Xtend `==` is `.equals()`, not identity. Convert to `.equals()` or `Objects.equals()`. Only `===`/`!==` are identity. | +| **`==` in Xtend** | On object/boxed operands, Xtend `==` is `.equals()` — convert to `.equals()`/`Objects.equals()`; only `===`/`!==` are identity. Between primitive-typed operands it compiles to Java `==` — check operand types in `xtend-gen/` (see [`rules/08-operator-overloads.md`](../rules/08-operator-overloads.md) §8.1). | ## Learnings from the per-module migration campaign diff --git a/.agents/skills/xtend-to-java/workflow/multi-file-batch.md b/.agents/skills/xtend-to-java/workflow/multi-file-batch.md index 72dc1d0699..32332f8008 100644 --- a/.agents/skills/xtend-to-java/workflow/multi-file-batch.md +++ b/.agents/skills/xtend-to-java/workflow/multi-file-batch.md @@ -46,19 +46,15 @@ A red gate means you do not start the next batch. Diagnose first. a pure `git mv` rename commit for all `.xtend` in the slice, an in-place translate commit, and — when the module is fully off Xtend — an infrastructure-cleanup commit. -Commit message format: -``` -refactor: migrate Xtend to Java - (1/2: rename sources) -refactor: migrate Xtend to Java - (2/2: translate to Java 21) -``` -Example: `refactor: migrate Xtend to Java - com.avaloq.tools.ddk.check.core.test` +Commit message format: see [`formatting-and-commit.md`](./formatting-and-commit.md). +Example: `refactor: migrate Xtend to Java - com.avaloq.tools.ddk.check.core.test (1/2: rename sources)` ### Rollback strategy If a batch fails any validation gate: 1. **Do not force-commit.** -2. Revert: `git reset --hard HEAD~1` (or `git revert -m 1 ` if already pushed). +2. Revert the whole slice per [`formatting-and-commit.md`](./formatting-and-commit.md) §Rollback (a slice is 2-3 commits — plain `HEAD~1` strands the rename commit). 3. Diagnose the failure file-by-file. 4. **Pin** any individually-problematic file for separate investigation. Skip it; do the remaining files. 5. Re-attempt without the pinned files. Tackle pins as one-off conversions afterwards. diff --git a/.agents/skills/xtend-to-java/workflow/one-file-conversion.md b/.agents/skills/xtend-to-java/workflow/one-file-conversion.md index 2a4d15df73..e564912901 100644 --- a/.agents/skills/xtend-to-java/workflow/one-file-conversion.md +++ b/.agents/skills/xtend-to-java/workflow/one-file-conversion.md @@ -11,7 +11,7 @@ Use this when converting a single `.xtend` to its `.java` counterpart. 5. **Apply rules in order.** Walk [`rules/01-...`](../rules/01-imports-and-package.md) through [`rules/09-...`](../rules/09-misc-syntax.md) for the constructs you identified. 6. **Write the `.java` file.** Match `xtend-gen/` behavior exactly while using idiomatic Java. 7. **Run the validation checklist.** [`workflow/validation-checklist.md`](./validation-checklist.md). Every item must pass. -8. **Delete the `.xtend` file** as part of the same commit. Don't leave both. +8. **Commit as two steps** — a pure `git mv` rename commit, then an in-place translate commit; see [`formatting-and-commit.md`](./formatting-and-commit.md) §Commit structure. For a single file the `git mv` IS the removal; do not delete+re-add. 9. **Verify the file compiles:** ```bash mvn -pl : -am -DskipTests compile -f ./ddk-parent/pom.xml > mvn-output.txt 2>&1 diff --git a/.agents/skills/xtend-to-java/workflow/overview.md b/.agents/skills/xtend-to-java/workflow/overview.md index a9b1a7132b..0a9e58e318 100644 --- a/.agents/skills/xtend-to-java/workflow/overview.md +++ b/.agents/skills/xtend-to-java/workflow/overview.md @@ -8,6 +8,14 @@ This is the full end-to-end workflow for migrating Xtend files to Java in dsl-de To get a deterministic overview of remaining Xtend work, run one of these commands from the repository root. +On macOS / Linux (bash): + +```bash +find . -name "*.xtend" -path "*/src/*" -not -path "*/bin/*" \ + | awk -F'/src/' '{print $1}' \ + | sort | uniq -c | sort -n +``` + On Windows (PowerShell): ```powershell @@ -23,14 +31,6 @@ Get-ChildItem -Recurse -Filter "*.xtend" -Path "." | Format-Table -AutoSize ``` -On macOS / Linux (bash): - -```bash -find . -name "*.xtend" -path "*/src/*" -not -path "*/bin/*" \ - | awk -F'/src/' '{print $1}' \ - | sort | uniq -c | sort -n -``` - Both list per-module Xtend file counts so you can plan slice scope. ### Scoping the session @@ -56,8 +56,8 @@ Always branch from **master** (or the project's main integration branch): ```bash SLICE=migrate/xtend-to-java/ -git fetch origin -git checkout -b "$SLICE" origin/master +git fetch upstream +git checkout -b "$SLICE" upstream/master ``` For stacked multi-slice migrations, suffix the branch name with `-step-N` @@ -168,14 +168,14 @@ Xtend's template whitespace rules: After reading both references, write Java that: 1. **Matches the `xtend-gen/` behavior exactly** for all string outputs, method signatures, and control flow 2. **Uses idiomatic Java** (text blocks, `.formatted()`, concatenation) instead of `StringConcatenation` -3. **Preserves the original class/member Javadoc exactly** — never invent. (The file copyright header is the exception: always normalise it to the Avaloq banner per [`formatting-and-commit.md`](./formatting-and-commit.md) — replacing any generated-stub or Javadoc-style header — which is not "inventing".) +3. **Preserves the original class/member Javadoc exactly** — never invent. (Copyright header excepted: always normalise it to the Avaloq banner per [`formatting-and-commit.md`](./formatting-and-commit.md).) 4. **Follows the quality checklist** in [`workflow/validation-checklist.md`](./validation-checklist.md) --- ## Step 4 — Apply the quality checklist -See [`workflow/validation-checklist.md`](./validation-checklist.md) — all 30 rules must pass. +See [`workflow/validation-checklist.md`](./validation-checklist.md) — every rule must pass. --- diff --git a/.agents/skills/xtend-to-java/workflow/validation-checklist.md b/.agents/skills/xtend-to-java/workflow/validation-checklist.md index 03c1804b51..5af79f33a1 100644 --- a/.agents/skills/xtend-to-java/workflow/validation-checklist.md +++ b/.agents/skills/xtend-to-java/workflow/validation-checklist.md @@ -4,7 +4,11 @@ Run through this list before declaring a conversion done. Every item is a hard g --- -## Quality rules (all 34 must pass) +## Quality rules + +Every rule below is a hard gate. + +> `#` is a stable rule ID (assigned in discovery order), not a sequence; rows are grouped by topic. Do not renumber — cross-refs ("rule 21", "rule 22", §4.8→rule 35) depend on these IDs. ### Javadoc and comments @@ -54,7 +58,7 @@ Run through this list before declaring a conversion done. Every item is a hard g | # | Rule | Requirement | |---|------|-------------| | 10 | No wildcard imports | Every import explicit. | -| 11 | Import order | `org.*`/`java.*`/`javax.*`/`junit.*` first, blank line, then `com.*`. Alphabetical within groups. | +| 11 | Import order | `java.*` → `org.*` → `com.*`, blank line between groups, alphabetical by full path within each group; `junit.*` sorts inside `org.*`; static imports form their own block. See [`rules/01-imports-and-package.md`](../rules/01-imports-and-package.md). | ### Exception handling @@ -127,7 +131,7 @@ Run through this list before declaring a conversion done. Every item is a hard g - [ ] All comments and class/member Javadoc preserved exactly. - [ ] Copyright header is the exact Avaloq banner — **replacing** any generated-stub or Javadoc-style header the source had (not preserved from source). - [ ] Checked exceptions handled (`throws` clause or `try`/`catch` with specific types). -- [ ] The `.xtend` file is deleted; the `.java` file is added; both never coexist. +- [ ] The `.xtend` no longer exists — renamed to `.java` via `git mv` then translated in place; no `.xtend`/`.java` pair coexists. See rule 22. ---