Skip to content

feat(taxonomy): fac bridge coverage + CF/recurrence trait axes#731

Merged
jfrench9 merged 5 commits into
mainfrom
chore/taxonomy-mvp-review-fixes
Jun 6, 2026
Merged

feat(taxonomy): fac bridge coverage + CF/recurrence trait axes#731
jfrench9 merged 5 commits into
mainfrom
chore/taxonomy-mvp-review-fixes

Conversation

@jfrench9
Copy link
Copy Markdown
Member

@jfrench9 jfrench9 commented Jun 6, 2026

Summary

Completes a set of pre-launch fixes from a taxonomy framework review, done in the pre-tenant window where the seeded library is still freely rebuildable. It hardens fac-trait coverage on the tenant-shipped rs-gaap working set, adds a new analytical trait axis, and completes fac as a cross-framework anchor over the MVP working set. All changes are either tenant-additive (recoverable via resync) or library-only.

Changes

Trait consistency — rs-gaap-traits

  • Bind indirectCashFlowReconcilingItem to the 13 kept IncreaseDecreaseIn* working-capital concepts (consistency with their excluded siblings; classification-only — verified it is not consumed by the renderer, so no behavior change).
  • Bind use/remeasurement to the 3 kept impairment-bearing concepts (matches the existing impairment pattern, e.g. TangibleAssetImpairmentCharges).

New recurrence trait axis — fac-traits + model + migration

  • Add a fac-traits axis recurrence/nonrecurring (single-value flag) for normalized-earnings / NOPAT classification, bound to the 9 kept operating special-items (restructuring x4, impairment, disposal gains/losses x3, debt extinguishment). Orthogonal to use/remeasurement so both "NOPAT ex-remeasurements" and "NOPAT ex-all-special-items" cuts are expressible.
  • Widen check_trait_category in robosystems/models/extensions/trait.py and in migrations/extensions/versions/0002_taxonomy_library.py. 0002 both creates the constraint and runs the content-driven seed that inserts the member, so the widen lives there; consolidated into 0002 rather than a separate migration since no DB has run it yet pre-launch.

fac->rs-gaap bridge — fac-to-rs-gaap

  • Add 96 owl:equivalentClass arcs so every concrete tenant-kept rs-gaap concept reaches a fac anchor (137/137, was 41/137), making fac a complete cross-framework substrate over the MVP working set. Most arcs were derived from each concept's nearest fac-anchored calc ancestor; the rest assigned by EFS/liquidity/CF-section. Library-only (the bridge is tenant_copy:false); the kept set and tenant-exclude/v1.json artifact are unchanged (verified by recomputing keep_critical).

Test fix — tests/taxonomy/test_framework_bridge_seed.py

  • Update a stale resolve_pin assertion. The fac package became tenant_copy:false in the earlier tenant-copy curation, so it is omitted from the resolved copy-pin; assert on fac-traits (a copied depends_on package) instead. This file skips when the extensions DB is absent, so the staleness was hidden in CI — surfaced here only because the change set was verified against a live seeded library.

Testing

  • Library reseed verified (just reset-local -> recovered via just migrate-up extensions): migration chain applies cleanly; recurrence trait seeds (26 categories / 100 members); 137/137 concrete kept concepts reach a fac anchor (0 without); tenant-exclude artifact still in exact sync (2012/2012, zero diff); coherence scan all four checks OK; all 3 reporting styles render non-empty BS/IS/CF/SE.
  • Seeded-library integration tests (run locally with the extensions DB seeded): test_suggest_liquidity_narrowing.py + test_framework_bridge_seed.py -> 13 passed.
  • Code quality: ruff check, ruff format --check, basedpyright on changed Python -> clean (0 errors); pre-commit hooks passed on every commit.
  • just test-all (full unit suite): not run this session.

Notes / Follow-ups

  • Migration consolidated into 0002 pre-launch (no prod DB has run it). Once 0002 runs in prod it is frozen, so any later trait-axis addition (e.g. an explicit recurrence/recurring value, or a specialItem axis) will need its own migration.
  • Prod rollout: the first extensions migration run seeds everything (recurrence axis + bindings + the 96 bridge arcs) via the full chain — no special migration step. The bridge is library-only, so tenant schemas never receive it.
  • Deferred by choice (from the review): ASC references for ~8 native concepts (additive-recoverable at filing/audit time); a CI lane that seeds the extensions library so the seeded-library integration tests run in CI (the stale resolve_pin test fixed here is the concrete consequence of that gap); a deep content audit of disclosure-mechanics / reporting-checklist / rollup-rules / disclosures-to-textblocks.
  • A design-doc refresh (local/docs/ref/taxonomy.md, gitignored) was made locally to match (fac = 4 packages, 26 trait categories); not part of this diff.

jfrench9 added 4 commits June 6, 2026 12:30
- bind indirectCashFlowReconcilingItem to the 13 kept IncreaseDecreaseIn*
  working-capital concepts (consistency with their excluded siblings;
  classification-only, not consumed by the renderer)
- bind use/remeasurement to the 3 kept impairment-bearing concepts
- add a new fac-traits 'recurrence' axis (member nonrecurring) for
  normalized-earnings / NOPAT classification, bound to the 9 kept operating
  special-items (restructuring, impairment, disposal G/L, debt extinguishment);
  orthogonal to use/remeasurement
- widen check_trait_category: model + migration 0019 (public + tenant schemas
  via for_each_tenant_schema) and 0002 so a fresh seed admits recurrence
Add 96 fac->rs-gaap equivalence arcs so every concrete tenant-kept rs-gaap
concept reaches a fac anchor (41/137 -> 137/137), making fac a complete
cross-framework substrate over the MVP working set. Library-only (the bridge
is tenant_copy:false); kept set + tenant-exclude artifact unchanged (verified).
… test

The 'fac' package became tenant_copy:false in the tenant-copy curation, so it is
omitted from the resolved copy-pin; assert on fac-traits (a copied depends_on
package) instead. The file skips when the extensions DB is absent, so the
staleness was hidden in CI.
…on 0019)

Pre-launch, no DB has run the 0002 seed yet, so the separate 0019 widen is
redundant: 0002 already creates check_trait_category with 'recurrence' and its
content-driven seed inserts the member. Folding it in avoids shipping a no-op
migration at launch. Once 0002 runs in prod it is frozen, so any later trait-axis
addition will need its own migration.
@jfrench9
Copy link
Copy Markdown
Member Author

jfrench9 commented Jun 6, 2026

@claude can you review

@claude
Copy link
Copy Markdown

claude Bot commented Jun 6, 2026

Claude finished @jfrench9's task in 2m 52s —— View job


PR Review: feat(taxonomy): fac bridge coverage + CF/recurrence trait axes

  • Read changed files and git diff
  • Review migration changes (0002_taxonomy_library.py)
  • Review model changes (trait.py)
  • Review taxonomy JSONLD files (fac-traits, rs-gaap-traits, fac-to-rs-gaap bridge)
  • Review test changes
  • Synthesize and post final review

Overall Assessment

Solid pre-launch cleanup. The changes are internally consistent, the migration consolidation into 0002 is the right call given no prod DB has run it, and the content is methodically verified per the PR description. A few stale docstring counts and one potentially confusing forward reference to a dropped migration are the main things worth fixing.


Issues

1. Stale category/member counts in docstrings (4 locations)

The recurrence axis bumps the totals from 25 categories / 99 members → 26 / 100, but four places in the changed files weren't updated:

File Line Stale text
robosystems/models/extensions/trait.py 8 "The 25 categories cover the 24 orthogonal FASB metamodel trait axes plus"
migrations/extensions/versions/0002_taxonomy_library.py 37 "fac-traits (trait vocabulary, 99 traits across 25 categories;"
migrations/extensions/versions/0002_taxonomy_library.py 672 "# traits: FASB metamodel vocabulary (25 element-side categories)."
migrations/extensions/versions/0002_taxonomy_library.py 1115 "# traits: FASB metamodel vocabulary (25 element-side categories)."

Note that the migration's schema header at line 20–21 was updated correctly — only the docstring and inline comments are stale.

Fix stale counts →%20robosystems%2Fmodels%2Fextensions%2Ftrait.py%20line%208%3A%20change%20%2225%20categories%22%20to%20%2226%20categories%22%20and%20update%20the%20description%20to%20include%20the%20recurrence%20axis.%202)%20migrations%2Fextensions%2Fversions%2F0002_taxonomy_library.py%20line%2037%3A%20change%20%2299%20traits%20across%2025%20categories%22%20to%20%22100%20traits%20across%2026%20categories%22.%203)%20Same%20file%20lines%20672%20and%201115%3A%20change%20%2225%20element-side%20categories%22%20to%20%2226%20element-side%20categories%22.&repo=RoboFinSystems/robosystems)


2. Forward reference to dropped migration 0019

migrations/extensions/versions/0002_taxonomy_library.py:283:

# created here must already admit it on a fresh DB; migration 0019 applies
# the same widen to DBs that ran an earlier version of this constraint.

Migration 0019 was dropped in the preceding commit (31a8f2c). Post-merge, this comment will leave a reader searching for a migration that doesn't exist. Since the PR rationale is that no prod DB has run 0002 yet (so 0019 was unnecessary), the cleaner wording is something like:

"…created here must already admit it on a fresh DB. No in-the-wild DB had run an earlier version of 0002 at the time this change was made, so no separate migration to widen existing deployments was needed."

Fix 0019 reference →


Minor Observations

3. AccumulatedDepreciationDepletionAndAmortizationPropertyPlantAndEquipmentfac:NoncurrentAssets

This contra-asset (credit normal balance) is mapped to fac:NoncurrentAssets alongside gross PP&E and positive asset concepts in fac-to-rs-gaap. The placement is correct from a BS-section perspective (it appears in the noncurrent assets section), but the credit balance distinguishes it from the other equivalents in that block. No action required — just flagging in case a future content audit wants a use/contra or similar marker here.

4. Test test_legacy_flat_dict_returned_asis still includes "fac": "v1"

The existing test at tests/taxonomy/test_framework_bridge_seed.py:169 passes a flat dict containing "fac": "v1". Given that fac is now tenant_copy:false, a consumer using a legacy flat dict this way won't trigger expansion — but since the test is asserting "returned as-is" this is intentional and correct. No issue.


What Looks Good

  • CHECK constraint consistency: _TRAIT_CATEGORY_CHECK is defined once and correctly referenced in op.create_table (public schema), _create_tenant_library_tables (per-tenant schema), and trait.py (ORM model). The widen is atomic and complete.
  • Trait binding counts: 13 IncreaseDecreaseIn* concepts receive indirectCashFlowReconcilingItem; 9 special-items get recurrence/nonrecurring; 3 impairment-bearing concepts get use/remeasurement. All counts match PR description.
  • Bridge arc completeness: The 96 new owl:equivalentClass arcs across CF sections (operating/investing/financing), BS sections (current/noncurrent assets/liabilities), equity components, and operating expenses are semantically sound. CF section placements for the IncreaseDecreaseIn* set under NetCashProvidedByUsedInOperatingActivities are correct.
  • RestructuringCosts (no use/remeasurement) vs RestructuringCostsAndAssetImpairmentCharges / RestructuringSettlementAndImpairmentProvisions (both): The distinction is correct — pure restructuring charges are not remeasurements; the combo concepts carry impairment components that are.
  • Test fix: The resolve_pin assertion update from pin["fac"] to pin["fac-traits"] correctly reflects fac becoming tenant_copy:false.
  • Downgrade path: The downgrade() function in 0002 doesn't need to address the recurrence axis specifically since the traits table is fully dropped and recreated on downgrade.

Address PR #731 review nits (all doc/comment-only):
- bump 25 categories / 99 members -> 26 / 100 in trait.py docstring and
  0002 docstring + the two trait-table comments (recurrence axis was added
  but these counts weren't updated)
- rewrite the check_trait_category comment that referenced migration 0019
  (dropped when the widen was consolidated into 0002) to explain no separate
  widen migration was needed
@jfrench9 jfrench9 merged commit d3fd502 into main Jun 6, 2026
7 checks passed
@jfrench9 jfrench9 deleted the chore/taxonomy-mvp-review-fixes branch June 6, 2026 18:20
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