Skip to content

fix: a project's description and its link are no longer swapped in the AI tools' project results EXO-91949 - #682

Open
bmestrallet wants to merge 27 commits into
feature/ai-contributionfrom
fix/EXO-91949-project-description-url-swap
Open

bmestrallet wants to merge 27 commits into
feature/ai-contributionfrom
fix/EXO-91949-project-description-url-swap

Conversation

@bmestrallet

@bmestrallet bmestrallet commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Symptom

The MCP tools that return a project (list_projects, and every tool going through toProjectModel) put the project's permanent link in description and its description in url. Seen on community.exoplatform.com and on a local instance: "description":"https://…/tasks/projectDetail/8387","url":"<p>Reworks the Shortcuts portlet…</p>".

Cause

ProjectModel is built through its Lombok all-args constructor, whose fields are declared id, name, description, url, …; TaskMcpTool#toProjectModel passed getUrl(project) third and the description fourth. The existing tests stub the description as "", which @JsonInclude(NON_EMPTY) drops, so the swap never showed.

Fix

Pass the description third and the link fourth. toProjectModel is the only ProjectModel construction in services/src/main. A new test, getProjectByIdShouldKeepTheDescriptionAndTheUrlEachInItsOwnField, stubs a non-empty description and asserts each value lands in its own field; it fails with the arguments swapped back. It reads the project through get_project_by_id, the full-model path that stays once list items become compact (#683), so the regression stays pinned after that PR lands.

mvn -o test -pl services -Dtest=TaskMcpToolTest at d41fc7bcf: 84 tests, 0 failures. The same test also passes on top of #683 (ee2976604 with this PR's two commits picked).

Classification: N3 proposed — a two-argument reordering in a tool's result mapping; no tool definition, REST, DAO, schema or ACL surface touched.
Knowledge: none — doc-neutral

🤖 Generated with Claude Code

aycherif and others added 26 commits October 21, 2026 01:39
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ssigned to its creator EXO-90661

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…drawer and published to MCP clients EXO-90930

The file-level "icon" of ai-tool-definitions.json is the default of every
tool of the file. Requires the mcp-server change of EXO-90930: an older
mcp-server rejects the unknown property and drops the file's tools.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…colour and image EXO-91474 (#674)

**Symptom**: with a background set for applications in Branding, the
rows of the Tasks list, and of a project's List view, stayed light grey
instead of showing it, and a background image set for applications
showed nowhere in the Tasks app.

**Cause**: the rows were painted with `@tableBackgroundAccent`
(`tasks.less`), a fixed grey that no Branding key drives. The
`TasksManagement` portlet opts out of the frame's background colour
(`no-layout-background-color`), and its two cards, the tab bar and the
tab content (`TasksManagement.vue`), paint
`application-background-color`, opaque by default, over the image that
the portlet frame (`PORTLET-FRAGMENT`) still painted.

**Fix**:
- the rows are transparent and keep their border, so they show the
application background;
- both cards carry `application-background-image` beside
`application-background-color`, and the portlet's `layout-css-class`
gains `no-layout-background-image`, so the frame paints neither and the
gap between the cards shows the page for the image as for the colour.
The image is painted per card, fitted to each card's box.

No automated test: CSS and template classes only (`frontend-vue.md`, no
JS unit test). Checked on a running 7.3.x `feature/ai-contribution`
server: the rows show the Branding application colour; the Branding
application image shows on the tab bar and on the content card, and
through the rows, on the Tasks tab and on a project's List view.

Knowledge: pending — EXO-91474

This change is classified N3 at `b47b02feb`: no REST/DAO/schema/ACL
surface touched (`classification.md` §3).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…round set in Branding EXO-91383 (#672)

Symptom: with a Drawers & Popup background set in Branding and Theme,
the
suggestions list of the project picker of a task event, in the
engagement center's rule form, stays white, with dark grey suggestions.

Cause: the suggestions menu is detached to the page's root application
container and keeps Vuetify's white surface. The picker's content-class
attribute lands on its input, not on the menu: Vuetify 2 takes the menu
content class only from menu-props, and the string form of menu-props
carries flags only.

Fix: menu-props takes its object form, keeping the closeOnClick and
closeOnContentClick flags, and adds the content classes layout-drawer,
which paints the Drawers & Popup colour on the menu, and
application-menu,
which lets the suggestions take the drawer text colour, size, weight and
style instead of the fixed dark grey, the page text size and the normal
weight and style the platform gives menu items, as Meeds-io/social#6233
does for exo-identity-suggester. The string's "maxHeight = 100" entry
was
read as an unknown flag and set no height, so the menu keeps its default
height.

Not covered: a Drawers & Popup background image is hidden by the list's
solid drawer colour.

Knowledge: Meeds-io/eng-standards#440

This change is classified N2 (at 97bf5ab: a shared component of the
addon's common module, rendering only, no REST/DAO/schema/ACL surface) —
its approver must be an Archi/Dev who knows it is N2, not an approval on
AI review alone.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… task's space EXO-91174

TaskSpaceScopeResolver tells which space a task belongs to (the one space
group the project's managers name, else none), so a call limited to one
space may run get_task_by_id, list_task_comments_by_id, update_task_status
and complete_task on a task of that space only. Their ai-tool-definitions
entries declare the space scope; the other task tools stay refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ole of that one space group EXO-91174

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
list_projects declares the space argument and reads the run's space when
none is given; given a space it lists, as the caller, only the projects
shared with that space's group the caller holds a role of, and none for a
non-member. get_project_by_id declares its project and a
ProjectSpaceScopeResolver tells the project's space, as the task resolver
reads it: one space group among all its managers, else none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… only EXO-91174

create_task_in_project declares its project and the project resolver, with
the arguments that stay inside the project (title, description, dates,
priority, a status of that project). The assignee and the coworkers can be
users outside the space and are not accepted. The approval stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cepts EXO-91174

Given a space, list_projects keeps, among the projects reached through the
caller's roles of that space group, the ones TaskSpaceScopeResolver gives to
that space, so the list and get_project_by_id can't disagree. The page is cut
from that selection and the count is its size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…aller's own EXO-91174

list_projects with a positive space id whose space is missing or deleted fell
back to the caller's own projects, outside the space the call was limited to.
It now lists nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ects its space accepts EXO-91174

The resolver filter of the space listing applies when the call carries a space
scope (a digital worker's thread run), where it keeps the list and
get_project_by_id in agreement. Interactive and unscoped callers keep every
project of a space they belong to; a non-member and an unknown space still get
an empty list. The scoped selection is read in chunks of 50 projects and stops
once one more project than the page asks for is kept, instead of mapping every
reachable project, and its page parameters are given back clamped. The tool's
description says that a limited run lists the projects managed through its
space.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…un limited to the task's space EXO-91405

list_project_statuses declares its project (project resolver) and
update_task_description its task (task resolver), accepting only the new
description. Both were refused under a space scope in the live check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In a run limited to a space, list_tasks was refused, so an agent asked to
act on a task of the space by its title had no way to find its id. The
tool now declares a space scope by its project and the project resolver:
it lists the tasks of one project of the run's space, with its filters and
paging, and is refused without a project, with a project of another space
or one that doesn't exist, and with any other argument.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
list_tasks takes an optional title: only the tasks whose title contains
it, ignoring case, among those its other filters select. The match is
added to the query's conjunction, so it narrows the project, or the
tasks the user can access, and never widens them. A run limited to a
space may pass it beside a project of that space.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eopens a task of its space EXO-91512

The task-level writes that take no reference beside the task declare their
space scope through the task: add_task_comment (text), update_task_title
(title), set_task_dates (start_date, due_date), set_task_priority (priority)
and reopen_task. In a run limited to a space they reach only a task of a
project of that space, as approved proposals, with those arguments only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…f its space EXO-91512

add_project_label_to_task and remove_project_label_from_task declare their
space scope through the task, with label_id as their only other argument.
A label of another project, or of no project, is refused on a task of a
project (scoped or not): before, any existing label could be put on any task
the user can access, so a call limited to the space of the task's project
could reach a label of another space. A task in no project keeps any label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t space EXO-91512

assign_task and add_task_coworker declare their space scope through the task,
with username as their only other argument. The scope reads the space of the
task only, and a project's participants may include people outside its space,
so in a call limited to a space TaskMcpTool also refuses a person who isn't a
member of that space, and anyone when the call's identity can't be read. A
call that isn't limited keeps the task's access rule alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ers of that space only EXO-91512

Each user a task comment mentions is notified, so the text of add_task_comment
reaches people too. In a call limited to a space, a comment that mentions a
user who isn't a member of that space is refused, by the same check as the
assignee and the coworkers; role mentions resolve to the project's space and
stay as they are. A call that isn't limited may mention anyone, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s an unreadable scope as such EXO-91512

checkScopeSpaceMembers reads the scope once per call, the people only for a
limited call and the space only when they name someone, instead of once per
mention. A call whose identity can't be read is refused with its own message
when it names someone, rather than one saying the user isn't a member. The
definition test's unaccepted-argument case uses an argument each tool doesn't
accept (an assignee for the tools that take a username).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… digital worker's task call EXO-91512

In a call limited to a space, an assignee, a coworker or a user a comment
mentions may be a member or a super manager of that space, as for the
platform's space rules and social's own mention receivers; the activity tools
follow the same rule (EXO-91521).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e AI tools' project results EXO-91949

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… returns it EXO-91949

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@exo-swf
exo-swf force-pushed the feature/ai-contribution branch from 09f5c0d to 0fc6729 Compare October 24, 2026 01:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants