{"$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":"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"]},{"target":{"id":"A07:2025","toolComponent":{"name":"OWASP Top 10","guid":"7d1f0c2e-4b6a-4e39-9a51-0b2e8c3d5f61"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"],"owasp":"A07:2025"}},{"id":"D14","name":"License Compliance","shortDescription":{"text":"License Compliance"},"helpUri":"https://codehealth.canine.dev/dimensions/D14"},{"id":"D15","name":"Churn \u00D7 Complexity Hotspots","shortDescription":{"text":"Churn \u00D7 Complexity Hotspots"},"helpUri":"https://codehealth.canine.dev/dimensions/D15"},{"id":"D17","name":"Explicit Debt","shortDescription":{"text":"Explicit Debt"},"helpUri":"https://codehealth.canine.dev/dimensions/D17"},{"id":"D19","name":"Documentation Quality","shortDescription":{"text":"Documentation Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D19"},{"id":"D20","name":"ADR Quality","shortDescription":{"text":"ADR Quality"},"helpUri":"https://codehealth.canine.dev/dimensions/D20"},{"id":"D21","name":"Naming Consistency","shortDescription":{"text":"Naming Consistency"},"helpUri":"https://codehealth.canine.dev/dimensions/D21"},{"id":"D26","name":"Project Cohesion","shortDescription":{"text":"Project Cohesion"},"helpUri":"https://codehealth.canine.dev/dimensions/D26"},{"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"]},{"target":{"id":"A07:2025","toolComponent":{"name":"OWASP Top 10","guid":"7d1f0c2e-4b6a-4e39-9a51-0b2e8c3d5f61"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-798","CWE-259"],"owasp":"A07:2025"}},{"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"]},{"target":{"id":"A05:2025","toolComponent":{"name":"OWASP Top 10","guid":"7d1f0c2e-4b6a-4e39-9a51-0b2e8c3d5f61"}},"kinds":["relevant"]}],"properties":{"cwe":["CWE-79","CWE-89","CWE-78","CWE-94","CWE-77"],"owasp":"A05:2025"}},{"id":"D35","name":"Change Coupling","shortDescription":{"text":"Change Coupling"},"helpUri":"https://codehealth.canine.dev/dimensions/D35"},{"id":"D44","name":"Platform End-of-Life","shortDescription":{"text":"Platform End-of-Life"},"helpUri":"https://codehealth.canine.dev/dimensions/D44"},{"id":"AX10","name":"Code composition","shortDescription":{"text":"Code composition"},"helpUri":"https://codehealth.canine.dev/dimensions/AX10"},{"id":"AX3","name":"Project dependency cycles","shortDescription":{"text":"Project dependency cycles"},"helpUri":"https://codehealth.canine.dev/dimensions/AX3"},{"id":"AX4","name":"Dependency direction","shortDescription":{"text":"Dependency direction"},"helpUri":"https://codehealth.canine.dev/dimensions/AX4"},{"id":"AX5","name":"Architecture \u0026 structure","shortDescription":{"text":"Architecture \u0026 structure"},"helpUri":"https://codehealth.canine.dev/dimensions/AX5"},{"id":"AXB1","name":"Runtime evidence locked \u2014 no reproducible boot","shortDescription":{"text":"Runtime evidence locked \u2014 no reproducible boot"},"helpUri":"https://codehealth.canine.dev/dimensions/AXB1"},{"id":"ED5","name":"Idempotency","shortDescription":{"text":"Idempotency"},"helpUri":"https://codehealth.canine.dev/dimensions/ED5"},{"id":"GD1","name":"Unfinished \u0026 placeholder code","shortDescription":{"text":"Unfinished \u0026 placeholder code"},"helpUri":"https://codehealth.canine.dev/dimensions/GD1"},{"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":"P3","name":"Security \u0026 performance tooling","shortDescription":{"text":"Security \u0026 performance tooling"},"helpUri":"https://codehealth.canine.dev/dimensions/P3"},{"id":"P6","name":"Release Hygiene","shortDescription":{"text":"Release Hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/P6"},{"id":"SC1","name":"Supply-chain hygiene","shortDescription":{"text":"Supply-chain hygiene"},"helpUri":"https://codehealth.canine.dev/dimensions/SC1"},{"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"}]}},"results":[{"ruleId":"D1","level":"warning","message":{"text":"LibraryTools.B4jSearchLibrary (cyclomatic 29): LibraryTools.B4jSearchLibrary has cyclomatic complexity 29 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 2 of the 10 methods over the threshold \u2014 including the worst \u2014 and 24 of the 58 points over it (41%), 2.7\u00D7 the next-largest file (B4jMcp/Tools/BasTools.vb at 9). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":104}}}],"partialFingerprints":{"codehealthFindingId/v1":"f9c12e90a07d6fd60759184eb424a6d4ff8828ce86758f6f4f32af3b38bb8df6"}},{"ruleId":"D1","level":"warning","message":{"text":"LibraryTools.RenderXmlDocs (cyclomatic 25): LibraryTools.RenderXmlDocs has cyclomatic complexity 25 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table. This file is where this pass\u0027s cyclomatic complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 2 of the 10 methods over the threshold \u2014 including the worst \u2014 and 24 of the 58 points over it (41%), 2.7\u00D7 the next-largest file (B4jMcp/Tools/BasTools.vb at 9). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":217}}}],"partialFingerprints":{"codehealthFindingId/v1":"a67d1943f7485632fb8d22aff35e01ddb288665b98068d41b3b6fc1adbdcc064"}},{"ruleId":"D1","level":"warning","message":{"text":"BasTools.B4jCreateModule (cyclomatic 24): BasTools.B4jCreateModule has cyclomatic complexity 24 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BasTools.vb"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"a753cc535b0edb2b7baf3e6d46c45539944a955af3fcb42da9228d0c76e77714"}},{"ruleId":"D1","level":"warning","message":{"text":"BalConverter.WriteMap (cyclomatic 23): BalConverter.WriteMap has cyclomatic complexity 23 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/BalConverter.vb"},"region":{"startLine":352}}}],"partialFingerprints":{"codehealthFindingId/v1":"0189fc5e86ef9a883ccb22521ec7b036a093934431237bd2d8351cb1119f5859"}},{"ruleId":"D1","level":"warning","message":{"text":"B4jParser.Parse (cyclomatic 21): B4jParser.Parse has cyclomatic complexity 21 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/B4jParser.vb"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"2daeb8f8bf476ba776938fb51caf8e7e5eeab364f13e30d065054fa0fbf2fdf2"}},{"ruleId":"D1","level":"warning","message":{"text":"ConfigTools.B4jDoctor (cyclomatic 18): ConfigTools.B4jDoctor has cyclomatic complexity 18 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/ConfigTools.vb"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"186d17598f39e2858fa96d76df48c5008828d80da5c6c5ab1bd0394f843d91df"}},{"ruleId":"D1","level":"warning","message":{"text":"BuildTools.B4jRun (cyclomatic 17): BuildTools.B4jRun has cyclomatic complexity 17 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d717df559f70c6bee15fa84be10fddae6822636157725d595ce6ddd695a786e"}},{"ruleId":"D1","level":"warning","message":{"text":"LayoutTools.B4jAddView (cyclomatic 17): LayoutTools.B4jAddView has cyclomatic complexity 17 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LayoutTools.vb"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"9de8877fcbbc2ac1fa8dac4568afd2091076b60b65e9c65c30bbc2ec7d134bae"}},{"ruleId":"D1","level":"warning","message":{"text":"NavTools.B4jFindSymbol (cyclomatic 17): NavTools.B4jFindSymbol has cyclomatic complexity 17 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/NavTools.vb"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"d8a30c66d4c8e424b3a4615364808bee4df17122fe2fd8d2242acb730aaff7f2"}},{"ruleId":"D1","level":"warning","message":{"text":"ViewTemplates.ValidateView (cyclomatic 17): ViewTemplates.ValidateView has cyclomatic complexity 17 (threshold 15). To reduce it, separate the branches: extract each independent case into its own named function, or replace a long branch ladder over a single value with a data-driven lookup or dispatch table."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/ViewTemplates.vb"},"region":{"startLine":322}}}],"partialFingerprints":{"codehealthFindingId/v1":"908298b555b097ff6b622052782160bdf80678bd71fb9e63b43cfb5da2e22e60"}},{"ruleId":"D2","level":"warning","message":{"text":"LibraryTools.B4jSearchLibrary (cognitive 74): LibraryTools.B4jSearchLibrary has cognitive complexity 74 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function. This file is where this pass\u0027s cognitive complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 4 of the 17 methods over the threshold \u2014 including the worst \u2014 and 119 of the 246 points over it (48%), 4.4\u00D7 the next-largest file (B4jMcp/Utils/B4jParser.vb at 27). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":104}}}],"partialFingerprints":{"codehealthFindingId/v1":"079521d44b3585e73ab89d1c10319ad1c0b10442e3668b7568720e916e82324c"}},{"ruleId":"D2","level":"warning","message":{"text":"LibraryTools.RenderXmlDocs (cognitive 60): LibraryTools.RenderXmlDocs has cognitive complexity 60 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function. This file is where this pass\u0027s cognitive complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 4 of the 17 methods over the threshold \u2014 including the worst \u2014 and 119 of the 246 points over it (48%), 4.4\u00D7 the next-largest file (B4jMcp/Utils/B4jParser.vb at 27). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":217}}}],"partialFingerprints":{"codehealthFindingId/v1":"947c6cf319521c773b58cbe3a7c419243aa81b79e9ffcad9e9337ec36a306200"}},{"ruleId":"D2","level":"warning","message":{"text":"BalConverter.WriteMap (cognitive 38): BalConverter.WriteMap has cognitive complexity 38 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/BalConverter.vb"},"region":{"startLine":352}}}],"partialFingerprints":{"codehealthFindingId/v1":"dbb935a5cdef795ca4576183c2b9066e8e8959ed1e164499f115e08d8345cea8"}},{"ruleId":"D2","level":"warning","message":{"text":"NavTools.B4jFindSymbol (cognitive 32): NavTools.B4jFindSymbol has cognitive complexity 32 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/NavTools.vb"},"region":{"startLine":32}}}],"partialFingerprints":{"codehealthFindingId/v1":"00ad82915cf8eaae2a847af9b09b875978ebc9f8b60b54327020f4c21d825c17"}},{"ruleId":"D2","level":"warning","message":{"text":"B4jParser.ParseCodeSection (cognitive 30): B4jParser.ParseCodeSection has cognitive complexity 30 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/B4jParser.vb"},"region":{"startLine":85}}}],"partialFingerprints":{"codehealthFindingId/v1":"156ef46204944f21f6422d906b19deaa7e7cd47681d760529d51568b7c907e0c"}},{"ruleId":"D2","level":"warning","message":{"text":"B4jSymbolParser.Parse (cognitive 28): B4jSymbolParser.Parse has cognitive complexity 28 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/B4jSymbolParser.vb"},"region":{"startLine":29}}}],"partialFingerprints":{"codehealthFindingId/v1":"6308e108859ae2f2ced4de1a222efadf8ee7787a9ebfbe8068991cf375788360"}},{"ruleId":"D2","level":"warning","message":{"text":"B4jParser.Parse (cognitive 27): B4jParser.Parse has cognitive complexity 27 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/B4jParser.vb"},"region":{"startLine":9}}}],"partialFingerprints":{"codehealthFindingId/v1":"7d264181199c411634dc2386fcf45490c8137d63fe145d4a5a995eeb6d7cedbc"}},{"ruleId":"D2","level":"warning","message":{"text":"ConfigTools.B4jDoctor (cognitive 26): ConfigTools.B4jDoctor has cognitive complexity 26 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/ConfigTools.vb"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"da4a9a4bd34c27d9cd15bce960583ea7d403e852c8fda03d3ba3ff23ce79870f"}},{"ruleId":"D2","level":"warning","message":{"text":"BasTools.B4jCreateModule (cognitive 25): BasTools.B4jCreateModule has cognitive complexity 25 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BasTools.vb"},"region":{"startLine":166}}}],"partialFingerprints":{"codehealthFindingId/v1":"358ce156155e9d3b00c3f4ea5f81048d27dc6516cbf5441875d6a0f171a8857a"}},{"ruleId":"D2","level":"warning","message":{"text":"LibraryTools.B4jListLibraries (cognitive 23): LibraryTools.B4jListLibraries has cognitive complexity 23 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function. This file is where this pass\u0027s cognitive complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 4 of the 17 methods over the threshold \u2014 including the worst \u2014 and 119 of the 246 points over it (48%), 4.4\u00D7 the next-largest file (B4jMcp/Utils/B4jParser.vb at 27). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":16}}}],"partialFingerprints":{"codehealthFindingId/v1":"36da3164179a27eb7c955b8a8c7a01b03aeb7d41df5b8c87eceae17dd9eceb36"}},{"ruleId":"D2","level":"warning","message":{"text":"ViewTemplates.ValidateView (cognitive 23): ViewTemplates.ValidateView has cognitive complexity 23 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/ViewTemplates.vb"},"region":{"startLine":322}}}],"partialFingerprints":{"codehealthFindingId/v1":"61846f47b150d63aa543c1012b825ae13f0c61ebc4242fbd0400215784cc2284"}},{"ruleId":"D2","level":"warning","message":{"text":"LibraryTools.RenderB4xlibDocs (cognitive 22): LibraryTools.RenderB4xlibDocs has cognitive complexity 22 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function. This file is where this pass\u0027s cognitive complexity CONCENTRATES: B4jMcp/Tools/LibraryTools.vb holds 4 of the 17 methods over the threshold \u2014 including the worst \u2014 and 119 of the 246 points over it (48%), 4.4\u00D7 the next-largest file (B4jMcp/Utils/B4jParser.vb at 27). No single row can show this, because each is measured only against the threshold: reducing this one file moves this dimension further than any other file in the repository."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":285}}}],"partialFingerprints":{"codehealthFindingId/v1":"599f8b7d06e69ded88af4a070107b094958d99776135e296c7e548b2332a73fe"}},{"ruleId":"D2","level":"warning","message":{"text":"ViewTemplates.ValidateLayout (cognitive 22): ViewTemplates.ValidateLayout has cognitive complexity 22 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/ViewTemplates.vb"},"region":{"startLine":260}}}],"partialFingerprints":{"codehealthFindingId/v1":"19ff1ed1c05fd9339e31671e7154bd2b33ca3c3dab1da9dfc6828a619fe4232e"}},{"ruleId":"D2","level":"warning","message":{"text":"BuildTools.B4jRun (cognitive 20): BuildTools.B4jRun has cognitive complexity 20 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"0072d0c91546b3d18305585b42a86cc1821297c972e833c7065305b67e11f0fc"}},{"ruleId":"D2","level":"warning","message":{"text":"BasTools.B4jMultiEditBas (cognitive 19): BasTools.B4jMultiEditBas has cognitive complexity 19 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BasTools.vb"},"region":{"startLine":107}}}],"partialFingerprints":{"codehealthFindingId/v1":"9b1ef03e46a47be0a35a50f718fbbe76f5eaf9c2ede6f7848b202576632bac77"}},{"ruleId":"D2","level":"warning","message":{"text":"LayoutTools.B4jAddView (cognitive 16): LayoutTools.B4jAddView has cognitive complexity 16 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LayoutTools.vb"},"region":{"startLine":81}}}],"partialFingerprints":{"codehealthFindingId/v1":"b7fc69726081ab7c0a1d5f07c026659ce918d1b714eed70d7bfda5d27e3cdb5f"}},{"ruleId":"D2","level":"warning","message":{"text":"AppConfig.MergeWithB4jDefaults (cognitive 16): AppConfig.MergeWithB4jDefaults has cognitive complexity 16 (threshold 15). To reduce it, flatten the nesting: invert conditions into early returns or guard clauses so the happy path stays at one level, and lift the deepest nested block into its own named function."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Utils/AppConfig.vb"},"region":{"startLine":40}}}],"partialFingerprints":{"codehealthFindingId/v1":"15f822d03621d316416367685dd4c3a0a248482027cf2ffde935c1f8fdd57038"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (9 lines \u00D7 2): B4jMcp/Tools/BuildTools.vb:19-27 | B4jMcp/Tools/BuildTools.vb:249-257 \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":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":19}}}],"partialFingerprints":{"codehealthFindingId/v1":"8452ae1f8d6b2863796067186bd7aa8fa5aa688b3d9ede8e6d5f63efb388fbd7"}},{"ruleId":"D4","level":"warning","message":{"text":"Duplicated block (5 lines \u00D7 2): B4jMcp/Tools/LibraryTools.vb:237-241 | B4jMcp/Tools/LibraryTools.vb:268-272 \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 \u0060B4jMcp/Tools/LibraryTools.vb:237\u0060 it begins part-way through the construct above it, so those exact lines cannot be lifted as they stand \u2014 widen the region to the smallest complete statement or declaration that contains it, and extract that. \u2605 These copies have DRIFTED, and that is worth reading before extracting anything: just after the matched lines, \u0060B4jMcp/Tools/LibraryTools.vb:242\u0060 calls \u0060Attribute\u0060, \u0060ShortType\u0060, \u0060If\u0060 and \u0060B4jMcp/Tools/LibraryTools.vb:273\u0060 does not \u2014 after which the two agree again for 3 more lines. One of those two behaviours is the intended one and the other is what a copy-paste left behind, so decide which BEFORE unifying them: extracting the shared part will silently settle it, and if the copy that skips the call is the wrong one, that bug is already live."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":237}}}],"partialFingerprints":{"codehealthFindingId/v1":"f6b3aa32a576bed595274387381c7ad22fbdd0c366eb74a604d59f0f5e8c2e09"}},{"ruleId":"D8","level":"error","message":{"text":"No automated tests: No automated tests \u2014 no test code was found in this repository. Untested code is the largest single risk to changing it safely. Start with the code you change most often: add a suite in a framework a runner can collect (xUnit, NUnit or MSTest), and run it in CI so the gap cannot reopen."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"3132564c6310e5d01a231f252a02d5d2f5a542c0a8fa29a14c89693f1e3df871"}},{"ruleId":"D9","level":"note","message":{"text":"No tests found: No test suite could be collected \u2014 no discoverable tests to count. If this repository does test, wiring the suite to a framework a runner can collect (xUnit, NUnit or MSTest) is what makes it countable here; a pipeline step that invokes a runner is not evidence on its own, because a runner over an empty suite passes. Tests written as plain executables or shell/PowerShell harnesses are not collectible this way and are not scored here."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"c9bf64cbb5a4ae13d6bcd01fa3bc8d2879d860c73bc67f176ee3c2cecb8adce3"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: B4jMcp/Tools/ConfigTools.vb: B4jMcp/Tools/ConfigTools.vb changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 18 in ConfigTools.B4jDoctor at line 45. 1 of those changes was a fix/bug commit, and the other 1 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-03-26..2026-06-24, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-03-26 11:55:08 \u002B03:00\u0027 --until=\u00272026-06-24 11:55:08 \u002B03:00\u0027 --full-history --no-merges -- B4jMcp/Tools/ConfigTools.vb\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":"B4jMcp/Tools/ConfigTools.vb"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"31fb62874b0c6650c662dd28b48ed52132388e5aae1319f05fd1b317649d61ce"}},{"ruleId":"D15","level":"warning","message":{"text":"Hotspot: B4jMcp/Tools/BuildTools.vb: B4jMcp/Tools/BuildTools.vb changed 2 times in last 90 days, and the most complex body those changes touched has cyclomatic complexity 17 in BuildTools.B4jRun at line 90. 1 of those changes was a fix/bug commit, and the other 1 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-03-26..2026-06-24, the 90 days ending at the analysed commit. Reproduce with \u0060git log --since=\u00272026-03-26 11:55:08 \u002B03:00\u0027 --until=\u00272026-06-24 11:55:08 \u002B03:00\u0027 --full-history --no-merges -- B4jMcp/Tools/BuildTools.vb\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":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":90}}}],"partialFingerprints":{"codehealthFindingId/v1":"93688bc60b5e615e8befce3930c6126801d5cc84155f10a7ba1136ea6efa6c3a"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":140}}}],"partialFingerprints":{"codehealthFindingId/v1":"f5b1d84d3fc0e56b5162510f0257ae058a6f1527edd093a3fb0d81a0c2afd2e7"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/BuildTools.vb"},"region":{"startLine":170}}}],"partialFingerprints":{"codehealthFindingId/v1":"69bcbafdd48f2574d284f7c736914739795a33a936d7f192fa60a39d24f0e727"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":45}}}],"partialFingerprints":{"codehealthFindingId/v1":"0728f4d211c6f62ff0beb353e6c19565f8c11d7b0030ccc7e1a7e6e56c60b560"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":151}}}],"partialFingerprints":{"codehealthFindingId/v1":"f24cb2c89a9752b985ae2e96591e109de2ac9741a299bb27bedda33b18584ce3"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":186}}}],"partialFingerprints":{"codehealthFindingId/v1":"41fa25f4760d8490cf67273e5cbd1120a8765569e91b4b2d7aa6d44001b5f21e"}},{"ruleId":"D17","level":"error","message":{"text":"EmptyCatchBlock: empty catch block \u2014 the error is discarded with nothing recorded, so a failure here leaves no trace anywhere. Record it through whatever this codebase already uses to report problems, or let it propagate. Where swallowing one specific failure really is correct \u2014 as it often is on a teardown/dispose path where throwing would mask the original failure \u2014 catch exactly that exception type and write down WHY in a comment on the catch. Both are needed: a comment on a catch-all still swallows every failure nobody anticipated, and a note that only restates the swallow (\u0022ignored\u0022, \u0022do nothing\u0022) is read as no explanation at all."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"B4jMcp/Tools/LibraryTools.vb"},"region":{"startLine":337}}}],"partialFingerprints":{"codehealthFindingId/v1":"82b9aad854470d69494061317b43c9b9af458f33a4eb8119daec207853a2b410"}},{"ruleId":"D20","level":"note","message":{"text":"No ADRs found: No ADRs found. No recognised ADR directory (\u0060docs/adr/\u0060, \u0060docs/decisions/\u0060, \u0060adr/\u0060, \u0060docs/rfcs/\u0060, an \u0060ADR0001/\u0060 folder, or their siblings) exists anywhere in this tree. What was searched, so you can tell an empty log from a search that missed one: every directory under the tree (build output, dependencies and VCS metadata excepted), for a document that is either any non-index page inside a recognised ADR directory, whatever its name and however deeply nested (\u0060docs/adr/use-postgres.md\u0060, \u0060docs/adr/2024/0001-x.md\u0060); or a file anywhere whose name is ADR-shaped (\u00600001-use-postgres.md\u0060, \u0060adr-012-caching.md\u0060); or, when neither turned anything up, a document carrying the decision-record signature (an \u0022Architecture Decision Record\u0022 heading, or Status / Context / Decision / Consequences as section headings). A decision log that clears none of these \u2014 unnumbered files outside any recognised directory, without those headings \u2014 is not seen by this check and this row is then wrong. If that is your case, say so rather than renaming anything; otherwise, consider recording architectural decisions in \u0060docs/adr/\u0060."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"d2bea044ff79d7d275f5a91a6e2f548586178eaf480274c33960ad020c854631"}},{"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.md names \u0060b4xV5.ini\u0060, but no file or folder \u0060b4xV5.ini\u0060 exists. Checked without a model against the repository: its files and folders, the scripts and dependencies of every package.json, the projects, namespaces, package references and target frameworks of the .NET build, the SDK and Node pins, and the identifiers of every file that is not a document; the documents\u0027 own text never counts. A footprint generated at build time, read only by a platform, or living outside this repository is not seen, and this row is then wrong."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"README.md"},"region":{"startLine":145}}}],"partialFingerprints":{"codehealthFindingId/v1":"b85864071a30ab325207b0475304e4f6aa1b79c8e2996b50e4173a6d35a328ea"}},{"ruleId":"P1","level":"warning","message":{"text":"No CI pipeline: No CI workflow found (.github/workflows, azure-pipelines.yml, .gitlab-ci.yml, \u2026) \u2014 changes aren\u0027t gated by an automated build/test."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"44f01af96e50474fba2df84d95ddf4f7e1d34c29c307830b9efc9057daa6b670"}},{"ruleId":"P3","level":"note","message":{"text":"No SAST: No static application security testing detected. For this repository\u0027s stack, add a Roslyn security analyzer package referenced from the project (the analyzer packages do analyse VB.NET), plus gitleaks for committed secrets \u2014 CodeQL has no VB.NET extractor, so its csharp pack would extract nothing from this tree and then report it clean \u2014 this repository has no CI pipeline yet, so run it locally to clear the existing findings, then make it a step of the first workflow you add so a regression fails the build. What was searched, so you can tell an absence from a miss: the 0 CI workflow file(s) in this repository, and the scanner and linter configuration checked in beside them. A scan that runs outside CI, one configured in your forge\u0027s web UI rather than in a committed file, or a tool whose name is none of those this check carries, is not seen \u2014 if that is your case the row is wrong, and saying so is more useful than adding a second scanner."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"6e54424179c892f03ef2fd003130ac4bd43f39bbf3b1ca0a0143e25acb80ec87"}},{"ruleId":"P6","level":"note","message":{"text":"No changelog: No CHANGELOG/HISTORY/RELEASES file \u2014 what shipped when isn\u0027t easy to reconstruct for support or audit. (Versioning/tagging makes releases traceable, but a changelog records the what.)"},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"dda5aa5aed8cbb292c3ef2b733bc138f614293ae6426c85e98bf31ef330d9415"}},{"ruleId":"SC1","level":"warning","message":{"text":"NuGet dependencies are not locked: No packages.lock.json and no central package management \u2014 restores aren\u0027t reproducible or pinned (SSDF PW.4.4). Enable \u003CRestorePackagesWithLockFile\u003Etrue\u003C/RestorePackagesWithLockFile\u003E (commit the lockfile) or adopt Directory.Packages.props. Advisory \u2014 never scored."},"locations":[],"partialFingerprints":{"codehealthFindingId/v1":"0a97b4f69ccac509400ece7eedefb06d3ede0522cd4d8bcb5c068bea719545a6"}}],"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-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-77","guid":"332c8ade-6612-9f56-a06b-d8d90b1a8750","name":"Improper Neutralization of Special Elements used in a Command (\u0027Command Injection\u0027)","shortDescription":{"text":"Improper Neutralization of Special Elements used in a Command (\u0027Command Injection\u0027)"},"helpUri":"https://cwe.mitre.org/data/definitions/77.html"},{"id":"CWE-78","guid":"2e31ceaf-c7ae-2e5e-9661-cfb1362789cf","name":"Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027)","shortDescription":{"text":"Improper Neutralization of Special Elements used in an OS Command (\u0027OS Command Injection\u0027)"},"helpUri":"https://cwe.mitre.org/data/definitions/78.html"},{"id":"CWE-79","guid":"fd45580b-e8c4-fc5e-8c2f-aa8fab0b4dbf","name":"Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)","shortDescription":{"text":"Improper Neutralization of Input During Web Page Generation (\u0027Cross-site Scripting\u0027)"},"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":"Improper Neutralization of Special Elements used in an SQL Command (\u0027SQL Injection\u0027)","shortDescription":{"text":"Improper Neutralization of Special Elements used in an SQL Command (\u0027SQL Injection\u0027)"},"helpUri":"https://cwe.mitre.org/data/definitions/89.html"},{"id":"CWE-94","guid":"75e7f50c-6c2f-dd52-bf40-bf6c52b861fd","name":"Improper Control of Generation of Code (\u0027Code Injection\u0027)","shortDescription":{"text":"Improper Control of Generation of Code (\u0027Code Injection\u0027)"},"helpUri":"https://cwe.mitre.org/data/definitions/94.html"}]},{"name":"OWASP Top 10","guid":"7d1f0c2e-4b6a-4e39-9a51-0b2e8c3d5f61","version":"2025","organization":"OWASP Foundation","informationUri":"https://top10.owasp.org/2025/","isComprehensive":false,"shortDescription":{"text":"The OWASP Top 10:2025 web application security risks."},"taxa":[{"id":"A05:2025","guid":"87e86033-3231-8458-8e4a-5cb82743553a","name":"Injection","shortDescription":{"text":"Injection"},"helpUri":"https://top10.owasp.org/2025/A05_2025-Injection/"},{"id":"A07:2025","guid":"334ddd78-539d-d35c-83dd-253647eb7eaf","name":"Authentication Failures","shortDescription":{"text":"Authentication Failures"},"helpUri":"https://top10.owasp.org/2025/A07_2025-Authentication_Failures/"}]}],"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":0,"secretScannerRunsExcluded":0}}}]}