Skip to content

[FEATURE] [MER-4945] Add adaptive AI activation points#6286

Draft
manelli wants to merge 8 commits intoMER-4943/adaptive-pages/enable-dot-on-pagefrom
MER-4945/adaptive-pages/screen-level-ai-activation-points
Draft

[FEATURE] [MER-4945] Add adaptive AI activation points#6286
manelli wants to merge 8 commits intoMER-4943/adaptive-pages/enable-dot-on-pagefrom
MER-4945/adaptive-pages/screen-level-ai-activation-points

Conversation

@manelli
Copy link
Collaborator

@manelli manelli commented Mar 10, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

Warnings
⚠️ PR is large (2629 LOC changed). Consider splitting.

Risk score: 22 → risk/high

Generated by 🚫 dangerJS against 7bcac6c

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

AI Review — performance

Full revision JSON fetched on hot trigger path

file: lib/oli/conversation/triggers.ex
line: 303
Description: Every adaptive trigger resolution loads rev.content (full revision JSON) from the DB, then uses only partsLayout to locate one part/prompt. On a high-frequency trigger endpoint, transferring and decoding full content increases DB, CPU, and memory pressure.
Suggestion: Query only the needed JSON fragment (for example partsLayout and the specific fields under custom) instead of full content, or cache pre-extracted adaptive trigger metadata by revision_id in SectionResourceDepot/Cachex to avoid repeated DB reads.

Fallback resolver query adds expensive join path per request

file: lib/oli/conversation/triggers.ex
line: 306
Description: Cache misses call DeliveryResolver.section_resource_revisions(section_slug) and filter by resource_id, introducing a heavier multi-join query in the request path. Under load or low cache hit rate, this increases latency and DB contention.
Suggestion: Avoid resolver fallback in this path by requiring/priming section resource cache first, or use a direct indexed lookup keyed by section_id + resource_id to fetch revision_id/metadata without the broader resolver join.

Duplicate suppression logs at info can become hot-path I/O

file: lib/oli/conversation/triggers.ex
line: 176
Description: Suppressed duplicates are expected behavior during rapid UI retries; logging each duplicate at info can create high log volume and unnecessary I/O/CPU in bursty traffic.
Suggestion: Downgrade duplicate logs to debug (or sample/rate-limit them) and keep info for accepted or anomalous paths only.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

AI Review — elixir

Malformed authoring content can crash edit validation

file: lib/oli/authoring/editing/activity_editor.ex
line: 812
Description: content |> map_value(:authoring) |> map_value(:parts) assumes authoring is a map. If a client sends malformed content (for example, "authoring" => []), map_value/2 has no matching clause and raises FunctionClauseError, turning a validation failure into a server error.
Suggestion: Make map_value/2 total (add a catch-all clause) and defensively normalize containers before enumeration, e.g. treat non-map authoring as %{} and non-list parts as [].

partsLayout type is not validated before Enum.find/2

file: lib/oli/conversation/triggers.ex
line: 321
Description: parts_layout = map_value(content, "partsLayout") || [] does not guarantee a list. If stored content is malformed (for example, "partsLayout" => "bad"), Enum.find/2 later raises Protocol.UndefinedError, causing trigger resolution to fail with an exception instead of returning {:error, :invalid_trigger}.
Suggestion: Guard with is_list(parts_layout) (or coerce non-lists to []) before calling Enum.find/2, and return {:error, :invalid_trigger} for invalid shapes.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

AI Review — typescript

AI trigger prompt is never sent to the trigger API

file: assets/src/components/parts/aiTrigger.ts
line: 28
Description: The new AI-trigger flow validates that a prompt exists, but buildAdaptiveAiTriggerPayload does not include prompt in the payload. This means author-configured prompts (aiTriggerPrompt / prompt) are ignored at runtime, so backend trigger behavior can be incorrect.
Suggestion: Extend AdaptiveAiTriggerConfig and buildAdaptiveAiTriggerPayload to accept prompt, include prompt in the returned payload, and pass the configured prompt from AITrigger.tsx, janus-image/Image.tsx, and janus-navigation-button/NavigationButton.tsx when invoking.

Selector always allocates a new array and can cause avoidable rerenders

file: assets/src/apps/authoring/store/app/slice.ts
line: 361
Description: selectPartComponentTypes now calls .filter(...) unconditionally, returning a new array reference even when triggers are allowed and nothing is filtered. Components consuming this selector may rerender on unrelated app state changes due to referential instability.
Suggestion: Return state.partComponentTypes directly when state.allowTriggers is true, and only allocate a filtered array when allowTriggers is false.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

AI Review — security

No issues found

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

AI Review — ui

Interactive image can become an unlabeled button

file: assets/src/components/parts/janus-image/Image.tsx
line: 177
Description: The image is now keyboard-focusable with role="button" when AI trigger is enabled, but no explicit accessible name is added for that button state. If alt is empty/decorative, screen readers can announce an unnamed control.
Suggestion: When aiTriggerAvailable is true, set an explicit accessible name (for example aria-label="Open DOT AI assistant" or a configurable label), and keep alt focused on image meaning rather than button labeling.

Global MutationObserver risks unnecessary UI churn

file: assets/src/components/parts/janus-ai-trigger/AITrigger.tsx
line: 90
Description: Observing document.body with childList: true and subtree: true can fire on most DOM updates, repeatedly calling setTriggerAvailable and causing avoidable re-renders/perf overhead in complex pages.
Suggestion: Replace with a narrower signal (for example a targeted observer on a stable container, or an explicit event when #ai_bot mounts/unmounts), and guard state updates so setTriggerAvailable runs only when availability actually changes.

@github-actions
Copy link
Contributor

Preview deployed to: https://pr-6286.plasma.oli.cmu.edu

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant