Skip to content

lisa/feat/bch-1312-suggestions-ui#264

Merged
gusfcarvalho merged 14 commits into
mainfrom
lisa/feat/bch-1312-suggestions-ui
Jun 16, 2026
Merged

lisa/feat/bch-1312-suggestions-ui#264
gusfcarvalho merged 14 commits into
mainfrom
lisa/feat/bch-1312-suggestions-ui

Conversation

@ccf-lisa

@ccf-lisa ccf-lisa Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

automated implementation by lisa.

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings inline (1 Medium, 4 Low; CI green, no blockers). Headline: the run poller stops permanently on any transient poll error (useDashboardSuggestions.ts:265), silently freezing generation progress — that's the one worth fixing; the rest are nil-guards, two dead exports, and a vacuous negative test. Nice work on the fail-closed config gate and the prior self-review passes. Out of scope: the duplicate inventory:index route in router/index.ts already exists on main.

Comment thread src/composables/useDashboardSuggestions.ts
Comment thread src/views/dashboard/SuggestionsView.vue Outdated
Comment thread src/views/dashboard/partials/dashboard-suggestions.ts Outdated
Comment thread src/views/dashboard/partials/dashboard-suggestions.ts Outdated
Comment thread src/views/dashboard/__tests__/SuggestionsView.spec.ts

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All review feedback from the prior pass is addressed in d79b459 and verified on the incremental diff:

  • Poller transient-error halt (Medium) — the catch now only stops on the new stopOnPollError opt-in (default off), so a flaky poll no longer freezes generation progress. Nice touch adding a regression test (keeps polling after a transient poll error) that genuinely fails under the old behavior.
  • SSP /full nil-guards (Low)?.metadata?.title and ?.controlImplementation?.implementedRequirements both hardened.
  • Dead exports (Low x2)getSuggestionId and buildDashboardSuggestionRunEndpoint removed (correct call to drop rather than switch accept/reject to uuid).
  • Vacuous negative test (Low) — positive enabled-path test added, asserting refreshLabelSets/refreshHistorySuggestions/pollLatest are called; both sides of the gate now covered.

CI green (test + type-check) on the new HEAD, all threads resolved, no regressions in the diff. LGTM.

Optional non-blocking nit (no need to action): stopOnPollError has no caller passing true yet — fine as a deliberate opt-in hook, just flagging it's currently unexercised in that direction.

@ccf-lisa

ccf-lisa Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

PR approved. Marking as ready for e2e.

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reopening with product feedback from the maintainer that supersedes my earlier approval (code itself is sound; this is about placement and UX).

Findings inline. Headline: (1) the AI dashboard-suggestions entry point belongs in the per-control Control Implementation editor next to the component-suggestions feature / 'Evidence Linking' (ControlStatementImplementation.vue ~1407/1451), where the SSP is already in context — not as a separate button + SSP-picker on the global /dashboards page; and (2) when AI isn't configured the entry point is hidden silently — it should show an explicit 'AI is not configured, can't generate suggestions' message instead. The existing disabled-state copy in SuggestionsView is unreachable in practice and conflates 'off' with 'not configured'.

Comment thread src/views/dashboard/IndexView.vue Outdated
Comment thread src/views/dashboard/IndexView.vue Outdated
Comment thread src/views/dashboard/SuggestionsView.vue Outdated
@ccf-lisa ccf-lisa Bot removed the ready-for-e2e label Jun 16, 2026

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Round 2 of maintainer UX feedback. Findings inline. Headline: (1) the evidence label-set selector should show a human Label Set Title (like the 'Create New Dashboard' evidence picker), not the raw hash; (2) the controls selector should show each control's title (not just the ID) and which profile(s) it belongs to. Note for (2): control titles need a catalog resolve (pattern exists in CreateFormView), and profile membership isn't in the SSP /full payload — it needs the bound profiles resolved — so this is a scoping call, flagged inline.

Comment thread src/views/dashboard/partials/SuggestionScopeDialog.vue Outdated
Comment thread src/views/dashboard/SuggestionsView.vue Outdated

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings inline. Headline: the scope dialog's AI-call estimate is a raw controls×label-sets product and over-reports massively (e.g. 1424 vs ~1) because it ignores server chunking — switch it to the new POST .../dashboard-suggestions/preview endpoint from API PR 420, which returns the real chunked plannedCalls (plus resolved control/label-set counts). Contract + suggested wiring in the thread.

Comment thread src/views/dashboard/partials/SuggestionScopeDialog.vue Outdated
gusfcarvalho
gusfcarvalho previously approved these changes Jun 16, 2026

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incremental review of 3a06fda..6986e73. All prior threads + the maintainer's feature feedback are addressed and verified in code: entry point relocated to the Control Implementation editor (global picker removed), explicit 'AI not configured' message, human label-set titles, control options now show title + profile membership (resolved-with-catalogs field names confirmed against RiskDetailView), and the cost estimate is wired to the new POST /dashboard-suggestions/preview endpoint — debounced with a stale-request guard, server plannedCalls drives the copy and the large-run gate, 422 empty-scope handled. Tests are solid (incl. the 16x89 -> 1 regression test) and CI is green. Approving. Two Low, non-blocking nits inline (redundant catalog fan-out; missing onUnmounted timer cleanup) — take or leave.

Comment thread src/views/dashboard/SuggestionsView.vue
Comment thread src/views/dashboard/partials/SuggestionScopeDialog.vue

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more UX refinement (maintainer request). Findings inline. Headline: bring the Controls scope selector up to the same standard as the Evidence-Linking selector — a two-line option where the main value is ID - Title and the sub-line is the Catalog, keeping profile membership as a chip. Needs controlOptions to emit structured options and the catalog title to be captured per control (currently discarded in the catalog walk).

Comment thread src/views/dashboard/partials/SuggestionScopeDialog.vue
Comment thread src/views/dashboard/SuggestionsView.vue

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two issues from live testing (reproduced via Playwright against the running stack). Headline: (1) functional bug — control title/catalog/profile resolution is case-sensitive, so the 12/29 SSP controls whose control-ids are stored lowercase render as bare ids (gd.sec.c08); all 12 resolve under case-insensitive matching. (2) the label-set dropdown rows still don't show the title as the main line (only the selected chips do) — bring them up to the Evidence-Linking standard. Details + the fix inline.

Comment thread src/views/dashboard/SuggestionsView.vue Outdated
Comment thread src/views/dashboard/partials/SuggestionScopeDialog.vue
ccf-lisa Bot and others added 2 commits June 16, 2026 07:31
Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
@gusfcarvalho gusfcarvalho enabled auto-merge (squash) June 16, 2026 11:42
Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings inline (A+B). The "matched evidence" count always renders 0 because pendingGroups reads suggestion.evidenceCount, a field the API never returns — the real count lives on the already-fetched labelSets array and must be joined by labelSetHash. Same root cause leaves the group label chips empty (suggestion.labels vs API labelSet).

Requested changes:

  • A — Join pendingGroups to labelSets by hash for evidenceCount, and source label chips from the matched label-set (SuggestionsView.vue pendingGroups).
  • B — Make the "N matched evidence" span a router-link to the evidence index pre-filtered by the group's labels (group.labels.join(' and ')), so users can see the exact matching evidence streams.
  • Companion — add camelcaseStopPaths: ['data.labelSet'] to the pending/history suggestion fetches to preserve _-prefixed label keys for the labelSet fallback.

No API change required for A+B; an optional follow-up could enrich the suggestion response with evidenceCount server-side so the UI need not depend on a second endpoint.

Comment thread src/views/dashboard/SuggestionsView.vue Outdated
Comment thread src/views/dashboard/SuggestionsView.vue
Comment thread src/composables/useDashboardSuggestions.ts

@gusfcarvalho gusfcarvalho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A+B implemented correctly in f56e6cd and all threads resolved — approving.

  • ApendingGroups now joins the fetched labelSets by labelSetHash via a labelSetByHash computed; evidenceCount comes from matched?.evidenceCount and label chips from matched?.labels (with suggestion.labelSet stale-fallback). The phantom suggestion.evidenceCount / Math.max path is gone.
  • B — the count is now a RouterLink to evidence:index filtered by group.labels.join(' and '), with sampleTitles surfaced as a tooltip.
  • Companion — camelcaseStopPaths: ['data.labelSet'] added to both the pending and history fetches, preserving _-prefixed keys for the fallback.

Verified locally: SuggestionsView.spec.ts passes (5/5, including the 7 matched evidence count and the _agent=scanner and env=prod filter link), and vue-tsc is clean on the touched files.

@ccf-lisa

ccf-lisa Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

PR approved. Marking as ready for e2e.

@gusfcarvalho gusfcarvalho merged commit 74ae0c8 into main Jun 16, 2026
2 checks passed
@gusfcarvalho gusfcarvalho deleted the lisa/feat/bch-1312-suggestions-ui branch June 16, 2026 12:36
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