- conventions §1.4: variant CSS modifier classes must keep the base class
(emit 'split split--text-first', not the modifier alone — else display:grid
is lost and a 2-col split stacks).
- conventions §2: custom decorate() must MOVE authored nodes, not re-wrap
innerHTML (re-wrapping double-wraps <p>/<h1> and drops media the moment a
cell holds block elements — hand-authored or fill-script-emitted).
- fill-script-pattern: field-coverage assertion — diff captured keys against
mapped slots and fail on unmapped, so a forgotten field can't silently
delete an entire section.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
aem-import-site/reference/templates/ (NEW dir):
link-audit.mjs — Phase 7 link audit
build-redirects.mjs — generate /redirects.json from query-index
mass-edit.mjs — Phase 9 mass DA-source amendment (project pastes
a mutate() function)
retry-mass-edit.mjs — sequential retry of failed mass-edit paths
README.md — per-template purpose + .env requirements +
copy-in usage examples
All config via .env (DA_TOKEN, DA_ORG, DA_REPO, EDS_PREVIEW_ORIGIN);
templates parse from .env at startup. No hardcoded org/repo/host —
copy + .env edit only.
Establishes the convention that the skill's reference/ dir may ship
.mjs templates alongside .md docs; the templates are explicit
ready-to-copy artifacts, not auto-installed.
SKILL.md Setup section: list the .env keys + the cp-from-skill workflow.
References section: link the templates dir.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
SKILL.md Procedure section rewritten: 6 phases (0-5) → 10 phases
(-1 through 9, plus phase 10 completion report). The new flow captures
the full migration arc end-to-end including the post-batch work that
the previous 6-phase shape stopped short of.
Phase -1 Pre-flight check (NEW) — token / permissions / structure
Phase 0 Site inventory + clustering
Phase 1 Mode-pick + pageType assignment — enhanced with pageType field
Phase 2 Per-template execution (one rep) — CLS Day-1 gate
Phase 3 Hub landing pages FIRST (NEW) — every chrome destination live
Phase 4 Per-template fill script — (was Phase 3)
Phase 5 Smoke-test batch (NEW) — --limit 5 + review
Phase 6 Full batch + verify — (combines old 4 + 5)
Phase 7 Link audit (NEW) — prioritized missing-pages list
Phase 8 Gap-fill sprint (NEW) — author top-N from audit
Phase 9 Polish (NEW) — redirects, dynamic conversions,
CLS re-measure, chrome consistency,
orphan management
Phase 10 Completion report (NEW) — written deliverable
Each phase has an explicit completion artifact and (where indicated)
a user-review gate. The phase-summary table at the top of Procedure
declares all of them upfront.
Setup section: includes scaffolding `scripts/utils/` with the
standard utility templates from Day 1.
5 new reference files round out the workflow:
reference/page-shape-inventory.md — typical catalog/dealer
page-shape inventory (counts, pageTypes, suggested modes) for
Day 1 planning. Generalizes from observed patterns; default
inventory for any multi-thousand-page migration.
reference/dynamic-vs-static.md — decision tree for when to author
content statically vs derive at render time. Catches common
false positives (breadcrumbs, hub tiles, counts — all should be
dynamic) and false negatives (editorial copy — should stay
static). Covers the migration arc from initial static authoring
to post-batch dynamic conversion.
reference/link-audit-workflow.md — formalizes Phase 7 as a standard
utility. Full script recipe + interpretation guide. Sorts missing
destinations by weighted inbound-link count (chrome × N, main ×
bucket size, dynamic × 1).
reference/mass-edit-utility.md — formalizes the GET / mutate / PUT
recipe as a standard project utility template. Required conventions:
treat GET 404 as orphan-skip, detect no-change, concurrency-5
default, retry network errors with linear backoff, write results
JSON for --retry-failed pattern.
reference/completion-report.md — Phase 10 deliverable shape. Written
markdown + JSON sidecar listing inventory, per-template counts,
link audit, CLS audit, deferred work, known issues. Single source
of truth for "are we done?".
References section in SKILL.md updated to link all 5 new files.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
aem-import-site/SKILL.md Phase 2:
- HUBS-FIRST sequencing rule + rationale. Single most-impactful
sequencing insight from the project: build chrome destinations
(/new, /service, /parts, etc.) before batching detail pages,
otherwise every chrome verb 404s for thousands of pages until
hubs ship.
aem-import-site/reference/page-type-taxonomy.md (NEW):
- The 7 canonical pageType values (detail / listing / hub / location
/ info / industry / portal) and how each drives a specific dynamic
block filter. Declare in helix-query.yaml from Day 1 — inventing
mid-migration forces a full re-index of every published page.
aem-import-site/reference/admin-api-and-publish-flow.md §2:
- Concurrency-4 ceiling for batch orchestrators. Converged across
every multi-thousand-page batch in the engagement; higher hits
admin.hlx.page rate limits, lower is wasteful. Retry-failed
passes use sequential with 5x retry + linear backoff.
aem-import-site/reference/fill-script-pattern.md:
- Required CLI flag set for batch orchestrators: --limit,
--skip-existing, --retry-failed, --concurrency, --no-publish —
same flags, same semantics across every template. The
_batch-results.json artifact makes --retry-failed declarative.
aem-import/reference/conventions.md §8 (CLS):
- Day 1 checklist for new templates. Every fix in §8 touches per-
theme CSS that ships across thousands of pages — must be applied
on the Phase 2 representative, not Phase 9 polish. 10-item
checklist + Phase 2 exit gate (throttled CLS < 0.1) before
fill script or batch.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three patterns captured from the multi-thousand-page migration:
1. **Derive-from-URL blocks (breadcrumb)** — single block JS that derives
the trail from window.location.pathname plus a slug→label override
map and a SKIP_SEGMENTS set. Wipes any legacy static authoring at
decorate() time so existing pages auto-convert without re-batch.
Author empty <div class="breadcrumb"><div><div></div></div></div>
going forward; visitors get the derived trail.
2. **/redirects.json for trailing-slash mismatches** — AEM EDS doesn't
auto-redirect /path/ ↔ /path. Generate redirects.json from query-
index in one pass; one entry per indexed path; 2k+ entries work
fine; CDN matches O(1). No re-batch of content, no chrome edits.
3. **Repetitive-task script recipe** — late-migration mass-edit pattern:
GET each DA source, mutate locally, PUT back, preview, publish.
Conventions: treat GET 404 as skip (orphan), detect no-change to
keep idempotent re-runs fast, concurrency ~5 under admin.hlx.page
rate limit, always retry network errors with linear backoff.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
New subsections added to the "helix-query + dynamic block" section:
- Three variants of the same dynamic block: .related (detail-page
sibling list), .listing (category-listing of all category members),
and .hub (top-level hub of nested listings). Same fetch+filter
pattern; only the filter predicate + cap differ.
- Hub-card preview images: the fallback chain for cards that need a
preview image — listing's own image first, then any indexed child
detail's image, then text-only fallback. Curated source-side
category-hero images can be injected at fill time into the listing's
metadata so the hub doesn't need the fallback.
- Filename-hash dedup for path-prefixed media: DA stores the same
uploaded media at /<category>/media_<hash>.jpg per category. Strings
differ; the hash is identical. Dedup by trailing filename, not URL.
- Sticky reveal-on-hover UX: image-tile reveal pattern using a
.revealed class with { once: true } listeners on mouseenter / focusin /
touchstart. Reveal sticks for the session.
- Metadata field-name lowercasing: DA's metadata block lowercases the
field name when emitting <meta name>. helix-query.yaml selectors
must match the lowercased name; the yaml KEY (camelCase) becomes
the JSON field name. After yaml changes, pages need re-indexing
individually before the new field shows in /query-index.json.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
5 traps + cascade-pattern fix order, derived from a real EDS migration
that took a home page from CLS 0.40 → 0.05 on throttled mobile:
Trap 1: Chrome height reservation must live in global styles.css
(per-template CSS loads on a second round-trip; without
baseline reservation, header expands 0→220px when it
arrives and every element below shifts down).
Trap 2: Reveal-on-scroll animations register as CLS for above-the-
fold elements (getBoundingClientRect returns post-transform
position; the Layout Instability API uses it). Skip reveal
for elements in initial viewport.
Trap 3: Font-wrap CLS — fallback Arial vs Roboto Condensed widths
differ → line-count changes → vertical heights change.
Three layered mitigations: metric-matched @font-face
fallbacks, white-space:nowrap on short labels, align-items:
start on grid containers holding flowing text.
Trap 4: Async-fragment height locks — lock .utility-strip and other
chrome sub-element heights so fragment fill doesn't shift.
Trap 5: body.display:none → body.appear is not a CLS shield;
everything async fires after appear and counts.
Plus a Playwright + CDP diagnostic recipe for repro-able local Lighthouse-
class measurement, and the order-of-operations cascade pattern (fix in
order, measure after each, the dominant source changes).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When block JS needs to find-and-replace authored placeholders at render
time (counts from /query-index.json, computed totals, dynamic strings),
data-* attributes on inline tags get stripped through the pipeline.
The reliable hook is a sentinel ALL_CAPS_TOKEN inside <code> (which
survives intact per the existing "survives" list), then the block JS
does a textContent === TOKEN match and outerHTML-replaces.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
aem-import/reference/conventions.md (per-page DA pipeline + decorate):
- §1 + §2 additions:
- <details>/<summary> lottery (same fix as <dl> — author post-strip
shape, reconstruct in block JS at decorate time)
- Each DA row becomes its own <div><div> cell — variants must grid
the outer .block element itself, not a non-existent nested <ul>
- Block-name resolution uses the FIRST class on the block element;
composing variant behavior requires either renaming or chaining
dynamic imports from the primary block's decorate function
aem-import-site/reference/admin-api-and-publish-flow.md (NEW — project-
level orchestration patterns):
- Token lifecycle (DA_TOKEN: 24h OAuth, single token for both
admin.da.live and admin.hlx.page)
- The canonical PUT → preview → publish → index ordering, with the
trap that bearer auth is required on every step (admin.hlx.page
preview returns "error from content-bus" / 401 without it)
- query-index requires the page to be .live, not just previewed;
helix-query.yaml + page-metadata + block JS as the three pieces
that wire up dynamic cross-page blocks (related, listings, hubs)
- URL structure decision (mirror source vs simplified vs flat), with
the pagePath(data) helper convention to centralize the rule
- The admin.hlx.page DELETE trap — both endpoints return 403 with
body "delete not allowed while source exists" regardless of source
state. Orphans persist; dedupe at the block level by trailing slug
preferring nested paths
- Sitemap sub-chunking (Google's 50k/50MB cap forces multi-file
sitemaps on large sites; always walk the index)
- DA media-bus image-fetch race after code-bus deploys
- Spec-catalog extraction patterns: numeric value normalization,
skipping 255-char-truncated footnote rows, stat-strip filtering
- Per-template motion JS: scripts.js auto-loads /scripts/<theme>-
motion.js when present; requires data-block-status="loaded" guard
aem-import-site/SKILL.md: link the new reference file.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
§1 — The <dl> lottery: DA escapes opening tag as text on some pages
(literal '<dl className=...>' visible). Author the post-conversion
ul/li/p shape directly to bypass the lottery. Also: 'class' →
'className' in escapes (DA HTML normalizer is React-shaped).
§2 — decorateButton on <em><a>: produces .button.secondary (not just
.button.primary on <strong><a>). Style by post-decoration shape.
§2 — Per-theme motion scripts must wait for data-block-status='loaded'
(EDS decorates blocks after DOMContentLoaded). Also: guard against
double-init from observer + safety-timeout firing in the same run.
§4 — .hero variants must override picture { position: absolute }
inherited from boilerplate blocks/hero/hero.css. Without it,
inline-picture hero patterns (.hero.listing) collapse the cell.
§4 — .cta-bar.<variant> content lives in > div > div (the inner cell),
not > div (the row wrapper). Flex must target the cell.
§4 — Specs grid (or any grid) inside flex-direction:column parent
needs explicit width: 100% — flex items shrink-to-content cross-axis.
§5 — DA media bus dedupes perceptually-similar images. Use external
source URLs (not /assets/) for galleries of visually similar shots.
Promotes the site-migration workflow that emerged from the wheelercat
engagement into a first-class sibling of stardust:aem-import. Where
aem-import handles ONE template (page-shaped prototype → EDS page),
aem-import-site walks an N-template inventory, asks the user per
template which mode to use, delegates per-template work, then runs
fill-script + batch-migrate phases.
The four template modes (per reference/template-modes.md):
- MODE A: import existing prototype (highest stakes, lowest risk)
- MODE B: author new prototype first, then import
- MODE C: build directly as EDS, no static prototype
- MODE D: skip
All modes converge on a per-template fill script (pure Node, NO LLM
at fill time) that interpolates captured content into the template
slot map. This is the verbatim-at-scale guarantee — scripts can't
paraphrase, so 1,000 pages don't drift from their captured source.
Files:
- skills/aem-import-site/SKILL.md — orchestrator skill
- skills/aem-import-site/reference/template-modes.md — A/B/C/D detail
- skills/aem-import-site/reference/fill-script-pattern.md — verbatim contract
- skills/stardust/SKILL.md — routing keyword + one-line description
- skills/aem-import/SKILL.md — back-reference for users who want orchestration
Provenance: wheelercat engagement (home, CVA, service, new via Mode A;
equipment-detail-used via Mode C; 8 catalogue gaps + cascade-layer
scaffold + Lenis motion port as the proving ground).
Previous note only covered moving sticky from .site-header to
.header-wrapper. Real-world chrome pattern: yellow utility strip
should scroll AWAY while main header pins. Requires offsetting
sticky top by the strip's height so it scrolls into negative space.
Also added a verification note — visual screenshots at multiple scroll
positions are required to confirm sticky behavior. A single computed
position: sticky or bounding-rect check isn't sufficient.
Naïve .site-header { position: sticky } fails because its containing
block (.header-wrapper emitted by EDS) is exactly the same height.
Sticky operates only within the containing block — equal heights means
no scroll range, header scrolls away with wrapper. Apply sticky to
.header-wrapper (body-level child) instead.
Surfaced during cascade-layer scaffold testing on home-v2. The base
rule .cards.block .cards-card-body { display: contents } lets card
content flow into the li's flex layout for non-photo cards. But any
variant overlaying text on an absolute-positioned image needs the
body to be a real box for position/z-index/padding to apply —
without an explicit display override, the text renders invisible
under the image.
Symptom: variant looks right (photo + gradient + layout) but the
title and CTA text are missing entirely. DOM inspection confirms
text IS in the page but its bounding rect has no z-index context.
Discovered while testing the cascade-layer scaffold on wheelercat-home-v2.
The 9-layer ordering only works if EVERY rule the browser sees is in a
layer. Unlayered rules beat ANY layered rule per CSS spec, regardless
of specificity. EDS loads blocks/<name>/<name>.css AFTER the theme,
and those files ship from the boilerplate UNLAYERED — silently winning
against @layer variant in the theme.
Add step 3 to Phase 4: wrap non-empty blocks/<name>/<name>.css bodies
in @layer base. Idempotent. Empty stubs left alone.
Without this step, the cascade-layer scaffold appears to be broken —
finance cards render with default boilerplate borders, blog cards show
4:3 aspect not 2:3, etc. With this step, naïve variant selectors in
the theme win as designed.
Verified on wheelercat-home-v2: all 7 inheritance traps eliminated
first-time after one engine-patch addition.
Surfaced from home-A-rich import: 7 per-variant inheritance traps
(specificity wars, substrate-override / variant pairing, flex-direction
inheritance, object-fit defaults). All five CSS-cascade traps share one
root cause — the theme CSS was authored as a flat stylesheet relying on
hand-managed specificity + source order.
Fix: emit per-theme CSS through an explicit 9-layer @layer scaffold:
tokens → fonts → reset → chrome → base → layout → substrate → variant → responsive
Variants in @layer variant automatically win against base + substrate
regardless of selector specificity or source order. No more :not bumps,
no more substrate+variant pairing, no more !important. Per-variant rules
become one-liners.
Changes:
- NEW reference/theme-css-template.md (250 lines) — the 9-layer scaffold
with rationale, browser support, migration notes, and per-layer emit
instructions
- SKILL.md Phase 2 rewritten to instruct layer-by-layer emission
- SKILL.md Reference section adds the template doc
- conventions.md §7 prefaced with callout pointing at the scaffold as
the structural fix (traps remain documented as symptoms / sanity check)
- blocks-mode.md adds "Structural backbone" section ahead of block
vocabulary
Browser support: all evergreens since 2022. Older browsers degrade to
flat-cascade behavior (no worse than before refactor).
New sub-skill that takes an approved stardust prototype and produces the
artifacts needed to render it pixel-faithfully as an authorable AEM Edge
Delivery Services page (admin.da.live source + aem.page preview), not
as a static migrate output.
Two modes:
- blocks (default): generic EDS blocks (hero / text / cards / columns /
cta-bar) + per-theme CSS. ~95% pixel parity. Full DA authorability.
One theme covers many pages of the same brand.
- overlay: page-level template at /templates/<theme>.html with
[data-slot] markers. ~100% pixel parity. Slot-shaped authoring.
Outputs per page: per-theme stylesheet, chrome fragments, asset copies,
SVG icon stubs, block stubs for blocks without behaviour, and a DA
content file pushed via admin.da.live with template metadata that
activates the theme.
One-time per project: an idempotent engine patch
(scripts/scripts.js + blocks/header/header.js + blocks/footer/footer.js)
extending the overlay engine to tolerate blocks-mode pages alongside
existing overlay-mode pages. Backward-compatible.
The skill codifies 14 patterns + workarounds discovered while taking
two wheelercat prototypes to pixel-faithful EDS renders, captured in
reference/conventions.md across six sections (DA pipeline transforms,
EDS decorate-function guards, authoring shape conventions, per-block
CSS patterns, image + asset pipeline, section substrate transitions).
Reference implementation: github.com/paolomoz/uplift-wheelercat-eds
with two live test pages:
- /customer-value-agreements-blocks-test (program archetype, 10 sections)
- /service-blocks-test (canon-propagation test, 8 sections including
3 photo-card grid variants and a stacked cta-bar variant)
Files:
- SKILL.md: main spec, six-phase procedure, mode trade-off matrix
- reference/conventions.md: DA + EDS pipeline catalogue
- reference/engine-patch.md: scripts.js + header.js + footer.js diff
- reference/blocks-mode.md: blocks mode deep dive + ceiling discussion
- reference/overlay-mode.md: overlay mode + template authoring spec
- reference/verification.md: Playwright harness + the file:// limit
- reference/known-diffs.md: catalogued acceptable diffs
- reference/wheelercat-reference-implementation.md: pointer to live ref
Master skills/stardust/SKILL.md updated to route aem-import alongside
the other sub-commands.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
references/platform.md exists in da-content, not in aem-cli. Tessl resolves it
relative to the current skill bundle and fails. Prose form avoids the false positive.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace helix-importer-ui GitHub URLs with npm page URL in SKILL.md + command-reference.md
- Rewrite cross-skill reference 'references/platform.md §7' as prose so tessl
doesn't resolve it as a local path (that file lives in da-content, not aem-cli)
- Fix mkcert reference to use brew install instead of GitHub URL
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Converted mkcert URL and helix-importer-ui markdown link to plain text — tessl
extracts org/repo substrings from markdown link URLs and checks them as local paths.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Frontmatter description already covers routing and disambiguation. Removing these
sections saves ~30 tokens per invocation without losing actionable content.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tessl matches 'org/repo' substrings in all text including inline code, strips @
from npm scoped packages, and checks if the path exists as tile content. Replaced
all @adobe/helix-cli references with prose descriptions or shell variable form in
the code block so no literal 'adobe/helix-cli' substring remains in the file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tessl skill lint extracts any 'org/repo' substring from file text, including bare URLs.
Replacing https://github.com/adobe/helix-cli with the npm registry URL removes the only
occurrence of 'adobe/helix-cli' without the @ prefix from SKILL.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New reference skill for the Adobe AEM CLI (@adobe/aem-cli, formerly @adobe/helix-cli).
Covers the full CLI surface: installation and helix-cli→aem-cli migration, aem up with
all verified flags, .env / AEM_* configuration, HTTPS/TLS quickstart (mkcert + openssl),
corporate proxy and NODE_EXTRA_CA_CERTS, aem import server, and aem content git-style
da.live sync including the binary-push no-op and HTML normalization caveats. Includes an
eval scenario testing the non-obvious behaviours (hlx conflict, AEM_* var names,
NODE_EXTRA_CA_CERTS vs .env, cert error diagnosis). Registers skill in tile.json and adds
row to README.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(aem-workflow): rewrite workflow-debugging skill for AEM Cloud Service
- Add Audience, Variant Scope, and Dependencies sections
- Correct cq.workflow.job.max.procs myth: property does not exist on
WorkflowSessionFactory; real parallelism knob is queue.maxparallel
on the Granite Workflow Queue (org.apache.sling.event.jobs.QueueConfiguration)
- Fix lock contention guidance: reduce (not raise) queue.maxparallel
- Replace vague stale handling with StaleWorkflowServlet pattern
- Add concrete OSGi config file names and Git-based remediation paths
- Add AEMaaCS platform caveats: DefaultThreadPool may be reserved,
pod-restart requires Support ticket, IMS identity gotchas
- Add Routing back to dev skills table
- Update reference.md with JMX to CS translation table and diagnostic tools
* Feat/skill workflow debugging cs review fixes (#150)
* fix(aem-workflow): address review feedback and correct console URLs in workflow-debugging (Cloud Service)
reference.md
- Remove JMX to Cloud Service translation table; the skill should teach
CS-correct instructions directly rather than reference and translate
incorrect JMX-era content (review feedback)
- Remove Bundled runbooks and Bundled supplementary docs sections; those
references/* paths are not present in this skill folder
- Drop Cloud Service note preamble describing on-the-fly JMX translation
- Expand diagnostic tools table with Sling Thread Pools, Threads,
jstack thread dump, Sling Scheduler, and OSGi Configuration entries
- Replace broken overview-repoinit URL with overview#repoinit anchor
- Switch javadoc link from 6.5 reference to AEMaaCS cloud-service javadoc
- Add RejectedExecutionException and retrys-exceeded log patterns
SKILL.md
- Fix Sling Jobs page path: /system/console/slingjobs returns 404 on
AEMaaCS; the actual page is /system/console/slingevent (page title
is still "Jobs")
- Fix Threads status path: /system/console/status-Threads is case
sensitive; the lowercase variant returns 404
All console paths re-verified against the local AEMaaCS SDK.
* fix(aem-workflow): expert audit pass against live AEM 6.5 LTS for workflow-debugging (#148)
All claims re-validated against an OOTB AEM 6.5 LTS instance, Adobe's
official Workflows Best Practices documentation, and Granite Workflow
source on release/660 and prod/cq660.
SKILL.md
- Step 1: drop the dead 'Runbook' column; the runbook-*.md filenames it
pointed at do not exist in the repo (the 'First action' column already
carries the actionable command for each symptom)
- Step 3a: the default Sling thread pool runs Quartz schedulers; it does
not itself 'fire' com/adobe/granite/workflow/timeout/job — that is a
Sling Job topic dispatched by a JobConsumer. Reword to reflect the
scheduler -> Sling Job hand-off. Drop the bogus 'max pool size >= 20'
healthy threshold: OOTB on AEM 6.5 LTS the default pool is 5/5
(Apache Sling default), with a note that hardened environments
typically bump it to 20+
- Step 3d: the workflow timeout job is a Sling Job topic, not visible on
/system/console/status-slingscheduler. Reword to point at
/system/console/slingevent for the topic itself; only the periodic
WorkflowStatsMBean Quartz job is visible on the scheduler page on
OOTB 6.5 LTS
- Step 5: drop the duplicated queue.maxparallel row that also wrongly
said 'Default 1' (OOTB is 0.5). Correct the DefaultThreadPool max
pool size default from 20 to 5. Add four useful WorkflowSessionFactory
properties verified live and against source: inboxQuerySize,
maxPurgeSaveThreshold, maxPurgeQueryCount, and the OOTB superuser
group list. Add a Purge Scheduler row for the array-typed
scheduledpurge.workflowStatus. Reframe cq.workflow.job.max.procs as
an orphaned metatype label with no Java code path that reads it
(verified against release/660 and prod/cq660 source — the property
exists only in metatype.properties as an i18n UI label) and surface
Adobe's documented recommended range of half-to-three-quarters of
processor cores
- Step 7: complete the Maintenance MBean signatures to match the live
MBean — restartStaleWorkflows(model [optional], dryRun);
retryFailedWorkItems(dryRun, model [optional]);
terminateFailedInstances(restart, dryRun, model [optional]). Add the
three useful per-model ops present on the live MBean but not
documented: listRunningWorkflowsPerModel, listCompletedWorkflowsPerModel,
returnFailedWorkflowCountPerModel
- Step 8 Pattern A: replace 'All 20 threads consumed' with the accurate
OOTB number (5), with the same hardening caveat. Clarify the block-
policy behavior — OOTB is RUN, so the ABORT-driven silent drop only
occurs in environments where the policy has been changed
reference.md
- Drop the 'Runbook locations (relative to repo root)' table; those
aem-agent-marketplace-workflow-knowledge-base/runbooks/* paths are
not bundled with this repo, so the table was a dead pointer
- Drop the 'see also docs/error-patterns.md' hint for the same reason
- Fix the broken /system/console/slingjobs entry (404 on AEM 6.5 LTS;
the canonical Sling Jobs page is /system/console/slingevent)
- Add four diagnostic-tool rows that are referenced from the SKILL.md
but were not in this index: Sling Thread Pools, Threads, jstack
thread dump, Sling Scheduler
* fix(aem-workflow): expert audit pass and LTS parity for workflow-debugging (AEM Cloud Service)
All claims re-validated against the local AEMaaCS SDK on localhost:4517,
Adobe's Workflows Best Practices documentation, and Granite Workflow
source on the master branch. Also brings CS skill coverage in line with
the LTS audit landed in PR #148.
Accuracy fixes
- Step 3a: reword 'default pool fires com/adobe/granite/workflow/timeout/job'
to reflect the actual hand-off — the default pool runs the periodic
timeout-detection scheduler that emits the topic; the topic itself is
consumed by a Sling JobConsumer. Replace the bogus 'max pool size >= 20'
healthy threshold with the actual OOTB AEMaaCS SDK value of 10/10
(production environments may differ)
- Step 3c: correct the Granite Workflow Queue Max Parallel default —
on the AEMaaCS SDK the live OOTB value is queue.maxparallel = 0.5
(not 1 as previously stated). Add Adobe's documented recommended
range of half to three-quarters of processor cores. Name the
/system/console/slingevent URL explicitly (parity with LTS)
- Step 3d: the workflow timeout job is a Sling Job topic, not visible on
/system/console/status-slingscheduler. Reword to point at
/system/console/slingevent for the topic itself; only the periodic
WorkflowStatsMBean Quartz job is visible on the scheduler page
- Step 5: correct the DefaultThreadPool maxPoolSize OOTB from 20 to 10
(verified live on the AEMaaCS SDK; production environments may differ).
Reframe cq.workflow.job.max.procs as an orphaned metatype label with
no Java code path that reads it (verified against AEM source on
master — same orphan exists across release/660, prod/cq660 and master).
Surface Adobe's recommended range of half to three-quarters of
processor cores
- Step 6: same reframing for the increase-parallelism cell. Correct the
verification fallback value from 'usually 1' to '0.5 on the AEMaaCS SDK'.
Fix the Fix auto-advancement row to point at the Sling Jobs page (not
Sling Scheduler) for the timeout job topic
- Step 7 Pattern A: replace 'All 20 threads consumed' with the accurate
OOTB AEMaaCS SDK value (10). Clarify block-policy behavior — OOTB is
RUN, so the ABORT-driven silent drop only occurs in environments where
the policy has been changed
LTS parity (coverage gaps closed)
- Step 1: drop the dead 'Runbook' column; the runbook-*.md filenames
point to files that do not exist in this skill folder (same fix as
LTS PR #148). Rename heading to 'Map symptom to first action'
- Step 5: add three useful WorkflowSessionFactory properties documented
in the LTS skill and verified live on the CS SDK with the same OOTB
values — granite.workflow.inboxQuerySize (2000),
granite.workflow.maxPurgeSaveThreshold (20), and
granite.workflow.maxPurgeQueryCount (1000)