Skip to content

Spec: Dojo to Angular dotAI portlet migration (#37417) - #37418

Open
fmontes wants to merge 4 commits into
mainfrom
fmontes/dot-ai-portlet
Open

Spec: Dojo to Angular dotAI portlet migration (#37417)#37418
fmontes wants to merge 4 commits into
mainfrom
fmontes/dot-ai-portlet

Conversation

@fmontes

@fmontes fmontes commented Sep 4, 2026

Copy link
Copy Markdown
Member

Spec-Kit PR 1 of 2 — the spec alone. No implementation. Review it as a contract, not as code: is this the right problem, scoped right, with criteria a reviewer could check?

Closes nothing yet — implementation lands in PR 2, which will link back here.

What this is

Dojo → Angular migration of the dotAI portlet (#37417), following the approved redesign. The legacy four tabs become five — Search, Chat, Image, Embeddings, Config Values — with a shared retrieval-settings panel on Search and Chat and a guided index dialog on Embeddings.

No new functionality. Every screen maps onto behavior that already ships, so there is no backend work beyond portlet registration.

Rollout follows the ES Search (#34733) and Velocity Playground (#34737) precedent: the new screen takes over the existing dotai menu entry so upgrades need no manual step, and the old screen stays reachable at an unlisted dotai-legacy address for rollback.

What's worth your attention

Three capabilities are dropped on purpose. Each is behavior a user has today, so each deserves an explicit nod rather than silent acceptance:

  • Chat sources — only the non-streaming mode carries them, and progressive rendering was chosen instead.
  • The raw structured-response mode — the provider's own response payload and total time become unreachable from the admin.
  • The recent-image-prompts list — browser-local, never portable, and could not have carried over to a new storage key regardless.

All three remain on the legacy screen while it exists.

Two defects get fixed along the way (FR-023, FR-024): the "Inner Product" distance option sends a value the server does not recognize, so it silently behaves as cosine; and the response-length field advertises a minimum of 10 tokens against a server minimum of 128.

One dead end gets closed (US6, FR-049): a user with portlet access but not the administrator role index operations require currently gets an empty index list and an empty picker, leaving Search and Chat silently unusable with no explanation. The approved design has no state for this either.

One deliberate deviation from the design (FR-053): the portlet renders in the installation's configured theme color, not the design's specific brand color. That color is customer-configurable at runtime, so hardcoding it would leave a branded admin with one screen in someone else's palette. If the design's color is meant as a new product-wide brand, that's a separate app-wide change.

One piece of genuinely new behavior (FR-018): the retrieval-settings panel persists between visits. The legacy screen never stored those controls. Called out rather than smuggled in.

Contents

specs/37417-dotai-portlet-rebuild/spec.md — 7 prioritized user stories, 57 functional requirements, 12 success criteria, edge cases, key entities, Out of Scope, and the dotCMS Legacy Considerations section.

Next: approval here unblocks /speckit-plan. It doesn't need to merge first — PR 2 branches off this branch.

Spec-Kit PR 1 of 2 — spec.md alone, no implementation.

Covers the five-tab rebuild (Search, Chat, Image, Embeddings, Config
Values), the swap-in-place rollout with an unlisted legacy twin, two
defects fixed along the way (inner-product silently behaving as cosine,
response-length minimum advertised as 10 against a server minimum of
128), and the non-administrator dead end the current screen has no
state for.

Three capabilities are dropped on purpose and recorded in Out of Scope:
chat sources, the raw structured-response mode, and the recent-image-
prompts list.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Claude finished @fmontes's task in 1m 31s —— View job


Spec review — dotAI portlet rebuild

Reviewed as a contract, not code. The spec is well-scoped: removals are called out explicitly rather than smuggled, the rollout mirrors the established -legacy twin precedent, and the two defect fixes (FR-023/FR-024) and the dead-end closure (US6/FR-049) are each justified. The two codebase-grounded claims check out against main (see below). Findings are all non-blocking.

Verified claims

  • FR-024CompletionsForm.java:24-30 maps only distance<->, cosine<=>, innerProduct<#>; line 114 does OPERATORS.getOrDefault(builder.operator, "<=>"). A legacy "product" value is not a key, so it silently resolves to cosine. Accurate, and innerProduct is the correct value to send for <#>.
  • FR-023@Min(128) sits on responseLengthTokens (CompletionsForm.java:39), while the builder default is 0 (line 173), which itself violates the annotation — confirming the annotation isn't enforced. The corrected rationale in commit a6583b0 holds.

New Issues

  • 🟡 Medium: spec.md:204 (FR-027) + spec.md:299 (Assumptions) — build status is "ready once its counts stop changing." That heuristic has an inherent false-positive the spec doesn't address: a stall (slow/rate-limited provider, a build that errors out, or a natural pause between batches) is indistinguishable from completion, so an index can report ready mid-build. The edge case at spec.md:157 covers already-building flicker but not premature-ready. Recommend the plan phase pin down a settle window, a max-wait, and an error/abort signal so "ready" isn't just "quiet for a moment." Fix this →
  • 🟡 Medium: spec.md:233-235 (FR-047/FR-049) — the two unavailability states are specified independently but their combination isn't. A non-administrator on an instance with no provider configured hits both the persistent no-provider notice (FR-047) and the role-requirement message on Embeddings/index picker (FR-049). Which message wins, or do both show? Undefined precedence risks two overlapping explanations or a confusing one. Worth one sentence stating precedence.
  • 🟡 Medium: spec.md:280 (SC-006) — "within one refresh cycle" is not measurable the way its sibling SC-005 ("within one second") is; a "refresh cycle" is undefined here. A success criterion a reviewer can check should be bounded (e.g., a wall-clock bound, or an explicit definition of the cycle).

Minor

  • spec.md:143-144 (US7) — acceptance scenarios are numbered 1, 2, 2b, 3; the 2b reads as an afterthought insertion. Harmless, but renumbering to 1, 2, 3, 4 keeps the list clean.

No contract-level correctness errors. The three Medium items are refinements for /speckit-plan to resolve, not blockers to approving the spec.
· fmontes/dot-ai-portlet

…enforced

Planning verified the backend: there is no @Valid anywhere in
com.dotcms.ai.rest, so CompletionsForm's @min(128) on
responseLengthTokens is decorative. The builder's own default for that
field is 0, which violates its own annotation.

So the legacy min="10" does not produce a server error, as the spec
claimed — it produces a silently truncated answer. The requirement is
unchanged (the field enforces 128); only the reason it matters is
corrected. The field is the one place the declared limit can be honored.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fmontes

fmontes commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

Spec updated — one correction from the planning phase, pushed as a6583b0.

FR-023 claimed the server rejects a response length below 128 tokens. It does not. There is no @Valid anywhere in com.dotcms.ai.rest, so CompletionsForm's @Min(128) on responseLengthTokens is decorative — and the builder's own default for that field is 0, which violates its own annotation. The legacy min="10" therefore produces a silently truncated answer, not an error.

The requirement is unchanged (the field enforces 128). Only the reason it matters is corrected: the field is the one place the declared limit can be honored.

FR-024 was re-verified and stands as written — OPERATORS accepts only distance/cosine/innerProduct, the legacy radio sends product, and getOrDefault silently falls back to cosine. "Inner Product" has never produced <#>.

…t a URL

Browser validation against a running instance: /c/dotai-legacy redirects
to the starter portlet rather than loading the old screen. So do
/c/es-search-legacy, /c/velocity_playground-legacy and
/c/query-tool-legacy — the guard rejects any portlet absent from the
user's layout, and the twins are deliberately in no layout.

The spec said the old screen "MUST remain reachable at a separate
documented address", which overstates it and matters because this is the
rollback story. Restoring it is an administrator adding the portlet to a
layout — still no redeploy, which is the property that counts.

FR-002, US7, SC-008 updated; US7 gains a scenario for the
not-in-any-layout case so the behavior is stated rather than discovered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@fmontes

fmontes commented Sep 5, 2026

Copy link
Copy Markdown
Member Author

Implementation is up in #37423, branched off this spec branch as the flow requires — so until this merges, that diff also carries the spec commit.

All 57 functional requirements are implemented and /speckit-converge is clean: it found 9 gaps, 7 were built and 2 consciously accepted with the reasoning recorded.

Two corrections landed on this PR while building, both from measuring the running product rather than reading the source — FR-023 (the 128-token minimum is declared but not enforced) and FR-002 (the legacy twin needs a layout, not just a URL). Worth a re-read of those two before approving.

@fmontes fmontes linked an issue Sep 7, 2026 that may be closed by this pull request
Co-authored-by: fmontes <751424+fmontes@users.noreply.github.com>
Copilot AI requested a review from a team as a code owner September 7, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Dojo to Angular: dotAI Portlet

2 participants