Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.d/0.98.0-analysis-run-open-report-grouping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# 0.98.0 Open the corp grouping with the scored week

Open period report 2026-W02 also switches Report grouping to Corporate
entity and marks Demo Corp current. Mean θ stays on the report panel.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@ All notable changes to this project are documented here. Format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.98.0] - 2026-08-17

### Added

- Opening **Open period report 2026-W02** from a corporate-entity
analysis run also switches Report grouping to Corporate entity and
marks the Demo Corp grouping current. The opened report is named
Demo Corp, not a UUID. Mean θ stays on the report panel. No TEPP
theta is invented.

## [0.97.0] - 2026-08-17

### Added
Expand Down
3 changes: 2 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ then start. Do not invent a theta. Hover the Result prefix to read
the parent-choice digest.
After `make seed`, open **Period report · Succeeded · Demo Corp**,
then **Open period report 2026-W02**. The report period field is
focused. Mean θ stays on the period-report panel.
focused. Report grouping is Corporate entity and Demo Corp is current.
Mean θ stays on the period-report panel.
21 changes: 21 additions & 0 deletions backend/app/analysis_run_ingestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,24 @@
"""


def scope_grouping_key(row: Any) -> str | None:
"""Persist the reconstruct grouping key for the run's authorized scope.

A corporate-entity report run stores the week on ``scope_key``. The
grouping that reconstruct and the period-report panel share is the
corporate entity (or process unit / thread group), never that week
label and never a theta.
"""
scope = row["scope_kind_code"]
if scope == "analysis_scope_corporate_entity" and row["corporate_entity_id"]:
return str(row["corporate_entity_id"])
if scope == "analysis_scope_process_unit" and row["process_unit_id"]:
return str(row["process_unit_id"])
if scope == "analysis_scope_thread_group" and row["scope_key"]:
return str(row["scope_key"])
return None


def _iso(value: Any) -> str:
"""Serialize a timestamptz the same way post payloads do."""
return value.isoformat() if hasattr(value, "isoformat") else str(value)
Expand Down Expand Up @@ -253,6 +271,9 @@ async def _serialize_runs(
item["scope_entity_name"] = row["scope_entity_name"]
if row["scope_key"]:
item["scope_key"] = row["scope_key"]
grouping_key = scope_grouping_key(row)
if grouping_key:
item["scope_grouping_key"] = grouping_key
payload.append(item)
return payload

Expand Down
6 changes: 5 additions & 1 deletion backend/app/report_ingestion.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,10 +490,14 @@ async def fetch_period_reports(
selected_by_group[row["grouping_key"]].append(row)
payload: list[dict[str, Any]] = []
for header in headers:
grouping_key = header["grouping_key"]
payload.append(
{
"grouping_kind": header["grouping_kind"],
"grouping_key": header["grouping_key"],
"grouping_key": grouping_key,
"grouping_label": await resolve_grouping_label(
conn, header["grouping_kind"], grouping_key
),
"period_code": header["period_code"],
"rubric_version": header["rubric_version"],
"selected_model": header["selected_model"],
Expand Down
6 changes: 4 additions & 2 deletions docs/adr/0024-seed-period-report-analysis-run.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ on a path that is not allowed to (ADR 0021 / ADR 0022 / ADR 0023).
After `make seed`, Demo Analyst opens Analysis runs and sees
**Period report · Succeeded · Demo Corp** next to the lineage and TEPP
rows. Opening it shows the cutoff posts and **Open period report
2026-W02** (the week stored on `scope_key`). Mean θ remains on the
period-report panel. Re-seed is idempotent on
2026-W02** (the week stored on `scope_key`). That click also switches
Report grouping to Corporate entity and marks the Demo Corp grouping
current, using the persisted scope grouping key. Mean θ remains on
the period-report panel. Re-seed is idempotent on
`demo-report-seed-2026-w02`.

## References — APA 7th
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "frontend",
"private": true,
"version": "0.97.0",
"version": "0.98.0",
"type": "module",
"scripts": {
"dev": "vite",
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
font-size: 1rem;
}

.post-list-item[aria-current="true"],
.ticket-list-item[aria-current="true"] {
border-color: #2563eb;
box-shadow: inset 0 0 0 1px #2563eb;
}

.post-badge {
font-size: 0.75rem;
opacity: 0.7;
Expand Down
68 changes: 67 additions & 1 deletion frontend/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ describe("App, authenticated", () => {
scope_kind_label: "Corporate entity",
scope_entity_name: "Demo Corp",
scope_key: "2026-W02",
scope_grouping_key: "corp-1",
status_code: reportSucceeded ? "analysis_status_succeeded" : "analysis_status_failed",
status_label: reportSucceeded ? "Succeeded" : "Failed",
knowledge_cutoff: "2026-01-12T12:00:00Z",
Expand Down Expand Up @@ -674,6 +675,7 @@ describe("App, authenticated", () => {
scope_kind_label: "Corporate entity",
scope_entity_name: "Demo Corp",
scope_key: "2026-W02",
scope_grouping_key: "corp-1",
status_code: options?.failedReportRun
? ("analysis_status_failed" as const)
: ("analysis_status_succeeded" as const),
Expand Down Expand Up @@ -743,7 +745,7 @@ describe("App, authenticated", () => {
{
grouping_kind: "corporate_entity",
grouping_key: "corp-1",
grouping_label: "Test Corp",
grouping_label: "Demo Corp",
mean_theta: 0.01,
post_count: 8,
link_method: "fipc",
Expand Down Expand Up @@ -793,6 +795,59 @@ describe("App, authenticated", () => {
}),
);
}
if (url.includes("/api/reports/corporate_entity/") && method === "GET") {
return Promise.resolve(
jsonResponse({
grouping_kind: "corporate_entity",
period_code: url.includes("2026-W03") ? "2026-W03" : "2026-W02",
reports: [
{
grouping_key: "corp-other",
grouping_label: "Other Corp",
selected_model: "grm",
mean_theta: -0.2,
mean_theta_sd: 0.1,
post_count: 2,
item_count: 3,
fit_converged: true,
link_method: "fipc",
anchor_period_code: "2026-W02",
delta_mean_theta: null,
selected_items: [],
members: [],
},
{
grouping_key: "corp-1",
grouping_label: "Demo Corp",
selected_model: "grm",
mean_theta: 0.42,
mean_theta_sd: 0.1,
post_count: 8,
item_count: 3,
fit_converged: true,
link_method: "fipc",
anchor_period_code: "2026-W02",
delta_mean_theta: null,
selected_items: [
{ item_code: "sales_lead_specificity", rank: 1, information: 0.7 },
],
members: [
{
post_id: "post-1",
post_title: "Public post",
theta_eap: 0.91,
theta_sd: 0.2,
ticket_due_date: "2026-01-12",
ticket_title: "Send Northridge Grid the revised quote",
ticket_status_code: "open",
ticket_status_label: "Open",
},
],
},
],
}),
);
}
if (url.includes("/api/reports/") && method === "GET") {
return Promise.resolve(
jsonResponse({
Expand Down Expand Up @@ -2119,9 +2174,20 @@ describe("App, authenticated", () => {
await userEvent.clear(periodInput);
await userEvent.type(periodInput, "2026-W03");
expect(periodInput).toHaveValue("2026-W03");
const groupingSelect = screen.getByLabelText("Report grouping");
expect(groupingSelect).toHaveValue("process_unit");
await userEvent.click(screen.getByRole("button", { name: "Open period report 2026-W02" }));
expect(periodInput).toHaveValue("2026-W02");
expect(groupingSelect).toHaveValue("corporate_entity");
expect(periodInput).toHaveFocus();
expect(
screen.getByRole("button", { name: "Compare corporate_entity: Demo Corp" }),
).toHaveAttribute("aria-current", "true");
expect(
screen.getByRole("button", { name: "Compare process_unit: Demo Report High" }),
).not.toHaveAttribute("aria-current");
expect(await screen.findByText(/Demo Corp: mean θ 0\.42/)).toBeInTheDocument();
expect(screen.queryByText(/corp-1: mean θ/)).not.toBeInTheDocument();
});

it("does not tell a failed period report to connect the measurement service", async () => {
Expand Down
Loading