Add 'VTL Viewtool Contract Change' rollback category (H-8, HIGH) to ROLLBACK_UNSAFE_CATEGORIES.md
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
docs/core/ROLLBACK_UNSAFE_CATEGORIES.md is the canonical reference that the automatic PR rollback-safety check (.github/workflows/ai_claude-rollback-safety.yml) reads at runtime (cat docs/core/ROLLBACK_UNSAFE_CATEGORIES.md, prompt STEP 1, line 98) to classify every PR as AI: Safe To Rollback / AI: Not Safe To Rollback.
The document currently has no category covering changes to the contract of a VTL Viewtool (Velocity ViewTool methods exposed to templates via toolbox.xml, e.g. $estool, $dotcontent). This is a genuine blind spot in the reference, surfaced while reviewing an ES→OS migration change.
Motivating example
As part of the ES→OpenSearch migration, ESContentTool.raw(String) (the $estool.raw() viewtool) changed its return type:
// before
public SearchResponse raw(String esQuery) { ... } // org.elasticsearch type
// after
public ContentSearchResponse raw(final String esQuery) { ... } // vendor-neutral DTO
SearchResponse and ContentSearchResponse expose different accessors (e.g. the new record exposes aggregationTree() / aggregations()). Customer VTL templates migrated to the new accessors are a persistent artifact stored outside the application binary (in the DB / theme filesystem). If the binary is rolled back to N-1 without reverting those templates, N-1's raw() returns the old SearchResponse, the template calls a method that no longer exists, and Velocity fails at render time — i.e. N-1 cannot "serve requests correctly."
Why it belongs in this document
The document's scope is not limited to DB/index state. The rule of thumb (line 5) includes "serve requests correctly", and M-3 explicitly states "This risk exists entirely outside the DB layer". The unifying principle is:
A change is rollback-unsafe if it leaves a persistent artifact outside the application binary — DB, index, file, queued bundle, deployed client (M-3), compiled OSGi plugin (M-4) — that survives a rollback and breaks N-1.
A VTL template is structurally identical to an OSGi plugin in this model: an external consumer written against the binary's contract that survives a rollback.
VTL template : viewtool method ≡ OSGi plugin : exported interface
Since M-3 (REST/GraphQL) and M-4 (OSGi) already capture code-contract risks where the persistent artifact is a deployed consumer, VTL viewtool contracts fit the same class and belong here.
Proposed category
Add M-5 — VTL Viewtool Contract Change with a scaled severity (precedent: H-7 already uses "escalates to MEDIUM/HIGH if…"):
| Condition | Risk |
|---|---|
| Viewtool method used in scope-limited templates (specific page/detail type) | 🟡 MEDIUM (base) — few pages affected; recovery = edit that template |
| Viewtool method invoked from shared/global templates (layouts, headers, footers, widely-reused containers) | 🟠 HIGH — one change breaks many pages at once; matches "core features broken for affected users" |
Rationale for not flat-HIGH or CRITICAL: no data loss, N-1 starts normally, recovery is a content/template edit (no backup/reindex). Flat-HIGH would also rank it above M-4 (OSGi, which can destabilize the container yet is rated MEDIUM), breaking the document's internal calibration. The trigger is conditional (only breaks if templates were co-migrated to the new contract) — same conditionality the document states for M-3.
The new section must follow the existing convention: Context · Why it is unsafe · Example (the raw() → ContentSearchResponse case above) · Signals to watch for in code review · Safer alternative — plus a line in the Decision Card (lines ~24–46).
Acceptance Criteria
- A new category
M-5 — VTL Viewtool Contract Changeis added todocs/core/ROLLBACK_UNSAFE_CATEGORIES.mdin the 🟡 MEDIUM section, following the exact structural convention of existing categories (Context, Why it is unsafe, Example, Signals to watch for in code review, Safer alternative). - The category documents scaled severity: 🟡 MEDIUM base, escalating to 🟠 HIGH when the viewtool method is reachable from shared/global templates (layouts, headers, footers, widely-reused containers), with the escalation worded in the style of H-7.
- The category includes the real-world example:
ESContentTool.raw(String)return type changeSearchResponse→ContentSearchResponseand the render-time failure scenario on rollback. - Signals to watch for include: return-type or signature change on a class implementing
ViewTool; the class is registered intoolbox.xml(or equivalent); the new return type exposes different accessor methods than the old one. - Safer alternative documents the additive pattern: keep the old accessors on the new return type (or keep the old method overload) for one release so co-migrated templates and rolled-back binaries both resolve — i.e. a two-phase contract change.
- A corresponding entry is added to the Decision Card (
VTL viewtool contract change? → 🟡 MEDIUM / 🟠 HIGH (M-5)). - The document remains internally consistent: M-5 is not ranked above M-4 (OSGi) as a flat level, and the new entry does not introduce a new GitHub label type (it reuses the existing
Safe / Not Safe To Rollbacklabels — no change required tocategorize.tsor thecheck-release-rollbackskill). - No change to
ai_claude-rollback-safety.ymlis required (the workflow reads the doc dynamically by exact path); confirm this explicitly in the PR.
Priority
Medium
Additional Context
- Consumer/pipeline analysis confirming how the doc is wired:
- Dynamic read by
ai_claude-rollback-safety.yml(prompt STEP 1, line 98;allowedToolsrestricts to that exact path, line 128) — so new categories added inside the file are picked up automatically on the next PR, with no workflow change. - Hardcoded labels (
AI: Not Safe To Rollback, etc.) live in.github/scripts/gather-release-data/src/categorize.ts(lines 10–14) and thecheck-release-rollbackskill — unaffected because M-5 reuses the existing labels.
- Dynamic read by
- The
allowedToolsallow-list (Bash(cat docs/core/ROLLBACK_UNSAFE_CATEGORIES.md)) is why a separate new.mdfile would NOT be picked up — it would be denied by the sandbox. Hence this change must go into the existing file. - Defining class of the example:
dotCMS/src/main/java/com/dotcms/rendering/velocity/viewtools/ESContentTool.java; new DTO:dotCMS/src/main/java/com/dotcms/content/index/domain/ContentSearchResponse.java; viewtool registration:dotCMS/src/main/webapp/WEB-INF/toolbox.xml(estool). Related migration work: PR #36026 (VTL aggregation backward-compat).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read docs/core/ROLLBACK_UNSAFE_CATEGORIES.md, especially the Decision Card and existing H-7 and M-4 sections, then review .github/workflows/ai_claude-rollback-safety.yml to confirm the document is read dynamically. Add the M-5 section and Decision Card entry with the specified severity, ESContentTool.raw example, signals, and safer alternative; done means the existing file fully captures the acceptance criteria without workflow changes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- documentation
- Issue type
- Documentation
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 82/100