{"$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":"D5","name":"Coupling","shortDescription":{"text":"Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D5"},{"id":"D6","name":"Cohesion (LCOM4)","shortDescription":{"text":"Cohesion (LCOM4)"},"helpUri":"https://codehealth.canine.dev/dimensions/D6"},{"id":"D8","name":"Code Coverage","shortDescription":{"text":"Code Coverage"},"helpUri":"https://codehealth.canine.dev/dimensions/D8"},{"id":"D9","name":"Test Distribution","shortDescription":{"text":"Test Distribution"},"helpUri":"https://codehealth.canine.dev/dimensions/D9"},{"id":"D10","name":"Test Quality","shortDescription":{"text":"Test Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D10"},{"id":"D11","name":"Test Reliability","shortDescription":{"text":"Test Reliability"},"helpUri":"https://codehealth.canine.dev/dimensions/D11"},{"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":"D18","name":"Solution Shape","shortDescription":{"text":"Solution Shape"},"helpUri":"https://codehealth.canine.dev/dimensions/D18"},{"id":"D19","name":"Documentation Quality","shortDescription":{"text":"Documentation Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D19"},{"id":"D21","name":"Naming Consistency","shortDescription":{"text":"Naming Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D21"},{"id":"D23","name":"Boundary Type-Coupling","shortDescription":{"text":"Boundary Type-Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D23"},{"id":"D24","name":"Comment Value","shortDescription":{"text":"Comment Value"},"helpUri":"https://codehealth.canine.dev/dimensions/D24"},{"id":"D26","name":"Project Cohesion","shortDescription":{"text":"Project Cohesion"},"helpUri":"https://codehealth.canine.dev/dimensions/D26"},{"id":"D27","name":"Navigability","shortDescription":{"text":"Navigability"},"helpUri":"https://codehealth.canine.dev/dimensions/D27"},{"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":"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":"D39","name":"IL Efficiency","shortDescription":{"text":"IL Efficiency"},"helpUri":"https://codehealth.canine.dev/dimensions/D39"},{"id":"AC1","name":"Text alternatives","shortDescription":{"text":"Text alternatives"},"helpUri":"https://codehealth.canine.dev/dimensions/AC1"},{"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":"AC4","name":"Keyboard semantics","shortDescription":{"text":"Keyboard semantics"},"helpUri":"https://codehealth.canine.dev/dimensions/AC4"},{"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":"AX1","name":"Captive dependencies","shortDescription":{"text":"Captive dependencies"},"helpUri":"https://codehealth.canine.dev/dimensions/AX1"},{"id":"AX10","name":"Code composition","shortDescription":{"text":"Code composition"},"helpUri":"https://codehealth.canine.dev/dimensions/AX10"},{"id":"AX2","name":"Stateful singletons","shortDescription":{"text":"Stateful singletons"},"helpUri":"https://codehealth.canine.dev/dimensions/AX2"},{"id":"AX3","name":"Project dependency cycles","shortDescription":{"text":"Project dependency cycles"},"helpUri":"https://codehealth.canine.dev/dimensions/AX3"},{"id":"AX5","name":"Architecture \u0026 structure","shortDescription":{"text":"Architecture \u0026 structure"},"helpUri":"https://codehealth.canine.dev/dimensions/AX5"},{"id":"AX6","name":"Interface segregation","shortDescription":{"text":"Interface segregation"},"helpUri":"https://codehealth.canine.dev/dimensions/AX6"},{"id":"AX7","name":"Slice cohesion","shortDescription":{"text":"Slice cohesion"},"helpUri":"https://codehealth.canine.dev/dimensions/AX7"},{"id":"AX8","name":"Test isolation","shortDescription":{"text":"Test isolation"},"helpUri":"https://codehealth.canine.dev/dimensions/AX8"},{"id":"C2","name":"Access Controls","shortDescription":{"text":"Access Controls"},"helpUri":"https://codehealth.canine.dev/dimensions/C2"},{"id":"DM1","name":"Aggregate boundaries","shortDescription":{"text":"Aggregate boundaries"},"helpUri":"https://codehealth.canine.dev/dimensions/DM1"},{"id":"DM10","name":"One transaction, one aggregate","shortDescription":{"text":"One transaction, one aggregate"},"helpUri":"https://codehealth.canine.dev/dimensions/DM10"},{"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":"DM2","name":"Strongly-typed ids","shortDescription":{"text":"Strongly-typed ids"},"helpUri":"https://codehealth.canine.dev/dimensions/DM2"},{"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":"ED5","name":"Idempotency","shortDescription":{"text":"Idempotency"},"helpUri":"https://codehealth.canine.dev/dimensions/ED5"},{"id":"ES1","name":"Fold determinism","shortDescription":{"text":"Fold determinism"},"helpUri":"https://codehealth.canine.dev/dimensions/ES1"},{"id":"GD1","name":"Unfinished \u0026 placeholder code","shortDescription":{"text":"Unfinished \u0026 placeholder code"},"helpUri":"https://codehealth.canine.dev/dimensions/GD1"},{"id":"IC1","name":"Incompleteness \u0026 stubs","shortDescription":{"text":"Incompleteness \u0026 stubs"},"helpUri":"https://codehealth.canine.dev/dimensions/IC1"},{"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":"P2","name":"Observability","shortDescription":{"text":"Observability"},"helpUri":"https://codehealth.canine.dev/dimensions/P2"},{"id":"P4","name":"Deployment \u0026 Rollback","shortDescription":{"text":"Deployment \u0026 Rollback"},"helpUri":"https://codehealth.canine.dev/dimensions/P4"},{"id":"PF1","name":"Benchmark discipline","shortDescription":{"text":"Benchmark discipline"},"helpUri":"https://codehealth.canine.dev/dimensions/PF1"},{"id":"PF2","name":"Allocation hygiene","shortDescription":{"text":"Allocation hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/PF2"},{"id":"PF3","name":"Async \u0026 latency hygiene","shortDescription":{"text":"Async \u0026 latency hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/PF3"},{"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":"R4","name":"Test Coverage","shortDescription":{"text":"Test Coverage"},"helpUri":"https://codehealth.canine.dev/dimensions/R4"},{"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":"X1","name":"Async correctness","shortDescription":{"text":"Async correctness"},"helpUri":"https://codehealth.canine.dev/dimensions/X1"},{"id":"X12","name":"Unreachable branch","shortDescription":{"text":"Unreachable branch"},"helpUri":"https://codehealth.canine.dev/dimensions/X12"},{"id":"X13","name":"Undrained process stream","shortDescription":{"text":"Undrained process stream"},"helpUri":"https://codehealth.canine.dev/dimensions/X13"},{"id":"X14","name":"Bypassable address classification","shortDescription":{"text":"Bypassable address classification"},"helpUri":"https://codehealth.canine.dev/dimensions/X14"},{"id":"X15","name":"Unvalidated length from an untrusted reader","shortDescription":{"text":"Unvalidated length from an untrusted reader"},"helpUri":"https://codehealth.canine.dev/dimensions/X15"},{"id":"X16","name":"Unfloored truncation loop","shortDescription":{"text":"Unfloored truncation loop"},"helpUri":"https://codehealth.canine.dev/dimensions/X16"},{"id":"X17","name":"Uncapped recursion over a caller-supplied document","shortDescription":{"text":"Uncapped recursion over a caller-supplied document"},"helpUri":"https://codehealth.canine.dev/dimensions/X17"},{"id":"X18","name":"Disposal-pattern correctness","shortDescription":{"text":"Disposal-pattern correctness"},"helpUri":"https://codehealth.canine.dev/dimensions/X18"},{"id":"X19","name":"Unrestored process-global state","shortDescription":{"text":"Unrestored process-global state"},"helpUri":"https://codehealth.canine.dev/dimensions/X19"},{"id":"X2","name":"Cancellation propagation","shortDescription":{"text":"Cancellation propagation"},"helpUri":"https://codehealth.canine.dev/dimensions/X2"},{"id":"X20","name":"Mistyped argument guard","shortDescription":{"text":"Mistyped argument guard"},"helpUri":"https://codehealth.canine.dev/dimensions/X20"},{"id":"X21","name":"Side-effecting pattern guard","shortDescription":{"text":"Side-effecting pattern guard"},"helpUri":"https://codehealth.canine.dev/dimensions/X21"},{"id":"X22","name":"Contradicted release guard","shortDescription":{"text":"Contradicted release guard"},"helpUri":"https://codehealth.canine.dev/dimensions/X22"},{"id":"X23","name":"Unguarded diagnostic materialisation","shortDescription":{"text":"Unguarded diagnostic materialisation"},"helpUri":"https://codehealth.canine.dev/dimensions/X23"},{"id":"X24","name":"Document value interpolated into markup unescaped","shortDescription":{"text":"Document value interpolated into markup unescaped"},"helpUri":"https://codehealth.canine.dev/dimensions/X24"},{"id":"X25","name":"Inert configuration knob","shortDescription":{"text":"Inert configuration knob"},"helpUri":"https://codehealth.canine.dev/dimensions/X25"},{"id":"X26","name":"Unsynchronised callback handoff","shortDescription":{"text":"Unsynchronised callback handoff"},"helpUri":"https://codehealth.canine.dev/dimensions/X26"},{"id":"X27","name":"Collection changed while being enumerated","shortDescription":{"text":"Collection changed while being enumerated"},"helpUri":"https://codehealth.canine.dev/dimensions/X27"},{"id":"X28","name":"Index access outside its own emptiness guard","shortDescription":{"text":"Index access outside its own emptiness guard"},"helpUri":"https://codehealth.canine.dev/dimensions/X28"},{"id":"X29","name":"Per-element action decided by a fixed element","shortDescription":{"text":"Per-element action decided by a fixed element"},"helpUri":"https://codehealth.canine.dev/dimensions/X29"},{"id":"X3","name":"Exception handling","shortDescription":{"text":"Exception handling"},"helpUri":"https://codehealth.canine.dev/dimensions/X3"},{"id":"X30","name":"Support guard that admits what it rejects","shortDescription":{"text":"Support guard that admits what it rejects"},"helpUri":"https://codehealth.canine.dev/dimensions/X30"},{"id":"X32","name":"Type resolved by simple name across every loaded assembly","shortDescription":{"text":"Type resolved by simple name across every loaded assembly"},"helpUri":"https://codehealth.canine.dev/dimensions/X32"},{"id":"X4","name":"Structured logging","shortDescription":{"text":"Structured logging"},"helpUri":"https://codehealth.canine.dev/dimensions/X4"},{"id":"X5","name":"Nullable reference types","shortDescription":{"text":"Nullable reference types"},"helpUri":"https://codehealth.canine.dev/dimensions/X5"}]}},"results":[{"ruleId":"D1","level":"warning","message":{"text":"AuthoringApi.MapAuthoringApi (cyclomatic 212): AuthoringApi.MapAuthoringApi has cyclomatic complexity 212 (threshold 15). Most of this is not in the body itself: 3 of the 212 points are its own statements and the rest belongs to 54 function literals inside it that branch (lines 291, 322, 134, \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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"c0eb5048a1f6e16417133b5f78c620d93cec3817dd40dbf5e54a2120779a95f8"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 48): render has cyclomatic complexity 48 (threshold 15). Of this number, 35 points are the body\u0027s own statements and 13 belong to 6 function items inside it that branch. 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":"widgets/cai-dimensions.js"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"3647308a53078db8d304fa873601f56025b5230026964a436d27307dc7d89a24"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 48): render has cyclomatic complexity 48 (threshold 15). Of this number, 35 points are the body\u0027s own statements and 13 belong to 6 function items inside it that branch. 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":"widgets/_src/cai-dimensions.js"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"934c1ef30eaed3dc6ffbd706bdeb5ccac56f913b24ff14e019126db402b4e9bb"}},{"ruleId":"D1","level":"warning","message":{"text":"AuthoringNodeJson.ApplyProps (cyclomatic 34): AuthoringNodeJson.ApplyProps has cyclomatic complexity 34 (threshold 15). Of this number, 33 points are the body\u0027s own statements and 1 belongs to one function literal inside it that branches. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Where every arm is uniform \u2014 the same kind of value, with no behaviour of its own \u2014 a table keyed by the case is the shorter form; wherever the arms carry different data or different behaviour, keep them as cases, because collapsing those trades an explicit, reviewable set of cases for nothing."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Api/AuthoringNodeJson.cs"},"region":{"startLine":384}}}],"partialFingerprints":{"codehealthFindingId/v1":"1598a7eddff53a73532752166c7316e137bb49148976760679b7758602eb3051"}},{"ruleId":"D1","level":"warning","message":{"text":"scorecard.check_page (cyclomatic 31): scorecard.check_page has cyclomatic complexity 31 (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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":239}}}],"partialFingerprints":{"codehealthFindingId/v1":"47ed5fb932814899ee14174e3a1cacab4dba970ea5a73929850c8a30dbc44f42"}},{"ruleId":"D1","level":"warning","message":{"text":"Verify.Run (cyclomatic 29): Verify.Run has cyclomatic complexity 29 (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":"tools/ContentSeeder/Verify.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"3936f5b02f7830482edf1fb8a136d67fd26026a09811561ff7d00ba1d630bff8"}},{"ruleId":"D1","level":"warning","message":{"text":"scorecard.scoreCardBodyHtml (cyclomatic 28): scorecard.scoreCardBodyHtml has cyclomatic complexity 28 (threshold 15). Of this number, 26 points are the body\u0027s own statements and 2 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":"widgets/_src/scorecard.js"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d9a1b26c8847db629a4ef86e4d3f7282281704d57714477072d7c49bc3f2c5b"}},{"ruleId":"D1","level":"warning","message":{"text":"cai-card-gallery.z (cyclomatic 28): cai-card-gallery.z has cyclomatic complexity 28 (threshold 15). Of this number, 26 points are the body\u0027s own statements and 2 belong to 2 function literals inside it that branch. 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":"widgets/cai-card-gallery.js"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"b69a7e832db6ec1b2ed1618e58772f5149d012512c7ae732fe53775062d946b9"}},{"ruleId":"D1","level":"warning","message":{"text":"cai-score-card.H (cyclomatic 28): cai-score-card.H has cyclomatic complexity 28 (threshold 15). Of this number, 26 points are the body\u0027s own statements and 2 belong to 2 function literals inside it that branch. 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":"widgets/cai-score-card.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e33511a6ed7f63edb14e942faae3a192c8abceecd1f05d3a07883eabc18a865"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 28): render has cyclomatic complexity 28 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 14 belong to 7 function items inside it that branch. 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":"widgets/contact-form.js"},"region":{"startLine":152}}}],"partialFingerprints":{"codehealthFindingId/v1":"6cca0eabdd0c47c0185e563f4bace562d2119f8a72fb4beedbe8a62e2f1ff7d6"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 28): render has cyclomatic complexity 28 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 14 belong to 7 function items inside it that branch. 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":"widgets/_src/contact-form.js"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"f3d31283bd6c4261431c3fdeffb52ba88a44483c6ad6072440a84b5b11fac87d"}},{"ruleId":"D1","level":"warning","message":{"text":"MarkdownToNodes.Inline (cyclomatic 26): MarkdownToNodes.Inline 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/Imprint.Authoring/Markdown/MarkdownToNodes.cs"},"region":{"startLine":395}}}],"partialFingerprints":{"codehealthFindingId/v1":"2c6db0c1a2c255eb32f28c42205e89e6051e70286fdbfeba23a33521182dd9f1"}},{"ruleId":"D1","level":"warning","message":{"text":"Migrator.MigrateSite (cyclomatic 24): Migrator.MigrateSite 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":"tools/ContentSeeder/Migrator.cs"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"e8715aa48a4b2d68e3ca67b6541125b2cb37b421cc3c69cbee6eb0b548fabc5d"}},{"ruleId":"D1","level":"warning","message":{"text":"scorecard.audit_site (cyclomatic 24): scorecard.audit_site 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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":393}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba1495c12c624fe1a5a6e3d15924fe11e6fd4c60341f6234e7656ed4a871e1fc"}},{"ruleId":"D1","level":"warning","message":{"text":"paint (cyclomatic 24): paint has cyclomatic complexity 24 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 8 belong to 7 function items inside it that branch. 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":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"2e4aab24f0f375c5c2f5355607bcb4c7d76f43414e1ad5a2daf4673ab2a05d42"}},{"ruleId":"D1","level":"warning","message":{"text":"paint (cyclomatic 24): paint has cyclomatic complexity 24 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 8 belong to 7 function items inside it that branch. 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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"0afd4b63f7b4240d194fe777de58d9b046f0649194205fcf214af4dcfde18101"}},{"ruleId":"D1","level":"warning","message":{"text":"Markdown.ToNodes (cyclomatic 21): Markdown.ToNodes 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":"tools/ContentSeeder/Markdown.cs"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"f33b993ac312b6783c8e278f5f665d49b449ef67a72616af9d8c26ff4ec54d25"}},{"ruleId":"D1","level":"warning","message":{"text":"#r (cyclomatic 21): #r has cyclomatic complexity 21 (threshold 15). Of this number, 20 points are the body\u0027s own statements and 1 belongs to one function literal inside it that branches. 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":"widgets/cai-findings.js"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"16069a2ca08cf0473ca5e8eb89f3caf0a3ff8c32096a4ec6e9cb820411afbb11"}},{"ruleId":"D1","level":"warning","message":{"text":"#repoHtml (cyclomatic 21): #repoHtml has cyclomatic complexity 21 (threshold 15). Of this number, 20 points are the body\u0027s own statements and 1 belongs to one function literal inside it that branches. 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":"widgets/_src/cai-findings.js"},"region":{"startLine":107}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd3c8067e909b9700bd4ffdeaf2a978a4df88d1ec3a966e137f6b63992ecf62c"}},{"ruleId":"D1","level":"warning","message":{"text":"serializeInline (cyclomatic 21): serializeInline has cyclomatic complexity 21 (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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"bfacd8d6c3b5678b730482aab77b3ea1e0a147cede6f9201afe2b0a90ef5c857"}},{"ruleId":"D1","level":"warning","message":{"text":"rich-toolbar.serializeInline (cyclomatic 20): rich-toolbar.serializeInline has cyclomatic complexity 20 (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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c4a682322531c4fd86eaf44137eb7f8116ce27f3d056b861f122ef3c28361f6"}},{"ruleId":"D1","level":"warning","message":{"text":"live.cardFromGallery (cyclomatic 19): live.cardFromGallery has cyclomatic complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs 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":"widgets/_src/live.js"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"a03b5d0f10b0cb47b27f0612862a7e2a861689f8f1ef88659cb78c465fb57f75"}},{"ruleId":"D1","level":"warning","message":{"text":"cai-card-gallery.U (cyclomatic 19): cai-card-gallery.U has cyclomatic complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-card-gallery.js"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"f07729810ee2b15776a77c47ee7bb68d9c5bd9ddc9a858e0a9e8f0b7fbc1d817"}},{"ruleId":"D1","level":"warning","message":{"text":"cai-score-card.z (cyclomatic 19): cai-score-card.z has cyclomatic complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-score-card.js"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"a7124d3a79ec8e32b48c7bc4aa27cc0607e76915b668c0c42525065ff71be9c8"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 19): render has cyclomatic complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs to 5 function items inside it that branch. 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":"widgets/cai-trend.js"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"82169929571ca016dbb2fc1eff2b4b191684d23ca266c7d9c6217d86131a68fa"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 19): render has cyclomatic complexity 19 (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":"widgets/cai-score-card.js"},"region":{"startLine":221}}}],"partialFingerprints":{"codehealthFindingId/v1":"9de8372fff0ad587e462c99a54304bcf6bd47945d47288ad8781f450f71be720"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 19): render has cyclomatic complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs to 5 function items inside it that branch. 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":"widgets/_src/cai-trend.js"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"e282c28665c2d3cb340c835f47ec136a0efe5038868812aa2d54364b042a5050"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 19): render has cyclomatic complexity 19 (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":"widgets/_src/cai-score-card.js"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"f54885ca894ffa1b47df2d8417aac602c8714a5d6f585ae99bcb74aeb523fddf"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 18): render has cyclomatic complexity 18 (threshold 15). Of this number, 17 points are the body\u0027s own statements and 1 belongs to 4 function literals inside it that branch. 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":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"85b528dc04678690aafb38b49bda4b0507476b4577c9d12850397c207e71ef9d"}},{"ruleId":"D1","level":"warning","message":{"text":"R (cyclomatic 18): R has cyclomatic complexity 18 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 4 belong to 8 function literals inside it that branch. 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":"widgets/cai-score-card.js"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"c82e04a2840b42b6b448b56f70b00df483deb83c38b8f961e545d8e7bf2390ee"}},{"ruleId":"D1","level":"warning","message":{"text":"B (cyclomatic 18): B has cyclomatic complexity 18 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 4 belong to 8 function literals inside it that branch. 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":"widgets/cai-card-gallery.js"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"e95f29d45e49c90e2450adfeed07e0b86faca3685650e68df6f6612799dd9490"}},{"ruleId":"D1","level":"warning","message":{"text":"#n (cyclomatic 18): #n has cyclomatic complexity 18 (threshold 15). Of this number, 13 points are the body\u0027s own statements and 5 belong to 2 function literals inside it that branch. 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":"widgets/cai-calculator.js"},"region":{"startLine":206}}}],"partialFingerprints":{"codehealthFindingId/v1":"3c4fac0be60387b59f157e091ca67671c05a4a427279a3f1b26de87afb8320af"}},{"ruleId":"D1","level":"warning","message":{"text":"parseCard (cyclomatic 18): parseCard has cyclomatic complexity 18 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 4 belong to 8 function literals inside it that branch. 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":"widgets/_src/scorecard.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"3f59c7bb53495a779104d5a4ef62f586811bde27ac63fda4b0a131c5a0b98f10"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 18): render has cyclomatic complexity 18 (threshold 15). Of this number, 17 points are the body\u0027s own statements and 1 belongs to 4 function literals inside it that branch. 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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"f760a6454bb9159bb064a94b6869999563be18a575e401ca4c80e8048ce15d1c"}},{"ruleId":"D1","level":"warning","message":{"text":"#result (cyclomatic 18): #result has cyclomatic complexity 18 (threshold 15). Of this number, 13 points are the body\u0027s own statements and 5 belong to 2 function literals inside it that branch. 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":"widgets/_src/cai-calculator.js"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a42d04a1293f693b6952b68531da271b5cf4d058bfb17a45ab686b6b4b2c526"}},{"ruleId":"D1","level":"warning","message":{"text":"CanonicalHtml.ParseInlineUntil (cyclomatic 17): CanonicalHtml.ParseInlineUntil 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/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"d709f346480b71a77eb8831af862842f0325dce52a35c3d7337e2d4384afdfd8"}},{"ruleId":"D1","level":"warning","message":{"text":"BlockMapper.PricingTiers (cyclomatic 17): BlockMapper.PricingTiers 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. This is NOT this file\u0027s highest cyclomatic complexity: BlockMapper.Map (cyclomatic 28) is higher and carries no row of its own \u2014 it was excluded as a flat dispatcher (a long switch/match over independent cases: many branches, almost no nesting), which this dimension does not treat as a refactor obligation. It is named here so the ranking you see in this file is not mistaken for the whole of it; the excluded method is counted neither in this dimension\u0027s figures nor in its score."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":536}}}],"partialFingerprints":{"codehealthFindingId/v1":"41987a6078aaaa66f347eb5fad05c7cedeeebeeb05978d76866688890cab197f"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 17): render has cyclomatic complexity 17 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 1 belongs to 4 function literals inside it that branch. 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":"widgets/cai-language-board.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2842fb3f6b1984ab3a78541b7aca57820e9a5e6483c8635c4a44e4fc41533cc"}},{"ruleId":"D1","level":"warning","message":{"text":"paint (cyclomatic 17): paint has cyclomatic complexity 17 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 3 belong to 7 function items inside it that branch. 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":"widgets/cai-language-board.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"f67a85c240d571c11135caae52613a6fa7bd15679741e94319cdeb2b100402dd"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 17): render has cyclomatic complexity 17 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 1 belongs to 4 function literals inside it that branch. 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":"widgets/_src/cai-language-board.js"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"67b4f3d2e7b7300fea24cd2ca9a5462bc96e1c3aa3032b409e390178db2809e8"}},{"ruleId":"D1","level":"warning","message":{"text":"paint (cyclomatic 17): paint has cyclomatic complexity 17 (threshold 15). Of this number, 14 points are the body\u0027s own statements and 3 belong to 7 function items inside it that branch. 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":"widgets/_src/cai-language-board.js"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"1053ee44d15452d60b4f044b4a967a7545f3127029b5305d656d524eb6cc3106"}},{"ruleId":"D1","level":"warning","message":{"text":"init (cyclomatic 17): init has cyclomatic complexity 17 (threshold 15). Most of this is not in the body itself: 7 of the 17 points are its own statements and the rest belongs to 8 function items inside it that branch (onKeyDown, onPointerDown, remember, \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/Imprint.Editor/wwwroot/js/post-split.js"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2bcb7779863faea695751ee8b06e9fcc89c227ab2374770ca1caa436f74acc9"}},{"ruleId":"D1","level":"warning","message":{"text":"restore-wiped-post-bodies.blanked (cyclomatic 16): restore-wiped-post-bodies.blanked 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":"tools/restore-wiped-post-bodies.py"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"07c23e12a2380c6408bcfca0e1df86cfa021b3636aa3106f52826f3e5b0b48db"}},{"ruleId":"D1","level":"warning","message":{"text":"canvas-interop.onKeyDown (cyclomatic 16): canvas-interop.onKeyDown has cyclomatic complexity 16 (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/Imprint.Editor/wwwroot/js/canvas-interop.js"},"region":{"startLine":275}}}],"partialFingerprints":{"codehealthFindingId/v1":"a1d0455d607b426dd55bca236487cbabb1f2b3124d34c07f1530f55c33c4d786"}},{"ruleId":"D1","level":"warning","message":{"text":"post-split.init (cyclomatic 16): post-split.init has cyclomatic complexity 16 (threshold 15). Most of this is not in the body itself: 6 of the 16 points are its own statements and the rest belongs to 3 function literals inside it that branch (lines 90, 77, 51). 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/Imprint.Editor/wwwroot/js/post-split.js"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"654ded9036f9a908781b40d1707f72505e2eac6a42e851cef274eb95653396a2"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 16): render has cyclomatic complexity 16 (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":"widgets/cai-language-support.js"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"d6b6f4406a41af48ef470f84899e58d481d93d8c7d97101957aea07084ca2143"}},{"ruleId":"D1","level":"warning","message":{"text":"render (cyclomatic 16): render has cyclomatic complexity 16 (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":"widgets/_src/cai-language-support.js"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"65a4726b00d1223435cc57f872280f4051983007f79ed8f68870e6ca0f4989c6"}},{"ruleId":"D2","level":"warning","message":{"text":"AuthoringApi.MapAuthoringApi (cognitive 225): AuthoringApi.MapAuthoringApi has cognitive complexity 225 (threshold 15). Most of this is not in the body itself: 2 of the 225 points are its own statements and the rest belongs to 54 function literals inside it that branch (lines 134, 291, 254, \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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"1bb63c619bcf31cc0153abc599b51e83af9e1a2080377cd341fc21effb12a6d4"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 68): render has cognitive complexity 68 (threshold 15). Of this number, 48 points are the body\u0027s own statements and 20 belong to 6 function items 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":"widgets/_src/cai-dimensions.js"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"c27e97e759b60a28ec70c92f4500ea4c76869c3d218f4b5a154fafe5857e77f5"}},{"ruleId":"D2","level":"warning","message":{"text":"Verify.Run (cognitive 64): Verify.Run has cognitive complexity 64 (threshold 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":"tools/ContentSeeder/Verify.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff0cdb37a8ef7fd15b700f6c5f6c097d4ad5e893a770456277ae24bbc3f9bd14"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 60): render has cognitive complexity 60 (threshold 15). Of this number, 43 points are the body\u0027s own statements and 17 belong to 6 function items 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":"widgets/cai-dimensions.js"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"3273f6c05a66fa5b8a6729cc8d485c5346037b09553b425aa182ee99dc7a00be"}},{"ruleId":"D2","level":"warning","message":{"text":"CanonicalHtml.ParseInlineUntil (cognitive 46): CanonicalHtml.ParseInlineUntil has cognitive complexity 46 (threshold 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/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"d0b157f113c9b7db7ea4a44fd2cea18a396b9a4091eb56a653935d9e4641827f"}},{"ruleId":"D2","level":"warning","message":{"text":"scoreCardBodyHtml (cognitive 40): scoreCardBodyHtml has cognitive complexity 40 (threshold 15). Of this number, 38 points are the body\u0027s own statements and 2 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":"widgets/_src/scorecard.js"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"bae198feae01798969c0a74f8fbb2dfaf318d55a6c2f39270adc5352e3bd11d6"}},{"ruleId":"D2","level":"warning","message":{"text":"Migrator.MigrateSite (cognitive 39): Migrator.MigrateSite has cognitive complexity 39 (threshold 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":"tools/ContentSeeder/Migrator.cs"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"f7e4c56bfda8bacc59ccbf8a348f7195081c2f19fdbbeb5a7552f98737180a68"}},{"ruleId":"D2","level":"warning","message":{"text":"MarkdownToNodes.Inline (cognitive 38): MarkdownToNodes.Inline has cognitive complexity 38 (threshold 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/Imprint.Authoring/Markdown/MarkdownToNodes.cs"},"region":{"startLine":395}}}],"partialFingerprints":{"codehealthFindingId/v1":"6df6532528bbd46aadc77dfab06c3f882a2cd4b4b3c76590a88f70e042d5b190"}},{"ruleId":"D2","level":"warning","message":{"text":"H (cognitive 37): H has cognitive complexity 37 (threshold 15). Of this number, 35 points are the body\u0027s own statements and 2 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":"widgets/cai-score-card.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"c1112562e00e58974e95ca88c23aaa70195179888c1a318dd61471317a2d1650"}},{"ruleId":"D2","level":"warning","message":{"text":"z (cognitive 37): z has cognitive complexity 37 (threshold 15). Of this number, 35 points are the body\u0027s own statements and 2 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":"widgets/cai-card-gallery.js"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"b609785b72ac0ae49a45e3e71edf85dadf30f3edf2a34d0583ae0fe4b760b345"}},{"ruleId":"D2","level":"warning","message":{"text":"scorecard.scoreCardBodyHtml (cognitive 33): scorecard.scoreCardBodyHtml has cognitive complexity 33 (threshold 15). Drivers by points: if/else 8 (12 pts), boolean chains 9, ternaries 4 (8 pts), loops 2 (4 pts) (nesting depth added 10). Of this number, 31 points are the body\u0027s own statements and 2 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":"widgets/_src/scorecard.js"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"5bdb70e414002567e68d3e96171535fae146a402e86e69d575c7a971b4d6f621"}},{"ruleId":"D2","level":"warning","message":{"text":"scorecard.audit_site (cognitive 32): scorecard.audit_site has cognitive complexity 32 (threshold 15). Drivers by points: if/else 13 (21 pts), boolean chains 5, loops 2 (3 pts), ternaries 3 (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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":393}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b0351fca4808e8187a421230784f76eb85fe4bf8f65fccc26c14a295c7fad4b"}},{"ruleId":"D2","level":"warning","message":{"text":"BlockMapper.PricingTiers (cognitive 30): BlockMapper.PricingTiers has cognitive complexity 30 (threshold 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":536}}}],"partialFingerprints":{"codehealthFindingId/v1":"62431bf9f5b0356093a8372eae4febdcb9efeb38cddb089b4a63e0d7697597a4"}},{"ruleId":"D2","level":"warning","message":{"text":"scorecard.check_page (cognitive 30): scorecard.check_page has cognitive complexity 30 (threshold 15). Drivers by points: boolean chains 15, ternaries 14, if/else 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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":239}}}],"partialFingerprints":{"codehealthFindingId/v1":"e438225f0ccc3d48c49b9f06176695a3f985883be3424d534ca568a00dd4b409"}},{"ruleId":"D2","level":"warning","message":{"text":"(anonymous) (cognitive 30): (anonymous) has cognitive complexity 30 (threshold 15). Most of this is not in the body itself: 7 of the 30 points are its own statements and the rest belongs to 3 function literals inside it that branch (lines 27, 22, 23). 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":"tools/mobile-sweep.js"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce6d2dbbf9f66f8be023cc748cb99f25eaa35caa6b2f1b1ee666f25c056feafe"}},{"ruleId":"D2","level":"warning","message":{"text":"serializeInline (cognitive 30): serializeInline has cognitive complexity 30 (threshold 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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"69a6b0e13cdd226f64397ad773f52a64b5b2d29133a9361fdcfcdde1bc75f783"}},{"ruleId":"D2","level":"warning","message":{"text":"SiteSettings.razor \u203A SaveNavigation (cognitive 28): SiteSettings.razor \u203A SaveNavigation has cognitive complexity 28 (threshold 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/Imprint.Editor/Components/Pages/SiteSettings.razor"},"region":{"startLine":819}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d5ef0a456e9c8040ef938ae1c4cf4487dfce30934dab64ffbdcfcba00ea604c"}},{"ruleId":"D2","level":"warning","message":{"text":"Markdown.ToNodes (cognitive 28): Markdown.ToNodes has cognitive complexity 28 (threshold 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":"tools/ContentSeeder/Markdown.cs"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"016320808e33022761e97bdcaa017067d74b14e3a7433f745c7f0347dd86e2c6"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 28): render has cognitive complexity 28 (threshold 15). Most of this is not in the body itself: 12 of the 28 points are its own statements and the rest belongs to 7 function items inside it that branch ((anonymous), closeModal, confirmSent, \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":"widgets/_src/contact-form.js"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a1cd125b6d8946b8c39f4639aa0194d371d138351b2b4ca34bc5a5ff7d08952"}},{"ruleId":"D2","level":"warning","message":{"text":"restore-wiped-post-bodies.blanked (cognitive 26): restore-wiped-post-bodies.blanked has cognitive complexity 26 (threshold 15). Drivers by points: if/else 5 (15 pts), boolean chains 8, loops 2 (3 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":"tools/restore-wiped-post-bodies.py"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd48d36c2f43427fb9addbe34fb3d8fa207f579ea5b45b7589ec13c013ac7d58"}},{"ruleId":"D2","level":"warning","message":{"text":"cai-card-gallery.z (cognitive 26): cai-card-gallery.z has cognitive complexity 26 (threshold 15). Drivers by points: boolean chains 12, ternaries 4 (8 pts), loops 2 (4 pts), if/else 2 (nesting depth added 6). Of this number, 24 points are the body\u0027s own statements and 2 belong to 2 function literals inside it that branch. 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":"widgets/cai-card-gallery.js"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ee555ab7d622071913e81ab31580f2edc603f973986e7abfb9b26cfd09c2d9e"}},{"ruleId":"D2","level":"warning","message":{"text":"cai-score-card.H (cognitive 26): cai-score-card.H has cognitive complexity 26 (threshold 15). Drivers by points: boolean chains 12, ternaries 4 (8 pts), loops 2 (4 pts), if/else 2 (nesting depth added 6). Of this number, 24 points are the body\u0027s own statements and 2 belong to 2 function literals inside it that branch. 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":"widgets/cai-score-card.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"966fc7aa349e4dcd82ed49fe25eb03aad7701411d40e767b5b04f8f3680e9290"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 26): render has cognitive complexity 26 (threshold 15). Most of this is not in the body itself: 12 of the 26 points are its own statements and the rest belongs to 7 function items inside it that branch ((anonymous), x, k, \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":"widgets/contact-form.js"},"region":{"startLine":152}}}],"partialFingerprints":{"codehealthFindingId/v1":"029f4e865456312d95445e59c7a09c130ef071f61a492c1bd1eaf7566f491d9e"}},{"ruleId":"D2","level":"warning","message":{"text":"paint (cognitive 26): paint has cognitive complexity 26 (threshold 15). Of this number, 20 points are the body\u0027s own statements and 6 belong to 7 function items 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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"a754424f02c0a56d2e5b9fbc9c8a7bf47f3dda57f1756c7e96e4cb9a9fca8566"}},{"ruleId":"D2","level":"warning","message":{"text":"RichTextHtml.ResolveLinks (cognitive 25): RichTextHtml.ResolveLinks has cognitive complexity 25 (threshold 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/Imprint.Rendering/RichTextHtml.cs"},"region":{"startLine":23}}}],"partialFingerprints":{"codehealthFindingId/v1":"26761592345290dee7f0fefca4f847b89d970a243a0299b897cf22945f5c10de"}},{"ruleId":"D2","level":"warning","message":{"text":"rich-toolbar.normalize (cognitive 24): rich-toolbar.normalize has cognitive complexity 24 (threshold 15). Drivers by points: if/else 10 (22 pts), boolean chains 1, loops 1 (nesting depth added 12). Most of this is not in the body itself: 0 of the 24 points are its own statements and the rest belongs to 2 function literals inside it that branch (lines 93, 85). 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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"e550b0426c975eb43fc491907e90375155c045a34326ff90ceab7e986b962330"}},{"ruleId":"D2","level":"warning","message":{"text":"rich-toolbar.serializeInline (cognitive 23): rich-toolbar.serializeInline has cognitive complexity 23 (threshold 15). Drivers by points: if/else 8 (16 pts), boolean chains 6, 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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb8d7b4af867cb80f767d9990b7cf9a5706a821f20e887b55d976f5ca57b1ac9"}},{"ruleId":"D2","level":"warning","message":{"text":"normalize::walk (cognitive 23): normalize::walk has cognitive complexity 23 (threshold 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/Imprint.Editor/wwwroot/js/rich-toolbar.js"},"region":{"startLine":93}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf05f8bd462ddf5ce2b8293e90975bce721e750479c4e28db4b1123a57b7f5dd"}},{"ruleId":"D2","level":"warning","message":{"text":"Migrator.IngestSvgFigures (cognitive 22): Migrator.IngestSvgFigures has cognitive complexity 22 (threshold 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":"tools/ContentSeeder/Migrator.cs"},"region":{"startLine":279}}}],"partialFingerprints":{"codehealthFindingId/v1":"9321d088274ceb2fe734580752050ca3d21aaa3c0a3e1a5d9280c72f28eb0171"}},{"ruleId":"D2","level":"warning","message":{"text":"TranslationSeeder.Seed (cognitive 22): TranslationSeeder.Seed has cognitive complexity 22 (threshold 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":"tools/ContentSeeder/TranslationSeeder.cs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"b9dd05332a993c5921cb7adac2777f4e098093d01e0f504b7813f34f0dcb4576"}},{"ruleId":"D2","level":"warning","message":{"text":"paint (cognitive 22): paint has cognitive complexity 22 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 6 belong to 7 function items 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":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"367705968b027421e7a6f81872bcc26f108781aaa0406c1d52474b82ccd3a136"}},{"ruleId":"D2","level":"warning","message":{"text":"paint (cognitive 21): paint has cognitive complexity 21 (threshold 15). Of this number, 19 points are the body\u0027s own statements and 2 belong to 7 function items 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":"widgets/cai-language-board.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"df71e86b3da00b071230159001f789f7eac60197787276bcd333a64c7a8f3dce"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 21): render has cognitive complexity 21 (threshold 15). Of this number, 20 points are the body\u0027s own statements and 1 belongs to 5 function items 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":"widgets/_src/cai-trend.js"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"1be562868f66ac9d40f6200df4db5389694ef43b4438a54d516c65c2a71ede17"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 21): render has cognitive complexity 21 (threshold 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":"widgets/_src/cai-score-card.js"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"56fc5f17723a776bafce5f6c94e99ea4cb648348070769c39b64bc5933f4cc34"}},{"ruleId":"D2","level":"warning","message":{"text":"#repoHtml (cognitive 21): #repoHtml has cognitive complexity 21 (threshold 15). Of this number, 20 points are the body\u0027s own statements and 1 belongs 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":"widgets/_src/cai-findings.js"},"region":{"startLine":107}}}],"partialFingerprints":{"codehealthFindingId/v1":"ce57c2cf1f44d2e0d123b93cc56ef5ca9dfc663581e5356f95a2babef4f4f5c1"}},{"ruleId":"D2","level":"warning","message":{"text":"NodeContentRules.Validate (cognitive 20): NodeContentRules.Validate has cognitive complexity 20 (threshold 15). The drivers above price the dispatch low by construction \u2014 a dispatch is charged once however many cases it lists, while each branch inside an arm is charged in full \u2014 so most of this count is what the case bodies hold, and the arms are where it can be reduced. To reduce it, keep the dispatch but shrink the arms: move each non-trivial case body into its own named function (or onto the value being matched) so the dispatch reads one line per case, and group related cases into a sub-dispatch. Keep every case explicit, and make the behaviour for cases you do not list a deliberate choice rather than an accident."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Pages/NodeContentRules.cs"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"c12dd6cfbbb87065f4c684e6ebe36d8ffb354606cbae33d1441c3014ce00608b"}},{"ruleId":"D2","level":"warning","message":{"text":"AuthoringNodeJson.ParseLink (cognitive 20): AuthoringNodeJson.ParseLink has cognitive complexity 20 (threshold 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/Imprint.Editor/Api/AuthoringNodeJson.cs"},"region":{"startLine":328}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd5d9bcd4799b23cf03219671c77156ec87e96a43a71d27c1a0ba69aac07e16f"}},{"ruleId":"D2","level":"warning","message":{"text":"Markdown.InlineToPlain (cognitive 20): Markdown.InlineToPlain has cognitive complexity 20 (threshold 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":"tools/ContentSeeder/Markdown.cs"},"region":{"startLine":245}}}],"partialFingerprints":{"codehealthFindingId/v1":"95a36426aa7d071210d0bad98f6a1e428da1f8eeeee3e287eed08abbd9ee5405"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 20): render has cognitive complexity 20 (threshold 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":"widgets/_src/cai-language-support.js"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"411e8d1abc56b86069a03555cefb0ec9b32fb06fe7d9b624c6dcb06ff6f408b1"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 20): render has cognitive complexity 20 (threshold 15). Of this number, 19 points are the body\u0027s own statements and 1 belongs to 4 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":"widgets/_src/cai-language-board.js"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"0d3aa7e090f0ea2831fd271719c3baae66f6ed06f4834f6a3d47387acedcf7ac"}},{"ruleId":"D2","level":"warning","message":{"text":"paint (cognitive 20): paint has cognitive complexity 20 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 2 belong to 7 function items 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":"widgets/_src/cai-language-board.js"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e254ddc3a1269b9bcf4e1b149248ff9088c5a0a21427b87ebd0c4786518c424"}},{"ruleId":"D2","level":"warning","message":{"text":"Site.ValidateNavigationItem (cognitive 19): Site.ValidateNavigationItem has cognitive complexity 19 (threshold 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/Imprint.Authoring/Domain/Sites/Site.cs"},"region":{"startLine":312}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b06ef8f8aaf2492499848cfd3c54e7896132709a5027442b7e2ee9869e05ec7"}},{"ruleId":"D2","level":"warning","message":{"text":"Pass.NavItemsFor (cognitive 19): Pass.NavItemsFor has cognitive complexity 19 (threshold 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/Imprint.Publishing/SitePublisher.cs"},"region":{"startLine":912}}}],"partialFingerprints":{"codehealthFindingId/v1":"26d5d112de84f9405e0f37baf030fde4ee8beef51625a0088edf5020b14f8091"}},{"ruleId":"D2","level":"warning","message":{"text":"SvgPublishGuard.IsSafe (cognitive 19): SvgPublishGuard.IsSafe has cognitive complexity 19 (threshold 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/Imprint.Publishing/SvgPublishGuard.cs"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"3be557b60c574da04ce714e568a61309b296046d9d93185a7abaf2143c2212bd"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 19): render has cognitive complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs to 5 function items 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":"widgets/cai-trend.js"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"39149b7804a4fea4c18912cfdf92d5be6e9c505e74eab3dc4b90ec3353f399f4"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 19): render has cognitive complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs to 4 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":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1d9cb67c797a352f6cd5acb4ac18c12748a33bc8654c67b3600667f404449a0"}},{"ruleId":"D2","level":"warning","message":{"text":"#r (cognitive 19): #r has cognitive complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-findings.js"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"914cbbcb183babd89ea09cc1f4bb58ac6dda8dd1d08c97032d808d969ae3aceb"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 19): render has cognitive complexity 19 (threshold 15). Of this number, 18 points are the body\u0027s own statements and 1 belongs to 4 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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"91d45cc43a090ea316bb5a744a02ea38b07161d2be3dc7599da1b123ef8dce72"}},{"ruleId":"D2","level":"warning","message":{"text":"BlockDefinition.ValidatePlacement (cognitive 18): BlockDefinition.ValidatePlacement has cognitive complexity 18 (threshold 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/Imprint.Authoring/Domain/Blocks/BlockDefinition.cs"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"a34b744745b85203ba22aa0d202d0391d230b7bed99f66a232c579f201d9d576"}},{"ruleId":"D2","level":"warning","message":{"text":"Page.SeedLocale (cognitive 18): Page.SeedLocale has cognitive complexity 18 (threshold 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/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":282}}}],"partialFingerprints":{"codehealthFindingId/v1":"cbb22e25e567eb18e0707e318b26882908fb73289f7ece053fa4493886127bc9"}},{"ruleId":"D2","level":"warning","message":{"text":"Inline.ToCanonicalInline (cognitive 18): Inline.ToCanonicalInline has cognitive complexity 18 (threshold 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":"tools/ContentSeeder/Inline.cs"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"a002b04cdc71ad4bbe208783860c9e3c64af533f603d5be53512b6772a168f9c"}},{"ruleId":"D2","level":"warning","message":{"text":"Fetcher._fetch (cognitive 18): Fetcher._fetch has cognitive complexity 18 (threshold 15). Drivers by points: if/else 3 (8 pts), error handling 2 (4 pts), boolean chains 3, ternaries 1 (2 pts), 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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"da8678ffd08b46492310cb2a90f5f96b0dc25127e8a19b69656a23cc8eb119ac"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 18): render has cognitive complexity 18 (threshold 15). Of this number, 17 points are the body\u0027s own statements and 1 belongs 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":"widgets/_src/cai-lens-gauges.js"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c68d19c42b57b67bfc4cddcaf068ea81555bbe011d8a355c2cbc47e1fd50f02"}},{"ruleId":"D2","level":"warning","message":{"text":"Page.EnsureSpecInternallyValid (cognitive 17): Page.EnsureSpecInternallyValid has cognitive complexity 17 (threshold 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/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":594}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec1ff9f23e55619055f4eb7395f7b17663bc389fa95355f41e6af3b28bb29164"}},{"ruleId":"D2","level":"warning","message":{"text":"SlotPlanner.Plan (cognitive 17): SlotPlanner.Plan has cognitive complexity 17 (threshold 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/Imprint.Authoring/Features/Pages/MoveNode/SlotPlanner.cs"},"region":{"startLine":30}}}],"partialFingerprints":{"codehealthFindingId/v1":"96873771d8e1a37778a09971bae4f75306526352fbfd86b4f92e7d1ae277e67a"}},{"ruleId":"D2","level":"warning","message":{"text":"MarkdownToNodes.Convert (cognitive 17): MarkdownToNodes.Convert has cognitive complexity 17 (threshold 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/Imprint.Authoring/Markdown/MarkdownToNodes.cs"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"c87246e528dc6d05496c0da1f5cbef2a94da4b1f0d21bae8fe0834f744f2fa00"}},{"ruleId":"D2","level":"warning","message":{"text":"SiteContactRecipients.Find (cognitive 17): SiteContactRecipients.Find has cognitive complexity 17 (threshold 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/Imprint.Editor/Contact/SiteContactRecipients.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6150b134614878045c1f8dd4c6f8ddbdca19142dd713856775b3041dd7c93f6"}},{"ruleId":"D2","level":"warning","message":{"text":"Pass.ChromePageLinks (cognitive 17): Pass.ChromePageLinks has cognitive complexity 17 (threshold 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/Imprint.Publishing/SitePublisher.cs"},"region":{"startLine":428}}}],"partialFingerprints":{"codehealthFindingId/v1":"0f4475bec0ef4e6f5d9fc0e1f3bd6a739d1042c13a3989da771b707c858a1db2"}},{"ruleId":"D2","level":"warning","message":{"text":"Page.jsonld_types (cognitive 17): Page.jsonld_types has cognitive complexity 17 (threshold 15). Drivers by points: ternaries 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":"tools/site-scorecard/scorecard.py"},"region":{"startLine":208}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a4e02775bd98f025dc948aeee38220aced83c12fd1716fff8554da241048eed"}},{"ruleId":"D2","level":"warning","message":{"text":"parseCard (cognitive 17): parseCard has cognitive complexity 17 (threshold 15). Of this number, 13 points are the body\u0027s own statements and 4 belong to 8 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":"widgets/_src/scorecard.js"},"region":{"startLine":311}}}],"partialFingerprints":{"codehealthFindingId/v1":"b86c837051d64b09732d0532eb87be04cfba1d84086e88651fd236adfabc369b"}},{"ruleId":"D2","level":"warning","message":{"text":"cardFromGallery (cognitive 17): cardFromGallery has cognitive complexity 17 (threshold 15). Of this number, 16 points are the body\u0027s own statements and 1 belongs 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":"widgets/_src/live.js"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"efa46fdc854a684b3a2c8a2e1870ccf20952758a85361bcf8483ca2dfe70d3bc"}},{"ruleId":"D2","level":"warning","message":{"text":"CanonicalHtml.ParseHref (cognitive 16): CanonicalHtml.ParseHref has cognitive complexity 16 (threshold 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/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"333dc8072e567113a3703ff540cb496a0c0d45f9bf70a4aa0f85eae072e4e881"}},{"ruleId":"D2","level":"warning","message":{"text":"AuthoringApi.TryParseEnvironments (cognitive 16): AuthoringApi.TryParseEnvironments has cognitive complexity 16 (threshold 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1543}}}],"partialFingerprints":{"codehealthFindingId/v1":"43d5390bea85536bd04cb1e603c70e796a54fd35963743223a5338eddeb4bc54"}},{"ruleId":"D2","level":"warning","message":{"text":"AuthoringNodeJson.ApplyProps (cognitive 16): AuthoringNodeJson.ApplyProps has cognitive complexity 16 (threshold 15). Of this number, 14 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/Imprint.Editor/Api/AuthoringNodeJson.cs"},"region":{"startLine":384}}}],"partialFingerprints":{"codehealthFindingId/v1":"794db372e7943b7eb4b04abf6697c439a5bdfec3e7be49a35b12328374c6df90"}},{"ruleId":"D2","level":"warning","message":{"text":"SvgSanitizer.SanitizeElement (cognitive 16): SvgSanitizer.SanitizeElement has cognitive complexity 16 (threshold 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/Imprint.Media/SvgSanitizer.cs"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b076f043d233a94d9ea16208b12296b92f855a3844f7b35870851c525418947"}},{"ruleId":"D2","level":"warning","message":{"text":"BlockMapper.Features (cognitive 16): BlockMapper.Features has cognitive complexity 16 (threshold 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":295}}}],"partialFingerprints":{"codehealthFindingId/v1":"eef38ff0cb3abceb70d9bb8ce14ac4d755787ab643541e1a2a9b520e5c42fc30"}},{"ruleId":"D2","level":"warning","message":{"text":"BlockMapper.PlainHeading (cognitive 16): BlockMapper.PlainHeading has cognitive complexity 16 (threshold 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":1159}}}],"partialFingerprints":{"codehealthFindingId/v1":"c522cad4c193efa2d2612f705044ca20461c4ddbef95efc7b2e5cc3840a790b4"}},{"ruleId":"D2","level":"warning","message":{"text":"canvas-interop.trackGap (cognitive 16): canvas-interop.trackGap has cognitive complexity 16 (threshold 15). Drivers by points: if/else 7 (9 pts), ternaries 2 (5 pts), boolean chains 1, loops 1 (nesting depth added 5). Of this number, 9 points are the body\u0027s own statements and 7 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/Imprint.Editor/wwwroot/js/canvas-interop.js"},"region":{"startLine":462}}}],"partialFingerprints":{"codehealthFindingId/v1":"25792c07c938ad81cf3cbf7bfb5d11c763ee577f42f52f626038aa9cd8ed8906"}},{"ruleId":"D2","level":"warning","message":{"text":"live.cardFromGallery (cognitive 16): live.cardFromGallery has cognitive complexity 16 (threshold 15). Drivers by points: ternaries 7, if/else 5, boolean chains 4. Of this number, 15 points are the body\u0027s own statements and 1 belongs 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":"widgets/_src/live.js"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"15d559aaa87f64e53518f529c1955ebe81b23845261a9e07062831091de98ac1"}},{"ruleId":"D2","level":"warning","message":{"text":"R (cognitive 16): R has cognitive complexity 16 (threshold 15). Of this number, 12 points are the body\u0027s own statements and 4 belong to 8 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":"widgets/cai-score-card.js"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"0739e5beab55dfdff486fed86b3696ef62fb8e78407c2e6f13e2ca72acfd58f1"}},{"ruleId":"D2","level":"warning","message":{"text":"z (cognitive 16): z has cognitive complexity 16 (threshold 15). Of this number, 15 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-score-card.js"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"3423de3c7212ac8b8a9f5998768b1acc9fe76f551bd65e5337625247d694cb3d"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 16): render has cognitive complexity 16 (threshold 15). Of this number, 15 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-lens-gauges.js"},"region":{"startLine":235}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7e15ec0ce0eee2229ddb14cb910fd5efe81146756351da30b81dcb6919ec946"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 16): render has cognitive complexity 16 (threshold 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":"widgets/cai-language-support.js"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"b618137c826abac6992ec5b11021fc48d944a00c840a38bc31b38a87682cc524"}},{"ruleId":"D2","level":"warning","message":{"text":"render (cognitive 16): render has cognitive complexity 16 (threshold 15). Of this number, 15 points are the body\u0027s own statements and 1 belongs to 4 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":"widgets/cai-language-board.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"cad27faa021fd505a65e2ac368d3fe385635e2da1ffa100e7d29b03619804bca"}},{"ruleId":"D2","level":"warning","message":{"text":"B (cognitive 16): B has cognitive complexity 16 (threshold 15). Of this number, 12 points are the body\u0027s own statements and 4 belong to 8 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":"widgets/cai-card-gallery.js"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"034b522b0b8b6e36fb67d64dc5e7289e073f13e1df1bc32236ae98e5d64c151c"}},{"ruleId":"D2","level":"warning","message":{"text":"U (cognitive 16): U has cognitive complexity 16 (threshold 15). Of this number, 15 points are the body\u0027s own statements and 1 belongs 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":"widgets/cai-card-gallery.js"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"76e2de22620d447a2a7c0a0c2ba391a8db4068b735700b51bfa5adc2a973f2e8"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: AuthoringApi.MapAuthoringApi: MethodTooLong \u2014 MapAuthoringApi runs 586 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 486 over it, 5.86\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"eebea0950cd6d1d8c69a26719d8f23b92071406eda48ef7a58633b53141cc796"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Pass: TooManyMethods \u2014 932 significant lines (blank, comment-only and punctuation-only lines excluded), 72 methods. The bar is 30 methods; this is 42 over it, 2.40\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/Imprint.Publishing/SitePublisher.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1e95f1a67dd172e1ba56e09e5b24e0f45d63d5b962e6c3a79ea6a2c1f3102c1"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: ImprintAuthoringMcpTools: TooManyMethods \u2014 813 significant lines (blank, comment-only and punctuation-only lines excluded), 63 methods. The bar is 30 methods; this is 33 over it, 2.10\u00D7 the bar. The type holds no instance state, so there is no shared data to group its members by. To reduce it, split it by area instead: give each cohesive family of members its own smaller type, so no one type has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"746e5f2cb9b24f6f40fbd9ec288d3fd18ca5125dbd92c190f2786e8df1b96766"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Api/AuthoringApi.cs: FileTooLong \u2014 999 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 499 over it, 2.00\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5e194d68ca460bbc2c7930738cbdfca2492650c930d08bebeab51ba2381bf4a"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Imprint.Publishing/SitePublisher.cs: FileTooLong \u2014 986 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 486 over it, 1.97\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/Imprint.Publishing/SitePublisher.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3462a84adadeab1d5696e4e4ac713e6b6af297fd8a9d2ed7e0a40a8fdb19aaad"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: Mcp/ImprintAuthoringMcpTools.cs: FileTooLong \u2014 867 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 367 over it, 1.73\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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"cd22866236d8d570556a0d52f3c96f754bdc8996bfbda4cd80e98ee792c2829a"}},{"ruleId":"D3","level":"warning","message":{"text":"MethodTooLong: Verify.Run: MethodTooLong \u2014 Run runs 135 significant lines (blank, comment-only and punctuation-only lines excluded) in one body. The bar is 100 significant lines; this is 35 over it, 1.35\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":"tools/ContentSeeder/Verify.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"d8cb8c8160748b187b377d22fb3b810ff519400f80359db2384e17726b4eb5b3"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Page: TooManyMethods \u2014 369 significant lines (blank, comment-only and punctuation-only lines excluded), 39 methods. The bar is 30 methods; this is 9 over it, 1.30\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/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"62f98af2a96782506d3d6a74768d5525a33ee3a106d5cdd2dab5ee47b1dd44e2"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: BlockMapper: TooManyMethods \u2014 588 significant lines (blank, comment-only and punctuation-only lines excluded), 38 methods. The bar is 30 methods; this is 8 over it, 1.27\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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3c5fc24f6fb3d2ad2b33d7d165a64c8bdc7cecd0d5dc297cfe681e1c61c7c60b"}},{"ruleId":"D3","level":"warning","message":{"text":"FileTooLong: ContentSeeder/BlockMapper.cs: FileTooLong \u2014 593 significant lines (blank, comment-only and punctuation-only lines excluded). The bar is 500 significant lines; this is 93 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2866520c63b57ebf12cc69f8c4091b9289f99d904d181e1cbb4c93127fcf0e9f"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: AuthoringApi: TooManyMethods \u2014 904 significant lines (blank, comment-only and punctuation-only lines excluded), 32 methods. The bar is 30 methods; this is 2 over it, 1.07\u00D7 the bar. The type holds no instance state, so there is no shared data to group its members by. To reduce it, split it by area instead: give each cohesive family of members its own smaller type, so no one type has to be read whole to change one of them."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"67017ea733cec01609ece427e74a8436ecf79b2c322e7b0986fae54d92bc6d99"}},{"ruleId":"D3","level":"warning","message":{"text":"TooManyMethods: Site: TooManyMethods \u2014 362 significant lines (blank, comment-only and punctuation-only lines excluded), 31 methods. The bar is 30 methods; this is 1 over it, 1.03\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/Imprint.Authoring/Domain/Sites/Site.cs"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c6639f294361f92068a2bcce37737e40e690bd82cabdace1c285fb5e86ad261d"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (9 members, 50\u002B identical tokens): tools/ContentSeeder/BlockMapper.cs:296-358 | tools/ContentSeeder/BlockMapper.cs:382-437 | tools/ContentSeeder/BlockMapper.cs:440-480 | tools/ContentSeeder/BlockMapper.cs:483-534 | tools/ContentSeeder/BlockMapper.cs:537-631 | tools/ContentSeeder/BlockMapper.cs:791-848 | tools/ContentSeeder/BlockMapper.cs:851-867 | tools/ContentSeeder/BlockMapper.cs:870-890 | tools/ContentSeeder/BlockMapper.cs:900-949 \u2014 These 9 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 9 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 9 times."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":296}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf02e077b41cbe7b30aa2f362642a66001ba5e0d4b2be90263f5081b5b04a868"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:472-499 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:508-535 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:560-592 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:601-611 \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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0579e9708df315fbc26dfbe07473acce97b8ca1cd2ac9e624d9d93a734a0cf1"}},{"ruleId":"D4","level":"warning","message":{"text":"Members sharing a duplicated core (4 members, 50\u002B identical tokens): tools/ContentSeeder/BlockMapper.cs:537-631 | tools/ContentSeeder/BlockMapper.cs:641-674 | tools/ContentSeeder/BlockMapper.cs:683-716 | tools/ContentSeeder/BlockMapper.cs:791-848 \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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":537}}}],"partialFingerprints":{"codehealthFindingId/v1":"a928dfe1af51b06194ec70e23cdc537abb701dea3e0d962ef3f4afa297c2316b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21\u201325 lines \u00D7 2): src/Imprint.Authoring/Features/Pages/CreatePage/CreatePageHandler.cs:12-36 | src/Imprint.Authoring/Features/Posts/CreatePost/CreatePostHandler.cs:13-33 \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/Imprint.Authoring/Features/Pages/CreatePage/CreatePageHandler.cs:12\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 \u0060cmd\u0060 to \u0060CreatePage\u0060 in one and \u0060CreatePost\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/Imprint.Authoring/Features/Pages/CreatePage/CreatePageHandler.cs"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"d46d1ef30b189bcffa4ca6cd603d257708ffb6c82f9e1d038e273707fe616633"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (21 lines \u00D7 2): src/Imprint.Authoring/Domain/Widgets/WidgetSubmission.cs:272-292 | src/Imprint.Rendering/Widgets.cs:133-153 \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/Imprint.Authoring/Domain/Widgets/WidgetSubmission.cs"},"region":{"startLine":272}}}],"partialFingerprints":{"codehealthFindingId/v1":"d65acf9b4a3dc29ab0ca3661a922c0c00f27261635501950ca42ce8d0db04222"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (20\u201321 lines \u00D7 2): src/Imprint.Rendering/RichTextHtml.cs:61-81 | src/Imprint.Rendering/RichTextHtml.cs:83-102 \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/Imprint.Rendering/RichTextHtml.cs:61\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Rendering/RichTextHtml.cs"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"370abb245378680cdbd71202ce20682be2cd7f75f85f8b2a210d881432e0e70b"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (19 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:1161-1179 | tools/ContentSeeder/Markdown.cs:248-266 \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 \u0060tools/ContentSeeder/BlockMapper.cs:1161\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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":1161}}}],"partialFingerprints":{"codehealthFindingId/v1":"a1ce782efdaf9004b60379a1ae776eab4df146fc4db8b477dfe65a6ddcaf0cf4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201316 lines \u00D7 3): src/Imprint.Authoring/Features/Pages/ChangePageMeta/ChangePageMetaHandler.cs:12-25 | src/Imprint.Authoring/Features/Pages/ChangePageTitle/ChangePageTitleHandler.cs:12-25 | src/Imprint.Authoring/Features/Pages/EditText/EditTextHandler.cs:12-27 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Authoring/Features/Pages/ChangePageMeta/ChangePageMetaHandler.cs:12\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. 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. Note first that the copies are not typed on the same thing: the declarations holding them bind \u0060cmd\u0060 to \u0060ChangePageMeta\u0060 in one and \u0060ChangePageTitle\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/Imprint.Authoring/Features/Pages/ChangePageMeta/ChangePageMetaHandler.cs"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"eea10dd0c7945f2fd332011a0ae4c5b1b6eaadd52f05671003d3433ddd27d943"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 3): tools/ContentSeeder/BlockMapper.cs:321-336 | tools/ContentSeeder/BlockMapper.cs:401-416 | tools/ContentSeeder/BlockMapper.cs:499-514 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060tools/ContentSeeder/BlockMapper.cs:321\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":321}}}],"partialFingerprints":{"codehealthFindingId/v1":"eebf5334f24b449f6339da53b6e0994a3a7a75efbe0ae71521a44e643dfb5abb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (16 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:340-355 | tools/ContentSeeder/BlockMapper.cs:462-477 \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 \u0060tools/ContentSeeder/BlockMapper.cs:340\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":340}}}],"partialFingerprints":{"codehealthFindingId/v1":"3a35f0ed93048738ea6adf5d6fcac75c10f6adde43150905521706a630839330"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14\u201315 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:517-531 | tools/ContentSeeder/BlockMapper.cs:609-622 \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 \u0060tools/ContentSeeder/BlockMapper.cs:517\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":517}}}],"partialFingerprints":{"codehealthFindingId/v1":"6ccf0049dcbeb7404c228d2c08361548eaa9269d51ef2d1c18819d695caffff4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (15 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:660-674 | tools/ContentSeeder/BlockMapper.cs:702-716 \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 \u0060tools/ContentSeeder/BlockMapper.cs:660\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":660}}}],"partialFingerprints":{"codehealthFindingId/v1":"230e6e349c20fbac0852aab4ac11b77d0c489f1daf5309553b19f5723250e7b3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 3): tools/ContentSeeder/BlockMapper.cs:296-309 | tools/ContentSeeder/BlockMapper.cs:440-453 | tools/ContentSeeder/BlockMapper.cs:483-496 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060tools/ContentSeeder/BlockMapper.cs:296\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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":296}}}],"partialFingerprints":{"codehealthFindingId/v1":"d62e0de5228e63ef8247c3d90e65c009025ec33c4f9043ef451b9966ab46f3ed"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 3): tools/ContentSeeder/BlockMapper.cs:586-599 | tools/ContentSeeder/BlockMapper.cs:654-667 | tools/ContentSeeder/BlockMapper.cs:828-841 \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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":586}}}],"partialFingerprints":{"codehealthFindingId/v1":"3637002cecb8bdb5cfc9207c7d38ddd02bcdaf09097dbc53b9eae3125b380c18"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): src/Imprint.Authoring/Features/Sites/CreateSite/CreateSite.cs:10-23 | src/Imprint.Authoring/Features/Sites/CreateSiteFromTemplate/CreateSiteFromTemplate.cs:15-28 \u2014 \u0060src/Imprint.Authoring/Features/Sites/CreateSite/CreateSite.cs\u0060 and \u0060src/Imprint.Authoring/Features/Sites/CreateSiteFromTemplate/CreateSiteFromTemplate.cs\u0060 are one unit implemented once per sibling directory, so they are most likely parallel implementations of one contract rather than a copy of each other \u2014 this scan matched 1 separate duplicated blocks between them, totalling at least 14 lines. If both are selected at run time, neither can be retired in favour of the other, and the lines that DIFFER between them are the reason both exist. The move that pays here is to hoist the identical part into a shared location the whole family can reach and give what differs a parameter or a seam, so a change lands once instead of once per sibling; extracting one helper per block leaves every sibling to drift on its own. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Authoring/Features/Sites/CreateSite/CreateSite.cs:10\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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Sites/CreateSite/CreateSite.cs"},"region":{"startLine":10}}}],"partialFingerprints":{"codehealthFindingId/v1":"027a52162299bc7d52a61bb9111c0e71ce923758ebb11a8efacc1889b868b6a8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (14 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:1180-1193 | tools/ContentSeeder/Markdown.cs:268-281 \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 \u0060tools/ContentSeeder/BlockMapper.cs:1180\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":1180}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd0e31ddc3b052f729dffaf0c479ffee469e7757dc0e0dd5387c3b3c2092682c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 3): tools/ContentSeeder/BlockMapper.cs:346-358 | tools/ContentSeeder/BlockMapper.cs:468-480 | tools/ContentSeeder/BlockMapper.cs:619-631 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060tools/ContentSeeder/BlockMapper.cs:346\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":346}}}],"partialFingerprints":{"codehealthFindingId/v1":"f67471526510a20df979dff9bd56d178433ed58a1db95dc2b86a9caccda3295c"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:714-726 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:744-756 \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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":714}}}],"partialFingerprints":{"codehealthFindingId/v1":"249d9d3e6a1813a926185836ee0a3d2b3f724d5a004dcb2e8a56ddb735e871e0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (13 lines \u00D7 2): src/Imprint.Editor/Components/Pages/PostEditor.razor:462-474 | src/Imprint.Editor/Components/Panels/AssetsPanel.razor:159-171 \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/Imprint.Editor/Components/Pages/PostEditor.razor:462\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. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060src/Imprint.Editor/Components/Pages/PostEditor.razor:476\u0060 calls \u0060New\u0060 and \u0060src/Imprint.Editor/Components/Panels/AssetsPanel.razor:173\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/Imprint.Editor/Components/Pages/PostEditor.razor"},"region":{"startLine":462}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ab155bc836aab5fba449ab0b40b61f8ebe09bc0a74f2a147cc1e0958ae179a4"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 5): tools/ContentSeeder/BlockMapper.cs:324-334 | tools/ContentSeeder/BlockMapper.cs:404-414 | tools/ContentSeeder/BlockMapper.cs:453-463 | tools/ContentSeeder/BlockMapper.cs:502-512 | tools/ContentSeeder/BlockMapper.cs:853-863 \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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":324}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e82c68c91d0af8482492d67e1eeb42f72a4c9a7ac5ad1b618ff7e6ce7a86627"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 4): tools/ContentSeeder/BlockMapper.cs:318-328 | tools/ContentSeeder/BlockMapper.cs:398-408 | tools/ContentSeeder/BlockMapper.cs:496-506 | tools/ContentSeeder/BlockMapper.cs:795-805 \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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":318}}}],"partialFingerprints":{"codehealthFindingId/v1":"eba4e211db3e7e428b175ba0188d8eefe2a8c32e9c114de4f845ee9e679cc2fb"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): src/Imprint.Authoring/Features/Pages/PublishAllStale/PublishAllStaleHandler.cs:29-44 | src/Imprint.Authoring/Features/Sites/SeedLocale/SeedLocaleHandler.cs:49-59 \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/Imprint.Authoring/Features/Pages/PublishAllStale/PublishAllStaleHandler.cs:29\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Pages/PublishAllStale/PublishAllStaleHandler.cs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac12facae6c4d8e22e7a3981e80c693835934466366bb3a7071ab544558d5b56"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:492-502 | tools/ContentSeeder/BlockMapper.cs:905-915 \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 \u0060tools/ContentSeeder/BlockMapper.cs:492\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":492}}}],"partialFingerprints":{"codehealthFindingId/v1":"d710195994346bdf2e825c4def7a57f11d3f5344956b93aaa2c16c5342af4aa2"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2): tools/ContentSeeder/BlockMapper.cs:872-882 | tools/ContentSeeder/BlockMapper.cs:915-925 \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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":872}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf7f5c6b85bf13c47f8ad09657e123bf953488cb63ba90e6eaed46f21ba570b1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (7\u20139 lines \u00D7 2): src/Imprint.Authoring/Domain/Pages/Page.cs:26-32 | src/Imprint.Authoring/Domain/Posts/Post.cs:35-43 \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/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"f66f53c6c2525ad79c4dfd2c6e5d587ab6aa3732bcac6fc44456ba2ca8d5da7f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:403-411 | src/Imprint.Editor/Api/AuthoringApi.cs:433-441 \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/Imprint.Editor/Api/AuthoringApi.cs:403\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":403}}}],"partialFingerprints":{"codehealthFindingId/v1":"90161cb5057876f9fb095e323daece0824e289671a41f33165447f3615dd6d13"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:543-551 | src/Imprint.Editor/Api/AuthoringApi.cs:581-589 \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/Imprint.Editor/Api/AuthoringApi.cs:543\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":543}}}],"partialFingerprints":{"codehealthFindingId/v1":"eec3d25eb73aa365c13b6231e58c1746db68bbbe59840f3a9e67049602f4761a"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): src/Imprint.Editor/Components/Pages/SiteSettings.razor:841-849 | src/Imprint.Editor/Components/Pages/SiteSettings.razor:869-877 \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/Imprint.Editor/Components/Pages/SiteSettings.razor:841\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. 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/Imprint.Editor/Components/Pages/SiteSettings.razor:839\u0060 calls \u0060foreach\u0060 and \u0060src/Imprint.Editor/Components/Pages/SiteSettings.razor:867\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/Imprint.Editor/Components/Pages/SiteSettings.razor"},"region":{"startLine":841}}}],"partialFingerprints":{"codehealthFindingId/v1":"70ad881e0fb7fe2505cf9b190843dfa38c2d335ef468e0bc984f2f3ffa604821"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:542-549 | src/Imprint.Editor/Api/AuthoringApi.cs:580-587 | src/Imprint.Editor/Api/AuthoringApi.cs:651-658 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:542\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":542}}}],"partialFingerprints":{"codehealthFindingId/v1":"07f6c358cc565a29663e440ecb1440add9586aeb36ab03c30295ebe3e2774f72"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:151-158 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:127-134 \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/Imprint.Editor/Api/AuthoringApi.cs:151\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":151}}}],"partialFingerprints":{"codehealthFindingId/v1":"1ca6051feb5f006716d8d87dca38fc504c5a7f726a381f4f7110287626086972"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:743-750 | src/Imprint.Editor/Api/AuthoringApi.cs:774-781 \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/Imprint.Editor/Api/AuthoringApi.cs:743\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":743}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae0329d341d7f180529bb9422688739ac5d58083fce481fc053a898ebb9b7824"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2): src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:472-479 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:508-515 \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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:472\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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"23006292f4b8ee37f011c3c3206967ace6c52bd6ed46d8c8478b8fa330d74a20"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 4): src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:472-477 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:508-513 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:560-565 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:601-606 \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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:472\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."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":472}}}],"partialFingerprints":{"codehealthFindingId/v1":"a595f276848f71d33f467217917d309705c2a09a122a3bdca4aff2e4ddcfcdbc"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:111-116 | src/Imprint.Editor/Api/AuthoringApi.cs:743-749 | src/Imprint.Editor/Api/AuthoringApi.cs:774-780 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:111\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"82f822051e9fe8425b128b2713b03861ea52db15ba24ccd00bef828bcda956d7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:535-540 | src/Imprint.Editor/Api/AuthoringApi.cs:573-578 | src/Imprint.Editor/Api/AuthoringApi.cs:633-638 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:535\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":535}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d1bf808ddb4a7fc08d35dba55eb9511ba37bcfa6fb82a8ab1e822705a9f11ef"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:534-539 | src/Imprint.Editor/Api/AuthoringApi.cs:572-577 | src/Imprint.Editor/Api/AuthoringApi.cs:742-747 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:534\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":534}}}],"partialFingerprints":{"codehealthFindingId/v1":"eb698fbeea4c568ea48399b327dc5ab54b07ae754b7777adcb8f24d4d00f3429"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:609-614 | src/Imprint.Editor/Api/AuthoringApi.cs:805-810 \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/Imprint.Editor/Api/AuthoringApi.cs:609\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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":609}}}],"partialFingerprints":{"codehealthFindingId/v1":"cde44b5c8999aa0a9d1adac82ecb228aebf345e472d640e9ea2ef531f7b1b90f"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:712-717 | src/Imprint.Editor/Api/AuthoringApi.cs:729-734 \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/Imprint.Editor/Api/AuthoringApi.cs:712\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":712}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3f03b7cbb48449fd3078d844b1c0f06692b8bf82eae7cae1044f0a58b867590"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:425-430 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:442-447 \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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:425\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 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/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs"},"region":{"startLine":425}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c3fb646d9b69950cd3899b5d00fa0b7ce936da4a4dad16bc12a89793dbe3b9d"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): tools/ContentSeeder/Migrator.cs:231-236 | tools/ContentSeeder/Migrator.cs:259-264 \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":"tools/ContentSeeder/Migrator.cs"},"region":{"startLine":231}}}],"partialFingerprints":{"codehealthFindingId/v1":"c9d34d3885e2e9bb29d4a2dfb1dea8364b6037de0b74f534268aa9af527ad224"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 5): src/Imprint.Editor/Api/AuthoringApi.cs:535-539 | src/Imprint.Editor/Api/AuthoringApi.cs:573-577 | src/Imprint.Editor/Api/AuthoringApi.cs:633-637 | src/Imprint.Editor/Api/AuthoringApi.cs:743-747 | src/Imprint.Editor/Api/AuthoringApi.cs:774-778 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:535\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":535}}}],"partialFingerprints":{"codehealthFindingId/v1":"54d636e594e8d815d7249348ec05e78e87696a4c6731e8a615dfce21fb649956"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:292-297 | src/Imprint.Editor/Api/AuthoringApi.cs:403-407 | src/Imprint.Editor/Api/AuthoringApi.cs:433-437 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:292\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":292}}}],"partialFingerprints":{"codehealthFindingId/v1":"dec5fb3d384dc2bf76fe502439a964ef37dedaf2f640f304d6cf00726133ac3e"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (4\u20135 lines \u00D7 4): src/Imprint.Editor/Api/AuthoringApi.cs:895-899 | src/Imprint.Editor/Api/AuthoringApi.cs:924-928 | src/Imprint.Editor/Api/AuthoringApi.cs:948-952 | src/Imprint.Editor/Api/AuthoringApi.cs:996-999 \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/Imprint.Editor/Api/AuthoringApi.cs:895\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":895}}}],"partialFingerprints":{"codehealthFindingId/v1":"447d1f09f117d7032d800198305383e4e898e225dc81e127c6ad7e6f311509d3"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 3): src/Imprint.Editor/Api/AuthoringApi.cs:1093-1097 | src/Imprint.Editor/Api/AuthoringApi.cs:1103-1107 | src/Imprint.Editor/Api/AuthoringApi.cs:1113-1117 \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. Read the line range as the matched WINDOW rather than a finished unit: at \u0060src/Imprint.Editor/Api/AuthoringApi.cs:1093\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1093}}}],"partialFingerprints":{"codehealthFindingId/v1":"c43617d2d569e62a8c0c443c568f77e15c49fa12391af40dbde7ec447dbc3a74"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:111-115 | src/Imprint.Editor/Api/AuthoringApi.cs:180-184 \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/Imprint.Editor/Api/AuthoringApi.cs:111\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7d06ac38d099306d45fa43d9ccb244bd2831c6222d6ea41ef4e3c9a3b2edbf1"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:323-327 | src/Imprint.Editor/Api/AuthoringApi.cs:351-355 \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/Imprint.Editor/Api/AuthoringApi.cs:323\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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/Imprint.Editor/Api/AuthoringApi.cs:356\u0060 calls \u0060IsNullOrWhiteSpace\u0060, \u0060BadRequest\u0060 and \u0060src/Imprint.Editor/Api/AuthoringApi.cs:328\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":323}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a1f6d3a8f60e9fdd4f7211e0cd0b7bee56a78a1a8f54b5b44654aca46da5ed0"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:371-375 | src/Imprint.Editor/Api/AuthoringApi.cs:390-394 \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/Imprint.Editor/Api/AuthoringApi.cs:371\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":371}}}],"partialFingerprints":{"codehealthFindingId/v1":"689fe336cb1422bd06e44a55e4990e5922b7dfe5ae82795907ecc73713d6c3ea"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:389-393 | src/Imprint.Editor/Api/AuthoringApi.cs:447-451 \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/Imprint.Editor/Api/AuthoringApi.cs:389\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":389}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f77bff82def0816cf151183d5d86d2cd600e9b579383b739052e5e816422238"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:842-846 | src/Imprint.Editor/Api/AuthoringApi.cs:910-914 \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/Imprint.Editor/Api/AuthoringApi.cs:842\u0060 it runs out through the closing brace of the declaration holding it \u2014 the window is that declaration\u0027s tail, not a fragment that begins part-way through something, 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. 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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":842}}}],"partialFingerprints":{"codehealthFindingId/v1":"6a3b9abbcef83b28dbf5a965eab0256a0fd9bdc7c9c0a46992083a1d2058d723"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Components/Panels/Inspector/AssetPicker.razor:71-75 | src/Imprint.Editor/Components/Posts/PostMediaShelf.razor:269-273 \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/Imprint.Editor/Components/Panels/Inspector/AssetPicker.razor:71\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/Imprint.Editor/Components/Panels/Inspector/AssetPicker.razor"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"172e6fffdd8a1c2d471b5f79e72b7f5468e5de1f241af271a0c3d6affe5eae70"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/Imprint.Authoring/Features/Pages/ChangeSlug/ChangeSlug.cs:9-14 | src/Imprint.Authoring/Features/Posts/ChangePostSlug/ChangePostSlug.cs:9-14 \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/Imprint.Authoring/Features/Pages/ChangeSlug/ChangeSlug.cs"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"cacb3b0ceaf62bbb4ebbff193c61f7a45cf1e300ed78274bf73c8d06a0191bb8"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:1378-1383 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:1202-1207 \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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1378}}}],"partialFingerprints":{"codehealthFindingId/v1":"f2f40ece028c22113c61c03bfabd53d46ba7f19b70c21fd2cf345109127e4861"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:1683-1687 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:1151-1155 \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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1683}}}],"partialFingerprints":{"codehealthFindingId/v1":"a469802f2acac40dcbac00927b9eb614cd6a07270c410ffccab58a9d0d05b097"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): src/Imprint.Editor/Api/AuthoringApi.cs:1690-1694 | src/Imprint.Editor/Mcp/ImprintAuthoringMcpTools.cs:1158-1162 \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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":1690}}}],"partialFingerprints":{"codehealthFindingId/v1":"a1b118bbe4f1693d91bb83b6c57dcd9c429d6862b1ae1a14e63b56d48c067efb"}},{"ruleId":"D5","level":"warning","message":{"text":"Off the main sequence: Imprint.Authoring: Imprint.Authoring: abstractness 0.02, instability 0.17, distance 0.81 \u2014 zone of pain \u2014 concrete and depended on by 5 project(s), so it\u0027s rigid to change."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"8fe88001b9f4986a2d0c2691887f3b8885140de05bba28351792209e72fe7895"}},{"ruleId":"D6","level":"warning","message":{"text":"Low cohesion: CanvasBridge (LCOM4 4): CanvasBridge\u0027s methods form 4 groups that share no state and don\u0027t call each other \u2014 a sign it may have several responsibilities. Review whether it splits into focused classes."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Services/CanvasBridge.cs"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f304d2400df544062f4aab4359fa0a547d749bd261807898eafb03fc2ebc044"}},{"ruleId":"D8","level":"warning","message":{"text":"Coverage not measured \u2014 no coverage collector is wired up: Coverage NOT MEASURED: the test suite built and its tests PASSED, but the run produced no coverage data \u2014 \u0060--collect:\u0022XPlat Code Coverage\u0022\u0060 found no data collector, which is what a test project with no \u0060coverlet.collector\u0060 PackageReference does. Nothing is wrong with the suite or the build; there is simply no coverage instrumentation wired up. Add a \u0060coverlet.collector\u0060 PackageReference to the test project(s) (or commit the Cobertura/OpenCover/lcov report your CI produces) and real coverage will be measured. It is excluded from the score rather than counted as a near-zero defect."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"62e63e619c28f057e129f2997c965d32a457366a9ce18ca019ffb6bdfba85c99"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_on_ready_degraded_base_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"6fcfcab43f35bca9adefbfd4245381a1796e5cff921a1178cdcd905f12d7e6d9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_before_the_base_is_processed_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7f0d1c949662ad0e66891f48e3fb4539c4a1a35d30f5f5dd13de0631449c079"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_on_a_video_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":94}}}],"partialFingerprints":{"codehealthFindingId/v1":"d598a407c2124a1f7c8b3f216d6668bba765e51edee9f671b2229daef2bce26f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_on_a_file_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":101}}}],"partialFingerprints":{"codehealthFindingId/v1":"390af324a8e244cb86ab2d65cee7be1d8236ff0dfbcae85d8d87b13f8f92a34c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_with_a_mismatched_kind_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":108}}}],"partialFingerprints":{"codehealthFindingId/v1":"816c68619bfc059726c547bd358cf217678a5ddd5aa9bd71282e5ab864ee13d2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: UploadDarkVariant_on_a_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"269705a626a138d46d083cced4845d1134b9201db93e61dffa5d5b3487b84938"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkImageVariants_with_no_variants_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":152}}}],"partialFingerprints":{"codehealthFindingId/v1":"db6a084a14fedd45ac30c4c5dff7908b4020c83623617994f2b1827499e3106e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkImageVariants_on_a_vector_dark_variant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":159}}}],"partialFingerprints":{"codehealthFindingId/v1":"300d737dda17d87de88b56060cb55c2978485408cabe1f389e461b08fd23af91"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkImageVariants_without_a_pending_variant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"28988cbfda518bdf8f4f1e8f685277de164aca39a48ca50ec9f9b2bf54f974e5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkImageVariants_when_dark_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"96a794d63a242d186608b1951e1f5f41f7352915cef1e67f2aa82c3135c8f8a5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkSvg_with_negative_removed_nodes_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":195}}}],"partialFingerprints":{"codehealthFindingId/v1":"9822b512af29f36606953e528d87994fc7c33fb19e9cac94414db5ffb80d2c54"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkSvg_on_an_image_dark_variant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5f57059527f0f8fb2f6cb0a1c36a320c7a5b210d65246d64734020abed73179"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkSvg_without_a_pending_variant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":209}}}],"partialFingerprints":{"codehealthFindingId/v1":"054cf33ba0d487e19303f99c512fe27f330acb5d9088766533a5b87b07fee460"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailDarkVariant_without_reason_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":233}}}],"partialFingerprints":{"codehealthFindingId/v1":"97c62cfa0341556896301b9bd5db8399a8ec00a0443ebd79be16f5e3fdeb75d9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailDarkVariant_without_a_pending_variant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":242}}}],"partialFingerprints":{"codehealthFindingId/v1":"a2ff258d219e61ffa947684e4f674881c985627e4723609d7a738e8fedb0fa2e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailDarkVariant_when_dark_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":249}}}],"partialFingerprints":{"codehealthFindingId/v1":"029b739d304ebfd2badb49d3b67f8a180f76ad49f5870ac4df4590f0af36e3ad"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveDarkVariant_while_still_pending_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":272}}}],"partialFingerprints":{"codehealthFindingId/v1":"1da4abc0e4a281a85ce23db2b746784bdb4c22e560f0ce10a3baa1c2a8cf9a09"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveDarkVariant_when_none_exists_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":279}}}],"partialFingerprints":{"codehealthFindingId/v1":"16083436d3bc2867abf368d260234a76014655344ad99d6ff01de2ca0954ffb9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveDarkVariant_on_a_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":286}}}],"partialFingerprints":{"codehealthFindingId/v1":"debde807bfb4674a903239d3c77010dab6f8ac560525d8a165fc891d7ab4c26e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkImageVariants_on_a_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":295}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a4b1c63d6d9a8f797f6fefcfb09eae9eea984eb9bcc0236a906e56d4f0cee85"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteDarkSvg_on_a_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":302}}}],"partialFingerprints":{"codehealthFindingId/v1":"efbf9939e52d5bc1f4368a2fcad7e6e8ebd24e319ed67b0886accaadfd95e637"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailDarkVariant_on_a_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":309}}}],"partialFingerprints":{"codehealthFindingId/v1":"a0a7d1541833dd5a2387518a55fde62013ef153f507a56ca52f3c0727da8a702"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetAlt_over_500_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"5df537bafd6de79532e9fd6f76c51cf3845efbc25ab25fb8dd79e9dfd1a0794b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetAlt_at_500_characters_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ad500392fa53cc4af756168bb468113c2c8c22656008dd29ac868fc6cdd665b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_unchanged_name_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":67}}}],"partialFingerprints":{"codehealthFindingId/v1":"5aea0f6e94943b9ea08315c7e10c17de746a934ee2c42da24b6908fe9fbc7069"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_blank_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"6da6790240c89515e69a7326111c189ebf03278e3b2441622c212ee2aec2d310"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_over_200_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"bdfe3b5a033488da0373a90c04e57e63226defbb61a236bb4cebb0339fc231f7"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Delete_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"fbe66e48e0885ec6730e1f2e776357d039c51e8534553d772eda4164d2acd38e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"0037bea54cd9f73132447a9b509f521644b58b30d6879f64ab9ee86e78f2b6be"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetAlt_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"54ca140aacd8ca58a7e521808042c5d733a94d574aaccb39f0c68472312038a4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"e65707565db3bdfab9ebaabeea89f9e566216301f05fa852d729dbf4b20c6a15"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteSvgSanitize_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":131}}}],"partialFingerprints":{"codehealthFindingId/v1":"12140e66d126dd50e7b2d2a7bde2c28330e1dd0db8df3b80690cfb95fa5f6ae4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteVideoTranscode_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"2fcc2a4ffa52a036ee55d23d766b36d61546df4b0f6575c1693bb8dddcf85604"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailProcessing_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":147}}}],"partialFingerprints":{"codehealthFindingId/v1":"31716ae0c53dc885f2a132c61b69ade4267337ef96d7c933668451ffdf4e6d11"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SkipProcessing_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetEditingTests.cs"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"6eb3b49a52564026f2f5ef5244d688bef38845d5abace27c7d8ac33c18355496"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_with_no_variants_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"c057a6274390f715647564961c1e7e05e50700aeba3db396369152082b6849e8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_on_wrong_kind_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":51}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e4707bc2a1d42c508aaa4e315a40b296b6c087e7f28aa45b747ccaed832127b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_when_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"95cd05e4a4fb77239894b736814f1264fb202044539c7af17103e82f537d27ba"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_after_failure_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":68}}}],"partialFingerprints":{"codehealthFindingId/v1":"45efd16244bac0e84e3fb6ce240c5724f04a61dfd76fde471a6638312eceec3d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteImageVariants_after_skip_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"250f84dcc3bc8dc211c5556763450615d63360dacebcb873501120eed061d261"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteSvgSanitize_with_zero_removed_nodes_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":96}}}],"partialFingerprints":{"codehealthFindingId/v1":"f73f628a72ded850a18b6f1c0b93392b4c0edd9c6cf07c27d34670b4f14d75d6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteSvgSanitize_with_negative_removed_nodes_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"46c25f838becc4075661b61010efcc78519878e8ee1be0144255085f1a94759f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteSvgSanitize_on_wrong_kind_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"3285283ff5f7ef8743b4f3b4bdcf6ac70e6e4f8bca12871136eef04df63294a9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteSvgSanitize_when_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":120}}}],"partialFingerprints":{"codehealthFindingId/v1":"f48a31ebb5130cfd736a3b8c788c1e0076059296a434584f01c3048e81537f57"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteVideoTranscode_without_content_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":141}}}],"partialFingerprints":{"codehealthFindingId/v1":"b51505e130e592c8b82fb6b4f7883b528d1395f8a4e07e302d631245b38717c8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteVideoTranscode_on_wrong_kind_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":150}}}],"partialFingerprints":{"codehealthFindingId/v1":"8ff917c61a9364fb2a2a46bef25a5dd67c42ee03183341774c18ee0908188799"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: CompleteVideoTranscode_when_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":160}}}],"partialFingerprints":{"codehealthFindingId/v1":"93dfdb03b07e02da81b901e9c40e6bd7807250c111a511d751cb17648d26156a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailProcessing_without_reason_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":181}}}],"partialFingerprints":{"codehealthFindingId/v1":"57e891e467fd264b63ee83ddd39bb323ee8285ef2f17288dc4e45dbed9635d7c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailProcessing_when_already_ready_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"9ff718d5521417d3dc114527638ce8fd60dbdd5d61eaf257ae1052f0881b444b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: FailProcessing_on_file_kind_is_rejected_because_files_are_never_pending: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"ae1cb73f06ec6b85305d3464911d9924780da516d74c1b8dc5386bfc6b75ef03"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SkipProcessing_without_reason_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":216}}}],"partialFingerprints":{"codehealthFindingId/v1":"cbfa047f1ebc47e984f8950a50f8a65d49fdfa0d9daf716578dbfad53895e550"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SkipProcessing_when_already_failed_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":225}}}],"partialFingerprints":{"codehealthFindingId/v1":"a194d6ecac0bf3ad99519bcd5a60c74ace230d232e8cbad89e33b65e3e48fc50"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SkipProcessing_when_already_skipped_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetProcessingTests.cs"},"region":{"startLine":232}}}],"partialFingerprints":{"codehealthFindingId/v1":"6e36873860c5bb02c4de7125b25a60030d74f19c8cde869acb9a5a0313b398ca"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_keeps_the_casing_the_author_typed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":26}}}],"partialFingerprints":{"codehealthFindingId/v1":"5d9e549b3687c2b8aaebfa4a6653b39eda78ce89ce8306ccd808fa75cb2136cc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_trims_and_collapses_whitespace: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"da26aef9531d3bb5a17509b346a536d1e22681baf99f52c4b06a2d1bd37bb2e3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_that_is_already_there_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":46}}}],"partialFingerprints":{"codehealthFindingId/v1":"6f66dda84b29b73d45d938e2b759a4b0bf48180706c91707493e9773e89d1825"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_differing_only_in_case_is_the_same_tag: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5a1486c88dd1d97dd8dc23f24465c2912e21f7d1db2c96012440643df06280e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_that_is_blank_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"07a24709e8d5bd86da1ac43e10114709e335ee87a9b3cf0281ca50e14d2b9ba5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_over_60_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":80}}}],"partialFingerprints":{"codehealthFindingId/v1":"e4271dbc5d6ced46525a161ff5d5247dc14eed55d0db0ae2bb5da1aa04ffcaa3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_at_60_characters_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"0410241c9eee8edebe8d10cbf32acd6a6aea1102d9a40719d047bf5bb9a013a4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_beyond_the_limit_of_25_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":94}}}],"partialFingerprints":{"codehealthFindingId/v1":"caef604ab347629ad7a3749bde37f145b5e95a3c5cd0b7736afbb5ae0af9908a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Untag_a_tag_the_asset_never_had_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"3c366c598023ed322de276cbb83dbd94600c83a6e3f420ab5b96fb4e0c9984be"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Tag_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":131}}}],"partialFingerprints":{"codehealthFindingId/v1":"61bd7d7f755f95f27cdbb4c22ef5563e0cc5ddc46eda5ce6e4510eb6d45958e8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Untag_on_deleted_asset_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetTaggingTests.cs"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"e0ddad86789e9a6368c80a6fcbb80dec5625e31d67ed643fd9679e6560380edc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_unchanged_name_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"7408aaf63311bead47a27c2ab0a1504d13ad9ccd3ac1f57e3f21aa5421f81ad4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_blank_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"a0e48740421b35aabd4c758c3993409b2498d4012c29257b374bbc26ad121dc6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_over_100_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":91}}}],"partialFingerprints":{"codehealthFindingId/v1":"7cc2eeec487e112b4538a4dc5b23640c5c344b8d56af6529de7c93c2d0484b74"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_on_deleted_block_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":98}}}],"partialFingerprints":{"codehealthFindingId/v1":"4b656ffa4407807d87fd622d961d7136b118f65c30536f88100fd0dfea703075"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Delete_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"67b795f075720102c22d8b093c2785c956e6329fe50db4859c1e64e2d9a95df6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_on_deleted_block_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionLifecycleTests.cs"},"region":{"startLine":125}}}],"partialFingerprints":{"codehealthFindingId/v1":"a5ccb92cf040116276e8ee9531e95d40c308c14ab0189f085c468a856ad6ffda"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_section_root_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionSpecValidationTests.cs"},"region":{"startLine":188}}}],"partialFingerprints":{"codehealthFindingId/v1":"22de567763a182e69b62bbd9da21770806ccbf3b60060de899a6d1e435ffbb1e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_nested_block_instance_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionSpecValidationTests.cs"},"region":{"startLine":195}}}],"partialFingerprints":{"codehealthFindingId/v1":"5407a1b26a3b02cf8c688489f49f70952eb1fd67ac4a6bc91ee4e34e4f622063"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_duplicate_node_ids_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionSpecValidationTests.cs"},"region":{"startLine":202}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b9b0d63169f6c036c6cc21860138fb75b5a38948b5a99aaf7c173ef90162f64"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_columns_cell_count_mismatch_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionSpecValidationTests.cs"},"region":{"startLine":212}}}],"partialFingerprints":{"codehealthFindingId/v1":"f1957ae94c6924c485c3224315ab542e3b89f8f02742d8d374912208bab62419"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeSpec_spec_at_eight_levels_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Blocks/BlockDefinitionSpecValidationTests.cs"},"region":{"startLine":219}}}],"partialFingerprints":{"codehealthFindingId/v1":"8239f05c35be72133443c1c5ccf576922a834cfe7a88b051374a3fb299f77791"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_non_section_at_root_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":39}}}],"partialFingerprints":{"codehealthFindingId/v1":"5352792f6ae9c6827043786ff83a7f7aad379943b15deecd2e8736a8ab78a7b8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_section_inside_a_container_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"ee51b5d8abcfc8ce0218928c25399b77c161937564f0e100c6f3013b02ffa82d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_into_unknown_parent_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"c9a048f4bfeff66ad88dfb5244f9158799e47997810e8d53158736d5e15773e5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_into_a_leaf_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"71606f59897ec198b65296753ccc49cbdea07f722981c5b6e1b31bde33d127d3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_into_columns_element_directly_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"0e1475b07e4e021f9ab2725f8546f8428af29a588f8393dda696be451931e5ec"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_into_a_column_cell_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"991c67d75929f65487b250143b7fe7ac3725af2ce25e4d6a137dca4f833a96f1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_spec_with_invalid_nested_placement_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"f32966f59577cf47c5db87001ceaf37114a1c696a73306fa824552d3672f76a8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_spec_reusing_an_id_from_the_tree_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":106}}}],"partialFingerprints":{"codehealthFindingId/v1":"c636eb10fc966efbe67199135ac66eb52b468dac93fbb1329f3de1ab8ee28f96"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_spec_with_duplicate_ids_inside_itself_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":114}}}],"partialFingerprints":{"codehealthFindingId/v1":"caaae49cb171e42a7e57c80513a9182d8b049d88d2af29385f9d063b84dbee33"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_spec_using_the_root_sentinel_id_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":126}}}],"partialFingerprints":{"codehealthFindingId/v1":"85d290bfe3d6b8343a7d89481f19059b008ceab156561ce10390aa5233434cf3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_valid_columns_spec_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"b5578dbc33ce346f898f4759fc3d8913f2eb7f19f8f5748720fc8a469be869ec"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_columns_spec_with_cell_count_mismatch_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"057691e100f5acf0dc7d00e9e1576e2b6c8eacc8dcefe30dd59a4a9b77b338b2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_columns_spec_with_non_stack_cell_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":154}}}],"partialFingerprints":{"codehealthFindingId/v1":"b58773937f415e5e84515ebb1e39ab0848b5aed1e7c8ee85f3deda8ffde47c0a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_columns_spec_with_a_single_ratio_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":162}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b5bccc671f5644ab26ce6e9aca3810b2978a5ecedc26367a04d062f6b7b3bff"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_columns_spec_with_five_ratios_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":170}}}],"partialFingerprints":{"codehealthFindingId/v1":"81cd4e6c7cb85672d9cb8cc16953834f71bea91a3a95dc3ea711008b07542aef"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_columns_spec_with_ratio_out_of_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"69c6121c582cb59769173cad41c5b5bdd0ea87edf20c282778243696d0279684"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_nested_columns_spec_is_validated_too: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a9230bfa8a4ca1caf3d064bb6e8eef621b97cfd0845d0b644d7df965b782b94"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_with_negative_index_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"39d7c447b01627c2efc515e87a9bd26593c592767acfa3960601024a9020713f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_with_index_beyond_child_count_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":205}}}],"partialFingerprints":{"codehealthFindingId/v1":"044225e19f7c95adaadd839f0c79fec7eec7ae9c0d43dccb7997e65ff6c561e0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_beyond_max_depth_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":226}}}],"partialFingerprints":{"codehealthFindingId/v1":"e1d6432a90160e39748255b4c74c8dd2fd3f4171a21391cba3a9e15dd9c72719"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_reaching_exactly_max_depth_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":237}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ff53f2dfbcaa4bdf5fb5fa53f1a2d2dd92adb290215f78122eb2840cb42bea3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_beyond_max_node_count_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":249}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba17739a08847ebdf540316d6f8b39d159638e081b4eef0aaa348e259425865e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_reaching_exactly_max_node_count_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageAddNodeTests.cs"},"region":{"startLine":260}}}],"partialFingerprints":{"codehealthFindingId/v1":"3b60676196525ea600b68abded9b630286fbdd5dffef96c0a2767c8fa371cef9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_on_unknown_instance_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":57}}}],"partialFingerprints":{"codehealthFindingId/v1":"8e50330d379b33f5aa934974a06937c2f3dbd28697bbb07eba3ad3c28a835e33"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_on_a_non_instance_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"d156dceccf304dcf33dfb2eeb0bc149f085af4bf14b94e69e79897d79dbf3929"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_with_unknown_field_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"7e016196fb03c6a66f200974c8e41cb35c8164a31e74f826ab3100c5890c0752"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_html_value_must_be_canonical: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"3315bbb0bd21bd54f3ac50eea9e912d060d944ee28289ca1ec7c98bbfae631ac"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_canonical_html_value_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":89}}}],"partialFingerprints":{"codehealthFindingId/v1":"93858ad8c39a289186bc18e23bbc6ad3f7d7ec9da343ea4e97cb59e53aa4e4ea"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetBlockOverride_plain_value_over_500_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"df4607ddbfbef85eab03ee873d6e57752428a96a85a3dd4a1d00ad6213d4d49d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_on_unknown_instance_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":125}}}],"partialFingerprints":{"codehealthFindingId/v1":"c6df9b8290aa9c52cb4f079cd514222ffb428607caa1751a5daef79a8c179d51"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_on_a_non_instance_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":133}}}],"partialFingerprints":{"codehealthFindingId/v1":"c68efb03cdc6fd3e20fe807bccc1b727f4bc0e2dd7054cac1ced8d81f4c91471"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_replacement_reusing_a_tree_id_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":141}}}],"partialFingerprints":{"codehealthFindingId/v1":"341506f4dba7f9db7c9c636b83760675f660bb3e3d89a87240c5f75881ccd4be"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_replacement_with_invalid_placement_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":149}}}],"partialFingerprints":{"codehealthFindingId/v1":"2010069d7245394b8127a6bd3676c2d31cd1ddaf3fa68d3cbb396312c02b138d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_replacement_with_invalid_nested_columns_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b35c2060652899b52c78230eb30039b93d7c9865db908f157fd141f99bb3777"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_beyond_max_depth_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"95c75f57c754125983fb566634844528c57eb6bb969a61c0221433301fb92cb6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DetachBlockInstance_counts_the_replaced_node_against_the_cap: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageBlockTests.cs"},"region":{"startLine":181}}}],"partialFingerprints":{"codehealthFindingId/v1":"0a8c5916c77dfb9e4aff85fdba6eec09e161dddf7603171c7072981e752d1c62"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_unknown_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"6b3859a6baa4d417b129785fac5b162c6bf1f2ffdf98398af9fe232d88bbc564"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_changing_the_node_type_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"7904bf839a30e2dbb477d11dca0d742def8aa1a7cbe58fd0a3cef66fe809ad18"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_identical_result_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"1c329766f2ff34e4375bcb33bcf0401d6fee11e4abdceb8bec3b9329c0d18332"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_identical_leaf_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"afeadbdb03b523edc32ef7e2ba60f34924b568b72fe0060a188adf99dad302db"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_columns_shrinking_over_a_non_empty_cell_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"a5affa1067204ae44c0220612a90fe75ea1da0a29a8139d2ede4946041b2a02d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_columns_ratio_out_of_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":138}}}],"partialFingerprints":{"codehealthFindingId/v1":"8dca3a02bc10be7c0852b847343cfd8ce6d8486963d8216f05fffacb965bf8f3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_columns_ratio_count_out_of_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"5b832ae8576d09c27e5fd293073a06079dd142fd9a6c7666dc2da46c8d887840"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_columns_identical_result_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageChangeNodePropsTests.cs"},"region":{"startLine":179}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2369d53009eca32367295a2babb5045e6ba0b008d7c0893a4015ec3d21a8bcb"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_button_label_is_editable: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"acf56e93a3dfb0d0fc01615573596acc66633c24084e6298306df28c4cd138f4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_image_alt_is_editable: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"a58d764d16ea882046bd1d7116bde990ad9e04b46a50a974fb0c62f34bdfc395"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_svg_alt_is_editable: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"98dbe3a7a3d55a22d1ea63eb943d64f7bcab970c5ab7ca86fb9748bf2450b19f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_unknown_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b771e1749a904ca6f55ba675aca2d421b1724649709626235b89aba4ac17341"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_field_not_on_the_node_type_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7e257ecbd58bdec375e01600cc0eb50c36d4591cd89fcd6a73e0f99095630e5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_on_a_node_without_text_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"1b5399dcbd7927f3b4647aaaaeecd54eb8d4a3de95effd1e24fca62d8ffcc2d6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_richtext_with_canonical_html_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"919072a5d0f70e6d856f230c246b0e43305f1f1b721984f16f7ee1c35274c31c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_richtext_rejection_surfaces_the_validator_message: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"69570247f15c6bb50c6c8e6f05afd245f1287d7fbf3fd717e279c39eb54531a5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_richtext_rejects_a_malformed_fragment: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb298e83504f0e7ac21e6a71a17bcd4e20fd1975c949b0a65378b863bff603c7"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_plain_value_over_500_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"d9b6c6b723eab8927291ab2a474b1d8333a40afeb3a8a6ae619ef319af7b3592"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_plain_value_of_exactly_500_characters_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":156}}}],"partialFingerprints":{"codehealthFindingId/v1":"9d55277a885e6ca922b1a85f62e07d5f50e207bc7c104ecae47eaa1be17919a1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_unchanged_value_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":164}}}],"partialFingerprints":{"codehealthFindingId/v1":"f25fa1be6a50644e391c50d3144595463d39c127807c84c934df50086c7b6734"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: EditText_clearing_an_absent_locale_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageEditTextTests.cs"},"region":{"startLine":172}}}],"partialFingerprints":{"codehealthFindingId/v1":"660ce882cdc49dcae87643cd2fa3625f508436405208b536c7c5c9afbcd0b4a0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Unpublish_a_never_published_page_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageLifecycleTests.cs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"bf56f95bd6ba2d5c3468f9ca362c082d76d6df3de6a5fa89b3b01d822810b815"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Unpublish_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageLifecycleTests.cs"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ce070cb33ae88f17c207c360d81690936f64306df38cbdf9b6ef1b075629c96"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Delete_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageLifecycleTests.cs"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"99f054e3146b3d6faadfe0cf7be74b10f8a5a1b2bbcfe6fb218e43d76483fa0d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_unknown_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"c8117a5a03ca6fc27aabf477a1e2d50150d247cadc601bc30bcc53110cbe37fb"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_into_own_descendant_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"f82e8830c731397cf236780f08585b46cf79d5c3ca67b33653d0caeb57c204fc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_into_itself_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":63}}}],"partialFingerprints":{"codehealthFindingId/v1":"91fd990bc0f449614c481cac13a5b11647e8d7661688d305f8402b64e91c78cc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_to_unknown_parent_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":71}}}],"partialFingerprints":{"codehealthFindingId/v1":"acceb5b5c6e478f3937ec4eabf297de8637592c3be572bafd7854c6e22c78ab6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_into_a_leaf_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"64f2681500029d789578660b59f857291225610f7993eb2ef02d892ee71252a2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_non_section_to_root_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":87}}}],"partialFingerprints":{"codehealthFindingId/v1":"76602e9e4775af8d25f65ae3b472a6f43d8b44c762d8c1c22bdc1418f10025a1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_section_into_a_container_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ace7b3d91bbbadea769f516821641842fb89c554b1a420954fba6bd285848b1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_of_a_managed_column_cell_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":115}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1c6955b5c30d272e81e9d2a55b9b208020f82e51597421e238f11610ef3cfa2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_into_columns_element_directly_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"d27cb06c1b3255e05de9b11f8ee482d8ce864da17ad5d1908d9f6169e74eede8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_into_a_column_cell_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":141}}}],"partialFingerprints":{"codehealthFindingId/v1":"87f568fa965d82bd50a26b35b0835c6736ae46574cfe7993a7ac4869f614eb2c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_identical_position_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"09527d42cdcea59af2bab12fe6ecaa496d75ab017ac5bd7e1e2e86907a29f5cc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_within_same_parent_beyond_shrunk_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"48189cb38fb72f30e6a8e7bce2edd4359011775ade4fd5b6676826b2396f02ff"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_to_other_parent_with_index_beyond_count_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"df3c6777fda892ce4a19d7eb286128bdf18df0ef3f8d489100ab5001088fa1a0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_with_negative_index_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":194}}}],"partialFingerprints":{"codehealthFindingId/v1":"70d0d28ece71b774d2bbb44a44da3e401c99db9aeae7cd073d8c28ea2be34d42"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_subtree_beyond_max_depth_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"a6ce1a0699ed4eebab3971c77fbc6ba0c540acf6fcc260476ea6ade739643c41"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: MoveNode_leaf_to_max_depth_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageMoveNodeTests.cs"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"e759874b430ffffb32c5a59ea68dacc64e86f552d566f28caf0474cca1fcd3d0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveNode_unknown_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"56f78d5fb158fed469dfea9b80d276bbda7d3c3424481ed26dbf380a835063af"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveNode_of_a_managed_column_cell_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"d173055dc6101c32f153689c674afc1e32526e20d0367a5ba6d8086fe15bf92c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveNode_of_a_whole_columns_element_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d406428482e48eb4f50e53ff4fb2162275f7608a25e91702d8efc157407633b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DuplicateNode_unknown_node_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":66}}}],"partialFingerprints":{"codehealthFindingId/v1":"5970c6d86841adedde1b1e6861d618c8ed02b4313b2ea78fbf0758f6603a8b7f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DuplicateNode_of_a_managed_column_cell_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"5fddb852a6d1f6944b86dcf75fd8ba33b7d43b1247a80b963a239600941c9d59"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DuplicateNode_beyond_max_node_count_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageRemoveAndDuplicateTests.cs"},"region":{"startLine":131}}}],"partialFingerprints":{"codehealthFindingId/v1":"a42bbff65e2fa13966439ccd6c4a7136cd5c1387f4abc0e793433cd43a8ea8ef"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SeedLocale_copies_every_text_field_into_the_new_locale: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSeedLocaleTests.cs"},"region":{"startLine":28}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd89689a037b586686c0c73a83d9545ae51e86385c791b0dd61142bb1e429798"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SeedLocale_from_itself_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSeedLocaleTests.cs"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7c7c183ca0c86e673a0ebbfa347b1492a9834c015e262e82b87b24b9fe0ff22"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_with_non_canonical_richtext_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":27}}}],"partialFingerprints":{"codehealthFindingId/v1":"c93a35006758bccdef357867e03770c30166cb2b88022bf5ec96a74ebd70261d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_with_non_canonical_richtext_in_a_nested_spec_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":43}}}],"partialFingerprints":{"codehealthFindingId/v1":"48669648b028421edefdd41831fe65648cb3f3fba5db9f664c33a73644a28752"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeNodeProps_cannot_smuggle_non_canonical_richtext: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"b8e1f066e41b450c59aec554abfe93f6eb24c209052df4a818cafb329c786f18"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_heading_level_out_of_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"08cb7fe242c9e4643580c21be2dfcc54917289730829e642c0407f3445b4938c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_grid_item_size_out_of_range_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":77}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ad73414621de15a1ed1a5976b8b8660cd413b2a71edffdf53ed33261dda82a5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddNode_block_instance_with_non_canonical_override_html_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":85}}}],"partialFingerprints":{"codehealthFindingId/v1":"dd79ef5a361c094a20a5b8fc69a6ecaacfd14a7feba89c3c2ba0a64d24af47cc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DuplicateNode_with_the_reserved_root_id_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageSpecValidationTests.cs"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"cc0f363eae722f8b56dd51d562c12dec81cf197fd64fc688dc5e87546fb9e2d9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeTitle_with_new_value_raises_event: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageTitleSlugMetaTests.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ee636a281c81474af048fd3c9c0ccb73d592cd568f33915462ae763c3256a3b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeTitle_over_200_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageTitleSlugMetaTests.cs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"8b468955a1a61fe97f9db1b608a5872a604ecf9d62b7f02d587ef917f5570f12"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeMeta_title_over_300_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageTitleSlugMetaTests.cs"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"d612907d08402b15a3650532900445bd6db986c16ddacc4a7d69a2b5124ab5fe"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeMeta_description_over_300_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageTitleSlugMetaTests.cs"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"ff804e39c5e1d8d8bb04d26fb31cfb288867e02fdba15a8512ee4594b097223b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeMeta_values_of_exactly_300_characters_are_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Pages/PageTitleSlugMetaTests.cs"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"7e48ab063a1226a45052ee06f75e6260c23244fe532ddd4c810f6a00830ac19c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SubmitForReview_refuses_prose_that_cannot_be_rendered: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":50}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f02484a0cfc8d377d2c02281700a839e44ca1a358113cfa7b63da7aaf7249af"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SubmitForReview_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":57}}}],"partialFingerprints":{"codehealthFindingId/v1":"06c8f56342d3e44ea1aa2f3cb76d6ee90b84fea72d4744fa0015e1e3f77a91eb"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SubmitForReview_of_a_live_post_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"30e8ff5d96adefa564f4b74f986e34dce87956995ab364de28dcb732ba3280b2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ApproveReview_of_a_post_nobody_submitted_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"1a334b9fe76fdd84e9a52eca228790ddb4b8f4b35a72f345ffb6f6116c2b1731"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RequestChanges_without_a_reason_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"4fb49428cd6db7b7d7a9058cb733229050fb3c819f168c0ddb8c689177b1726c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: An_autosave_that_changes_nothing_keeps_the_approval: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"b2a594110b4590195786b4d9e76a2e27a6b7cb8d39cfa9c8dc73ca168b09f3f5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Editing_a_published_post_does_not_lapse_anything: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":151}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3fe2eac6949742de2618019e8a0dd217c491997cf1e78047774af0d2e998896"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetPublishDate_to_the_same_instant_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostReviewTests.cs"},"region":{"startLine":201}}}],"partialFingerprints":{"codehealthFindingId/v1":"f40910087d47eb9cd02768a73ea897572163302d5c95069e73829379facf3340"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Changing_the_body_stores_the_markdown_verbatim: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"20260c24cc59a1cd5f247d93ed0436b60f3279ebc8b8dbf89c57b17fb4be6598"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_draft_may_hold_markdown_that_cannot_yet_be_represented: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"03605d3d386fc87ebc3ef82c5a2f4224f431a214086859373c34e84af5664fec"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: An_unreasonably_long_body_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":103}}}],"partialFingerprints":{"codehealthFindingId/v1":"b003b1eb7a93608c23b5364f61292fe89641c6185f446ce00d41eba82eb03801"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Unpublishing_a_draft_does_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":167}}}],"partialFingerprints":{"codehealthFindingId/v1":"fabe8a8d3b89bdc6b96ef578b4c6f8365a2524f497e71564c96825af8e7e657d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Changing_the_title_raises_it_per_locale: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":175}}}],"partialFingerprints":{"codehealthFindingId/v1":"aba62013907f38731b14997b3d308e0b4ef180526b026df3a725aff7d85c3d03"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Changing_the_meta_raises_it: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":193}}}],"partialFingerprints":{"codehealthFindingId/v1":"cef430eeedd4d4a2864ccc87e0cd845b01912fe7b883984e76b527aa4740967a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Deleting_marks_it_deleted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"2763471f5e3ff6501b623f2616fcebc8f95f35d90f5a9fc9b034bbca68f502d2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Editing_a_deleted_post_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Posts/PostTests.cs"},"region":{"startLine":213}}}],"partialFingerprints":{"codehealthFindingId/v1":"4ff87559afaac3dce5ec135ca3969aecaf7b44f7647fee2a6a5da35f8b8fc32d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_accepts_a_direct_external_link: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"a30e07d01484e20f28744543ba840bbb226fe72b670d71d8d3d88fd56f1cf497"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_accepts_a_group_with_page_and_external_children: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"643dd57dae7014d8ccc3a10f931e52901d5f09de355a72557b31dce444709ba4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_group_without_a_label_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba2e45c61fa66c54b9f1968546b47aeeff6958bea951c5c82ce55cc480e91353"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_external_link_without_a_label_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"382f79f170cc94e698358d525156e2c7652649ea03c3d7c9704ffd021f154c95"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_the_same_page_twice_at_top_level_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":68}}}],"partialFingerprints":{"codehealthFindingId/v1":"7073e9fe6ff32008f4ec226281b5021936c7540d934fb2bce3316ed2955436a7"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_the_same_page_as_a_group_child_and_a_top_level_link_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":79}}}],"partialFingerprints":{"codehealthFindingId/v1":"224de574496ca15ac9571a27e99c8fa5a528849d6e5562ea38c41f4ef7e590b2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_more_than_the_child_cap_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":97}}}],"partialFingerprints":{"codehealthFindingId/v1":"af7a52351338e14733d84a227e4bcc3073c52e1e622cec51395d07221fdfcbcc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFooter_valid_groups_raise_footer_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":112}}}],"partialFingerprints":{"codehealthFindingId/v1":"b01c05d974d96a5c9253df2f7693bb0998208604f1ac4ea4150ad3dc43f35dd4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFooter_group_without_a_heading_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"42de68f0e04694f35903bd1bdef5f7f38396c1e20750dcb61b9c30ee1a0ce88d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFooter_external_link_without_a_label_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":149}}}],"partialFingerprints":{"codehealthFindingId/v1":"5eb8dbada6072d98749eadb30fde46ecbe0509c838e423871fd322eab975c9db"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFooter_with_unchanged_groups_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":157}}}],"partialFingerprints":{"codehealthFindingId/v1":"7a3d100306c205a422dac294ac952601136a716cac3e353590aba64c5cb1f417"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetHeaderActions_raises_actions_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":171}}}],"partialFingerprints":{"codehealthFindingId/v1":"17ac30bd751fbf50a7136c215ad036b619f1b33a649be5a6b6cf1e8c7043b931"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetHeaderActions_with_unchanged_pair_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":196}}}],"partialFingerprints":{"codehealthFindingId/v1":"d48afd0534977b1a4e87803d2c3beb0976abfef48c2336aa58f8a0ed1de8eaf3"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFavicon_raises_favicon_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":209}}}],"partialFingerprints":{"codehealthFindingId/v1":"24093ebe5569b451ece70f01189c4a6e6ce0a49c68f9733fb71ba44fcbf713e7"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFavicon_can_clear_an_existing_favicon: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":220}}}],"partialFingerprints":{"codehealthFindingId/v1":"34032033269f552bb6f77ecedfa6d5e1b6198e754db6f452ba0fcdcd20d4c7bc"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetFavicon_with_the_same_asset_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":227}}}],"partialFingerprints":{"codehealthFindingId/v1":"ccc799723b96a3a00cdd7f390d67637777737953457a085c821743c6ad61641d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetHeaderLogo_with_the_same_asset_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":251}}}],"partialFingerprints":{"codehealthFindingId/v1":"d59e92a1271303252b189df41f66933e0646fb09dab35a03f8faf3170c010722"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetSocialImage_can_clear_an_existing_share_image: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":277}}}],"partialFingerprints":{"codehealthFindingId/v1":"23747139413b825c14807deb61a4601cbed06fd877460302b8bdea4baa06c200"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetSocialImage_with_the_same_asset_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"d98830a9ee3590f6ce968921196ff5817c56047cbc3e7f077374f1fadc7b89ee"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_blank_preamble_is_no_preamble_not_a_preamble_of_spaces: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":324}}}],"partialFingerprints":{"codehealthFindingId/v1":"7adb3039e4700970fdca4d2989e0201c27a7ab63865b61353ab0351075a4933d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetLlmsPreamble_with_the_same_text_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":331}}}],"partialFingerprints":{"codehealthFindingId/v1":"3de5a7199ebe84f47e81a0e23b8500a1c946e0662f8656520260461001a6c161"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_preamble_longer_than_the_limit_is_refused: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":338}}}],"partialFingerprints":{"codehealthFindingId/v1":"e4d9cadecb0130ab84144f37368b9aedbb4f163204705f6af5ac0977122a669a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetCopyLine_raises_copy_line_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":349}}}],"partialFingerprints":{"codehealthFindingId/v1":"73c3feb2dbcc2da5e752dccd275f2347190de2f476a004c199b155797e49af1c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetCopyLine_can_clear_an_existing_line: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":360}}}],"partialFingerprints":{"codehealthFindingId/v1":"02e790e1ed3f25b101d3fd90644f6a12f4ce2665e69ff3d86f0609fb17d499ac"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetCopyLine_with_unchanged_value_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":367}}}],"partialFingerprints":{"codehealthFindingId/v1":"d90a84eae81535839d14b0020b949135196465a9e898c1d53b7206b622acfc61"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetCopyLine_clearing_when_already_clear_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteChromeTests.cs"},"region":{"startLine":374}}}],"partialFingerprints":{"codehealthFindingId/v1":"53ff81fc9d64c04bc7257e00b0adcf0028ada2a77ef95adb6df73d480dfc5fe0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Adding_a_collaborator_raises_added: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"28b5ffd009f3d896cda44005e1e667a7df604ec10858d21aaf4442383a5f1063"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: The_email_is_trimmed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"b82b57d44086fda731815a4bce0f8b679e93fcd3535eabdf1ab7ab6bff6d20bf"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Adding_the_same_email_twice_is_rejected_case_insensitively: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":27}}}],"partialFingerprints":{"codehealthFindingId/v1":"5358759ffbacb6b2eaa0d953e9e5b7630a652c6d422b2b7dc87a5660757fad5a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: An_empty_email_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"a86d8bc2d2a9dc0af3d98c8c037a6a11f01faeb99f8c3eca75e58dd8527e2b19"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_value_that_does_not_look_like_an_email_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"9e3c2f232174e6041229bcee65d197f72263d9fd41f94e4f6d5a0428101630ae"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Adding_beyond_the_cap_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":53}}}],"partialFingerprints":{"codehealthFindingId/v1":"0ca15092115a53cba67b3bc78fccc4d447b1a541159c48e07bc1d89be7361661"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Removing_a_collaborator_raises_removed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"e7c25dd22922ae66cd53cad84280d0263465174cb5f419822a653d0031dd6c2f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Removing_an_unknown_email_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"fe7c4fb4ca2dea53e34faf0860e5e93dd762b409911018b26ce09ea108963044"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_removed_collaborator_can_be_added_again: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteCollaboratorTests.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"8462b33367dc14bbde2c8fc0fb8795a4dbe39a2129a9c74ce4a250887fe00af6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_valid_pipeline_raises_environments_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"58791ff2d8367b09c0eef02f00480e597e4479f543dc08d3f183dbd4c09aed47"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_trims_names_and_paths_before_raising: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":28}}}],"partialFingerprints":{"codehealthFindingId/v1":"aca83a80b0887f21ce139e1c7b957d688654a29d3c5c0c60fa1f869a807e48ef"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_empty_name_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"2ce146569a9997f4e9c190dbe2acf66b79ad3984dc30c03c7b2c55b82add13c4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_overlong_name_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"391f1569d9dbc35de4152db7c0bd55a7f95d816b8e6a0f040853842431fd9595"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_empty_path_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":59}}}],"partialFingerprints":{"codehealthFindingId/v1":"dc7e3eedee9b20648069c122aed6d6179b4bb762150875274d3e23446ac65490"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_duplicate_names_are_rejected_case_insensitively: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":66}}}],"partialFingerprints":{"codehealthFindingId/v1":"22136a1f3c10370185284b3f0471bd1af56a60b6d65be0e43360cf46b39b0197"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_two_environments_may_share_a_folder: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"b1b937bf84e1fe6f101912900ec647251b33cd646d7a57cecaf6f9a53b184bd0"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_at_the_maximum_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":85}}}],"partialFingerprints":{"codehealthFindingId/v1":"bf3dacb882a98937ccda8ef13c69fe9b04dd1f8d72b96607f2c27ee795c86ce6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_above_the_maximum_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":98}}}],"partialFingerprints":{"codehealthFindingId/v1":"871b8e6cc72762056a0957526b78d8ca3c98324cbceef8001fc018f5b2e044d9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_reordering_raises_environments_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":111}}}],"partialFingerprints":{"codehealthFindingId/v1":"06441a0f00e7f99bff8aad5af6b102636113d75cf94e7cd227da495d5016b690"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_unchanged_value_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":118}}}],"partialFingerprints":{"codehealthFindingId/v1":"96b2346b75826ea3ee0c227986973e9ae66764985ff36affcd167b46ef728d7e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_unchanged_after_whitespace_normalization_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"68da59888b1542254ab349ee593233060e6ff1a008e18a3d438d7f2d580a805a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_clearing_existing_raises_environments_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a47a58f86e0c13f074b19462d532a8b74036469201e22cd9d248bcef3493948"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_empty_when_already_empty_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":141}}}],"partialFingerprints":{"codehealthFindingId/v1":"ed4c196b4109e270d8d34a25b569922edb7067d1c618ac517c5bab3b0c30bc49"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_valid_base_url_raises_environments_changed_with_it: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":150}}}],"partialFingerprints":{"codehealthFindingId/v1":"091eb64fff3351e2cede04b3e1253a4c701f6c005b83c9368450b0cb8b1b5c13"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_base_url_trailing_slash_is_normalized_off: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":159}}}],"partialFingerprints":{"codehealthFindingId/v1":"d6bd1e360a7e2f3554ff7dee9aa9db813e375864265e77f3018df0a601c4f9e4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_blank_base_url_is_stored_as_null: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":170}}}],"partialFingerprints":{"codehealthFindingId/v1":"89c7a091a86c58a964ca4df35715dfbb8e645054926973073d4f6259ad750057"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_relative_base_url_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":178}}}],"partialFingerprints":{"codehealthFindingId/v1":"673ea63d4f2146ce5e17db9e591556236321d2c353d785c8a001ae329cbe6b65"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_non_http_scheme_base_url_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":185}}}],"partialFingerprints":{"codehealthFindingId/v1":"36bb4568341d791f668df14256ee2f57d54b87853506a236d7509af1a0f23f5f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetEnvironments_unchanged_base_url_after_normalization_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteEnvironmentsTests.cs"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"c8e2cf8c9a64e01369f0eae1b38eb75c3add3fa01216b6e32a0f3f53066ab2bb"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Prefixes_are_stored_as_given_when_already_clean: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"6067501e7b9c69e416d65fde03a4a01b7858ae046b577c28b0c48eed21801577"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Slashes_and_case_are_normalized_away: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"ed37dbdd7b4dcd0847dfa84bc46e67aceea888d97d96329c9ecc6347de83128c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Blank_entries_are_dropped_rather_than_stored_as_empty_prefixes: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"b53d1416d5c57c1e1984704efab276a1936a31f59512ba4856f0cad0bd5520a2"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Duplicates_collapse: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"f7979dd280f140709f052a7b089413e42a2e86e90fb0b8a184be490b2207378b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_trailing_wildcard_is_kept_so_a_family_of_generated_names_needs_one_rule: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":52}}}],"partialFingerprints":{"codehealthFindingId/v1":"aa3679064d957e84f36d05752d0f48980ff4f369ff4fd9f21cd9704018c12128"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: A_prefix_that_is_not_path_shaped_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":61}}}],"partialFingerprints":{"codehealthFindingId/v1":"1f164b6abf5f20d41fa8ef609bbe4816f765bcb66e15118c46c6aa42f8c4f474"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: More_than_the_cap_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"63e0d6010028503c3bb972e5f87128a78b724e3687e2146fefb2e5cac580568c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Setting_the_same_policy_again_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":83}}}],"partialFingerprints":{"codehealthFindingId/v1":"a3c1a19e0f27fe2a694c44806121e0399dc8c43bd410a9a068011336215a1e48"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Clearing_the_policy_raises_an_empty_list: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLlmsExcludedPathsTests.cs"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"aaca3aa147f73b25c6d14a31471748ad9fc15896966eddc008a6191d145d3a09"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddLocale_new_locale_raises_locale_added: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"80c90e93a0896bc5a571ef280f263df2eb73117cec604b673254d184901a4f88"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddLocale_already_present_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"5bd0c46df9739faf908717a1c9d8bea90fb52f16c7088422e2a179d10bff9f4e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddLocale_same_locale_with_different_casing_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"c199d281a1fc3a38c831feef851f7a2dc2e65e0eadc22367678d80caa78f38d1"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddLocale_tenth_locale_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":58}}}],"partialFingerprints":{"codehealthFindingId/v1":"91d76859a7d56aa22aa241d34e4d9c8c59659bd4f2b00516e477ec8f45074943"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: AddLocale_beyond_ten_locales_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":65}}}],"partialFingerprints":{"codehealthFindingId/v1":"0859f85ced1c4d90a070ce8a6af5536629aab1d5d1443b5e6b10a733fd455175"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_non_default_locale_raises_locale_removed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":74}}}],"partialFingerprints":{"codehealthFindingId/v1":"6c30022b86975d5230101a22ba5b24c27a2a570a756353f4a3eeba8d90466ec5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_with_differently_cased_tag_removes_the_same_locale: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"f8b0036ae3d78b21d0b046fe92e748ef8351e6905c6b5e708737bd44ea8a1e3c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_absent_locale_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"caba24a0ba1edcfd331f16d0f2b821abde628e9e700bb541a686923a011f4b43"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_default_locale_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":95}}}],"partialFingerprints":{"codehealthFindingId/v1":"8f049db49916e0e44a5695d0a00b332c82b96480c4d0a94c28927f3afcbd3fe6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_referenced_by_a_navigation_label_override_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":102}}}],"partialFingerprints":{"codehealthFindingId/v1":"ba35f95e389c52f8556fb62ddd0efe4800ea7692575a8593ea5a72aa4743516d"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeDefaultLocale_to_a_site_locale_raises_default_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":127}}}],"partialFingerprints":{"codehealthFindingId/v1":"1fddd2ad538ecb47b3257a25c7d8d911f0d22b8fee0364d0170378f608c8c8a6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: ChangeDefaultLocale_to_an_unknown_locale_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":134}}}],"partialFingerprints":{"codehealthFindingId/v1":"4f8e9139458ef5b3ce96dec5b90d8ce3d0687d25b5448f72ef6ad106f9d44dff"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_previous_default_after_default_changed_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":141}}}],"partialFingerprints":{"codehealthFindingId/v1":"7258c834f002efa72bc4b243a0a85928af5b0d4b291e5f8af84f72fc973e2302"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: RemoveLocale_new_default_after_default_changed_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteLocaleTests.cs"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"017d94a62d683022a39379747f2153ecd970b1a8817204666763d57e09e47d3e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_valid_items_raises_navigation_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":18}}}],"partialFingerprints":{"codehealthFindingId/v1":"6d00b586813a4826ae41ada3306f6b04bc65c48967d092c36684a7694082acd4"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_duplicate_pages_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"1d4896e5ff7b4b53467c06dd4a4f5d3adbe72d352f159be9666f7713d8cfe06f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_may_hold_several_sections_of_the_same_page: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"1b296599744c96fc9c67fc87f09340fa1f359f4ba3fbdd9635fdae1eeed8658a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_the_same_section_of_a_page_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":69}}}],"partialFingerprints":{"codehealthFindingId/v1":"33323fa319da2ca408f1f11888f96aff422da9ed87f12bac8455777e38ecaa2b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_an_unnamed_section_link_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":86}}}],"partialFingerprints":{"codehealthFindingId/v1":"5b9964b9f068b66821b659e3af48c0d02118ac6ccfb5f1bf10f9e7664ef8f4db"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_twenty_items_is_accepted: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"3c3ac27e7b27fc14de44dc3836be40301b60f5eabcba14d803af561bc4ea30d8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_more_than_twenty_items_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":110}}}],"partialFingerprints":{"codehealthFindingId/v1":"2227354b57c87c73f85a3f1599db66bdad4e9250d2e3141de68cabe3ea7284cd"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_unchanged_items_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"af860a2b12b74f34f983987ac2769e612b049060e20d2d2339c239d7fba2c8eb"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_with_reordered_items_raises_navigation_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"229ac21b916847ab060eaff11ccb05e0490315f1282e68bb88d1c3628a0b117c"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_clearing_existing_navigation_raises_navigation_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":142}}}],"partialFingerprints":{"codehealthFindingId/v1":"1e685c68a9bf474972de3a33c3c4a43634e9a2d14709feceb92f00dbd7cc85ef"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetNavigation_empty_when_already_empty_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteNavigationTests.cs"},"region":{"startLine":149}}}],"partialFingerprints":{"codehealthFindingId/v1":"21ad7666d195956fb14a0a0a68e400b9a69462a133139a44deb1f548a5bd80d6"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Claiming_ownership_raises_claimed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteOwnershipTests.cs"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"99e31348a41b2900280493cde2048b1a20bc35cc64d5f8431847064c6811a3c9"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_a_new_name_raises_renamed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteRenameTests.cs"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"a6add927472149aa4a5a68549424a4c67db400dd9b09a64090dccb48b62e4083"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_the_unchanged_name_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteRenameTests.cs"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"75324571d97096585a6f58a9bfc2cc6545270afdfc136fd00be7d6ea86afb998"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_the_unchanged_name_with_surrounding_whitespace_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteRenameTests.cs"},"region":{"startLine":28}}}],"partialFingerprints":{"codehealthFindingId/v1":"7ccec556aad036e5587876d20e4625176f5ffb286170b8866392ff726f0c4295"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_empty_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteRenameTests.cs"},"region":{"startLine":35}}}],"partialFingerprints":{"codehealthFindingId/v1":"5f525d19c1df9c57001125f49a6944a79c86f778cedb95f2025acff0dff8320a"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Rename_to_more_than_100_characters_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteRenameTests.cs"},"region":{"startLine":42}}}],"partialFingerprints":{"codehealthFindingId/v1":"852e5c25b2d23e4b992f390723e337a13a002cab546ce8af2bb22de4bdbf1245"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SeedChromeLocale_from_itself_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteSeedLocaleTests.cs"},"region":{"startLine":86}}}],"partialFingerprints":{"codehealthFindingId/v1":"55850793aef420d9cc1d2a2a60041b1b8ca3a0a1d570a8ccfa9088b038f233f8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_known_token_with_valid_colors_raises_token_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb52c3bcb17447ec3f0aa94964cb1e11249ceb0bd6cddfc6ef1ecc2b32f50808"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_unknown_token_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"4fb8345806616ec64d7d50cf31a44cfa469a0092e5e34ea236e6010239249051"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_invalid_light_color_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":48}}}],"partialFingerprints":{"codehealthFindingId/v1":"5df623f5000c2a3ed71e044456c0f0ccaba45859752427e700bf10b33734e541"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_invalid_dark_color_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":55}}}],"partialFingerprints":{"codehealthFindingId/v1":"56bc6d34e7d5eebfebac88330461b98a6d8017dc821ecd2880fab8c404b00c9e"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_with_unchanged_default_values_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":62}}}],"partialFingerprints":{"codehealthFindingId/v1":"5505afafcee18d3bcaba93306e2fe13bf3617b78c3df8d5349cd3154fce9df93"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetThemeToken_unchanged_after_a_previous_change_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":73}}}],"partialFingerprints":{"codehealthFindingId/v1":"d20e09b7ba88558beb152e72789bc6c84d6f11bd46001588238fc47f9140311f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetTypography_valid_typography_raises_typography_changed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":82}}}],"partialFingerprints":{"codehealthFindingId/v1":"237fd81819974d0909bfd725e495ea8ead08aea44fa2e6663a43369a48b31901"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetTypography_out_of_range_values_are_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":99}}}],"partialFingerprints":{"codehealthFindingId/v1":"fe025d52a8fd40b1631e848cf6f09ce05420b393fdfee600d3ab6a7354ce2acf"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetTypography_with_unchanged_typography_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf2080474ddf6b50b29a05170c569d50773d7062195e9b250c6a79fff487306b"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: SetTypography_unchanged_after_a_previous_change_raises_nothing: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Sites/SiteThemeTests.cs"},"region":{"startLine":124}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b868edfafdee8a70c8a6f3557b658b755522082718e91c450e3676b34e89717"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Approve_without_an_approver_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":204}}}],"partialFingerprints":{"codehealthFindingId/v1":"36c01ae009df77df36e6b0f6893fca15d6e68fbd807badd1f0289b9f4369a6b8"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Approve_an_already_approved_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":211}}}],"partialFingerprints":{"codehealthFindingId/v1":"fb0991d3165d1db4cd272bc05228d0300e401c7238e05beb4dc049fb64847eab"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Approve_a_rejected_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"77664e0347baf46c33491ed81d3e972506944384baa3a27207dc8d833651573f"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Approve_a_withdrawn_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":225}}}],"partialFingerprints":{"codehealthFindingId/v1":"bee7c261dfa112b610ee03555609d511cc9d2e1b656efc19a5be29130b551333"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Reject_without_a_reason_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":246}}}],"partialFingerprints":{"codehealthFindingId/v1":"e24379fb34b077e793cbbe0310bff7331b701adeb52f91f2e289cbe4c875ef74"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Reject_without_a_rejecter_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":255}}}],"partialFingerprints":{"codehealthFindingId/v1":"397c629cb159d9d4eb4267f60b22021c0d087146dfb4d9b95c797688324d03ff"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Reject_an_approved_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":262}}}],"partialFingerprints":{"codehealthFindingId/v1":"099f9f2b3d7f47f22fa18e8b08208a83690b7fc4f6c7b7dcfa4089c0b273da98"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Withdraw_an_approved_submission_is_allowed: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":282}}}],"partialFingerprints":{"codehealthFindingId/v1":"ef2b8fb4929ae9c3ef9072db627a3a00ddcaab6b515f0a75e6ac753a85362314"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Withdraw_twice_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":289}}}],"partialFingerprints":{"codehealthFindingId/v1":"c5d5e5c0527948578be3a006014c52e43f5ce11c1b241bdafb60c669a05bde98"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Revise_still_validates_the_manifest: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":323}}}],"partialFingerprints":{"codehealthFindingId/v1":"4e0841c42d1fa9c1024343bba52b7e03509ee06243816a4dcc0a0b00202b68a5"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Revise_an_approved_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":330}}}],"partialFingerprints":{"codehealthFindingId/v1":"79996c98426d5787d75c1aadad17e801f10073f5989d9ee8fba5164a20dd4e97"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Revise_a_withdrawn_submission_is_rejected: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Widgets/WidgetSubmissionTests.cs"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"8c71b90ffb2643236c30d02ef27cc457220228eb143f75375a3c490f10785187"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Inline_edit_of_a_heading_commits_and_survives_reload: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.E2E/CanvasInteractionTests.cs"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"61b8d7282ba2bca27641aeb83b4565ec883735fdb3c3b30215579ebb766f8325"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: Requesting_a_widget_then_approving_it_makes_it_available_in_the_picker: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.E2E/WidgetApprovalTests.cs"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"83521ffb3b8fc30b5cf21ccfbb8bd96a00bf024aed304ca4b9edb80dd38a0a12"}},{"ruleId":"D10","level":"warning","message":{"text":"No assertions: DeleteAll_for_unknown_asset_is_a_no_op: Test method exercises code but verifies nothing \u2014 add an assertion."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Media.Tests/DiskMediaStoreTests.cs"},"region":{"startLine":179}}}],"partialFingerprints":{"codehealthFindingId/v1":"855a3ff9a2a8e3dcdfa6ca3e3fb6c80ac258a314649d55ccb2563ffe91aa127b"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Editor/Api/AuthoringApi.cs: src/Imprint.Editor/Api/AuthoringApi.cs changed 25 times in last 90 days, max cyclomatic complexity 212 in AuthoringApi.MapAuthoringApi at line 88. 6 of those changes were fix/bug commits, and the other 19 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Editor/Api/AuthoringApi.cs\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/Imprint.Editor/Api/AuthoringApi.cs"},"region":{"startLine":88}}}],"partialFingerprints":{"codehealthFindingId/v1":"4174cc13fa5b37fe985dc69f2404770f22cfe7ca08fc34304f38c74a1230962e"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Publishing/SitePublisher.cs: src/Imprint.Publishing/SitePublisher.cs changed 32 times in last 90 days, max cyclomatic complexity 17 in Pass.PlanPages at line 502. 10 of those changes were fix/bug commits, and the other 22 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Publishing/SitePublisher.cs\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/Imprint.Publishing/SitePublisher.cs"},"region":{"startLine":502}}}],"partialFingerprints":{"codehealthFindingId/v1":"0b91156b00d9d7c7d35d61c16f4b686cfa9283c71ba7f204d355c9a3455a3dd0"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Domain/Sites/Site.cs: src/Imprint.Authoring/Domain/Sites/Site.cs changed 15 times in last 90 days, max cyclomatic complexity 23 in Site.When at line 775. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Domain/Sites/Site.cs\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/Imprint.Authoring/Domain/Sites/Site.cs"},"region":{"startLine":775}}}],"partialFingerprints":{"codehealthFindingId/v1":"638aee8ffe41f100e6b9ccafd9c7b3d9b7d650db3bd3c8914a485b71291ecc39"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: tools/ContentSeeder/BlockMapper.cs: tools/ContentSeeder/BlockMapper.cs changed 11 times in last 90 days, max cyclomatic complexity 28 in BlockMapper.Map at line 37. 1 of those changes was a fix/bug commit, and the other 10 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- tools/ContentSeeder/BlockMapper.cs\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":"tools/ContentSeeder/BlockMapper.cs"},"region":{"startLine":37}}}],"partialFingerprints":{"codehealthFindingId/v1":"15ea201760214572e24b66dedaa56145cd0b05697c949ad60732f8075adf6691"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: tools/ContentSeeder/Migrator.cs: tools/ContentSeeder/Migrator.cs changed 9 times in last 90 days, max cyclomatic complexity 24 in Migrator.MigrateSite at line 56. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- tools/ContentSeeder/Migrator.cs\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":"tools/ContentSeeder/Migrator.cs"},"region":{"startLine":56}}}],"partialFingerprints":{"codehealthFindingId/v1":"465d8a3d3853d8623d7be29d49770f751b319aa6e682eb9b3da31e4c1121479b"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-card-gallery.js: widgets/cai-card-gallery.js changed 8 times in last 90 days, max cyclomatic complexity 26 in z at line 122. 3 of those changes were fix/bug commits, and the other 5 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-card-gallery.js\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":"widgets/cai-card-gallery.js"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"17a232e817d1d68abd005f02854ae0638a4934c9e06d66264dd2a42993f94191"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-score-card.js: widgets/cai-score-card.js changed 7 times in last 90 days, max cyclomatic complexity 26 in H at line 117. 3 of those changes were fix/bug commits, and the other 4 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-score-card.js\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":"widgets/cai-score-card.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"20f849110e293ca672073da343e105f80ce38b0b0a5fdf0d9c8e62e26a86088e"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Editor/Api/AuthoringNodeJson.cs: src/Imprint.Editor/Api/AuthoringNodeJson.cs changed 5 times in last 90 days, max cyclomatic complexity 34 in AuthoringNodeJson.ApplyProps at line 384. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Editor/Api/AuthoringNodeJson.cs\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/Imprint.Editor/Api/AuthoringNodeJson.cs"},"region":{"startLine":384}}}],"partialFingerprints":{"codehealthFindingId/v1":"ef7b2c7c9336760c6f2252bd768f7d9426d5b74040294ae2e2d8f4f969b8abad"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: tools/ContentSeeder/Verify.cs: tools/ContentSeeder/Verify.cs changed 5 times in last 90 days, max cyclomatic complexity 29 in Verify.Run at line 19. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- tools/ContentSeeder/Verify.cs\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":"tools/ContentSeeder/Verify.cs"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"5955c1e68da3581171a46432553976b4e6853f3a6c80e18f1a31e4ebc03df34f"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: tools/ContentSeeder/Program.cs: tools/ContentSeeder/Program.cs changed 9 times in last 90 days, max cyclomatic complexity 16 in Args.Parse at line 345. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- tools/ContentSeeder/Program.cs\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":"tools/ContentSeeder/Program.cs"},"region":{"startLine":345}}}],"partialFingerprints":{"codehealthFindingId/v1":"55760b3a46758643566dfad2c053694f81c80b78400913f625e6545082ca6b1b"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-dimensions.js: widgets/_src/cai-dimensions.js changed 4 times in last 90 days, max cyclomatic complexity 35 in render at line 192. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-dimensions.js\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":"widgets/_src/cai-dimensions.js"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"30ff45df5cfdd47bf108f04922553106102b2a04bfdb33da5813f592af11ed0c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Domain/Pages/Page.cs: src/Imprint.Authoring/Domain/Pages/Page.cs changed 7 times in last 90 days, max cyclomatic complexity 19 in Page.When at line 462. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Domain/Pages/Page.cs\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/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":462}}}],"partialFingerprints":{"codehealthFindingId/v1":"87c14fcef721c68a609c59dec47ae82bc341c93c180973f5e3b681598d53d260"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/live.js: widgets/_src/live.js changed 7 times in last 90 days, max cyclomatic complexity 18 in cardFromGallery at line 64. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/live.js\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":"widgets/_src/live.js"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"104cc664bc241af5a8f3c61065e13c47cf9fc6754f7b998bb374623cacd67379"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-findings.js: widgets/cai-findings.js changed 6 times in last 90 days, max cyclomatic complexity 20 in #r 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-findings.js\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":"widgets/cai-findings.js"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"68a964c2ac5e1855fff2a18c21bbab92735e71f4e46b2a5fc9910abf5130bcca"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-dimensions.js: widgets/cai-dimensions.js changed 3 times in last 90 days, max cyclomatic complexity 35 in render at line 173. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-dimensions.js\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":"widgets/cai-dimensions.js"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"eb7b642be3ce14b6edf91b1ccdf8bd92d9b7343c4d3ffe4f1909188f37708ee8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Editor/wwwroot/js/canvas-interop.js: src/Imprint.Editor/wwwroot/js/canvas-interop.js changed 6 times in last 90 days, max cyclomatic complexity 16 in onKeyDown at line 275. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Editor/wwwroot/js/canvas-interop.js\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/Imprint.Editor/wwwroot/js/canvas-interop.js"},"region":{"startLine":275}}}],"partialFingerprints":{"codehealthFindingId/v1":"cad6f3f1c73451e3e4ab27d646e8f3a937aa491553e52af2b8e8d48c16fd9403"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-score-card.js: widgets/_src/cai-score-card.js changed 5 times in last 90 days, max cyclomatic complexity 19 in render at line 72. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-score-card.js\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":"widgets/_src/cai-score-card.js"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"aaaa3650f8e354d4019e08036442c215d9c39885f4d9d5fe6e4933bf1c52ef41"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-language-support.js: widgets/cai-language-support.js changed 5 times in last 90 days, max cyclomatic complexity 16 in render at line 158. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-language-support.js\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":"widgets/cai-language-support.js"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"b4f288489fe29915938368bacc6ae823763f37ca9b8a122ba8fae7ed0bdc8343"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-findings.js: widgets/_src/cai-findings.js changed 4 times in last 90 days, max cyclomatic complexity 20 in #repoHtml at line 107. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-findings.js\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":"widgets/_src/cai-findings.js"},"region":{"startLine":107}}}],"partialFingerprints":{"codehealthFindingId/v1":"09434e0ea3c6dafe7329572cadf36a7de86c6df4294bbcce60a520fa815f58f8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Domain/Assets/Asset.cs: src/Imprint.Authoring/Domain/Assets/Asset.cs changed 4 times in last 90 days, max cyclomatic complexity 18 in Asset.When at line 328. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Domain/Assets/Asset.cs\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/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":328}}}],"partialFingerprints":{"codehealthFindingId/v1":"468ce2a7965da90d93accd05f34ad6acd0beaf6c341c17c8c94b8eb4e1ce474a"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-survey-list.js: widgets/_src/cai-survey-list.js changed 4 times in last 90 days, max cyclomatic complexity 17 in render at line 92. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-survey-list.js\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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f2a2ff1fe269a43b7346637b6034028f9bed489b67849693127be6c4cfbdc7a"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-survey-list.js: widgets/cai-survey-list.js changed 4 times in last 90 days, max cyclomatic complexity 17 in render at line 268. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-survey-list.js\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":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"fe18ce115de9dc6ad7fd90e3c07ad5653acf16db193f8690961491fc74591e16"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs: src/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs changed 4 times in last 90 days, max cyclomatic complexity 17 in CanonicalHtml.ParseInlineUntil at line 105. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs\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/Imprint.Authoring/Domain/Pages/CanonicalHtml.cs"},"region":{"startLine":105}}}],"partialFingerprints":{"codehealthFindingId/v1":"48562e1a4332e8233dd4c54e0a9066bddf37fa83dc7a8471a387790b2c9ec149"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-language-support.js: widgets/_src/cai-language-support.js changed 4 times in last 90 days, max cyclomatic complexity 16 in render 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-language-support.js\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":"widgets/_src/cai-language-support.js"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"df4fe2c3b2895237249a335848273a76244b300394e9d943e2ba9c9947ea50f6"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Rendering/NodeTypeNames.cs: src/Imprint.Rendering/NodeTypeNames.cs changed 3 times in last 90 days, max cyclomatic complexity 18 in NodeTypeNames.Of at line 13. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Rendering/NodeTypeNames.cs\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/Imprint.Rendering/NodeTypeNames.cs"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"bbd3c7b6242963c763ac0021dd3c73a715c4babc13081806c4ddfdbfb7bb009a"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Markdown/MarkdownToNodes.cs: src/Imprint.Authoring/Markdown/MarkdownToNodes.cs changed 2 times in last 90 days, max cyclomatic complexity 26 in MarkdownToNodes.Inline at line 395. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Markdown/MarkdownToNodes.cs\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/Imprint.Authoring/Markdown/MarkdownToNodes.cs"},"region":{"startLine":395}}}],"partialFingerprints":{"codehealthFindingId/v1":"cc92c93ad058fea4ad486e75b4c583b32a4378ddebb2fd8486dc8a35b03769f8"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Publishing/SitePreview.cs: src/Imprint.Publishing/SitePreview.cs changed 3 times in last 90 days, max cyclomatic complexity 17 in SitePreview.ContentTypeOf at line 184. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Publishing/SitePreview.cs\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/Imprint.Publishing/SitePreview.cs"},"region":{"startLine":184}}}],"partialFingerprints":{"codehealthFindingId/v1":"de88432b2b17fc6176934bb81b2b19d55ba9a0b17f3d1b4e44d8c1e07e2ae731"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Projections/PostList.cs: src/Imprint.Authoring/Projections/PostList.cs changed 3 times in last 90 days, max cyclomatic complexity 15 in PostList.Apply at line 122. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Projections/PostList.cs\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/Imprint.Authoring/Projections/PostList.cs"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"2696da7e7249568d1c0a2484274a65a9af78115716094f5e3388d804bdddb55c"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-trend.js: widgets/_src/cai-trend.js changed 2 times in last 90 days, max cyclomatic complexity 18 in render at line 139. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-trend.js\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":"widgets/_src/cai-trend.js"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"b6859638bbd3a9c56b71dd337963285f54f141eeb422a1d0e0427cec35eb2fcd"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-trend.js: widgets/cai-trend.js changed 2 times in last 90 days, max cyclomatic complexity 18 in render at line 258. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-trend.js\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":"widgets/cai-trend.js"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"c4b2f6c2f3832caff8bc94929cf213ada07cab62eae766fbb4a7737f342a9868"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/_src/cai-language-board.js: widgets/_src/cai-language-board.js changed 2 times in last 90 days, max cyclomatic complexity 16 in render at line 136. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/_src/cai-language-board.js\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":"widgets/_src/cai-language-board.js"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"877745e66a8bfb154c7ae85409aad9976ec7ffba2b8c8f865cb8a83188f30281"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: widgets/cai-language-board.js: widgets/cai-language-board.js changed 2 times in last 90 days, max cyclomatic complexity 16 in render at line 284. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- widgets/cai-language-board.js\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":"widgets/cai-language-board.js"},"region":{"startLine":284}}}],"partialFingerprints":{"codehealthFindingId/v1":"065eb53199e99f07b9a0f552fc1ee0fe60576a84db5ad214ad4a8d88d4ddaa22"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Editor/Components/Panels/LayersPanel.razor: src/Imprint.Editor/Components/Panels/LayersPanel.razor changed 2 times in last 90 days, max cyclomatic complexity 16. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Editor/Components/Panels/LayersPanel.razor\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/Imprint.Editor/Components/Panels/LayersPanel.razor"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3e9e2f63de298b195caef5807a9976c9ac564916d18fe3a5e219abb73c89018e"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: src/Imprint.Authoring/Domain/Pages/NodeContentRules.cs: src/Imprint.Authoring/Domain/Pages/NodeContentRules.cs changed 2 times in last 90 days, max cyclomatic complexity 15 in NodeContentRules.Validate at line 17. 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-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Domain/Pages/NodeContentRules.cs\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/Imprint.Authoring/Domain/Pages/NodeContentRules.cs"},"region":{"startLine":17}}}],"partialFingerprints":{"codehealthFindingId/v1":"9dd24f4daab0d29a379f9d04eb25a60203db965efc0de649c40437589a9e56c3"}},{"ruleId":"D15","level":"warning","message":{"text":"Repeated repair: src/Imprint.Editor/Components/Pages/PostEditor.razor: src/Imprint.Editor/Components/Pages/PostEditor.razor changed 9 times in last 90 days and 5 of those changes were fix/bug commits, so repair is the majority of this file\u0027s churn. Its max cyclomatic complexity is 10, UNDER the 15 threshold, so this is deliberately not filed as a churn \u00D7 complexity hotspot \u2014 the difficulty here is in the behaviour the file has to get right, not in its control flow, and refactoring it for complexity would be the wrong move. The repairs counted were: \u201Cfix(posts): opening a post is not editing it, and a reviewer may open theirs\u201D; \u201Cfix(posts): a preview link that resolves, and panes you can resize\u201D; \u201Cfix(posts): the preview could not be scrolled, because the scroller was inert\u201D; \u201Cfix(posts): tags you can see, and an upload that is never unfiled\u201D. Each one is a case this code did not handle. Before the next change lands here, check that every one of them is pinned by a test that fails without its fix; where the same area keeps coming back, the durable fix is usually at the interface that keeps being misused rather than at the line that was last corrected. Counted over 2026-06-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Editor/Components/Pages/PostEditor.razor\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/Imprint.Editor/Components/Pages/PostEditor.razor"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"9232afd8ec6cdf75bdf87ba74b9003e95f87e879de8af40d084d52c2e2566b90"}},{"ruleId":"D15","level":"warning","message":{"text":"Repeated repair: src/Imprint.Authoring/Syndication/SyndicatedPath.cs: src/Imprint.Authoring/Syndication/SyndicatedPath.cs changed 4 times in last 90 days and 3 of those changes were fix/bug commits, so repair is the majority of this file\u0027s churn. Its max cyclomatic complexity is 6 (its worst body is SyndicatedPath.Sanitize at line 33), UNDER the 15 threshold, so this is deliberately not filed as a churn \u00D7 complexity hotspot \u2014 the difficulty here is in the behaviour the file has to get right, not in its control flow, and refactoring it for complexity would be the wrong move. The repairs counted were: \u201Cfix(syndication): the rejection message states the depth actually enforced\u201D; \u201Cfix(syndication): a nested namespace needs room to be a path\u201D; \u201Cfix(syndication): a locale can only shadow the FIRST segment of a path\u201D. Each one is a case this code did not handle. Before the next change lands here, check that every one of them is pinned by a test that fails without its fix; where the same area keeps coming back, the durable fix is usually at the interface that keeps being misused rather than at the line that was last corrected. Counted over 2026-06-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Authoring/Syndication/SyndicatedPath.cs\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/Imprint.Authoring/Syndication/SyndicatedPath.cs"},"region":{"startLine":33}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c4a38b3d7d53b58a82df0bca316e64907e0e35d5e4feb09c5ac0860dda19dbd"}},{"ruleId":"D15","level":"warning","message":{"text":"Repeated repair: src/Imprint.Media/SvgSanitizer.cs: src/Imprint.Media/SvgSanitizer.cs changed 4 times in last 90 days and 3 of those changes were fix/bug commits, so repair is the majority of this file\u0027s churn. Its max cyclomatic complexity is 11 (its worst body is SvgSanitizer.SanitizeElement at line 130), UNDER the 15 threshold, so this is deliberately not filed as a churn \u00D7 complexity hotspot \u2014 the difficulty here is in the behaviour the file has to get right, not in its control flow, and refactoring it for complexity would be the wrong move. The repairs counted were: \u201Cfix(security): close SVG integration-point XSS \u002B block-override XSS; harden undo/dup/staleness\u201D; \u201Cfix(security): validate node content at every entry point \u002B SVG case-insensitivity\u201D; \u201Cfix(security): harden SVG sanitization, publish guard, media serving, color validation\u201D. Each one is a case this code did not handle. Before the next change lands here, check that every one of them is pinned by a test that fails without its fix; where the same area keeps coming back, the durable fix is usually at the interface that keeps being misused rather than at the line that was last corrected. Counted over 2026-06-07..2026-09-05, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-06-07 08:50:05 \u002B02:00\u0027 --until=\u00272026-09-05 08:50:05 \u002B02:00\u0027 --full-history --no-merges -- src/Imprint.Media/SvgSanitizer.cs\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/Imprint.Media/SvgSanitizer.cs"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"ac655e43eed75f77edc9abdd3178c5e74259d3b952925478c4a7ada6926f236c"}},{"ruleId":"D17","level":"error","message":{"text":"WriteOnlyPrivateField: private DarkSvgSanitized DarkSvg \u2014 assigned 1 time(s), read never \u2014 this field is written and never read anywhere its type can be reached from, so the state it keeps answers no question: every assignment to it computes a value that nothing observes, on every instance, for the lifetime of each one. It reads as a flag the code branches on, and nothing branches on it. Delete the field and its assignments \u2014 or, if the value was MEANT to be consulted, the missing read is the defect this row is pointing at, and the branch that should have depended on it is not there."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tests/Imprint.Authoring.Tests/Domain/Assets/AssetDarkVariantTests.cs"},"region":{"startLine":47}}}],"partialFingerprints":{"codehealthFindingId/v1":"b9e5b9c3a06c11774d18deea94c199e5c05064aaa097da444a6431548c61b3c2"}},{"ruleId":"D17","level":"error","message":{"text":"WriteOnlyPrivateField: private JsonSerializerOptions Json \u2014 assigned 1 time(s), read never \u2014 this field is written and never read anywhere its type can be reached from, so the state it keeps answers no question: every assignment to it computes a value that nothing observes, on every instance, for the lifetime of each one. It reads as a flag the code branches on, and nothing branches on it. Delete the field and its assignments \u2014 or, if the value was MEANT to be consulted, the missing read is the defect this row is pointing at, and the branch that should have depended on it is not there."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"tools/ContentSeeder/CmsModel.cs"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"edc9d718d8c137a8b4e0f18ac800c44a1e74b71e0475f8686a534f03cfc4fdca"}},{"ruleId":"D17","level":"error","message":{"text":"AnalyzerSeverityNone: XUNIT1051 \u2014 this rule is switched off for every file the section matches, in every project under this directory, and the only record that it was ever switched off is this line: nothing at the sites it would have reported says so, so a reader of that code has no reason to look here, and code added years from now inherits the decision silently. Fix what the rule reports and delete the entry, or \u2014 where some sites really are legitimate \u2014 leave the rule on and suppress it at those sites with their reasons, so it keeps protecting the rest of the tree. If the rule is genuinely unwanted here, say why in a comment above the entry: a comment that only repeats the rule\u0027s own title is read as no explanation at all and leaves this row in place."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":".editorconfig"},"region":{"startLine":24}}}],"partialFingerprints":{"codehealthFindingId/v1":"fc34c9169936bfd57f9239e0d6a432a067791f2cbb4b006cb87005780fcb66ac"}},{"ruleId":"D17","level":"warning","message":{"text":"Dead code: AssetUi: NamedType AssetUi \u2014 no references found in solution."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Components/Panels/Assets/AssetUi.cs"},"region":{"startLine":6}}}],"partialFingerprints":{"codehealthFindingId/v1":"bb719a58a697da7991d1e680844bdcf4cc8c4a901742354e9a4b1044e6b4c565"}},{"ruleId":"D21","level":"note","message":{"text":"The parameter name \u0027Node Copy\u0027 contains a space, which is non-standard for C# identifiers and likely a typo or copy-paste artifact. It refers to the same concept as the type \u0027Node\u0027 or a copy of it.: Rename parameter to \u0027nodeCopy\u0027 or \u0027sourceNode\u0027 to follow standard camelCase naming conventions and remove the space. (symbols: Imprint.Authoring.Domain.Pages.Node Copy, Imprint.Authoring.Domain.Pages.Node)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"53da07defdc10f3d2a2e3c07e4fe594eb0c3fe724523cd0b5b4a3b784c87f153"}},{"ruleId":"D23","level":"note","message":{"text":"Bounded contexts not declared: At 25200 LoC across 15 projects the codebase is large and multi-module, so explicit bounded contexts are needed. Name this codebase\u0027s bounded contexts (\u22652 module groups, e.g. per subsystem) so cross-boundary type coupling can be assessed. Declare them in \u0060.codehealth/config.yaml\u0060 at the repository root (create it if absent), mapping each context name to the module-path or namespace prefixes that belong to it \u2014 e.g. \u0060architecture:\u0060 \u2192 \u0060contexts:\u0060 \u2192 \u0060Billing: [\u0022src/billing\u0022, \u0022Acme.Billing\u0022]\u0060, \u0060Catalog: [\u0022src/catalog\u0022, \u0022Acme.Catalog\u0022]\u0060."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"1c7e276c9c682731f01819ed5378b90ca320cde1b583c90920172911598362b3"}},{"ruleId":"D26","level":"note","message":{"text":"Split Imprint.Authoring: A generic Authoring project whose namespaces are all domain pages/events, sites/events, assets/events, and posts/events under one cohesive authoring domain. Suggested: "},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"690b0dcfa2c2da9117ae40385a38096ab1332eb2b81aee76ddbd34a39c898747"}},{"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":"b9219ef80d370f8d25d754980e9dccc506bfd15b5d8013e0028b22c9d32e1a48"},"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":"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":"cfca8edbaafc900c59b88d725683b9dc6b4e7828e94be6a3695d1bd18f561936"},"taxa":[{"id":"CWE-79","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":"890c810d60fb978385db41f98daae00bfc5f36a3816c573f2f89eac2f8d733f2"},"taxa":[{"id":"CWE-79","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":"8e4a9a3813f74c65a68c36c407cbb0f4a0c5dc9153e1dd23eef62861e5762d8b"},"taxa":[{"id":"CWE-79","toolComponent":{"name":"CWE","guid":"c3a2b1d0-7f3e-4b2a-9c1d-5e6f7a8b9c0d"}}]},{"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":"1b213f6eedd4b140d0bc37bdf1496f72811a643f34064f12518b32e9e83bcfc7"}},{"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":"0e17f71490e4d120a48b2b2881ab866c93b272bef2febb673a3e8e42b2c288ab"}},{"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":"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":"9658270ba49f37ed04e99ab1263b6393cd42aed8bdfb7aafd9fa1070f5491895"}},{"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":"ace515990e7ee0f17b5c17e44dd168a5bdecf90804a3a3dd845cf05540978013"}},{"ruleId":"D39","level":"note","message":{"text":"IL efficiency: 17 authored method(s) exceed the IL budget: 17 of 2252 first-party methods compile to oversized IL bodies (\u003E 250 instructions); worst: Imprint.Editor.Api.AuthoringNodeJson.ApplyProps @ src/Imprint.Editor/Api/AuthoringNodeJson.cs:386, 498 IL instructions; that pulled this dimension to 9.8/10. These bodies are far past the JIT\u0027s inline budget, so splitting them does not make them inlinable \u2014 what moves the number is emitting less: collapsing LINQ chains and closures on hot paths, and interpolation built eagerly where it is only sometimes used."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Api/AuthoringNodeJson.cs"},"region":{"startLine":386}}}],"partialFingerprints":{"codehealthFindingId/v1":"18c4ee2545f2965e02e1fc2e7e9999a180a37001bd01822827ce4ec749c6fbd0"}},{"ruleId":"AC1","level":"warning","message":{"text":"\u003Cvideo\u003E without a captions track: Video with no captions \u003Ctrack\u003E offers no captions. This player\u0027s source is set at runtime, so there is no caption file to author here: give the player a way to carry captions \u2014 accept a track/captions URL alongside the media and render a \u003Ctrack kind=\u0022captions\u0022\u003E when one is supplied \u2014 and capture that asset wherever the media enters the product (upload, import or generation)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Rendering/Views/VideoView.razor"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"6473c66bc99053545bb73da7760e191fd61257bd834b8d700297e19b3e7039ee"}},{"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/Imprint.Editor/Components/Editor/InsertPicker.razor"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"fc19af05d61ab01cc245fc6c158fbf8301fcfe1334e8e235f547e23c289ad7b1"}},{"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/Imprint.Editor/Components/Editor/NodeToolbar.razor"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"9990516fe3ff28cab225b8a1c65a8739cdca42d558dab20496c9393dea287e4c"}},{"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/Imprint.Editor/Components/Pages/AdminWidgets.razor"},"region":{"startLine":86}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f591ee6a66f2148844c151f4b540b87d1c30ae0b7251ffd013260cfeced8c27"}},{"ruleId":"AC2","level":"error","message":{"text":"\u003Ctextarea\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/Imprint.Editor/Components/Pages/PostEditor.razor"},"region":{"startLine":146}}}],"partialFingerprints":{"codehealthFindingId/v1":"2a2381490da9f8a47b8e794b012ed6d583032372a4862993b11a7fa2e771cb40"}},{"ruleId":"AC4","level":"error","message":{"text":"Click handler on a non-interactive \u003Cdiv\u003E: A click handler on a plain element isn\u0027t keyboard-operable. Use a \u003Cbutton\u003E, or add role \u002B tabindex=\u00220\u0022 \u002B a key handler."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Components/Editor/Canvas.razor"},"region":{"startLine":21}}}],"partialFingerprints":{"codehealthFindingId/v1":"7030cf7bbccf63f827fe7537de1bd8fe6ed21f4979cb86fec8a42483e3bcf419"}},{"ruleId":"AC4","level":"error","message":{"text":"Clickable element isn\u0027t keyboard-operable: The repo\u0027s own CSS styles .locale-row with \u0060cursor: pointer\u0060, so this \u003Cli\u003E is a control \u2014 but it has no role, no tabindex=\u00220\u0022 and no key handler, so it can only be reached with a mouse. Use a \u003Cbutton\u003E, or add role \u002B tabindex=\u00220\u0022 \u002B a key handler."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Editor/Components/Panels/Pages/LocaleManager.razor"},"region":{"startLine":20}}}],"partialFingerprints":{"codehealthFindingId/v1":"c457c8b311db80d9a8ace333f0a3867132400dc8766d2f6dfb8237fbb083f8f3"}},{"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."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d46019b86eff5ddad9db289e6802ac158899e980df54c34f67722442787ead62"}},{"ruleId":"AX2","level":"warning","message":{"text":"Stateful singleton: PublisherStatus: \u0060PublisherStatus\u0060 is a singleton (one shared instance) but mutates instance state outside any lock (Last; e.g. \u0060Last\u0060 at line 17)."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Publishing/PublisherStatus.cs"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"677a496d4050561176c056d06a95ca24a4d66cc6bdf87b22457dc0e002f0eb86"}},{"ruleId":"DM10","level":"warning","message":{"text":"One operation mutates 2 aggregates: DefineBlockFromNodeHandler.Handle: \u0060DefineBlockFromNodeHandler.Handle\u0060 saves \u0060BlockDefinition\u0060, \u0060Page\u0060 in a single operation. Each is its own consistency boundary, so committing them together makes the second\u0027s invariants depend on the first\u0027s transaction, holds a lock across both for the whole operation, and means the pair can no longer be separated \u2014 into different services, or different databases. Mutate one aggregate here and let the others follow from a domain event."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Blocks/DefineBlockFromNode/DefineBlockFromNodeHandler.cs"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"5a5ece37876d339548910bb709d99b76c973a0e2090d5a8753f2729f83bb8105"}},{"ruleId":"DM10","level":"warning","message":{"text":"One operation mutates 2 aggregates: UpdateBlockFromInstanceHandler.Handle: \u0060UpdateBlockFromInstanceHandler.Handle\u0060 saves \u0060BlockDefinition\u0060, \u0060Page\u0060 in a single operation. Each is its own consistency boundary, so committing them together makes the second\u0027s invariants depend on the first\u0027s transaction, holds a lock across both for the whole operation, and means the pair can no longer be separated \u2014 into different services, or different databases. Mutate one aggregate here and let the others follow from a domain event."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Blocks/UpdateBlockFromInstance/UpdateBlockFromInstanceHandler.cs"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"26cebe137f9b3671a5ada8d90d79d73001a3cfdf8c2cf2ee74706e43c75a4da7"}},{"ruleId":"DM10","level":"warning","message":{"text":"One operation mutates 2 aggregates: CreateSiteFromTemplateHandler.Handle: \u0060CreateSiteFromTemplateHandler.Handle\u0060 saves \u0060Site\u0060, \u0060Page\u0060 in a single operation. Each is its own consistency boundary, so committing them together makes the second\u0027s invariants depend on the first\u0027s transaction, holds a lock across both for the whole operation, and means the pair can no longer be separated \u2014 into different services, or different databases. Mutate one aggregate here and let the others follow from a domain event."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Sites/CreateSiteFromTemplate/CreateSiteFromTemplateHandler.cs"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"c45b24b73dceebd38936dfb913d575e8d8b57d2641112e4837c1079cbd3bf601"}},{"ruleId":"DM10","level":"warning","message":{"text":"One operation mutates 2 aggregates: SeedLocaleHandler.Handle: \u0060SeedLocaleHandler.Handle\u0060 saves \u0060Site\u0060, \u0060Page\u0060 in a single operation. Each is its own consistency boundary, so committing them together makes the second\u0027s invariants depend on the first\u0027s transaction, holds a lock across both for the whole operation, and means the pair can no longer be separated \u2014 into different services, or different databases. Mutate one aggregate here and let the others follow from a domain event."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Sites/SeedLocale/SeedLocaleHandler.cs"},"region":{"startLine":22}}}],"partialFingerprints":{"codehealthFindingId/v1":"4d7b8c7356f670b10c440a5edb494ece2339bd8165ef56a716652575b010689f"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Asset.OriginalStorageKey: \u0060Asset.OriginalStorageKey\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"915856fd63a88c1661b90dcac9b2e6d7d4549268f279a52d2f46297f8d0026d5"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Asset.DerivedStorageKey: \u0060Asset.DerivedStorageKey\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":34}}}],"partialFingerprints":{"codehealthFindingId/v1":"40f2b2f16c0985901b5b28d314e29f77a2798e034bb855ea90cc888b78f4cf87"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Asset.DarkOriginalStorageKey: \u0060Asset.DarkOriginalStorageKey\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c88242832cdf028ca68063c064b84a7a8a0063c73cf18b81f55e99f79fd22d6"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Asset.DarkDerivedStorageKey: \u0060Asset.DarkDerivedStorageKey\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":46}}}],"partialFingerprints":{"codehealthFindingId/v1":"62e8c14e9245ec5a040ab954686f3f2f72c2a48bee7fe77eb947914e7c048859"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Asset.StreamId: \u0060Asset.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":60}}}],"partialFingerprints":{"codehealthFindingId/v1":"a9b10077e0fe75fe94a255dfc83878e75502a1a6f46122bde2579bfff637acd3"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: BlockDefinition.StreamId: \u0060BlockDefinition.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Blocks/BlockDefinition.cs"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"47cd3a125a86a2f82a24e446b3b921c2449f8b7f54cc06ea01413d4536522854"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Page.StreamId: \u0060Page.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"15f1549d4a28345d3b8212920df7b5d1cfb8090d85c54d0b022e60a9f8b72889"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Post.StreamId: \u0060Post.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Posts/Post.cs"},"region":{"startLine":68}}}],"partialFingerprints":{"codehealthFindingId/v1":"0897462ff1bcec403db8df1db73a4c4cf878c7a67886b3012220706958d80b84"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: Site.StreamId: \u0060Site.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Sites/Site.cs"},"region":{"startLine":113}}}],"partialFingerprints":{"codehealthFindingId/v1":"2f3f2136c9473d92f7fb69142b6470e46808061439f6cbb01d581f175f692dc7"}},{"ruleId":"DM2","level":"note","message":{"text":"Primitive id on a domain type: WidgetSubmission.StreamId: \u0060WidgetSubmission.StreamId\u0060 is a raw \u0060String\u0060 \u2014 give it a strongly-typed id: a dedicated single-field type wrapping the \u0060String\u0060, in whatever form your language spells that."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Widgets/WidgetSubmission.cs"},"region":{"startLine":38}}}],"partialFingerprints":{"codehealthFindingId/v1":"41e0fd4a3dfeedb4ee8899ef770ea99924af7efbc9cc51e04a46d60103216965"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: Asset: \u0060Asset\u0060 is an aggregate/entity with 20 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Assets/Asset.cs"},"region":{"startLine":12}}}],"partialFingerprints":{"codehealthFindingId/v1":"db7ae4c43bc778a8dc6c1ca8073e328b81aa590529657a65705d6e87e797b2eb"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: BlockDefinition: \u0060BlockDefinition\u0060 is an aggregate/entity with 5 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Blocks/BlockDefinition.cs"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"6f63fd4be62fa68212ba430f980061188250ae8d40bb9da6bcd7ffc28dae4ab6"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: Page: \u0060Page\u0060 is an aggregate/entity with 11 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Pages/Page.cs"},"region":{"startLine":11}}}],"partialFingerprints":{"codehealthFindingId/v1":"9a38bf62bd2a27884ca8b59cf99ab891fb1ae0bef59bf6679c0c963db71408b1"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: Post: \u0060Post\u0060 is an aggregate/entity with 15 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Posts/Post.cs"},"region":{"startLine":25}}}],"partialFingerprints":{"codehealthFindingId/v1":"16815e2417c4914cc8e470ea0aff27490929e3077741f88163c2b4ffe3691372"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: Site: \u0060Site\u0060 is an aggregate/entity with 23 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Sites/Site.cs"},"region":{"startLine":13}}}],"partialFingerprints":{"codehealthFindingId/v1":"82774366dda2d451de43cb89fbb6b2eca5fa715fbfff63abe6b5cf567cdbd4cc"}},{"ruleId":"DM4","level":"warning","message":{"text":"Anemic entity: WidgetSubmission: \u0060WidgetSubmission\u0060 is an aggregate/entity with 16 data propert(ies) but no state-changing behaviour (only data and queries) \u2014 the business logic lives in a service."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Domain/Widgets/WidgetSubmission.cs"},"region":{"startLine":15}}}],"partialFingerprints":{"codehealthFindingId/v1":"4c9a3bec790b67c88898c406dcc5e303097eeb40a6682a55b621bdc1dd3c4a7e"}},{"ruleId":"ED5","level":"warning","message":{"text":"Non-idempotent mutation: PublishPost.PublishPostHandler.Handle: \u0060PublishPost.PublishPostHandler.Handle\u0060 mutates persistent state (an event publish) with no idempotency guard, and the model confirms a re-run would double-apply it. A retry or at-least-once redelivery means it can run twice \u2014 add an exists/dedup check, an upsert, an idempotency-key/inbox, or a versioned write."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Authoring/Features/Posts/PublishPost/PublishPostHandler.cs"},"region":{"startLine":14}}}],"partialFingerprints":{"codehealthFindingId/v1":"55a1ceb990e38a83e126770f3b13ee2aab844675a3c726680f2660e414940c29"}},{"ruleId":"M2","level":"note","message":{"text":"No ADRs: No Architecture Decision Records found \u2014 no conventional ADR directory, no numbered \u0060NNNN-title\u0060 documents in any markup this check reads, and nothing ADR-shaped by content. Design rationale recorded elsewhere (a design-notes tree, a mailing list, pull-request discussion) is not visible to this check and is not re-findable per decision, so a future maintainer cannot ask why one choice was made and get an answer."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"670b3d6e36a756d63097d0dfbf90afd5fc761308800b9354894a07c3f4e4aa14"}},{"ruleId":"M4","level":"note","message":{"text":"README/code drift: README advertises Docker containerisation, but no Dockerfile/compose file exists"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"343bbbd51ceb8de7a9ff88d79f7c797abf9b5921f8727b67b4d0f4f8a22c5e49"}},{"ruleId":"P2","level":"note","message":{"text":"Logging is not universal: Only 6/7 service-like projects use logging (pure contract/DTO projects are excluded \u2014 they have nothing to log). Of those 7, 3 ship a process this repository operates; the rest are libraries their consumer hosts, where the logging decision belongs to the host."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"91a94e21d6d4d0e6a2003f94505b0b02b157176f0b24c4820f3f82b4447a97fe"}},{"ruleId":"PF1","level":"note","message":{"text":"No performance benchmarks: No benchmark suite was found. Where code is performance-sensitive, a benchmark guards against silent regressions \u2014 but it\u0027s a bonus here, not a deduction."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"fd90d18ee3bb127e8033d41e8efe4e131487a6d794a5730a72c56105ef7485ea"}},{"ruleId":"R1","level":"warning","message":{"text":"Type Safety: 0 typed \u00B7 47 plain JS \u2014 the untyped files are tools/mobile-sweep.js, widgets/_src/cai-band-scale.js, widgets/_src/cai-c4-heat.js, widgets/_src/cai-calculator.js, widgets/_src/cai-card-gallery.js, widgets/_src/cai-composition-bar.js (\u002B41 more)."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d00ee7953f55325a823d27e5db9657c80ca9b9861c0c0abf8fe487cd3fa586d3"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (44 lines \u00D7 2 locations): widgets/_src/cai-calculator.js:133 \u00B7 widgets/_src/cai-verifier.js:80 \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":"widgets/_src/cai-calculator.js"},"region":{"startLine":133}}}],"partialFingerprints":{"codehealthFindingId/v1":"bd5c03855e78a9ce5c42021fb1d8c50134426959f683e4f81dfa98c42ff390e2"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (11 matched lines \u00D7 2 locations): widgets/_src/cai-band-scale.js:41 \u00B7 widgets/_src/cai-composition-bar.js:71 \u2014 the two spans are one implementation copied and then locally edited \u2014 52 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":"widgets/_src/cai-band-scale.js"},"region":{"startLine":41}}}],"partialFingerprints":{"codehealthFindingId/v1":"23e10861231c69ba6b8b552c0fbf6ebc778764d80e9f924d1014b9f805a6c8c2"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (11 lines \u00D7 2 locations): widgets/_src/cai-language-board.js:221 \u00B7 widgets/_src/cai-survey-list.js:206 \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":"widgets/_src/cai-language-board.js"},"region":{"startLine":221}}}],"partialFingerprints":{"codehealthFindingId/v1":"c15b00aa4826fa3443d995bf6f94d600d955e7d46f4be94d192b7f11f89d09a7"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (11 matched lines \u00D7 2 locations): widgets/_src/cai-survey-list.js:90 \u00B7 widgets/_src/cai-trend.js:137 \u2014 the two spans are one implementation copied and then locally edited \u2014 52 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":"widgets/_src/cai-survey-list.js"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6aa643feab2ee2847f9a6d8ba878dec53e8349ab42a30ff446e7632e460509b"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (10 matched lines \u00D7 2 locations): widgets/_src/cai-calculator.js:98 \u00B7 widgets/_src/cai-report-index.js:75 \u2014 the two spans are one implementation copied and then locally edited \u2014 52 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":"widgets/_src/cai-calculator.js"},"region":{"startLine":98}}}],"partialFingerprints":{"codehealthFindingId/v1":"98e0d963c295526dde9f1bae7c8460acd24858dbe320daefb5938abe6b29f8f0"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (10 lines \u00D7 2 locations): widgets/_src/cai-lens-gauges.js:49 \u00B7 widgets/_src/cai-link-cards.js:78 \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":"widgets/_src/cai-lens-gauges.js"},"region":{"startLine":49}}}],"partialFingerprints":{"codehealthFindingId/v1":"414074ed06f627939900bcabcaae9f33e58ac6cb094f87257ac68ed794fc456b"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block with local edits (10 matched lines \u00D7 2 locations): widgets/_src/cai-report-index.js:75 \u00B7 widgets/_src/cai-verifier.js:51 \u2014 the two spans are one implementation copied and then locally edited \u2014 52 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":"widgets/_src/cai-report-index.js"},"region":{"startLine":75}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec7b754d4f39e94aa63f718849e1aed4b81ef57d4bc2b73526ed08c0b88e6799"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2 locations): widgets/_src/cai-c4-heat.js:165 \u00B7 widgets/_src/cai-findings.js:172 \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":"widgets/_src/cai-c4-heat.js"},"region":{"startLine":165}}}],"partialFingerprints":{"codehealthFindingId/v1":"7bebc361ddc763f07945181e7f4d9d63ed09c32c4bff904deabc2c3eb384466b"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (8 lines \u00D7 2 locations): widgets/_src/cai-language-board.js:197 \u00B7 widgets/_src/cai-trend.js:238 \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":"widgets/_src/cai-language-board.js"},"region":{"startLine":197}}}],"partialFingerprints":{"codehealthFindingId/v1":"3ee0247b293e98ef7b240d2fedb1e6bfa209666ee2ce45f87b14c27e8ad04884"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (7 lines \u00D7 2 locations): widgets/_src/cai-evidence-flow.js:44 \u00B7 widgets/_src/cai-lens-gauges.js:42 \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":"widgets/_src/cai-evidence-flow.js"},"region":{"startLine":44}}}],"partialFingerprints":{"codehealthFindingId/v1":"402e7dd4e58d868d240a080a3e4b24b0540f0b6adab1fb0dd07876c7dcd538ba"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (6 lines \u00D7 2 locations): widgets/_src/cai-report-index.js:172 \u00B7 widgets/cai-report-index.js:145 \u2014 the 2 copies are spread across 2 directories, so the shared home is a decision rather than an obvious spot: check first whether one of them already owns this behaviour, and otherwise put the extracted module somewhere all of the sites already reach rather than making one of them depend on another."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-report-index.js"},"region":{"startLine":172}}}],"partialFingerprints":{"codehealthFindingId/v1":"0c8e3c322da45c09767d2c8cdc9a639b265dddef0c9b7212538e02c7c461524a"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2 locations): widgets/_src/cai-calculator.js:190 \u00B7 widgets/cai-calculator.js:206 \u2014 the 2 copies are spread across 2 directories, so the shared home is a decision rather than an obvious spot: check first whether one of them already owns this behaviour, and otherwise put the extracted module somewhere all of the sites already reach rather than making one of them depend on another."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-calculator.js"},"region":{"startLine":190}}}],"partialFingerprints":{"codehealthFindingId/v1":"f0e03cc62b5cdd233680b96539c9e9eced09f2dafecae279464e7cf3391363cc"}},{"ruleId":"R10","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2 locations): widgets/_src/cai-dimensions.js:137 \u00B7 widgets/_src/live.js:245 \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":"widgets/_src/cai-dimensions.js"},"region":{"startLine":137}}}],"partialFingerprints":{"codehealthFindingId/v1":"be0fe2651e703eda1fa53e1f78337b48d4d166f4bb0b014f202540e6d9fb2326"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 35, cognitive 48): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-dimensions.js"},"region":{"startLine":192}}}],"partialFingerprints":{"codehealthFindingId/v1":"06daed51abb089c1e56e93cdf88eb0ec7c9296c17bf475a566ef3f4123547c7b"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 35, cognitive 43): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-dimensions.js"},"region":{"startLine":173}}}],"partialFingerprints":{"codehealthFindingId/v1":"6efea0097bbdc467dbb97a5caf4f94b23866dbb3710707915cb4f2a7a1d71d1d"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function scoreCardBodyHtml (cyclomatic 26, cognitive 38): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/scorecard.js"},"region":{"startLine":130}}}],"partialFingerprints":{"codehealthFindingId/v1":"2be26c4080cac14d804607631e4ff94215813a1300ea0cc214605f28c6831516"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function z (cyclomatic 26, cognitive 35): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-card-gallery.js"},"region":{"startLine":122}}}],"partialFingerprints":{"codehealthFindingId/v1":"862e6e96cc558d13a328f00c2e7e09408e593c3e4a438dcfccaec93d5f8e00a2"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function H (cyclomatic 26, cognitive 35): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-score-card.js"},"region":{"startLine":117}}}],"partialFingerprints":{"codehealthFindingId/v1":"d9434028183654100a137ebb035ffa5a7376c3897c71fc16dd986efc732df31a"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function #repoHtml (cyclomatic 20, cognitive 20): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-findings.js"},"region":{"startLine":107}}}],"partialFingerprints":{"codehealthFindingId/v1":"858599245fb292a1b6cd16371c7756515aee5e65824a8497a7874f85239c15a3"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function #r (cyclomatic 20, cognitive 18): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-findings.js"},"region":{"startLine":143}}}],"partialFingerprints":{"codehealthFindingId/v1":"922fad5e0cccc96ef6e840f88f9a2e12f66e99c653cd9b2d87db6d5fbee7662b"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 19, cognitive 21): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-score-card.js"},"region":{"startLine":72}}}],"partialFingerprints":{"codehealthFindingId/v1":"8cf6f485d1f632e31465d4f15a07ddbf5c237ff743664948e353fcc750e1707c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 19, cognitive 14): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-score-card.js"},"region":{"startLine":221}}}],"partialFingerprints":{"codehealthFindingId/v1":"017aef4acab67cd70534cc5fbe7dffaa515cf289b3cf0cf5cf3d7c287c01d856"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 18, cognitive 20): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-trend.js"},"region":{"startLine":139}}}],"partialFingerprints":{"codehealthFindingId/v1":"b60615462ab208e685391d085b5f7a8be49af54c41bd32c50a3c815c501c177d"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 18, cognitive 18): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-trend.js"},"region":{"startLine":258}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0c15a6b5b48045eb7fffb0933bb2fa442f46b9363a853ad878faed33e9719b6"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function cardFromGallery (cyclomatic 18, cognitive 16): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/live.js"},"region":{"startLine":64}}}],"partialFingerprints":{"codehealthFindingId/v1":"ec75cb5a45bcbe08cea3c75be9cdfc68ba9db909ac2bcead9929eef4b3b8bc2c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function U (cyclomatic 18, cognitive 15): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-card-gallery.js"},"region":{"startLine":223}}}],"partialFingerprints":{"codehealthFindingId/v1":"d77558d37e3b16fcd212d960d4f7dc141bab26af0545234a3b80163e3e60e876"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function z (cyclomatic 18, cognitive 15): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-score-card.js"},"region":{"startLine":218}}}],"partialFingerprints":{"codehealthFindingId/v1":"5db52daa44d947aad1cb4df5bb6cac7a20289e5f338b462616d02f606c602686"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 17, cognitive 18): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-survey-list.js"},"region":{"startLine":92}}}],"partialFingerprints":{"codehealthFindingId/v1":"9020e889c7ca354556979fae21bad58ecb9faaf14aec9e5a28eda80d81a26c5e"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 17, cognitive 18): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-survey-list.js"},"region":{"startLine":268}}}],"partialFingerprints":{"codehealthFindingId/v1":"980a6bbada8073338ec148b5cd6539f6e4fb5c13b9a97d77a7b4197547045258"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 16, cognitive 20): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-language-support.js"},"region":{"startLine":148}}}],"partialFingerprints":{"codehealthFindingId/v1":"cf122b47d851305c3750fd573ced5fcf7b126cff5b18bd3364929dc2bf15279c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function paint (cyclomatic 16, cognitive 20): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-survey-list.js"},"region":{"startLine":182}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6595ca785c4f08dd030e220def5013780bbdbab4ec38f43c1ab1049ec54503c"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 16, cognitive 19): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-language-board.js"},"region":{"startLine":136}}}],"partialFingerprints":{"codehealthFindingId/v1":"e587f89afcb5f244e306ebedaa1e893e1e229743b76b1fa6d4fc8dca3199ce5e"}},{"ruleId":"R2","level":"warning","message":{"text":"Complex function render (cyclomatic 16, cognitive 16): Branch-heavy code is where defects cluster \u2014 extract decisions into smaller functions."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-language-support.js"},"region":{"startLine":158}}}],"partialFingerprints":{"codehealthFindingId/v1":"c87d90eb414c7053a8feb6db4b81e210fc88bdb596b724ca712983d0504b20f3"}},{"ruleId":"R4","level":"warning","message":{"text":"Test Coverage: 0% of 47 production file(s) reachable from 0 test file(s) via the import graph"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"64e0e3511eb969fb4720b196e7d3799e1714077217351c3c56a27b50e3e21220"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~338 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), but 7 in-repo import(s) from 7 other file(s) do name it (widgets/_src/cai-band-scale.js, widgets/_src/cai-card-gallery.js, widgets/_src/cai-language-board.js and 4 more) \u2014 every one of those referrers is itself unreachable, so this file is dead only as a member of that cluster: if any referrer is in fact alive, this row falls with it"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/scorecard.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ff9528e1219eae5faba7a220e2a42e4ca9134ca2e43a6f38f8ff34df13eed52"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~325 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-language-board.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b82f67bade8bf8815e34b50f8661371f51b116458a6b33757d7c5718b1235f78"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~322 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-dimensions.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d26de7a9d301b6102a68f22737099290809c5aac64939a09dce13ce5bd3c8b56"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~299 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), but 9 in-repo import(s) from 9 other file(s) do name it (widgets/_src/cai-band-scale.js, widgets/_src/cai-c4-heat.js, widgets/_src/cai-card-gallery.js and 6 more) \u2014 every one of those referrers is itself unreachable, so this file is dead only as a member of that cluster: if any referrer is in fact alive, this row falls with it"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/live.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e58843a0f75e0e25fa0c92af6f70b4a274bf24cc968520439a9194dea0ffcbd1"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~284 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-language-board.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"f04fc6e37e7983b172b691f420f91cfa3ddba18cab064f997f748b689edfd0d1"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~275 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-trend.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"99e0a00802526f04b7afd1305cb42ba9600f6becfdd7f6d3d858bf2611d3c65d"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~268 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-survey-list.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"27f98e91e7c532f811a3bb60093f943d2ba077ddd2c3d7cce218861f5c724f23"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~263 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), but 20 in-repo import(s) from 20 other file(s) do name it (widgets/_src/cai-band-scale.js, widgets/_src/cai-c4-heat.js, widgets/_src/cai-calculator.js and 17 more) \u2014 every one of those referrers is itself unreachable, so this file is dead only as a member of that cluster: if any referrer is in fact alive, this row falls with it"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/tokens.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a17ad5feac7ee60ad98737efa733d690b92ada5778fbf577207f0174445c3a65"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~262 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-survey-list.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e1bdf6d5b62d1ba3c2cb35df1dae6fb57f2c4112eccad3dca4da4dc6b733a968"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~258 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-trend.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"039e979c1120ffd911cc722f47d7a4fddfa456bb45dca5072965e6831c536803"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~238 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-calculator.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"e810d776ac5baf7f79621602f5894a82ae767949983bfe756ea513a6c48bae88"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~236 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-band-scale.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"71a60bd3e07e498b070364eefd8d1c801d5253493d2a85555eb8de9cbf4fab79"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~235 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-lens-gauges.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"55acff9f17998e52230bbefd78b85a3200b5a77cd085c1638c65054873129f47"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~228 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-card-gallery.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3700f1a2d8b8e581e912cd4ca465fe4568362d775625e848b7bd028140d65ae2"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~221 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/contact-form.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"242854a2f786d4c98913de46ecd795d35bc218f98b0cb2781f7a0533386178e8"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~221 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-calculator.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5644613412ed72f6f7d020ce690d142cd5357697af5240a164247fa7a9e4c15b"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~221 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-score-card.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"d58cd4ca834d4748285a3e2dbaec28d06fcfa491113c2e7d49f4d7a8bc91544e"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~202 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-report-index.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"926729d77e5848838f73cde42afd4f0a0c2c02918b18c687e8acb2fff315dd70"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~194 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-language-support.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"69b6d06be335dd6e996d42882b8a1f04c2f0bb337641fc3e0b09226f9564b47d"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~183 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-verifier.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"0fe64300ea894cc6371fa99082ddbcfef9944b71c0ad022b5667610954484f3f"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~182 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-findings.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"2b5368228f8ae20bc994da4a816cf9580efaefea57be8de89cbe80299b85f84a"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~178 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-public-reports.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"3627959b5706c8524f76a6f12d908caec51df51a4ce4bf49124a5f627f79a83f"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~176 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-c4-heat.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"ead02083f133bff0ddf76782b57d3511de2f22d3d4d2ca7345fd98c66db29777"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~173 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-dimensions.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"6105750a1eda8712de002737397d016ef41cc88d26b1322b239085937095d28a"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~169 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-public-reports.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"538fe9c335b5aa557c294cce9e5b1726b0e8f0916771ae47cc055cfbdad39351"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~167 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-verifier.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"1241cb99eebe5cdc24dcf9c2c921cd64ae54dfd7cc4110402761b167c10c5599"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~162 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/wd-embed.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"50b2298dbcf76498893635c5f739319ca26621b349379b7a05728869e6b6c142"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~158 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-language-support.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b0113b0f3174d9c8dd21351b7212dcfbd5b0de0ccddf66e633180f6d0c74376f"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~158 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/contact-form.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"28d74ec71a3b3aad41aa874af5a722b87fb05b77df6cdb33a99e41325e8e62c1"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~152 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-report-index.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"13a790a28e987d4cf6d01d1ddb99c43fe23e65eadbc1411dadc0c62ebfb9572d"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~147 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-link-cards.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"005fc67c4ae96f96768c2fed3038718b895b3c3ad2284c7ce8938edc3c22be09"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~144 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-evidence-flow.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"a542275746d072e2c162803de9502eb68c8d559e8ac3f7effffeb5fb98f978d1"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~143 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-findings.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"84130e8038b5defdede6d990a706c044f9d33ba8d39fab015f76c32477aff6fb"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~140 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/x-theme-toggle.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"82aefc923e1689fe890f16455ae3451e6d8f77b5d6cf5e0c2a78e9c7980d8dcf"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~136 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-c4-heat.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5976d145aa88c8e50003d3f7c058ac7bbd2afa42475915327c21c9c3e708b0c8"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~130 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-composition-bar.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"fad0d9b21bfc82b5c981aebdf44293d43d83d77d13b64cad7b3abd0072e55040"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~128 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/cai-composition-bar.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"c6791a03dcda5282a2fba9f51aee20490ab2a61b943e04de21fc5df6876b6378"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~112 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-score-card.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"b14e1936fe892ab4a5e3957bb63ebbe64ff8606adc6fcabb755ed0a975b037fd"}},{"ruleId":"R7","level":"warning","message":{"text":"Dead file (~108 LoC): no import path from any entry point (1 application, 1 tooling, 0 test roots considered), and no other file in the scanned tree imports it \u2014 nothing in-repo names this module at all, which is the strongest form of this claim the import graph can make"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"widgets/_src/cai-link-cards.js"},"region":{"startLine":1}}}],"partialFingerprints":{"codehealthFindingId/v1":"5ed381fb06826dad016e5414de4de9ba33619d571e08b52542ad7b219c51991e"}},{"ruleId":"R7","level":"note","message":{"text":"\u2026and 7 more: 7 further occurrence(s) are not listed individually; the score already reflects all 47."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"6ee38e4cbcd70b8755638f54bbadf8e6c6eb3ba09379fce40df557fce089810e"}},{"ruleId":"X18","level":"warning","message":{"text":"Disposable created and abandoned in the method that made it: \u0060pending\u0060 is a \u0060SemaphoreSlim\u0060, which implements \u0060IDisposable\u0060, and it is created here (line 36). Every use of it in \u0060ExecuteAsync\u0060 reads a member through it \u2014 it is never returned, never stored, never handed to anything else, and never disposed \u2014 so this method both creates the value and is the last thing that can release it, and does not. Nothing announces the leak: the object holds its resource until finalization if its type has a finalizer, and until the process ends if it does not, so the cost accumulates once per CALL rather than showing up as a failure. Declare it with \u0060using\u0060 (\u0060using var pending = \u2026;\u0060), which releases it at the end of the scope on every path including a throw."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"src/Imprint.Publishing/PublisherHostedService.cs"},"region":{"startLine":36}}}],"partialFingerprints":{"codehealthFindingId/v1":"a98f29df06c0a24592b2f77d044678993b4b21a88916bf3196a916decbf8299d"}},{"ruleId":"X2","level":"note","message":{"text":"Not all async methods take a CancellationToken: Only 173/205 async methods accept a CancellationToken, so in-flight work can\u0027t be stopped early when the caller gives up \u2014 whatever ends it in your host (shutdown signal, timeout, abandoned request, user cancel). Thread a token through the call chain and honour it at each await and loop; where a method genuinely cannot be interrupted, omitting it is a deliberate choice \u2014 judge against your hosting model."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"bf623a92fb752b336427856888a9b386c434e686662a2cdc1bba21832c0a048c"}},{"ruleId":"X5","level":"note","message":{"text":"Null-forgiving operator (\u0060!\u0060) suppressions reduce the NRT score: ~0.8 \u0060!\u0060 suppressions per 1k syntax nodes \u2014 109 suppression(s) across the 135067 syntax node(s) in code where nullable warnings are ENABLED, which is the only code a \u0060!\u0060 can suppress anything in (a \u0060!\u0060 under \u0060#nullable disable\u0060 is inert and is not counted, and its file\u0027s nodes are not in the denominator). Each one tells the compiler to trust you about null, suppressing the very safety NRTs provide."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"93cfe05d4ad8c8c171267603b23dfe289b74842e38edd1b7bfed59cc32bda337"}}],"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-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-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-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-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-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-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":10,"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."]}]}