refactor(v1.4.16): apply simplify-review safe suggestions

7 of 8 apply-yes simplify findings landed:

F2 — `generateInsight()` confidenceContext config-bag dropped. No
production caller passed the resolver; the wrapper now derives inputs
from the parsed payload directly (n from metricSource.n, recencyDays
=0, deviationStdRatio=null). Two confidence-wrapper tests rewritten
to test the parsed-payload path. v1.4.17 will re-introduce a
resolver injection when the feedback ratchet ships a real second
caller.

F3 — `aiRecommendationRationaleSchema.referenceId` speculative
optional field removed. No consumer reads it; rec-level referenceId
is the canonical citation pointer.

F4 — `applyLastWorkingCache` doc-comment trimmed: dropped the
"NEW array" defensive note (no caller compares the input ref).

F5 — `<RecommendationFeedback>` re-uses the canonical
`RecommendationFeedbackRequest` types from the validation schema
instead of hand-maintaining the same enum vocabulary. Removes a
silent-drift risk if v1.4.17 adds another time-range value.

F6 — `formatRelativeTime` doc-comment trimmed: dropped the stale
`Intl.RelativeTimeFormat` polyfill claim (baseline-supported since
2018) — kept the genuine WHY (i18n consistency).

F7 — `<RecommendationCard>` 26-line slot-architecture header trimmed
to a 4-line WHY. The slots being narrated as "future" were filled by
B5d / B5e in the same file.

F9 — `pickProviderType` doc-comment trimmed: removed the
mis-anchored PROMPT_VERSION snapshot paragraph (the function only
picks providerType — promptVersion is read elsewhere).

F10 — `legacy-payload.ts` `UnknownRec` interface removed; cast
inlined as `(rec as { rationale?: unknown })`.

F12 — `<ConfidenceMeter>` 20-line band-policy header trimmed to a
3-line WHY. The bandFor() helper + colour-by-band record below are
the documentation now.

(F1 + F8 deferred — both flagged "no" in simplify review and need
Marc's call.)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-10 03:10:09 +02:00
1 parent 56614392be
commit f3025a8dd5
10 files changed
+78 -175

No files matched your search

+3 -19
View File
@@ -1,25 +1,9 @@
import { useTranslations } from "@/lib/i18n/context";
/**
* v1.4.16 phase B5d — `<ConfidenceMeter>`.
*
* Renders a deterministic 0..100 confidence score (server-computed by
* `computeConfidence()` and overridden in `generateInsight()`) as
* either a 5-bar meter (default) or an SVG ring.
*
* Color bands match research §2.A "three-band visual" extended to 4
* bands so the under-50 region splits into "low" + "draft":
*
* - >=80: green ("high"), 5 bars / full ring
* - 50..79: yellow ("medium"), 3-4 bars
* - 25..49: orange ("low"), 2 bars / partial ring + caption
* - <25: "draft" pill REPLACES the meter — Apple's
* "quiet-when-unsure" affordance per research §2.A. The rec is
* drafted but the model isn't asserting it.
*
* aria-label always announces the numeric score so a screen reader
* isn't blind to the visual band distinction. Mobile-friendly: the
* bars variant fits in 56 px wide; the ring variant in 28×28.
* Renders a 0..100 confidence score as a 5-bar meter (default) or SVG
* ring. Sub-25 replaces the meter with a "draft" pill ("quiet-when-
* unsure"). aria-label always carries the numeric value.
*/
export type ConfidenceBand = "high" | "medium" | "low" | "draft";
@@ -41,13 +41,8 @@ interface InsightsPageHeroProps {
}
/**
* Format a relative time using the i18n translation keys. Avoids the
* `Intl.RelativeTimeFormat` polyfill cost on the client AND keeps every
* surface that renders relative times locked to the project's
* established translation vocabulary.
*
* Buckets: <1min → just now; <60min → N min ago; <24h → N h ago;
* else N days ago.
* Bucketed relative-time using i18n translation keys so every surface
* shares vocabulary. Buckets: <1m, <1h, <24h, else days.
*/
function formatRelativeTime(
iso: string,
@@ -20,30 +20,10 @@ import {
import { ConfidenceMeter } from "./confidence-meter";
/**
* v1.4.16 phase B5c — Oura-style RecommendationCard.
*
* Each recommendation lives in its own collapsible card. The
* collapsed row shows: severity badge + rec text + named slot for
* the future confidence-ring (B5d) + chevron toggle.
*
* Expanding reveals:
* - 3-row rationale card (Window / Compared to / Deviation)
* - mini-chart pinned to the rationale's data window via
* HealthChart's new `mini` + `windowOverride` props
* - citation footnote (B5a) when `referenceId` resolves
* - named slot for the future feedback-thumbs (B5e)
*
* Default state: collapsed. Chevron toggles `aria-expanded`. Plain-
* string recs (legacy InsightResult shape) and recs without
* `rationale` render as a non-expandable list item — there's nothing
* to expand to. The legacy-payload CTA at the parent advisor card
* level surfaces the regenerate prompt for those.
*
* Layout slots are deliberately named so B5d (confidence) and B5e
* (feedback) can plug in without touching this file:
*
* - data-slot="rec-confidence-slot" → B5d ConfidenceRing
* - data-slot="rec-feedback-slot" → B5e RecommendationFeedback
* Collapsible recommendation card with severity badge, confidence
* meter, and an expandable rationale block (window / compared-to /
* deviation) + mini-chart. Plain-string and rationale-less recs
* render as a non-expandable row.
*/
const SEVERITY_BADGE_STYLES: Record<string, string> = {
@@ -31,18 +31,18 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { ThumbsUp, ThumbsDown, Loader2, Check } from "lucide-react";
import { useTranslations } from "@/lib/i18n/context";
import { useAuth } from "@/hooks/use-auth";
import type { RecommendationFeedbackRequest } from "@/lib/validations/recommendation-feedback";
// v1.4.16 phase D reconcile (simplify F5) — re-export the canonical
// types from the validation schema instead of hand-maintaining the
// same enum vocabulary. Drift between the two used to be a real risk
// (a future "last180days" added to the schema would silently break
// the component without a compile error).
export type RecommendationFeedbackSeverity =
| "info"
| "suggestion"
| "important"
| "urgent";
RecommendationFeedbackRequest["recommendationSeverity"];
export type RecommendationFeedbackTimeRange =
| "last7days"
| "last30days"
| "last90days"
| "allTime";
RecommendationFeedbackRequest["metricSourceTimeRange"];
export interface RecommendationFeedbackProps {
recId: string;