Repository navigation
Add Streamlit analysis stories and visual design review - #15
Conversation
Generate business-focused dashboards and workbooks from verified analysis reports. Add the taxi narrative, readable month labels, mobile heatmaps, explicit color-scale endpoints, and axis spacing. Add native Claude visual review with up to two Sol presentation revisions, browser checks, and LangSmith evidence. Include CLI integration, offline guidance, tests, and CI dependencies.
Codex Review Summary: ❌ FailedThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 624e3aaf7b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if provider == "anthropic": | ||
| from langchain_anthropic import ChatAnthropic |
There was a problem hiding this comment.
Restrict native Anthropic construction to dashboard review
Because build_model() is also called by the general ask, benchmark, and judge paths, accepting anthropic/* here lets commands such as backintel ask --model anthropic/... run the analyst directly through Anthropic rather than limiting the native provider to the independent dashboard reviewer. Add an explicit review-only gate or a dedicated reviewer factory so the new provider cannot bypass the repository's model-routing boundary.
AGENTS.md reference: AGENTS.md:L36-L41
Useful? React with 👍 / 👎.
| menuitem = page.get_by_role("menuitem", name=name, exact=True) | ||
| target = menuitem if menuitem.is_visible() else link | ||
| target.click(timeout=10000) | ||
| page.get_by_role("heading", name=name, exact=True).wait_for(timeout=15000) |
There was a problem hiding this comment.
Scope the page-heading wait to the section heading
When a valid design plan gives a section and one of its charts the same title, the page renders both an st.header and st.subheader with that accessible name. This unscoped locator then matches multiple headings, causing Playwright's strict wait_for to fail and the review to end as review_error even though the dashboard rendered correctly; constrain the lookup by heading level or select the section heading explicitly.
Useful? React with 👍 / 👎.
| if dashboard_reviewer is not None: | ||
| from backintel.presentation.review import review_dashboard | ||
|
|
||
| record["dashboard_review"] = await asyncio.to_thread( |
There was a problem hiding this comment.
Keep automatic review inside the run deadline
When analyze --review-dashboard is used, this review starts after the graph's asyncio.timeout and the publisher's remaining-time check, with no deadline of its own. It can therefore perform three reviewer calls, two writer calls, and repeated browser captures after timeout_s has already elapsed, so --timeout no longer bounds the analysis command; pass the remaining budget into the review or enforce a deadline around the entire stage.
Useful? React with 👍 / 👎.
|
|
||
|
|
||
| class Section(StrictModel): | ||
| title: str = Field(min_length=1, max_length=45) |
There was a problem hiding this comment.
Reject whitespace-only design copy
Pydantic's min_length=1 accepts values such as " ", so a generated or supplied plan can pass validation with a visually blank section title. That produces an unusable navigation entry and can make capture fail while waiting for a heading with no accessible name; trim or explicitly reject whitespace-only values for required presentation strings.
Useful? React with 👍 / 👎.
| ) | ||
| f.update_layout(barmode="group", bargap=0.4, showlegend=True, legend=dict(orientation="h", y=1.25, x=0)) | ||
| f.update_xaxes( | ||
| range=[0, 17], |
There was a problem hiding this comment.
Derive the airport axis range from retained shares
Any accepted taxi story containing an airport share above 17% has its bar truncated at this fixed maximum, which visually understates the retained value even though the hover and label report the larger percentage. The valid fixture in tests/test_taxi_story.py already supplies a 20% JFK fare share, so this occurs for data the validator accepts; calculate the upper bound from the plotted shares with suitable padding.
Useful? React with 👍 / 👎.
| report = validate_report(spec) | ||
| # Explicit allowlists prevent arbitrary report extensions and execution metadata | ||
| # from entering the browser. Narrative text remains the analyst's responsibility. | ||
| result = {key: report[key] for key in ("title", "summary", "findings", "caveats")} |
There was a problem hiding this comment.
Preserve sanitized source context in dashboard data
For reports whose title and summary do not redundantly name the source, this projection discards the required sources records entirely, including their human-readable descriptions. Consequently the dashboard, downloaded workbook, and design reviewer cannot tell readers what dataset or period the analysis represents; retain a sanitized source description while continuing to exclude snapshots, hashes, and execution metadata.
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1f84386b4
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| record["artifacts"] = verify_bundle(output / "artifacts" / "report") | ||
| from backintel.presentation.dashboard import generate_dashboard | ||
|
|
||
| record["dashboard"] = generate_dashboard(rendered["spec"], output / "dashboard") |
There was a problem hiding this comment.
Include dashboard generation in the run deadline
When artifact publication finishes close to timeout_s, this always-on dashboard step builds and styles the workbook without checking the remaining budget or running under a timeout. A report near the 100,000-cell contract limit can therefore keep analyze running past --timeout and still be recorded as completed; apply the remaining whole-run deadline to dashboard generation as well.
AGENTS.md reference: AGENTS.md:L28-L31
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3465bc2706
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if list(frame(story, "fare_bands").Fare_band) != FARE_BANDS or len(frame(story, "quality")) != 10: | ||
| raise ValueError("Incomplete fare or coverage table.") |
There was a problem hiding this comment.
Require the ten-zone table promised by the story
When the zones table contains any nonempty number of rows other than ten, validate_story still accepts it—the committed test fixture contains only three—while the Explore view describes the result as “Ten pickup zones” and zone_chart plots every supplied row. An incomplete or oversized aggregate can therefore be presented with a false population claim; validate that this table contains exactly the ten expected ranking rows before displaying it.
Useful? React with 👍 / 👎.
| ) | ||
| ) | ||
| f.update_xaxes( | ||
| range=[0, 28], |
There was a problem hiding this comment.
Size the zone axis from the retained fare values
When any accepted pickup zone has more than $28 million in Gross_fare_USD, this fixed axis maximum clips its bar and outside value label, visually understating the retained aggregate. validate_story permits any finite fare total, so derive the upper bound from the plotted values with label padding rather than assuming this dataset-specific ceiling.
Useful? React with 👍 / 👎.
| if len(row) != len(table["columns"]): | ||
| raise ValueError(f"Invalid {name} row.") | ||
| if any(isinstance(value, (int, float)) and not math.isfinite(value) for value in row): |
There was a problem hiding this comment.
Reject nonnumeric values in numeric story columns
When an unbound numeric field such as monthly.Gross_fare_USD contains a string, this check accepts it because it only tests values already typed as numbers. prepare_story then publishes the invalid story, and the Streamlit app raises an uncaught decimal.InvalidOperation while computing summary() instead of showing its readable invalid-data state. Validate every required numeric column by schema rather than allowing arbitrary strings through.
Useful? React with 👍 / 👎.
| if expected: | ||
| await charts.first.locator(".main-svg").first.wait_for(timeout=15000) |
There was a problem hiding this comment.
Wait for all charts before taking review screenshots
When a page contains multiple Plotly charts and later charts render more slowly than the first, the count assertion succeeds as soon as their containers exist, but this waits for an SVG only in the first chart. Screenshots can therefore capture blank later charts and cause the reviewer to reject a correctly rendered dashboard based on incomplete evidence; await the rendered SVG for every chart before capture.
AGENTS.md reference: AGENTS.md:L36-L39
Useful? React with 👍 / 👎.
| for row, label in zip(rows, names, strict=True): | ||
| row[0] = label |
There was a problem hiding this comment.
Preserve the meaning of quality rows when relabeling
When the retained quality table contains the expected ten populations in a different order, this positional rewrite silently assigns each count to the wrong business label—for example, an eligible-record count can be presented as source records. Neither prepare_story nor validate_story checks the original Population values, so map recognized source labels explicitly or reject an unexpected order before replacing them.
Useful? React with 👍 / 👎.
| centers, counts, width = _histogram(chart, table) | ||
| f.add_trace(go.Bar(x=centers, y=counts, width=width, marker_color="#176581")) |
There was a problem hiding this comment.
Show histogram bin ranges instead of only their centers
For every histogram dashboard, _histogram returns each bin's width but this trace discards it for hover semantics, so Plotly reports only the bin center and count; a reader can mistake a center such as 15 for an observed value rather than the interval 10–20. The existing artifact renderer uses the same width to expose lower and upper bounds in artifacts.py lines 439–443, so retain those bounds in the dashboard trace as well.
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c2f67db6ea
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if type(value) not in (int, float): | ||
| raise ValueError(f"Nonnumeric value in {name}.{column}.") | ||
| if not math.isfinite(value): | ||
| raise ValueError(f"Non-finite value in {name}.{column}.") |
There was a problem hiding this comment.
Validate numeric domains before publishing the story
When a retained report contains fractional or negative record counts, or a percentage outside 0–100, this validation accepts it because every finite int or float passes. The resulting public story can show impossible shares or negative source records, and fractional monthly.Trips are silently truncated by summary() while the workbook retains the original values, causing the headline and supporting data to disagree. Enforce column-specific domains, including integral nonnegative counts and bounded percentage fields, before publication.
Useful? React with 👍 / 👎.
| if not self.passed and not (self.blocking_issues or self.revisions): | ||
| raise ValueError("A failing review must provide actionable feedback.") | ||
| return self |
There was a problem hiding this comment.
Require reviews to cover every captured view
When the reviewer cites one valid screenshot for each rating but ignores the remaining pages or the entire mobile capture, this check still accepts the review because it only rejects unknown view names. A five-star response can therefore mark the dashboard ready without assessing layout failures visible in uncited captures, despite the capture stage supplying every section at both widths. Require the union of cited views to cover view_names before allowing a passing review.
Useful? React with 👍 / 👎.
| "--server.headless", | ||
| "true", | ||
| "--browser.gatherUsageStats", | ||
| "false", | ||
| "--server.fileWatcherType", | ||
| "none", |
There was a problem hiding this comment.
Render review captures with the delivered theme
When dashboard review is run from an installed package or any directory without this repository's .streamlit/config.toml, this preview command receives only server flags and falls back to Streamlit's default client and theme settings. The normal dashboard serve command supplies the BackIntel colors, fonts, sizing, borders, and toolbar options explicitly, so the reviewer can accept or reject screenshots that do not match what readers receive. Pass the same client and theme flags to the capture server rather than relying on the caller's working directory.
AGENTS.md reference: AGENTS.md:L36-L40
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc25b1e0b3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if list(monthly.Month) != list(MONTHS) or (monthly.Trips_per_day <= 0).any(): | ||
| raise ValueError("This story requires the complete January–March 2025 monthly view.") |
There was a problem hiding this comment.
Reject data that contradicts the fixed March-growth story
When a structurally valid Q1 report has March Trips_per_day equal to or below January, this check still accepts it because it only requires every daily rate to be positive. The dashboard then says activity “rose,” while the KPI unconditionally prepends + and can render values such as +-10.0%; either validate the growth premise or make the KPI and narrative conditional on the measured direction.
Useful? React with 👍 / 👎.
| if monthly.Trips.sum() <= 0 or monthly.Gross_fare_USD.sum() <= 0: | ||
| raise ValueError("Quarterly trip and fare totals must be positive.") |
There was a problem hiding this comment.
Bound computed airport shares against quarterly totals
When the JFK and LaGuardia rows contain trip or fare totals greater than the quarterly totals in monthly, every individual value passes these checks, but summary() divides those airport values by the smaller monthly denominators and publishes a share above 100%. The bounded *_share_pct columns do not protect this separately computed headline, so validate the cross-table totals before accepting the story.
Useful? React with 👍 / 👎.
| "Use the existing OpenAI/ChatGPT writer; the reviewer must be a different family." | ||
| ) | ||
| reviewer = build_dashboard_reviewer(args.reviewer_model) | ||
| writer = build_model(writer_id, reasoning_effort="medium", max_retries=0, timeout_s=120) |
There was a problem hiding this comment.
Skip writer construction for review-only runs
When dashboard review --max-revisions 0 is run with native Anthropic credentials but without an OpenAI key or ChatGPT-plan login, this unconditional build_model call aborts before the reviewer runs, even though the loop can never invoke the reviser and the documented option is specifically meant to review without revising. Defer writer construction and validation unless max_revisions is greater than zero, or permit an absent reviser in that mode.
Useful? React with 👍 / 👎.
| await client.create_feedback( | ||
| run_id=run.id, | ||
| session_id=session_id, | ||
| key="dashboard_" + rating.criterion, | ||
| score=rating.score, | ||
| comment=rating.evidence, | ||
| ) |
There was a problem hiding this comment.
Keep feedback-upload failures from invalidating a review
When LANGSMITH_TRACING=true and LangSmith is temporarily unavailable or rejects feedback writes, this awaited create_feedback call raises after the model has already returned a valid assessment. The outer review loop then records review_error instead of accepting or retaining that assessment, making optional observability availability determine dashboard readiness; preserve the local review result and record feedback-upload failure separately.
Useful? React with 👍 / 👎.
| segments = frame(story, "segments") | ||
| for month in (date[:7] for date in MONTHS): | ||
| if not set(AIRPORTS) <= set(segments[segments.Month == month].Pickup_segment): | ||
| raise ValueError("Incomplete monthly airport coverage.") |
There was a problem hiding this comment.
Reject airport-mix rows outside the declared quarter
When segments contains all required January–March rows plus rows for another month, this loop accepts the table because it checks only that each expected month is present. The story still declares January–March 2025 while business_workbook() exports every segment row, so the delivered workbook silently includes out-of-scope data; require the set of segment months to match the declared quarter.
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 670bc71b6d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| plan = validate_plan(plan.model_dump(), data) | ||
| if plan: | ||
| (folder / "presentation.json").write_text(plan.model_dump_json(indent=2)) | ||
| (folder / "analysis.xlsx").write_bytes(workbook_bytes(data, plan)) |
There was a problem hiding this comment.
Move workbook creation outside the event loop
When automatic review starts with little time remaining, or a valid report approaches the 100,000-cell limit, this synchronous OpenPyXL serialization blocks the event loop, so the surrounding asyncio.timeout cannot expire until the workbook finishes; every revision repeats the work. As a result, analyze --timeout can still be exceeded despite the new whole-review deadline. Run workbook creation in a cancellable owned process, as dashboard generation already does, or create it before entering the remaining-time budget.
Useful? React with 👍 / 👎.
| for column in ("Trips", "Gross_fare_USD"): | ||
| if sum(Decimal(str(x)) for x in airports[column]) > sum(Decimal(str(x)) for x in monthly[column]): | ||
| raise ValueError("Airport totals cannot exceed the quarterly trip or fare totals.") |
There was a problem hiding this comment.
Cross-check displayed airport shares against totals
When the two airport rows contain bounded but incorrect Trip_share_pct or Fare_share_pct values, this new check accepts them because it validates only raw trip and fare totals. For example, the retained counts can make summary() report a 5% combined airport share while two 90% share fields make airport_chart() display 90% for each airport. Even after the new count-total check, the dashboard can therefore contradict its own headline; validate the supplied shares against their monthly/quarterly denominators within a rounding tolerance, and ensure mutually exclusive airport shares cannot exceed 100% in aggregate.
Useful? React with 👍 / 👎.
| blocking_issues: list[str] = Field(max_length=12) | ||
| revisions: list[str] = Field(max_length=8) |
There was a problem hiding this comment.
Reject blank review feedback items
When the reviewer returns blocking_issues=[""] or revisions=[" "], whitespace stripping leaves a nonempty list containing an empty string, and checked() treats that as actionable feedback. The candidate is therefore rejected and subsequent paid revision calls are asked to fix an unspecified issue; require every list item to contain bounded nonblank text before accepting a failing review.
Useful? React with 👍 / 👎.
| if list(frame(story, "fare_bands").Fare_band) != FARE_BANDS or list( | ||
| frame(story, "quality").Population | ||
| ) != list(QUALITY_LABELS.values()): | ||
| raise ValueError("Incomplete fare or coverage table.") |
There was a problem hiding this comment.
Validate coverage counts against the retained population
When the named quality rows contain individually valid but contradictory counts, this check accepts them because it verifies only their labels. The app can then state that a source with 100 records retained 300 trips, or that the fare guardrail excluded more records than were otherwise eligible, while displaying those incompatible values in the coverage table. Validate the funnel rows and require the eligible count minus the tail exclusion to agree with the quarterly retained-trip total before publishing this narrative.
Useful? React with 👍 / 👎.
| if height > 16000: | ||
| raise ValueError( | ||
| "Dashboard view is too tall to review completely; split it into sections." | ||
| ) |
There was a problem hiding this comment.
Allow valid long dashboards to reach the revision loop
When an unplanned but contract-valid report contains the allowed twelve 40-row bar charts, their declared 1,200-pixel heights alone consume 14,400 pixels, and the headings, metrics, and page chrome can push the initial Story view past this 16,000-pixel cutoff. Capture then aborts before the first review, so the writer never gets an opportunity to split the charts into the sections that this error requests. Capture the complete baseline in bounded viewport segments, or otherwise create a splittable initial plan before enforcing the per-page height limit.
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 377c68cdbf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if dashboard_reviewer is not None: | ||
| from backintel.presentation.review import review_dashboard_async | ||
|
|
||
| record["dashboard_review"] = await review_dashboard_async( |
There was a problem hiding this comment.
Keep optional review failures from failing completed analysis
When --review-dashboard is requested for a valid table-only report, review_dashboard_async() raises before its internal error-recording block because the dashboard has no charts. This unguarded call then reaches the outer exception handler and changes the entire run to failed, even though the analysis and dashboard export completed successfully; record the review as unavailable/error without invalidating analytical completion.
AGENTS.md reference: AGENTS.md:L36-L41
Useful? React with 👍 / 👎.
| monthly = frame(story, "monthly") | ||
| if list(monthly.Month) != list(MONTHS) or (monthly.Trips_per_day <= 0).any(): | ||
| raise ValueError("This story requires the complete January–March 2025 monthly view.") | ||
| if monthly.Trips.sum() <= 0 or monthly.Gross_fare_USD.sum() <= 0: | ||
| raise ValueError("Quarterly trip and fare totals must be positive.") |
There was a problem hiding this comment.
Reconcile monthly rates with retained totals
When a monthly row has positive but inconsistent derived values, this validation accepts it—for example, 3,100 trips with Trips_per_day=1, or $31,000 in fares over 3,100 trips with Mean_fare_USD=50. The dashboard then displays those derived values alongside conflicting quarterly totals and explicitly describes them as calendar-day rates and average fares; validate both fields against the retained trip/fare totals and the known month lengths within the report's rounding tolerance.
Useful? React with 👍 / 👎.
| if list(frame(story, "fare_bands").Fare_band) != FARE_BANDS or list( | ||
| frame(story, "quality").Population | ||
| ) != list(QUALITY_LABELS.values()): | ||
| raise ValueError("Incomplete fare or coverage table.") |
There was a problem hiding this comment.
Reject fare-band shares that do not form a distribution
When the five required fare bands contain individually bounded shares whose total is not approximately 100%, this check still accepts the story. The Explore view then presents them as an exhaustive share of eligible quarterly trips and can make claims from a distribution totaling, for example, 250%; require the retained band shares to sum to 100% within an appropriate rounding tolerance.
Useful? React with 👍 / 👎.
| for magnitude, suffix in [(1e9, "bn"), (1e6, "m")]: | ||
| if abs(value) >= magnitude: | ||
| return f"{value / magnitude:,.2f}{suffix}" | ||
| return f"{value:,.2f}".rstrip("0").rstrip(".") if value % 1 else f"{value:,.0f}" |
There was a problem hiding this comment.
Preserve small nonzero metric values in KPI formatting
When a valid metric has a small nonzero value such as 0.001, formatting it to two decimal places and stripping trailing zeros renders the KPI as 0 in both generated dashboard variants, while the retained table and workbook still contain 0.001. This can materially misstate rates, ratios, or small currency measures; use significant-digit or magnitude-aware formatting so a nonzero metric is never displayed as zero.
Useful? React with 👍 / 👎.
|
The account paying for this security review has reached its Codex usage limits. The payer can check the Codex usage dashboard. For personal accounts, using credits requires enabling “Use credits for security reviews” in Code review settings. If you do not manage the paying account, contact this repository's admins. |
Verified analysis reports now generate a local Streamlit dashboard and business workbook. Readers get a business brief, a guided chart narrative, table exploration, and supporting definitions instead of having to reconstruct the decision from exported artifacts.
Changes
dashboard generate,serve, andreview, plus opt-in automatic review throughanalyze --review-dashboard.Validation
Current limits
Serving remains local. Design review is opt-in and uses the configured native provider accounts; it can make up to three reviewer calls and two writer calls. Presentation revisions cannot invent calculations or arbitrary app code. Datasets, generated workbooks/screenshots, and raw review records remain outside Git.
See dashboard setup and evidence for commands, boundaries, and the retained taxi example.