diff --git a/plugins/aem/cloud-service/skills/code-assessment/asset-manager/SKILL.md b/plugins/aem/cloud-service/skills/code-assessment/asset-manager/SKILL.md index 70b3e5cf..6d0e272e 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/asset-manager/SKILL.md +++ b/plugins/aem/cloud-service/skills/code-assessment/asset-manager/SKILL.md @@ -56,6 +56,30 @@ license: Apache-2.0 --- +## Discovery + +Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook: + +```bash +bash ../scripts/analyze.sh --pattern asset-manager +``` + +**Match criteria (what the detector flags):** in a file importing **`com.day.cq.dam.api.AssetManager`**, a call to **`createAssetForBinary`**, **`getAssetForBinary`**, **`removeAssetForBinary`**, or **`createAsset`**. **One finding per call site** (each call is individually actionable, unlike the class-level patterns), with the call as the snippet. Parse-level only — gated on the import; the receiver type is not resolved, so an unrelated `createAsset(...)` in the same file could match (rare). + +## Resolution contract + +**guided** — `apply (guided)`. The analyzer reports each legacy call site; remediation is judgment-based, routed by the call (create/upload → C1–C3, delete → D1–D3) and applied in an apply session. + +| Call site | Disposition | +|---|---| +| `createAssetForBinary` / `getAssetForBinary` (removed on CS) | apply (guided) → C1–C3 | +| `removeAssetForBinary` (removed on CS) | apply (guided) → D1–D3 | +| Client-facing `createAsset(...)` upload | apply (guided) → C1–C3 (Direct Binary Access) | +| In-JVM back-office `createAsset(...)` with a service-user resolver | skipped: `already-compliant` | +| Test code (`src/test/`) | skipped: `test-scope` | + +--- + ## Complete example — Path A (create / upload) ### Before (client-facing upload via `AssetManager.createAsset`) diff --git a/plugins/aem/cloud-service/skills/code-assessment/event-migration/SKILL.md b/plugins/aem/cloud-service/skills/code-assessment/event-migration/SKILL.md index 718560fb..8f9d6159 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/event-migration/SKILL.md +++ b/plugins/aem/cloud-service/skills/code-assessment/event-migration/SKILL.md @@ -75,6 +75,32 @@ A typo'd topic string compiles fine and silently subscribes to a topic that noth --- +## Discovery + +Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook: + +```bash +bash ../scripts/analyze.sh --pattern event-migration +``` + +**Match criteria (what the detector flags):** a class that **`implements org.osgi.service.event.EventHandler`** or **`javax.jcr.observation.EventListener`** (import-aware) — both map here per the BPA subtype taxonomy. + +Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause; the subscribed topic (resource vs non-resource) is not resolved at detection, so topic-based routing to `resource-change-listener` happens during remediation (see Routing / Classification). A class implementing both an event interface and `ResourceChangeListener` is flagged by both patterns (rare). + +## Resolution contract + +**guided** — `apply (guided)`. The analyzer locates each handler/listener; remediation is judgment-based and applied via E0–E5 (per the Classification above) in an apply session. **Rows are evaluated top-down — first match wins**, so resource/content observation routes to `resource-change-listener` *before* the E0 fall-through is considered. + +| Site shape | Disposition | +|---|---| +| Observes repository content — a `javax.jcr.observation.EventListener` watching content, or an `EventHandler` on a resource topic (`org/apache/sling/api/resource/Resource/*`) | skipped: `wrong-pattern` (use `resource-change-listener`) | +| `EventHandler` on a non-resource topic (replication / workflow / custom), `handleEvent()` does heavy work | apply (guided) → E1–E5 | +| Legacy `javax.jcr.observation.EventListener` that **genuinely cannot** be modeled as a `ResourceChangeListener` (rare residual) | apply (guided) → E0 then E1–E5 | +| `EventHandler` on a non-resource topic, `handleEvent()` only enqueues a Sling Job | skipped: `already-compliant` | +| Test code (`src/test/`) | skipped: `test-scope` | + +--- + ## Complete example — before and after ### Before (replication EventHandler with inline business logic) diff --git a/plugins/aem/cloud-service/skills/code-assessment/references/runbook.md b/plugins/aem/cloud-service/skills/code-assessment/references/runbook.md index fbf91be9..01d8bb90 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/references/runbook.md +++ b/plugins/aem/cloud-service/skills/code-assessment/references/runbook.md @@ -51,7 +51,7 @@ Match the request to one expert skill under `code-assessment//` using t ### 2. Read reference module -Read the chosen expert skill's `SKILL.md` then its `recipe.md` (or `path-*.md`) in full — **Discovery**, input contract, recipe, Unlocatable, editing strategy. +Read the chosen expert skill's `SKILL.md` in full, then its `recipe.md` / `path-*.md` if present (guided patterns may carry the migration steps inline instead) — **Discovery**, **Resolution contract**, input contract, recipe/steps, Unlocatable, editing strategy. ### 3. Resolve findings (with_findings or discover) @@ -181,7 +181,18 @@ Copy this structure; keep section headings so runs are comparable across session ## Candidates | File | Finding | Planned action | Target / notes | |------|---------|----------------|----------------| -| | | apply \| skipped | | +| : | | apply \| skipped \| apply (guided) | | + +**Same columns for every pattern — mechanical *and* guided.** `Finding` is the analyzer `snippet` +(present for every pattern). `Planned action` is the **per-site disposition from that pattern's own +Resolution contract** — `apply`, `apply → N`, `skipped — ` (e.g. `needs-pagination`, +`test-scope`, `already-compliant`), or `apply (guided)` for architectural patterns whose +Resolution contract has no finer per-site action (remediation opens the expert guide — name it in +*Target / notes*). **Do not collapse a pattern to one blanket action from its `fix` kind:** a +`fix: guided` pattern that triages sites (e.g. `unbounded-query`: bound some, skip others) shows +that triage per row, not a uniform `apply (guided)`. When several patterns are in play, group rows +under per-pattern subheadings ordered by `severity`; never drop a column or render a pattern as a +bare file list. ## Summary counts - Apply: diff --git a/plugins/aem/cloud-service/skills/code-assessment/replication/SKILL.md b/plugins/aem/cloud-service/skills/code-assessment/replication/SKILL.md index 32d7f8a7..c350f61b 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/replication/SKILL.md +++ b/plugins/aem/cloud-service/skills/code-assessment/replication/SKILL.md @@ -53,6 +53,30 @@ Identify the source pattern in the file: --- +## Discovery + +Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook: + +```bash +bash ../scripts/analyze.sh --pattern replication +``` + +**Match criteria (what the detector flags):** a file that imports **`com.day.cq.replication.Replicator`** or any **`org.apache.sling.replication.*`** type — the legacy replication APIs removed on Cloud Service. One finding per file, at the file's primary type, with the class header as the snippet. Parse-level only — import-based, no type resolution. The modern `org.apache.sling.distribution.*` API is not flagged. + +> Analyzer-only: `replication` has no BPA subtype, so a `replication` finding originates from the local analyzer, never from a BPA/CAM report. + +## Resolution contract + +**guided** — `apply (guided)`. The analyzer locates each legacy replication caller; remediation is judgment-based (CQ `Replicator` / Sling Replication Agent → Sling Distribution API) and applied via P1–P4 in an apply session. + +| Site shape | Disposition | +|---|---| +| `Replicator` / Sling Replication Agent usage in custom code | apply (guided) → P1–P4 | +| Replication tied to a workflow step (workflow owns it) | skipped: `workflow-owned` | +| Test code (`src/test/`) | skipped: `test-scope` | + +--- + ## Complete example — before and after ### Before (legacy CQ Replicator with admin resolver) diff --git a/plugins/aem/cloud-service/skills/code-assessment/resource-change-listener/SKILL.md b/plugins/aem/cloud-service/skills/code-assessment/resource-change-listener/SKILL.md index 370e39ba..69ef81b3 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/resource-change-listener/SKILL.md +++ b/plugins/aem/cloud-service/skills/code-assessment/resource-change-listener/SKILL.md @@ -53,6 +53,31 @@ Three CS-specific constraints every listener must satisfy: --- +## Discovery + +Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook: + +```bash +bash ../scripts/analyze.sh --pattern resource-change-listener +``` + +**Match criteria (what the detector flags):** a class that **`implements org.apache.sling.api.resource.observation.ResourceChangeListener`** or **`ExternalResourceChangeListener`** (import-aware) — the modern API, flagged for review against the lightweight + JobConsumer contract. + +Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause; reached-via-base-class is not resolved. Legacy `javax.jcr.observation.EventListener` is detected by the `event-migration` pattern (matching the BPA subtype taxonomy); when its logic is plain content observation, that guide routes it back here. A class implementing both `ResourceChangeListener` and an event interface is flagged by both patterns (rare). + +## Resolution contract + +**guided** — `apply (guided)`. The analyzer locates each `ResourceChangeListener`; remediation is judgment-based and applied via R0–R5 (per the Classification above) in an apply session. + +| Site shape | Disposition | +|---|---| +| `implements ResourceChangeListener`, `onChange()` does repository/JCR/heavy work | apply (guided) → R1–R5 | +| Legacy `javax.jcr.observation.EventListener` / resource-topic `EventHandler` routed here *(arrives via `event-migration` redirect or migration handoff — this pattern's own detector flags only the modern API)* | apply (guided) → R0 then R1–R5 | +| `implements ResourceChangeListener`, `onChange()` only enqueues a Sling Job | skipped: `already-compliant` | +| Test code (`src/test/`) | skipped: `test-scope` | + +--- + ## Complete example — before and after ### Before (legacy JCR `EventListener` with inline logic and admin resolver) diff --git a/plugins/aem/cloud-service/skills/code-assessment/scheduler/SKILL.md b/plugins/aem/cloud-service/skills/code-assessment/scheduler/SKILL.md index 0e865a22..856b3667 100644 --- a/plugins/aem/cloud-service/skills/code-assessment/scheduler/SKILL.md +++ b/plugins/aem/cloud-service/skills/code-assessment/scheduler/SKILL.md @@ -43,6 +43,35 @@ Three properties control every scheduler: --- +## Discovery + +Detection is performed by the analyzer ([`../scripts/analyze.sh`](../scripts/README.md)), run by the runbook: + +```bash +bash ../scripts/analyze.sh --pattern scheduler +``` + +**Match criteria (what the detector flags):** + +- A class that **`implements org.apache.sling.commons.scheduler.Job`** (import-aware). +- The **OSGi-property scheduler** shape — a class that **`implements Runnable`** and carries an OSGi `@Component` declaring a `scheduler.expression` / `scheduler.name` / `scheduler.period` property. +- A file that **imports `org.apache.sling.commons.scheduler.Scheduler`** (programmatic use via an injected `Scheduler`) but has no class-level match — one finding at the file's primary type. + +Emitted at the class declaration, with the class header as the snippet. Parse-level only — direct `implements` clause and same-file `@Component`; reached-via-base-class and constant-valued properties are not resolved. + +## Resolution contract + +**guided** — `apply (guided)`. The analyzer locates and reports each scheduler class; remediation is judgment-based and routed by the Classification above to **Path A** ([path-a.md](path-a.md), Runnable + OSGi properties) or **Path B** ([path-b.md](path-b.md), Sling Jobs via `JobManager`). Open the chosen path and apply its steps in an apply session. + +| Site shape | Disposition | +|---|---| +| Single-schedule, hardcoded cron, `implements Runnable` | apply (guided) → path-a.md | +| Config-driven cron, multiple schedules, `implements Job`, or `ScheduleOptions.config()` | apply (guided) → path-b.md | +| Already Sling Jobs via `JobManager` with single-execution guard | skipped: `already-compliant` | +| Test code (`src/test/`) | skipped: `test-scope` | + +--- + ## Review Checklist Use the path-specific checklists in [path-a.md](path-a.md) and [path-b.md](path-b.md) for scheduler mechanics.