Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7b7a6c1
feat(frontend): coverage — what reads for a person, and for how many
Aug 10, 2026
fad159a
feat(frontend): scope coverage over the roster the viewer was served
Aug 10, 2026
d064d64
feat(frontend): "What we can see" tab on Overview
Aug 10, 2026
28b62f5
feat(frontend): fold coverage-per-person into Health radar, and name …
Aug 10, 2026
06d0ce0
feat(frontend): lead the coverage section with its finding, not its s…
Aug 10, 2026
8c9602c
refactor(frontend): one coverage model, three cuts — verdict, parts, …
Aug 10, 2026
e72f112
fix(frontend): show where the coverage headline comes from
Aug 10, 2026
96166ae
feat(frontend): open a coverage level into the people at it
Aug 10, 2026
1765771
fix(frontend): the person page reads source availability from the ten…
Aug 10, 2026
5ddb090
Merge branch 'main' into feat/coverage-readout
dzarlax Aug 10, 2026
3e4fb32
fix(frontend): coverage must not turn its own failures into verdicts …
Aug 10, 2026
ecf70d8
Merge remote-tracking branch 'fork-cf/feat/coverage-readout' into fea…
Aug 10, 2026
fb4b734
chore: keep the branch's diff to the frontend
Aug 10, 2026
0add897
Merge branch 'main' into feat/coverage-readout
dzarlax Aug 11, 2026
4aba94d
fix(frontend): an empty scope is an answer, not a wait
Aug 11, 2026
964f0e0
Merge remote-tracking branch 'fork-cf/feat/coverage-readout' into fea…
Aug 11, 2026
79534c1
chore: bring four files back in line with upstream main
Aug 11, 2026
a4db1ae
Merge remote-tracking branch 'upstream/main' into feat/coverage-readout
Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/frontend/src/api/metric-definitions-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const METRIC: MetricDefinition = {
direction: "higher_is_better",
dimensions: ["repo"],
is_enabled: true,
origin: "builtin" as const,
schema_status: "ok",
schema_error_code: null,
last_observed_date: "2026-07-20",
Expand Down
10 changes: 10 additions & 0 deletions src/frontend/src/api/metric-definitions-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const BASE =

export type MetricDefinitionSchemaStatus = "ok" | "error" | "unchecked";

export type MetricDefinitionOrigin = "builtin" | "custom";

export interface MetricDefinition {
metric_key: string;
label: string;
Expand All @@ -32,6 +34,14 @@ export interface MetricDefinition {
direction: MetricDirection;
dimensions: string[];
is_enabled: boolean;
/**
* `builtin` reads managed observation relations; `custom` executes inline
* SQL at query time. The validator stamps `schema_status` and
* `last_observed_date` from materialized relations only, so for `custom`
* they stay "unchecked" / absent however much data the metric serves —
* reading their absence as "never measured" is wrong for those.
*/
origin: MetricDefinitionOrigin;
schema_status: MetricDefinitionSchemaStatus;
/** Why schema_status is "error"; null otherwise. */
schema_error_code: MetricSchemaErrorCode | null;
Expand Down
2 changes: 1 addition & 1 deletion src/frontend/src/components/portal/context-pane.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ describe("ContextPane", () => {
expect(screen.getByText("Overview")).toBeInTheDocument();
expect(screen.getByText("Cross-functional org rollup")).toBeInTheDocument();
const item = renderHook(() => usePortalItem());
await userEvent.click(screen.getByText("Health radar"));
await userEvent.click(screen.getByText("What we can see"));
expect(item.result.current).toBe("health");
});

Expand Down
82 changes: 74 additions & 8 deletions src/frontend/src/components/portal/domain-lens-view.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ vi.mock("@tanstack/react-router", async () => {
import { portalRouter } from "@/test/portal-router";

import { act, render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";

import { GROUPS } from "@/lib/insight/groups";
import type { NormalizedMetricResult } from "@/lib/metrics/collection";
import { identityPerson, pid } from "@/test/identity";
import type { IdentityPerson } from "@/types/insight";
Expand All @@ -35,6 +37,8 @@ const mocks = vi.hoisted(() => ({
refetch: vi.fn(),
},
call: 0,
collectionSet: new Map<string, unknown>(),
definitions: [] as unknown[],
collections: [] as Array<{
byKey: Map<string, NormalizedMetricResult>;
isPending: boolean;
Expand Down Expand Up @@ -68,6 +72,16 @@ vi.mock("@/queries/metric-results", () => ({
mocks.call += 1;
return r;
},
// Only the coverage section reads the set form; it fetches its own
// period-only collection rather than riding the zone grid.
useMetricCollectionSet: () => mocks.collectionSet,
}));
vi.mock("@/queries/metric-definitions", async (orig) => ({
...(await orig<Record<string, unknown>>()),
useMetricDefinitionsResponse: () => ({
data: { metrics: mocks.definitions },
isPending: false,
}),
}));
vi.mock("@/hooks/use-portal-period", () => ({
usePortalPeriod: () => ({
Expand Down Expand Up @@ -411,7 +425,7 @@ describe("by-unit auto-section (rule 7: slice cohorts inside scope)", () => {
});
});

describe("direction-cards / coverage-radar / attention sections", () => {
describe("direction-cards / attention sections", () => {
it("renders attention rows for cohort outliers, named and linked (O3)", () => {
// 7 healthy + 1 collapsed member
const labels = ["m1", "m2", "m3", "m4", "m5", "m6", "m7", "z"];
Expand All @@ -434,16 +448,68 @@ describe("direction-cards / coverage-radar / attention sections", () => {
expect(screen.getByText(/no commits/)).toBeInTheDocument();
});

it("suppresses the coverage radar below the minimum cohort", () => {
mocks.tree = person("boss", {}, [person("a"), person("b")]);
});

describe("coverage section (#2408)", () => {
/** One group reading for the named people, the rest silent. */
function coverageWorld(seenByGitOutput: string[]) {
const ids = seenByGitOutput.map((l) => pid(l));
mocks.definitions = GROUPS.flatMap((g) =>
g.collection.metrics.map((m) => ({
metric_key: m.key,
is_enabled: true,
schema_status: "ok",
schema_error_code: null,
// Only git output has ever observed anything for this tenant, so every
// other part must read as "no connector" rather than as idle people.
last_observed_date: g.id === "git_output" ? "2026-07-26" : null,
})),
);
const gitKey = GROUPS.find((g) => g.id === "git_output")!.collection
.metrics[0]!.key;
mocks.collectionSet = new Map(
GROUPS.map((g) => [
g.id,
{
byKey:
g.id === "git_output"
? new Map([
[gitKey, metric(gitKey, ids.map((id) => [id, 3]))],
])
: new Map(),
isPending: false,
},
]),
);
}

it("opens a level into exactly the people at it, and why each is thin", async () => {
mocks.tree = person("boss", {}, [person("a"), person("b"), person("c")]);
coverageWorld(["a"]);
render(
<DomainLensView
config={{ title: "T", sections: [{ kind: "coverage-levels" }] }}
/>,
);

// One person reads in one part; the other two read in none.
await userEvent.click(screen.getByRole("button", { name: /1 of 5/ }));
expect(screen.getByText("a")).toBeInTheDocument();
expect(screen.queryByText("b")).not.toBeInTheDocument();

// And the reason is the actionable half: nothing feeds those parts for the
// tenant, which is a plumbing job — not people who did no work.
expect(screen.getAllByText(/no connector:/).length).toBeGreaterThan(0);
});

it("does not open a level nobody is at", async () => {
mocks.tree = person("boss", {}, [person("a")]);
coverageWorld([]);
render(
<DomainLensView
config={{ title: "T", sections: [
{ kind: "headline", metrics: ["t.commits"] },
{ kind: "coverage-radar" },
] }}
config={{ title: "T", sections: [{ kind: "coverage-levels" }] }}
/>,
);
expect(screen.queryByText("Health radar")).not.toBeInTheDocument();
expect(screen.getByRole("button", { name: /5 of 5/ })).toBeDisabled();
});
});
Loading
Loading