# Graph Report - /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup (2026-04-22) ## Corpus Check - 57 files · ~13,245 words - Verdict: corpus is large enough that graph structure adds value. ## Summary - 354 nodes · 497 edges · 40 communities detected - Extraction: 73% EXTRACTED · 27% INFERRED · 0% AMBIGUOUS · INFERRED: 132 edges (avg confidence: 0.76) - Token cost: 0 input · 0 output ## Community Hubs (Navigation) - [[_COMMUNITY_Community 0|Community 0]] - [[_COMMUNITY_Community 1|Community 1]] - [[_COMMUNITY_Community 2|Community 2]] - [[_COMMUNITY_Community 3|Community 3]] - [[_COMMUNITY_Community 4|Community 4]] - [[_COMMUNITY_Community 5|Community 5]] - [[_COMMUNITY_Community 6|Community 6]] - [[_COMMUNITY_Community 7|Community 7]] - [[_COMMUNITY_Community 8|Community 8]] - [[_COMMUNITY_Community 9|Community 9]] - [[_COMMUNITY_Community 10|Community 10]] - [[_COMMUNITY_Community 11|Community 11]] - [[_COMMUNITY_Community 12|Community 12]] - [[_COMMUNITY_Community 13|Community 13]] - [[_COMMUNITY_Community 14|Community 14]] - [[_COMMUNITY_Community 15|Community 15]] - [[_COMMUNITY_Community 16|Community 16]] - [[_COMMUNITY_Community 17|Community 17]] - [[_COMMUNITY_Community 18|Community 18]] - [[_COMMUNITY_Community 19|Community 19]] - [[_COMMUNITY_Community 20|Community 20]] - [[_COMMUNITY_Community 21|Community 21]] - [[_COMMUNITY_Community 22|Community 22]] - [[_COMMUNITY_Community 23|Community 23]] - [[_COMMUNITY_Community 24|Community 24]] - [[_COMMUNITY_Community 25|Community 25]] - [[_COMMUNITY_Community 26|Community 26]] - [[_COMMUNITY_Community 27|Community 27]] - [[_COMMUNITY_Community 28|Community 28]] - [[_COMMUNITY_Community 29|Community 29]] - [[_COMMUNITY_Community 30|Community 30]] - [[_COMMUNITY_Community 31|Community 31]] - [[_COMMUNITY_Community 32|Community 32]] - [[_COMMUNITY_Community 33|Community 33]] - [[_COMMUNITY_Community 34|Community 34]] - [[_COMMUNITY_Community 35|Community 35]] - [[_COMMUNITY_Community 36|Community 36]] - [[_COMMUNITY_Community 37|Community 37]] - [[_COMMUNITY_Community 38|Community 38]] - [[_COMMUNITY_Community 39|Community 39]] ## God Nodes (most connected - your core abstractions) 1. `send_followup_email()` - 22 edges 2. `compute_aging()` - 21 edges 3. `FollowupLevelSpec` - 20 edges 4. `get_overdue_for_partner()` - 13 edges 5. `compute_followup_level()` - 12 edges 6. `generate_followup_text()` - 12 edges 7. `TestFusionFollowupEngine` - 11 edges 8. `select_tone()` - 11 edges 9. `TestFollowupController` - 10 edges 10. `TestLevelResolver` - 10 edges ## Surprising Connections (you probably didn't know these) - `test_buckets_sum_equals_total()` --calls--> `compute_aging()` [INFERRED] /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/tests/test_engine_property.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/services/overdue_aging.py - `test_overdue_amount_excludes_current()` --calls--> `compute_aging()` [INFERRED] /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/tests/test_engine_property.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/services/overdue_aging.py - `test_risk_score_in_range()` --calls--> `score_partner()` [INFERRED] /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/tests/test_engine_property.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/services/risk_scorer.py - `The follow-up engine — orchestrator for customer follow-ups. 7-method public AP` --uses--> `FollowupLevelSpec` [INFERRED] /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/models/fusion_followup_engine.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/services/level_resolver.py - `Cache lookup + LLM fallback.` --uses--> `FollowupLevelSpec` [INFERRED] /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/models/fusion_followup_engine.py → /Users/gurpreet/Github/Odoo-Modules/fusion_accounting_followup/services/level_resolver.py ## Communities ### Community 0 - "Community 0" Cohesion: 0.07 Nodes (22): FusionFollowupController, get_partner_detail(), list_overdue(), _parse_date(), pause(), HTTP controller: 6 JSON-RPC endpoints for the OWL follow-up dashboard. All endp, reset(), send_followup() (+14 more) ### Community 1 - "Community 1" Cohesion: 0.11 Nodes (13): _max_days_overdue(), Level resolver: which follow-up level should fire for this partner? Pure-Python, Pick the highest-sequence level whose delay_days has been crossed by the mos, Return the actual max days-overdue tracked on the report, falling back to th, resolve_level(), AgingBucket, AgingReport, compute_aging() (+5 more) ### Community 2 - "Community 2" Cohesion: 0.07 Nodes (14): Both new fields are declared on account.move.line., We can write the new fields onto an existing move line., Verify follow-up tracking fields are added to account.move.line., TestAccountMoveLineFollowup, Coexistence tests: fusion_accounting_followup menu only visible when Enterprise, TestFollowupCoexistence, Property-based invariants for follow-up services., test_buckets_sum_equals_total() (+6 more) ### Community 3 - "Community 3" Cohesion: 0.11 Nodes (14): generate_text(), FusionFollowupEngine, Force the next-higher level than the partner's current last_level., Pause follow-ups for a partner until a date (default 30 days)., Reset partner's follow-up state to no_action., Return audit history for a partner., Fetch posted, unreconciled receivable lines for a partner., Compute risk score from partner's payment history. (+6 more) ### Community 4 - "Community 4" Cohesion: 0.15 Nodes (2): FollowupDashboard, FollowupService ### Community 5 - "Community 5" Cohesion: 0.13 Nodes (10): generate_followup_text(), _get_provider(), AI-generated follow-up text with templated fallback., Look up provider for 'followup_text' feature., Generate follow-up text via LLM, with templated fallback. Returns: {subject, _templated_fallback(), build_prompt(), LLM prompt for AI-generated follow-up text. Output contract: { "subject": str (+2 more) ### Community 6 - "Community 6" Cohesion: 0.13 Nodes (7): HttpCase, Python wrappers for OWL tours via HttpCase.start_tour., TestFollowupTours, _percentile(), Performance benchmarks tagged 'benchmark'., TestControllerBenchmarks, TestEngineBenchmarks ### Community 7 - "Community 7" Cohesion: 0.21 Nodes (6): Cache lookup + LLM fallback., compute_fingerprint(), FusionFollowupTextCache, lookup(), Cache of AI-generated follow-up text to avoid LLM cost on repeats., TestFusionFollowupTextCache ### Community 8 - "Community 8" Cohesion: 0.19 Nodes (6): FusionMigrationWizard, Followup-specific migration step. Backfills fusion.followup.level from Enterpri, Backfill fusion.followup.level from account_followup.followup.line., Migration step: copy Enterprise account_followup per-partner state onto, Verify the partner-state migration step runs without error., TestFollowupMigrationRoundTrip ### Community 9 - "Community 9" Cohesion: 0.24 Nodes (5): PartnerRiskScore, Payment-history risk scorer. Pure-Python: takes payment history (list of paymen, Compute a 0-100 risk score from payment-history primitives. Heuristic weigh, score_partner(), TestRiskScorer ### Community 10 - "Community 10" Cohesion: 0.22 Nodes (5): test_tone_always_in_valid_set(), TestToneSelector, Tone selector: pick gentle/firm/legal based on follow-up level + risk score., Default tone follows level sequence; high risk can escalate., select_tone() ### Community 11 - "Community 11" Cohesion: 0.18 Nodes (3): FusionFollowupRun, Audit record of one follow-up execution (per partner per level)., TestFusionFollowupRun ### Community 12 - "Community 12" Cohesion: 0.2 Nodes (6): _cron_daily_scan(), _cron_risk_refresh(), FusionFollowupCron, Cron handlers for fusion_accounting_followup. Two scheduled jobs: - Daily scan:, Smoke tests for the fusion follow-up cron handlers., TestFollowupCron ### Community 13 - "Community 13" Cohesion: 0.29 Nodes (2): HttpCase tests for the 6 follow-up JSON-RPC endpoints., TestFollowupController ### Community 14 - "Community 14" Cohesion: 0.2 Nodes (3): Inherit res.partner: add follow-up state fields., ResPartner, TestResPartnerFollowup ### Community 15 - "Community 15" Cohesion: 0.22 Nodes (3): FusionBatchFollowupWizard, Batch send follow-ups to selected partners (or all overdue)., TestBatchFollowupWizard ### Community 16 - "Community 16" Cohesion: 0.25 Nodes (2): AI tool dispatch tests for fusion follow-up tools., TestFusionFollowupTools ### Community 17 - "Community 17" Cohesion: 0.25 Nodes (2): FollowupAdapter wiring tests — engine paths., TestFollowupAdapter ### Community 18 - "Community 18" Cohesion: 0.38 Nodes (4): _detect_local_llm(), Local LLM compat test for followup_text_generator. Auto-detects LM Studio (:123, _server_reachable(), TestLocalLLMFollowupText ### Community 19 - "Community 19" Cohesion: 0.67 Nodes (2): AccountMoveLine, Inherit account.move.line: track last follow-up level. ### Community 20 - "Community 20" Cohesion: 0.67 Nodes (2): FusionFollowupLevel, Follow-up level definition (e.g. Reminder at 7 days, Warning at 30, Legal at 60) ### Community 21 - "Community 21" Cohesion: 0.67 Nodes (1): FollowupHistoryTable ### Community 22 - "Community 22" Cohesion: 0.67 Nodes (1): AgingBucketStrip ### Community 23 - "Community 23" Cohesion: 1.0 Nodes (1): RiskBadge ### Community 24 - "Community 24" Cohesion: 1.0 Nodes (1): PartnerCard ### Community 25 - "Community 25" Cohesion: 1.0 Nodes (1): AiTextPanel ### Community 26 - "Community 26" Cohesion: 1.0 Nodes (0): ### Community 27 - "Community 27" Cohesion: 1.0 Nodes (0): ### Community 28 - "Community 28" Cohesion: 1.0 Nodes (0): ### Community 29 - "Community 29" Cohesion: 1.0 Nodes (0): ### Community 30 - "Community 30" Cohesion: 1.0 Nodes (0): ### Community 31 - "Community 31" Cohesion: 1.0 Nodes (0): ### Community 32 - "Community 32" Cohesion: 1.0 Nodes (0): ### Community 33 - "Community 33" Cohesion: 1.0 Nodes (1): Stable hash of the inputs that determine the generated text. ### Community 34 - "Community 34" Cohesion: 1.0 Nodes (1): Find a cached entry matching these inputs, or empty recordset. ### Community 35 - "Community 35" Cohesion: 1.0 Nodes (1): Scan every partner with overdue and send follow-ups when due. ### Community 36 - "Community 36" Cohesion: 1.0 Nodes (1): Refresh fusion_followup_risk_score on every partner with overdue. ### Community 37 - "Community 37" Cohesion: 1.0 Nodes (0): ### Community 38 - "Community 38" Cohesion: 1.0 Nodes (0): ### Community 39 - "Community 39" Cohesion: 1.0 Nodes (0): ## Knowledge Gaps - **58 isolated node(s):** `Property-based invariants for follow-up services.`, `AI tool dispatch tests for fusion follow-up tools.`, `Local LLM compat test for followup_text_generator. Auto-detects LM Studio (:123`, `Verify follow-up tracking fields are added to account.move.line.`, `Both new fields are declared on account.move.line.` (+53 more) These have ≤1 connection - possible missing edges or undocumented components. - **Thin community `Community 23`** (2 nodes): `RiskBadge`, `risk_badge.js` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 24`** (2 nodes): `PartnerCard`, `partner_card.js` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 25`** (2 nodes): `AiTextPanel`, `ai_text_panel.js` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 26`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 27`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 28`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 29`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 30`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 31`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 32`** (1 nodes): `__manifest__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 33`** (1 nodes): `Stable hash of the inputs that determine the generated text.` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 34`** (1 nodes): `Find a cached entry matching these inputs, or empty recordset.` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 35`** (1 nodes): `Scan every partner with overdue and send follow-ups when due.` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 36`** (1 nodes): `Refresh fusion_followup_risk_score on every partner with overdue.` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 37`** (1 nodes): `followup_tours.js` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 38`** (1 nodes): `followup_dashboard_view.js` Too small to be a meaningful cluster - may be noise or needs more connections extracted. - **Thin community `Community 39`** (1 nodes): `__init__.py` Too small to be a meaningful cluster - may be noise or needs more connections extracted. ## Suggested Questions _Questions this graph is uniquely positioned to answer:_ - **Why does `TestEngineBenchmarks` connect `Community 6` to `Community 2`?** _High betweenness centrality (0.099) - this node is a cross-community bridge._ - **Why does `send_followup_email()` connect `Community 0` to `Community 3`, `Community 6`, `Community 7`, `Community 10`, `Community 12`, `Community 15`?** _High betweenness centrality (0.089) - this node is a cross-community bridge._ - **Are the 14 inferred relationships involving `send_followup_email()` (e.g. with `.test_send_no_overdue_returns_no_action()` and `.test_send_followup_p95()`) actually correct?** _`send_followup_email()` has 14 INFERRED edges - model-reasoned connections that need verification._ - **Are the 16 inferred relationships involving `compute_aging()` (e.g. with `test_buckets_sum_equals_total()` and `test_overdue_amount_excludes_current()`) actually correct?** _`compute_aging()` has 16 INFERRED edges - model-reasoned connections that need verification._ - **Are the 18 inferred relationships involving `FollowupLevelSpec` (e.g. with `TestLevelResolver` and `FusionFollowupEngine`) actually correct?** _`FollowupLevelSpec` has 18 INFERRED edges - model-reasoned connections that need verification._ - **Are the 9 inferred relationships involving `get_overdue_for_partner()` (e.g. with `.test_get_overdue_returns_dict()` and `.test_get_overdue_p95()`) actually correct?** _`get_overdue_for_partner()` has 9 INFERRED edges - model-reasoned connections that need verification._ - **What connects `Property-based invariants for follow-up services.`, `AI tool dispatch tests for fusion follow-up tools.`, `Local LLM compat test for followup_text_generator. Auto-detects LM Studio (:123` to the rest of the system?** _58 weakly-connected nodes found - possible documentation gaps or missing edges._