Skip to content

[Epic #845][P1] Return-series spreadsheet export - #859

Merged
stranske merged 2 commits into
mainfrom
codex/issue-849-return-series-spreadsheet
Jul 26, 2026
Merged

[Epic #845][P1] Return-series spreadsheet export#859
stranske merged 2 commits into
mainfrom
codex/issue-849-return-series-spreadsheet

Conversation

@stranske

@stranske stranske commented Jul 26, 2026

Copy link
Copy Markdown
Owner

Source: Issue #849

Closes #849

Automated Status Summary

Scope

Scope section missing from source issue.

Context for Agent

Related Issues/PRs

Tasks

  • Add openpyxl to pyproject.toml dependencies (pure-Python, Pyodide-viable — verify no native/transitive
    binary enters the core import graph).
  • Implement an Exporter (X1 port) in src/inv_man_intake/export/spreadsheet.py that consumes
    ExtractedTable cells and the normalized performance/ series and writes .xlsx:
    sheet 1 = the return series (period, value, frequency) with a provenance column per row
    (source_doc:page:method); sheet 2 = manifest/lineage refs.
  • Provide a .csv variant of sheet 1 through the same exporter for the same data.
  • Route all numeric values through the existing finite/bounds validation ([P1] Add finite/bounds validation at performance-metrics, conflict-resolver, and threshold-config boundaries #695) so no NaN/inf can reach a cell;
    a series with no usable points produces a no_series_found manifest skip row rather than an empty workbook.

Acceptance criteria

  • Named test: tests/export/test_spreadsheet_export.py::test_return_series_roundtrips_with_provenance — export a

Summary by CodeRabbit

  • New Features
    • Added export of return performance series to CSV and Excel formats.
    • Excel exports include return data, provenance details, and lineage information.
    • Exports support monthly, quarterly, and annual series.
    • Missing series are recorded as skipped, while invalid numeric values are rejected.
  • Quality
    • Added coverage for spreadsheet contents, provenance, skipped exports, and invalid values.

@stranske stranske added agent:codex Assign to Codex agent agents:keepalive Enable keepalive monitoring on PR autofix Let bots format/lint automatically labels Jul 26, 2026
@cursor

cursor Bot commented Jul 26, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Keepalive Loop Reporter. Do not edit.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 38 minutes

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2d77e2a3-a584-42b1-9041-83e2dc7318b6

📥 Commits

Reviewing files that changed from the base of the PR and between f29a30c and ac21187.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (2)
  • src/inv_man_intake/export/spreadsheet.py
  • tests/export/test_spreadsheet_export.py
📝 Walkthrough

Walkthrough

Changes

Return Series Export

Layer / File(s) Summary
Export contract and package wiring
pyproject.toml, src/inv_man_intake/export/__init__.py, src/inv_man_intake/export/spreadsheet.py
Adds openpyxl, configures Black for Python 3.12, and exposes export_return_series from the export package.
Return-series artifact generation
src/inv_man_intake/export/spreadsheet.py
Normalizes performance payloads, validates finite point values, and produces CSV/XLSX artifacts with provenance and table-cell lineage.
Export behavior validation
tests/export/test_spreadsheet_export.py
Tests workbook sheets and values, CSV provenance, non-finite value rejection, and the no_series_found skip manifest.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant export_return_series
  participant normalize_payload
  participant _return_rows
  participant _build_csv
  participant _build_workbook
  Caller->>export_return_series: performance payload and provenance inputs
  export_return_series->>normalize_payload: normalize non-normalized payload
  export_return_series->>_return_rows: serialize return points
  _return_rows->>_build_csv: build CSV rows
  _return_rows->>_build_workbook: build XLSX rows and lineage
  _build_workbook-->>export_return_series: workbook bytes
  export_return_series-->>Caller: ExportManifest
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR implements the requested XLSX/CSV return-series exporter with provenance, manifest, finite-value checks, and no-series skips.
Out of Scope Changes check ✅ Passed No unrelated code changes stand out; the edits stay focused on export support, dependency setup, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding return-series spreadsheet export functionality.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-849-return-series-spreadsheet

Comment @coderabbitai help to get the list of available commands.

@agents-workflows-bot

agents-workflows-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

🤖 Keepalive Loop Status

PR #859 | Agent: Codex | Iteration 0/12

Current State

Metric Value
Iteration progress [----------] 0/12
Action run (agent-run-skipped)
Gate success
Tasks 0/5 complete
Timeout 45 min (default)
Timeout usage 3m elapsed (7%, 42m remaining)
Keepalive ✅ enabled
Autofix ❌ disabled

Last Codex Run

Result Value
Status ⏭️ Skipped
Reason agent-run-skipped

To retry:

  • Add the agent:retry label, OR
  • Wait for conditions to resolve (e.g., Gate success, labels present)

🔍 Failure Classification

| Error type | infrastructure |
| Error category | transient |
| Suggested recovery | Capture logs and context; retry once and escalate if the issue persists. |

@agents-workflows-bot

agents-workflows-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor
Keepalive Work Log (click to expand)
# Time (UTC) Agent Action Result Files Tasks Progress Commit Gate
0 2026-07-26 09:08:08 Codex wait (gate-cancelled-transient-transient) skipped 0 0/8 cancelled
0 2026-07-26 09:09:31 Codex run (agent-run-cancelled) cancelled 0 0/8 cancelled
0 2026-07-26 09:13:17 Codex run (agent-run-failed) failure 5 file(s) 0 0/8 cancelled
0 2026-07-26 09:14:02 Codex skip (needs-human) skipped 0 0/8 success
0 2026-07-26 09:33:44 Codex run (agent-run-failed) failure 5 file(s) +3 0/5 success
0 2026-07-26 09:52:30 Codex run (agent-run-failed-repeat) failure 5 file(s) 0 0/5 success
0 2026-07-26 09:53:13 Codex skip (needs-human) skipped 0 0/5
0 2026-07-26 09:53:56 Codex skip (needs-human) skipped 0 0/5 cancelled
0 2026-07-26 09:56:00 Codex skip (needs-human) skipped 0 0/5 success
0 2026-07-26 10:02:45 Codex wait (gate-pending-transient) skipped 0 0/5
0 2026-07-26 10:05:09 Codex run (agent-run-skipped) skipped 0 0/5 success
0 2026-07-26 10:07:03 Codex run (agent-run-skipped) skipped 0 0/5 success
0 2026-07-26 10:26:36 Codex run (agent-run-skipped) skipped 0 0/5 success

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Gate Followups. Do not edit.

@stranske

Copy link
Copy Markdown
Owner Author

Autofix attempts exhausted for this head.
Attempts: 7 / 3

Latest Gate summary:

Gate run: https://github.com/stranske/Inv-Man-Intake/actions/runs/30195879426
Conclusion: cancelled
PR: #859
Head SHA: fe54474a84ec38e91021725a8b4058722bf62dbe
Autofix attempts for this head: 7 / 3
Fix scope: src/, tests/, tools/, scripts/, agents/, templates/, .github/
Failing jobs:
- classify changed paths (cancelled)

Please investigate manually.

@github-actions

github-actions Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Runner dispatch state for codex on PR #859. Do not edit.

@stranske
stranske force-pushed the codex/issue-849-return-series-spreadsheet branch from fe54474 to f29a30c Compare July 26, 2026 09:24
@stranske

Copy link
Copy Markdown
Owner Author

Closer recovery: rebased onto current main after #858 merged and force-pushed f29a30c. Validation in an isolated Python 3.12 dev environment: uv run --extra dev python -m pytest tests/export -o addopts= (28 passed), plus ruff check/format and focused mypy were clean. The initial bare-shell pytest failure was only missing local optional dev dependencies; it was not reproduced in the project environment. Post-push review is deferred to the next scheduled closer check; current head is awaiting new Gate/CodeRabbit signals.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/inv_man_intake/export/spreadsheet.py`:
- Around line 48-51: Add a test for the empty concrete-payload path in the
spreadsheet export flow, using an empty PerformanceSeries rather than
performance=None. Assert that the result is an ExportManifest containing an
ExportItem with item_ref="return-series" and skip_reason="no_series_found",
matching the existing empty-row behavior.
- Around line 112-140: Escape formula-leading string values before writing them
in _build_csv and _build_workbook, including provenance fields in return rows
and manifest references from provenance_refs and _table_lineage(tables). Apply
one shared sanitizer for values beginning with “=”, “+”, “-”, or “@”, preserving
other values, and add a regression test covering malicious provenance in both
CSV and XLSX exports.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 073ae5d6-3c94-48a9-9643-dd291ddf6016

📥 Commits

Reviewing files that changed from the base of the PR and between ea2dad4 and f29a30c.

📒 Files selected for processing (4)
  • pyproject.toml
  • src/inv_man_intake/export/__init__.py
  • src/inv_man_intake/export/spreadsheet.py
  • tests/export/test_spreadsheet_export.py

Comment thread src/inv_man_intake/export/spreadsheet.py
Comment thread src/inv_man_intake/export/spreadsheet.py Outdated
Addresses CodeRabbit review on #859: sanitize string cells written to the
CSV and XLSX artifacts so extracted provenance cannot execute as a formula,
and cover the empty normalized-series skip path.
@stranske

Copy link
Copy Markdown
Owner Author

Closer addressed both CodeRabbit threads on head ac21187 (previous head f29a30c).

  1. Formula injection (Major, src/inv_man_intake/export/spreadsheet.py) — added _safe_cell/_safe_row and applied them at the cell-write boundary in both _build_csv and _build_workbook, covering return rows (provenance is built from source_doc_id), provenance_refs, and _table_lineage(tables) manifest references. Values beginning with =, +, -, or @ are prefixed with '; numeric cells are written as numbers and are never rewritten. Escaping happens at write time only, so ExportArtifact.provenance_refs metadata stays byte-faithful to the source.
  2. Empty concrete-payload skip path (Minor) — added test_empty_normalized_series_records_skip, which drives a NormalizedPerformancePayload whose monthly PerformanceSeries has no points. That is the reachable empty-rows branch: normalize_payload rejects an empty PerformancePayload.monthly via validate_payload, so an already-normalized payload is the only way _return_rows returns empty. It asserts the same ("return-series", "no_series_found") skip and no artifacts.
  3. Added test_formula_leading_provenance_is_escaped_in_both_artifacts as the malicious-provenance regression, asserting the escape in the parsed CSV, the XLSX Return Series provenance column, and the Manifest sheet references.

Validation on ac21187 (uv run --extra dev):

  • python -m pytest tests/export -o addopts= -> 30 passed (was 28 before these tests)
  • ruff check src/inv_man_intake/export tests/export -> All checks passed
  • ruff format --check -> clean
  • mypy src/inv_man_intake/export/spreadsheet.py -> Success, no issues

Both threads resolved. Next: Gate/CodeRabbit on the new head, then merge + verify:compare.

@stranske-automation-bot

Copy link
Copy Markdown
Collaborator

🤖 Bot Comment Handler

  • Agent: codex
  • Bot comments to address: 2

The agent has been assigned to this PR to address the bot review comments.

Instructions for agent

  1. Implement suggested fixes that improve the code
  2. Skip suggestions that don't apply (note why in your response)

The bot comment handler workflow has prepared context in the artifacts.

@agents-workflows-bot agents-workflows-bot Bot added agent:needs-attention Agent needs human review or intervention needs-human labels Jul 26, 2026
@stranske stranske added agent:retry Add to trigger agent retry after rate limit or pause and removed agent:needs-attention Agent needs human review or intervention needs-human labels Jul 26, 2026
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:02 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:02 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:02 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:02 — with GitHub Actions Inactive
@stranske
stranske merged commit c95590d into main Jul 26, 2026
147 of 150 checks passed
@stranske
stranske deleted the codex/issue-849-return-series-spreadsheet branch July 26, 2026 10:23
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:23 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:23 — with GitHub Actions Inactive
@stranske
stranske temporarily deployed to agent-standard July 26, 2026 10:23 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Verifier. Do not edit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:codex Assign to Codex agent agent:retry Add to trigger agent retry after rate limit or pause agents:keepalive Enable keepalive monitoring on PR autofix Let bots format/lint automatically verify:compare

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Epic #845][P1] Return-series spreadsheet export (openpyxl, provenance per row)

2 participants