{"$schema":"https://json.schemastore.org/sarif-2.1.0.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"codehealth","informationUri":"https://codehealth.canine.dev","rules":[{"id":"D1","name":"Cyclomatic Complexity","shortDescription":{"text":"Cyclomatic Complexity"},"helpUri":"https://codehealth.canine.dev/dimensions/D1"},{"id":"D2","name":"Cognitive Complexity","shortDescription":{"text":"Cognitive Complexity"},"helpUri":"https://codehealth.canine.dev/dimensions/D2"},{"id":"D3","name":"God Classes","shortDescription":{"text":"God Classes"},"helpUri":"https://codehealth.canine.dev/dimensions/D3"},{"id":"D4","name":"Code Duplication","shortDescription":{"text":"Code Duplication"},"helpUri":"https://codehealth.canine.dev/dimensions/D4"},{"id":"D7","name":"Architectural Integrity","shortDescription":{"text":"Architectural Integrity"},"helpUri":"https://codehealth.canine.dev/dimensions/D7"},{"id":"D9","name":"Test Distribution","shortDescription":{"text":"Test Distribution"},"helpUri":"https://codehealth.canine.dev/dimensions/D9"},{"id":"D12","name":"Dependency Hygiene","shortDescription":{"text":"Dependency Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/D12"},{"id":"D13","name":"Secret Scanning","shortDescription":{"text":"Secret Scanning"},"helpUri":"https://codehealth.canine.dev/dimensions/D13","relationships":[{"target":{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"]}},{"id":"D14","name":"License Compliance","shortDescription":{"text":"License Compliance"},"helpUri":"https://codehealth.canine.dev/dimensions/D14"},{"id":"D15","name":"Churn \u00D7 Complexity Hotspots","shortDescription":{"text":"Churn \u00D7 Complexity Hotspots"},"helpUri":"https://codehealth.canine.dev/dimensions/D15"},{"id":"D17","name":"Explicit Debt","shortDescription":{"text":"Explicit Debt"},"helpUri":"https://codehealth.canine.dev/dimensions/D17"},{"id":"D19","name":"Documentation Quality","shortDescription":{"text":"Documentation Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D19"},{"id":"D20","name":"ADR Quality","shortDescription":{"text":"ADR Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D20"},{"id":"D21","name":"Naming Consistency","shortDescription":{"text":"Naming Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D21"},{"id":"D22","name":"Internal API Consistency","shortDescription":{"text":"Internal API Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D22"},{"id":"D25","name":"ADR Conformance","shortDescription":{"text":"ADR Conformance"},"helpUri":"https://codehealth.canine.dev/dimensions/D25"},{"id":"D28","name":"Secrets (history)","shortDescription":{"text":"Secrets (history)"},"helpUri":"https://codehealth.canine.dev/dimensions/D28","relationships":[{"target":{"id":"CWE-798","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-259","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"]}},{"id":"D29","name":"Static Analysis (SAST)","shortDescription":{"text":"Static Analysis (SAST)"},"helpUri":"https://codehealth.canine.dev/dimensions/D29","relationships":[{"target":{"id":"CWE-79","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-89","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-78","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-94","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-77","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-79","CWE-89","CWE-78","CWE-94","CWE-77"]}},{"id":"D30","name":"Dependency Vulnerabilities","shortDescription":{"text":"Dependency Vulnerabilities"},"helpUri":"https://codehealth.canine.dev/dimensions/D30","relationships":[{"target":{"id":"CWE-1395","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-937","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1395","CWE-937"]}},{"id":"D31","name":"IaC \u0026 Container Security","shortDescription":{"text":"IaC \u0026 Container Security"},"helpUri":"https://codehealth.canine.dev/dimensions/D31","relationships":[{"target":{"id":"CWE-1032","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-732","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-16","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1032","CWE-732","CWE-16"]}},{"id":"D32","name":"Data Compliance (PII/GDPR)","shortDescription":{"text":"Data Compliance (PII/GDPR)"},"helpUri":"https://codehealth.canine.dev/dimensions/D32","relationships":[{"target":{"id":"CWE-359","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-312","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-200","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-359","CWE-312","CWE-200"]}},{"id":"D34","name":"Knowledge Freshness","shortDescription":{"text":"Knowledge Freshness"},"helpUri":"https://codehealth.canine.dev/dimensions/D34"},{"id":"D35","name":"Change Coupling","shortDescription":{"text":"Change Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D35"},{"id":"D36","name":"Supply-chain Provenance \u0026 Signing","shortDescription":{"text":"Supply-chain Provenance \u0026 Signing"},"helpUri":"https://codehealth.canine.dev/dimensions/D36","relationships":[{"target":{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]},{"target":{"id":"CWE-494","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1357","CWE-494"]}},{"id":"D37","name":"Vulnerability-disclosure Policy","shortDescription":{"text":"Vulnerability-disclosure Policy"},"helpUri":"https://codehealth.canine.dev/dimensions/D37","relationships":[{"target":{"id":"CWE-1059","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-1059"]}},{"id":"D43","name":"Malicious Dependencies","shortDescription":{"text":"Malicious Dependencies"},"helpUri":"https://codehealth.canine.dev/dimensions/D43","relationships":[{"target":{"id":"CWE-506","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-506"]}},{"id":"D44","name":"Platform End-of-Life","shortDescription":{"text":"Platform End-of-Life"},"helpUri":"https://codehealth.canine.dev/dimensions/D44"},{"id":"AC2","name":"Forms \u0026 labels","shortDescription":{"text":"Forms \u0026 labels"},"helpUri":"https://codehealth.canine.dev/dimensions/AC2"},{"id":"AC3","name":"Page structure","shortDescription":{"text":"Page structure"},"helpUri":"https://codehealth.canine.dev/dimensions/AC3"},{"id":"AC5","name":"ARIA correctness","shortDescription":{"text":"ARIA correctness"},"helpUri":"https://codehealth.canine.dev/dimensions/AC5"},{"id":"AC6","name":"Visual \u0026 motion safety","shortDescription":{"text":"Visual \u0026 motion safety"},"helpUri":"https://codehealth.canine.dev/dimensions/AC6"},{"id":"AC7","name":"A11y enforcement","shortDescription":{"text":"A11y enforcement"},"helpUri":"https://codehealth.canine.dev/dimensions/AC7"},{"id":"AX10","name":"Code composition","shortDescription":{"text":"Code composition"},"helpUri":"https://codehealth.canine.dev/dimensions/AX10"},{"id":"AX5","name":"Architecture \u0026 structure","shortDescription":{"text":"Architecture \u0026 structure"},"helpUri":"https://codehealth.canine.dev/dimensions/AX5"},{"id":"AXB2","name":"Runtime readiness","shortDescription":{"text":"Runtime readiness"},"helpUri":"https://codehealth.canine.dev/dimensions/AXB2"},{"id":"DM1","name":"Aggregate boundaries","shortDescription":{"text":"Aggregate boundaries"},"helpUri":"https://codehealth.canine.dev/dimensions/DM1"},{"id":"DM11","name":"Constructible invalid state","shortDescription":{"text":"Constructible invalid state"},"helpUri":"https://codehealth.canine.dev/dimensions/DM11"},{"id":"DM12","name":"Ambient inputs in the domain","shortDescription":{"text":"Ambient inputs in the domain"},"helpUri":"https://codehealth.canine.dev/dimensions/DM12"},{"id":"DM4","name":"Rich vs anemic model","shortDescription":{"text":"Rich vs anemic model"},"helpUri":"https://codehealth.canine.dev/dimensions/DM4"},{"id":"DM5","name":"Encapsulated state","shortDescription":{"text":"Encapsulated state"},"helpUri":"https://codehealth.canine.dev/dimensions/DM5"},{"id":"DM6","name":"Domain \u2194 infrastructure boundary","shortDescription":{"text":"Domain \u2194 infrastructure boundary"},"helpUri":"https://codehealth.canine.dev/dimensions/DM6"},{"id":"DM8","name":"Value-object opportunities","shortDescription":{"text":"Value-object opportunities"},"helpUri":"https://codehealth.canine.dev/dimensions/DM8"},{"id":"M1","name":"Documentation (README)","shortDescription":{"text":"Documentation (README)"},"helpUri":"https://codehealth.canine.dev/dimensions/M1"},{"id":"M2","name":"Architecture documentation","shortDescription":{"text":"Architecture documentation"},"helpUri":"https://codehealth.canine.dev/dimensions/M2"},{"id":"M3","name":"Folder \u0026 project structure","shortDescription":{"text":"Folder \u0026 project structure"},"helpUri":"https://codehealth.canine.dev/dimensions/M3"},{"id":"M4","name":"Documentation accuracy","shortDescription":{"text":"Documentation accuracy"},"helpUri":"https://codehealth.canine.dev/dimensions/M4"},{"id":"P1","name":"CI/CD gates","shortDescription":{"text":"CI/CD gates"},"helpUri":"https://codehealth.canine.dev/dimensions/P1"},{"id":"P12","name":"CI test-gate honesty","shortDescription":{"text":"CI test-gate honesty"},"helpUri":"https://codehealth.canine.dev/dimensions/P12"},{"id":"P3","name":"Security \u0026 performance tooling","shortDescription":{"text":"Security \u0026 performance tooling"},"helpUri":"https://codehealth.canine.dev/dimensions/P3"},{"id":"P4","name":"Deployment \u0026 Rollback","shortDescription":{"text":"Deployment \u0026 Rollback"},"helpUri":"https://codehealth.canine.dev/dimensions/P4"},{"id":"P5","name":"DR \u0026 Backup","shortDescription":{"text":"DR \u0026 Backup"},"helpUri":"https://codehealth.canine.dev/dimensions/P5"},{"id":"P6","name":"Release Hygiene","shortDescription":{"text":"Release Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/P6"},{"id":"R1","name":"Type Safety","shortDescription":{"text":"Type Safety"},"helpUri":"https://codehealth.canine.dev/dimensions/R1"},{"id":"R10","name":"Code Duplication","shortDescription":{"text":"Code Duplication"},"helpUri":"https://codehealth.canine.dev/dimensions/R10"},{"id":"R2","name":"Cyclomatic Complexity","shortDescription":{"text":"Cyclomatic Complexity"},"helpUri":"https://codehealth.canine.dev/dimensions/R2"},{"id":"R3","name":"Large Files","shortDescription":{"text":"Large Files"},"helpUri":"https://codehealth.canine.dev/dimensions/R3"},{"id":"R7","name":"Dead Code","shortDescription":{"text":"Dead Code"},"helpUri":"https://codehealth.canine.dev/dimensions/R7"},{"id":"R9","name":"Circular Imports","shortDescription":{"text":"Circular Imports"},"helpUri":"https://codehealth.canine.dev/dimensions/R9"},{"id":"S1","name":"Web-Security Posture","shortDescription":{"text":"Web-Security Posture"},"helpUri":"https://codehealth.canine.dev/dimensions/S1"},{"id":"X9","name":"Subsumed condition operand","shortDescription":{"text":"Subsumed condition operand"},"helpUri":"https://codehealth.canine.dev/dimensions/X9"}]}},"results":[{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 142): (anonymous) has cyclomatic complexity 142 (threshold 15). Most of this is not in the body itself: 2 of the 142 points are its own statements and the rest belongs to 35 function items inside it that branch (_sorted::(anonymous), _renderTable::(anonymous), _filtered::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"5beaff398ed477444139695640bc378585a048034bf4e7012b200c0fc0eff106"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 135): (anonymous) has cyclomatic complexity 135 (threshold 15). Most of this is not in the body itself: 1 of the 135 points is its own statement and the rest belongs to 97 function items inside it that branch (_transferCollapseState, _renderSwimlanes, _renderTimelineAxis, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1d2cf7bbb247998914e989b1e19da91f9fec4670996d95f4f04e5f7b2dbb04c"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 125): (anonymous) has cyclomatic complexity 125 (threshold 15). Most of this is not in the body itself: 1 of the 125 points is its own statement and the rest belongs to 74 function items inside it that branch (_zoomToConnected, _computeLayout, _computeLayout::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"9d3b092d7a7fbb120552cc5508e18acd684a52bbca182f3621944db3dae6fcc3"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 114): (anonymous) has cyclomatic complexity 114 (threshold 15). Most of this is not in the body itself: 2 of the 114 points are its own statements and the rest belongs to 28 function items inside it that branch (_sorted::(anonymous), _renderTable::(anonymous), _exportCSV::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"be9a53a4380b45e0389c4a00efd6876cd5dc6ba5b12d95967e4da6b09019924d"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 106): (anonymous) has cyclomatic complexity 106 (threshold 15). Most of this is not in the body itself: 3 of the 106 points are its own statements and the rest belongs to 48 function items inside it that branch (_initKeyboard::(anonymous), timeAgo, statusClass, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/core.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"bbf08a67b9b46481c276c471b30772da3f01d19f26d02f467de9927a548da7f5"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 83): (anonymous) has cyclomatic complexity 83 (threshold 15). Most of this is not in the body itself: 2 of the 83 points are its own statements and the rest belongs to 29 function items inside it that branch (_fieldTypeLabel, _fieldConstraints, show, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"d5deedd24ad9ba1ff36d8144ef38b263d3a2873ddd352de4afa27941bc58a1f3"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 74): (anonymous) has cyclomatic complexity 74 (threshold 15). Most of this is not in the body itself: 1 of the 74 points is its own statement and the rest belongs to 58 function items inside it that branch (render, _buildBadgeText, _renderSingleNode, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-topology.js"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"197fc4210a6c195835c69b5062b06268321b655fc5a58e3d13ac1202ff099f83"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 73): (anonymous) has cyclomatic complexity 73 (threshold 15). Most of this is not in the body itself: 2 of the 73 points are its own statements and the rest belongs to 22 function items inside it that branch (_sorted::(anonymous), _renderOutbox::(anonymous), _updateSummary, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"c140a87ca6438d8ea87b92a9e52b6c3f9e488ed9b098b7bc5e47189c88d80c3e"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 69): (anonymous) has cyclomatic complexity 69 (threshold 15). Most of this is not in the body itself: 2 of the 69 points are its own statements and the rest belongs to 37 function items inside it that branch (_wireSearch::(anonymous), _switchTab, _wireSearch, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain.js"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"8bacb46912b9c1b1fb373cf3da1a0de897afbb605b5d5bba3e3d9188e733c910"}},{"ruleId":"D1","level":"warning","message":{"text":"recover.recover (cyclomatic 48): recover.recover has cyclomatic complexity 48 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/recover.py"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"6390f9333e3d7f6c6558a28093ab7a13d1ae813ad23585b3977645a10d3d893a"}},{"ruleId":"D1","level":"warning","message":{"text":"SqlalchemyModel.__init_subclass__ (cyclomatic 46): SqlalchemyModel.__init_subclass__ has cyclomatic complexity 46 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":595}}}],"partialFingerprints":{"codehealthFindingId/v1":"98506984a048cdb9cd675defeb7464bfda374a80f4940324b410168d05fd7ed6"}},{"ruleId":"D1","level":"warning","message":{"text":"slice_generator._validate (cyclomatic 44): slice_generator._validate has cyclomatic complexity 44 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/slice_generator.py"},"region":{"startLine":648}}}],"partialFingerprints":{"codehealthFindingId/v1":"ade09ece18f66b2017ad73491c0e18ef5229680148bae094459acbb679b43712"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 40): (anonymous) has cyclomatic complexity 40 (threshold 15). Most of this is not in the body itself: 1 of the 40 points is its own statement and the rest belongs to 32 function items inside it that branch (areaChart, sparkline, barChart, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/charts.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"829f5105f440d69dd17d360125609c9e09fcc6cae4c4cbfd2ae2b1be31ffdd8b"}},{"ruleId":"D1","level":"warning","message":{"text":"metrics._hand_rolled_metrics (cyclomatic 39): metrics._hand_rolled_metrics has cyclomatic complexity 39 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":527}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ca6c9256c39558291c1993a8f93104d8b9108fe86f61a5375f4eb854f657d10"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 39): (anonymous) has cyclomatic complexity 39 (threshold 15). Most of this is not in the body itself: 3 of the 39 points are its own statements and the rest belongs to 21 function items inside it that branch (_buildHeaderHTML, _renderTransitions::(anonymous), _toggleExpand, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-processes.js"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"13fcb008fe931f86f576e770db5d53d7a6cdc8b4cb091a037d704e79fbc1299d"}},{"ruleId":"D1","level":"warning","message":{"text":"mypy_plugin._synthesize_init (cyclomatic 38): mypy_plugin._synthesize_init has cyclomatic complexity 38 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":631}}}],"partialFingerprints":{"codehealthFindingId/v1":"d97f7271449e9e358e54e6e142b3682270df39b3067704615eba847e896053e0"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous) (cyclomatic 36): (anonymous) has cyclomatic complexity 36 (threshold 15). Most of this is not in the body itself: 2 of the 36 points are its own statements and the rest belongs to 13 function items inside it that branch (_onDataLoaded, _formatUptime, _updateTile, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/infrastructure.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"439d60a47b22ac58fdfec7e91e4946a99f963e4101f8492f751c336f7a8d97bc"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._bindEvents (cyclomatic 35): timeline._bindEvents has cyclomatic complexity 35 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 19 belong to 5 function literals inside it that branch. To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1081}}}],"partialFingerprints":{"codehealthFindingId/v1":"c9590e74122fdd4dfda91dec39776b9faf32bcce29c8744cde8dac6b7a7372d7"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._extract_resolved_field (cyclomatic 33): IRBuilder._extract_resolved_field has cyclomatic complexity 33 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":424}}}],"partialFingerprints":{"codehealthFindingId/v1":"3994529a90642c272066dd924b68be76443805b3b110ffbcca2f8ca73ebb4a1a"}},{"ruleId":"D1","level":"warning","message":{"text":"ir.diff (cyclomatic 32): ir.diff has cyclomatic complexity 32 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"e4d8dd3605e7de235e4daefff21a1e228c091881848e25d4f68396520ae57f56"}},{"ruleId":"D1","level":"warning","message":{"text":"UnitOfWork._do_commit (cyclomatic 32): UnitOfWork._do_commit has cyclomatic complexity 32 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/unit_of_work.py"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"4047196f956ebad8aefc675314f7347a81c55d06f71d06413fe4ad115e8c832f"}},{"ruleId":"D1","level":"warning","message":{"text":"CommandProcessor.process (cyclomatic 31): CommandProcessor.process has cyclomatic complexity 31 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/command_processor.py"},"region":{"startLine":278}}}],"partialFingerprints":{"codehealthFindingId/v1":"205be5b5ff639b21700d24b37d4d0cdc38e9cd904570366feef1cb90b299ed53"}},{"ruleId":"D1","level":"warning","message":{"text":"utils._prepare_pydantic_namespace (cyclomatic 31): utils._prepare_pydantic_namespace has cyclomatic complexity 31 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":309}}}],"partialFingerprints":{"codehealthFindingId/v1":"79ea464af0506ad9a642f157ded4f6bb4938d89d3f223241a23e65f0527850dd"}},{"ruleId":"D1","level":"warning","message":{"text":"handlers._sorted (cyclomatic 31): handlers._sorted has cyclomatic complexity 31 (threshold 15). Most of this is not in the body itself: 1 of the 31 points is its own statement and the rest belongs to one function literal inside it that branches (line 56). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b5d9426b5b22fa8a1d702c39f21faa5e61876ac0b9b814959f1b7e25bc6c6a1"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._showEventDetail (cyclomatic 31): timeline._showEventDetail has cyclomatic complexity 31 (threshold 15). Of this number, 26 points are the body\u0027s own statements and 5 belong to 3 function literals inside it that branch. To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":830}}}],"partialFingerprints":{"codehealthFindingId/v1":"edee4e9bee4e02fa9b9d01cd2ba599f8436b9d0623a2eca728cc35d514abdfaf"}},{"ruleId":"D1","level":"warning","message":{"text":"domain._build_flow_graph (cyclomatic 30): domain._build_flow_graph has cyclomatic complexity 30 (threshold 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/domain.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"e81cf7dffd459d75791f61e76e2adb7738e44176dae2654339e480d279243361"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseCommand._build_metadata (cyclomatic 29): BaseCommand._build_metadata has cyclomatic complexity 29 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"9da4460a021f4ca238a1974d54bc03e35c65d14970310a85ce9a0f06345d5bc6"}},{"ruleId":"D1","level":"warning","message":{"text":"processes._sorted (cyclomatic 29): processes._sorted has cyclomatic complexity 29 (threshold 15). Most of this is not in the body itself: 1 of the 29 points is its own statement and the rest belongs to one function literal inside it that branches (line 49). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"1dfa91a0251e5ec2c5cf8509cc52919aa2add137139f69d1cd450d8e2fe19445"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._renderCausationTree (cyclomatic 29): timeline._renderCausationTree has cyclomatic complexity 29 (threshold 15). Of this number, 27 points are the body\u0027s own statements and 2 belong to one function literal inside it that branches. To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"1cdb5201474ba675c18dfb58bb51f6164592ce57128852335ebe47fb11e5c192"}},{"ruleId":"D1","level":"warning","message":{"text":"Engine.handle_message (cyclomatic 28): Engine.handle_message has cyclomatic complexity 28 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":815}}}],"partialFingerprints":{"codehealthFindingId/v1":"2bdd854a2bfc184e5abfa1f9eacfb04b20e521ca2e0f62025c421b1520eae3c9"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseRepository._sync_children (cyclomatic 27): BaseRepository._sync_children has cyclomatic complexity 27 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"fafe010182a741ea14230ecad685b173cf2885f547cc95e035739967eae6ae82"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_renderCausationTree (cyclomatic 27): (anonymous)::_renderCausationTree has cyclomatic complexity 27 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"6352debc3b45f56e4d839dc1eb636aefa78eed7b7fea6ecf5e8ef5f9af467971"}},{"ruleId":"D1","level":"warning","message":{"text":"docs.generate (cyclomatic 26): docs.generate has cyclomatic complexity 26 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/docs.py"},"region":{"startLine":101}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5c776719b8fd5fe7df19194b00c1c0d7e5725c9b4034e0647c70472ffb30f0e"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEntity.model_post_init (cyclomatic 26): BaseEntity.model_post_init has cyclomatic complexity 26 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":534}}}],"partialFingerprints":{"codehealthFindingId/v1":"daa09b93895dcfd0def1acf689ad594ac876d50ef5989e29d8c9179ea92a85b5"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline.collect_all_events (cyclomatic 26): timeline.collect_all_events has cyclomatic complexity 26 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":208}}}],"partialFingerprints":{"codehealthFindingId/v1":"efa4285eb944b08902c4d0041cf4503e289d9cb89f7936a43a11f9b0358b2222"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_showEventDetail (cyclomatic 26): (anonymous)::_showEventDetail has cyclomatic complexity 26 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":830}}}],"partialFingerprints":{"codehealthFindingId/v1":"49525af72684b28cd7af4a5d4c101b85baa690f25a900dd8990d059a4a78901d"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEvent._build_metadata (cyclomatic 25): BaseEvent._build_metadata has cyclomatic complexity 25 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/event.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"37f0634d633759758d7d87ed49cd1469641997a845291bad05677afe18ce16b2"}},{"ruleId":"D1","level":"warning","message":{"text":"mypy_plugin._synthesize_has_many_methods (cyclomatic 25): mypy_plugin._synthesize_has_many_methods has cyclomatic complexity 25 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":894}}}],"partialFingerprints":{"codehealthFindingId/v1":"c860bd0b2f39896c3a4ca3a3879cfb03696bbb38bcbbb93b87f18f007378ee7a"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._diagnose_unsourced_projection_field (cyclomatic 25): IRBuilder._diagnose_unsourced_projection_field has cyclomatic complexity 25 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2481}}}],"partialFingerprints":{"codehealthFindingId/v1":"215419939985ec97434b716884f4658f4fb0fe1e5638fe54a5808774738e4cdf"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._find_deprecated_import_uses (cyclomatic 25): IRBuilder._find_deprecated_import_uses has cyclomatic complexity 25 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3807}}}],"partialFingerprints":{"codehealthFindingId/v1":"36969313f5707db28bd25b9bee80d111e05f853f3fdb6dd386039c084e493120"}},{"ruleId":"D1","level":"warning","message":{"text":"domain._wireSearch (cyclomatic 25): domain._wireSearch has cyclomatic complexity 25 (threshold 15). Most of this is not in the body itself: 7 of the 25 points are its own statements and the rest belongs to 5 function literals inside it that branch (lines 256, 247, 169, \u2026). The decisions are inside those literals, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literals\u0027 work into a named function or method at the enclosing scope and have each literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain.js"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b485658c639c8620c8e59f76f37bb0ca279e12139cc47259838a819edfc5d37"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEntity.__init__ (cyclomatic 24): BaseEntity.__init__ has cyclomatic complexity 24 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":419}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc934ae08e14978ef6ebc9473fc2cadd592de4100a133cb8f451bec1d656ed54"}},{"ruleId":"D1","level":"warning","message":{"text":"handlers._renderTable (cyclomatic 24): handlers._renderTable has cyclomatic complexity 24 (threshold 15). Most of this is not in the body itself: 10 of the 24 points are its own statements and the rest belongs to one function literal inside it that branches (line 135). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"f50aa9223c878d263943a2f4b2fef98c8545f883c2e7ddd8b6cff07a2eca2036"}},{"ruleId":"D1","level":"warning","message":{"text":"Domain._register_element (cyclomatic 23): Domain._register_element has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":1046}}}],"partialFingerprints":{"codehealthFindingId/v1":"c52b7dfe4c630a52080d2c33668241b6da1e38a0eaa912d1584895d37ec86fee"}},{"ruleId":"D1","level":"warning","message":{"text":"CommandProcessor.enrich (cyclomatic 23): CommandProcessor.enrich has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/command_processor.py"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"b9918f765a3832f2ab324f5337304e9c8be2d50e8ee3374c11b72db94383987d"}},{"ruleId":"D1","level":"warning","message":{"text":"upgrade_uow._http_names (cyclomatic 23): upgrade_uow._http_names has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_uow.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3882b3469493f2ee0d8aad66d3e55e4fdccd227ab1b83a2c760f6597b9d77dd"}},{"ruleId":"D1","level":"warning","message":{"text":"messages.showTraceDetail (cyclomatic 23): messages.showTraceDetail has cyclomatic complexity 23 (threshold 15). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb8703900d82e232baa24511522144bafd5a783b8145cf82cd72bdb18fa26b9e"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._readURL (cyclomatic 23): timeline._readURL has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"e90ff49fc5580e07f6ac6f673e896d951dd4a78cd99d64907f6da369ad1f9e37"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_readURL (cyclomatic 23): (anonymous)::_readURL has cyclomatic complexity 23 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"b3499a81543e345401e59c6949cbeaefa5488b0e9d56cd56c0dd489dab8a7c89"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::showTraceDetail (cyclomatic 23): (anonymous)::showTraceDetail has cyclomatic complexity 23 (threshold 15). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e2ddb3a5df40e0b8cc5761ace82336b0cd82c781023014b94c987e86a801201"}},{"ruleId":"D1","level":"warning","message":{"text":"OutboxProcessor._process_single_message (cyclomatic 22): OutboxProcessor._process_single_message has cyclomatic complexity 22 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/outbox_processor.py"},"region":{"startLine":358}}}],"partialFingerprints":{"codehealthFindingId/v1":"bcad49b96f5c9d06ea0a5e7b71605ab3b2bb73dd44cdb0204e83aa7b05e570b5"}},{"ruleId":"D1","level":"warning","message":{"text":"SubscriptionConfig.validate (cyclomatic 22): SubscriptionConfig.validate has cyclomatic complexity 22 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"3af12e1da4a67080268f7369f1cae8604e3614462320c7c8a7b9ad0a33170580"}},{"ruleId":"D1","level":"warning","message":{"text":"overview.updateSubscriptions (cyclomatic 22): overview.updateSubscriptions has cyclomatic complexity 22 (threshold 15). Of this number, 17 points are the body\u0027s own statements and 5 belong to 2 function literals inside it that branch. To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"9befa8dcaa7ac51be5f2cead798b0d04b3494cf681e7669577aba38f7d8c4918"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEntity._maybe_inject_auto_id (cyclomatic 21): BaseEntity._maybe_inject_auto_id has cyclomatic complexity 21 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":288}}}],"partialFingerprints":{"codehealthFindingId/v1":"db66c5a71607bfb6ae93c7a2dc392343982cfdb7bf4e9a5d78e549901a3d23e3"}},{"ruleId":"D1","level":"warning","message":{"text":"EventStoreSubscription.process_batch (cyclomatic 21): EventStoreSubscription.process_batch has cyclomatic complexity 21 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":862}}}],"partialFingerprints":{"codehealthFindingId/v1":"51c0a997b2e06220b9f38772f62d57031b2d4ff251ba0138d3a395b6d3323edf"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline.searchTraces (cyclomatic 21): timeline.searchTraces has cyclomatic complexity 21 (threshold 15). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":200}}}],"partialFingerprints":{"codehealthFindingId/v1":"d1952848c910e61492f3d0214fb2cb8d0635f9a9d7d287bc704719e89ed329c8"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._switchCausationView (cyclomatic 21): timeline._switchCausationView has cyclomatic complexity 21 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"c007eec20c901ebfb557ca66ffc9040ecd9d5b0c30b06a0a7304f96dde27ea41"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::searchTraces (cyclomatic 21): (anonymous)::searchTraces has cyclomatic complexity 21 (threshold 15). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":200}}}],"partialFingerprints":{"codehealthFindingId/v1":"861ebcc1be93356d3e4afbdb737562b72662a9648ae89dd8125056b32bc39326"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_switchCausationView (cyclomatic 21): (anonymous)::_switchCausationView has cyclomatic complexity 21 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"30df3716b38d2ad8e7b2b8e63a5361450b947381a32b3ac4b7b58c863b34d5ab"}},{"ruleId":"D1","level":"warning","message":{"text":"HasOne.__set__ (cyclomatic 20): HasOne.__set__ has cyclomatic complexity 20 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":429}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd15e1bd22706a2587d3e4f4b824e4c0e2b4fcdc77ae4f4d19d1d7aee40fda6b"}},{"ruleId":"D1","level":"warning","message":{"text":"processes._renderTable (cyclomatic 20): processes._renderTable has cyclomatic complexity 20 (threshold 15). Most of this is not in the body itself: 4 of the 20 points are its own statements and the rest belongs to one function literal inside it that branches (line 108). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"6fd72282be7c2461b029f68b75ab043314693614d787a21009f3be1c2c6cefa6"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._renderAggregateTimeline (cyclomatic 20): timeline._renderAggregateTimeline has cyclomatic complexity 20 (threshold 15). Of this number, 15 points are the body\u0027s own statements and 5 belong to 3 function literals inside it that branch. To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"5545c0929ae3fb9fc2d8e252003356f7e5f4154893fdbb1db91d9974405ea94a"}},{"ruleId":"D1","level":"warning","message":{"text":"check._print_rich (cyclomatic 19): check._print_rich has cyclomatic complexity 19 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/check.py"},"region":{"startLine":306}}}],"partialFingerprints":{"codehealthFindingId/v1":"0a9bcc1d33b55436cbff83242986858e2a394093ae2629ad0513324dea080aea"}},{"ruleId":"D1","level":"warning","message":{"text":"value_object.value_object_from_entity (cyclomatic 19): value_object.value_object_from_entity has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/value_object.py"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"a6e2bd9cc7faeb779e205d06dbb8bc6b97db776152c8c383dfff1f33485071df"}},{"ruleId":"D1","level":"warning","message":{"text":"HandlerConfigurator.validate_sequential_by (cyclomatic 19): HandlerConfigurator.validate_sequential_by has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/handler_setup.py"},"region":{"startLine":355}}}],"partialFingerprints":{"codehealthFindingId/v1":"123095e99b416fae724cac7ca97dce43447fe5f285ade2021c5b6c099a4ee103"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._materialize_method_edges (cyclomatic 19): IRBuilder._materialize_method_edges has cyclomatic complexity 19 (threshold 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1557}}}],"partialFingerprints":{"codehealthFindingId/v1":"f910400ddee4f13f2a9c69dc3796b1f2a77281c037daf74a8b94b89e2a1b0ef2"}},{"ruleId":"D1","level":"warning","message":{"text":"handlers.merge_subscription_status (cyclomatic 19): handlers.merge_subscription_status has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"9432549337a2b2f0a96e3cb53b67f5a61b3688060e080379af8839cc201b0537"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline.collect_timeline_stats (cyclomatic 19): timeline.collect_timeline_stats has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":316}}}],"partialFingerprints":{"codehealthFindingId/v1":"21b20dc7dd1b25fc1c6c00ec2a090590556cd5aeba01a42c9abad14964b68703"}},{"ruleId":"D1","level":"warning","message":{"text":"event_store_subscription.reconstruct_unresolved (cyclomatic 19): event_store_subscription.reconstruct_unresolved has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"406c7e1ef989e5527c9c3cc79f0eabe4e8798b4dbdbaaba1ef33f784401415b5"}},{"ruleId":"D1","level":"warning","message":{"text":"Message.to_cloudevent (cyclomatic 19): Message.to_cloudevent has cyclomatic complexity 19 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":1223}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a23b1c5f841621fd4b64ec4901316891627732cf1b58e37eafbe0250aaf9219"}},{"ruleId":"D1","level":"warning","message":{"text":"ir._print_diff_text (cyclomatic 18): ir._print_diff_text has cyclomatic complexity 18 (threshold 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":385}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ff253bcb9ac17f9e5b73ee15aa74a0fcbff2a1d9c28f5e5b5ce5f8f3d907cbf"}},{"ruleId":"D1","level":"warning","message":{"text":"subscriptions.status (cyclomatic 18): subscriptions.status has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/subscriptions.py"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"e1a90aee471393a6d0c890e7c8d0311d475413c8bd1450c1b3e5dffe79612a6e"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseAggregate.raise_ (cyclomatic 18): BaseAggregate.raise_ has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd62d452a19301f12eae9f27807e33d633c6155c00ece0a3faadb37b8ef34009"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEntity._run_invariants (cyclomatic 18): BaseEntity._run_invariants has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":717}}}],"partialFingerprints":{"codehealthFindingId/v1":"f10a4c6104be95f09dfa07d976a63e363e57bef916fe37981ef626f47f675f95"}},{"ruleId":"D1","level":"warning","message":{"text":"Domain.configure_logging (cyclomatic 18): Domain.configure_logging has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":2738}}}],"partialFingerprints":{"codehealthFindingId/v1":"45f95665580eebd10494adc77e4d6aa048a5e834d67610f52191cf9c7b4c03d2"}},{"ruleId":"D1","level":"warning","message":{"text":"HasMany.add (cyclomatic 18): HasMany.add has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":588}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f8d056bc56e77809a85d90b128f30fa3c674e8b58c1e26902703e1835e76428"}},{"ruleId":"D1","level":"warning","message":{"text":"ResolvedField.__init__ (cyclomatic 18): ResolvedField.__init__ has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/resolved.py"},"region":{"startLine":58}}}],"partialFingerprints":{"codehealthFindingId/v1":"07b6b53cd36accad1631708ad8077ded51022ea96dd0d7d8d43e931c35251f36"}},{"ruleId":"D1","level":"warning","message":{"text":"diff._diff_contracts (cyclomatic 18): diff._diff_contracts has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":485}}}],"partialFingerprints":{"codehealthFindingId/v1":"25b7449807c0d87ec235c8f5a11473aa5f31833f6156785675aea240b1c07827"}},{"ruleId":"D1","level":"warning","message":{"text":"handlers.collect_per_handler_trace_metrics (cyclomatic 18): handlers.collect_per_handler_trace_metrics has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":328}}}],"partialFingerprints":{"codehealthFindingId/v1":"a1d9ed7eafa6d939946b603dd7173f642f9df3d147269e1eb885771aa71221b2"}},{"ruleId":"D1","level":"warning","message":{"text":"processes.collect_pm_trace_metrics (cyclomatic 18): processes.collect_pm_trace_metrics has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/processes.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7d98ecac9d7931d7cbdfdb3eb9dce0fe859aab432fa48ccf508120d85bfb25c"}},{"ruleId":"D1","level":"warning","message":{"text":"SubscriptionConfig.from_profile (cyclomatic 18): SubscriptionConfig.from_profile has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":582}}}],"partialFingerprints":{"codehealthFindingId/v1":"8fbc89f487f2fc5e7352f57a606e55c0fdce3d717946998024ca16380adc3fbe"}},{"ruleId":"D1","level":"warning","message":{"text":"subscription_status._collect_stream_status (cyclomatic 18): subscription_status._collect_stream_status has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":451}}}],"partialFingerprints":{"codehealthFindingId/v1":"000651335a0c866fc11ea9668139a5b54e4bc4f8e47a8fd3659bcb41c6c67098"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._renderTracesTable (cyclomatic 18): timeline._renderTracesTable has cyclomatic complexity 18 (threshold 15). Of this number, 10 points are the body\u0027s own statements and 8 belong to 3 function literals inside it that branch. To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":241}}}],"partialFingerprints":{"codehealthFindingId/v1":"abd27f2cf02049766c6a064194a5b3d9e4c988990f062bd5106170ce71a70a3c"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._showCorrelationView (cyclomatic 18): timeline._showCorrelationView has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb43f80a86bebbb551c4cc0f614f912ef1e703765a580b7f01a01b08bd01da16"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._showAggregateView (cyclomatic 18): timeline._showAggregateView has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":596}}}],"partialFingerprints":{"codehealthFindingId/v1":"313ca3c969ffe6154617f7b448ae1c818d95990330d0983f2b3a0cfe07724b61"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._fetchLatestEvent (cyclomatic 18): timeline._fetchLatestEvent has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1320}}}],"partialFingerprints":{"codehealthFindingId/v1":"6e0de8fb67d9495b3f1c7e720f8c737a5d6572f8db5ca19043ed9c31858d7bdc"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_showCorrelationView (cyclomatic 18): (anonymous)::_showCorrelationView has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"1ee53418d9d61e1ec2f66cac3f10f33900f5f65557d31941c159c5dc50decd75"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_showAggregateView (cyclomatic 18): (anonymous)::_showAggregateView has cyclomatic complexity 18 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":596}}}],"partialFingerprints":{"codehealthFindingId/v1":"224bd94d208ff27176df2d3299e83b4e71ac616db50cc916043782f620e64422"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_fetchLatestEvent (cyclomatic 18): (anonymous)::_fetchLatestEvent has cyclomatic complexity 18 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1320}}}],"partialFingerprints":{"codehealthFindingId/v1":"728d29057614d043cdd62a396fbe17ff5d1d2eac50c510bb1db81ba2ea03345e"}},{"ruleId":"D1","level":"warning","message":{"text":"RedisBroker._read_blocking (cyclomatic 17): RedisBroker._read_blocking has cyclomatic complexity 17 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function so the top-level body reads as a short sequence of named decisions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":390}}}],"partialFingerprints":{"codehealthFindingId/v1":"62f74e4c6665b513e8f4feaba97d6c3f5411afeb9105a5cad4c116c604627e12"}},{"ruleId":"D1","level":"warning","message":{"text":"cli.server (cyclomatic 17): cli.server has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/__init__.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"999a45aa5cfe0eb8f7c45325b54333c39d7916cc4cb818195b91a3c15879fba5"}},{"ruleId":"D1","level":"warning","message":{"text":"ir._print_element_changes (cyclomatic 17): ir._print_element_changes has cyclomatic complexity 17 (threshold 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":495}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b8463fe88e027956ef0f948c89f25dbfdb979de90fdc10fe7bdefba873ee8b5"}},{"ruleId":"D1","level":"warning","message":{"text":"projection.status (cyclomatic 17): projection.status has cyclomatic complexity 17 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/projection.py"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"26fbe920ed59b143f626f1ce8ee6c5956cd757e9a2e1bdc75ac342d7557b836a"}},{"ruleId":"D1","level":"warning","message":{"text":"aggregate.aggregate_factory (cyclomatic 17): aggregate.aggregate_factory has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":625}}}],"partialFingerprints":{"codehealthFindingId/v1":"3692c55e38a6045cb91b9deb2f63d5aa5eb6523a2ee71f6df555169f2473cf94"}},{"ruleId":"D1","level":"warning","message":{"text":"entity.entity_factory (cyclomatic 17): entity.entity_factory has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":1189}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3ff081cd16d933cb6b6dff2f116df578ec769467c0b2958cec9cf3cf26969c2"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseRepository._do_add (cyclomatic 17): BaseRepository._do_add has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":252}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ff6dbb83cbde3880828733cdeb77cccff66bc2b3d8f28c2e3996b9e65e0f780"}},{"ruleId":"D1","level":"warning","message":{"text":"HasMany.remove (cyclomatic 17): HasMany.remove has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":712}}}],"partialFingerprints":{"codehealthFindingId/v1":"f97369223870ae8517d34e5acbfc1f53a42f3c2d940b08fb31ae6b4d2ff67158"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._diagnose_unindexed_filter_path (cyclomatic 17): IRBuilder._diagnose_unindexed_filter_path has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2737}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f53b6f15c0f62251ec03d48b28cf2a7b72b909f17f8385d4adfe750baa6b6c3"}},{"ruleId":"D1","level":"warning","message":{"text":"config._parse_config (cyclomatic 17): config._parse_config has cyclomatic complexity 17 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/config.py"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"98cd106082c52fa9a142658c1b2fe8269ea86ef07d80541e24bae4d27107594d"}},{"ruleId":"D1","level":"warning","message":{"text":"schema._field_to_schema (cyclomatic 17): schema._field_to_schema has cyclomatic complexity 17 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/schema.py"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a53b26287af46d061dad03f6c7622c9898ec012ea6831a6f06a400d2e0b0a29"}},{"ruleId":"D1","level":"warning","message":{"text":"slice_generator._validate_names (cyclomatic 17): slice_generator._validate_names has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/slice_generator.py"},"region":{"startLine":1134}}}],"partialFingerprints":{"codehealthFindingId/v1":"a46e1162171306d023cc7b4c0ed9f23434f0122bbbca5898e7c50e13ee02d543"}},{"ruleId":"D1","level":"warning","message":{"text":"subscription_status._collect_partitioned_stream_status (cyclomatic 17): subscription_status._collect_partitioned_stream_status has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":321}}}],"partialFingerprints":{"codehealthFindingId/v1":"88e8c2bc56aaa9f5668ce46c3de7ea3d3bc7c6a3fb966bc88e2e374d91c3a59b"}},{"ruleId":"D1","level":"warning","message":{"text":"subscription_status._collect_broker_status (cyclomatic 17): subscription_status._collect_broker_status has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":567}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f592e6109e2601c7963b5e9e4ae0924948cd5e3cae32ca06e6d8baeb73f5747"}},{"ruleId":"D1","level":"warning","message":{"text":"upgrade_opportunities._apply_import (cyclomatic 17): upgrade_opportunities._apply_import has cyclomatic complexity 17 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":530}}}],"partialFingerprints":{"codehealthFindingId/v1":"a475219b7b8818615f705a1b4aa4c5df3aa890380ffff1c6794b478d223d477e"}},{"ruleId":"D1","level":"warning","message":{"text":"new.run_project_setup (cyclomatic 16): new.run_project_setup has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/new.py"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"789617324dd5d0c925e715a2f680c60bf34e66cc066ceb1d3e4cdbf1f19e969d"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseEntity.__setattr__ (cyclomatic 16): BaseEntity.__setattr__ has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":939}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd671f6e5d710b1906825415fd19c5ec2ea4f6f0e506cdddca5427acd4e081e8"}},{"ruleId":"D1","level":"warning","message":{"text":"BaseProjection.__init__ (cyclomatic 16): BaseProjection.__init__ has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":224}}}],"partialFingerprints":{"codehealthFindingId/v1":"068e4e809564724f3aa0f8ba356b73a381606c55204787dab07ae6a8810b1bd4"}},{"ruleId":"D1","level":"warning","message":{"text":"containers.List (cyclomatic 16): containers.List has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/containers.py"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"765762fa6600e379ee816b43a3160ca1d2128570d4c63d883ccb18c0a377841c"}},{"ruleId":"D1","level":"warning","message":{"text":"DomainContextMiddleware._emit_http_wide_event (cyclomatic 16): DomainContextMiddleware._emit_http_wide_event has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/integrations/fastapi/middleware.py"},"region":{"startLine":359}}}],"partialFingerprints":{"codehealthFindingId/v1":"190c69c02bc66fa208ad136df4ecc982ee35dccb524ea283990f59b28948a2c8"}},{"ruleId":"D1","level":"warning","message":{"text":"_FlowBuilder._step_simple (cyclomatic 16): _FlowBuilder._step_simple has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/dataflow.py"},"region":{"startLine":688}}}],"partialFingerprints":{"codehealthFindingId/v1":"d73cff283324bb00de389b35c6aee3532df7be525afede955fcae28248fd6379"}},{"ruleId":"D1","level":"warning","message":{"text":"SourceProvider._discover_modules (cyclomatic 16): SourceProvider._discover_modules has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/source_provider.py"},"region":{"startLine":220}}}],"partialFingerprints":{"codehealthFindingId/v1":"a1ffc8bc610ce7f8475f4ba8a26530577d5b2e221c9140de96f6b4ca82699372"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._extract_fields (cyclomatic 16): IRBuilder._extract_fields has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":353}}}],"partialFingerprints":{"codehealthFindingId/v1":"212e6d89ef0f3e51a639d07c5d3700c06072038e5caa19eab12e5db7df20fc3f"}},{"ruleId":"D1","level":"warning","message":{"text":"IRBuilder._diagnose_unraised_event (cyclomatic 16): IRBuilder._diagnose_unraised_event has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3212}}}],"partialFingerprints":{"codehealthFindingId/v1":"e20c8288af9fb62aafae34a5f6d63e9b265cfb1365dc8aec82a206ddec1a926d"}},{"ruleId":"D1","level":"warning","message":{"text":"diff._classify_field_changes (cyclomatic 16): diff._classify_field_changes has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1224}}}],"partialFingerprints":{"codehealthFindingId/v1":"cbbea8ac6c159432bcae02a53c02c284867f2e2a4a0c82bb52d5b9df76741982"}},{"ruleId":"D1","level":"warning","message":{"text":"apply.apply_plan (cyclomatic 16): apply.apply_plan has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/apply.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e5d9258a9915de67911a67e89c82cb73991e7acd6710ae05c1a8bd64f05cb51"}},{"ruleId":"D1","level":"warning","message":{"text":"model_parser.emit_model (cyclomatic 16): model_parser.emit_model has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":738}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9940a0c5e7a0b55435bf66ece1942fdb298b1eb67cb1d00aea979d75c4827d6"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline._load_traces_for_correlation (cyclomatic 16): timeline._load_traces_for_correlation has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":518}}}],"partialFingerprints":{"codehealthFindingId/v1":"bf0f1d247ad4b8e4f0fbabda14e1c11745b65b63aac00e6ea2a6738b85215521"}},{"ruleId":"D1","level":"warning","message":{"text":"utils.clone_class (cyclomatic 16): utils.clone_class has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":658}}}],"partialFingerprints":{"codehealthFindingId/v1":"97e0c987f46460f2da0e90932736f782529db47f47cd4789107d603f7ae377f4"}},{"ruleId":"D1","level":"warning","message":{"text":"dlq.discover_subscriptions (cyclomatic 16): dlq.discover_subscriptions has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/dlq.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"91e02037383872cefeaf95859e1f46fc78b5bb608e57c22db2c700a98369a805"}},{"ruleId":"D1","level":"warning","message":{"text":"overview.updateHealthBanner (cyclomatic 16): overview.updateHealthBanner has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c333a2b6394ce7e729ea241ae16a5109a395bf002db3be7e978095f80e40c5e"}},{"ruleId":"D1","level":"warning","message":{"text":"timeline.fetchEvents (cyclomatic 16): timeline.fetchEvents has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"88004689ac246b75fcb722b0da1fa7c107fc418f8c52c668c8f3ef8110f8cade"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::fetchEvents (cyclomatic 16): (anonymous)::fetchEvents has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"7f06aecbef4ca0b40539fa237ae95075bb84621cfadb46e1745e3388ddf56d6c"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::_bindEvents (cyclomatic 16): (anonymous)::_bindEvents has cyclomatic complexity 16 (threshold 15). To reduce it, split the body: these branches sit side by side rather than nested inside one another, so extracting each one on its own would leave a function per branch. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1081}}}],"partialFingerprints":{"codehealthFindingId/v1":"c92de56746e8bd09048eba8e3275daf90d9c9d7c281e518bc5fc7efe99ce8375"}},{"ruleId":"D1","level":"warning","message":{"text":"(anonymous)::updateHealthBanner (cyclomatic 16): (anonymous)::updateHealthBanner has cyclomatic complexity 16 (threshold 15). To reduce it, separate the cases: extract each independent branch into its own named function, and where the body has guards that only reject input, fold those into early returns at the top."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"30127ed31d9254d46a43e43ebda15ffda4f1f623ee00b9243be6b519c84af940"}},{"ruleId":"D2","level":"warning","message":{"text":"SqlalchemyModel.__init_subclass__ (cognitive 119): SqlalchemyModel.__init_subclass__ has cognitive complexity 119 (threshold 15). Drivers by points: if/else 26 (97 pts), boolean chains 14, ternaries 1 (5 pts), loops 2 (3 pts) (nesting depth added 76). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":595}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c6b9dc62b6649165745b16aa594ed954c7c6702bbb980d1969e9f949a8fb4cd"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 113): (anonymous) has cognitive complexity 113 (threshold 15). Drivers by points: boolean chains 42, if/else 36 (38 pts), ternaries 29 (31 pts), error handling 1, match/switch 1 (nesting depth added 4). Most of this is not in the body itself: 2 of the 113 points are its own statements and the rest belongs to 28 function items inside it that branch (_sorted::(anonymous), _renderTable::(anonymous), _filtered::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e3078a222c9ada831e36fda7d0d96f34c2c530c54560b1727ebef2b26bd4f18"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 96): (anonymous) has cognitive complexity 96 (threshold 15). Drivers by points: if/else 57 (62 pts), boolean chains 12, ternaries 6 (8 pts), error handling 5 (7 pts), loops 5, match/switch 2 (nesting depth added 9). Most of this is not in the body itself: 3 of the 96 points are its own statements and the rest belongs to 48 function items inside it that branch (_initKeyboard::(anonymous), timeAgo, number, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/core.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b6b30e87394e962aa7135e8210e0f7da257c43b0e3288b9cb715fd995abb92b"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 87): (anonymous) has cognitive complexity 87 (threshold 15). Drivers by points: if/else 52 (55 pts), boolean chains 29, ternaries 3 (nesting depth added 3). Most of this is not in the body itself: 1 of the 87 points is its own statement and the rest belongs to 29 function items inside it that branch (_fieldTypeLabel, show, _fieldConstraints, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"312fdcc35a7c53faab66123f6afb802ce09f373541184c167e6396dd3a6c3dec"}},{"ruleId":"D2","level":"warning","message":{"text":"utils._prepare_pydantic_namespace (cognitive 85): utils._prepare_pydantic_namespace has cognitive complexity 85 (threshold 15). Drivers by points: if/else 17 (63 pts), loops 4 (13 pts), boolean chains 9 (nesting depth added 55). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":309}}}],"partialFingerprints":{"codehealthFindingId/v1":"af0a432cecf5f9598774c77f815539f4e46b4145a884128267a0b60e43c0a77d"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 82): (anonymous) has cognitive complexity 82 (threshold 15). Drivers by points: if/else 47 (53 pts), ternaries 9 (14 pts), boolean chains 13, error handling 1, loops 1 (nesting depth added 11). Most of this is not in the body itself: 2 of the 82 points are its own statements and the rest belongs to 37 function items inside it that branch (_wireSearch::(anonymous), _updateStats, _switchTab, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain.js"},"region":{"startLine":8}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8cc2829abb42ff3ef37e60b5600e30f21a1a97f81f5bdb71832c80f94267ee2"}},{"ruleId":"D2","level":"warning","message":{"text":"metrics._hand_rolled_metrics (cognitive 80): metrics._hand_rolled_metrics has cognitive complexity 80 (threshold 15). Drivers by points: if/else 14 (37 pts), loops 8 (18 pts), error handling 9 (15 pts), boolean chains 5, ternaries 2 (5 pts) (nesting depth added 42). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":527}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8809a8d006e23137f85ebf90f40479eec7a6c74385d9b444d35fb59f357e87c"}},{"ruleId":"D2","level":"warning","message":{"text":"recover.recover (cognitive 74): recover.recover has cognitive complexity 74 (threshold 15). Drivers by points: if/else 30 (45 pts), loops 6 (16 pts), boolean chains 8, ternaries 3 (5 pts) (nesting depth added 27). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/recover.py"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"b22b24f2568d1ef3279fff604bd95af4cc732ab84f564def37d03f59ffe9ea93"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 74): (anonymous) has cognitive complexity 74 (threshold 15). Drivers by points: if/else 26 (29 pts), boolean chains 25, ternaries 15 (17 pts), loops 1 (2 pts), match/switch 1 (nesting depth added 6). Most of this is not in the body itself: 2 of the 74 points are its own statements and the rest belongs to 22 function items inside it that branch (_updateSummary, _sorted::(anonymous), _renderOutbox::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"c2f5609ab9accbf241e564cc8db2838ebc24c27e59e21b13b5524209a92b27f2"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 72): (anonymous) has cognitive complexity 72 (threshold 15). Drivers by points: if/else 36, boolean chains 24, ternaries 11, loops 1. Most of this is not in the body itself: 0 of the 72 points are its own statements and the rest belongs to 58 function items inside it that branch (render, _renderSingleNode, _buildBadgeText, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-topology.js"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"01f5f27d6a1c03a97528350dff8beef1dab9f7dde1b4776525d5f6198ec91afe"}},{"ruleId":"D2","level":"warning","message":{"text":"slice_generator._validate (cognitive 71): slice_generator._validate has cognitive complexity 71 (threshold 15). Drivers by points: if/else 30 (55 pts), boolean chains 9, loops 3 (6 pts), ternaries 1 (nesting depth added 28). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/slice_generator.py"},"region":{"startLine":648}}}],"partialFingerprints":{"codehealthFindingId/v1":"20daf0ecede7f319786d61763ba56319f3cf3ec1c3d28a33c11cdb69d3655784"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_unsourced_projection_field (cognitive 68): IRBuilder._diagnose_unsourced_projection_field has cognitive complexity 68 (threshold 15). Drivers by points: if/else 11 (39 pts), loops 5 (12 pts), ternaries 3 (11 pts), boolean chains 6 (nesting depth added 43). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2481}}}],"partialFingerprints":{"codehealthFindingId/v1":"43abc179fe186b769142f17f137f17b70bdb08db165b4e4f056f3384ccbd9c40"}},{"ruleId":"D2","level":"warning","message":{"text":"mypy_plugin._synthesize_init (cognitive 64): mypy_plugin._synthesize_init has cognitive complexity 64 (threshold 15). Drivers by points: if/else 27 (50 pts), error handling 2 (6 pts), boolean chains 5, loops 3 (nesting depth added 27). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":631}}}],"partialFingerprints":{"codehealthFindingId/v1":"83dc335c76deb033679652dd7627d5cb6048d7e2c2dc368040a1204053fa15be"}},{"ruleId":"D2","level":"warning","message":{"text":"domain._build_flow_graph (cognitive 60): domain._build_flow_graph has cognitive complexity 60 (threshold 15). Drivers by points: loops 19 (35 pts), if/else 6 (21 pts), boolean chains 4 (nesting depth added 31). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/domain.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"f936cb0d99d212b9064d73869bbaec67fa0a885cb633a1287d7f0543b784f33e"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseRepository._sync_children (cognitive 58): BaseRepository._sync_children has cognitive complexity 58 (threshold 15). Drivers by points: if/else 13 (37 pts), loops 7 (18 pts), boolean chains 3 (nesting depth added 35). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"bcf37dad4a964242819b1340e9a1d5d9bc8ea9d2aa617fb8931751d5851cfc55"}},{"ruleId":"D2","level":"warning","message":{"text":"UnitOfWork._do_commit (cognitive 58): UnitOfWork._do_commit has cognitive complexity 58 (threshold 15). Drivers by points: if/else 14 (29 pts), loops 9 (18 pts), error handling 5, boolean chains 4, ternaries 1 (2 pts) (nesting depth added 25). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/unit_of_work.py"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"7b68daadd5d8e58aaa42e94b7acb3e5c134c09e3ef43559473edd36a7512a769"}},{"ruleId":"D2","level":"warning","message":{"text":"CommandProcessor.process (cognitive 51): CommandProcessor.process has cognitive complexity 51 (threshold 15). Drivers by points: if/else 18 (32 pts), boolean chains 9, ternaries 3 (7 pts), error handling 1 (3 pts) (nesting depth added 20). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/command_processor.py"},"region":{"startLine":278}}}],"partialFingerprints":{"codehealthFindingId/v1":"70f24dffcd8189d688de007fb534b1d3efd8d5d8deeefd7851f471ec07b42383"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers.merge_subscription_status (cognitive 50): handlers.merge_subscription_status has cognitive complexity 50 (threshold 15). Drivers by points: if/else 10 (31 pts), loops 5 (10 pts), ternaries 1 (6 pts), error handling 1 (2 pts), boolean chains 1 (nesting depth added 32). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a40eab663fec1c7f54f786a80742971a39c7b51294af86d4d94629906117139"}},{"ruleId":"D2","level":"warning","message":{"text":"mypy_plugin._synthesize_has_many_methods (cognitive 47): mypy_plugin._synthesize_has_many_methods has cognitive complexity 47 (threshold 15). Drivers by points: if/else 14 (35 pts), boolean chains 6, loops 4 (6 pts) (nesting depth added 23). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":894}}}],"partialFingerprints":{"codehealthFindingId/v1":"df590a0ab552fdaaec4b2139c2eb09df79698b9f25ac0bbe819d0c32ef24aba6"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 47): (anonymous) has cognitive complexity 47 (threshold 15). Drivers by points: if/else 27 (30 pts), ternaries 8 (10 pts), boolean chains 7 (nesting depth added 5). Most of this is not in the body itself: 2 of the 47 points are its own statements and the rest belongs to 21 function items inside it that branch (_buildHeaderHTML, _toggleExpand, _renderStateMachine::(anonymous), \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-processes.js"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1bfbe9bb3c2f6b40ad8230f560896c0f8def25fb6eea2f4108e1257858103ae"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._find_deprecated_import_uses (cognitive 46): IRBuilder._find_deprecated_import_uses has cognitive complexity 46 (threshold 15). Drivers by points: if/else 9 (28 pts), loops 6 (12 pts), boolean chains 6 (nesting depth added 25). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3807}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac3edc8fd27bea10c338d4f15a9149a605a9ea99cf982a1d1e135397f4dada98"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity._run_invariants (cognitive 45): BaseEntity._run_invariants has cognitive complexity 45 (threshold 15). Drivers by points: if/else 8 (19 pts), loops 5 (15 pts), ternaries 4 (9 pts), error handling 1 (2 pts) (nesting depth added 27). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":717}}}],"partialFingerprints":{"codehealthFindingId/v1":"986505bfd32b635948e8785093e7e447031a7a72e2af6ad941da8d74a2e211a8"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_unindexed_filter_path (cognitive 45): IRBuilder._diagnose_unindexed_filter_path has cognitive complexity 45 (threshold 15). Drivers by points: if/else 7 (29 pts), loops 6 (13 pts), boolean chains 3 (nesting depth added 29). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2737}}}],"partialFingerprints":{"codehealthFindingId/v1":"599ec7976e8920303671ea02dcc3e9a7b146df15941d36384f017623cb91979d"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_uow._http_names (cognitive 44): upgrade_uow._http_names has cognitive complexity 44 (threshold 15). Drivers by points: if/else 8 (22 pts), loops 6 (13 pts), boolean chains 6, ternaries 1 (3 pts) (nesting depth added 23). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_uow.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"0bac3b51eb84f5fffe117ef1f28c07e574b4806ea2ea8a28c7bd1b8ca28e2167"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline.collect_all_events (cognitive 43): timeline.collect_all_events has cognitive complexity 43 (threshold 15). Drivers by points: if/else 14 (27 pts), boolean chains 7, loops 3 (4 pts), ternaries 1 (3 pts), error handling 1 (2 pts) (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":208}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1ef658b6cda273a7411d02a7e0b8bb64771eed312912d04fc8f5fed6033399c"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity.__init__ (cognitive 41): BaseEntity.__init__ has cognitive complexity 41 (threshold 15). Drivers by points: if/else 11 (28 pts), loops 6 (11 pts), boolean chains 1, error handling 1 (nesting depth added 22). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":419}}}],"partialFingerprints":{"codehealthFindingId/v1":"859ed521995162d842f1927b977b8ca58a862e93af666f5edbbd91410aa7d4f5"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline.collect_timeline_stats (cognitive 41): timeline.collect_timeline_stats has cognitive complexity 41 (threshold 15). Drivers by points: if/else 10 (27 pts), error handling 2 (7 pts), boolean chains 4, loops 2 (3 pts) (nesting depth added 23). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":316}}}],"partialFingerprints":{"codehealthFindingId/v1":"2cb3d09a26901bdd7524a51c7c2029d6edf7dbb856c6f4a99a205f60ba0e21c3"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._extract_resolved_field (cognitive 40): IRBuilder._extract_resolved_field has cognitive complexity 40 (threshold 15). Drivers by points: if/else 27 (34 pts), boolean chains 6 (nesting depth added 7). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":424}}}],"partialFingerprints":{"codehealthFindingId/v1":"80f0eebc01aff94ac3b94af38be29b70079e2727c8db56b527a75d9f246a13d7"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 40): (anonymous) has cognitive complexity 40 (threshold 15). Drivers by points: if/else 29 (30 pts), boolean chains 5, ternaries 3 (5 pts) (nesting depth added 3). Most of this is not in the body itself: 2 of the 40 points are its own statements and the rest belongs to 13 function items inside it that branch (_onDataLoaded, _formatUptime, _updateTile, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/infrastructure.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"d61354a1ac0060b6a699137516dab8ecf966faed3216cccee7e4c67112c63e9b"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity.model_post_init (cognitive 39): BaseEntity.model_post_init has cognitive complexity 39 (threshold 15). Drivers by points: if/else 13 (23 pts), loops 8 (11 pts), boolean chains 5 (nesting depth added 13). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":534}}}],"partialFingerprints":{"codehealthFindingId/v1":"149be653508edc2296607916b94384125e7608cf8ea8b7ef7d3b060b4e25a2cc"}},{"ruleId":"D2","level":"warning","message":{"text":"EventStoreSubscription.process_batch (cognitive 39): EventStoreSubscription.process_batch has cognitive complexity 39 (threshold 15). Drivers by points: if/else 8 (19 pts), ternaries 4 (12 pts), boolean chains 7, loops 1 (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":862}}}],"partialFingerprints":{"codehealthFindingId/v1":"1b0c6fd88e22a23f4d2e0d870932c9706ac9bc60faa1d25b2741ca8ef4ccb119"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._bindEvents (cognitive 39): timeline._bindEvents has cognitive complexity 39 (threshold 15). Drivers by points: if/else 27 (33 pts), boolean chains 6 (nesting depth added 6). Most of this is not in the body itself: 15 of the 39 points are its own statements and the rest belongs to 5 function literals inside it that branch (lines 1252, 1168, 1226, \u2026). The decisions are inside those literals, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literals\u0027 work into a named function or method at the enclosing scope and have each literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1081}}}],"partialFingerprints":{"codehealthFindingId/v1":"7de6264e57aaeabbd415388f6b86256f9e801bf30d9159fa14e7234d8c89ac81"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity._maybe_inject_auto_id (cognitive 38): BaseEntity._maybe_inject_auto_id has cognitive complexity 38 (threshold 15). Drivers by points: if/else 11 (26 pts), loops 5 (8 pts), boolean chains 4 (nesting depth added 18). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":288}}}],"partialFingerprints":{"codehealthFindingId/v1":"be6510e35d4520dbaa751c4f43427c176aadb8ade010c5e59937731fb415d78d"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._materialize_method_edges (cognitive 38): IRBuilder._materialize_method_edges has cognitive complexity 38 (threshold 15). Drivers by points: loops 13 (22 pts), if/else 5 (16 pts) (nesting depth added 20). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1557}}}],"partialFingerprints":{"codehealthFindingId/v1":"baab3f7673c831cf0a22606da5b6da3215b5d4de606c655013f1799d12e50dd3"}},{"ruleId":"D2","level":"warning","message":{"text":"diff._diff_contracts (cognitive 38): diff._diff_contracts has cognitive complexity 38 (threshold 15). Drivers by points: if/else 16 (32 pts), loops 4 (6 pts) (nesting depth added 18). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":485}}}],"partialFingerprints":{"codehealthFindingId/v1":"07124509c86ddd1a54fcb429bfdd4055d333881de6d32cd53510348856d1abfc"}},{"ruleId":"D2","level":"warning","message":{"text":"HandlerConfigurator.validate_sequential_by (cognitive 37): HandlerConfigurator.validate_sequential_by has cognitive complexity 37 (threshold 15). Drivers by points: if/else 9 (25 pts), loops 6 (9 pts), boolean chains 3 (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/handler_setup.py"},"region":{"startLine":355}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b4f8f29678965eadde3b44382d73c30a6877f7a6a413395a8793e2ccfca3ed3"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._strongly_connected_components (cognitive 37): IRBuilder._strongly_connected_components has cognitive complexity 37 (threshold 15). Drivers by points: if/else 8 (27 pts), loops 4 (10 pts) (nesting depth added 25). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1933}}}],"partialFingerprints":{"codehealthFindingId/v1":"374fd94455b3d06375528d4e9b82d239606e825b4529fc92be120c2a35a68aae"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 36): (anonymous) has cognitive complexity 36 (threshold 15). Drivers by points: boolean chains 18, if/else 10 (11 pts), ternaries 6, loops 1 (nesting depth added 1). Most of this is not in the body itself: 0 of the 36 points are its own statements and the rest belongs to 32 function items inside it that branch (areaChart, sparkline, barChart, \u2026). Those helpers are already separate functions, so extracting the branching again is not available. To reduce it, move them out of the body to the enclosing scope, where each is measured, reviewed and tested on its own, and reduce whichever one then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/charts.js"},"region":{"startLine":7}}}],"partialFingerprints":{"codehealthFindingId/v1":"67ed0298a0ff1932226f7819270dadde89bfe0c02bf1b03ed7fa8394de688645"}},{"ruleId":"D2","level":"warning","message":{"text":"RedisBroker._read_blocking (cognitive 35): RedisBroker._read_blocking has cognitive complexity 35 (threshold 15). Drivers by points: if/else 7 (15 pts), loops 6 (15 pts), error handling 3 (5 pts) (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":390}}}],"partialFingerprints":{"codehealthFindingId/v1":"f585d76dcdbf1a0506051a59a53003f990b34c1fdb10e6951e41b63fdd8f3508"}},{"ruleId":"D2","level":"warning","message":{"text":"event_store_subscription.reconstruct_unresolved (cognitive 35): event_store_subscription.reconstruct_unresolved has cognitive complexity 35 (threshold 15). Drivers by points: if/else 10 (21 pts), ternaries 3 (8 pts), boolean chains 3, loops 2 (3 pts) (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"34d9dd705bdf3ed1f9f13a12cb103f5b0e17dfe8e5b1034ac336af5a9fd514fb"}},{"ruleId":"D2","level":"warning","message":{"text":"ir.diff (cognitive 34): ir.diff has cognitive complexity 34 (threshold 15). Drivers by points: if/else 19 (24 pts), boolean chains 9, error handling 1 (nesting depth added 5). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"4952466d9467946fb100ab0b4aa6a4c8ef505680180cd9a51809a22a7d453885"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_unraised_event (cognitive 34): IRBuilder._diagnose_unraised_event has cognitive complexity 34 (threshold 15). Drivers by points: if/else 7 (18 pts), loops 7 (15 pts), boolean chains 1 (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3212}}}],"partialFingerprints":{"codehealthFindingId/v1":"f72132ee4410f0b36a6032784220a9c1aed3d1e3bc5e8cc89e8745a6acd26d59"}},{"ruleId":"D2","level":"warning","message":{"text":"OutboxProcessor._process_single_message (cognitive 34): OutboxProcessor._process_single_message has cognitive complexity 34 (threshold 15). Drivers by points: if/else 10 (16 pts), ternaries 5 (8 pts), error handling 3 (6 pts), boolean chains 4 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/outbox_processor.py"},"region":{"startLine":358}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e884557066fb9dc4413e3aefcda99539f6c18da09019b13f8ee6a607c1ddfb6"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseCommand._build_metadata (cognitive 33): BaseCommand._build_metadata has cognitive complexity 33 (threshold 15). Drivers by points: if/else 11 (15 pts), boolean chains 11, ternaries 7 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"8865cda411b29643a53e76e97da2174e8dfd642f2c75d9c0f1eb15cfcba41815"}},{"ruleId":"D2","level":"warning","message":{"text":"Domain._register_element (cognitive 33): Domain._register_element has cognitive complexity 33 (threshold 15). Drivers by points: if/else 12 (21 pts), boolean chains 8, loops 2 (4 pts) (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":1046}}}],"partialFingerprints":{"codehealthFindingId/v1":"21c943dc93b46f4f60b5bebe8d9f4573859fa5e81f519c5e9da2bc3b0463e35a"}},{"ruleId":"D2","level":"warning","message":{"text":"subscription_status._collect_partitioned_stream_status (cognitive 33): subscription_status._collect_partitioned_stream_status has cognitive complexity 33 (threshold 15). Drivers by points: if/else 9 (22 pts), loops 3 (5 pts), error handling 2 (3 pts), boolean chains 2, ternaries 1 (nesting depth added 16). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":321}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d3e17f16460140fd08668e6361d5f3ff38a2bfe42d5b073afb272b341438598"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_opportunities._apply_import (cognitive 33): upgrade_opportunities._apply_import has cognitive complexity 33 (threshold 15). Drivers by points: if/else 6 (16 pts), loops 3 (7 pts), boolean chains 5, ternaries 2 (5 pts) (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":530}}}],"partialFingerprints":{"codehealthFindingId/v1":"e867f5b5ccc8abbc42421d137cd40a3be0598536aca67676a1f1b98667ecb224"}},{"ruleId":"D2","level":"warning","message":{"text":"entity.entity_factory (cognitive 32): entity.entity_factory has cognitive complexity 32 (threshold 15). Drivers by points: if/else 10 (22 pts), loops 4 (7 pts), boolean chains 3 (nesting depth added 15). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":1189}}}],"partialFingerprints":{"codehealthFindingId/v1":"e72b65eb82d4ad91ff15ad34709f42e11c37163bfd34e1f616b4cbcf7bc7e8fa"}},{"ruleId":"D2","level":"warning","message":{"text":"CommandProcessor.enrich (cognitive 32): CommandProcessor.enrich has cognitive complexity 32 (threshold 15). Drivers by points: if/else 13 (21 pts), boolean chains 5, ternaries 4, loops 1 (2 pts) (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/command_processor.py"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"e72b3558d8068f0f01f8a9c96f2ea6cdd6a0e42070bf477db106fe9a7b0f54c1"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._build_vo_cluster_map (cognitive 32): IRBuilder._build_vo_cluster_map has cognitive complexity 32 (threshold 15). Drivers by points: if/else 7 (25 pts), loops 4 (7 pts) (nesting depth added 21). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1424}}}],"partialFingerprints":{"codehealthFindingId/v1":"d641b6ef6a84e3e54e2edf2eb70c132109eaad1449124bdb19353319f2860ce4"}},{"ruleId":"D2","level":"warning","message":{"text":"events._render_process_manager_subgraph (cognitive 32): events._render_process_manager_subgraph has cognitive complexity 32 (threshold 15). Drivers by points: if/else 9 (25 pts), loops 4 (7 pts) (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":316}}}],"partialFingerprints":{"codehealthFindingId/v1":"2abb88d9a8ebbf7ae3f36350c5d4463f057cf03b03cec92bcf73893a76b2cee3"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers._render_process_managers (cognitive 32): handlers._render_process_managers has cognitive complexity 32 (threshold 15). Drivers by points: if/else 9 (25 pts), loops 4 (7 pts) (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/handlers.py"},"region":{"startLine":155}}}],"partialFingerprints":{"codehealthFindingId/v1":"ecc4446c405e0fc2941247cb4e93ebaf9f420e626acbfd58ed872a11c30b94bc"}},{"ruleId":"D2","level":"warning","message":{"text":"StreamSubscription.poll (cognitive 32): StreamSubscription.poll has cognitive complexity 32 (threshold 15). Drivers by points: if/else 10 (26 pts), error handling 2 (4 pts), boolean chains 1, loops 1 (nesting depth added 18). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/stream_subscription.py"},"region":{"startLine":344}}}],"partialFingerprints":{"codehealthFindingId/v1":"a39cc91ef911c635b1864fe52f957c8523676ba7ec90ad0321b79f815646f97e"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._showEventDetail (cognitive 32): timeline._showEventDetail has cognitive complexity 32 (threshold 15). Drivers by points: if/else 16 (21 pts), boolean chains 9, error handling 1, ternaries 1 (nesting depth added 5). Of this number, 24 points are the body\u0027s own statements and 8 belong to 3 function literals inside it that branch. To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":830}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a1336ecbe5cab1cd2946686d48ca473f7a131803302ce0fda09e662716dcbf7"}},{"ruleId":"D2","level":"warning","message":{"text":"events._render_process_managers (cognitive 31): events._render_process_managers has cognitive complexity 31 (threshold 15). Drivers by points: if/else 8 (24 pts), loops 4 (7 pts) (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c329a5d042eb94a210dfae023db85c90fda7e1f0f6169e10c7ce8c2f3d15717"}},{"ruleId":"D2","level":"warning","message":{"text":"model_parser._parse_constraints (cognitive 31): model_parser._parse_constraints has cognitive complexity 31 (threshold 15). Drivers by points: if/else 11 (26 pts), error handling 1 (3 pts), boolean chains 1, loops 1 (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":459}}}],"partialFingerprints":{"codehealthFindingId/v1":"7cc9539095b8157dbb3adcb911fae124c2750884e2e84bfb73ac26e907068591"}},{"ruleId":"D2","level":"warning","message":{"text":"domain._build_links (cognitive 31): domain._build_links has cognitive complexity 31 (threshold 15). Drivers by points: if/else 4 (16 pts), loops 7 (14 pts), boolean chains 1 (nesting depth added 19). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/domain.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"e869446ef9279ec38d35b615a2ffb59406ec7f1668b7f7e7909a9867cc08c525"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_switchCausationView (cognitive 31): (anonymous)::_switchCausationView has cognitive complexity 31 (threshold 15). Drivers by points: if/else 12 (21 pts), boolean chains 5, ternaries 3 (5 pts) (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"328ad7b0c0b67ae97fdcb4eb98e99d05fdf673f1db4cee1de3245c75c61abac6"}},{"ruleId":"D2","level":"warning","message":{"text":"RedisBroker._read (cognitive 30): RedisBroker._read has cognitive complexity 30 (threshold 15). Drivers by points: if/else 7 (22 pts), loops 2 (5 pts), boolean chains 2, error handling 1 (nesting depth added 18). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":342}}}],"partialFingerprints":{"codehealthFindingId/v1":"43637d43ece872ee0a33627aed6eec4cf7ae005c31a5d45867771626d0ccc232"}},{"ruleId":"D2","level":"warning","message":{"text":"Engine._wire_components (cognitive 30): Engine._wire_components has cognitive complexity 30 (threshold 15). Drivers by points: if/else 7 (15 pts), loops 5 (10 pts), error handling 2 (4 pts), boolean chains 1 (nesting depth added 15). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":347}}}],"partialFingerprints":{"codehealthFindingId/v1":"638d3201002be7386d74285eaf32ab60ea58cfbb6352016ae63a61e79da6a66a"}},{"ruleId":"D2","level":"warning","message":{"text":"domain._build_pm_graphs (cognitive 30): domain._build_pm_graphs has cognitive complexity 30 (threshold 15). Drivers by points: if/else 10 (20 pts), loops 5 (10 pts) (nesting depth added 15). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/domain.py"},"region":{"startLine":353}}}],"partialFingerprints":{"codehealthFindingId/v1":"9813850c95eecf9bf91e5f7c92c80bf7d333467dc429edae7a10678c645adf8a"}},{"ruleId":"D2","level":"warning","message":{"text":"subscription_status._collect_broker_status (cognitive 30): subscription_status._collect_broker_status has cognitive complexity 30 (threshold 15). Drivers by points: if/else 6 (14 pts), error handling 4 (8 pts), boolean chains 3, ternaries 2 (3 pts), loops 1 (2 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":567}}}],"partialFingerprints":{"codehealthFindingId/v1":"017ba8e91ca97b4e7b1015e6ea1990e5a4f72e009f434c6f155e4b3a2d5045dc"}},{"ruleId":"D2","level":"warning","message":{"text":"diff._classify_field_changes (cognitive 29): diff._classify_field_changes has cognitive complexity 29 (threshold 15). Drivers by points: if/else 12 (23 pts), loops 4, boolean chains 2 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1224}}}],"partialFingerprints":{"codehealthFindingId/v1":"abddd71bde6a3b15cf0020b31b312811d0c0a89f7eed25ff0d19aefdd46b9c40"}},{"ruleId":"D2","level":"warning","message":{"text":"domain._wireSearch (cognitive 29): domain._wireSearch has cognitive complexity 29 (threshold 15). Drivers by points: if/else 14 (17 pts), ternaries 6 (9 pts), boolean chains 3 (nesting depth added 6). Most of this is not in the body itself: 5 of the 29 points are its own statements and the rest belongs to 5 function literals inside it that branch (lines 256, 247, 169, \u2026). The decisions are inside those literals, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literals\u0027 work into a named function or method at the enclosing scope and have each literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain.js"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"63a17286bd21e74084ddab2577290e3a3f86d81bc6fc25d422623a4dafd0b10f"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_showEventDetail (cognitive 29): (anonymous)::_showEventDetail has cognitive complexity 29 (threshold 15). Drivers by points: if/else 13 (15 pts), ternaries 6 (8 pts), boolean chains 5, error handling 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":830}}}],"partialFingerprints":{"codehealthFindingId/v1":"e8df9b8acc234995dcf2edb68caff6acc05b2a7dbbebcee39325a919dfc25208"}},{"ruleId":"D2","level":"warning","message":{"text":"cli.server (cognitive 28): cli.server has cognitive complexity 28 (threshold 15). Drivers by points: if/else 12 (20 pts), error handling 3 (6 pts), boolean chains 2 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/__init__.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"d6a623c0853c577ba6bf8fde29055205764d51636a77dc1c1d6456c15406313a"}},{"ruleId":"D2","level":"warning","message":{"text":"ir._print_element_changes (cognitive 28): ir._print_element_changes has cognitive complexity 28 (threshold 15). Drivers by points: loops 11 (20 pts), if/else 4 (5 pts), ternaries 1 (3 pts) (nesting depth added 12). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":495}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ccc09349a1b06c23ceabef6d301c2bcd4090a931ee2d0bf8555cae432095893"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEvent._build_metadata (cognitive 28): BaseEvent._build_metadata has cognitive complexity 28 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 10, ternaries 5 (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/event.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"c96b9e0908c315d9542177b0d082bb9bf05ef1152af4d67a49d74e72e49ccf9b"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseProjection.__init__ (cognitive 28): BaseProjection.__init__ has cognitive complexity 28 (threshold 15). Drivers by points: if/else 7 (17 pts), loops 5 (10 pts), error handling 1 (nesting depth added 15). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":224}}}],"partialFingerprints":{"codehealthFindingId/v1":"2533a3dcae324afb4dfd71c05e8253efd8c833c23db83badfb5a4cf865b34030"}},{"ruleId":"D2","level":"warning","message":{"text":"Engine.handle_message (cognitive 28): Engine.handle_message has cognitive complexity 28 (threshold 15). Drivers by points: if/else 10, boolean chains 7, ternaries 5 (7 pts), error handling 3 (4 pts) (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":815}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2c5142e3a7313935fd8196246662c3f2cfd2fce41597baa87e16e5bfd9003d5"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers.collect_per_handler_trace_metrics (cognitive 28): handlers.collect_per_handler_trace_metrics has cognitive complexity 28 (threshold 15). Drivers by points: if/else 9 (18 pts), ternaries 2 (4 pts), error handling 2 (3 pts), loops 2, boolean chains 1 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":328}}}],"partialFingerprints":{"codehealthFindingId/v1":"533a6d4c5dfb1346e293c58d259053361bcb113bd5238607e5faad2c24bde103"}},{"ruleId":"D2","level":"warning","message":{"text":"processes.merge_pm_subscription_status (cognitive 28): processes.merge_pm_subscription_status has cognitive complexity 28 (threshold 15). Drivers by points: if/else 4 (14 pts), loops 4 (6 pts), ternaries 1 (5 pts), error handling 1 (2 pts), boolean chains 1 (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/processes.py"},"region":{"startLine":137}}}],"partialFingerprints":{"codehealthFindingId/v1":"4a0eb99e42e8cd3f7a8e2eba21c32564e4e7713860a800fa1e98ab798f46c369"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._load_traces_for_correlation (cognitive 28): timeline._load_traces_for_correlation has cognitive complexity 28 (threshold 15). Drivers by points: if/else 7 (15 pts), error handling 4 (9 pts), boolean chains 2, loops 2 (nesting depth added 13). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":518}}}],"partialFingerprints":{"codehealthFindingId/v1":"90fcd88876a683250112466b69df72edd4a25fe09562b5490ef0af47ee5ea9ce"}},{"ruleId":"D2","level":"warning","message":{"text":"subscription_status.collect_subscription_statuses (cognitive 28): subscription_status.collect_subscription_statuses has cognitive complexity 28 (threshold 15). Drivers by points: if/else 8 (14 pts), loops 8 (10 pts), error handling 2 (4 pts) (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":808}}}],"partialFingerprints":{"codehealthFindingId/v1":"17576746b7a7a84e3f08f2e51ca99ae5d34ec686c1f2d4c9cd7dc1d32c52e227"}},{"ruleId":"D2","level":"warning","message":{"text":"dlq.discover_subscriptions (cognitive 28): dlq.discover_subscriptions has cognitive complexity 28 (threshold 15). Drivers by points: if/else 7 (15 pts), loops 7 (11 pts), ternaries 1 (2 pts) (nesting depth added 13). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/dlq.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e71597ef19a503be7186d9f46ea7076897bc7d78697f4ab5a2e8ad5add9452a"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers._renderTable (cognitive 28): handlers._renderTable has cognitive complexity 28 (threshold 15). Drivers by points: if/else 5 (10 pts), ternaries 9, boolean chains 7, loops 1 (2 pts) (nesting depth added 6). Of this number, 14 points are the body\u0027s own statements and 14 belong to one function literal inside it that branches. To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"f855daaed461132ca73d570721c7a4ea334e597c1d3819446ce80a8bdae53a25"}},{"ruleId":"D2","level":"warning","message":{"text":"value_object.value_object_from_entity (cognitive 27): value_object.value_object_from_entity has cognitive complexity 27 (threshold 15). Drivers by points: if/else 9 (21 pts), boolean chains 4, loops 2 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/value_object.py"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"fe205814e1853b3af17420dd08bf74bb8d988c1b807c2c0d462334ecd7afda57"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._extract_fields (cognitive 27): IRBuilder._extract_fields has cognitive complexity 27 (threshold 15). Drivers by points: if/else 11 (26 pts), loops 1 (nesting depth added 15). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":353}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7dc631b5b476fda61ee55c559b06b88d3b93a868a18c883da3725417cb46f63"}},{"ruleId":"D2","level":"warning","message":{"text":"profiles.build_profile_registry (cognitive 27): profiles.build_profile_registry has cognitive complexity 27 (threshold 15). Drivers by points: if/else 14 (26 pts), loops 1 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":243}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c2d060f58385ae3eef237e879ddd5aa168898bf2d81b64284c1ebecada8f246"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_readURL (cognitive 27): (anonymous)::_readURL has cognitive complexity 27 (threshold 15). Drivers by points: if/else 14 (19 pts), boolean chains 6, ternaries 1 (2 pts) (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"63b1fe8bc049ca66821d28c21c905015d1571a6ddc7a0a26f7a4694a66c6742d"}},{"ruleId":"D2","level":"warning","message":{"text":"docs.generate (cognitive 26): docs.generate has cognitive complexity 26 (threshold 15). Drivers by points: if/else 14 (15 pts), boolean chains 8, ternaries 3 (nesting depth added 1). To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/docs.py"},"region":{"startLine":101}}}],"partialFingerprints":{"codehealthFindingId/v1":"16e6a540abaf972ad33d5fe1cf17c18af0c569b5deb234f85045d0aeb7b1ca64"}},{"ruleId":"D2","level":"warning","message":{"text":"ir._print_diff_text (cognitive 26): ir._print_diff_text has cognitive complexity 26 (threshold 15). Drivers by points: loops 7 (14 pts), if/else 9 (11 pts), boolean chains 1 (nesting depth added 9). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":385}}}],"partialFingerprints":{"codehealthFindingId/v1":"af3194b3b6be5cf7426c0b4f2234755c2e2dddbc63e5e0d814993ecc0a76de4b"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseProjection.model_post_init (cognitive 26): BaseProjection.model_post_init has cognitive complexity 26 (threshold 15). Drivers by points: if/else 6 (14 pts), loops 6 (9 pts), boolean chains 3 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":291}}}],"partialFingerprints":{"codehealthFindingId/v1":"82c4bbd0964aacb4c74d98ac23a2475194bcb0241c1508fbb21a45e2936362b6"}},{"ruleId":"D2","level":"warning","message":{"text":"Domain._traverse (cognitive 26): Domain._traverse has cognitive complexity 26 (threshold 15). Drivers by points: if/else 9 (19 pts), loops 3 (4 pts), boolean chains 3 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":795}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c8d86a0bef1bed759749645e06e38ea7795aa129a56e06937d9ac840694f050"}},{"ruleId":"D2","level":"warning","message":{"text":"clusters._collect_cross_references (cognitive 26): clusters._collect_cross_references has cognitive complexity 26 (threshold 15). Drivers by points: if/else 4 (16 pts), loops 4 (8 pts), boolean chains 2 (nesting depth added 16). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/clusters.py"},"region":{"startLine":119}}}],"partialFingerprints":{"codehealthFindingId/v1":"b6ee3ee7356d18732d37fe08c4097848271878c5373430e25c92e101118594cc"}},{"ruleId":"D2","level":"warning","message":{"text":"events._collect_referenced_event_fqns (cognitive 26): events._collect_referenced_event_fqns has cognitive complexity 26 (threshold 15). Drivers by points: loops 8 (15 pts), if/else 3 (11 pts) (nesting depth added 15). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":256}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c6c56efa6593b401ff696a396b81f96bd8bc70020e473ae0770151d63159cea"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEventStore.verify (cognitive 26): BaseEventStore.verify has cognitive complexity 26 (threshold 15). Drivers by points: if/else 9 (18 pts), boolean chains 3, ternaries 1 (3 pts), loops 2 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1194}}}],"partialFingerprints":{"codehealthFindingId/v1":"c2b2e0a980b2c8d0c822a0f76978f1c6b0952597e114e8d5bba2054fa3920f2e"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers.collect_handler_metadata (cognitive 26): handlers.collect_handler_metadata has cognitive complexity 26 (threshold 15). Drivers by points: if/else 4 (10 pts), ternaries 2 (10 pts), loops 3 (6 pts) (nesting depth added 17). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"12164b3fc9cc94d6f2276a74544ba84f797503f1eb121d4e6566ca007922e50d"}},{"ruleId":"D2","level":"warning","message":{"text":"processes.collect_pm_trace_metrics (cognitive 26): processes.collect_pm_trace_metrics has cognitive complexity 26 (threshold 15). Drivers by points: if/else 7 (14 pts), ternaries 2 (4 pts), boolean chains 3, error handling 2 (3 pts), loops 2 (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/processes.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"cb7a4bba5eb5f6a9172e1778bcd1be7f591c18dadd208353d7b292642166fc9c"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade._check_outbox_schema (cognitive 26): upgrade._check_outbox_schema has cognitive complexity 26 (threshold 15). Drivers by points: if/else 9 (19 pts), error handling 2 (3 pts), loops 2 (3 pts), boolean chains 1 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade.py"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"065020c0beb2cf376cb2ddc45a9d540ad1507dcefb3f69e2d9ac9cf067e5b313"}},{"ruleId":"D2","level":"warning","message":{"text":"handlers._sorted (cognitive 26): handlers._sorted has cognitive complexity 26 (threshold 15). Drivers by points: boolean chains 22, ternaries 2 (3 pts), match/switch 1 (nesting depth added 1). Most of this is not in the body itself: 0 of the 26 points are its own statements and the rest belongs to one function literal inside it that branches (line 56). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"2d2b200e3df89cae534a3e1573bf4940ec5e086c554235fc5424b41e0177c0da"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._switchCausationView (cognitive 26): timeline._switchCausationView has cognitive complexity 26 (threshold 15). Drivers by points: if/else 12 (21 pts), boolean chains 4, ternaries 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"71c978fb297e76dc2fa592621b3db03fd6c5f4544742b267f78a5faff3aa7896"}},{"ruleId":"D2","level":"warning","message":{"text":"HasOne.__set__ (cognitive 25): HasOne.__set__ has cognitive complexity 25 (threshold 15). Drivers by points: if/else 14 (19 pts), boolean chains 3, loops 1 (3 pts) (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":429}}}],"partialFingerprints":{"codehealthFindingId/v1":"84ff88f94bef86a17afc333aa2c1a5dc2b72d0fe3863a6dcb5306cb8f6244035"}},{"ruleId":"D2","level":"warning","message":{"text":"_FlowBuilder._step_simple (cognitive 25): _FlowBuilder._step_simple has cognitive complexity 25 (threshold 15). Drivers by points: if/else 10 (15 pts), loops 5 (9 pts), boolean chains 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/dataflow.py"},"region":{"startLine":688}}}],"partialFingerprints":{"codehealthFindingId/v1":"3a2fb18f4f3b96a49fe099a031a1b5f6d4f99a4b910fd37134c2fd25b3eddfb8"}},{"ruleId":"D2","level":"warning","message":{"text":"SourceProvider._discover_modules (cognitive 25): SourceProvider._discover_modules has cognitive complexity 25 (threshold 15). Drivers by points: if/else 7 (14 pts), loops 3 (4 pts), boolean chains 3, error handling 2 (3 pts), ternaries 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/source_provider.py"},"region":{"startLine":220}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d4cd5b2be4340250f2e8710e5b2b33920c64118cd65354ad713135d752831b6"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_adapter_calls (cognitive 25): IRBuilder._diagnose_adapter_calls has cognitive complexity 25 (threshold 15). Drivers by points: if/else 5 (15 pts), loops 5 (9 pts), boolean chains 1 (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2110}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f020911112f3ce35117e98fb6df1161197d15d5ac1cefc331491045d983d583"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline.search_traces (cognitive 25): timeline.search_traces has cognitive complexity 25 (threshold 15). Drivers by points: if/else 7 (17 pts), boolean chains 4, loops 3 (4 pts) (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":850}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e35c7e4bfd0bc5dbaf4907f88fcb6fdc6a5e88f387c88d688311d0377ff30f2"}},{"ruleId":"D2","level":"warning","message":{"text":"Message.to_cloudevent (cognitive 25): Message.to_cloudevent has cognitive complexity 25 (threshold 15). Drivers by points: if/else 12 (17 pts), ternaries 3 (5 pts), boolean chains 3 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":1223}}}],"partialFingerprints":{"codehealthFindingId/v1":"67b67141a03df5dad0d725779001ed2a05bf4e2f3889a4722d9b7ca02455b438"}},{"ruleId":"D2","level":"warning","message":{"text":"overview.updateSubscriptions (cognitive 25): overview.updateSubscriptions has cognitive complexity 25 (threshold 15). Drivers by points: if/else 8 (12 pts), boolean chains 9, loops 3 (4 pts) (nesting depth added 5). Of this number, 22 points are the body\u0027s own statements and 3 belong to 2 function literals inside it that branch. To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"557ea33065473c6aadaf6a40b5003811adac8975ef4283190d53e96cf256bec0"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._readURL (cognitive 25): timeline._readURL has cognitive complexity 25 (threshold 15). Drivers by points: if/else 14 (19 pts), boolean chains 6 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd37b5e91aa96b239912c5472d9f82d47ce73f72db68ad1f339e787c25542c0f"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_renderCausationTree (cognitive 25): (anonymous)::_renderCausationTree has cognitive complexity 25 (threshold 15). Drivers by points: boolean chains 9, ternaries 9, if/else 5, loops 1 (2 pts) (nesting depth added 1). To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"233858867104ada59391b32709eefe68db965845f0129446fb8a83fbe15dedbe"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseAggregate.raise_ (cognitive 24): BaseAggregate.raise_ has cognitive complexity 24 (threshold 15). Drivers by points: if/else 12 (16 pts), boolean chains 3, ternaries 3, loops 1 (2 pts) (nesting depth added 5). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc1cfcbacdd0b5f013620dccb1a1b15b4f380a0cf56f877d7fa7fae03c9eb06d"}},{"ruleId":"D2","level":"warning","message":{"text":"HasMany.remove (cognitive 24): HasMany.remove has cognitive complexity 24 (threshold 15). Drivers by points: if/else 8 (15 pts), loops 3 (5 pts), boolean chains 3, ternaries 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":712}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5e032349510869f4e6dcbf0123901adb3d03550d3a95380c2f51f99bd94f91d"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_event_handler_foreign_event (cognitive 24): IRBuilder._diagnose_event_handler_foreign_event has cognitive complexity 24 (threshold 15). Drivers by points: if/else 5 (15 pts), loops 5 (9 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2178}}}],"partialFingerprints":{"codehealthFindingId/v1":"f576dbb983dcae7e4af7acf67fd76628a2abd6c08dd6431fa5bbe87f1a42bae8"}},{"ruleId":"D2","level":"warning","message":{"text":"apply.apply_plan (cognitive 24): apply.apply_plan has cognitive complexity 24 (threshold 15). Drivers by points: if/else 9 (17 pts), loops 3, ternaries 1 (2 pts), boolean chains 1, error handling 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/apply.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"6b936c112638e16ca0f215082c89aeb94511ff15869f904fdb8c4ad2fb67f467"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_opportunities._scan_scope (cognitive 24): upgrade_opportunities._scan_scope has cognitive complexity 24 (threshold 15). Drivers by points: if/else 6 (17 pts), loops 4 (7 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":794}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce358736a376eab6c13129efdcc6b0faa0efeea7572140b7c5ed976f66ff49be"}},{"ruleId":"D2","level":"warning","message":{"text":"processes._sorted (cognitive 24): processes._sorted has cognitive complexity 24 (threshold 15). Drivers by points: boolean chains 20, ternaries 2 (3 pts), match/switch 1 (nesting depth added 1). Most of this is not in the body itself: 0 of the 24 points are its own statements and the rest belongs to one function literal inside it that branches (line 49). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"f81a1734909c1f262f9b3c8de1ac4e8a97245a4a9f9b84c9a3c4e787510dc941"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._renderCausationTree (cognitive 24): timeline._renderCausationTree has cognitive complexity 24 (threshold 15). Drivers by points: boolean chains 10, if/else 6, ternaries 6, loops 1 (2 pts) (nesting depth added 1). Of this number, 22 points are the body\u0027s own statements and 2 belong to one function literal inside it that branches. To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"758a97846dc86a98a454c6fab557616319d1bbba67e722e39ab0ea8bd6266cf9"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._fetchLatestEvent (cognitive 24): timeline._fetchLatestEvent has cognitive complexity 24 (threshold 15). Drivers by points: if/else 13 (18 pts), boolean chains 3, loops 1 (2 pts), error handling 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1320}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c149ed07761645abfd3581dd4823b255674b0db211b385ded0e94ab5e3131f5"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_updateCorrelationDisplay (cognitive 24): (anonymous)::_updateCorrelationDisplay has cognitive complexity 24 (threshold 15). Drivers by points: if/else 13 (20 pts), boolean chains 2, ternaries 1 (2 pts) (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":400}}}],"partialFingerprints":{"codehealthFindingId/v1":"4506d9d0cd2e8cf57e1372b89922cf3e428bbd3a5b7fb628b4509654624c9599"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_renderAggregateTimeline (cognitive 24): (anonymous)::_renderAggregateTimeline has cognitive complexity 24 (threshold 15). Drivers by points: ternaries 10 (20 pts), boolean chains 3, loops 1 (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"5870bfa9ee5b2c4a887b47e5d8def0091a858294c87b69a24172f310906db222"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_fetchLatestEvent (cognitive 24): (anonymous)::_fetchLatestEvent has cognitive complexity 24 (threshold 15). Drivers by points: if/else 13 (18 pts), boolean chains 3, loops 1 (2 pts), error handling 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1320}}}],"partialFingerprints":{"codehealthFindingId/v1":"f79a909a3ccc4f7fc7fa164ad99a7658e42863d7769c44c1d5fb678aa35adf1a"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_renderSwimlanes (cognitive 24): (anonymous)::_renderSwimlanes has cognitive complexity 24 (threshold 15). Drivers by points: if/else 8 (16 pts), ternaries 2 (4 pts), loops 2 (3 pts), boolean chains 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":484}}}],"partialFingerprints":{"codehealthFindingId/v1":"d261d42aa592cb744cdf4dae685fdfc92cd308d928451b0f31763c2c9ff731ef"}},{"ruleId":"D2","level":"warning","message":{"text":"Brokers._initialize (cognitive 23): Brokers._initialize has cognitive complexity 23 (threshold 15). Drivers by points: if/else 6 (9 pts), error handling 3 (7 pts), loops 4 (5 pts), boolean chains 2 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/__init__.py"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"db2f96c9a2498439f12a1622a56aec58b7cc456e4223b2846fd98fd8a2da0f57"}},{"ruleId":"D2","level":"warning","message":{"text":"EventStore.handlers_for (cognitive 23): EventStore.handlers_for has cognitive complexity 23 (threshold 15). Drivers by points: if/else 7 (13 pts), loops 3 (8 pts), boolean chains 1, ternaries 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/event_store/__init__.py"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"920592faa233753043b2c558de168972f4bacba3ffe3c76462445747d1c59b6d"}},{"ruleId":"D2","level":"warning","message":{"text":"check._print_rich (cognitive 23): check._print_rich has cognitive complexity 23 (threshold 15). Drivers by points: if/else 10, loops 3 (6 pts), ternaries 2 (6 pts), boolean chains 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/check.py"},"region":{"startLine":306}}}],"partialFingerprints":{"codehealthFindingId/v1":"436413d06f14f2e3bed47e317b2260c19e7553231d5f28348c03bd010516fa0e"}},{"ruleId":"D2","level":"warning","message":{"text":"HasMany.add (cognitive 23): HasMany.add has cognitive complexity 23 (threshold 15). Drivers by points: if/else 6 (11 pts), loops 3 (5 pts), boolean chains 4, ternaries 2, error handling 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":588}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd6aa9cb43ad2e4dccac1b3005c0b83ce524b00757625c352824309df5f6176f"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_unhandled_events (cognitive 23): IRBuilder._diagnose_unhandled_events has cognitive complexity 23 (threshold 15). Drivers by points: if/else 4 (12 pts), loops 7 (10 pts), boolean chains 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2309}}}],"partialFingerprints":{"codehealthFindingId/v1":"14ea43a1af9aa33626bf5354d0e6859f920f7e716bc1b4ca3da876c6b5320fe1"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_cross_aggregate_reference (cognitive 23): IRBuilder._diagnose_cross_aggregate_reference has cognitive complexity 23 (threshold 15). Drivers by points: if/else 5 (16 pts), loops 3 (6 pts), boolean chains 1 (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3036}}}],"partialFingerprints":{"codehealthFindingId/v1":"8cea170cc9514a2b34c0e23214d29d0c6ec5b4b41ecdfbfa27f4faba61f4dc8b"}},{"ruleId":"D2","level":"warning","message":{"text":"overview.updateHealthBanner (cognitive 23): overview.updateHealthBanner has cognitive complexity 23 (threshold 15). Drivers by points: if/else 9 (12 pts), boolean chains 7, ternaries 1 (3 pts), loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"475c3a5cbb26ea9349ed2e3df7d2a9d80ea71e90f39b1474718f787fc0526a64"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::updateHealthBanner (cognitive 23): (anonymous)::updateHealthBanner has cognitive complexity 23 (threshold 15). Drivers by points: if/else 9 (12 pts), boolean chains 7, ternaries 1 (3 pts), loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f74a08370a51702476b9854e42b49abd037401d07435573a7c925dccabf92b8"}},{"ruleId":"D2","level":"warning","message":{"text":"aggregate.aggregate_factory (cognitive 22): aggregate.aggregate_factory has cognitive complexity 22 (threshold 15). Drivers by points: if/else 6 (10 pts), loops 4 (6 pts), boolean chains 5, ternaries 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":625}}}],"partialFingerprints":{"codehealthFindingId/v1":"4750957f14b94b410f5d9d21da7ea7d0cc97eed9f76ab4717b7e54f00d75bc8e"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._build_projections (cognitive 22): IRBuilder._build_projections has cognitive complexity 22 (threshold 15). Drivers by points: if/else 6 (15 pts), loops 6 (7 pts) (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1200}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e7be1ef8a0a8dd93c143c81b14796ea0fad4cd4b6e3233d0886e511ad434a73"}},{"ruleId":"D2","level":"warning","message":{"text":"subscription_status._collect_stream_status (cognitive 22): subscription_status._collect_stream_status has cognitive complexity 22 (threshold 15). Drivers by points: if/else 6 (10 pts), boolean chains 5, error handling 4 (5 pts), loops 1, ternaries 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":451}}}],"partialFingerprints":{"codehealthFindingId/v1":"eb7a3adb7931b0fd2d772a90312ee53e07a8d93e51210fe5f29efde6493e432c"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._updateCorrelationDisplay (cognitive 22): timeline._updateCorrelationDisplay has cognitive complexity 22 (threshold 15). Drivers by points: if/else 13 (20 pts), boolean chains 2 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":400}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ec316af8dd17aedba3a78ee3cd719fecfd86b2819eed94367414b92f1c26068"}},{"ruleId":"D2","level":"warning","message":{"text":"subscriptions.status (cognitive 21): subscriptions.status has cognitive complexity 21 (threshold 15). Drivers by points: if/else 10, ternaries 4 (8 pts), boolean chains 2, loops 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/subscriptions.py"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"3390998792cba020406b8f678d70e3504bf9805a53a2daffbb704615f03017a1"}},{"ruleId":"D2","level":"warning","message":{"text":"aggregate._pydantic_element_to_fact_event (cognitive 21): aggregate._pydantic_element_to_fact_event has cognitive complexity 21 (threshold 15). Drivers by points: if/else 6 (14 pts), ternaries 2 (6 pts), loops 1 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":518}}}],"partialFingerprints":{"codehealthFindingId/v1":"1020c6e504a9a3e98b693c1813c6d2eb13e8327f357e853d9d7cbb92f7a71bf5"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity.__setattr__ (cognitive 21): BaseEntity.__setattr__ has cognitive complexity 21 (threshold 15). Drivers by points: if/else 6 (11 pts), boolean chains 4, ternaries 2 (4 pts), error handling 1 (2 pts) (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":939}}}],"partialFingerprints":{"codehealthFindingId/v1":"81ea2d89094ef52c44721b14a754ac9a44b51cf229207cee98f4005b7e46af78"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseValueObject._resolve_fieldspecs (cognitive 21): BaseValueObject._resolve_fieldspecs has cognitive complexity 21 (threshold 15). Drivers by points: if/else 8 (16 pts), loops 4, boolean chains 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/value_object.py"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"a8a8b1e27f31719673ae2f5efe199d5961366b2bc0741ca0d5d0ca291544df7c"}},{"ruleId":"D2","level":"warning","message":{"text":"mypy_plugin._resolve_field_type_for_init (cognitive 21): mypy_plugin._resolve_field_type_for_init has cognitive complexity 21 (threshold 15). Drivers by points: if/else 7 (11 pts), error handling 3 (8 pts), boolean chains 2 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":810}}}],"partialFingerprints":{"codehealthFindingId/v1":"f21351f6295eb656859ad2d64374535878de1fbb859c5f7abfa363f615625433"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_unbounded_indexed_string (cognitive 21): IRBuilder._diagnose_unbounded_indexed_string has cognitive complexity 21 (threshold 15). Drivers by points: if/else 4 (13 pts), loops 3 (6 pts), boolean chains 2 (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2666}}}],"partialFingerprints":{"codehealthFindingId/v1":"dac6b97420097c19f2c9d564b7ae89eb0c05a155c5ce713f88ea157c3ea9e8b8"}},{"ruleId":"D2","level":"warning","message":{"text":"manifest._derive_domain_name (cognitive 21): manifest._derive_domain_name has cognitive complexity 21 (threshold 15). Drivers by points: if/else 7 (15 pts), loops 2 (3 pts), error handling 2, boolean chains 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/manifest.py"},"region":{"startLine":236}}}],"partialFingerprints":{"codehealthFindingId/v1":"8168bc8f26db9e8c0ecab6d1c3ab414458b26559379df4398861215232244d8e"}},{"ruleId":"D2","level":"warning","message":{"text":"slice_generator._validate_names (cognitive 21): slice_generator._validate_names has cognitive complexity 21 (threshold 15). Drivers by points: if/else 9 (13 pts), loops 5 (6 pts), boolean chains 1, ternaries 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/slice_generator.py"},"region":{"startLine":1134}}}],"partialFingerprints":{"codehealthFindingId/v1":"8884f841009a5c12e740835d5c501eb067081adabf2ec94bd951b30145bd5b09"}},{"ruleId":"D2","level":"warning","message":{"text":"EventStoreSubscription.run_recovery_pass (cognitive 21): EventStoreSubscription.run_recovery_pass has cognitive complexity 21 (threshold 15). Drivers by points: if/else 7 (12 pts), ternaries 3 (6 pts), boolean chains 2, loops 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":1227}}}],"partialFingerprints":{"codehealthFindingId/v1":"da08e32443c07d1bac89a0d083d0d29890afbf34dfa42acfa87e5c5b740ca2c8"}},{"ruleId":"D2","level":"warning","message":{"text":"SubscriptionConfig.validate (cognitive 21): SubscriptionConfig.validate has cognitive complexity 21 (threshold 15). Drivers by points: if/else 15, boolean chains 6. To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"f774b753af994e10fa97a14d71f940f1db78806c50566ad1f5d7dcac7fc2e30d"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_opportunities._sqlalchemy_text_names (cognitive 21): upgrade_opportunities._sqlalchemy_text_names has cognitive complexity 21 (threshold 15). Drivers by points: if/else 3 (10 pts), loops 3 (7 pts), boolean chains 4 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":120}}}],"partialFingerprints":{"codehealthFindingId/v1":"00ceb1220796f22d9072b9acf822e8c646210360c39f593e1a6325854e0a4a2b"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_opportunities._split_scopes (cognitive 21): upgrade_opportunities._split_scopes has cognitive complexity 21 (threshold 15). Drivers by points: if/else 8 (16 pts), loops 2 (4 pts), boolean chains 1 (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":600}}}],"partialFingerprints":{"codehealthFindingId/v1":"058aee7e20f6d11658bd91b68399f99e2518643b0f2ef0d85243abdd2282b13d"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._showCorrelationView (cognitive 21): timeline._showCorrelationView has cognitive complexity 21 (threshold 15). Drivers by points: if/else 14 (17 pts), boolean chains 3, error handling 1 (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"25c9a36c86002e66f79080001df1c9f9154ad0699dcd38a8cb7189cdc193d77d"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._renderAggregateTimeline (cognitive 21): timeline._renderAggregateTimeline has cognitive complexity 21 (threshold 15). Drivers by points: ternaries 6 (12 pts), boolean chains 5, if/else 3, loops 1 (nesting depth added 6). Of this number, 16 points are the body\u0027s own statements and 5 belong to 3 function literals inside it that branch. To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"7f05abc755a34e41093935eee7408127a2be6aaba8a4548eec8d5636768bb7b5"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_showCorrelationView (cognitive 21): (anonymous)::_showCorrelationView has cognitive complexity 21 (threshold 15). Drivers by points: if/else 14 (17 pts), boolean chains 3, error handling 1 (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"a754dfcfc936d6ef8074d39d4f3d271ddd9957dc44a6cad6280def626d45378f"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_showAggregateView (cognitive 21): (anonymous)::_showAggregateView has cognitive complexity 21 (threshold 15). Drivers by points: if/else 13 (16 pts), boolean chains 2, ternaries 1 (2 pts), error handling 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":596}}}],"partialFingerprints":{"codehealthFindingId/v1":"452a55b4afe9fec7b483aa4f71dc3c586b196eccefd738d11f35067fb60eeba0"}},{"ruleId":"D2","level":"warning","message":{"text":"projection.status (cognitive 20): projection.status has cognitive complexity 20 (threshold 15). Drivers by points: if/else 9, ternaries 4 (8 pts), boolean chains 2, loops 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/projection.py"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"80a71d80291a49297abeff8cbe13105760ef65488c8512d55226d082403aa96a"}},{"ruleId":"D2","level":"warning","message":{"text":"index.validate_indexes (cognitive 20): index.validate_indexes has cognitive complexity 20 (threshold 15). Drivers by points: if/else 10 (18 pts), boolean chains 1, loops 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/index.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"009677f04acfa2b614013deb2564c3ee9a45287c332c731ed9b5aa385c892df4"}},{"ruleId":"D2","level":"warning","message":{"text":"mypy_plugin._get_kwarg_bool (cognitive 20): mypy_plugin._get_kwarg_bool has cognitive complexity 20 (threshold 15). Drivers by points: if/else 4 (17 pts), loops 2 (3 pts) (nesting depth added 14). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":1133}}}],"partialFingerprints":{"codehealthFindingId/v1":"7c51e7c15b79f85808e6d6f61ec7025d102f1cf06bd0052d5c274e6a739d790c"}},{"ruleId":"D2","level":"warning","message":{"text":"Field._load (cognitive 20): Field._load has cognitive complexity 20 (threshold 15). Drivers by points: if/else 7 (13 pts), ternaries 2 (5 pts), loops 1 (2 pts) (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/base.py"},"region":{"startLine":291}}}],"partialFingerprints":{"codehealthFindingId/v1":"68f6a8234fb8883edc3a2b45f4ad7d44436bfa83bc8ce3b5523e47a8680a81aa"}},{"ruleId":"D2","level":"warning","message":{"text":"containers.List (cognitive 20): containers.List has cognitive complexity 20 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 4, ternaries 1 (3 pts) (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/containers.py"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"48f91f0fbdc5b84ab057705ecb8922007207b6cc35eb676fd2f8035ce703e058"}},{"ruleId":"D2","level":"warning","message":{"text":"_FlowBuilder._step (cognitive 20): _FlowBuilder._step has cognitive complexity 20 (threshold 15). Drivers by points: if/else 12 (16 pts), loops 1 (2 pts), ternaries 1 (2 pts) (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/dataflow.py"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"9413cf8980fd9b2da30ab99117d248286bb1888c9b6f8ed85603b4983bcdc163"}},{"ruleId":"D2","level":"warning","message":{"text":"config._parse_config (cognitive 20): config._parse_config has cognitive complexity 20 (threshold 15). Drivers by points: if/else 13 (17 pts), boolean chains 3 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/config.py"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"398ddaa7ceb16b382fa841b302727520bf32bad83009a36da7fe5de8a67331fa"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseBroker.publish (cognitive 20): BaseBroker.publish has cognitive complexity 20 (threshold 15). Drivers by points: if/else 8 (14 pts), loops 1 (3 pts), error handling 1 (2 pts), boolean chains 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/broker.py"},"region":{"startLine":255}}}],"partialFingerprints":{"codehealthFindingId/v1":"110b20219691fd86efdb495914c6cab861a247ca89da79a0850e6647adade7f2"}},{"ruleId":"D2","level":"warning","message":{"text":"model_parser.emit_model (cognitive 20): model_parser.emit_model has cognitive complexity 20 (threshold 15). Drivers by points: if/else 9 (12 pts), boolean chains 3, ternaries 1 (3 pts), error handling 1, loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":738}}}],"partialFingerprints":{"codehealthFindingId/v1":"44c8cf691c2bfb5c249763c5ea1bfd2bf38db9a024dc9da8c06606f5aa426bc6"}},{"ruleId":"D2","level":"warning","message":{"text":"Engine._register_handler_subscriptions (cognitive 20): Engine._register_handler_subscriptions has cognitive complexity 20 (threshold 15). Drivers by points: loops 9 (14 pts), if/else 2 (6 pts) (nesting depth added 9). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":512}}}],"partialFingerprints":{"codehealthFindingId/v1":"738ddbe7bce040bf2b313c740d3056d3ad1a8019bf0b49c29654dd9c4cda329f"}},{"ruleId":"D2","level":"warning","message":{"text":"logging.configure_logging (cognitive 20): logging.configure_logging has cognitive complexity 20 (threshold 15). Drivers by points: if/else 9 (12 pts), boolean chains 3, error handling 1 (2 pts), loops 1 (2 pts), ternaries 1 (nesting depth added 5). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/logging.py"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"5c141571ef46b7b64507ac49909278ad3f638a8652b6c5fc10c0f47725c4a162"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline.fetchEvents (cognitive 20): timeline.fetchEvents has cognitive complexity 20 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 3, loops 1 (2 pts), error handling 1, ternaries 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ad0eb67e3682969a64ddbae691335f7d57a96bb4d262ab713284f799e65e8c7"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::fetchEvents (cognitive 20): (anonymous)::fetchEvents has cognitive complexity 20 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 3, loops 1 (2 pts), error handling 1, ternaries 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"ad2b50e0c1e21c78451d711a4f9455153e090d59cd50cb9312885ec9b3440d47"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_transferCollapseState (cognitive 20): (anonymous)::_transferCollapseState has cognitive complexity 20 (threshold 15). Drivers by points: if/else 7 (11 pts), boolean chains 5, loops 2 (4 pts) (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":1112}}}],"partialFingerprints":{"codehealthFindingId/v1":"09e89ebb26b9e77aed142b149b5597ae3e3cb617cfde0d31a791216a132940a7"}},{"ruleId":"D2","level":"warning","message":{"text":"sqlalchemy._make_sa_indexes (cognitive 19): sqlalchemy._make_sa_indexes has cognitive complexity 19 (threshold 15). Drivers by points: if/else 8 (16 pts), ternaries 1 (2 pts), loops 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":408}}}],"partialFingerprints":{"codehealthFindingId/v1":"de3787b60a669d36c86778db37e1185eb1e0c0a6696607b3f3a82e940e91ee2d"}},{"ruleId":"D2","level":"warning","message":{"text":"schema.write_index_ddl (cognitive 19): schema.write_index_ddl has cognitive complexity 19 (threshold 15). Drivers by points: if/else 3 (11 pts), loops 3 (6 pts), boolean chains 2 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/schema.py"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"fca243c256d6146ba15c49f27676b2eba6cb90dabebbc10ed09caed549a7c45d"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEntity._update_data (cognitive 19): BaseEntity._update_data has cognitive complexity 19 (threshold 15). Drivers by points: loops 5 (11 pts), error handling 2 (5 pts), if/else 2 (3 pts) (nesting depth added 10). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":677}}}],"partialFingerprints":{"codehealthFindingId/v1":"3128d7ad9595c1b63ae133ec4f622b8f480188ace7a6516bfc2fdc229aeac77c"}},{"ruleId":"D2","level":"warning","message":{"text":"Domain.configure_logging (cognitive 19): Domain.configure_logging has cognitive complexity 19 (threshold 15). Drivers by points: if/else 10 (12 pts), boolean chains 5, loops 2 (nesting depth added 2). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":2738}}}],"partialFingerprints":{"codehealthFindingId/v1":"6eacb08448802da5d953cc939b6c1e1e13d774b983045c6b41bc2dab6943a8e6"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._extract_indexes (cognitive 19): IRBuilder._extract_indexes has cognitive complexity 19 (threshold 15). Drivers by points: if/else 6 (17 pts), boolean chains 1, loops 1 (nesting depth added 11). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":623}}}],"partialFingerprints":{"codehealthFindingId/v1":"7bfed19e3ef05d2d3113c9fc728d28b1323935b3d19b08754f91346cb5e31ea0"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._run_custom_lint_rules (cognitive 19): IRBuilder._run_custom_lint_rules has cognitive complexity 19 (threshold 15). Drivers by points: if/else 5 (12 pts), error handling 2 (4 pts), loops 2 (3 pts) (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":4014}}}],"partialFingerprints":{"codehealthFindingId/v1":"8025a3d6a427da7d7111d5d84bfa99544af5029583ca8afc6548d2a3c232a381"}},{"ruleId":"D2","level":"warning","message":{"text":"diff._diff_element (cognitive 19): diff._diff_element has cognitive complexity 19 (threshold 15). Drivers by points: if/else 13 (19 pts) (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":280}}}],"partialFingerprints":{"codehealthFindingId/v1":"d327a4820c2f2f8283f670ceec3dec6d33372fcd299830f07df28f5f097a0034"}},{"ruleId":"D2","level":"warning","message":{"text":"diff._classify_clusters (cognitive 19): diff._classify_clusters has cognitive complexity 19 (threshold 15). Drivers by points: loops 7 (14 pts), if/else 2 (5 pts) (nesting depth added 10). To reduce it, break up the iteration: give each loop body a named function, and split a multi-phase loop into one function per phase so no single body carries the whole pipeline."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1075}}}],"partialFingerprints":{"codehealthFindingId/v1":"548b02e6388f0c49e36f521708d953988ceee9502a83bfa36c4550a27157cc4c"}},{"ruleId":"D2","level":"warning","message":{"text":"utils.clone_class (cognitive 19): utils.clone_class has cognitive complexity 19 (threshold 15). Drivers by points: if/else 12 (16 pts), boolean chains 2, loops 1 (nesting depth added 4). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":658}}}],"partialFingerprints":{"codehealthFindingId/v1":"53832be464ac715ac4d15c0cfa14414feabfd1c34ebacb397257407d05d9f549"}},{"ruleId":"D2","level":"warning","message":{"text":"messages.showTraceDetail (cognitive 19): messages.showTraceDetail has cognitive complexity 19 (threshold 15). Drivers by points: boolean chains 12, if/else 5, error handling 1, ternaries 1. To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"a61966b1f0caaa83433c0a09bc4d566f9e5ddf7ab758b45dd6173d594e29c0af"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline.searchTraces (cognitive 19): timeline.searchTraces has cognitive complexity 19 (threshold 15). Drivers by points: boolean chains 10, if/else 7 (8 pts), error handling 1 (nesting depth added 1). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":200}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c59fd468222c40f9caf6cfad5be750cb283a35154c2bf3f51fbb9b33a3d7e63"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._showAggregateView (cognitive 19): timeline._showAggregateView has cognitive complexity 19 (threshold 15). Drivers by points: if/else 13 (16 pts), boolean chains 2, error handling 1 (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":596}}}],"partialFingerprints":{"codehealthFindingId/v1":"804b5ef8465d8a3cc3e313ec7f1705c94bc88b3cf4d789009e17afe4cecd273f"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::searchTraces (cognitive 19): (anonymous)::searchTraces has cognitive complexity 19 (threshold 15). Drivers by points: boolean chains 10, if/else 7 (8 pts), error handling 1 (nesting depth added 1). To reduce it, name the conditions: bind each compound test to a well-named local or a small predicate function, so the body reads as a sequence of named decisions rather than a chain of operators."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":200}}}],"partialFingerprints":{"codehealthFindingId/v1":"ace946f1ed42fd004c323e39b4dbd8e5038f5cd06ad947862f50a19a3688a3cc"}},{"ruleId":"D2","level":"warning","message":{"text":"SADAO._update (cognitive 18): SADAO._update has cognitive complexity 18 (threshold 15). Drivers by points: if/else 7 (12 pts), boolean chains 4, error handling 1, loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":1050}}}],"partialFingerprints":{"codehealthFindingId/v1":"1907e7ca66c893b538b1af2785f08530b5dca00fa32022a66d7f979a71565acd"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseRepository._do_add (cognitive 18): BaseRepository._do_add has cognitive complexity 18 (threshold 15). Drivers by points: if/else 7 (10 pts), boolean chains 7, error handling 1 (nesting depth added 3). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":252}}}],"partialFingerprints":{"codehealthFindingId/v1":"83a5de0bee90b95589753aa231f72901fcacd85aa6be1237ad60b59793784a2d"}},{"ruleId":"D2","level":"warning","message":{"text":"DomainValidator._validate_association_fields (cognitive 18): DomainValidator._validate_association_fields has cognitive complexity 18 (threshold 15). Drivers by points: if/else 4 (15 pts), loops 2 (3 pts) (nesting depth added 12). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/validation.py"},"region":{"startLine":207}}}],"partialFingerprints":{"codehealthFindingId/v1":"d743b993f709b2ecb346f085ea7ee988ff79ef5b731c97f064fdacec38ea6bd1"}},{"ruleId":"D2","level":"warning","message":{"text":"adapter_conformance.pytest_collection_modifyitems (cognitive 18): adapter_conformance.pytest_collection_modifyitems has cognitive complexity 18 (threshold 15). Drivers by points: if/else 4 (11 pts), loops 3 (6 pts), boolean chains 1 (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/integrations/pytest/adapter_conformance.py"},"region":{"startLine":170}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d19de00e1d03a29f4587ce2fa7b298ba84e250828dd2e93db5877df0c0dcdc4"}},{"ruleId":"D2","level":"warning","message":{"text":"element_index._role (cognitive 18): element_index._role has cognitive complexity 18 (threshold 15). Drivers by points: if/else 11 (17 pts), boolean chains 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/analysis/element_index.py"},"region":{"startLine":566}}}],"partialFingerprints":{"codehealthFindingId/v1":"a0871a0ba059ddf9c30a3a6b67f50f8d8e38aac59d78ba0a1c0c9abfd2b49f50"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_circular_cluster_dependencies (cognitive 18): IRBuilder._diagnose_circular_cluster_dependencies has cognitive complexity 18 (threshold 15). Drivers by points: if/else 3 (10 pts), loops 4 (7 pts), boolean chains 1 (nesting depth added 10). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1891}}}],"partialFingerprints":{"codehealthFindingId/v1":"173c675b0356c3cdd42fda7d3d7c4e989c95efd001fadd9361325a3f2bb1f8b4"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._apply_suppressions (cognitive 18): IRBuilder._apply_suppressions has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (13 pts), loops 3 (4 pts), boolean chains 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2232}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c6dacc0e7a358015149bf99e52e00e7ef8dd0e3c75d00d9301b82ec4bad2346"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_deprecated_imports (cognitive 18): IRBuilder._diagnose_deprecated_imports has cognitive complexity 18 (threshold 15). Drivers by points: if/else 4 (10 pts), loops 4 (6 pts), ternaries 1 (2 pts) (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3735}}}],"partialFingerprints":{"codehealthFindingId/v1":"07b7bf79fcbe18e858c26dfb233b95da06f8965b0680e27a3afe12df7e700711"}},{"ruleId":"D2","level":"warning","message":{"text":"event_model.generate_event_model_diff (cognitive 18): event_model.generate_event_model_diff has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (9 pts), loops 7, boolean chains 2 (nesting depth added 3). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/event_model.py"},"region":{"startLine":1059}}}],"partialFingerprints":{"codehealthFindingId/v1":"853cb0410c42c0e4e21d884df86bd4855747f0b84e20d48da4f919fe046c1456"}},{"ruleId":"D2","level":"warning","message":{"text":"schema._field_to_schema (cognitive 18): schema._field_to_schema has cognitive complexity 18 (threshold 15). Drivers by points: if/else 14 (16 pts), boolean chains 2 (nesting depth added 2). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/schema.py"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd2dc37bb5e02b40dcff5fa58e79574c555e7c07862accb3c999ba2022d1f737"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseDAO.save (cognitive 18): BaseDAO.save has cognitive complexity 18 (threshold 15). Drivers by points: if/else 8 (11 pts), boolean chains 3, loops 1 (3 pts), error handling 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/dao.py"},"region":{"startLine":759}}}],"partialFingerprints":{"codehealthFindingId/v1":"23d47788345c44caad55bdcee8838e70015d035284ea8987b12cd957787142e4"}},{"ruleId":"D2","level":"warning","message":{"text":"SubscriptionConfig.from_profile (cognitive 18): SubscriptionConfig.from_profile has cognitive complexity 18 (threshold 15). Drivers by points: ternaries 11, if/else 6, boolean chains 1. To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":582}}}],"partialFingerprints":{"codehealthFindingId/v1":"323632fb6e003953a084b894dfb2dd2538267ae8bd8988a7f1f2704f09de5d40"}},{"ruleId":"D2","level":"warning","message":{"text":"subscription_status._collect_one_recovery_checkpoint (cognitive 18): subscription_status._collect_one_recovery_checkpoint has cognitive complexity 18 (threshold 15). Drivers by points: if/else 7 (8 pts), error handling 3 (5 pts), ternaries 2 (3 pts), boolean chains 1, loops 1 (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":1101}}}],"partialFingerprints":{"codehealthFindingId/v1":"59233e87eb6f3191da2cae08fce4f2624dab10588bd19176a98a08122bbf6288"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade._check_outbox_migrations (cognitive 18): upgrade._check_outbox_migrations has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (12 pts), error handling 2 (3 pts), boolean chains 2, loops 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade.py"},"region":{"startLine":463}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a8f13f4204ec6e4d7a36f4e44db7053df770b3f66b1d9d78853da9038508bf6"}},{"ruleId":"D2","level":"warning","message":{"text":"logging._extract_aggregate_info (cognitive 18): logging._extract_aggregate_info has cognitive complexity 18 (threshold 15). Drivers by points: if/else 6 (16 pts), boolean chains 2 (nesting depth added 10). To reduce it, flatten the nesting: this score is depth rather than breadth \u2014 most of its points come from checks stacked inside one another, so the work sits several levels in. Invert each enclosing check into an early exit (a return, or the language\u0027s equivalent) so the happy path stays at one level, and where a level cannot be exited early, lift the block it encloses into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/logging.py"},"region":{"startLine":387}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a629f530de16024eb42b7ce5d25b6b95ea62682b1534ba335b8bd25bfdc32c5"}},{"ruleId":"D2","level":"warning","message":{"text":"projection_rebuilder._replay_projector (cognitive 18): projection_rebuilder._replay_projector has cognitive complexity 18 (threshold 15). Drivers by points: ternaries 3 (9 pts), error handling 2 (4 pts), boolean chains 3, loops 2 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/projection_rebuilder.py"},"region":{"startLine":172}}}],"partialFingerprints":{"codehealthFindingId/v1":"07188fcf624ed46b34734c9279cbcae58b6d4b97d714640ee0543f784cfb163e"}},{"ruleId":"D2","level":"warning","message":{"text":"processes._renderTable (cognitive 18): processes._renderTable has cognitive complexity 18 (threshold 15). Drivers by points: ternaries 9, boolean chains 7, if/else 2. Most of this is not in the body itself: 2 of the 18 points are its own statements and the rest belongs to one function literal inside it that branches (line 108). The decisions are inside the literal, which nothing outside this body can call, review or test on its own, so splitting the enclosing body is not the move available here. To reduce it, lift the literal\u0027s work into a named function or method at the enclosing scope and have the literal call it, then reduce whichever part then reads as the largest."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"e2887df2f8bc0e195bffa8e744513d9125b6ee5bbc6739926adb1c3e017d532a"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::updateSubscriptions (cognitive 18): (anonymous)::updateSubscriptions has cognitive complexity 18 (threshold 15). Drivers by points: if/else 7 (11 pts), loops 3 (4 pts), boolean chains 3 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"6904eb8505479137d76935f0dc6818c8c7a7e7d58b1a6d59a25443ca21909d45"}},{"ruleId":"D2","level":"warning","message":{"text":"MemorySession.commit (cognitive 17): MemorySession.commit has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (11 pts), loops 3 (4 pts), ternaries 1 (2 pts) (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/memory.py"},"region":{"startLine":194}}}],"partialFingerprints":{"codehealthFindingId/v1":"eed636c10055d9b6ee23176c3e333ed0c93fe6d0376fd37538c7f47885718697"}},{"ruleId":"D2","level":"warning","message":{"text":"DictDAO._check_unique_indexes (cognitive 17): DictDAO._check_unique_indexes has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (12 pts), loops 2 (3 pts), boolean chains 2 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/memory.py"},"region":{"startLine":545}}}],"partialFingerprints":{"codehealthFindingId/v1":"5546cf55890bc5ccff785f3639425119f7d38baa51d767f433ef59a55c027acc"}},{"ruleId":"D2","level":"warning","message":{"text":"docs._generate_handlers (cognitive 17): docs._generate_handlers has cognitive complexity 17 (threshold 15). Drivers by points: if/else 4 (7 pts), ternaries 2 (6 pts), loops 3, boolean chains 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/docs.py"},"region":{"startLine":496}}}],"partialFingerprints":{"codehealthFindingId/v1":"24d3c254dc13e6d0ef1e2a5f9aa134a55f1def105f942a7b6d8a945a2d9b1e72"}},{"ruleId":"D2","level":"warning","message":{"text":"atomic_change._validate_status_transitions (cognitive 17): atomic_change._validate_status_transitions has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (10 pts), ternaries 2 (4 pts), boolean chains 2, loops 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":743}}}],"partialFingerprints":{"codehealthFindingId/v1":"44bbc12646015c93699002ce2b837230591b39b3237afc84b7b0d171cb9b7e10"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_handler_persists_and_calls_out (cognitive 17): IRBuilder._diagnose_handler_persists_and_calls_out has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (13 pts), loops 2 (3 pts), boolean chains 1 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3117}}}],"partialFingerprints":{"codehealthFindingId/v1":"0948d327cc4d0a0cf7bc03f7243a933083eb85d1721c90162757283753b0f869"}},{"ruleId":"D2","level":"warning","message":{"text":"diff._apply_upcaster_mitigation (cognitive 17): diff._apply_upcaster_mitigation has cognitive complexity 17 (threshold 15). Drivers by points: if/else 7 (12 pts), boolean chains 3, loops 2 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1009}}}],"partialFingerprints":{"codehealthFindingId/v1":"981a307e96d6c429971080d58ef58c6813b0a94e800784f4083d3cda734ad56d"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEventStore._load_aggregate_at_version (cognitive 17): BaseEventStore._load_aggregate_at_version has cognitive complexity 17 (threshold 15). Drivers by points: if/else 6 (10 pts), loops 1 (4 pts), error handling 1 (3 pts) (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":560}}}],"partialFingerprints":{"codehealthFindingId/v1":"0a638f6c60ddf4f4e1abecbc0c120cfd33944e434e2971c678e03efcf557ea60"}},{"ruleId":"D2","level":"warning","message":{"text":"model_parser._validate_read_side (cognitive 17): model_parser._validate_read_side has cognitive complexity 17 (threshold 15). Drivers by points: if/else 11 (14 pts), boolean chains 2, loops 1 (nesting depth added 3). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":638}}}],"partialFingerprints":{"codehealthFindingId/v1":"025c8260ca5b523a613b8ce3fb89dd9cd66f63f851f67639a628942eba674c68"}},{"ruleId":"D2","level":"warning","message":{"text":"Engine.shutdown (cognitive 17): Engine.shutdown has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (8 pts), loops 2 (5 pts), ternaries 2, boolean chains 1, error handling 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":1165}}}],"partialFingerprints":{"codehealthFindingId/v1":"69b6dd34346d776a0fbcaeae53f9c8ffdd5c083d2ddcc644cff5ab0c30f2c40c"}},{"ruleId":"D2","level":"warning","message":{"text":"Supervisor._monitor (cognitive 17): Supervisor._monitor has cognitive complexity 17 (threshold 15). Drivers by points: if/else 4 (10 pts), loops 3 (4 pts), boolean chains 2, error handling 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/supervisor.py"},"region":{"startLine":255}}}],"partialFingerprints":{"codehealthFindingId/v1":"5bf059fda761a0e38930d4cd1a295a66df9cdca4342f79aa0ebd0258bc55bc53"}},{"ruleId":"D2","level":"warning","message":{"text":"utils._derive_element_class (cognitive 17): utils._derive_element_class has cognitive complexity 17 (threshold 15). Drivers by points: if/else 10 (13 pts), boolean chains 2, error handling 1 (2 pts) (nesting depth added 4). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":473}}}],"partialFingerprints":{"codehealthFindingId/v1":"43b86b6d1742ce96c5203aa711cfa6e4cb220efa5cd825ce2d7787df14aaa150"}},{"ruleId":"D2","level":"warning","message":{"text":"domain_discovery.find_domain_by_string (cognitive 17): domain_discovery.find_domain_by_string has cognitive complexity 17 (threshold 15). Drivers by points: if/else 7 (10 pts), error handling 3 (6 pts), boolean chains 1 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/domain_discovery.py"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"6beecd9dd708b11bf2d678472b7ac69a494ef84590f11d5182e67d8fa36702b1"}},{"ruleId":"D2","level":"warning","message":{"text":"Message._resolve_field_aliases (cognitive 17): Message._resolve_field_aliases has cognitive complexity 17 (threshold 15). Drivers by points: if/else 5 (10 pts), loops 2 (3 pts), ternaries 2 (3 pts), boolean chains 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":902}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c47e17872a6f31c372ce77ed143f0de14a9f0394714e7d61305eeb00211e81c"}},{"ruleId":"D2","level":"warning","message":{"text":"Message._extract_subject (cognitive 17): Message._extract_subject has cognitive complexity 17 (threshold 15). Drivers by points: if/else 9 (13 pts), ternaries 2 (3 pts), boolean chains 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":1168}}}],"partialFingerprints":{"codehealthFindingId/v1":"b30fd75f2ccea0d5ec4cf0bf75618dcf8d9d0ccf8b9381a0f99e20cfa00bf832"}},{"ruleId":"D2","level":"warning","message":{"text":"RedisBroker._cleanup_stale_consumers (cognitive 16): RedisBroker._cleanup_stale_consumers has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (9 pts), boolean chains 3, error handling 2 (3 pts), loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":865}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e924d9bb68130b85da9c0bf1ab69e8d667200d8b75386d3187bc8ce38733869"}},{"ruleId":"D2","level":"warning","message":{"text":"cli.main (cognitive 16): cli.main has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (11 pts), error handling 2 (4 pts), boolean chains 1 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/__init__.py"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b91c3e7c5f828151ed41e55fd6aa6760c80587ff84bca1802919fee788120a7"}},{"ruleId":"D2","level":"warning","message":{"text":"docs._load_domain_snapshot_config (cognitive 16): docs._load_domain_snapshot_config has cognitive complexity 16 (threshold 15). Drivers by points: if/else 9 (11 pts), boolean chains 2, loops 1 (2 pts), error handling 1 (nesting depth added 3). To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/docs.py"},"region":{"startLine":702}}}],"partialFingerprints":{"codehealthFindingId/v1":"63ec43a339f6545c5ca457ce64c32dc28e592f72b4aaeba4c8d9d62f0292c2fe"}},{"ruleId":"D2","level":"warning","message":{"text":"ir._print_check_text (cognitive 16): ir._print_check_text has cognitive complexity 16 (threshold 15). Drivers by points: if/else 7 (12 pts), boolean chains 2, ternaries 1 (2 pts) (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":648}}}],"partialFingerprints":{"codehealthFindingId/v1":"591cf34c32117af004bcfeb74e3a9b05ae897fd8e2472ab51aaf83fc4d7facda"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseQuery._convert_vo_descriptors (cognitive 16): BaseQuery._convert_vo_descriptors has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (12 pts), loops 4 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/query.py"},"region":{"startLine":128}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f3e1999ced355d685740dcf262273539e1bffaa47ac1d170e68534b41cfc6a6"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseRepository._has_changed_child (cognitive 16): BaseRepository._has_changed_child has cognitive complexity 16 (threshold 15). Drivers by points: if/else 3 (9 pts), loops 2 (4 pts), boolean chains 3 (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":341}}}],"partialFingerprints":{"codehealthFindingId/v1":"4ef47718f6b6fed268515a33e1600cb08df3e9c6954d16e56b1d8b7d79a2755b"}},{"ruleId":"D2","level":"warning","message":{"text":"ResolvedField.__init__ (cognitive 16): ResolvedField.__init__ has cognitive complexity 16 (threshold 15). Drivers by points: if/else 7 (9 pts), ternaries 3, boolean chains 2, loops 1 (2 pts) (nesting depth added 3). To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/resolved.py"},"region":{"startLine":58}}}],"partialFingerprints":{"codehealthFindingId/v1":"56788e66ea5b5403e24f2c1512248bfbc2f3857d52c49db6322edcc7159912fc"}},{"ruleId":"D2","level":"warning","message":{"text":"query_assertions._limit_values (cognitive 16): query_assertions._limit_values has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (12 pts), boolean chains 3, loops 1 (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/integrations/pytest/query_assertions.py"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"d217a2f08b4cbdb1985d66185ea8c913bc00f7626643fbf4bedac097cf716915"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._diagnose_infra_imports (cognitive 16): IRBuilder._diagnose_infra_imports has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (12 pts), loops 3 (4 pts) (nesting depth added 8). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2009}}}],"partialFingerprints":{"codehealthFindingId/v1":"0160084c40bfc3b2d8bc3a94e06ffc2060804c8ea86a8419b5f5577cc64cd3f1"}},{"ruleId":"D2","level":"warning","message":{"text":"IRBuilder._check_element_deprecated (cognitive 16): IRBuilder._check_element_deprecated has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (14 pts), loops 2 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3558}}}],"partialFingerprints":{"codehealthFindingId/v1":"99cb90b053740c44cbf795cec2e777ff60c118280d48c6dd95663d733a9bc73a"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseEventStore._resolve_and_load_group (cognitive 16): BaseEventStore._resolve_and_load_group has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (9 pts), ternaries 2 (4 pts), boolean chains 2, loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":876}}}],"partialFingerprints":{"codehealthFindingId/v1":"f49ca379232cc0afe413e1f9feb37dbfd8d7dc91e18a28c4d7a916b73a928fe3"}},{"ruleId":"D2","level":"warning","message":{"text":"timeline._group_by_correlation (cognitive 16): timeline._group_by_correlation has cognitive complexity 16 (threshold 15). Drivers by points: if/else 3 (8 pts), loops 3 (4 pts), boolean chains 2, error handling 1 (2 pts) (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":738}}}],"partialFingerprints":{"codehealthFindingId/v1":"dc1d6ec2bd8675bfec147ce3ad0a25a6a79c16e95185bbdf5d55e042d5b57147"}},{"ruleId":"D2","level":"warning","message":{"text":"upgrade_opportunities._custom_middleware_sites (cognitive 16): upgrade_opportunities._custom_middleware_sites has cognitive complexity 16 (threshold 15). Drivers by points: if/else 3 (11 pts), loops 2 (3 pts), boolean chains 2 (nesting depth added 9). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":303}}}],"partialFingerprints":{"codehealthFindingId/v1":"ad2ddc4079fc96412c82b48cac6b5bea06b9d1bbcc3e142fb1c4d29192eb619a"}},{"ruleId":"D2","level":"warning","message":{"text":"BaseMessageType._convert_vo_descriptors (cognitive 16): BaseMessageType._convert_vo_descriptors has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (12 pts), loops 4 (nesting depth added 6). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":391}}}],"partialFingerprints":{"codehealthFindingId/v1":"551a08960b7689fb5090f862619da25902c4405402dda38f0a49ff1ce7b2f340"}},{"ruleId":"D2","level":"warning","message":{"text":"Message.to_domain_object (cognitive 16): Message.to_domain_object has cognitive complexity 16 (threshold 15). Drivers by points: if/else 6 (9 pts), ternaries 3 (5 pts), boolean chains 1, error handling 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":975}}}],"partialFingerprints":{"codehealthFindingId/v1":"289f3e4f435872c685a92bebaa990bb0e8221f86ee89cb8b93ef82b179e6768e"}},{"ruleId":"D2","level":"warning","message":{"text":"logging._emit_wide_event (cognitive 16): logging._emit_wide_event has cognitive complexity 16 (threshold 15). Drivers by points: if/else 7 (8 pts), ternaries 4 (5 pts), boolean chains 3 (nesting depth added 2). To reduce it, split the body: most of this score is breadth rather than depth \u2014 checks laid out side by side rather than stacked \u2014 so group the statements between the checks into named steps and move each step into its own function. Some of it IS depth: where a check sits inside another whose only job is to reach it, merge the two into one condition, and where an else follows a branch that already returns, drop the trailing else and let the rest of the body continue at one level."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/logging.py"},"region":{"startLine":695}}}],"partialFingerprints":{"codehealthFindingId/v1":"72afd8e3eacd5ed020417f573fd2f004c5870609ae40af265a85028c657e1bc8"}},{"ruleId":"D2","level":"warning","message":{"text":"HandlerMixin._handle (cognitive 16): HandlerMixin._handle has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (10 pts), ternaries 3, boolean chains 2, error handling 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/mixins.py"},"region":{"startLine":568}}}],"partialFingerprints":{"codehealthFindingId/v1":"ca18591db6176a2ff4c8e89ecdb455d61031df218be2d5c5720bb1de2e0749fd"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::showTraceDetail (cognitive 16): (anonymous)::showTraceDetail has cognitive complexity 16 (threshold 15). Drivers by points: boolean chains 7, if/else 5, ternaries 3, error handling 1. To reduce it, split the body: this score is breadth rather than depth \u2014 many checks laid out side by side rather than nested inside one another, so inverting conditions into early returns has nothing left to flatten. Group the statements between the checks into named steps and move each step into its own function, so the body reads as a short sequence of named stages."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d32babb26354c2f47fb9b439ec5c73d32bcb7f41d8350b8e4071f8c4791903b"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_renderTable (cognitive 16): (anonymous)::_renderTable has cognitive complexity 16 (threshold 15). Drivers by points: if/else 5 (10 pts), boolean chains 2, loops 1 (2 pts), ternaries 1 (2 pts) (nesting depth added 7). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2e01eb8f4f9442d54429dbcaf9f9f2728ca334b293ce0b49d0f53d927d501d8"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous)::_zoomToConnected (cognitive 16): (anonymous)::_zoomToConnected has cognitive complexity 16 (threshold 15). Drivers by points: if/else 8 (13 pts), boolean chains 2, loops 1 (nesting depth added 5). To reduce it, split the body into named stages: move each independent step or branch into its own named function so the body reads as a short sequence of named calls rather than one long body."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":597}}}],"partialFingerprints":{"codehealthFindingId/v1":"62d19be060ec2ebc4c06d13c43b0c4c7d270fff6f437da62da6ad8913d5338e6"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: ir/builder.py: FileTooLong \u2014 2388 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 1888 over it, 4.78\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"4ff17e8f78b4d91a052d911dff0705fcd3a1bff9a28a4e2fd6f53ae98e7463aa"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Domain: TooManyMethods \u2014 131 methods. The bar is 30 methods; this is 101 over it, 4.37\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":210}}}],"partialFingerprints":{"codehealthFindingId/v1":"77af220c63f052a327eca17bc6398014a4be4bf808348e7d2d28fa2b69d0fa57"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: IRBuilder: TooManyMethods \u2014 95 methods. The bar is 30 methods; this is 65 over it, 3.17\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"822aca4d7046ecb8ff860b2d56041dd1733a22cf466c1259b2228ca43522bfe9"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: domain/__init__.py: FileTooLong \u2014 1526 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 1026 over it, 3.05\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f3b67d9c002f06a27defb26b0980976168b1d35a1ee01c20bc7caa729700d5d7"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: repository/sqlalchemy.py: FileTooLong \u2014 1302 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 802 over it, 2.60\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b38a8372cd9e59c696ceec774ffa39acf131eaf14ee140bb5f85ff298b461386"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: js/timeline.js: FileTooLong \u2014 976 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 476 over it, 1.95\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8dbfd758f5797edeec1b132b341cc8017d58acf7cefa9de1a74fda538128dd6d"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: broker/redis.py: FileTooLong \u2014 950 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 450 over it, 1.90\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"bafcd4abd31fcb866a7afcaecbe953ded7ec0cb8a8e20a8e58e1d2030b6e23b9"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: observatory/api.py: FileTooLong \u2014 930 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 430 over it, 1.86\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"4bec9bd4138e942ff2b97a2efb6e7d8135056a089546bcf8a3547205d521beb4"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: RedisBroker: TooManyMethods \u2014 55 methods. The bar is 30 methods; this is 25 over it, 1.83\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"25d6ca9c22319a1ebc95473b4ced5d7364d63db4e54ea025d6882b5a6b2436ec"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: scaffold/slice_generator.py: FileTooLong \u2014 891 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 391 over it, 1.78\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/slice_generator.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8513a9f0dde37e556ca82d82e2882afd6de5e77c30716febd89418c299252c85"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: BaseBroker: TooManyMethods \u2014 53 methods. The bar is 30 methods; this is 23 over it, 1.77\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/broker.py"},"region":{"startLine":121}}}],"partialFingerprints":{"codehealthFindingId/v1":"a97e606a4fc9d2dc4a8883e11e916149efa06a62323fd1e385667d39c6bfd18b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: ir/diff.py: FileTooLong \u2014 880 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 380 over it, 1.76\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f15e0eafd5f2b0324886103aaa32e3a6064197ecae63144a4885ca98e84344ed"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: server/engine.py: FileTooLong \u2014 843 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 343 over it, 1.69\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"be8d529f4d144172c46ef2772f7203a9cbc8fa5c943b8d06f5fb4ca3c5c9d074"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: utils/eventing.py: FileTooLong \u2014 811 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 311 over it, 1.62\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a74484f4a0a75e11cce2b39a653799effb69e5fcf4368e357adf824563a37ec4"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: server/subscription_status.py: FileTooLong \u2014 790 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 290 over it, 1.58\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b15d82fb5ef991dc959f6f657a1062b27b4f5cdc4a98a3788999046a13184079"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: InlineBroker: TooManyMethods \u2014 47 methods. The bar is 30 methods; this is 17 over it, 1.57\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/inline.py"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"2bb5067ece6b4762dfbaa254df7eb29a96bcbeafc80e7a94651a1119ca4d4f3c"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: core/entity.py: FileTooLong \u2014 776 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 276 over it, 1.55\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8158455adf6f7ff1c40ab667c13541b97d9e4463c09f8c3c552cdff3979cc1c8"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: ir/diagnostics.py: FileTooLong \u2014 757 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 257 over it, 1.51\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diagnostics.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"68cee701ced34bd7aa500be31979f283479aba32b11ec13e5b02330c336e34bd"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: subscription/event_store_subscription.py: FileTooLong \u2014 711 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 211 over it, 1.42\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"10127d28d4a50418988be0f2456350963616a92e5393fe1684a13d103611e7dc"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: broker/inline.py: FileTooLong \u2014 709 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 209 over it, 1.42\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/inline.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"457de7c13161cc9631294d2718ceb84662e6b27d7606d6c06ac5f576f81deccd"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: port/event_store.py: FileTooLong \u2014 686 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 186 over it, 1.37\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2d901de82a5019d6b2130f0274b5cb936e66b810c7508282b159307d25b176dc"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: routes/timeline.py: FileTooLong \u2014 672 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 172 over it, 1.34\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ec88535d5d449730abbd2f24c6ce69d730b9d1251ffade31d569dda6a909f9d"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: BaseEventStore: TooManyMethods \u2014 40 methods. The bar is 30 methods; this is 10 over it, 1.33\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"98630b582d5284e1b20b7a3746903c30ba1c76eff5eeee8cf9773432f98b5146"}},{"ruleId":"D3","level":"warning","message":{"text":"FunctionTooLong: timeline._bindEvents: FunctionTooLong \u2014 _bindEvents runs 130 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 30 over it, 1.30\u00D7 the bar. This is length, not branching: a long straight-line body scores low on complexity and is still read whole to change any part of it, so the complexity numbers beside this row neither confirm nor excuse it. To reduce it, extract each cohesive step of the body \u2014 the runs of statements that work on the same values and would earn the same name \u2014 into its own named unit, and have this one call them in order."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1081}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a168d7498fabc5023e5a12c4ddeafd9c2f0e16f82d0671eb1391a18daafee10"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: scaffold/model_parser.py: FileTooLong \u2014 635 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 135 over it, 1.27\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"59f7d34379b14792dec35e6cdc241c27780e935c266633bbca174cb234ce660e"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: ext/mypy_plugin.py: FileTooLong \u2014 628 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 128 over it, 1.26\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c601b48bd6dc794828f74c181d6fad2d6d3a0842f9854a578c62eff7de8f5927"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: repository/memory.py: FileTooLong \u2014 598 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 98 over it, 1.20\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/memory.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"098b4def0a37257686e19c1471ccab75634f088139d11b446e0bae7c6f86fcba"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: protean/testing.py: FileTooLong \u2014 597 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 97 over it, 1.19\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/testing.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"bac6f14a3db4b7d35d7e9ba5e469221ce82f552b710f7282ba75edc904704761"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: observatory/metrics.py: FileTooLong \u2014 563 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 63 over it, 1.13\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"602fa6007f77de3057873ae9deec8a18391d9648a7e727e2e0cf4da32bec716c"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: BaseDAO: TooManyMethods \u2014 33 methods. The bar is 30 methods; this is 3 over it, 1.10\u00D7 the bar. To reduce it, group the members that share the same data into a smaller type of their own and delegate to it, so no single type carries every responsibility."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/dao.py"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"d5be682bba22469e29184d9c48f00af9ca87cb44612b7986cc7520b521d10970"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: utils/logging.py: FileTooLong \u2014 548 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 48 over it, 1.10\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/logging.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"68c43f86f7a6e2db71bfd72d571148a4d8c89871570be81206c957fdabad588d"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: generators/event_model.py: FileTooLong \u2014 545 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 45 over it, 1.09\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/event_model.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f39fc904660ac1d1eb1cbe45867e5f2694d72c06c4a095a4decbeac1e9068c55"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: dx/managed_files.py: FileTooLong \u2014 533 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 33 over it, 1.07\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/managed_files.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3c9d6bfa68f1e6c058a0433c710aefe8ea296ffbe15425c8e4e5f7ae4f91d2ff"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: subscription/stream_subscription.py: FileTooLong \u2014 530 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 30 over it, 1.06\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/stream_subscription.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"efe57ad290cfde7cb83253ba5efb1f6072d5e4ca646a3646319d176b36abd201"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: protean/upgrade_opportunities.py: FileTooLong \u2014 530 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 30 over it, 1.06\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3dbed63a5580c50d11a6026bb1e20a26e3d4d1200d82c7a995d4567e2a5fdefd"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: port/broker.py: FileTooLong \u2014 511 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 11 over it, 1.02\u00D7 the bar. To reduce it, split the file along the responsibilities already in it: move each cohesive group of declarations into its own sibling file in the same module or package, so no one file has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/broker.py"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"abbd1a4b7421fed3c57302b6b57615a53f0ccdc59e2a88ea038bbacf795c8778"}},{"ruleId":"D4","level":"warning","message":{"text":"Near-duplicate member pair (65 shared lines): src/protean/server/observatory/routes/handlers.py:332-425 | src/protean/server/observatory/routes/processes.py:207-284 \u2014 These two members are variants of one another: 65 of their lines are already reported as duplicated blocks below, spread through both bodies rather than gathered into one. Read them as a single construct written twice. The repair is at the members\u0027 grain \u2014 factor the shared pipeline into one implementation the two call with their differences as parameters or as an injected step, or, where the difference is systematic (sync against async, one transport against another), generate one from the other. Extracting the individual blocks below is not the same fix: it leaves the two bodies in place and the next edit still has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":332}}}],"partialFingerprints":{"codehealthFindingId/v1":"9bd64bfe9dabf4662b164b8935567228fe05426ab7149572fd250b1350856176"}},{"ruleId":"D4","level":"warning","message":{"text":"Near-duplicate member pair (41 shared lines): src/protean/port/event_store.py:1028-1103 | src/protean/server/observatory/routes/timeline.py:403-515 \u2014 These two members are variants of one another: 41 of their lines are already reported as duplicated blocks below, spread through both bodies rather than gathered into one. Read them as a single construct written twice. The repair is at the members\u0027 grain \u2014 factor the shared pipeline into one implementation the two call with their differences as parameters or as an injected step, or, where the difference is systematic (sync against async, one transport against another), generate one from the other. Extracting the individual blocks below is not the same fix: it leaves the two bodies in place and the next edit still has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1028}}}],"partialFingerprints":{"codehealthFindingId/v1":"40af0e2da5f7367201b78bf533e32a851793b3bdf2d66700da2819c8e3117e23"}},{"ruleId":"D4","level":"warning","message":{"text":"Edited copy of a member (35 corresponding lines): src/protean/core/query.py:129-170 | src/protean/utils/eventing.py:392-432 \u2014 These two members are one piece of code written twice and then edited apart: 35 consecutive lines correspond almost exactly, broken only by small local edits. Most of that correspondence is NOT reported as duplicated blocks below \u2014 the edits cut it into fragments and only the largest of them clear the block floor, so the rows below understate it. The repair is at the members\u0027 grain \u2014 factor the shared implementation into one the two call with their differences as parameters or as an injected step, or, where the difference is systematic (an extra return value, one transport against another), generate one from the other. Left alone, the next edit has to be made twice and the two will drift further apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/query.py"},"region":{"startLine":129}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c588a7d6dcbbfb6326508f1f7f404d292596c25be128d64d08df247e11fc8da"}},{"ruleId":"D4","level":"warning","message":{"text":"Edited copy of a member (11 corresponding lines): docs_src/guides/domain-definition/009.py:14-31 | src/protean/dx/pack/skills/value-object/assets/value_object_with_validation.py:29-55 \u2014 These two members are one piece of code written twice and then edited apart: 11 consecutive lines correspond almost exactly, broken only by small local edits. Most of that correspondence is NOT reported as duplicated blocks below \u2014 the edits cut it into fragments and only the largest of them clear the block floor, so the rows below understate it. The repair is at the members\u0027 grain \u2014 factor the shared implementation into one the two call with their differences as parameters or as an injected step, or, where the difference is systematic (an extra return value, one transport against another), generate one from the other. Left alone, the next edit has to be made twice and the two will drift further apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-definition/009.py"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"1b6cd8c697bd4b5eb30b75330141ecd6f857c3c0249fb1afdcf2ae5f7e74d4ee"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (10 members, 50\u002B identical tokens): src/protean/ir/generators/events.py:129-143 | src/protean/ir/generators/events.py:150-195 | src/protean/ir/generators/events.py:202-226 | src/protean/ir/generators/events.py:290-313 | src/protean/ir/generators/events.py:320-372 | src/protean/ir/generators/events.py:379-411 | src/protean/ir/generators/handlers.py:81-118 | src/protean/ir/generators/handlers.py:125-152 | src/protean/ir/generators/handlers.py:159-218 | src/protean/ir/generators/handlers.py:225-261 \u2014 These 10 members share a duplicated core: a run of at least 50 identical tokens appears in every one of them. That run is NOT broken out as duplicated-block rows below \u2014 it is what admitted this row, and the blocks below cover only the part of it that clears the block floor, so they understate the correspondence. Read the members as one construct written 10 times. The repair is at the members\u0027 grain \u2014 factor the shared implementation out once and have all of them call it with their differences as parameters or as an injected step, or, where the difference is systematic, generate them from one template. Extracting the individual blocks below is not the same fix: it leaves every body in place and the next edit still has to be made 10 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":129}}}],"partialFingerprints":{"codehealthFindingId/v1":"64e7e04038bf3c9c179f9d46f26bcc9cd90ad62ca83f1b618ab5e6522e411566"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (5 members, 50\u002B identical tokens): docs_src/guides/getting-started/es-tutorial/ch06.py:214-223 | docs_src/guides/getting-started/es-tutorial/ch08.py:240-249 | docs_src/guides/getting-started/es-tutorial/ch18.py:185-194 | docs_src/guides/getting-started/es-tutorial/ch20.py:179-188 | docs_src/guides/getting-started/es-tutorial/ch22.py:364-373 \u2014 These 5 members share a duplicated core: a run of at least 50 identical tokens appears in every one of them. That run is NOT broken out as duplicated-block rows below \u2014 it is what admitted this row, and the blocks below cover only the part of it that clears the block floor, so they understate the correspondence. Read the members as one construct written 5 times. The repair is at the members\u0027 grain \u2014 factor the shared implementation out once and have all of them call it with their differences as parameters or as an injected step, or, where the difference is systematic, generate them from one template. Extracting the individual blocks below is not the same fix: it leaves every body in place and the next edit still has to be made 5 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch06.py"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6e30c1ab54334c9a3b4409a938a7384ff8bc20d6f528e1c1cff780b8669e26f"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (5 members, 50\u002B identical tokens): src/protean/core/command.py:80-135 | src/protean/core/email.py:101-117 | src/protean/core/event.py:62-127 | src/protean/core/query.py:199-240 | src/protean/core/value_object.py:197-212 \u2014 These 5 members share a duplicated core: a run of at least 50 identical tokens appears in every one of them. That run is NOT broken out as duplicated-block rows below \u2014 it is what admitted this row, and the blocks below cover only the part of it that clears the block floor, so they understate the correspondence. Read the members as one construct written 5 times. The repair is at the members\u0027 grain \u2014 factor the shared implementation out once and have all of them call it with their differences as parameters or as an injected step, or, where the difference is systematic, generate them from one template. Extracting the individual blocks below is not the same fix: it leaves every body in place and the next edit still has to be made 5 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"8457f9a5975d81c56583ecfd846a199c33842029703c9f95c22e32bba37a776f"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): src/protean/ir/diff.py:95-114 | src/protean/ir/diff.py:163-191 | src/protean/ir/diff.py:219-240 | src/protean/ir/diff.py:252-277 \u2014 These 4 members share a duplicated core: a run of at least 50 identical tokens appears in every one of them. That run is NOT broken out as duplicated-block rows below \u2014 it is what admitted this row, and the blocks below cover only the part of it that clears the block floor, so they understate the correspondence. Read the members as one construct written 4 times. The repair is at the members\u0027 grain \u2014 factor the shared implementation out once and have all of them call it with their differences as parameters or as an injected step, or, where the difference is systematic, generate them from one template. Extracting the individual blocks below is not the same fix: it leaves every body in place and the next edit still has to be made 4 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"46e70896c0516677e51ae9ef19a9c29e08571d89103f53004de62f672193bdbb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (39\u201354 lines \u00D7 2): src/protean/adapters/broker/redis.py:1233-1286 | src/protean/adapters/broker/redis_pubsub.py:165-203 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":1233}}}],"partialFingerprints":{"codehealthFindingId/v1":"108e7ac808af96a33856ec61dcde0ec694643d5cc525cafe75381f3e2a5d7dbc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (41\u201345 lines \u00D7 2): src/protean/domain/__init__.py:2357-2397 | src/protean/domain/__init__.py:2439-2483 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":2357}}}],"partialFingerprints":{"codehealthFindingId/v1":"dbc9ad331fe76caa43883555abcfcad045b245bc490b889144d5666b1ff7581c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (41\u201344 lines \u00D7 2): src/protean/core/entity.py:567-610 | src/protean/core/projection.py:303-343 \u2014 before extracting anything, compare \u0060src/protean/core/entity.py\u0060 and \u0060src/protean/core/projection.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 85 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/core/entity.py:613\u0060 calls \u0060_discover_invariants\u0060, \u0060defaults\u0060 and \u0060src/protean/core/projection.py:346\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":567}}}],"partialFingerprints":{"codehealthFindingId/v1":"3bebe24a85b30dc6bfd1c1eeebe78674e1b2c779b0196b49f7b314f88e0ffd82"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (43 lines \u00D7 2): src/protean/server/subscription_status.py:491-533 | src/protean/server/subscription_status.py:598-640 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/server/subscription_status.py:537\u0060 calls \u0060suppress\u0060, \u0060xlen\u0060 and \u0060src/protean/server/subscription_status.py:642\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":491}}}],"partialFingerprints":{"codehealthFindingId/v1":"e5771e712ffc0c5a5b204dbda6adbe9fe6c23feff0096de35d7f5a6bcba2a638"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (30\u201342 lines \u00D7 2): src/protean/server/engine.py:645-686 | src/protean/server/subscription_status.py:162-191 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/engine.py:645\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060handler_cls\u0060 to \u0060type[BaseCommandHandler | BaseEventHandler]\u0060 in one and \u0060type[Any]\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"bf39a071057fbed85515fd842f7ef7a2040ed27f4d31c7dffa8aca92e0657bd6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (39 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:273-311 | src/protean/server/observatory/routes/processes.py:161-199 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":273}}}],"partialFingerprints":{"codehealthFindingId/v1":"e16b49b9099ce35991a1a0c2c81ba134b0be53d62dc18c071a4cfe4d7f207e5d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (23\u201338 lines \u00D7 2): src/protean/ir/generators/event_model.py:1148-1185 | src/protean/ir/generators/event_model.py:1188-1210 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/event_model.py"},"region":{"startLine":1148}}}],"partialFingerprints":{"codehealthFindingId/v1":"ca91fc7656a173dfe0d9032cda3066dbfc9ee79efb1d84b97ae86b36ecccddfe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (34\u201335 lines \u00D7 2): src/protean/core/query.py:136-170 | src/protean/utils/eventing.py:399-432 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/query.py"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e69eef1853d299025a4557ad4b4658bbd53dd60f8ddcf66bce4947271019dca"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (34 lines \u00D7 2): src/protean/server/observatory/api.py:1226-1259 | src/protean/server/observatory/api.py:1277-1310 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":1226}}}],"partialFingerprints":{"codehealthFindingId/v1":"e91878cd890ea367cb74558f4400982f644ca321bfc02228679afb451f17b7d2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (32\u201333 lines \u00D7 2): src/protean/server/observatory/api.py:290-322 | src/protean/server/observatory/api.py:354-385 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/api.py:290\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"9f96487f42d79beab263c752f64ffd409f44bf4ec7015964dbcf246e251deea2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22\u201331 lines \u00D7 2): src/protean/port/dao.py:715-736 | src/protean/port/dao.py:811-841 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/dao.py"},"region":{"startLine":715}}}],"partialFingerprints":{"codehealthFindingId/v1":"eee64ff0d2829c8be9eb4b648d001b364780493a0a49a4ca5a8ad213707df103"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (28\u201330 lines \u00D7 2): src/protean/core/repository.py:494-523 | src/protean/core/repository.py:529-556 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":494}}}],"partialFingerprints":{"codehealthFindingId/v1":"f3c140986c50f22f3345cb78dc265cdf2b6dd2c11194f8954ee50f1f19b2ac45"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (27\u201330 lines \u00D7 2): src/protean/ir/builder.py:678-707 | src/protean/ir/builder.py:719-745 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":678}}}],"partialFingerprints":{"codehealthFindingId/v1":"195a9f20249e14773963703ba2cba4aa363dcb22141a059afe449b615b49c37d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (29 lines \u00D7 2): src/protean/core/command.py:215-243 | src/protean/core/event.py:195-223 \u2014 before extracting anything, compare \u0060src/protean/core/command.py\u0060 and \u0060src/protean/core/event.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 61 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/core/command.py:215\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":215}}}],"partialFingerprints":{"codehealthFindingId/v1":"97d598a6c1b6d2c3827eaa51580c4942fcf2e4f2f2620894ec2f7950f917aee2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (26\u201328 lines \u00D7 3): src/protean/ir/generators/events.py:151-178 | src/protean/ir/generators/events.py:322-347 | src/protean/ir/generators/handlers.py:161-188 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/ir/generators/handlers.py:189\u0060 calls \u0060_evt_node_id\u0060, \u0060short_name\u0060 and \u0060src/protean/ir/generators/events.py:179\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":151}}}],"partialFingerprints":{"codehealthFindingId/v1":"9250f1295d5a0e9a4e8bd6bc4d976c7ad6368ddd2eebce46ce77ef1a30a34c09"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (27\u201328 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:398-425 | src/protean/server/observatory/routes/processes.py:258-284 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/routes/handlers.py:398\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":398}}}],"partialFingerprints":{"codehealthFindingId/v1":"09563d14a6d5109138cbc9179798825eca0148887fb98c1ce13e228805d0cea9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (26 lines \u00D7 2): src/protean/ir/diff.py:1080-1105 | src/protean/ir/diff.py:1144-1169 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1080}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ed368998aa0245be07751c38a53e9707ee60ce1dd3d2cb46e9ead92f5feaa77"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (25\u201326 lines \u00D7 2): src/protean/ir/generators/base.py:173-197 | src/protean/ir/generators/base.py:201-226 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/base.py"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"c97923adec1287d140193e48c5d985b6627e2147d6d0d49b9b5a134abb59e324"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22\u201325 lines \u00D7 2): src/protean/cli/eventstore.py:492-516 | src/protean/cli/eventstore.py:580-601 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/eventstore.py"},"region":{"startLine":492}}}],"partialFingerprints":{"codehealthFindingId/v1":"f9d693725f638a336124db2c3dac4acb92b6abf8b44d6e5cc464b0340f991799"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (23 lines \u00D7 2): src/protean/fields/association.py:621-643 | src/protean/fields/association.py:725-747 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/fields/association.py:618\u0060 calls \u0060super\u0060, \u0060__set__\u0060 and \u0060src/protean/fields/association.py:722\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":621}}}],"partialFingerprints":{"codehealthFindingId/v1":"feffb66b7ecff7395f861826ade403fb72f2dd9cbed8eb51cbf410cc0c93dd0b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (22 lines \u00D7 3): src/protean/server/observatory/api.py:315-336 | src/protean/server/observatory/api.py:378-399 | src/protean/server/observatory/metrics.py:732-753 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":315}}}],"partialFingerprints":{"codehealthFindingId/v1":"236dd28ae2a23e842c725fc04835886576bc3b5b9585309c22026054c85c96f5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201322 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:83-104 | src/protean/server/observatory/routes/processes.py:78-95 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"31198bc35aadeea44493de74cd18cdf9b3f178570ca123ce1a73d053fe969b80"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 3): src/protean/ir/generators/events.py:203-223 | src/protean/ir/generators/events.py:381-400 | src/protean/ir/generators/handlers.py:227-246 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":203}}}],"partialFingerprints":{"codehealthFindingId/v1":"baabd95418f51189d93b894170314918ebf969d852af08207585711d7ce93fc0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:369-389 | src/protean/server/observatory/routes/processes.py:237-256 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":369}}}],"partialFingerprints":{"codehealthFindingId/v1":"c16c9e8948b0dd76739a113db80a0b49e057d21b3d0ff630910d52e2efdcb31a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20 lines \u00D7 2): src/protean/core/command.py:105-124 | src/protean/core/event.py:91-110 \u2014 before extracting anything, compare \u0060src/protean/core/command.py\u0060 and \u0060src/protean/core/event.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 61 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/core/event.py:111\u0060 calls \u0060pop\u0060 and \u0060src/protean/core/command.py:125\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"657c433ab7f5218846cd3ed222a64d3d12c593727eb8f4cf1d12c747e11742b3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20 lines \u00D7 2): src/protean/server/observatory/api.py:1128-1147 | src/protean/server/observatory/api.py:1180-1199 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":1128}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e013df15d6c263c1bce3f06f29713e0796b33f8606d689d3ad669909616f107"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15\u201319 lines \u00D7 3): src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py:168-186 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py:121-135 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_simple.py:90-108 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py\u0060 and \u0060src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 58 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py"},"region":{"startLine":168}}}],"partialFingerprints":{"codehealthFindingId/v1":"c89be7aa385d06cfff4022b07199f5de8c2d8225bf137f0563eaf5f923072bd3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201319 lines \u00D7 2): src/protean/cli/projection.py:181-198 | src/protean/cli/subscriptions.py:74-92 \u2014 before extracting anything, compare \u0060src/protean/cli/projection.py\u0060 and \u0060src/protean/cli/subscriptions.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 44 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/cli/subscriptions.py:93\u0060 calls \u0060add_column\u0060 and \u0060src/protean/cli/projection.py:199\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/projection.py"},"region":{"startLine":181}}}],"partialFingerprints":{"codehealthFindingId/v1":"e786d4cc3cb4c13f1080407d800bf169b66e6b306e3b7ebda25af134981602e7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): src/protean/integrations/fastapi/health.py:83-101 | src/protean/server/health.py:511-529 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/integrations/fastapi/health.py"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"0628b674563e8606cbbb3eff53658cc933ba9f2f44b90e0bb90c2cf74f81599c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201319 lines \u00D7 2): src/protean/port/event_store.py:1044-1062 | src/protean/server/observatory/routes/timeline.py:420-437 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1044}}}],"partialFingerprints":{"codehealthFindingId/v1":"92e2734930905b5a15e1c4d86d62c14dbe2f44f75649693d0a9f17ce225cab69"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17\u201319 lines \u00D7 2): src/protean/server/observatory/metrics.py:633-651 | src/protean/server/observatory/metrics.py:776-792 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/metrics.py:633\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":633}}}],"partialFingerprints":{"codehealthFindingId/v1":"b193e4ffcff228d85961e82d04487fdd3d26f7af53ec315d6738f617be631b3b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201319 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:349-367 | src/protean/server/observatory/routes/processes.py:218-235 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":349}}}],"partialFingerprints":{"codehealthFindingId/v1":"dc31dfcd8ca7eae67b7787695eeba5d8388c5e13c79df39631ca6f4893446dd9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17\u201319 lines \u00D7 2): src/protean/server/subscription/__init__.py:120-138 | src/protean/server/subscription/partitioned_stream_subscription.py:247-263 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/__init__.py"},"region":{"startLine":120}}}],"partialFingerprints":{"codehealthFindingId/v1":"4651626bc8eaae6d992935c81b6a3956ca1225d53faf43eb3db4788150d593fe"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/protean/ir/builder.py:921-938 | src/protean/ir/builder.py:957-974 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/ir/builder.py:975\u0060 calls \u0060getattr\u0060 and \u0060src/protean/ir/builder.py:939\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":921}}}],"partialFingerprints":{"codehealthFindingId/v1":"a15a6df6fd642dbf5d0c696126e6afadf29aaa4611425fe044d3c25806d10936"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/protean/ir/generators/handlers.py:135-152 | src/protean/ir/generators/handlers.py:244-261 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/handlers.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"00b54749e29e8fc27389a0ef2bca9fa5dec1422e1d37aa799f6bcd439e1e0de6"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/protean/port/broker.py:1082-1099 | src/protean/port/provider.py:461-478 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/broker.py"},"region":{"startLine":1082}}}],"partialFingerprints":{"codehealthFindingId/v1":"bfebc8742de48f961b94dd7b710b4a50fdea8f1a28274bbccea0774c0743d86e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2): src/protean/server/observatory/api.py:707-727 | src/protean/server/observatory/api.py:731-748 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/api.py:707\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":707}}}],"partialFingerprints":{"codehealthFindingId/v1":"caeadba44a76f7cc2a699f47335244b26b18c9b2c19dd5491029292a2b39d4a4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16\u201318 lines \u00D7 2): src/protean/server/subscription/broker_subscription.py:366-383 | src/protean/server/subscription/stream_subscription.py:964-979 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/subscription/broker_subscription.py:366\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/broker_subscription.py"},"region":{"startLine":366}}}],"partialFingerprints":{"codehealthFindingId/v1":"725e45c230eab1994cb88467e7b1dd34ce1dc5e5ce8915679df54d7a2a0c0e46"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201318 lines \u00D7 2): src/protean/server/subscription_status.py:894-911 | src/protean/server/subscription_status.py:915-928 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":894}}}],"partialFingerprints":{"codehealthFindingId/v1":"a71d4d74a6702a4d6d3b95fb0dcf8fe5d60ba9289f8518b4d365932058086574"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16\u201318 lines \u00D7 2): src/protean/upgrade.py:198-215 | src/protean/upgrade.py:484-499 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/upgrade.py:500\u0060 calls \u0060get_indexes\u0060 and \u0060src/protean/upgrade.py:216\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade.py"},"region":{"startLine":198}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9236b3269cbc2139b0984cf6d2487f2cfc94f6f506411e344d6b79e3043af4e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201317 lines \u00D7 3): src/protean/server/projection_status.py:139-155 | src/protean/server/subscription_status.py:895-911 | src/protean/server/subscription_status.py:916-928 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/projection_status.py"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e52b73c27bb51cc3f0e8319d6ae9dd1cc99e108611ac11a86d18fa0dcbbe9dd"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 2): src/protean/core/entity.py:452-468 | src/protean/core/projection.py:251-267 \u2014 before extracting anything, compare \u0060src/protean/core/entity.py\u0060 and \u0060src/protean/core/projection.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 85 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":452}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd15aa092d5d427528e7c443470e4ca2984cd01e35b02785ecca12388e4868f2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (17 lines \u00D7 2): src/protean/upgrade.py:635-651 | src/protean/upgrade_opportunities.py:968-984 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade.py"},"region":{"startLine":635}}}],"partialFingerprints":{"codehealthFindingId/v1":"ddcc95272947119eb0298a905f9027bb7a4865f84b1773b8673e677f97199168"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 3): docs_src/guides/consume-state/002.py:32-47 | src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py:62-77 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:59-74 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/consume-state/002.py"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"99f0cfacb598b4bbb3a0166aa186543f89e39fc4ef658feac1cd8b373b172ba9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15\u201316 lines \u00D7 3): src/protean/core/email.py:102-117 | src/protean/core/query.py:223-238 | src/protean/core/value_object.py:198-212 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/email.py"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"9bf84be8aa2e03cb0a017eecc116cc15ba33f063c9633f7920cef09abeaed86b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 3): src/protean/server/observatory/routes/infrastructure.py:108-123 | src/protean/server/observatory/routes/infrastructure.py:137-152 | src/protean/server/observatory/routes/infrastructure.py:216-231 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/infrastructure.py"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"db6003f07487b3a0bd23afb79a56736e0361aabcf3c4ef2ec156f5863ab1e6f5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201316 lines \u00D7 2): src/protean/ir/builder.py:2310-2325 | src/protean/ir/builder.py:2356-2366 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2310}}}],"partialFingerprints":{"codehealthFindingId/v1":"a4cb5df7c040e2fe17b99baf1075f74ddd7c08e20b4ae15c271294e9077caef0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): src/protean/ir/diff.py:225-240 | src/protean/ir/diff.py:262-277 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":225}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5bd858185da340e1ad284546a2a98593d29beaa37c1058ca496c79dad631bca"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201315 lines \u00D7 2): src/protean/adapters/broker/inline.py:745-756 | src/protean/adapters/broker/inline.py:846-860 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/inline.py"},"region":{"startLine":745}}}],"partialFingerprints":{"codehealthFindingId/v1":"e43f0f7dba5b6d9cc7f374b3308f4aeee0a03a98d28c244ef0f1295063e7875d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): src/protean/adapters/broker/redis.py:1296-1310 | src/protean/adapters/broker/redis_pubsub.py:239-252 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":1296}}}],"partialFingerprints":{"codehealthFindingId/v1":"40998ec87e12687b02ccf82269cd57aeed3d8ee31a4935aa5ff503d724a7ebb7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201315 lines \u00D7 2): src/protean/adapters/repository/memory.py:748-762 | src/protean/adapters/repository/memory.py:845-855 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/adapters/repository/memory.py:748\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/memory.py"},"region":{"startLine":748}}}],"partialFingerprints":{"codehealthFindingId/v1":"d8e1e89136b22b3b4e0acdb0174caa78cdaed4d5750efde1a6516796c3588900"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): src/protean/core/aggregate.py:586-600 | src/protean/core/value_object.py:459-472 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":586}}}],"partialFingerprints":{"codehealthFindingId/v1":"6b569ac99fc08e226bf14bc6b70b29b4901d30b8534afb7b6b8445b6f3036e64"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): src/protean/core/queryset.py:355-369 | src/protean/core/queryset.py:463-476 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/queryset.py"},"region":{"startLine":355}}}],"partialFingerprints":{"codehealthFindingId/v1":"cee6435a112ccfa4fe3ba584d1d51b8fe1f98f66af9aaf5c9aea6c06d231da45"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201315 lines \u00D7 2): src/protean/dx/managed_files.py:477-489 | src/protean/scaffold/manifest.py:55-69 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/managed_files.py"},"region":{"startLine":477}}}],"partialFingerprints":{"codehealthFindingId/v1":"79e4b443d138c7b34be2e51a2a63d9c37a64e2267f1bcee483fcb5395c41abb1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/protean/ir/diff.py:292-306 | src/protean/ir/diff.py:316-330 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":292}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ec96a7aa85b4674a627df86b0d95e95ba56a0aeb50dcd83357ea589da60bf23"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): src/protean/server/observatory/api.py:1166-1179 | src/protean/server/observatory/api.py:1212-1226 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/api.py:1166\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":1166}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f0e92affa68cfc5e9b8141f7ab99c2695b2959c3d14c1cf793947cd2a3614f5"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/protean/server/observatory/metrics.py:565-581 | src/protean/server/observatory/metrics.py:595-609 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/metrics.py:565\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/server/observatory/metrics.py:594\u0060 calls \u0060get\u0060 and \u0060src/protean/server/observatory/metrics.py:565\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":565}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7a6a371d514a9ac92e70a71ddcebf97cbcde3cb50ea64a04f28daf79847e33c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): src/protean/server/observatory/routes/eventstore.py:41-55 | src/protean/server/observatory/routes/processes.py:99-113 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/eventstore.py"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"005f599b21ee46c0fc71c0ed842fc6555f94404a5002908b089ffe72f2a569ab"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13\u201314 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch09.py:281-294 | docs_src/guides/getting-started/es-tutorial/ch22.py:519-531 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch09.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch22.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 46 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch09.py"},"region":{"startLine":281}}}],"partialFingerprints":{"codehealthFindingId/v1":"8a0610154f9051cabdb6251855f201ea5655f0dae58c571b9415c04a2c78a85d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/protean/ir/generators/events.py:300-313 | src/protean/ir/generators/events.py:398-411 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":300}}}],"partialFingerprints":{"codehealthFindingId/v1":"75128a8cc86235a83e25d1c1954fcab0ede3715f1ce43fcdc813a5822eb826a4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201314 lines \u00D7 2): src/protean/server/observatory/api.py:671-682 | src/protean/server/observatory/api.py:937-950 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/api.py:671\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/server/observatory/api.py:952\u0060 calls \u0060get\u0060 and \u0060src/protean/server/observatory/api.py:685\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":671}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc54c36cc6e44035705023cf2116cd4b2ead3fc583e2c2a4297b2b62e9965a36"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/protean/server/outbox_processor.py:422-435 | src/protean/server/outbox_processor.py:735-748 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/outbox_processor.py"},"region":{"startLine":422}}}],"partialFingerprints":{"codehealthFindingId/v1":"a593148a028901e37b9efaf66547ec6de74d5b35d77706962b5a41f1546dc6ac"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/protean/server/subscription/broker_subscription.py:385-399 | src/protean/server/subscription/stream_subscription.py:981-994 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/subscription/broker_subscription.py:385\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/broker_subscription.py"},"region":{"startLine":385}}}],"partialFingerprints":{"codehealthFindingId/v1":"3f079bab897166eda0b5889c8ccb597b8318adc0ebfc916134917ce272a2d849"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201313 lines \u00D7 4): src/protean/ir/diff.py:95-103 | src/protean/ir/diff.py:163-171 | src/protean/ir/diff.py:219-227 | src/protean/ir/diff.py:252-264 \u2014 all 4 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"322ac01fc989c6587f224690e0887eed67e68870b1fb3177d47a55047bdb098e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 3): docs_src/guides/domain-behavior/006.py:122-134 | docs_src/guides/domain-behavior/007.py:121-133 | src/protean/dx/pack/skills/domain-service/assets/domain_service_with_invariants.py:137-149 \u2014 before extracting anything, compare \u0060docs_src/guides/domain-behavior/006.py\u0060 and \u0060docs_src/guides/domain-behavior/007.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 45 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-behavior/006.py"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff2773de6a76c9d2d7da25231fdaef86c3703e0461b62ff7d699a80c130f2999"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201313 lines \u00D7 3): src/protean/cli/eventstore.py:535-546 | src/protean/cli/projection.py:185-196 | src/protean/cli/subscriptions.py:78-90 \u2014 before extracting anything, compare \u0060src/protean/cli/projection.py\u0060 and \u0060src/protean/cli/subscriptions.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 44 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/cli/eventstore.py:535\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/cli/subscriptions.py:93\u0060 calls \u0060add_column\u0060 and \u0060src/protean/cli/projection.py:199\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/eventstore.py"},"region":{"startLine":535}}}],"partialFingerprints":{"codehealthFindingId/v1":"8d3894d529f2e26af9112ab3bbdbd2f1b9c38cebcb3bfb102f2376f09fcac9a0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201313 lines \u00D7 3): src/protean/server/observatory/api.py:1082-1093 | src/protean/server/observatory/api.py:1244-1256 | src/protean/server/observatory/api.py:1295-1307 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060subscription\u0060 to \u0060str | None = Query(None, description=\u0022Filter by stream category\u0022)\u0060 in one and \u0060str = Query(..., description=\u0022Stream category (required)\u0022)\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":1082}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a769411b736d5749bd9671e77fa16e47d2579ecf12f1703c0d6e5dc1f9bc95b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12\u201313 lines \u00D7 3): src/protean/server/observatory/routes/timeline.py:227-239 | src/protean/server/observatory/routes/timeline.py:329-341 | src/protean/server/observatory/routes/timeline.py:749-760 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":227}}}],"partialFingerprints":{"codehealthFindingId/v1":"519d51d86af15e59305b2cb079c09c8b94897aa3bf3b5bdb1b56d1b972bc8ee7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/core/domain_service.py:97-109 | src/protean/core/domain_service.py:113-125 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/domain_service.py"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"850ddbecc15fa1e89bf46159687df8e8df59ca5fdf65abb952ce888f50a003ac"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/core/unit_of_work.py:365-377 | src/protean/core/unit_of_work.py:386-398 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/unit_of_work.py"},"region":{"startLine":365}}}],"partialFingerprints":{"codehealthFindingId/v1":"4701832f069e142c96fec700a5b444b407f5f4485f293be992da9a9006810965"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/ir/generators/base.py:253-265 | src/protean/ir/generators/base.py:269-281 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/base.py"},"region":{"startLine":253}}}],"partialFingerprints":{"codehealthFindingId/v1":"797563199ff1f8a9107141a9ba24c029a7981a9abaec7151118b2ddf8ad632ba"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/server/engine.py:576-588 | src/protean/server/engine.py:614-626 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":576}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1dbb19322e83c767f03b537b00d36a88330b892824bb6d0c161601d5209bae1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/server/subscription/broker_subscription.py:116-128 | src/protean/server/subscription/event_store_subscription.py:459-471 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/broker_subscription.py"},"region":{"startLine":116}}}],"partialFingerprints":{"codehealthFindingId/v1":"342867fde46bd345590268638c67424613262a6f4e2ef2283c2918a564d9482d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 9): src/protean/ir/builder.py:712-723 | src/protean/ir/builder.py:756-767 | src/protean/ir/builder.py:913-924 | src/protean/ir/builder.py:949-960 | src/protean/ir/builder.py:986-997 | src/protean/ir/builder.py:1078-1089 | src/protean/ir/builder.py:1177-1188 | src/protean/ir/builder.py:1263-1274 | src/protean/ir/builder.py:1292-1303 \u2014 all 9 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/ir/builder.py:768\u0060 calls \u0060_extract_fields\u0060 and \u0060src/protean/ir/builder.py:1275\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":712}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ac3d7dc2f355f784c1c2b9c7f5f3082fa3e0b4167451a3263ac391a5e413051"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 5): src/protean/core/command.py:105-116 | src/protean/core/email.py:101-112 | src/protean/core/event.py:91-102 | src/protean/core/query.py:222-233 | src/protean/core/value_object.py:197-208 \u2014 before extracting anything, compare \u0060src/protean/core/command.py\u0060 and \u0060src/protean/core/event.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 61 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"194a667e2366f0dd830a81c876ec3931559d26455794e2c3414cfeb2e551b1cf"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 4): src/protean/ir/builder.py:917-928 | src/protean/ir/builder.py:953-964 | src/protean/ir/builder.py:1127-1138 | src/protean/ir/builder.py:1181-1192 \u2014 all 4 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":917}}}],"partialFingerprints":{"codehealthFindingId/v1":"9bdfe3748b3212fe56545ae40b05e1864b7b90ca8b067a4fa3cbe029ea48ca71"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11\u201312 lines \u00D7 2): src/protean/cli/projection.py:215-225 | src/protean/cli/subscriptions.py:112-123 \u2014 before extracting anything, compare \u0060src/protean/cli/projection.py\u0060 and \u0060src/protean/cli/subscriptions.py\u0060 as WHOLE FILES: this scan already matched 3 separate duplicated blocks between them, totalling at least 44 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/cli/projection.py:215\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/cli/subscriptions.py:124\u0060 calls \u0060sum\u0060 and \u0060src/protean/cli/projection.py:227\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/projection.py"},"region":{"startLine":215}}}],"partialFingerprints":{"codehealthFindingId/v1":"7725003b6f6af04be2941b3038deb0121ea1eee11670e5a7ee8e3b1bac54426b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/protean/port/dao.py:450-461 | src/protean/port/dao.py:515-526 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/dao.py"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"eafba3cfd4ed19a84b20754399ec931a8b55e1d6e4ca8b712aa2912aa996c31a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201312 lines \u00D7 2): src/protean/port/event_store.py:1092-1103 | src/protean/server/observatory/routes/timeline.py:506-515 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1092}}}],"partialFingerprints":{"codehealthFindingId/v1":"493a938076ea7686732160140bfdf4c4d7a40969aca647048c6f197e3e37e1c4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:516-527 | src/protean/server/observatory/routes/processes.py:455-466 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/routes/handlers.py:516\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":516}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ec0636c1188280a32d6517cf36fb968b9d8dd73997cd7bb5e08e1470620dc6c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/protean/server/observatory/routes/handlers.py:522-533 | src/protean/server/observatory/routes/handlers.py:567-578 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/routes/handlers.py:522\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":522}}}],"partialFingerprints":{"codehealthFindingId/v1":"558539130b4660c5d6b04e10c3bab3b2e0a82df1add2e582c0d6d25f85669fee"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/protean/utils/health.py:31-42 | src/protean/utils/health.py:53-64 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/health.py"},"region":{"startLine":31}}}],"partialFingerprints":{"codehealthFindingId/v1":"060e6d7c66cf01b5672f2a13172d6cefaf017075a16d86f3d972e7ee2a24d143"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 5): src/protean/ir/builder.py:715-725 | src/protean/ir/builder.py:759-769 | src/protean/ir/builder.py:1081-1091 | src/protean/ir/builder.py:1154-1164 | src/protean/ir/builder.py:1295-1305 \u2014 all 5 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/ir/builder.py:770\u0060 calls \u0060_extract_invariants\u0060 and \u0060src/protean/ir/builder.py:1165\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":715}}}],"partialFingerprints":{"codehealthFindingId/v1":"86631136004a4569810cad1b7a1007b2290cabaece75add2f02c17c89843dfc4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 3): src/protean/ir/builder.py:990-1000 | src/protean/ir/builder.py:1049-1059 | src/protean/ir/builder.py:1354-1364 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/builder.py:1351\u0060 calls \u0060getattr\u0060 and \u0060src/protean/ir/builder.py:987\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":990}}}],"partialFingerprints":{"codehealthFindingId/v1":"20619b6ad5919abd608395080b308f7dd51f01762481f80d5b91077615d95e13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 3): src/protean/ir/generators/events.py:179-188 | src/protean/ir/generators/events.py:348-357 | src/protean/ir/generators/handlers.py:191-201 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/ir/generators/events.py:179\u0060 it does not close everything it opens, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/generators/handlers.py:189\u0060 calls \u0060_evt_node_id\u0060, \u0060short_name\u0060 and \u0060src/protean/ir/generators/events.py:178\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":179}}}],"partialFingerprints":{"codehealthFindingId/v1":"895ac27a800d3509464d0eb93f61e4316d5fe793ba66cdda5fbbe8ec2229820d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/protean/ir/builder.py:3432-3442 | src/protean/ir/builder.py:3444-3454 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":3432}}}],"partialFingerprints":{"codehealthFindingId/v1":"b068f51406cb098c497e39d459a0445ab11f69773bef8249f713bf5b72aa8e59"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/protean/ir/generators/events.py:130-140 | src/protean/ir/generators/events.py:292-302 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"e5279a5c3c6b8ec9ffb5806b07d11efd55d14453ef577a72fa546151b81baa39"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10\u201311 lines \u00D7 2): src/protean/port/event_store.py:1065-1074 | src/protean/server/observatory/routes/timeline.py:455-465 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/routes/timeline.py:455\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1065}}}],"partialFingerprints":{"codehealthFindingId/v1":"d2fb337bf2d2291934fba507606f1bbccd62bb667f7efb36baf645f9de152a17"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 8): src/protean/ir/builder.py:916-925 | src/protean/ir/builder.py:952-961 | src/protean/ir/builder.py:989-998 | src/protean/ir/builder.py:1048-1057 | src/protean/ir/builder.py:1126-1135 | src/protean/ir/builder.py:1180-1189 | src/protean/ir/builder.py:1266-1275 | src/protean/ir/builder.py:1353-1362 \u2014 all 8 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/ir/builder.py:926\u0060 calls \u0060_extract_handler_map\u0060 and \u0060src/protean/ir/builder.py:999\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":916}}}],"partialFingerprints":{"codehealthFindingId/v1":"da10457fbcad9cf9cea5d044b0e9300d0545610c5d8ca3acba6368178445f3ed"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 5): docs_src/guides/getting-started/es-tutorial/ch06.py:214-223 | docs_src/guides/getting-started/es-tutorial/ch08.py:240-249 | docs_src/guides/getting-started/es-tutorial/ch18.py:185-194 | docs_src/guides/getting-started/es-tutorial/ch20.py:179-188 | docs_src/guides/getting-started/es-tutorial/ch22.py:364-373 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch06.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch18.py\u0060 as WHOLE FILES: 85% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 3 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch06.py"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"71d8e13141e997331f4c0ecf8682df2ecc9e8b1080dd66aa5e432d4fa7f8b94f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 3): src/protean/ir/builder.py:995-1004 | src/protean/ir/builder.py:1025-1034 | src/protean/ir/builder.py:1054-1063 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/builder.py:1023\u0060 calls \u0060getattr\u0060 and \u0060src/protean/ir/builder.py:994\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":995}}}],"partialFingerprints":{"codehealthFindingId/v1":"0d866b3e21fb945da713aa6dd73166439295c02356f768bc2881ab5e151e65b0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9\u201310 lines \u00D7 2): docs_src/guides/domain-definition/009.py:23-31 | src/protean/dx/pack/skills/value-object/assets/value_object_with_validation.py:46-55 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. Read the line range as the matched WINDOW rather than a finished unit: at \u0060docs_src/guides/domain-definition/009.py:23\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-definition/009.py"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"d99b4e62dd011c408e2c1dabca051dfd8b493e0338d8daa1a3724ce08e902166"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): docs_src/guides/getting-started/tutorial/ch06.py:202-211 | docs_src/guides/getting-started/tutorial/ch09.py:201-210 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/tutorial/ch06.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"d41bd278e6f29f9d14254bb3562b0b576a3ab41666b52b2e3613caaa053b08ee"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/protean/core/entity.py:1252-1261 | src/protean/core/value_object.py:374-383 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":1252}}}],"partialFingerprints":{"codehealthFindingId/v1":"95e6928c8558422baedc36e3ad5d80c246cf995f1f39485ec8f5d93c093d1154"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 4): src/protean/server/observatory/api.py:759-774 | src/protean/server/observatory/routes/handlers.py:522-530 | src/protean/server/observatory/routes/handlers.py:567-575 | src/protean/server/observatory/routes/processes.py:461-469 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/api.py:759\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":759}}}],"partialFingerprints":{"codehealthFindingId/v1":"55ea7737ab34594ebb03d89fbdcf4113b54ad9cb2977e3d747ae81f9beae9753"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3): src/protean/ir/builder.py:802-810 | src/protean/ir/builder.py:998-1006 | src/protean/ir/builder.py:1028-1036 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/builder.py:801\u0060 calls \u0060_extract_fields\u0060 and \u0060src/protean/ir/builder.py:997\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":802}}}],"partialFingerprints":{"codehealthFindingId/v1":"74542448cf890ab419c178ad8c47fab156711559b3c579ae2d691feb598f93fd"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20139 lines \u00D7 4): src/protean/server/observatory/metrics.py:326-335 | src/protean/server/observatory/metrics.py:339-347 | src/protean/server/observatory/metrics.py:351-359 | src/protean/server/observatory/metrics.py:360-366 \u2014 all 4 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/server/observatory/metrics.py:326\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/server/observatory/metrics.py:337\u0060 calls \u0060health_stats\u0060, \u0060get\u0060, \u0060create_observation\u0060 and \u0060src/protean/server/observatory/metrics.py:360\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":326}}}],"partialFingerprints":{"codehealthFindingId/v1":"54b3740951976c2bb6f530be325cc10d7bc713444e5cf08575c3ea3a613c78cc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch22.py:470-478 | docs_src/guides/getting-started/es-tutorial/ch22.py:482-490 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060event\u0060 to \u0060DepositMade\u0060 in one and \u0060WithdrawalMade\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch22.py"},"region":{"startLine":470}}}],"partialFingerprints":{"codehealthFindingId/v1":"595631ce69f574c046685ec09d3ae444eab0d72a1fefade38af2df591869929d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/core/entity.py:940-948 | src/protean/core/projection.py:369-377 \u2014 before extracting anything, compare \u0060src/protean/core/entity.py\u0060 and \u0060src/protean/core/projection.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 85 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":940}}}],"partialFingerprints":{"codehealthFindingId/v1":"818118f85cbff8ec87b7cacb81f97d4e891dd90f9e0e0638af1708f6466e3e60"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/ir/builder.py:796-804 | src/protean/ir/builder.py:1158-1166 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/builder.py:792\u0060 calls \u0060getattr\u0060, \u0060sorted\u0060 and \u0060src/protean/ir/builder.py:1156\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":796}}}],"partialFingerprints":{"codehealthFindingId/v1":"4360cbbb09bc0e737400bed5ad2948a06cc932c4ea1387a6777c0ccccdce6360"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/ir/builder.py:1225-1233 | src/protean/ir/builder.py:1236-1244 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/ir/builder.py:1225\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1225}}}],"partialFingerprints":{"codehealthFindingId/v1":"ee1ec6f7597e597b38d1e3f972f2b11996d7478cbdfea9e908695da7362666d2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8\u20139 lines \u00D7 2): src/protean/server/observatory/api.py:262-270 | src/protean/server/observatory/api.py:614-621 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":262}}}],"partialFingerprints":{"codehealthFindingId/v1":"382e6cc469ae35ffb7c729f9ce9a1b7a4aa5799821a236bcce9c8898a09cc607"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/server/observatory/api.py:817-825 | src/protean/server/observatory/api.py:944-952 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":817}}}],"partialFingerprints":{"codehealthFindingId/v1":"0da18c6874a379257f6c311b92e915b6d5d32756fc86a6f69984e8817df3cd1c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4): src/protean/server/observatory/api.py:816-823 | src/protean/server/observatory/api.py:943-950 | src/protean/server/observatory/routes/handlers.py:358-365 | src/protean/server/observatory/routes/processes.py:226-233 \u2014 before extracting anything, compare \u0060src/protean/server/observatory/routes/handlers.py\u0060 and \u0060src/protean/server/observatory/routes/processes.py\u0060 as WHOLE FILES: this scan already matched 8 separate duplicated blocks between them, totalling at least 165 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/protean/server/observatory/routes/handlers.py:367\u0060 calls \u0060get\u0060 and \u0060src/protean/server/observatory/api.py:952\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":816}}}],"partialFingerprints":{"codehealthFindingId/v1":"90e387cf011f3403fced9eb93187b35df8554e7cb211926d35345a05a06e35cd"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/protean/core/aggregate.py:675-682 | src/protean/core/entity.py:1252-1259 | src/protean/core/value_object.py:374-381 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":675}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f930f1f11d38a17bb2c2e4321d57e62df4f9d7add15e12bc6adebd862e579e8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20138 lines \u00D7 3): src/protean/ir/generators/handlers.py:133-139 | src/protean/ir/generators/handlers.py:183-190 | src/protean/ir/generators/handlers.py:242-248 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/handlers.py"},"region":{"startLine":133}}}],"partialFingerprints":{"codehealthFindingId/v1":"1421ec3a0241b3e75e8b3742283d8415e2c0f9fd3bc92cb87594ee382ef352de"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/protean/port/event_store.py:1069-1076 | src/protean/server/observatory/routes/timeline.py:106-113 | src/protean/server/observatory/routes/timeline.py:460-467 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1069}}}],"partialFingerprints":{"codehealthFindingId/v1":"3364790ab5a59c2cfd308dcbc9d706fffdf732a92c0f31b53a12a2de9119e9d2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/domain/validation.py:330-337 | src/protean/domain/validation.py:343-350 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/validation.py"},"region":{"startLine":330}}}],"partialFingerprints":{"codehealthFindingId/v1":"14c2da1003d3142eea800917b12a697e15d05c9c56bd1bf500be265b7f42c253"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/ext/mypy_plugin.py:676-686 | src/protean/ext/mypy_plugin.py:924-931 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ext/mypy_plugin.py:923\u0060 calls \u0060isinstance\u0060 and \u0060src/protean/ext/mypy_plugin.py:673\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":676}}}],"partialFingerprints":{"codehealthFindingId/v1":"7264ff7bb802779ef717f21b58bff4b3bd704883c2debf8d90f3528a5220be95"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/ext/mypy_plugin.py:968-975 | src/protean/ext/mypy_plugin.py:990-997 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/ext/mypy_plugin.py:968\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":968}}}],"partialFingerprints":{"codehealthFindingId/v1":"349ffdb41d0bfeecef2edee8c2fa8cbc38424088ed1c4d5f769d6665b6cb5b3f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/server/observatory/api.py:468-475 | src/protean/server/observatory/routes/timeline.py:555-562 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/server/observatory/routes/timeline.py:552\u0060 calls \u0060debug\u0060 and \u0060src/protean/server/observatory/api.py:467\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":468}}}],"partialFingerprints":{"codehealthFindingId/v1":"e9c510629559ef75f654811746292a3155789853f42517357acef06197572634"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/protean/core/entity.py:444-450 | src/protean/core/projection.py:243-249 \u2014 before extracting anything, compare \u0060src/protean/core/entity.py\u0060 and \u0060src/protean/core/projection.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 85 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":444}}}],"partialFingerprints":{"codehealthFindingId/v1":"df19e406551252d6c467555424ab2aa962a64c3aa28b0f5021fbcbee7f17dcec"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/protean/ir/builder.py:938-944 | src/protean/ir/builder.py:975-981 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/ir/builder.py:974\u0060 calls \u0060getattr\u0060 and \u0060src/protean/ir/builder.py:936\u0060 does not \u2014 after which the two agree again for 4 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":938}}}],"partialFingerprints":{"codehealthFindingId/v1":"83822a147fc104414b9e31f8a87f5cd8e4b3db860ede5224235052ab8dc50223"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/protean/server/observatory/api.py:267-273 | src/protean/server/observatory/api.py:579-585 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/api.py"},"region":{"startLine":267}}}],"partialFingerprints":{"codehealthFindingId/v1":"b6ad86664c27e302406ab09ece27e84d614b489e5ad9e4d75d68156b7a9a793a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 4): src/protean/ir/generators/events.py:135-140 | src/protean/ir/generators/events.py:297-302 | src/protean/ir/generators/handlers.py:92-98 | src/protean/ir/generators/handlers.py:132-137 \u2014 there are 4 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 4 sites; resolving a subset leaves the remainder to drift apart."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"132135fdc482c64ec2f847b830fd26fa55c925aec928488156377bb3c28192c2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/protean/ir/builder.py:1217-1222 | src/protean/ir/builder.py:1228-1233 | src/protean/ir/builder.py:1239-1244 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":1217}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a257c45e7823b6a809baf8b938321072dbe009aff1dff9be6471b39c02a7762"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/protean/ir/generators/events.py:290-295 | src/protean/ir/generators/events.py:379-386 | src/protean/ir/generators/handlers.py:225-232 \u2014 there are 3 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 3 sites; resolving a subset leaves the remainder to drift apart. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"90701e794a0bc9d87a3c15a5722034558f927e909d2e5cd03656e57433688d7a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/protean/ir/generators/events.py:138-143 | src/protean/ir/generators/events.py:221-226 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"ecbef57b4df7996e8e36cdf11565545bc37ceb545fe33df737c7d2449535f85b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/protean/ir/generators/events.py:263-268 | src/protean/ir/generators/events.py:276-281 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":263}}}],"partialFingerprints":{"codehealthFindingId/v1":"6935d0f4fe808e7656c93fbe83e5d8a0c332d707c96a418528879b90e0883fe3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/protean/server/engine.py:1362-1367 | src/protean/server/engine.py:1369-1376 | src/protean/server/engine.py:1377-1384 \u2014 all 3 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/server/engine.py:1362\u0060 calls \u0060create_task\u0060, \u0060start\u0060 and \u0060src/protean/server/engine.py:1377\u0060 does not \u2014 after which the two agree again for 2 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":1362}}}],"partialFingerprints":{"codehealthFindingId/v1":"e4b2efec3d7a90bcfc631da93e096da1bbd87b7880a521cf94593c63c2fa1ea3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 4): src/protean/ir/generators/events.py:136-140 | src/protean/ir/generators/events.py:218-223 | src/protean/ir/generators/events.py:298-302 | src/protean/ir/generators/events.py:396-400 \u2014 all 4 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/events.py"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"aeae8aedd29e9f5889e9e2fae077190038de598d52b23685ad5fe4ea676e55a0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/ir/generators/clusters.py:92-96 | src/protean/ir/generators/clusters.py:105-109 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/clusters.py"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"92f160db6fd6dc5c365fc593481cdd3d496287a74589799694a633bcbd6bed0f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/ir/generators/handlers.py:81-89 | src/protean/ir/generators/handlers.py:125-129 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/handlers.py"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"192f5d159717fa8f3426428142758519e36800ba4d99ab7753272fb8212e6cfd"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (50 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch02.py:47-96 | docs_src/guides/getting-started/es-tutorial/ch03.py:44-145 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch02.py"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"f4ba76df4683dc87d6288fe7b259b444cce6dda801d183c75fd85a2e711975d1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (145 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch04.py:55-199 | docs_src/guides/getting-started/es-tutorial/ch07.py:50-222 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch04.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch07.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 692 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch04.py"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"86bed27e5dd1b504136ed101e19ee1a1259cb146dd1d1f3b6763f005b0b610b1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (112 lines \u00D7 4): docs_src/guides/getting-started/es-tutorial/ch04.py:55-199 | docs_src/guides/getting-started/es-tutorial/ch07.py:50-222 | docs_src/guides/getting-started/es-tutorial/ch12.py:61-172 | docs_src/guides/getting-started/es-tutorial/ch13.py:59-184 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch04.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch07.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 692 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch04.py"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"7496266ff988aaeea78fef73747ac433f5bd4aa58b481c697c5100c513efec54"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (126 lines \u00D7 3): docs_src/guides/getting-started/es-tutorial/ch04.py:55-199 | docs_src/guides/getting-started/es-tutorial/ch07.py:50-222 | docs_src/guides/getting-started/es-tutorial/ch13.py:59-184 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch04.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch07.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 692 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch04.py"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"a450776c899771f4a8cb7bd08e6738091f5a911bc0765f9d2e0fbefd5e9ddc54"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (126 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch07.py:50-222 | docs_src/guides/getting-started/es-tutorial/ch16.py:52-177 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch07.py"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"1441378957209a0c58bd42711aaae954972d63cde94f783ab061914597eb17fa"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (103 lines \u00D7 7): docs_src/guides/getting-started/es-tutorial/ch04.py:55-199 | docs_src/guides/getting-started/es-tutorial/ch07.py:50-222 | docs_src/guides/getting-started/es-tutorial/ch13.py:59-184 | docs_src/guides/getting-started/es-tutorial/ch16.py:52-177 | docs_src/guides/getting-started/es-tutorial/ch17.py:57-159 | docs_src/guides/getting-started/es-tutorial/ch19.py:54-156 | docs_src/guides/getting-started/es-tutorial/ch21.py:55-157 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch04.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch07.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 692 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch04.py"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"dc5ec6a95cbf5251b0cc530a5f43e8a53854b4be77a81c734a24e4c752b45f04"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (36 lines \u00D7 2): src/protean/dx/pack/skills/add-event/assets/add_event_same_aggregate.py:65-108 | src/protean/dx/pack/skills/event-handler/assets/event_handler_same_aggregate.py:47-82 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-event/assets/add_event_same_aggregate.py"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"001078275a6a784c1c44188c944d0791492847091e7236362d4dfcfb9c47a125"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): docs_src/guides/consume-state/002.py:127-138 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:161-170 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/consume-state/002.py"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"5972ed5f6042ccb8dcd0d0f01315ea88200df8b1e4b96847f72332103ae9af57"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): docs_src/guides/consume-state/002.py:142-148 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:174-178 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/consume-state/002.py"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"08061423aab5623a6f6ff563f33306d95eb701410008949abf52efcf433cd144"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 7): docs_src/guides/domain-behavior/006.py:77-84 | docs_src/guides/domain-behavior/007.py:76-83 | docs_src/guides/domain-behavior/008.py:76-83 | src/protean/dx/pack/skills/domain-service/assets/domain_service_callable.py:90-97 | src/protean/dx/pack/skills/domain-service/assets/domain_service_class_methods.py:84-91 | src/protean/dx/pack/skills/domain-service/assets/domain_service_instance_methods.py:87-94 | src/protean/dx/pack/skills/domain-service/assets/domain_service_with_invariants.py:87-94 \u2014 before extracting anything, compare \u0060docs_src/guides/domain-behavior/006.py\u0060 and \u0060docs_src/guides/domain-behavior/007.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 45 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-behavior/006.py"},"region":{"startLine":77}}}],"partialFingerprints":{"codehealthFindingId/v1":"493a2def7a6f1b649242458c968ced9a95cbdd6a27f577f6d777d48bba598680"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 4): docs_src/guides/domain-behavior/006.py:96-102 | docs_src/guides/domain-behavior/007.py:95-101 | src/protean/dx/pack/skills/domain-service/assets/domain_service_callable.py:127-133 | src/protean/dx/pack/skills/domain-service/assets/domain_service_with_invariants.py:166-172 \u2014 before extracting anything, compare \u0060docs_src/guides/domain-behavior/006.py\u0060 and \u0060docs_src/guides/domain-behavior/007.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 45 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-behavior/006.py"},"region":{"startLine":96}}}],"partialFingerprints":{"codehealthFindingId/v1":"1efb531492f21b66bc814f6f2999796180525961aeea2953374fc205df2ea1c9"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 5): docs_src/guides/domain-behavior/006.py:106-111 | docs_src/guides/domain-behavior/007.py:105-110 | src/protean/dx/pack/skills/domain-service/assets/domain_service_callable.py:119-124 | src/protean/dx/pack/skills/domain-service/assets/domain_service_instance_methods.py:117-122 | src/protean/dx/pack/skills/domain-service/assets/domain_service_with_invariants.py:121-126 \u2014 before extracting anything, compare \u0060docs_src/guides/domain-behavior/006.py\u0060 and \u0060docs_src/guides/domain-behavior/007.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 45 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-behavior/006.py"},"region":{"startLine":106}}}],"partialFingerprints":{"codehealthFindingId/v1":"418f48aec592332d99e31e7e2aea9307145713e35030b6a69e6b59dbaa279f97"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 3): docs_src/guides/domain-behavior/006.py:138-148 | docs_src/guides/domain-behavior/007.py:137-147 | src/protean/dx/pack/skills/domain-service/assets/domain_service_with_invariants.py:153-163 \u2014 before extracting anything, compare \u0060docs_src/guides/domain-behavior/006.py\u0060 and \u0060docs_src/guides/domain-behavior/007.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 45 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/domain-behavior/006.py"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d2e49647f1048120ecd0e6356c310ebb8e60226c5c0cd4553c86d6ed978b4a3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 5): docs_src/guides/getting-started/es-tutorial/ch06.py:227-232 | docs_src/guides/getting-started/es-tutorial/ch08.py:253-258 | docs_src/guides/getting-started/es-tutorial/ch18.py:198-203 | docs_src/guides/getting-started/es-tutorial/ch20.py:192-197 | docs_src/guides/getting-started/es-tutorial/ch22.py:377-382 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch06.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch18.py\u0060 as WHOLE FILES: 85% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 3 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch06.py"},"region":{"startLine":227}}}],"partialFingerprints":{"codehealthFindingId/v1":"972d88f11045b49e2aabd64bd7abda9f3dd0cfd1c13e7413b6d8fbdfa76795cb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 5): docs_src/guides/getting-started/es-tutorial/ch06.py:236-241 | docs_src/guides/getting-started/es-tutorial/ch08.py:262-267 | docs_src/guides/getting-started/es-tutorial/ch18.py:207-212 | docs_src/guides/getting-started/es-tutorial/ch20.py:201-206 | docs_src/guides/getting-started/es-tutorial/ch22.py:386-391 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch06.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch18.py\u0060 as WHOLE FILES: 85% of the shorter file\u0027s lines also appear in the other, so this reads as one file having been copied from the other rather than as a helper waiting to be extracted. The 3 duplicated block(s) this scan matched between them are fragments of that copy, not the extent of it \u2014 treat the file pair as the unit. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch06.py"},"region":{"startLine":236}}}],"partialFingerprints":{"codehealthFindingId/v1":"a913e5b8300746e109bb3fb22216caa54773645744b5b40401041136c76f1c13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch09.py:186-195 | docs_src/guides/getting-started/es-tutorial/ch22.py:233-242 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch09.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch22.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 46 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch09.py"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c96149354060a8139f969f254301dd9a721d84b9bdbd511e1041804f31cde04"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch09.py:205-209 | docs_src/guides/getting-started/es-tutorial/ch22.py:252-256 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch09.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch22.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 46 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch09.py"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0229585bcfc70328752ac9f3d7e4f9f5b4facd84a9267b6d2a5a990315e1174"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch09.py:246-252 | docs_src/guides/getting-started/es-tutorial/ch22.py:289-295 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch09.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch22.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 46 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch09.py"},"region":{"startLine":246}}}],"partialFingerprints":{"codehealthFindingId/v1":"842bf11ebbf560a97c336912360c4aaf9bc0904e669d368d83f65cc9c7a3553f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): docs_src/guides/getting-started/es-tutorial/ch09.py:298-307 | docs_src/guides/getting-started/es-tutorial/ch22.py:535-543 \u2014 before extracting anything, compare \u0060docs_src/guides/getting-started/es-tutorial/ch09.py\u0060 and \u0060docs_src/guides/getting-started/es-tutorial/ch22.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 46 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/es-tutorial/ch09.py"},"region":{"startLine":298}}}],"partialFingerprints":{"codehealthFindingId/v1":"be2bb68bd49a1f82c5ce57923efe31747227f6447daf4f4913a46344c88e8ca4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): docs_src/guides/getting-started/tutorial/ch06.py:222-233 | docs_src/guides/getting-started/tutorial/ch09.py:217-228 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"docs_src/guides/getting-started/tutorial/ch06.py"},"region":{"startLine":222}}}],"partialFingerprints":{"codehealthFindingId/v1":"db2e54ee113d36f32c0ee66d740557620805be7371f1c978efd3411b929666f7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/protean/adapters/broker/inline.py:134-146 | src/protean/adapters/broker/redis_pubsub.py:81-93 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/inline.py"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c5ddf78f8228e0d535c71a9f0f2074c0e2b289ca90332be05f3cd02c93d638d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/protean/adapters/broker/inline.py:989-995 | src/protean/adapters/broker/redis_pubsub.py:110-116 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060stream\u0060 to \u0060str | None = None\u0060 in one and \u0060str | None = \u0022\u0022\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/inline.py"},"region":{"startLine":989}}}],"partialFingerprints":{"codehealthFindingId/v1":"d586b381eb62f6476af13b5cdd815621ba2a6a776bcc5e999befc1b314d7d44f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/adapters/broker/redis.py:1563-1571 | src/protean/adapters/broker/redis_pubsub.py:294-306 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. Note that the copies do not run to the end of the range shown: their LAST lines are different code, not the same code under different names \u2014 the matched region ends inside that line. Extract the lines above it, and read the last line of each site separately."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":1563}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb1d4de83b6afe4067c0b759ceb215e1387b5088aadc18535f02dda5fbdaa55d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/protean/cli/check.py:270-283 | src/protean/cli/verify.py:328-337 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060counts\u0060 to \u0060dict[str, int]\u0060 in one and \u0060dict[str, Any]\u0060 in another, and the duplicated lines use it. The extracted unit therefore needs a parameter type that fits BOTH \u2014 their common supertype where they have one, or a new abstraction over them where they do not \u2014 and settling that is the step that comes BEFORE the extraction above. Where the two types are deliberately unrelated, the duplication is the price of that separation and the honest resolution is to record the decision rather than to extract."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/check.py"},"region":{"startLine":270}}}],"partialFingerprints":{"codehealthFindingId/v1":"88f72b211a48d9e49c36eb031a021004005eb06a22a39b92a3797a2fcb4c0594"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/protean/core/email.py:89-96 | src/protean/core/query.py:189-196 | src/protean/core/value_object.py:185-192 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from all 3 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/email.py"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0f7b75985df0dacabc2a4bccb624b16f4964d28fdb2ea3355cb37e95cb9080f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/core/email.py:145-149 | src/protean/core/value_object.py:325-329 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/email.py"},"region":{"startLine":145}}}],"partialFingerprints":{"codehealthFindingId/v1":"ab003cd06843eac21d805bcf34e5676c1cdffc8bf7c96fff8f22428305b58145"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/core/entity.py:662-666 | src/protean/core/value_object.py:238-242 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":662}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f762c1e2b2d0f18111755cbbcf60e7260efd524db50913330da61712d7bd198"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/core/entity.py:1042-1049 | src/protean/core/projection.py:400-407 \u2014 before extracting anything, compare \u0060src/protean/core/entity.py\u0060 and \u0060src/protean/core/projection.py\u0060 as WHOLE FILES: this scan already matched 5 separate duplicated blocks between them, totalling at least 85 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":1042}}}],"partialFingerprints":{"codehealthFindingId/v1":"67f2c18201f4bc4c442c0bfcf6ef39c9084f97d6bee5b3ae8f84167af69caed4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/protean/core/projection.py:205-214 | src/protean/utils/eventing.py:473-485 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"10a464b8cabf6ada70e37e3395bce78ecbe859bfb47e4332d9f4d5181e2492b0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/core/query.py:254-258 | src/protean/utils/eventing.py:489-493 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/query.py"},"region":{"startLine":254}}}],"partialFingerprints":{"codehealthFindingId/v1":"20e27ad64a64c633d78dc0b0b7f9710a0e8ca846043fbbc1de9587ec64ce7fea"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4): src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py:127-134 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py:89-96 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_simple.py:66-73 | src/protean/dx/pack/skills/command-handler/assets/command_handler_simple.py:68-82 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py\u0060 and \u0060src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 58 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"a8f2d2d1252763b2ecb510f8026ee54d8dc19aad7ec7d151491aeb8c2e8083e2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py:146-150 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py:100-104 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py\u0060 and \u0060src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 58 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"febb139b2200cbbf47b3d5387c07b4c615f182033a718bc893a459cc9f26213a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py:211-226 | src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py:140-158 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py\u0060 and \u0060src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_path_params.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 58 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. The two sit in different directories, so one cannot simply be deleted in favour of the other while both are reached separately: hoist the shared part into a location both already depend on and have each file call it, and retire whichever file turns out to have no caller of its own left. Extracting one helper per block leaves the fork in place. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-command/assets/add_command_multiple_commands.py"},"region":{"startLine":211}}}],"partialFingerprints":{"codehealthFindingId/v1":"70bc85cc251bab8b4b4cdee691153f46fa6795d70b47921414bb2ca92af66cc7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/dx/pack/skills/add-event/assets/add_event_cross_aggregate.py:120-128 | src/protean/dx/pack/skills/event-handler/assets/cross_sync_order_inventory.py:89-93 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-event/assets/add_event_cross_aggregate.py"},"region":{"startLine":120}}}],"partialFingerprints":{"codehealthFindingId/v1":"427887be6be2062d24f99b57ea340a4e903e114068618b30512ebabcfd598145"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/protean/dx/pack/skills/add-event/assets/add_event_multiple_events.py:69-80 | src/protean/dx/pack/skills/event-handler/assets/event_handler_error_handling.py:53-63 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/dx/pack/skills/add-event/assets/add_event_multiple_events.py:65\u0060 calls \u0060String\u0060, \u0060DateTime\u0060 and \u0060src/protean/dx/pack/skills/event-handler/assets/event_handler_error_handling.py:50\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/add-event/assets/add_event_multiple_events.py"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"a6c328978cf86c1f76096bf972d483b333104f6a1f9ebb3121acc10ba904605a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_with_pydantic.py:76-83 | src/protean/dx/pack/skills/command-handler/assets/command_handler_multiple_commands.py:90-97 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/api-endpoint/assets/api_endpoint_with_pydantic.py"},"region":{"startLine":76}}}],"partialFingerprints":{"codehealthFindingId/v1":"de560f8f164168137379e7071f992109e0b6844b906031843e7517cfdd51a9aa"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/dx/pack/skills/entity/assets/entity_with_hasmany.py:73-77 | src/protean/dx/pack/skills/generate-test-scaffold/assets/scaffold_aggregate_unit.py:127-131 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/entity/assets/entity_with_hasmany.py"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"388865c5a8b07951822e686fe8769473bde261550535ce69965066d43c60f909"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py:80-88 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:77-85 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py\u0060 and \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 40 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"9c291173a298de18ecebacec660124d25bd9e2752ccff6640522503303b34a6c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2): src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py:116-125 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:132-141 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py\u0060 and \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 40 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py"},"region":{"startLine":116}}}],"partialFingerprints":{"codehealthFindingId/v1":"5c6ac1e608142fc9ec50bc767d7e12708a0a646760334e11e65338ee7dbaf4c3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py:129-133 | src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py:145-149 \u2014 before extracting anything, compare \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py\u0060 and \u0060src/protean/dx/pack/skills/projector/assets/projector_multiple_projectors.py\u0060 as WHOLE FILES: this scan already matched 4 separate duplicated blocks between them, totalling at least 40 lines, which is the signature of one file having been copied from the other rather than of a helper waiting to be extracted. If that is what happened, the fix is to keep one copy and have the other call it (or delete it), which resolves this row and its siblings together \u2014 extracting one helper per block leaves the fork in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/projector/assets/projector_multiple_events.py"},"region":{"startLine":129}}}],"partialFingerprints":{"codehealthFindingId/v1":"c88194adc05d519dd28442ef58db29715b4b8535688ba98a18dcd472d8fcdf0f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/protean/dx/pack/skills/subscriber/assets/subscriber_domain_interaction.py:61-76 | src/protean/dx/pack/skills/subscriber/assets/subscriber_multiple_streams.py:62-72 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/subscriber/assets/subscriber_domain_interaction.py"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"479d703128e20d646eff93535b2d8ff0d26a5ca9bff502d3a226aebf1c99fca0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/dx/pack/skills/value-object/assets/value_object_in_aggregate.py:102-115 | src/protean/dx/pack/skills/value-object/assets/value_object_in_entity.py:138-146 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/value-object/assets/value_object_in_aggregate.py"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"0d9d0b809b83f946bd6b704079f34b0ea111d0905737d20bc39f82cdfa013bc1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/protean/dx/pack/skills/value-object/assets/value_object_nested.py:84-89 | src/protean/dx/pack/skills/value-object/assets/value_object_with_methods.py:34-39 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/pack/skills/value-object/assets/value_object_nested.py"},"region":{"startLine":84}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3093471a24ed32b97e95ee3b1b124ef6cf79e8224a27c02e7d4e1751efa2c91"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 5): src/protean/port/event_store.py:831-839 | src/protean/port/event_store.py:843-851 | src/protean/port/event_store.py:855-863 | src/protean/server/observatory/routes/timeline.py:149-157 | src/protean/server/observatory/routes/timeline.py:727-735 \u2014 there are 5 copies across 2 file(s) \u2014 more copies than files, so at least one file holds the block twice. Extract it once into a single shared function every call site can reach and call it from all 5 sites; resolving a subset leaves the remainder to drift apart. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":831}}}],"partialFingerprints":{"codehealthFindingId/v1":"76fa62de8aff6b2f5326b42f3e1d5f1ab37a86e977e2f361d33ead8787124875"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/protean/scaffold/add_plan.py:242-256 | src/protean/upgrade_uow.py:44-52 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/add_plan.py"},"region":{"startLine":242}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0aee99789261fe00ce4fcc3476db81ce793c4f1e3d6a639882dca65292905cc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/protean/server/reloader.py:310-315 | src/protean/server/supervisor.py:234-239 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/reloader.py"},"region":{"startLine":310}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a97b86649f980faf9db2e8962b79849c5730e16d94e45978ec77975258c3e58"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20 lines \u00D7 2): src/protean/server/subscription/config_resolver.py:462-481 | src/protean/server/subscription/profiles.py:560-579 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The matched lines also transfer control out of the body holding them, which cannot survive a move into a called unit unchanged: have the extracted unit return that decision and let each site act on it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/config_resolver.py"},"region":{"startLine":462}}}],"partialFingerprints":{"codehealthFindingId/v1":"86647bc38e2e715570f7f30c04565efcf9927aead1d23b03bc11f1a7fa9d9463"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/protean/adapters/broker/__init__.py:38-45 | src/protean/adapters/cache/__init__.py:52-59 | src/protean/adapters/repository/__init__.py:102-109 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere all 3 call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made 3 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/__init__.py"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"f18c5d5fa1aac4e0eb105992c4ec85e80fd2b6b3069df50b6909f597e21b0d69"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/adapters/broker/redis.py:1322-1329 | src/protean/adapters/cache/redis.py:63-70 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":1322}}}],"partialFingerprints":{"codehealthFindingId/v1":"054730f0c2b5ceb6474b1db1e5e850c9f1aabfe960fcea83190005130f3fc2d2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/protean/core/application_service.py:77-84 | src/protean/core/query_handler.py:88-95 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/application_service.py"},"region":{"startLine":77}}}],"partialFingerprints":{"codehealthFindingId/v1":"66e923913a2a155d0c66c47423dfe9511df3299e79e538241020e0908a1a2b39"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2): src/protean/core/projection.py:168-178 | src/protean/utils/eventing.py:440-446 \u2014 the copies span different directories, so extracting a shared function means choosing where it lives: put it somewhere both call sites can already reach \u2014 a location they all depend on today, or a new shared one if there is none \u2014 and call it from each site; until then, every change has to be made twice."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":168}}}],"partialFingerprints":{"codehealthFindingId/v1":"8d80ee7348335f0e28d00175e4a2bbd0c65f1cae068a5f42c85b379e990b90d2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (12 lines \u00D7 2): src/protean/port/broker.py:1103-1114 | src/protean/port/provider.py:482-493 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from both call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/broker.py"},"region":{"startLine":1103}}}],"partialFingerprints":{"codehealthFindingId/v1":"530ed6ff9dc454898bfa8a951776d320bf4ca12aee315b546260904c0b058483"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 4): src/protean/utils/checkpoint_trace.py:100-116 | src/protean/utils/occ_trace.py:106-122 | src/protean/utils/outbox_trace.py:99-114 | src/protean/utils/recovery_trace.py:103-118 \u2014 the copies sit in sibling files of one directory, so a shared home is within easy reach: extract the block into a single shared function the call sites can all reach \u2014 a file they already depend on, or a new one alongside them \u2014 and call it from all 4 call sites, so a change lands once."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/checkpoint_trace.py"},"region":{"startLine":100}}}],"partialFingerprints":{"codehealthFindingId/v1":"8cb1f97bc3f50eeaa3bfcb8dbec1f4d55e8a61652d72d24c55ea6707a8f3976f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (18\u201324 lines \u00D7 2): src/protean/cli/test.py:297-314 | src/protean/cli/test.py:422-445 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/protean/cli/test.py:422\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. The \u0060return\u0060 at the foot of the matched lines is the enclosing body\u0027s own terminal exit, not an early one: it moves with them unchanged, and each site calls the extracted unit from the position that \u0060return\u0060 occupied \u2014 no decision has to be handed back and re-acted on. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just before the matched lines, \u0060src/protean/cli/test.py:295\u0060 calls \u0060track_exit_code\u0060, \u0060run_command\u0060, \u0060ThreadPoolExecutor\u0060 and \u0060src/protean/cli/test.py:422\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/test.py"},"region":{"startLine":297}}}],"partialFingerprints":{"codehealthFindingId/v1":"82e3a17ad90bc6d632f2f5cab9da34e32cc132d1b29731aef0db881b100d1bc2"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/ir/builder.py: src/protean/ir/builder.py changed 39 times in last 90 days, max cyclomatic complexity 33 in IRBuilder._extract_resolved_field at line 424. 1 of those changes was a fix/bug commit, and the other 38 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/ir/builder.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":424}}}],"partialFingerprints":{"codehealthFindingId/v1":"d2ddcceef715093b074c5fb78cd7fe6d829b512715d70045ccdceb950c80b3a8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/adapters/repository/sqlalchemy.py: src/protean/adapters/repository/sqlalchemy.py changed 24 times in last 90 days, max cyclomatic complexity 46 in SqlalchemyModel.__init_subclass__ at line 595. 3 of those changes were fix/bug commits, and the other 21 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/adapters/repository/sqlalchemy.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/repository/sqlalchemy.py"},"region":{"startLine":595}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d542b609836a3d6003ab9229a60a5ad5b09c499056a1c79315b3b293216f3cc"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/fields/spec.py: src/protean/fields/spec.py changed 15 times in last 90 days, max cyclomatic complexity 38 in FieldSpec.resolve_field_kwargs at line 232. 1 of those changes was a fix/bug commit, and the other 14 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/fields/spec.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/spec.py"},"region":{"startLine":232}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce465af9793cf215cba00d170beddb15fe15ed8e4af78cfb114ad140bcf2f069"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/unit_of_work.py: src/protean/core/unit_of_work.py changed 17 times in last 90 days, max cyclomatic complexity 32 in UnitOfWork._do_commit at line 258. 3 of those changes were fix/bug commits, and the other 14 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/unit_of_work.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/unit_of_work.py"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"aecf6ed3cec487a01991d07b72191947cd7c9594d5b9a13157fd73c245e022e1"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/utils/__init__.py: src/protean/utils/__init__.py changed 17 times in last 90 days, max cyclomatic complexity 31 in utils._prepare_pydantic_namespace at line 309. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/utils/__init__.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/__init__.py"},"region":{"startLine":309}}}],"partialFingerprints":{"codehealthFindingId/v1":"425ec80aa15b9b42bc9a917c3058b3d6e349291f64474cda31f6e1cfd1dc04c8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/domain/__init__.py: src/protean/domain/__init__.py changed 20 times in last 90 days, max cyclomatic complexity 23 in Domain._register_element at line 1046. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/domain/__init__.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/__init__.py"},"region":{"startLine":1046}}}],"partialFingerprints":{"codehealthFindingId/v1":"229efce2be745f2cc985c1be23ec676042fd7f772970c59359c28b8f6c8c2728"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/entity.py: src/protean/core/entity.py changed 15 times in last 90 days, max cyclomatic complexity 26 in BaseEntity.model_post_init at line 534. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/entity.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/entity.py"},"region":{"startLine":534}}}],"partialFingerprints":{"codehealthFindingId/v1":"d34f1c01822d5c53659fdfc73a4a0341b4fa0cb45564a53efafd780eec0915ee"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/repository.py: src/protean/core/repository.py changed 12 times in last 90 days, max cyclomatic complexity 27 in BaseRepository._sync_children at line 370. 1 of those changes was a fix/bug commit, and the other 11 changed it for other reasons \u2014 this file is under both repair and feature pressure. Before the next change lands here, make sure the area it touches is under test, then split that area out of the file so the following change is smaller than this one \u2014 a file this often edited pays the complexity back every time. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/repository.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/repository.py"},"region":{"startLine":370}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5020a4ee835c2cab05ad4edab4aa40c443d1ceb9fbff9f44aee6d93676cfe20"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/utils/eventing.py: src/protean/utils/eventing.py changed 17 times in last 90 days, max cyclomatic complexity 19 in Message.to_cloudevent at line 1223. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/utils/eventing.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/eventing.py"},"region":{"startLine":1223}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7224ef464c29fc5c736ddcda298289bec5d48a6e5073803e6290a3b97caeaa6"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/engine.py: src/protean/server/engine.py changed 11 times in last 90 days, max cyclomatic complexity 28 in Engine.handle_message at line 815. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/engine.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/engine.py"},"region":{"startLine":815}}}],"partialFingerprints":{"codehealthFindingId/v1":"d99a3d9e2cac2c0b86ab34e98b7df8309a6b412e0e04fa41c8667aa868f4da21"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/outbox_processor.py: src/protean/server/outbox_processor.py changed 13 times in last 90 days, max cyclomatic complexity 22 in OutboxProcessor._process_single_message at line 358. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/outbox_processor.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/outbox_processor.py"},"region":{"startLine":358}}}],"partialFingerprints":{"codehealthFindingId/v1":"124c21ffc3fd8ffc0a4dbf955940c955ce02d67f1a0c44f74e62e326bb927fb0"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/subscription/event_store_subscription.py: src/protean/server/subscription/event_store_subscription.py changed 13 times in last 90 days, max cyclomatic complexity 21 in EventStoreSubscription.process_batch at line 862. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/subscription/event_store_subscription.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/event_store_subscription.py"},"region":{"startLine":862}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7a6d120c4070db45020d36e2181bcb4354692c8aa0ee06a1db4620b88993de4"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/__init__.py: src/protean/cli/__init__.py changed 16 times in last 90 days, max cyclomatic complexity 17 in cli.server at line 174. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/__init__.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/__init__.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"3d3432d38b3cda6786e8d9b21dc95cddec8dc90c656c583d908d58d15713c26d"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/command.py: src/protean/core/command.py changed 9 times in last 90 days, max cyclomatic complexity 29 in BaseCommand._build_metadata at line 143. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/command.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/command.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"6add443c18e85c8fde9e83b58ba798b865537f4c693180aae261350578e6d833"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/ir.py: src/protean/cli/ir.py changed 8 times in last 90 days, max cyclomatic complexity 32 in ir.diff at line 111. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/ir.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/ir.py"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb7bbb9c95b470e92fcb9a1e2c37e3f84ce864e9726f278d3a990d32847ccedc"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/docs.py: src/protean/cli/docs.py changed 9 times in last 90 days, max cyclomatic complexity 26 in docs.generate at line 101. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/docs.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/docs.py"},"region":{"startLine":101}}}],"partialFingerprints":{"codehealthFindingId/v1":"23bd03473353bf87878e623bac85cc414ccd6eec662b5d0f56c7e4fb1848bea3"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/observatory/metrics.py: src/protean/server/observatory/metrics.py changed 6 times in last 90 days, max cyclomatic complexity 39 in metrics._hand_rolled_metrics at line 527. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/observatory/metrics.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/metrics.py"},"region":{"startLine":527}}}],"partialFingerprints":{"codehealthFindingId/v1":"78034e21cbd40a69b32236137ca45bbba7c89164e5608e6c66993d0306320f51"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/aggregate.py: src/protean/core/aggregate.py changed 12 times in last 90 days, max cyclomatic complexity 18 in BaseAggregate.raise_ at line 174. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/aggregate.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/aggregate.py"},"region":{"startLine":174}}}],"partialFingerprints":{"codehealthFindingId/v1":"86d4804dbb605fb838277f1602ca1bb08bf46dbf3d4a9403f3b184be2975f0f7"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/event.py: src/protean/core/event.py changed 8 times in last 90 days, max cyclomatic complexity 25 in BaseEvent._build_metadata at line 135. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/event.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/event.py"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"6d39505bf013a4604ad23548f5c3feb2e9f2fd1027d2e8f55171da716b7c0a87"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/fields/resolved.py: src/protean/fields/resolved.py changed 11 times in last 90 days, max cyclomatic complexity 18 in ResolvedField.__init__ at line 58. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/fields/resolved.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/resolved.py"},"region":{"startLine":58}}}],"partialFingerprints":{"codehealthFindingId/v1":"989de9ae083c5fbecc5765acb02fdec945bc63d366d8224e8f605d8b851e27bd"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/projection.py: src/protean/core/projection.py changed 12 times in last 90 days, max cyclomatic complexity 16 in BaseProjection.__init__ at line 224. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/projection.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/projection.py"},"region":{"startLine":224}}}],"partialFingerprints":{"codehealthFindingId/v1":"8a1edd9cb11a88fda474d0c01cee1c3f762518e57c2246cb088a5e899c1305ac"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/core/value_object.py: src/protean/core/value_object.py changed 10 times in last 90 days, max cyclomatic complexity 19 in value_object.value_object_from_entity at line 389. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/core/value_object.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/core/value_object.py"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"15b79d31abbca9832d3a498b1854328c5fd154893f7c926e3f489fff5d3c5ace"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/ext/mypy_plugin.py: src/protean/ext/mypy_plugin.py changed 5 times in last 90 days, max cyclomatic complexity 38 in mypy_plugin._synthesize_init at line 631. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/ext/mypy_plugin.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ext/mypy_plugin.py"},"region":{"startLine":631}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ae5fa92cc4942d89f197c2b54c4312052e039e9f6961f7f2b4f65ac8546af22"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/domain/command_processor.py: src/protean/domain/command_processor.py changed 6 times in last 90 days, max cyclomatic complexity 31 in CommandProcessor.process at line 278. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/domain/command_processor.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/command_processor.py"},"region":{"startLine":278}}}],"partialFingerprints":{"codehealthFindingId/v1":"99df2cac831087d0a3a41bab76dadd3c52ffbf464d6b82dea092e3a9a42d2614"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/check.py: src/protean/cli/check.py changed 8 times in last 90 days, max cyclomatic complexity 19 in check._print_rich at line 306. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/check.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/check.py"},"region":{"startLine":306}}}],"partialFingerprints":{"codehealthFindingId/v1":"f790cbee072cbf6ed12e90d69fc8fc382daa2079b4937cc42a0a3ead275a73f1"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/port/event_store.py: src/protean/port/event_store.py changed 10 times in last 90 days, max cyclomatic complexity 15 in BaseEventStore.verify at line 1194. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/port/event_store.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/port/event_store.py"},"region":{"startLine":1194}}}],"partialFingerprints":{"codehealthFindingId/v1":"aebe5b225575dfaf167daae5a03a2a7b14b9d4e13ac3bfe9d112f83ae81bbf0c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/recover.py: src/protean/cli/recover.py changed 3 times in last 90 days, max cyclomatic complexity 48 in recover.recover at line 223. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/recover.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/recover.py"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"18c3030a4c94acf9b4873a4fa8493a4d3e0219607dd3820f66081ddc4c70cb21"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/subscription_status.py: src/protean/server/subscription_status.py changed 8 times in last 90 days, max cyclomatic complexity 18 in subscription_status._collect_stream_status at line 451. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/subscription_status.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription_status.py"},"region":{"startLine":451}}}],"partialFingerprints":{"codehealthFindingId/v1":"534803a89c71b032152a29d302f4bfd779800b53c812d20adcd4a1e70be3470f"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/adapters/broker/redis.py: src/protean/adapters/broker/redis.py changed 8 times in last 90 days, max cyclomatic complexity 17 in RedisBroker._read_blocking at line 390. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/adapters/broker/redis.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/redis.py"},"region":{"startLine":390}}}],"partialFingerprints":{"codehealthFindingId/v1":"d278f30c3d3a5f663cf2c478ec33b85ff0059ca6d7532493e106d97f56bfe5e9"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/domain/handler_setup.py: src/protean/domain/handler_setup.py changed 6 times in last 90 days, max cyclomatic complexity 19 in HandlerConfigurator.validate_sequential_by at line 355. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/domain/handler_setup.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/domain/handler_setup.py"},"region":{"startLine":355}}}],"partialFingerprints":{"codehealthFindingId/v1":"09f7ec26e86a3fe7a134ea6b4c9d461a8ec11cc57fc1d2e800ec3578246c3e1f"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/new.py: src/protean/cli/new.py changed 7 times in last 90 days, max cyclomatic complexity 16 in new.run_project_setup at line 18. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/new.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/new.py"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"1972e1e881095b8b50ccce881c5619e95bbdf59e223a40ba531f8c04b8e355eb"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/test.py: src/protean/cli/test.py changed 7 times in last 90 days, max cyclomatic complexity 16 in test.test_adapter at line 758. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/test.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/test.py"},"region":{"startLine":758}}}],"partialFingerprints":{"codehealthFindingId/v1":"9f6864ffd055ebda89c9689c3c67d8eb27cba81906b94b4c6f0a0369695f708f"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/subscription/profiles.py: src/protean/server/subscription/profiles.py changed 5 times in last 90 days, max cyclomatic complexity 22 in SubscriptionConfig.validate at line 472. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/subscription/profiles.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/subscription/profiles.py"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"795b5644ea5d6944924dd6dc25f33ba256804da9a1d16c61250409da8acf7c0e"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/subscriptions.py: src/protean/cli/subscriptions.py changed 6 times in last 90 days, max cyclomatic complexity 18 in subscriptions.status at line 45. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/subscriptions.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/subscriptions.py"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e9dcca13df90d819a0d52119e7bdc1903d26eae5cb5d2dc7186b0db444554ab"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/ir/diff.py: src/protean/ir/diff.py changed 6 times in last 90 days, max cyclomatic complexity 18 in diff._diff_contracts at line 485. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/ir/diff.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":485}}}],"partialFingerprints":{"codehealthFindingId/v1":"ef09d544b69adb3d8ef46611f808c02476ebf19e471d72325e064668873a9288"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/utils/logging.py: src/protean/utils/logging.py changed 7 times in last 90 days, max cyclomatic complexity 15 in logging.configure_logging at line 154. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/utils/logging.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/logging.py"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"e789e6c8efc359dc1fcc3887c408dc654b4c6b7122495c926f8ef82764911ef7"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/cli/projection.py: src/protean/cli/projection.py changed 6 times in last 90 days, max cyclomatic complexity 17 in projection.status at line 148. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/cli/projection.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/projection.py"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"389c8092b9a37fde64636093c818fca6f76b620b3b165fcec2c47f500d73f704"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/utils/dlq.py: src/protean/utils/dlq.py changed 6 times in last 90 days, max cyclomatic complexity 16 in dlq.discover_subscriptions at line 143. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/utils/dlq.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/utils/dlq.py"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"e85121b4b0902418de4cd0cd59d4fe3eeb1538c25ad9f612a9c4691de41f01e5"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/fields/containers.py: src/protean/fields/containers.py changed 6 times in last 90 days, max cyclomatic complexity 16 in containers.List at line 20. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/fields/containers.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/containers.py"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"f960dd28e21cbf240a24d9ab11b26f1e0fc79918484d93071fdbd3d4a2986a9d"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/ir/generators/schema.py: src/protean/ir/generators/schema.py changed 4 times in last 90 days, max cyclomatic complexity 17 in schema._field_to_schema at line 54. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/ir/generators/schema.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/generators/schema.py"},"region":{"startLine":54}}}],"partialFingerprints":{"codehealthFindingId/v1":"831ab99df2978675540f3e8a00495bec45747fa800ecf5400d1437654b534f70"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/dx/managed_files.py: src/protean/dx/managed_files.py changed 4 times in last 90 days, max cyclomatic complexity 15 in managed_files.diff_managed_file at line 836. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/dx/managed_files.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/dx/managed_files.py"},"region":{"startLine":836}}}],"partialFingerprints":{"codehealthFindingId/v1":"a97d5163a5df1359b7c4390dc17ae7f746de2dbbad5cda84796540c340559fe9"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/fields/association.py: src/protean/fields/association.py changed 3 times in last 90 days, max cyclomatic complexity 20 in HasOne.__set__ at line 429. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/fields/association.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/fields/association.py"},"region":{"startLine":429}}}],"partialFingerprints":{"codehealthFindingId/v1":"83565d9f8e1bfc96ff5646efadb12a70d54f2d3a1efc6c5e6430d4fd6669ec40"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/observatory/routes/domain.py: src/protean/server/observatory/routes/domain.py changed 2 times in last 90 days, max cyclomatic complexity 30 in domain._build_flow_graph at line 202. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/observatory/routes/domain.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/domain.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"824e76da161097cf4b06eb5ca4098fb3b15255300ae56801cc33b442c6f768f9"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/observatory/routes/handlers.py: src/protean/server/observatory/routes/handlers.py changed 3 times in last 90 days, max cyclomatic complexity 19 in handlers.merge_subscription_status at line 214. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/observatory/routes/handlers.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/handlers.py"},"region":{"startLine":214}}}],"partialFingerprints":{"codehealthFindingId/v1":"297cac501eeb809f975517d5647e06fbe2afb80a502cad8b6d1947fbe510f2b7"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/observatory/routes/processes.py: src/protean/server/observatory/routes/processes.py changed 3 times in last 90 days, max cyclomatic complexity 18 in processes.collect_pm_trace_metrics at line 202. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/observatory/routes/processes.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/processes.py"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"3300e0e506194018c326f388b84469b71cc6fbb672d5a8b9df2ce1d8309c1cb8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/server/observatory/routes/timeline.py: src/protean/server/observatory/routes/timeline.py changed 2 times in last 90 days, max cyclomatic complexity 26 in timeline.collect_all_events at line 208. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/server/observatory/routes/timeline.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/routes/timeline.py"},"region":{"startLine":208}}}],"partialFingerprints":{"codehealthFindingId/v1":"7068f851ac65a58ec16552259b0b3e973a95dbfabfa7757752810f8092466a88"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/upgrade_uow.py: src/protean/upgrade_uow.py changed 2 times in last 90 days, max cyclomatic complexity 23 in upgrade_uow._http_names at line 80. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/upgrade_uow.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_uow.py"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"871806fedebf246841196fb9c8312c53a55ccc42c36358099a459d850ed21d81"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/upgrade_opportunities.py: src/protean/upgrade_opportunities.py changed 2 times in last 90 days, max cyclomatic complexity 17 in upgrade_opportunities._apply_import at line 530. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/upgrade_opportunities.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/upgrade_opportunities.py"},"region":{"startLine":530}}}],"partialFingerprints":{"codehealthFindingId/v1":"a6d0d6f8fe43df777232755c38e202a061a515cc40c32114c204adbe29d0c6bc"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/scaffold/model_parser.py: src/protean/scaffold/model_parser.py changed 2 times in last 90 days, max cyclomatic complexity 16 in model_parser.emit_model at line 738. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/scaffold/model_parser.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/scaffold/model_parser.py"},"region":{"startLine":738}}}],"partialFingerprints":{"codehealthFindingId/v1":"06e818a85622eb2244b14877c9c89c28728b758e788e69f7c04d3079fbb1ef0d"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/integrations/fastapi/middleware.py: src/protean/integrations/fastapi/middleware.py changed 2 times in last 90 days, max cyclomatic complexity 16 in DomainContextMiddleware._emit_http_wide_event at line 359. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/integrations/fastapi/middleware.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/integrations/fastapi/middleware.py"},"region":{"startLine":359}}}],"partialFingerprints":{"codehealthFindingId/v1":"149aa17c18535f3d1e7a771f3bc382bc3d217050023566d06f05a500861e4e0f"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/protean/adapters/broker/__init__.py: src/protean/adapters/broker/__init__.py changed 2 times in last 90 days, max cyclomatic complexity 15 in Brokers._initialize at line 47. Frequent change and high complexity in one file compound: schedule the next change to it to include carving out the part being edited, with the area under test before it moves. Counted over 2026-06-22..2026-09-20, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-22 14:53:19 -07:00\u0027 --until=\u00272026-09-20 14:53:19 -07:00\u0027 --full-history --no-merges -- src/protean/adapters/broker/__init__.py\u0060: merges are excluded because a merge re-states changes already counted at their own commits, and history is NOT path-simplified because a change that reached the file through a merged branch is still a change to it. That command counts raw commits and can read HIGHER than this row, which counts a cherry-picked re-land, and a revert together with the commit it undoes, once each \u2014 a difference of several commits on a file whose history was re-landed or reverted inside the window."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/broker/__init__.py"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"713a3e01d2b4687f3a6348136159ca8b53117f843fb92c5af4d952ce64495ace"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: # TODO: page-in the whole stream only because the message-db client has \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060# REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/adapters/event_store/message_db.py"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"b34ae60478d5f8a88fb54fefdd42bbd4694a0ba3dbe17f34f26a14da9428d808"}},{"ruleId":"D17","level":"warning","message":{"text":"FixmeComment: # FIXME\u0060\u0060 \u2014 so it was removed outright during the 1.0 CLI \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060# REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/cli/generate.py"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b68bb029108ad5b6e05e7d65143163c667e59e9337271ffa592213bb168d060"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: # TODO(3.4.6): key by the qualified type string once available in the IR. \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060# REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/diff.py"},"region":{"startLine":1046}}}],"partialFingerprints":{"codehealthFindingId/v1":"fc8877afb6f410833cc76b7e51b77d85a0d5acd312bde9386b3b3aed0d3c4af9"}},{"ruleId":"D17","level":"warning","message":{"text":"TodoComment: # pre-existing limitation of the name-based type string; TODO(3.4.6): \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060# REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/ir/builder.py"},"region":{"startLine":2983}}}],"partialFingerprints":{"codehealthFindingId/v1":"39b75cb74be78201d5fb264bf7014430f0f3c8004111083add28fcc0aed19bb5"}},{"ruleId":"D17","level":"warning","message":{"text":"FixmeComment: # FIXME\u0060\u0060); it was removed outright in the 1.0 CLI surface \u2014 source code is not a task system: move the work to your tracker and leave a reference instead (e.g. \u0060# REF: #123\u0060), so the task is planned where tasks live and the ticket links back to the code."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/cli/test_generate_docker_compose.py"},"region":{"startLine":4}}}],"partialFingerprints":{"codehealthFindingId/v1":"4685a1c87bf96fec583a1f0cd2dc4b0a4c44fa91ebe93b8f48ebfba84e74b2cb"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem statement; the only content is a one-line decision with no consequences: Add why this test matters (e.g. catching adapter-specific divergence that single-adapter tests miss) and its trade-offs (re-randomization cost, false-positive risk)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1270.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e60b9db90bd2b1e6a16999902a24bb206135bd202b3238e332b729a7bda0eadc"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem framing or consequences; only the specs and TLC claim is stated: Add why Protean\u0027s delivery guarantees matter (e.g. out-of-order commits, crash resilience) and note any trade-offs such verification imposes"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1271.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd1ec3ec2d0df1113974222db6a037a12c6942a032c7bb2c499cff2e9a9fb8a7"}},{"ruleId":"D20","level":"warning","message":{"text":"Consequences/trade-offs are absent despite a strong context (shared test suite asserting shared adapter behaviour across memory and Redis) and an explicit rationale for failing fast: Add a Consequences section noting the trade-off of requiring a strict expected-failure pass to catch adapter divergence before it becomes a gap"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1310.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f976452ba632d9b9d8207d56231ffa510e562fa245b10174effc058a35cb93dc"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision is stated: Add why versioned ChangePlans matter (e.g. managing change proposals before committing) and what trade-offs exist (version drift when changes are reverted or merged)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1327.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a63ff38e82d01908976c3ecbce6f6de258b276b8dd002366a6ce3420f39d4f6"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why derive the project.json) and no consequences/trade-offs: Add a Context section explaining why derived manifests are needed over an authoritative one, and a Consequences section covering drift detection trade-offs"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1328.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b40c46d8f049440b35219be415145cca53885e70f7514cce864163bd87597da"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why init-time/runtime raises need diagnostics) and no consequences/trade-offs: Add a Context section explaining that exceptions across outbox/broker boundaries are currently untraceable and the diagnostic needs fix this. Add Consequences covering pickle-invariance cost and the check-rule coexistence it enables"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1331.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"4087540dac929569916070c9373f5af4b26d8fa8b6c1b73649ee9d99abc0c1d4"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision \u0022Runtime invariant failures now carry a coded diagnostic\u0022 is stated: Add why this matters (e.g. failure diagnostics are stale or lost after re-running) and document trade-offs such as the invariant-pre/post annotation burden"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1332.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b75e913e1a968ac19228f499874ec3abc3273b8787ac98b6c69dcda284391e4a"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why diagnostics need resolving_operation) and no consequences/trade-offs: Add a Context section explaining why deterministic commands alone cannot resolve failures and why diagnostic resolution is needed. Add Consequences covering trade-offs such as the resolved failure being visible again or staleness-diagnostic overhead"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1333.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5508009ecd9d10bc1aa92ae8b6a23a38507d8d4be99c901e5a3aacc90cbdee39"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; only the structural format change and no cost of adding Given-When-Then before diagrams: Add a Consequences section noting that each generated slice is longer by one line (Given-When-Then) and how reviewers might find it less readable than the original single-line event-model output"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1336.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"14d1d8373af046fac35dd673e7e154bd6dad04d9e2540cfbd540e0dd65d63102"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; only the decision and no discussion of why it matters or what it costs: Add a Consequences section covering false-positive rate, overhead for raising events, and how to handle existing clusters that already emit nothing"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1337.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f4083ac4ea9889e0f2e15a6f57b18b40534ecbd2af8b5c5e078f4fce01d0a86a"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem statement (why an element-type name needs to be added) and no consequences/trade-offs: Add a Context section explaining the problem (e.g. existing add commands are destructive or create plans that cannot be rolled back) and a Consequences section on trade-offs like preview-only behavior"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1340.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8f8e2c835a4aeed1b49ee9f2496db3adc749ac7af4abb8890e4ef83edda436df"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; the body is restated as a decision with no rationale or impact: Add why generation-gap ownership matters (e.g. prevent accidental re-implementation of hand-owned code) and document the trade-offs: maintenance burden for owners, risk of stale ownership markers when apply fails mid-generation"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1341.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"338680ea5335bd66a9fa68beaff48a37f84008066f8ee0decdc7d972717a620c"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why versioned llms.txt context pack matters) and no consequences/trade-offs: Add a Context section explaining the problem (e.g. needing a single versioned context for Protean projects plus domain-specific overlays) and a Consequences section covering trade-offs like increased boilerplate or dependency coupling"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1344.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"be0f2c995e215694947d647814f122bd7372e4f2a04302547fe300fad166d246"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why an agents doc) and no consequences/trade-offs: Add a Context section explaining why this agent docs feature is needed (e.g. unifying documentation across error types, making fixes self-evident). Add Consequences: the new AGENTS.md file grows with code, how it compares to existing docs, and any maintenance burden."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1346.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5932589deca212b1e5cd369fb44ba05fc16baf61828be3080ae43ecc9962dfc9"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences; only scoring details (per-task spec.json recipe, deterministic gold, compare()) are present: Add the problem being solved (e.g. comparing two evaluation pipelines) and the trade-offs of each approach (deterministic vs adaptive rubric)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1349.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ee772bef248ae9a2b6c6c08fbf4a3921b507fcce8f855a88084f7d0f03a0d66"}},{"ruleId":"D20","level":"warning","message":{"text":"No decision (explicit change or removal) and no consequences/trade-offs are stated: State what the metric is replacing (e.g. a single deterministic pass/fail guard) and its trade-offs (re-running on CI, added overhead)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1350.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac329b6a55205b51e1957af74013929e427f3519ca0d74413d2f07ca50246824"}},{"ruleId":"D20","level":"warning","message":{"text":"Consequences/trade-offs are absent despite a concrete decision (widening mutation testing to three paths) and an explicit test-killer list: Add a Consequences section noting the cost of adding new targets: longer CI/CD cycles, the need for a quarterly pass, and that tests alone drive mutant-killing without source changes"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1353.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"de058ffcc02ff8694da4cc8e58e5c100d9d6e26457236020aac1bac973e46c08"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem or consequences/trade-offs; only an applicability charter is described: Add a Context section explaining why Protean\u0027s shape-inflexible model matters (e.g. avoiding rework for growing systems) and a Consequences section on trade-offs such as loss of control over design decisions"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1354.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"77ddf235dc74049909418c6d9464f76b19a638dafadf823d06e7a29b64715fb3"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision is stated: Add a Context section explaining why batching past the read cap silently truncates (e.g. projection rebuilds failing on a store larger than the old cap) and a Consequences section noting trade-offs such as batch-size overhead, replay cost, or increased memory usage"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1358.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a97f52f7e0d8fdc1ac401b1e4bb06d6896f28cbdd0bd275dd16af17c54f6a75b"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why snapshot predates schema matters) and no consequences/trade-offs: Add a Context section explaining the failure mode (snapshot fails on mismatched field rename/requirement) and a Consequences section covering rebuild cost, warning channel load, and how to handle stale snapshots"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1362.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"751dc205fc34de57bda6647b56d3c5bb89b9fe3f6d67b88fe897f963514ad01b"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why a dead-letter queue) and no consequences/trade-offs: Add a Context section explaining why an exhausted event-store DLQ matters (e.g. retry exhaustion, lost events). Add Consequences covering operational cost of maintaining the DLQ vs the benefit of inspecting failed positions"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1364.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd282e5bf40f06e679744525f1732e0d9ebebe89b2260fcf69f492371df71c8e"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs section describing why drain-rate computation matters (e.g. false positives under load) and how it interacts with the sliding-window slope: Add a Consequences section noting that the lag_drain_rate signal is computed on-the-fly from the existing lag-seconds gauge, so it does not expose new metrics but instead gives insight into drain behavior, and why ignoring gaps could lead to misjudging backlog recovery"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1368.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b14a89ed05bdccb75dd64f2708ef7a3e2dfebc9e1bbf84060eba04afafcb713c"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only an explicit decision (TLa\u002B failure-recovery protocol) with no framing: Add the problem motivating the specification (e.g. unrecoverable subscription dropouts under load) and its consequences (reliability risk vs build cost of TLa\u002B verification)}"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1372.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"8834446d25166015b29727dc03671306d541c0832c39c70c4b704becff23cc34"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why an optimistic-concurrency no-lost-update spec) and no consequences/trade-offs: Add the problem motivating this specification (e.g. concurrent updates causing lost updates under a given invariant), and note any trade-offs such as runtime cost of verification"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1373.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a545faeb38a89018b34c0d7040d014b2fb2513d170314dfca0e60594b23750b7"}},{"ruleId":"D20","level":"warning","message":{"text":"No Context/Problem section describing why Werkzeug\u0027s LocalProxy stack was chosen over stdlib contextvars: Add a Context section explaining the prior problem (incompatibility with asyncio/task semantics) and why domain/context vars were selected"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1375.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"983d6d357bdadf267ab15e1bac9f159e5f94c2c7c85f07fff6d5550b139b6bf0"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why cffi/greenlet were removed from core) and no consequences/trade-offs: Add a Context section explaining the dependency removal rationale (e.g. upstream deprecations, Pinning to supported versions) and a Consequences section on how existing code must change (import declarations, wheel pinning)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1376.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fd791a9e9216f5eb53aff32fb006ad6ed86052819f2be0e1de5fd01740acc1b0"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why trace validation matters) and no consequences/trade-offs: Add the problem motivating OCC protocol trace validation (e.g. a lost-update bug is silently accepted by shipped code) and note any trade-offs such as added runtime overhead or increased log verbosity"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1382.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"42060fd431b9f15b5a4cd57d0a06d7f513ebd66e4dff48f30057fd6a87578cfb"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why an update without a UoW would lose version race) and no consequences/trade-offs: Add the problem statement: why standalone SQLAlchemy updates are needed vs. UnitOfWork, and note the trade-off of losing the UoW path\u0027s concurrency semantics."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1382.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"49dc9d6bafe41c611d2fc3dabd7486d9247cac2d460af297159fc7e423442f09"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; the decision (trace validation via verify-specs \u002B negative checks) is stated but its cost (re-running tests for every failure, false-positive tolerance from divergence rejection) and how it interacts with CI/CD are not mentioned: Add a Consequences section noting that each test run incurs overhead and that the divergence/replay rejection thresholds must be tuned to avoid false positives"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1383.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d3c61bceea4a5d6d448624ac6a3a00eab295f71bbe26ba28117f14a28c616a98"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why the gap-safe \u0060$all\u0060 checkpoint was added) and no consequences/trade-offs: Add a Context section explaining why gap safety for \u0060$all\u0060 matters and a Consequences section on trade-offs such as increased runtime cost of verifying out-of-order logs"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1384.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"05fee806e73e4d49a9d347d7c271cdf3e5c904f50d93b69f535d6bdb575b08d7"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; the decision \u0022Trace validation for the recovery protocol\u0022 is stated but there are no notes on why it matters beyond the shipped record-before-advance path or how it affects test suite behavior: Add a Consequences section noting that this adds an extra negative check (log diverges, no crash redelivery) and explains why green runs are still required despite the model being sound"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1385.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"31d1634eb936364d901d699ec70aabe2113498482c04204c18f80b2bdfd2dcc2"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs are stated: Explain why pattern-matching zero keys should not raise (e.g. avoid false-positive errors) and note the trade-off of silently ignoring a non-existent delete"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1399.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"db52123efba0cd6fb47944b6d1be670563ab4d6f70cafeb7060212cd8907d273"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why schema evolution is needed) and no consequences/trade-offs: Add the problem motivating each ladder tier (e.g. why lenient mode matters for new payloads) and document the trade-offs of permanent lenient mode"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1400.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"58e6f830af15457d3744474c495fa5bc66a6539b64e948d8a788242788f1bf88"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs: Add the problem (advisory check silencing) and its consequences (false positives, expected handler behavior)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1408.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d88ae7cf3e4b3da13dab9a843ac07b1bef28834eec2188404c73263cc75115ab"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision \u0022Added Python 3.15\u0022 is stated: Add a Context section explaining why 3.15 was chosen over 3.14 (e.g., new features, deprecations) and a Consequences section on trade-offs such as requiring allow-prereleases or the CI/PyPI workflow"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1426.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c5df9d6a9796c80870142ef3f77405226e7a27c0474ff6e3c2a55169baeb831"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs: over-reporting/under-reporting and receiver-blind matching are stated but no negative impact is noted: Add a Consequences section noting that \u0060raises\u0060 can falsely claim an event is raised when it isn\u0027t (false positive) and that \u0060invokes\u0060 may wrongly record a call where none exists (false positive), plus the trade-off of needing to re-run diffs after schema changes"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1433.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"49911e3e82cbd21435690f81a5d6f587722030f284052db5dab1b5c1bca0ed3f"}},{"ruleId":"D20","level":"warning","message":{"text":"No migration/consequences section and no trade-offs; the body is a single decision statement with no context or consequences: Add a Consequences section covering why the checksum baseline must be regenerated (version mismatch failure) and how to do it (run protean-check-staleness then regenerate ir.json)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1433.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"19a54806439707c1b8c0bb75bb9bcae05f2821a248b8544f4b69ed4f549046f7"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why EventModeling diff vs text format matters) and no consequences/trade-offs: Add a Context section explaining why EventModeling diff is needed over the existing text format, and a Consequences section on trade-offs such as requiring EventModeling slice parsing"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1435.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2fdf8a45c981511718c41b6d620ff1a55c4cc1315b31f0b7cd47cd408822e6ef"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the validation rule is stated: Add a Context section explaining why format validation matters (e.g. reproducible diffs) and a Consequences section on how rejection breaks existing workflows"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1435.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6f4bed23ec1bc035075fd44a2a9b7a56ed48ba9cef31ea04796ba2d9e496851"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why beyond-head staleness matters) and no consequences/trade-offs: Add a Context section explaining why checkpoints can become stale after a restore and the failure modes it avoids. Add Consequences covering operational cost of requiring verify-checkpoints and any false-positive risk from resetting to head."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1446.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"684040ca23bcd6d9b7dae8bbdafb1ee840cd694d6c1abcf6c6de5fb85c396679"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; the decision is stated but there are no notes on why truncating before every message_db test matters beyond the test-isolation claim: Add a Consequences section noting that autouse fixture overhead (e.g. per-test setup/teardown) could be measurable and whether it is acceptable for the test suite"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1449.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6bd3f3e3841fff564d487e7b91d38ccf2dc42375ba415ad11427767e51644336"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only a one-line rationale with no framing: Add why this bundling is needed (e.g. runtime guidance without vendoring) and the trade-offs (bundled size, dependency on importlib-resources)}"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1463.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b27e064fb6a0c70933bd0eefd60c9f90f84ed482abc858d5486946cd7bcd89f"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem motivation or consequences/trade-offs: Add why protean dx is needed (e.g. decoupling coding-agent guidance from the project) and note trade-offs such as managed-block persistence vs. re-run cost"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1465.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"62c959f92174e5d5ef285a8f3e416a9ab9c4145ce24b3c1bc392c3e164e68dcc"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; only the problem and a one-line fix are stated: Add a Consequences section noting the change breaks observatory commands requiring click in core-only mode until server extra is installed"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1465.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"467ead9deb0833e3682b95076783b739f2356c4eebb3dba1bb4867dc53e7aa22"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs section describing what the change breaks for users who rely on dry-run output (project-relative path listing) and why it is still needed: Add a Consequences section noting that the dry run now prints project-relative paths instead of failing with FileExistsError, so anyone running \u0060protean new --dry-run\u0060 to inspect what will be created must read the output rather than being warned off by failure"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1466.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"11fea686c4bffceddaaf32b22c8b57800c9a10a88dba8af8f6e4e83d81f296c3"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs; the decision is stated but no cost of rejecting new . and .. names (e.g. migration pain for projects that previously used them): Add a Consequences section noting that existing projects relying on new ./.. names will break and describe how to migrate them"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1466.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2611ffdf847d1da1cf02d3b9f9b12eaae9c012f791ff538243a3b5a19579b64a"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision \u0022\u0060protean new\u0060 refuses a target directory that resolves outside the output directory\u0022 is stated: Add why this matters (e.g. projects referencing symlinks in the output dir are now broken) and note any trade-offs, e.g. requiring targets to be placed inside the output dir instead of elsewhere"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1466.security.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"de03d3d0573eebea15cb286892d974465633489a536dfda5ad743ff6ba93a9b2"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why a Model Context Protocol server) and no consequences/trade-offs: Add the problem motivating the MCP command (e.g. need to expose framework tools as standalone commands) and document trade-offs such as default stdio vs streaming over HTTP"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1467.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"17405d1ac3ca47b7ffeb6910a0ad1a90d771b07493971b70891297985e6c0717"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only the decision (renaming --pretend to --dry-run) is stated: Add a Context section explaining why pretend was removed and what it broke for users who relied on it, then a Consequences section noting that dry-running does not change output files or commit hooks"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1473.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"822bf58b3480d592aae044306ef418f01096380c7cd3b3cce33f208871592732"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why three files instead of one) or consequences/trade-offs: Add a Context section explaining the problem (the canonical set plus three new files) and a Consequences section on trade-offs such as increased file count and dx check drift detection"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1474.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"7cbd232a745d6494c81980f430f7b349794e264f17af5da63141a5a64ed35743"}},{"ruleId":"D20","level":"warning","message":{"text":"The decision is excellent but the context/problem and consequences/trade-offs are thin; only a one-line summary of each is visible: Add a Context section explaining why security boundaries matter (e.g. injection attacks on String/Text fields) and a Consequences section covering trade-offs like the lack of operator control over transport/authentication"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1482.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"380130e0ca9e3a57fd5e814df90818c068a8caa5f5c782645fc1fcbc8c9c6d56"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why the quickstart needed rework) and no consequences/trade-offs: Add a Context section explaining why the existing docs quickstart was stale (no test ran), and a Consequences section covering trade-offs such as the removal of the non-tested guide"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1485.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"39b5087a4e9030832d6c4113d5231cee85f7ddd19c62db2285f227c43d3ee542"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why replace the README Quick Start) and no consequences/trade-offs: Add why the README Quick Start is stale/corrupting (e.g. a published post was added but not reflected in docs), and note any trade-offs such as the guard test\u0027s cost of comparing verbatim regions"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1486.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e06003dde75c436e6aad76f26483a4e0392eca33fe5c79b5262bb5d838d6409f"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem and no consequences/trade-offs; only a documentation-linking rationale: Add the problem (e.g. why the reference application matters) and the trade-offs of linking docs to an external runnable app"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1487.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0cd8b93d24845ed0c278ffa32e1f29e2b63a1a1a5b88f1c737b61a06d609e68"}},{"ruleId":"D20","level":"warning","message":{"text":"No consequences/trade-offs: the ADR describes only what the harness does without stating when it should or shouldn\u0027t be used: Add a Consequences section covering trade-offs such as CI cost for the replay lane and how the transcript format interacts with existing scoring tools"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1509.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"bc771b3e3bbb31b3644c88acff3f9549d3b8c5f8de333d8b13683bbb58757995"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why move skills from placeholder to full set) and no consequences/trade-offs: Add a Context section explaining why the placeholder was inadequate and a Consequences section on trade-offs such as increased pack size and relicensing"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1521.added.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"db49f3cc92a343411cd25bc356f2b1f4d13e736ab323cf366b6fb51b77321592"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (why upcasters must run on replayed events rather than snapshots) and no consequences/trade-offs: Add a Context section explaining the problem: stored snapshots hold aggregate state that may no longer match the current schema, so they must be discarded and replayed to rebuild aggregates. Then document Consequences such as replay cost vs snapshot durability."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1526.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"74a754161a8fb44d946c3ac20197624a97f34a8404556cb83d54c6a1131b02be"}},{"ruleId":"D20","level":"warning","message":{"text":"No context/problem (the stale read bug) and no consequences/trade-offs: Add the original problem (stale record returned instead of newest) and document the trade-offs: the false-positive staleness risk when replaying past checkpoints"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1529.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"74d000a755abce090e0e07fb280d52fa1ec76b0cf92107a7c183b972f803ea16"}},{"ruleId":"D22","level":"warning","message":{"text":"Duplicate function definition. The same function signature and likely implementation exist in two different internal modules (\u0060_helpers\u0060 and \u0060_ir_utils\u0060).: Remove the duplicate from one module and import from the other, or consolidate into a single utility module. (signatures: src.protean.cli._helpers.load_domain(domain_path: str, as_json: bool): Domain | src.protean.cli._ir_utils.load_domain(domain_path: str, as_json: bool): Domain)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"50caaa46c0921d3c4d75b3babaf6a7520547beb854f77891af6de5cc9261aab0"}},{"ruleId":"D22","level":"warning","message":{"text":"Inconsistent DLQ (Dead Letter Queue) API surface across broker implementations. \u0060InlineBroker\u0060 exposes message retrieval (\u0060get_dlq_messages\u0060), while \u0060RedisBroker\u0060 exposes management operations (\u0060dlq_depth\u0060, \u0060dlq_trim\u0060) but lacks a direct message retrieval method in the signature list. This forces consumers to use different methods or rely on underlying client instances to inspect DLQs depending on the broker.: Standardize the DLQ interface. Either add \u0060get_dlq_messages\u0060 to \u0060RedisBroker\u0060 or ensure the \u0060Brokers\u0060 manager provides a unified way to inspect DLQ contents across all providers. (signatures: src.protean.adapters.broker.inline.InlineBroker.get_dlq_messages(self, consumer_group: str, stream: str | None): dict[str, list[tuple[str, dict[str, Any], str, float]]] | src.protean.adapters.broker.redis.RedisBroker.dlq_depth(self, dlq_stream: str): int | src.protean.adapters.broker.redis.RedisBroker.dlq_trim(self, dlq_stream: str, min_id: str): int)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"5f610663e071ebda514f5c105da2febf3031759b0572e8c77a3405aa9ddf9e37"}},{"ruleId":"D22","level":"warning","message":{"text":"Inconsistent method naming for lookup evaluation/generation. Elasticsearch lookups use \u0060as_expression\u0060, Memory lookups use \u0060evaluate\u0060, and SQLAlchemy lookups primarily expose \u0060lookup_name\u0060 (with some having \u0060as_expression\u0060 or \u0060process_target\u0060). This inconsistency makes it difficult to write generic code that iterates over lookup types.: Unify the method name across all repository adapters for generating query expressions (e.g., standardize on \u0060as_expression\u0060 or \u0060build_query\u0060). If \u0060evaluate\u0060 is meant for in-memory filtering, document the distinction clearly, but the naming variance is confusing. (signatures: src.protean.adapters.repository.elasticsearch.Exact.as_expression(self): Any | src.protean.adapters.repository.memory.Exact.evaluate(self): bool | src.protean.adapters.repository.sqlalchemy.Exact.lookup_name: str)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"279d4a3f393a20663702246f2f1c8a6cb967b43e3648bd8c1045469a4711372f"}},{"ruleId":"D22","level":"warning","message":{"text":"Duplicate CLI commands for DLQ management. Both \u0060eventstore\u0060 and \u0060dlq\u0060 subcommands expose a \u0060list_dlq\u0060 (and likely \u0060inspect\u0060, \u0060replay\u0060, \u0060purge\u0060) functionality. This creates user confusion about which command to use.: Deprecate one of the command groups (likely \u0060eventstore\u0060 if \u0060dlq\u0060 is the dedicated namespace) and redirect users to the single canonical command. (signatures: src.protean.cli.eventstore.list_dlq(ctx: Context, domain: ..., subscription, output_json: ...) | src.protean.cli.dlq.list_dlq(domain: ..., subscription, limit: ...))"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"ded5807898b28c0612a3d7e6f5e789ba8b39a7a747bab17224f5a6211da773f5"}},{"ruleId":"D25","level":"error","message":{"text":"ADR not followed: 1391.fixed: The summary shows only Protean types, so the presence-check behavior of remove/keys and set_ttl is not observable, leaving whether the KeyError branch was dropped in favor of a silent absence check unverifiable. (changes/1391.fixed.md)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1391.fixed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ad48317097a8bffaabeeec2dc0f872437e99742560d2fbd51e3f4f14465dd01e"}},{"ruleId":"D25","level":"error","message":{"text":"ADR not followed: 1455.changed: The summary shows no String or Text type, so the mandated sanitization default flip and new [field_defaults] sanitize config key cannot be verified. (changes/1455.changed.md)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1455.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d00bae68cfc649919731a1a50f8d17284a8d4299c1a3d1c785c940929e5b7fb1"}},{"ruleId":"D25","level":"error","message":{"text":"ADR not followed: 1473.changed: --pretend and its -p short form are deprecated in favor of --dry-run, so the code must not expose either. (changes/1473.changed.md)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"changes/1473.changed.md"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5ea22e6bb8a1cc782493c4d433501d4b2a82cd7872ecd72152f9cea0333eb9a"}},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"d5b8f11381d61a58459ffc7c595fd52d09c03c711894a63a9578043d2338412b"},"taxa":[{"id":"CWE-829","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"6c6c4d237167bdc6ddef76f81db70800dfd61f906b2e1955367c10054ca299c9"},"taxa":[{"id":"CWE-269","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-829","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"125054216d7ce73eaefb5f26e751d7c84f3d2bba5452077f01807dde88091bd1"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"edfdc045e10792b9c928ca745b16610981c5794f41b5f59f1e7eea31862caf66"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a1f31e3fc38e806c632551480508ae27b2701acddad0a9d80c648ba1fc9463b3"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"c1bb7814097052b3b9e49cf20adb5ffa3c94da3abc00863955683dc4725b2e91"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"9a4694634fcc293590fee9e2191767b55a632013523e5569a7db2972085e85fc"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"71d409363b55a1d24dc05307b924cc6c6729c6dbea72afa05fed85828fe13b0b"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"ae4b19a624088a80ae967fa19fc6e2d3b4d86bf95f6afb9918729adad8224e32"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b7d0141152c5300ba863d47573fe0b6384121aac3afaa70381eea83bdc15cefe"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"493308c88e8c66fcb98ce33fa8a7c07e2fee06375429dcf7629ec741ee5f79d7"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"82a1893f62fe8dee3fcdaad2e3da3e94b86729172346ee8d336b86cb9d8780c6"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"9d07e15baa39ee5cdf7c003e36a9f051ab49f0febe1db421a9f914243272717a"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a550cf5e27a8b506045e8d79bea30953c1a97b6937e60e5e7073c41d1cf1cd6e"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"6b562a86ba4fad32d6ccdcd6ca2d4c34c2236a59e5d8276adbfb83a1790cdee0"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"2903fa9664e2d196228e6564cf156160d4e6d6702304b78c69ad819fad43a630"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"86cc361b36735e4f8d9b9924f9bfcd4f8ebd2ce257f31fd78c4b71420d976aeb"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"0a02061a85b317c44abbb431933da8bd61c6f33417c729cd0eade79448b4127e"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"d789fc811d81ae3e39cfa7dd3279809c0b7e527d2ff78dd2b53ebfc25825f041"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"e70c345f4d1433a65509fd2be24ba8f096ea474179246f8a2ed2be77537913e8"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"10f13a2de4f6a6cfaf66bd9f2ed1e56e0212f43f25accd9dacc5d5fafd97a67b"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b8b7c21505d0dfce59e03bfde35252da1f893ba2d1214245a8e80fbdb6addee1"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"84150de1ff64b9ad0d1bb317379afdc1c18a575d31dbb21ea917801131b25c19"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"f5af43878084eccdb48d1ee06fe6b73a01a895e01daf46dd717bbb61cc3ab095"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"0368062220b7d03a1fa9e9d2bccb854d86c67fc9ecc0cc9ff48703e4ad75233a"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"3bfb062085fda1f3c91e45900c000e1ef9d1449d8ad7ab90e3a7218da6970c0c"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b76302d18983e3c0cee9775f03774a94229c7acc75fcce0c17820ebd1b7afbf3"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"d818e944899ba27da1fbc623858eb1f91f4682165316fc5b831f8d206800cdd7"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"3b9efcad3268ab46fd0fb54df14deea6c5951ea38e77698fc552ed94fc361f11"},"taxa":[{"id":"CWE-89","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a63d5412fec2a26b71be1cdb539d0d07eb9cda287c6833604acc3beeb24bdb54"},"taxa":[{"id":"CWE-89","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"254d9caa7c6cbc484a34ffd6c37ef221dde95637c59dad29e311d643fb07a92a"},"taxa":[{"id":"CWE-276","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D29","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"c7b62d3d23124798abe784e9f6fd9621f69ec051ccbb209dbffcbcdc456f4036"},"taxa":[{"id":"CWE-276","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"error","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"dbe5dd3727ba4046de16db291cdceaae5d3efa33568619b215aecdc5c3f7afb6"}},{"ruleId":"D31","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"476176a40f7dde5968156df41a3ad51fabec36db7b9ad2c78af7fdee298fccfb"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a0297c8aaa596b1956ed1f7042756a810605c555c1c1338bffa648c457ffa757"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"4ee3859a47479e2bd660fa18dc71aa4bd99036c46abb6c1c8f7678d0f6c07c14"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"a59fbc7b17e129cebdc63ccf0e22fa87fb197f9dd5f2fa32d0d2af68d4b928f2"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}},{"id":"CWE-353","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"35f120102942fbbc83fe61c7559876429b1f870fe753b44a9b99ac50073fb409"},"taxa":[{"id":"CWE-1357","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"ruleId":"D31","level":"note","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b5e717a1b8b7733e788760df475586d0e21de9957de78aed8f71717e6171e372"}},{"ruleId":"D32","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"3e0b28668a3f7d1228ec5e221703696feadbb00ec114e9cd7c146cd4d5c9cfcb"}},{"ruleId":"D32","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"aaa9cdf2d943dc973b5d71dce36333ce7ddef574e38c10e9663e37aa13092334"}},{"ruleId":"D32","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"b5c17d2ec43c359056a1152db366531081d7dc0f7919d320315fa86e0ea44630"}},{"ruleId":"D32","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"bec08b6a9ea6d6482e283f5a6c685f84d5e340c6696aa086967d85e75c527920"}},{"ruleId":"D34","level":"note","message":{"text":"Orphaned files with no living knowledge: 1 of 352 analysed file(s) have no living knowledge left \u2014 their last meaningful change has decayed away, so if one breaks, no one currently understands it (counted over production source files of roughly 2,400 bytes or more, excluding vendored, generated and example/demo trees and test files identified by path convention, largest first; 352 of the 529 production source files in this repository met that bar). None is large enough to earn a read-through of its own, so this row stands in for the per-file rows rather than raising one each \u2014 most significant first: src/protean/utils/inflection.py. Attach the read to the next change that touches one of them: have a second person review that change, and leave behind a short comment or test recording what the file is for, so the knowledge comes back at the cost of a change you were making anyway."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"ce861fd78f6935114d3a342cb90ad25870f984e1042954fcbbe27c0e23be3658"}},{"ruleId":"D36","level":"note","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"eb00976a698a5d68999b7ee6d27206fd374e916853e7ff1ead5eed42386f043f"}},{"ruleId":"D36","level":"warning","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"90f83b4fa27db32740afe9540c905f3c0499caed87f61049a8a903ecc95b41c3"}},{"ruleId":"D36","level":"note","message":{"text":"A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."},"partialFingerprints":{"codehealthFindingId/v1":"4f1e7684f8281bd255ddef97105c7055c2ebae06964c8745716b83e174debe83"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cbutton\u003E with no accessible text: A button with no text and no aria-label has no accessible name. Add visible text or an aria-label (an icon-only button still needs one)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":405}}}],"partialFingerprints":{"codehealthFindingId/v1":"46e4c578c22c3e5eb8ba02e04d30b9b9770726e634f01591f1c1636111c88f30"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cinput\u003E without a programmatic label: This control has only a placeholder \u2014 a placeholder is not a label (it vanishes on input and many AT ignore it). Add a \u003Clabel for\u003E, a wrapping \u003Clabel\u003E, or aria-label."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/eventstore.html"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"2776ae8eef2b49ace4b9658ebf9765b745944d7b220936f04b382bdd6f8d5718"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cselect\u003E without a programmatic label: This control has no associated label. Add a \u003Clabel for\u003E / wrapping \u003Clabel\u003E / aria-label / aria-labelledby so assistive tech can name it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/handlers.html"},"region":{"startLine":66}}}],"partialFingerprints":{"codehealthFindingId/v1":"77b8121878e1f95358f21b9578d628d10445fc0c77e07dd21811307580c826e4"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cinput\u003E without a programmatic label: This control has only a placeholder \u2014 a placeholder is not a label (it vanishes on input and many AT ignore it). Add a \u003Clabel for\u003E, a wrapping \u003Clabel\u003E, or aria-label."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/messages.html"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b0512f28c6919b41a96e9681692e7462f2cb8ad5e6f8c42d094449e0ec1f686"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cselect\u003E without a programmatic label: This control has no associated label. Add a \u003Clabel for\u003E / wrapping \u003Clabel\u003E / aria-label / aria-labelledby so assistive tech can name it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/processes.html"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1f897a8d84b13ae9934916429e34d4107345922e8e7f4194c16fc416a24c8e2"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cselect\u003E without a programmatic label: This control has no associated label. Add a \u003Clabel for\u003E / wrapping \u003Clabel\u003E / aria-label / aria-labelledby so assistive tech can name it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/timeline.html"},"region":{"startLine":46}}}],"partialFingerprints":{"codehealthFindingId/v1":"b88c5aa662f7194953b833947624316b55f60e661f3911c879df0ca3f7f8364c"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cinput\u003E without a programmatic label: This control has only a placeholder \u2014 a placeholder is not a label (it vanishes on input and many AT ignore it). Add a \u003Clabel for\u003E, a wrapping \u003Clabel\u003E, or aria-label."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/timeline.html"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"080d2f89a755bf1c89a5a514ccc382232f7fa17cc3fe5e2c167abb5386c1584c"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cinput\u003E without a programmatic label: This control has only a placeholder \u2014 a placeholder is not a label (it vanishes on input and many AT ignore it). Add a \u003Clabel for\u003E, a wrapping \u003Clabel\u003E, or aria-label."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/timeline.html"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"0417a91334abd33465887a26cfb4c09c83dbec9a62839abf54b91f577beddc70"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Cselect\u003E without a programmatic label: This control has no associated label. Add a \u003Clabel for\u003E / wrapping \u003Clabel\u003E / aria-label / aria-labelledby so assistive tech can name it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/timeline.html"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"98ab509b4134468e57dd780f69ccb3c57d15c2e0b2f5bb67d4f8ff64296ff49b"}},{"ruleId":"AC3","level":"warning","message":{"text":"Heading level jumps from h1 to h3: Skipping heading levels breaks the document outline assistive tech relies on. Don\u0027t jump levels \u2014 increase by at most one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/templates/timeline.html"},"region":{"startLine":326}}}],"partialFingerprints":{"codehealthFindingId/v1":"c22b3f81557d58dab95f2bcec41cb514611901e10d15cc2e74b15c789b9d22f1"}},{"ruleId":"AC7","level":"warning","message":{"text":"Accessibility enforcement below the top rung: No accessibility enforcement found \u2014 no automated accessibility check runs over the HTML your app renders. Assert the accessibility invariants over that HTML in the test suite you already have (parse the output and assert, or drive a browser), and gate that test in CI so a regression blocks the merge. What was searched, so you can tell an absence from a miss: the 22 markup file(s) this pass actually assessed, the linter configuration checked in beside them, and this repository\u0027s test and CI files \u2014 matched by name against the accessibility checkers this dimension carries. An audit run outside the repository, a hosted scanner, or a check whose name is not one of those, is not seen here."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d46019b86eff5ddad9db289e6802ac158899e980df54c34f67722442787ead62"}},{"ruleId":"P3","level":"note","message":{"text":"No SAST: No static application security testing detected. For this repository\u0027s stack, add bandit, \u0060semgrep --config=p/python\u0060, or CodeQL\u0027s python pack as a CI step. What was searched, so you can tell an absence from a miss: the 20543 CI workflow file(s) in this repository, and the scanner and linter configuration checked in beside them. A scan that runs outside CI, one configured in your forge\u0027s web UI rather than in a committed file, or a tool whose name is none of those this check carries, is not seen \u2014 if that is your case the row is wrong, and saying so is more useful than adding a second scanner."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"6e54424179c892f03ef2fd003130ac4bd43f39bbf3b1ca0a0143e25acb80ec87"}},{"ruleId":"R1","level":"warning","message":{"text":"Type Safety: 0 typed \u00B7 15 plain JS \u2014 the untyped files are src/protean/server/observatory/static/js/causation-graph.js, src/protean/server/observatory/static/js/charts.js, src/protean/server/observatory/static/js/core.js, src/protean/server/observatory/static/js/domain-detail.js, src/protean/server/observatory/static/js/domain-flows.js, src/protean/server/observatory/static/js/domain-processes.js (\u002B9 more)."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d00ee7953f55325a823d27e5db9657c80ca9b9861c0c0abf8fe487cd3fa586d3"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (198 matched lines \u00D7 2 locations): src/protean/server/observatory/static/js/handlers.js:121 \u00B7 src/protean/server/observatory/static/js/processes.js:94 \u2014 the two spans are one implementation copied and then locally edited \u2014 1433 tokens are still identical, in the same order in both files, with only local edits between them. The copies have already begun to drift, which is this row\u0027s finding: an edit made to one and not the other changes behaviour silently. Diff the two spans first to learn what genuinely differs, then extract the shared core into one module both sites use, passing the differences in as parameters \u2014 or, if one copy exists only because the other could not be imported from its context, make one of them the single source the other is generated or re-exported from. If one copy is no longer reachable, delete it rather than letting it shadow the live one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":121}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0664b527797bc5260a301ad89e9601116eb7f2283183dad645e16d3ad2c9c00"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (107 matched lines \u00D7 2 locations): src/protean/server/observatory/static/js/eventstore.js:32 \u00B7 src/protean/server/observatory/static/js/processes.js:40 \u2014 the two spans are one implementation copied and then locally edited \u2014 714 tokens are still identical, in the same order in both files, with only local edits between them. The copies have already begun to drift, which is this row\u0027s finding: an edit made to one and not the other changes behaviour silently. Diff the two spans first to learn what genuinely differs, then extract the shared core into one module both sites use, passing the differences in as parameters \u2014 or, if one copy exists only because the other could not be imported from its context, make one of them the single source the other is generated or re-exported from. If one copy is no longer reachable, delete it rather than letting it shadow the live one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"9731dd07d0512727729a8faef74beffb99d9e6bc08e386bb109d6e569e171e2e"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (58 matched lines \u00D7 2 locations): src/protean/server/observatory/static/js/handlers.js:34 \u00B7 src/protean/server/observatory/static/js/processes.js:30 \u2014 the two spans are one implementation copied and then locally edited \u2014 421 tokens are still identical, in the same order in both files, with only local edits between them. The copies have already begun to drift, which is this row\u0027s finding: an edit made to one and not the other changes behaviour silently. Diff the two spans first to learn what genuinely differs, then extract the shared core into one module both sites use, passing the differences in as parameters \u2014 or, if one copy exists only because the other could not be imported from its context, make one of them the single source the other is generated or re-exported from. If one copy is no longer reachable, delete it rather than letting it shadow the live one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"a8070d4947dd4984a8194515db12768cdc687f131d5fec126dc0d4b2adfb5f35"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (29 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:799 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:640 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":799}}}],"partialFingerprints":{"codehealthFindingId/v1":"805ec4405f822958330a5d36e8a602e916d49a435cc73b9121044c6f2066471f"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (22 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:750 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:586 \u2014 the 2 copies sit in sibling files in one directory, so check first whether one of them (or an existing module there) already owns this behaviour and the others should call it; otherwise extract it into one module in that directory and have each site call it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":750}}}],"partialFingerprints":{"codehealthFindingId/v1":"291f54a7ddb41d31cc865369ef2fd57a3aefb11ec1dabc8d6768107a8d1053d0"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2 locations): src/protean/server/observatory/static/js/charts.js:84 \u00B7 src/protean/server/observatory/static/js/charts.js:189 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/charts.js"},"region":{"startLine":84}}}],"partialFingerprints":{"codehealthFindingId/v1":"792c60401cdb332f52b91eee50546354b0a8b520a1510f76ae773d116cc4e6c8"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (18 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:645 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:530 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"66006adf4284228ec30c50a5f86c65d0b67b3433039a0cedba537cda0b3b7494"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (15 matched lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:965 \u00B7 src/protean/server/observatory/static/js/timeline.js:953 \u2014 the two spans are one implementation copied and then locally edited \u2014 95 tokens are still identical, in the same order in both files, with only local edits between them. The copies have already begun to drift, which is this row\u0027s finding: an edit made to one and not the other changes behaviour silently. Diff the two spans first to learn what genuinely differs, then extract the shared core into one module both sites use, passing the differences in as parameters \u2014 or, if one copy exists only because the other could not be imported from its context, make one of them the single source the other is generated or re-exported from. If one copy is no longer reachable, delete it rather than letting it shadow the live one."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":965}}}],"partialFingerprints":{"codehealthFindingId/v1":"0fd7251b69aca9722c9693841a416faa73a1bfdb639722d278bc09cfff76697b"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-flows.js:737 \u00B7 src/protean/server/observatory/static/js/domain-processes.js:382 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":737}}}],"partialFingerprints":{"codehealthFindingId/v1":"a917e0db133553911fe94f533196d792db6bf23731b75c7ac7f7110a0c349639"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2 locations): src/protean/server/observatory/static/js/messages.js:433 \u00B7 src/protean/server/observatory/static/js/messages.js:452 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":433}}}],"partialFingerprints":{"codehealthFindingId/v1":"044c81d85423025b1c078a7ddfa7ea8eb5cfe1333fd22624cab7a9fa432789a5"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:93 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:119 \u2014 the 2 copies sit in sibling files in one directory, so check first whether one of them (or an existing module there) already owns this behaviour and the others should call it; otherwise extract it into one module in that directory and have each site call it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":93}}}],"partialFingerprints":{"codehealthFindingId/v1":"79f466a4575e58f240a22fa8ad9e5476a89053a28b5bfc8f322022cd3a39162a"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 3 locations): src/protean/server/observatory/static/js/eventstore.js:60 \u00B7 src/protean/server/observatory/static/js/handlers.js:121 \u00B7 src/protean/server/observatory/static/js/processes.js:94 \u2014 the 3 copies are spread across 3 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"f97abe51012572501ee26023850cc4386689c2bd08a5c7807f0e90b1f3db0ec2"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2 locations): src/protean/server/observatory/static/js/messages.js:51 \u00B7 src/protean/server/observatory/static/js/messages.js:68 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"c4d8fb950464e8e56b88091fffb4d2294ac7ae5ec37ab53c207fd8697face6f2"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2 locations): src/protean/server/observatory/static/js/overview.js:373 \u00B7 src/protean/server/observatory/static/js/timeline.js:1553 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":373}}}],"partialFingerprints":{"codehealthFindingId/v1":"856dd385077aef04898faf3d2f1374a1cb0d2675c8ee56406931c5f22182f30f"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2 locations): src/protean/server/observatory/static/js/timeline.js:1092 \u00B7 src/protean/server/observatory/static/js/timeline.js:1105 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1092}}}],"partialFingerprints":{"codehealthFindingId/v1":"40178e9fc260b170d054abec2eba4def2e4a77f9f36f40faba35b531752c42fd"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-detail.js:117 \u00B7 src/protean/server/observatory/static/js/domain-detail.js:129 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"e3c02747349a5b9df58080cb12517ba14a18b139912ad3cf97971a73ac186d6c"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-flows.js:608 \u00B7 src/protean/server/observatory/static/js/domain-flows.js:792 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":608}}}],"partialFingerprints":{"codehealthFindingId/v1":"4148ea2625277971f16c211c47c49eb02f68e7c7f5c6e145ad25c91ff1612182"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2 locations): src/protean/server/observatory/static/js/timeline.js:288 \u00B7 src/protean/server/observatory/static/js/timeline.js:772 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":288}}}],"partialFingerprints":{"codehealthFindingId/v1":"f720de6ee8cad6f5482f161cd1ec4ddde06062d2b354aafa06e06122a9f0e7a6"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:206 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:1098 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":206}}}],"partialFingerprints":{"codehealthFindingId/v1":"33255fa8088b699608eaf4adb9e343907ee72c980746c16e3b5fc4fa28d34a92"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:349 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:364 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":349}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e2244e1a71fcd33e1c0628c52c8d2c2740ab50cbea5e50381b41ad5f9feea0c"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:410 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:429 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":410}}}],"partialFingerprints":{"codehealthFindingId/v1":"09299456cff266e116fa51c23bf00f7ba56f2bd53cf7c8be98061999d9810a81"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 4 locations): src/protean/server/observatory/static/js/causation-graph.js:690 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:703 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:718 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:560 \u2014 the 2 copies sit in sibling files in one directory, so check first whether one of them (or an existing module there) already owns this behaviour and the others should call it; otherwise extract it into one module in that directory and have each site call it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":690}}}],"partialFingerprints":{"codehealthFindingId/v1":"c19a2920e81f55198c5c5611ce11dbd17169000a8737b4c188fd4dcb99bd49b0"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 3 locations): src/protean/server/observatory/static/js/domain-detail.js:192 \u00B7 src/protean/server/observatory/static/js/domain-detail.js:214 \u00B7 src/protean/server/observatory/static/js/domain-detail.js:319 \u2014 all 3 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4a2d2bda28fcb3f9b241998583764240a214c773e9c1e75254233492e35d286"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-detail.js:208 \u00B7 src/protean/server/observatory/static/js/domain-detail.js:309 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":208}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e53a6399029e2691012aff92e98e481dbda1439ed3d893d098242a7f0efdcf7"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-flows.js:659 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:528 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":659}}}],"partialFingerprints":{"codehealthFindingId/v1":"a29f21c3a78dd4f66c634e079ff0971fc5224e4a66e09f1eb141c3c2a4511157"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-topology.js:557 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:570 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-topology.js"},"region":{"startLine":557}}}],"partialFingerprints":{"codehealthFindingId/v1":"c9cc912d0ef1374a7b068fd683bee21b0b91acfbf129041116a1ee657be94692"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-detail.js:284 \u00B7 src/protean/server/observatory/static/js/domain-detail.js:294 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-detail.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ded92e4207f7e9dee28fb877af01f993a62fb73090d8c96c2a524649fe57787"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-topology.js:343 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:356 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-topology.js"},"region":{"startLine":343}}}],"partialFingerprints":{"codehealthFindingId/v1":"29121fdb54259fee35b744d725ad8b79934033a8aee1cdca6b6a4cfa5198735b"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3 locations): src/protean/server/observatory/static/js/eventstore.js:101 \u00B7 src/protean/server/observatory/static/js/handlers.js:188 \u00B7 src/protean/server/observatory/static/js/processes.js:147 \u2014 the 3 copies are spread across 3 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":101}}}],"partialFingerprints":{"codehealthFindingId/v1":"1f1e9fd251a39a0b1b6318076d49757adaed5a209817d727b9d302a3cfc199d3"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 4 locations): src/protean/server/observatory/static/js/handlers.js:62 \u00B7 src/protean/server/observatory/static/js/handlers.js:70 \u00B7 src/protean/server/observatory/static/js/processes.js:59 \u00B7 src/protean/server/observatory/static/js/processes.js:67 \u2014 the 4 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff1f19e56ecd2dac17a9ba30e0ae8af9302ff10939aacd230f87104e34312338"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2 locations): src/protean/server/observatory/static/js/messages.js:297 \u00B7 src/protean/server/observatory/static/js/messages.js:355 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":297}}}],"partialFingerprints":{"codehealthFindingId/v1":"07848aea209d786b6b5643d1628258cd1a0101419be897dfa8dc03943f5a2cf4"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2 locations): src/protean/server/observatory/static/js/timeline.js:244 \u00B7 src/protean/server/observatory/static/js/timeline.js:726 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":244}}}],"partialFingerprints":{"codehealthFindingId/v1":"8de0ca20dc4a8c84efaf9420954c6b152e92040d2d85f25f9d82db6089ffc689"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 4 locations): src/protean/server/observatory/static/js/causation-graph.js:678 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:689 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:702 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:717 \u2014 all 4 copies are in the same file, so extract the block into one function there and call it from every one of those sites \u2014 resolving only two of them leaves the rest to drift apart the first time one is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":678}}}],"partialFingerprints":{"codehealthFindingId/v1":"10c0255b731b483ba089bff0a0b0bbd5bc5eee22f782b70103c8b9a10024ddad"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-flows.js:519 \u00B7 src/protean/server/observatory/static/js/timeline.js:262 \u2014 the 2 copies sit in sibling files in one directory, so check first whether one of them (or an existing module there) already owns this behaviour and the others should call it; otherwise extract it into one module in that directory and have each site call it."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-flows.js"},"region":{"startLine":519}}}],"partialFingerprints":{"codehealthFindingId/v1":"509e0adf381cb7be8568c78c8f3dd06ca725cb66a11ce4df411b0acc7980e22e"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 3 locations): src/protean/server/observatory/static/js/timeline.js:692 \u00B7 src/protean/server/observatory/static/js/timeline.js:708 \u00B7 src/protean/server/observatory/static/js/timeline.js:770 \u2014 all 3 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":692}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d4ec95703e4072d3334bc093d9eaa070062cf481fed795e82b89551d9bb13c6"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:394 \u00B7 src/protean/server/observatory/static/js/causation-graph.js:420 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":394}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb23c3b868e61c538e2938b36ffa6b37d694b56de195ca175f8b66d6b1b812fb"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2 locations): src/protean/server/observatory/static/js/causation-graph.js:937 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:682 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":937}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d5884085a3e2ba844c6fd12c713c2b75c35e75381cee00300a0fb14a68b017a"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2 locations): src/protean/server/observatory/static/js/domain-topology.js:373 \u00B7 src/protean/server/observatory/static/js/domain-topology.js:399 \u2014 both copies are in the same file, so extract the block into one function there and call it from each site \u2014 the copies drift apart the first time only one of them is edited."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/domain-topology.js"},"region":{"startLine":373}}}],"partialFingerprints":{"codehealthFindingId/v1":"58923647bdb9a17d3b7c004f9e1a46f118b67b958f7a161273969b50b10224b6"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2 locations): src/protean/server/observatory/static/js/timeline.js:1000 \u00B7 src/protean/server/observatory/static/js/timeline.js:1258 \u2014 all 2 copies are in the same file, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1000}}}],"partialFingerprints":{"codehealthFindingId/v1":"f853dcd3d322922ecdd8709dbd397a97aeeea3352977c528960b782e96b3219e"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2 locations): src/protean/server/observatory/static/js/eventstore.js:27 \u00B7 src/protean/server/observatory/static/js/handlers.js:40 \u2014 the 2 copies are spread across 2 files, and the CITED SPAN is not a self-contained block \u2014 it runs from inside one construct into the next (the tail of a branch plus the head of the following one, a run of switch arms, the end of a declaration plus the list that follows it) rather than covering a whole unit. So do not lift these lines literally: no call can be substituted for a half-open construct. Extract the enclosing repeated UNIT instead \u2014 the whole function, component or branch these lines sit in \u2014 and where the repetition IS the construct (a run of switch arms, a stack of near-identical declarations) replace it with one table or registry looked up by key rather than a helper each arm calls. The copies still drift apart the first time only one of them is edited, which is why this is reported."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/eventstore.js"},"region":{"startLine":27}}}],"partialFingerprints":{"codehealthFindingId/v1":"9d9b66f01011d864ce68ff1e6ce2aeafb73743704121d9c354fd00577e4f7447"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function (anonymous) (cyclomatic 31, cognitive 26): (anonymous) has cyclomatic complexity 31 and cognitive complexity 26; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2dd72a3cd75b4c92a9af4584bf0072619a8bf0749c3734f7d0e43b9924cd79f"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function (anonymous) (cyclomatic 29, cognitive 24): (anonymous) has cyclomatic complexity 29 and cognitive complexity 24; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"0687aeaf2bc78e85339224dd45213f9cae8dc50a71cd999c25c959eaafc798ff"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _renderCausationTree (cyclomatic 27, cognitive 25): _renderCausationTree has cyclomatic complexity 27 and cognitive complexity 25; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"77bacef8ad601a5c7757e27804c1139d10c5f6670994a50f25ce397444d3f1a2"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _showEventDetail (cyclomatic 26, cognitive 29): _showEventDetail has cyclomatic complexity 26 and cognitive complexity 29; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":830}}}],"partialFingerprints":{"codehealthFindingId/v1":"26592d948215fb9ddedd199d6f7a62eb62322e76a1dc5ca48c15ad5b9be1b58d"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function (anonymous) (cyclomatic 24, cognitive 21): (anonymous) has cyclomatic complexity 24 and cognitive complexity 21; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/core.js"},"region":{"startLine":396}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e0811afbf8a441287b15a033c51ae42e7c21ddbe363995a16842da37d6632c6"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _readURL (cyclomatic 23, cognitive 27): _readURL has cyclomatic complexity 23 and cognitive complexity 27; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":986}}}],"partialFingerprints":{"codehealthFindingId/v1":"11a81085e9bde5c40347e2dc75627dfa664c410dd9e6dbb1818aec5ab2e5fab4"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function showTraceDetail (cyclomatic 23, cognitive 16): showTraceDetail has cyclomatic complexity 23 and cognitive complexity 16; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/messages.js"},"region":{"startLine":290}}}],"partialFingerprints":{"codehealthFindingId/v1":"9bdb31e7f555a2f46084e38a24ee2d2507962ee3505be3269ea792c2d4ccf0f8"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _switchCausationView (cyclomatic 21, cognitive 31): _switchCausationView has cyclomatic complexity 21 and cognitive complexity 31; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":450}}}],"partialFingerprints":{"codehealthFindingId/v1":"d9679d14b0425922119eb82ecc783a858e922cc962b2e11f528011371b046ad9"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function searchTraces (cyclomatic 21, cognitive 19): searchTraces has cyclomatic complexity 21 and cognitive complexity 19; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":200}}}],"partialFingerprints":{"codehealthFindingId/v1":"4501085795c795091c171725ee9f28e40c2bbea43521b6367af2d920354b3e61"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _fetchLatestEvent (cyclomatic 18, cognitive 24): _fetchLatestEvent has cyclomatic complexity 18 and cognitive complexity 24; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1320}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ad603fe521ced0cafa085909e8387bae80f99be908197e3447136f3742e58c7"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _showCorrelationView (cyclomatic 18, cognitive 21): _showCorrelationView has cyclomatic complexity 18 and cognitive complexity 21; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e8b50f01c61cec3c73fbe1b04372947598b7544804a8ceab37acbb18bc73608"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _showAggregateView (cyclomatic 18, cognitive 21): _showAggregateView has cyclomatic complexity 18 and cognitive complexity 21; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":596}}}],"partialFingerprints":{"codehealthFindingId/v1":"81cb971fb6a4a50d5cf5ff0e4a724b7e06f4f1de3dac99ed5fce2c94bdbe1035"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function (anonymous) (cyclomatic 17, cognitive 15): (anonymous) has cyclomatic complexity 17 and cognitive complexity 15; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/processes.js"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"739ce25434ec1005f1b65b58a006f06896ee44bfd25950c3dc53f7523fbde99c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function updateHealthBanner (cyclomatic 16, cognitive 23): updateHealthBanner has cyclomatic complexity 16 and cognitive complexity 23; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/overview.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e2ad41c19cbf967887ee3577bb659199c76e432c71015f6ef8bd818b1a8711a"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function fetchEvents (cyclomatic 16, cognitive 20): fetchEvents has cyclomatic complexity 16 and cognitive complexity 20; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a0d675491b22621d57e29814b1e5bd0d19f8b5f12caed01a71d149671fed4b0"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _bindEvents (cyclomatic 16, cognitive 15): _bindEvents has cyclomatic complexity 16 and cognitive complexity 15; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":1081}}}],"partialFingerprints":{"codehealthFindingId/v1":"13ead74cd3e3bbf6513e40ac5850d1ce6cc638fdf660e547c5124efd1ca8af30"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _updateCorrelationDisplay (cyclomatic 15, cognitive 24): _updateCorrelationDisplay has cyclomatic complexity 15 and cognitive complexity 24; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":400}}}],"partialFingerprints":{"codehealthFindingId/v1":"96cf8b7261e85fd838b1025efa6f5479ce26fccfb5a15c49aa5c0b6a992721d0"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _renderAggregateTimeline (cyclomatic 15, cognitive 24): _renderAggregateTimeline has cyclomatic complexity 15 and cognitive complexity 24; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/timeline.js"},"region":{"startLine":645}}}],"partialFingerprints":{"codehealthFindingId/v1":"92608097bd8e739e1783425fb1c8dbac8ee40d5f1b251d5767e3a70ffbfdeabc"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function _transferCollapseState (cyclomatic 15, cognitive 20): _transferCollapseState has cyclomatic complexity 15 and cognitive complexity 20; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive is at or above cyclomatic here, so the branching is nested or entangled rather than laid out side by side \u2014 extracting each decision into its own named function is the change that pays. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/causation-graph.js"},"region":{"startLine":1112}}}],"partialFingerprints":{"codehealthFindingId/v1":"f00f401ff5dda2170feadb4bab11553f18daa12393466be0ab23869e0e11590c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function (anonymous) (cyclomatic 15, cognitive 14): (anonymous) has cyclomatic complexity 15 and cognitive complexity 14; this row is raised above a cyclomatic bar of 10. The two numbers answer different questions and the gap between them is what decides whether to act: cyclomatic counts the independent arms through the body, cognitive counts what it costs to hold them in your head, so nesting and mixed boolean chains raise it while a flat run of independent arms does not. Cognitive sits below cyclomatic here, so much of the count is breadth \u2014 arms side by side rather than stacked \u2014 and splitting per arm would leave a function per arm; group the work between the checks into named steps instead. Measured by this repository\u0027s own parse of the file, so a body assembled at runtime, or generated, is counted as written rather than as it executes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/server/observatory/static/js/handlers.js"},"region":{"startLine":135}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff0712197c2645d6e9c5a209bb919a995befe14924e23a87ba8d1b73d37d5651"}},{"ruleId":"R3","level":"warning","message":{"text":"Large Files: 7 file(s) over 400 lines (counted as significant lines \u2014 blank lines excluded \u2014 over production source only, tests excluded), largest first: src/protean/server/observatory/static/js/timeline.js (1365), src/protean/server/observatory/static/js/causation-graph.js (992), src/protean/server/observatory/static/js/domain-flows.js (702), src/protean/server/observatory/static/js/messages.js (619), src/protean/server/observatory/static/js/domain-topology.js (617), src/protean/server/observatory/static/js/core.js (518) (\u002B1 more)."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"cecee31b569df4f07e06db732f1ca037af27b5afef9023da51f9673d931a142f"}},{"ruleId":"S1","level":"note","message":{"text":"No security response headers detected: No Content-Security-Policy / X-Frame-Options / X-Content-Type-Options configuration found \u2014 defense in depth, even when a reverse proxy could set them. This is reported because \u0060nginx.conf\u0060 is committed to this repository and declares the server that serves it, so the configuration that would carry these headers is in this repository and was read in full. (\u22122.0 on this card.)"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/protean/template/domain_template/nginx.conf"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"af2661b5abe574e0f3d62dffd3b2579e891e6a4ccd28ad59c64b569d37f2c080"}}],"taxonomies":[{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d","organization":"MITRE","informationUri":"https://cwe.mitre.org/","isComprehensive":false,"shortDescription":{"text":"The MITRE Common Weakness Enumeration (CWE)."},"taxa":[{"id":"CWE-1032","guid":"5f21e517-68aa-a650-9a25-5771ef024637","name":"OWASP Top Ten \u2014 Security Misconfiguration category","shortDescription":{"text":"OWASP Top Ten \u2014 Security Misconfiguration category"},"helpUri":"https://cwe.mitre.org/data/definitions/1032.html"},{"id":"CWE-1059","guid":"a2381a08-60f6-9554-a8b8-f3018cfaaca5","name":"Insufficient Technical Documentation","shortDescription":{"text":"Insufficient Technical Documentation"},"helpUri":"https://cwe.mitre.org/data/definitions/1059.html"},{"id":"CWE-1357","guid":"e4d2e772-757e-0a5c-bd7d-77052949d866","name":"Reliance on Insufficiently Trustworthy Component","shortDescription":{"text":"Reliance on Insufficiently Trustworthy Component"},"helpUri":"https://cwe.mitre.org/data/definitions/1357.html"},{"id":"CWE-1395","guid":"800e09e7-c11a-8654-9fa6-86f398995fed","name":"Dependency on Vulnerable Third-Party Component","shortDescription":{"text":"Dependency on Vulnerable Third-Party Component"},"helpUri":"https://cwe.mitre.org/data/definitions/1395.html"},{"id":"CWE-16","guid":"659db3ea-affc-8453-8add-c1218fbfcb92","name":"Configuration","shortDescription":{"text":"Configuration"},"helpUri":"https://cwe.mitre.org/data/definitions/16.html"},{"id":"CWE-200","guid":"b0ce3b1d-7a29-fe50-8aab-9aba899d2988","name":"Exposure of Sensitive Information to an Unauthorized Actor","shortDescription":{"text":"Exposure of Sensitive Information to an Unauthorized Actor"},"helpUri":"https://cwe.mitre.org/data/definitions/200.html"},{"id":"CWE-259","guid":"ae9ad959-fbb6-9d5e-892d-3dca66da0b69","name":"Use of Hard-coded Password","shortDescription":{"text":"Use of Hard-coded Password"},"helpUri":"https://cwe.mitre.org/data/definitions/259.html"},{"id":"CWE-269","guid":"70e1f5f6-81e5-4e5a-ba40-b541c3a346e2","name":"CWE-269","shortDescription":{"text":"CWE-269"},"helpUri":"https://cwe.mitre.org/data/definitions/269.html"},{"id":"CWE-276","guid":"4e27da05-61af-1d5c-aeb5-9f56b6ede3e3","name":"CWE-276","shortDescription":{"text":"CWE-276"},"helpUri":"https://cwe.mitre.org/data/definitions/276.html"},{"id":"CWE-312","guid":"96724ece-b0b2-a45c-83f9-0869fa3f6bea","name":"Cleartext Storage of Sensitive Information","shortDescription":{"text":"Cleartext Storage of Sensitive Information"},"helpUri":"https://cwe.mitre.org/data/definitions/312.html"},{"id":"CWE-353","guid":"09d7e902-d4ee-f05d-ae6c-0a1554d0c18f","name":"CWE-353","shortDescription":{"text":"CWE-353"},"helpUri":"https://cwe.mitre.org/data/definitions/353.html"},{"id":"CWE-359","guid":"b7dfe5b0-0351-645b-a311-b936102c2929","name":"Exposure of Private Personal Information to an Unauthorized Actor","shortDescription":{"text":"Exposure of Private Personal Information to an Unauthorized Actor"},"helpUri":"https://cwe.mitre.org/data/definitions/359.html"},{"id":"CWE-494","guid":"b8a65e0d-e459-4a55-a931-fc1136482375","name":"Download of Code Without Integrity Check","shortDescription":{"text":"Download of Code Without Integrity Check"},"helpUri":"https://cwe.mitre.org/data/definitions/494.html"},{"id":"CWE-506","guid":"401d6455-56e3-0552-9a39-f77461673e3f","name":"CWE-506","shortDescription":{"text":"CWE-506"},"helpUri":"https://cwe.mitre.org/data/definitions/506.html"},{"id":"CWE-732","guid":"1da27e8f-b330-7650-ab63-bd61953eae5d","name":"Incorrect Permission Assignment for Critical Resource","shortDescription":{"text":"Incorrect Permission Assignment for Critical Resource"},"helpUri":"https://cwe.mitre.org/data/definitions/732.html"},{"id":"CWE-77","guid":"332c8ade-6612-9f56-a06b-d8d90b1a8750","name":"Command Injection","shortDescription":{"text":"Command Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/77.html"},{"id":"CWE-78","guid":"2e31ceaf-c7ae-2e5e-9661-cfb1362789cf","name":"OS Command Injection","shortDescription":{"text":"OS Command Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/78.html"},{"id":"CWE-79","guid":"fd45580b-e8c4-fc5e-8c2f-aa8fab0b4dbf","name":"Cross-site Scripting (XSS)","shortDescription":{"text":"Cross-site Scripting (XSS)"},"helpUri":"https://cwe.mitre.org/data/definitions/79.html"},{"id":"CWE-798","guid":"5e8f057d-fee3-995a-a0cb-9fc5b0d174d1","name":"Use of Hard-coded Credentials","shortDescription":{"text":"Use of Hard-coded Credentials"},"helpUri":"https://cwe.mitre.org/data/definitions/798.html"},{"id":"CWE-829","guid":"13c33925-97fb-5a5e-b40c-56d328b8a4d7","name":"CWE-829","shortDescription":{"text":"CWE-829"},"helpUri":"https://cwe.mitre.org/data/definitions/829.html"},{"id":"CWE-89","guid":"6d08fdad-37eb-c150-bbf0-d7d946863407","name":"SQL Injection","shortDescription":{"text":"SQL Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/89.html"},{"id":"CWE-937","guid":"16f316ae-415c-b354-a59b-1f7905f756e9","name":"Using Components with Known Vulnerabilities","shortDescription":{"text":"Using Components with Known Vulnerabilities"},"helpUri":"https://cwe.mitre.org/data/definitions/937.html"},{"id":"CWE-94","guid":"75e7f50c-6c2f-dd52-bf40-bf6c52b861fd","name":"Code Injection","shortDescription":{"text":"Code Injection"},"helpUri":"https://cwe.mitre.org/data/definitions/94.html"}]}],"properties":{"codehealthPublication":{"public":true,"notice":"This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings \u2014 which rule fired, in which file, on which line, and how to fix it \u2014 are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.","securityFindingsRedacted":46,"secretScannerRunsExcluded":0}},"redactionTokens":["A security finding was recorded here. Its details are withheld on the public artifact \u2014 ask the repository owner for the full report."]}]}