Skip to content

fix(schedule13): OwnershipComparison uses total_shares' max; add aggregation_basis - #1400

Merged
dgunning merged 1 commit into
mainfrom
fix/schedule13-aggregate-basis
Oct 1, 2026
Merged

dgunning merged 1 commit into
mainfrom
fix/schedule13-aggregate-basis

Conversation

@dgunning

@dgunning dgunning commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Bead edgartools-qsk4. Decision recorded on the bead: use max plus an aggregation_basis flag, shipping in 5.x.

Problem

OwnershipComparison summed every reporting person's shares and percent, including rows flagged is_aggregate_exclude_shares. Meanwhile total_shares and total_percent take the max over the unflagged persons. In a control chain, where a fund, its GP and its manager each report the same position, the sum counts that position once per person. The Jushi 13G fixture's two 10,000,000-share rows compared as 20,000,000.

The "max() is always correct" docstrings were also false. In a sample of joint filings:

  • GAMCO / Nevro (0000807249-25-000053): sub-advisers hold separate accounts, so the max is 1,322,950 while Item 5(a) states 2,123,900 shares (5.54%).
  • ZIM group (0001178913-25-004165, 33 persons): matches neither the sum nor the max.

No structured field says which rows roll up into which.

Changes

  • Comparison: OwnershipComparison now uses the same max as total_shares. reported_* goes through models._reported_total; shares_change, percent_change and get_summary() use an unreported-as-0 max. The reported_* accessors are unreleased (fix(schedule13): no sale or purchase from ownership figures a filing leaves out #1379 came after 5.59.1). shares_change's numbers change in 5.x as a correctness fix; the changelog says so.

  • aggregation_basis on Schedule13D and Schedule13G:

    Value Meaning
    single one reporting person counts
    identical every person reports the same shares
    parent_sums_children the largest row equals the sum of the distinct smaller ones (Blackstone 0000950170-25-090888: 4,782,781 = 2,989,238 + 1,793,543)
    ambiguous anything else: the group total can exceed total_shares

    to_context() flags ambiguous totals.

  • Docs: the false docstrings are fixed. The guide's "Joint vs. Separate Filers" section described detection logic that was never implemented, and it's rewritten. The ownership skill gets a Schedule 13 pattern.

Distribution on 60 joint filings from 2025 Q3:

  • 13D: 15 identical, 13 ambiguous, 2 single.
  • 13G: 23 identical, 3 parent_sums_children, 4 ambiguous.

Reading the filer's own Item 5(a) total is bead edgartools-vazz.

Verification

  • Fast tests: each basis using the real filings' row values; the Aadi fixture (ambiguous, flagged in context); the Jushi fixture (identical).
  • Network tests: GAMCO (ambiguous, 1,322,950) and Blackstone (parent_sums_children, 4,782,781).
  • fix(schedule13): no sale or purchase from ownership figures a filing leaves out #1379's tests: they pinned the summed values, and are updated to the max (Aadi 4,535,000 → 2,435,000, Jushi 20,000,000 → 10,000,000).
  • test-fast: the only failure is the dt1f1 20-F test, which also fails on main.

🤖 Generated with Claude Code

…egation_basis (qsk4)

OwnershipComparison summed aggregate_amount / percent_of_class over every
reporting person, including rows flagged is_aggregate_exclude_shares, while
total_shares / total_percent and _reported_total take the max over the
unflagged persons: one rule, two implementations, disagreeing twice. In a
control chain (fund, GP, manager, individual each reporting the same
position) the sum counts one position once per person; the Jushi 13G
fixture's two 10,000,000-share rows compared as 20,000,000.

The comparison now goes through models._reported_total (reported_*) and
an unreported-as-0 max (shares_change, percent_change, get_summary). The
reported_* accessors are unreleased (#1379, after 5.59.1); shares_change's
numbers change in 5.x as a correctness fix.

The "max() is always correct" docstrings were false. Sampled joint
filings: most rows restate one position, but GAMCO/Nevro
(0000807249-25-000053) sub-advisers hold separate accounts, 1,322,950 by
max vs 2,123,900 stated in Item 5(a), and the 33-person ZIM group
(0001178913-25-004165) matches neither sum nor max. No structured field
says which rows roll up into which, so a new aggregation_basis reports the
shape: 'single', 'identical', 'parent_sums_children' (largest row = sum of
the distinct smaller ones; Blackstone 0000950170-25-090888 4,782,781 =
2,989,238 + 1,793,543) or 'ambiguous'. On 60 joint filings from 2025Q3:
13D 15 identical / 13 ambiguous / 2 single; 13G 23 identical / 3 parent /
4 ambiguous. to_context() flags ambiguous totals. The guide's "Joint vs.
Separate Filers" section described member_of_group / >100% / identical-
count detection that was never implemented; rewritten. The Item 5(a)
stated total is bead edgartools-vazz.

1379's tests pinned the summed values; updated to the max (Aadi 4,535,000
-> 2,435,000, Jushi 20,000,000 -> 10,000,000).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dgunning
dgunning enabled auto-merge (squash) October 1, 2026 23:00
@dgunning
dgunning merged commit fd7ac87 into main Oct 1, 2026
10 checks passed
@dgunning
dgunning deleted the fix/schedule13-aggregate-basis branch October 1, 2026 23:15
@dgunning dgunning mentioned this pull request Oct 2, 2026
dgunning added a commit that referenced this pull request Oct 20, 2026
…edgartools-u6tkw) (#1621)

* docs(upgrade): pre-rc review of the 6.0 migration guide

Every breaking PR since v5.62.0 (17) and every pending removed/changed
fragment (19) has a section; nothing was missing. Fixes from reading the
whole guide and running all 43 python blocks against main:

- The intro said 6.0 is still in development; it now says the page covers
  every change merged for 6.0.
- "Each of these warns in 5.x" was false for two removals that never
  warned (edgar.core.Result, the names outside edgar.__all__); the note now
  lists what warned and names the two that did not.
- "Still to come": public API enforcement shipped (#1611) and the source
  tree reorg was deferred to 6.x; both rows are gone. The Schedule 13D/G row
  stays until edgartools-u6tkw lands.
- The five `sed -i ''` rewrites were macOS-only; they are perl -pi -e now,
  tested on a sample file.
- The get_concept() lease example returned None for every company:
  get_concept takes synonym-group names, not raw tags. It uses get_fact()
  with a same-period check (Snowflake: 59.8M + 420.0M = 479.8M).
- Smaller accuracy fixes: the access modes did not move to edgar.settings,
  __all__ shipped in 5.47.0, the Apple blank-cell row is fiscal 2023, the
  Citigroup Item 1 count names its filing, the mda example's comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(schedule13)!: figures a filing does not report are None, not 0 (edgartools-u6tkw)

6.0 flip staged in 5.x by #1379/#1384/#1400. ReportingPerson's six
ownership figures hold None for an unreported figure (__post_init__ keeps
the fields and unreported_fields in step, so 5.x-style construction with a
placeholder 0 still works); total_voting_power/total_dispositive_power are
None when either half is; Schedule13D/G total_shares/total_percent use the
shared _reported_total rule (None for a counted person leaving the figure
out or no reporting-person rows; 0 when every person is excluded).
OwnershipComparison.shares_change/percent_change and get_summary() values
are None for unreported figures and no longer emit a FutureWarning;
reported_shares_change/reported_percent_change and ReportingPerson.reported()
stay as non-warning aliases.

Tests in test_issue_1379 that asserted the 5.x placeholder 0s and the
FutureWarning now assert None and no warning. New regression test pins
values from BML Investment Partners' 13D on Aadi Bioscience,
0001373604-24-000118.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(upgrade): Schedule 13D/G unreported figures section; Still to come becomes Not in 6.0 (edgartools-u6tkw)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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