Skip to content

Fix SEC decoding and financial fact grain - #2

Merged
rlancaster243 merged 15 commits into
mainfrom
agent/fix-public-release-corrections
Jul 27, 2026
Merged

Fix SEC decoding and financial fact grain#2
rlancaster243 merged 15 commits into
mainfrom
agent/fix-public-release-corrections

Conversation

@rlancaster243

@rlancaster243 rlancaster243 commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

  • decode gzip and deflate SEC Company Facts responses before JSON parsing
  • add live-client regression coverage for both supported encodings
  • include period_start_date in the financial fact grain and deterministic identifier
  • add synthetic fixture observations that share a filing and end date but have different start dates
  • add a dbt data test proving distinct reporting periods survive the mart transformation
  • add Ruff formatting checks to CI and local validation

Acceptance criteria

  • compressed SEC responses parse successfully
  • quarterly and year-to-date observations from the same filing remain separate facts
  • the former grain definition would fail the new dbt test
  • Ruff, formatting, mypy, pytest, fixture smoke test, dbt build, and Terraform validation pass

Scope

No cloud deployment, live SEC request, repository visibility change, or unrelated refactor is included.

Summary by CodeRabbit

  • Bug Fixes
    • Improved decoding of SEC API responses by correctly handling compressed HTTP bodies (gzip and deflate).
    • Updated financial fact deduplication/identifiers to preserve accurate period grain across quarter and year-to-date observations.
  • Tests
    • Added tests covering compressed response decoding.
    • Added a dbt test to verify period-grain preservation and updated pipeline expectations for distinct periods.
  • Chores
    • Added Ruff formatting checks to CI and local validation, including formatter-specific diagnostics on failures.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@rlancaster243, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 8dbb98ea-bf84-4d4d-91ce-4677fffde202

📥 Commits

Reviewing files that changed from the base of the PR and between 33a81b3 and d00e5c2.

📒 Files selected for processing (3)
  • dbt/tests/test_fct_financial_facts_preserves_period_grain.sql
  • tests/test_pipeline.py
  • tests/test_sec_client.py
📝 Walkthrough

Walkthrough

The PR preserves financial period grain in the mart, adds period-grain validation, enables gzip and deflate response decoding in the SEC client, adds compressed-response tests, and runs Ruff formatting checks in CI and local validation.

Changes

Financial period grain

Layer / File(s) Summary
Mart period identity
dbt/models/marts/fct_financial_facts.sql
Deduplication and financial_fact_id generation now include period_start_date, with null handling for instant facts.
Period grain validation
tests/fixtures/CIK0000320193.json, tests/test_pipeline.py, dbt/tests/test_fct_financial_facts_preserves_period_grain.sql
Fixtures and tests validate distinct financial periods, updated normalized counts, and matching source-to-mart period grain.

SEC response decoding

Layer / File(s) Summary
Response decompression
src/ledger/sec_client.py
SEC responses support identity, gzip, and deflate encodings before UTF-8 JSON decoding.
Compressed response tests
tests/test_sec_client.py
Parameterized tests verify gzip and deflate decoding with a fake HTTP response.

Format validation

Layer / File(s) Summary
Ruff format checks
.github/workflows/ci.yml, scripts/validate.sh, src/ledger/config.py
CI and local validation run Ruff formatting checks, with the configuration change matching the formatter’s expected layout.

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

Sequence Diagram(s)

sequenceDiagram
  participant SecCompanyFactsClient
  participant urlopen
  participant HTTPResponse
  participant _decompress_body
  participant _decode_payload
  SecCompanyFactsClient->>urlopen: request company facts
  urlopen-->>SecCompanyFactsClient: compressed response and Content-Encoding
  SecCompanyFactsClient->>HTTPResponse: read raw bytes
  SecCompanyFactsClient->>_decompress_body: decompress response bytes
  _decompress_body-->>SecCompanyFactsClient: return decompressed bytes
  SecCompanyFactsClient->>_decode_payload: decode UTF-8 JSON
  _decode_payload-->>SecCompanyFactsClient: return company facts payload
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the two main changes: SEC response decoding and financial fact grain updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/fix-public-release-corrections

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

@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.

🧹 Nitpick comments (3)
tests/test_pipeline.py (1)

20-21: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert period/value pairs rather than independent sets.

The current assertions pass if the two values become associated with the wrong start dates. Assert tuples to preserve the fixture’s quarterly-vs-YTD semantic contract.

Proposed test tightening
-    assert {row["period_start_date"] for row in rows} == {"2026-01-01", "2026-07-01"}
-    assert {row["value"] for row in rows} == {250000, 750000}
+    assert {
+        (row["period_start_date"], row["value"])
+        for row in rows
+    } == {
+        ("2026-01-01", 750000),
+        ("2026-07-01", 250000),
+    }
🤖 Prompt for 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.

In `@tests/test_pipeline.py` around lines 20 - 21, Update the assertions in the
test around the rows collection to compare paired (period_start_date, value)
tuples rather than independent sets. Verify the expected associations are
2026-01-01 with 250000 and 2026-07-01 with 750000, preserving the fixture’s
quarterly-versus-YTD contract.
dbt/tests/test_fct_financial_facts_preserves_period_grain.sql (1)

1-35: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Compare period identities, not only counts.

A mart with two incorrect start dates still passes when its distinct count matches the source. Compare the distinct keyed periods symmetrically so substitutions and unexpected extras fail the test.

Proposed test tightening
 with source_periods as (
-    select
+    select distinct
         cik,
         fact_namespace,
         fact_name,
         unit,
         accession_number,
         period_end_date,
-        count(
-            distinct coalesce(cast(period_start_date as varchar), '__instant__')
-        ) as period_count
+        coalesce(cast(period_start_date as varchar), '__instant__') as period_start_key
     from {{ ref('stg_financial_facts') }}
-    group by all
 ),
 
 mart_periods as (
-    select
+    select distinct
         cik,
         fact_namespace,
         fact_name,
         unit,
         accession_number,
         period_end_date,
-        count(
-            distinct coalesce(cast(period_start_date as varchar), '__instant__')
-        ) as period_count
+        coalesce(cast(period_start_date as varchar), '__instant__') as period_start_key
     from {{ ref('fct_financial_facts') }}
-    group by all
 )
 
-select source_periods.*
-from source_periods
-left join mart_periods
-    using (cik, fact_namespace, fact_name, unit, accession_number, period_end_date)
-where source_periods.period_count != coalesce(mart_periods.period_count, 0)
+(
+    select * from source_periods
+    except
+    select * from mart_periods
+)
+union all
+(
+    select * from mart_periods
+    except
+    select * from source_periods
+)
🤖 Prompt for 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.

In `@dbt/tests/test_fct_financial_facts_preserves_period_grain.sql` around lines 1
- 35, Update the test query to compare the actual distinct period identities
between stg_financial_facts and fct_financial_facts, using the existing grouping
keys plus period_start_date (with the instant-date sentinel). Perform a
symmetric comparison so missing source periods and unexpected mart periods both
produce failures, rather than comparing only period_count values.
tests/test_sec_client.py (1)

34-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover truncated-body retry behavior.

This only tests successful decompression. Add a regression case where the first compressed response is truncated and a subsequent response is valid, asserting urlopen is called twice.

🤖 Prompt for 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.

In `@tests/test_sec_client.py` around lines 34 - 60, Extend
test_live_client_decodes_compressed_responses with a retry regression case using
sequential fake responses: return a truncated compressed body first, then a
valid compressed payload, and assert fetch_companyfacts succeeds with urlopen
called twice. Preserve coverage for both gzip and deflate encodings and
configure retries to allow the second attempt.
🤖 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.

Nitpick comments:
In `@dbt/tests/test_fct_financial_facts_preserves_period_grain.sql`:
- Around line 1-35: Update the test query to compare the actual distinct period
identities between stg_financial_facts and fct_financial_facts, using the
existing grouping keys plus period_start_date (with the instant-date sentinel).
Perform a symmetric comparison so missing source periods and unexpected mart
periods both produce failures, rather than comparing only period_count values.

In `@tests/test_pipeline.py`:
- Around line 20-21: Update the assertions in the test around the rows
collection to compare paired (period_start_date, value) tuples rather than
independent sets. Verify the expected associations are 2026-01-01 with 250000
and 2026-07-01 with 750000, preserving the fixture’s quarterly-versus-YTD
contract.

In `@tests/test_sec_client.py`:
- Around line 34-60: Extend test_live_client_decodes_compressed_responses with a
retry regression case using sequential fake responses: return a truncated
compressed body first, then a valid compressed payload, and assert
fetch_companyfacts succeeds with urlopen called twice. Preserve coverage for
both gzip and deflate encodings and configure retries to allow the second
attempt.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 026ce211-08d6-4d5d-b2d4-f679a16aa7d9

📥 Commits

Reviewing files that changed from the base of the PR and between 28535f8 and bded1f9.

📒 Files selected for processing (8)
  • .github/workflows/ci.yml
  • dbt/models/marts/fct_financial_facts.sql
  • dbt/tests/test_fct_financial_facts_preserves_period_grain.sql
  • scripts/validate.sh
  • src/ledger/sec_client.py
  • tests/fixtures/CIK0000320193.json
  • tests/test_pipeline.py
  • tests/test_sec_client.py

@rlancaster243
rlancaster243 merged commit 320fd8b into main Jul 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant