{"schema_version":"2","scorer_version":"0.1.0","scoring_version":"prov-4+qual-2+sec-2","generated_at":"2026-11-13T23:58:22.515712Z","repo":{"ref":{"host":"github.com","owner":"ds-sebastian","name":"pricecious"},"default_branch":"main","clone_url":"https://github.com/ds-sebastian/pricecious.git","html_url":"https://github.com/ds-sebastian/pricecious","description":"AI Price Tracker","stars":38,"forks":7,"is_fork":false,"is_archived":false,"is_private":false,"size_kb":7881,"primary_language":"Python","license_spdx":"GPL-3.0","created_at":"2025-11-18T21:17:51Z","pushed_at":"2026-11-12T14:56:39Z","security_policy_url":null,"distribution":{"owner_created_at":"2020-08-10T23:45:42Z","owner_type":"User","release_assets":[{"name":"CHANGELOG.md","size":12858,"download_count":1,"release_tag":"v0.3.3","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.3.3/CHANGELOG.md"},{"name":"CHANGELOG.md","size":12452,"download_count":3,"release_tag":"v0.3.2","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.3.2/CHANGELOG.md"},{"name":"CHANGELOG.md","size":10877,"download_count":3,"release_tag":"v0.3.0","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.3.0/CHANGELOG.md"},{"name":"CHANGELOG.md","size":5701,"download_count":3,"release_tag":"v0.2.5","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.5/CHANGELOG.md"},{"name":"CHANGELOG.md","size":5701,"download_count":5,"release_tag":"v0.2.4","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.4/CHANGELOG.md"},{"name":"CHANGELOG.md","size":5701,"download_count":3,"release_tag":"v0.2.3","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.3/CHANGELOG.md"},{"name":"CHANGELOG.md","size":5066,"download_count":4,"release_tag":"v0.2.2","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.2/CHANGELOG.md"},{"name":"CHANGELOG.md","size":4655,"download_count":6,"release_tag":"v0.2.1","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.1/CHANGELOG.md"},{"name":"CHANGELOG.md","size":3927,"download_count":4,"release_tag":"v0.2.0","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.2.0/CHANGELOG.md"},{"name":"CHANGELOG.md","size":2623,"download_count":5,"release_tag":"v0.1.6","url":"https://github.com/ds-sebastian/pricecious/releases/download/v0.1.6/CHANGELOG.md"}]}},"commit_sha":"a086bb9696af822d8352f5a20ca441fb4c0fd5fe","profile":{"lines_by_language":{"Python":5190,"JavaScript":3216},"files_by_category":{"source":44,"config":13,"test":11,"binary":8,"other":4,"docs":3,"generated":2,"oversized":1},"source_lines":6426,"test_lines":1980},"pillars":{"ai_provenance":{"score":25.3,"confidence":0.95,"coverage":1.0,"label":"explicit","breakdown":{"attributed_share":0.2534,"suspected_share":0.2482,"estimated_share":0.2534,"ai_artifacts":0.0,"flagged_work_units":2.0,"flagged_releases":0.0},"summary":"Explicit AI attribution on 25% of first-party code added; an estimated 25% including velocity signals."},"quality":{"score":71.6,"confidence":0.9,"coverage":1.0,"label":"adequate","breakdown":{"complexity":53.9,"duplication":95.4,"lint":54.7,"testing":90.4,"docs":85.0,"type_safety":0.0,"process":null},"summary":"Code quality is adequate: test-to-source ratio 0.31, CI runs tests; 21% of function code in complex or long functions; 1% duplicated lines. Weakest area: type safety."},"security":{"score":67.2,"confidence":0.85,"coverage":1.0,"label":"weak","breakdown":{"secrets":100.0,"sast":70.4,"dependencies":72.9,"ci_actions":5.3,"posture":60.0,"scorecard":null},"summary":"Security posture is weak: 15 known vulnerabilities in 3 dependencies; 5 high-severity SAST findings; 15 high-severity workflow issues. Weakest area: ci actions."}},"analyzer_results":[{"analyzer":"sec-scorecard","pillar":"security","status":"skipped","tool_version":null,"metrics":{},"findings":[],"evidence":[],"data":{},"error":"no published OpenSSF Scorecard result for this repo"},{"analyzer":"sec-registry","pillar":"security","status":"ok","tool_version":null,"metrics":{"declared":31.0,"checked":31.0,"missing":0.0,"recent":0.0,"lookup_errors":0.0},"findings":[],"evidence":[],"data":{"phantom":false},"error":null},{"analyzer":"ai-attribution","pillar":"ai_provenance","status":"ok","tool_version":"signatures-v1","metrics":{"commits":521.0,"attributed_commits":39.0,"attributed_commit_share":0.07485604606525911,"effective_loc":31818.0,"attributed_loc":8062.0,"attributed_loc_share":0.2533785907348042,"tools_detected":2.0},"findings":[],"evidence":[{"kind":"attribution-summary","description":"GitHub Copilot coding agent: 21 attributed commits, 353 lines added","ref":null,"url":null,"weight":1.0},{"kind":"attribution-summary","description":"Claude Code: 18 attributed commits, 7,709 lines added","ref":null,"url":null,"weight":1.0},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"b92eecfc5fadcb45a44e53bd8770be2090497983","url":"https://github.com/ds-sebastian/pricecious/commit/b92eecfc5fadcb45a44e53bd8770be2090497983","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"0daa26a54a5f5753edc877733a40102a3e0b06e3","url":"https://github.com/ds-sebastian/pricecious/commit/0daa26a54a5f5753edc877733a40102a3e0b06e3","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: trailer 'Co-authored-by: Claude'","ref":"a675cd19eceb2051213754ae2e7e92110d4a4eee","url":"https://github.com/ds-sebastian/pricecious/commit/a675cd19eceb2051213754ae2e7e92110d4a4eee","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"1ea5aca4cea8e3bc43eadc10980b8bd7365e6179","url":"https://github.com/ds-sebastian/pricecious/commit/1ea5aca4cea8e3bc43eadc10980b8bd7365e6179","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"00a9a8f283aa6f30c78ce05e9f7acf8b3e2f3e72","url":"https://github.com/ds-sebastian/pricecious/commit/00a9a8f283aa6f30c78ce05e9f7acf8b3e2f3e72","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"275e865d81640a64a34340d2c4e25954b57443e3","url":"https://github.com/ds-sebastian/pricecious/commit/275e865d81640a64a34340d2c4e25954b57443e3","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"baa4976bc9e6f59bd694e707dfcd521824b9eb76","url":"https://github.com/ds-sebastian/pricecious/commit/baa4976bc9e6f59bd694e707dfcd521824b9eb76","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"eb3378f8cca5dd4cb429a3cb843632d0188afaf2","url":"https://github.com/ds-sebastian/pricecious/commit/eb3378f8cca5dd4cb429a3cb843632d0188afaf2","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"e3cf5b2effa280a538787d7ab69683fa51714517","url":"https://github.com/ds-sebastian/pricecious/commit/e3cf5b2effa280a538787d7ab69683fa51714517","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"0efb796a5750a54eb0822a7c8674eecdd3cb1765","url":"https://github.com/ds-sebastian/pricecious/commit/0efb796a5750a54eb0822a7c8674eecdd3cb1765","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"2e5ba512a674ccb3c7f265d8b4c70cd5a9be5564","url":"https://github.com/ds-sebastian/pricecious/commit/2e5ba512a674ccb3c7f265d8b4c70cd5a9be5564","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"a0dcc9987c86411308be221cf7b84a2fde944b51","url":"https://github.com/ds-sebastian/pricecious/commit/a0dcc9987c86411308be221cf7b84a2fde944b51","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"3ba40dfcf76eccb293cd6c99d7faa7ee8d1b024d","url":"https://github.com/ds-sebastian/pricecious/commit/3ba40dfcf76eccb293cd6c99d7faa7ee8d1b024d","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"eaf42990cc9b0ac25e9797286e7abee6f738196b","url":"https://github.com/ds-sebastian/pricecious/commit/eaf42990cc9b0ac25e9797286e7abee6f738196b","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"62300c5845753cd56d6a568985fa47406de38ad6","url":"https://github.com/ds-sebastian/pricecious/commit/62300c5845753cd56d6a568985fa47406de38ad6","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"b1b99ba9c33b229bb5730a49907d9d2eb0850e38","url":"https://github.com/ds-sebastian/pricecious/commit/b1b99ba9c33b229bb5730a49907d9d2eb0850e38","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: author email noreply@anthropic.com","ref":"9ad06f1b5075f3de6ac22a0aa9b7987a8f258804","url":"https://github.com/ds-sebastian/pricecious/commit/9ad06f1b5075f3de6ac22a0aa9b7987a8f258804","weight":0.9},{"kind":"attributed-commit","description":"Claude Code: trailer 'Co-Authored-By: Claude'","ref":"876c070e9900304ebf7b113103ef8aec9006ffce","url":"https://github.com/ds-sebastian/pricecious/commit/876c070e9900304ebf7b113103ef8aec9006ffce","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"d7af85aa46403b3325a7a4647ec94e931288d063","url":"https://github.com/ds-sebastian/pricecious/commit/d7af85aa46403b3325a7a4647ec94e931288d063","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"41be2ba0903d2c12ec2b52fa09727b9d4f9b2aa5","url":"https://github.com/ds-sebastian/pricecious/commit/41be2ba0903d2c12ec2b52fa09727b9d4f9b2aa5","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"6e86a6bd9794ddd55f66d36aff0b419a39dc0b16","url":"https://github.com/ds-sebastian/pricecious/commit/6e86a6bd9794ddd55f66d36aff0b419a39dc0b16","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"1be80e11bbd23b78c6cdc670de5373677e32b191","url":"https://github.com/ds-sebastian/pricecious/commit/1be80e11bbd23b78c6cdc670de5373677e32b191","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"c37044099201d34fee4767d6afc67012aa2fd1e7","url":"https://github.com/ds-sebastian/pricecious/commit/c37044099201d34fee4767d6afc67012aa2fd1e7","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"50569e0547fe6ad66a434bfcf957b540306fe410","url":"https://github.com/ds-sebastian/pricecious/commit/50569e0547fe6ad66a434bfcf957b540306fe410","weight":0.9},{"kind":"attributed-commit","description":"GitHub Copilot coding agent: author copilot-swe-agent[bot]","ref":"c1ee8eac1a6b6ad9190317fc3c0e67357e306862","url":"https://github.com/ds-sebastian/pricecious/commit/c1ee8eac1a6b6ad9190317fc3c0e67357e306862","weight":0.9}],"data":{"attributed_loc_by_commit":{"9f21b80ddbd85cd27c7f559564e8a67f0285e3c9":0,"6f72506973fa77a94729811d5bcb892c008b2bfb":52,"e532ca3c48ad84bb4e356880da9108b2f9ccf995":0,"658aa5b09c3f1a9d6244c8c99900368674bf4470":111,"bbef333f85cdaabbe51f24357972422f9ff25ac6":92,"e697c3c51b9594bfa72ae9ac4e8b478b4b10af92":0,"a776fef65cd00667c4b6e7f4bfe6d183cbf74486":0,"c887491ac8f9f7c9600f71c3380b296f2220df7d":0,"072bffb900b56d9f1762f7abf9e3e4ade0c21ae3":1,"7f9936a4d6eebb60f02d18afe18c2dffb5f673eb":6,"a52f827d5177acf6b4ba3594eb5b2f4e7d8f32c8":0,"aada8f738b240a28c495ae9b3aeeccbc78b65064":0,"b9f99406198219b33381e3f1d2b9335f259a947f":0,"1594f9a72f411ac5806db77196dac325eb71d788":0,"c1ee8eac1a6b6ad9190317fc3c0e67357e306862":0,"50569e0547fe6ad66a434bfcf957b540306fe410":0,"c37044099201d34fee4767d6afc67012aa2fd1e7":4,"1be80e11bbd23b78c6cdc670de5373677e32b191":86,"6e86a6bd9794ddd55f66d36aff0b419a39dc0b16":0,"41be2ba0903d2c12ec2b52fa09727b9d4f9b2aa5":0,"d7af85aa46403b3325a7a4647ec94e931288d063":1,"876c070e9900304ebf7b113103ef8aec9006ffce":6634,"9ad06f1b5075f3de6ac22a0aa9b7987a8f258804":0,"b1b99ba9c33b229bb5730a49907d9d2eb0850e38":51,"62300c5845753cd56d6a568985fa47406de38ad6":319,"eaf42990cc9b0ac25e9797286e7abee6f738196b":387,"3ba40dfcf76eccb293cd6c99d7faa7ee8d1b024d":40,"a0dcc9987c86411308be221cf7b84a2fde944b51":104,"2e5ba512a674ccb3c7f265d8b4c70cd5a9be5564":0,"0efb796a5750a54eb0822a7c8674eecdd3cb1765":0,"baa4976bc9e6f59bd694e707dfcd521824b9eb76":2,"eb3378f8cca5dd4cb429a3cb843632d0188afaf2":61,"e3cf5b2effa280a538787d7ab69683fa51714517":97,"275e865d81640a64a34340d2c4e25954b57443e3":0,"00a9a8f283aa6f30c78ce05e9f7acf8b3e2f3e72":0,"1ea5aca4cea8e3bc43eadc10980b8bd7365e6179":14,"a675cd19eceb2051213754ae2e7e92110d4a4eee":0,"0daa26a54a5f5753edc877733a40102a3e0b06e3":0,"b92eecfc5fadcb45a44e53bd8770be2090497983":0},"tools":{"github-copilot":{"name":"GitHub Copilot coding agent","commits":21,"loc":353,"first_seen":1772297359,"last_seen":1772401343},"claude-code":{"name":"Claude Code","commits":18,"loc":7709,"first_seen":1790351319,"last_seen":1792819933}},"monthly":{"2025-11":{"loc":11378,"attributed_loc":0},"2025-12":{"loc":9826,"attributed_loc":0},"2026-02":{"loc":52,"attributed_loc":52},"2026-03":{"loc":874,"attributed_loc":301},"2026-04":{"loc":0,"attributed_loc":0},"2026-05":{"loc":1159,"attributed_loc":0},"2026-06":{"loc":3,"attributed_loc":0},"2026-07":{"loc":804,"attributed_loc":0},"2026-08":{"loc":0,"attributed_loc":0},"2026-09":{"loc":7709,"attributed_loc":7709},"2026-10":{"loc":0,"attributed_loc":0},"2026-11":{"loc":13,"attributed_loc":0}}},"error":null},{"analyzer":"ai-artifacts","pillar":"ai_provenance","status":"ok","tool_version":"signatures-v1","metrics":{"artifacts":0.0,"workflow_agents":0.0,"tools_configured":0.0},"findings":[],"evidence":[],"data":{"artifacts":[],"workflows":[],"tools":[]},"error":null},{"analyzer":"ai-velocity","pillar":"ai_provenance","status":"ok","tool_version":"prov-4","metrics":{"work_units":42.0,"flagged_units":2.0,"pre_ai_era_bursts":0.0,"pre_ai_era_measured_loc":0.0,"pre_ai_era_burst_loc":0.0,"measured_loc":25184.0,"flagged_loc":7898.0,"flagged_loc_share":0.3136118170266836,"max_loc_per_hour":795.7506882191007,"median_loc_per_hour":152.68579511382006,"pr_timed_units":1.0,"excluded_import_loc":6634.0},"findings":[],"evidence":[{"kind":"velocity-burst","description":"6,263 lines of first-party code in ~7.9h (796 lines/hour, 18 commit session)","ref":"2b630669a75785fd188838866b6c9edac420477b","url":"https://github.com/ds-sebastian/pricecious/commit/2b630669a75785fd188838866b6c9edac420477b","weight":0.2387252064657302},{"kind":"velocity-burst","description":"1,635 lines of first-party code in ~3.2h (511 lines/hour, 10 commit session)","ref":"fdb440e512f4b725e0d09b039e03ac78073515d3","url":"https://github.com/ds-sebastian/pricecious/commit/fdb440e512f4b725e0d09b039e03ac78073515d3","weight":0.1534410844629823}],"data":{"flagged_loc_by_commit":{"ca1c9a2ef6ec98f297c5e489e187d57aeddd8ce5":31,"4c03c792399801942fcb6a804cff38ec587666fd":80,"23cf6184be9a9197a2fc5539528b9cc9ba33a8ed":160,"f39322c627948c505e1b8940288102c191155695":39,"c7243284be113af38b78d13ed67a3d33ce11b16c":9,"3185d3bc6b2466428d692e445bccedeb9e80e04e":190,"2e668087b6844688b34542ad224bcbc9ddc210b2":819,"d4234537d1e2bfa0f213ab29d5e39135fca835b4":167,"935590817bfe6ecb48c780d5d8ad8976d4ad94b5":139,"fdb440e512f4b725e0d09b039e03ac78073515d3":1,"d0d238f56227741f7f8e52c80d9672d030190a77":592,"2540910a1cd7494b0a250057322fc699d35002bb":3,"17daab3f680027ceee0534ae233c1b2b1f16fd0c":5,"e5b4eb5486fff536bf3ab58bee7ef386da984dc1":196,"70e4f0a251561de948d23981edfaedf426f2e708":1,"7c00ad08b018e289998abd80f38a3d8fb72da35c":18,"b4655ba13270b925652c059a01a76eadbc9f6846":3384,"367682c48204bc16e48c412ff2ae0780e8e6a962":93,"ec4b6e1a80ac14c2d56dbf61379e4a4ed6afd046":1107,"f988c8bbc86fdf20c9b2721c4b09185e8d3e87e5":137,"0448b976c3d4d7d62a319037bd9b3d54cdb2a04f":2,"0943ad88a54d8c6868390ae881f2144d7c91c56d":1,"7cb3e088ba26fd6619ab1a75f4253608df65cf18":102,"2413ed68159b04cb6b4539bf438566387bffa4b2":446,"1b4a8174f68344e7809760e0975e2df40b75dc6e":90,"b853af995feb34c6b3ce0c8fd1d7bfcbaab0154d":29,"8ed6377b522e0dda615b9155a219650c3917361f":42,"2b630669a75785fd188838866b6c9edac420477b":15},"excluded_import_commits":["876c070e9900304ebf7b113103ef8aec9006ffce"]},"error":null},{"analyzer":"ai-release-velocity","pillar":"ai_provenance","status":"ok","tool_version":"prov-4","metrics":{"releases":15.0,"flagged_releases":0.0,"max_loc_per_day":5592.0},"findings":[],"evidence":[],"data":{"releases":[{"from":"v0.1.0","to":"v0.1.1","loc":0,"days":0.04,"loc_per_day":0.0,"flagged":false},{"from":"v0.1.1","to":"v0.1.3","loc":28,"days":1.15,"loc_per_day":24.3,"flagged":false},{"from":"v0.1.3","to":"v0.1.4","loc":608,"days":0.11,"loc_per_day":5592.0,"flagged":false},{"from":"v0.1.4","to":"v0.1.5","loc":519,"days":1.45,"loc_per_day":358.6,"flagged":false},{"from":"v0.1.5","to":"v0.1.6","loc":128,"days":2.47,"loc_per_day":51.8,"flagged":false},{"from":"v0.1.6","to":"v0.2.0","loc":8667,"days":9.84,"loc_per_day":880.9,"flagged":false},{"from":"v0.2.0","to":"v0.2.1","loc":423,"days":2.84,"loc_per_day":149.1,"flagged":false},{"from":"v0.2.1","to":"v0.2.2","loc":736,"days":6.0,"loc_per_day":122.7,"flagged":false},{"from":"v0.2.2","to":"v0.2.3","loc":352,"days":75.13,"loc_per_day":4.7,"flagged":false},{"from":"v0.2.3","to":"v0.2.4","loc":574,"days":39.19,"loc_per_day":14.6,"flagged":false},{"from":"v0.2.4","to":"v0.2.5","loc":1162,"days":62.74,"loc_per_day":18.5,"flagged":false},{"from":"v0.2.5","to":"v0.3.0","loc":1705,"days":105.91,"loc_per_day":16.1,"flagged":false},{"from":"v0.3.0","to":"v0.3.1","loc":174,"days":0.04,"loc_per_day":4176.0,"flagged":false},{"from":"v0.3.1","to":"v0.3.2","loc":0,"days":28.51,"loc_per_day":0.0,"flagged":false},{"from":"v0.3.2","to":"v0.3.3","loc":13,"days":19.39,"loc_per_day":0.7,"flagged":false}]},"error":null},{"analyzer":"ai-stylometry","pillar":"ai_provenance","status":"ok","tool_version":null,"metrics":{"lines_scanned":6426.0,"index":0.0,"count:narrated_steps":0.0,"per_kloc:narrated_steps":0.0,"files:narrated_steps":0.0,"count:placeholder":0.0,"per_kloc:placeholder":0.0,"files:placeholder":0.0,"count:emoji_in_code":0.0,"per_kloc:emoji_in_code":0.0,"files:emoji_in_code":0.0,"count:assistant_voice":0.0,"per_kloc:assistant_voice":0.0,"files:assistant_voice":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-secrets","pillar":"security","status":"ok","tool_version":"gitleaks 8.30.1","metrics":{"secrets_current":0.0,"secrets_history":0.0,"secrets_nonprod":0.0,"secrets_low_confidence":0.0},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"sec-sast","pillar":"security","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":6.0,"findings_high":5.0,"findings_medium":1.0,"findings_low":0.0,"weighted_findings":6.45,"scanned_lines":6426.0,"parse_errors":1.0},"findings":[{"rule_id":"opengrep/javascript.lang.security.detect-insecure-websocket","severity":"high","message":"Insecure WebSocket Detected. WebSocket Secure (wss) should be used for all WebSocket connections. [confidence low]","path":".env.example","line":5,"fingerprint":"javascript.lang.security.detect-insecure-websocket:.env.example:5"},{"rule_id":"opengrep/dockerfile.security.missing-user","severity":"high","message":"By not specifying a USER, a program in the container may run as 'root'. This is a security hazard. If an attacker can control a process running as root, they may have control over the container. Ensure that the last USER in a Dockerfile is a USER other than 'root'. [confidence medium]","path":"Dockerfile","line":19,"fingerprint":"dockerfile.security.missing-user:Dockerfile:19"},{"rule_id":"opengrep/dockerfile.security.missing-user","severity":"high","message":"By not specifying a USER, a program in the container may run as 'root'. This is a security hazard. If an attacker can control a process running as root, they may have control over the container. Ensure that the last USER in a Dockerfile is a USER other than 'root'. [confidence medium]","path":"Dockerfile","line":21,"fingerprint":"dockerfile.security.missing-user:Dockerfile:21"},{"rule_id":"opengrep/javascript.lang.security.detect-insecure-websocket","severity":"high","message":"Insecure WebSocket Detected. WebSocket Secure (wss) should be used for all WebSocket connections. [confidence low]","path":"app/scraper.py","line":24,"fingerprint":"javascript.lang.security.detect-insecure-websocket:app/scraper.py:24"},{"rule_id":"opengrep/javascript.lang.security.detect-insecure-websocket","severity":"high","message":"Insecure WebSocket Detected. WebSocket Secure (wss) should be used for all WebSocket connections. [confidence low]","path":"app/scraper.py","line":343,"fingerprint":"javascript.lang.security.detect-insecure-websocket:app/scraper.py:343"},{"rule_id":"opengrep/python.flask.security.audit.directly-returned-format-string","severity":"medium","message":"Detected Flask route directly returning a formatted string. This is subject to cross-site scripting if user input can reach the string. Consider using the template engine instead and rendering pages with 'render_template()'. [confidence medium]","path":"app/main.py","line":64,"fingerprint":"python.flask.security.audit.directly-returned-format-string:app/main.py:64"}],"evidence":[],"data":{"rulesets":["javascript","python","dockerfile"]},"error":null},{"analyzer":"sec-deps","pillar":"security","status":"ok","tool_version":"osv-scanner version: 2.7.1","metrics":{"vulnerable_packages":3.0,"vulnerabilities":15.0,"vulns_critical":0.0,"vulns_high":2.0,"vulns_medium":10.0,"vulns_low":3.0,"vulns_unknown":0.0,"penalty":19.0},"findings":[{"rule_id":"osv/GHSA-v4x8-3wr5-3wq8","severity":"high","message":"filelock@3.32.7 (PyPI) is affected by GHSA-v4x8-3wr5-3wq8","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-v4x8-3wr5-3wq8"},{"rule_id":"osv/GHSA-3jp2-3mrg-2vxc","severity":"high","message":"oauthlib@4.0.0 (PyPI) is affected by GHSA-3jp2-3mrg-2vxc","path":"uv.lock","line":null,"fingerprint":"oauthlib@4.0.0 (PyPI):GHSA-3jp2-3mrg-2vxc"},{"rule_id":"osv/GHSA-6627-m3xw-93mp","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-6627-m3xw-93mp","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-6627-m3xw-93mp"},{"rule_id":"osv/GHSA-69hj-f68j-2879","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-69hj-f68j-2879","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-69hj-f68j-2879"},{"rule_id":"osv/GHSA-8mx5-7m5m-r77g","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-8mx5-7m5m-r77g","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-8mx5-7m5m-r77g"},{"rule_id":"osv/GHSA-9c4x-gm8v-wgc4","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-9c4x-gm8v-wgc4","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-9c4x-gm8v-wgc4"},{"rule_id":"osv/GHSA-cwqr-hh33-gh44","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-cwqr-hh33-gh44","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-cwqr-hh33-gh44"},{"rule_id":"osv/GHSA-fq56-3cx3-fjxp","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-fq56-3cx3-fjxp","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-fq56-3cx3-fjxp"},{"rule_id":"osv/GHSA-j8f7-rjxc-mr56","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-j8f7-rjxc-mr56","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-j8f7-rjxc-mr56"},{"rule_id":"osv/GHSA-m462-7rxw-wvpg","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-m462-7rxw-wvpg","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-m462-7rxw-wvpg"},{"rule_id":"osv/GHSA-rfpc-qcw5-3pc4","severity":"medium","message":"filelock@3.32.7 (PyPI) is affected by GHSA-rfpc-qcw5-3pc4","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-rfpc-qcw5-3pc4"},{"rule_id":"osv/GHSA-mf5v-w3w3-f6cg","severity":"medium","message":"opentelemetry-api@1.45.1 (PyPI) is affected by GHSA-mf5v-w3w3-f6cg","path":"uv.lock","line":null,"fingerprint":"opentelemetry-api@1.45.1 (PyPI):GHSA-mf5v-w3w3-f6cg"},{"rule_id":"osv/GHSA-567q-5qvw-pf92","severity":"low","message":"filelock@3.32.7 (PyPI) is affected by GHSA-567q-5qvw-pf92","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-567q-5qvw-pf92"},{"rule_id":"osv/GHSA-9j6q-wvj5-jgjg","severity":"low","message":"filelock@3.32.7 (PyPI) is affected by GHSA-9j6q-wvj5-jgjg","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-9j6q-wvj5-jgjg"},{"rule_id":"osv/GHSA-9vhv-jxww-xfm5","severity":"low","message":"filelock@3.32.7 (PyPI) is affected by GHSA-9vhv-jxww-xfm5","path":"uv.lock","line":null,"fingerprint":"filelock@3.32.7 (PyPI):GHSA-9vhv-jxww-xfm5"}],"evidence":[],"data":{"ecosystems":["PyPI","npm"]},"error":null},{"analyzer":"sec-actions","pillar":"security","status":"ok","tool_version":"zizmor 1.32.0","metrics":{"workflows":2.0,"findings":23.0,"findings_high":15.0,"findings_medium":3.0,"findings_low":5.0,"penalty":176.4},"findings":[{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":35,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:35"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":36,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:36"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":53,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:53"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":54,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:54"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":73,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:73"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":77,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:77"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":80,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:80"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":84,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:84"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":92,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:92"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":103,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:103"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":128,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:128"},{"rule_id":"zizmor/unpinned-uses","severity":"high","message":"unpinned action reference [confidence high]","path":".github/workflows/ci.yml","line":131,"fingerprint":"unpinned-uses:.github/workflows/ci.yml:131"},{"rule_id":"zizmor/cache-poisoning","severity":"high","message":"runtime artifacts potentially vulnerable to a cache poisoning attack [confidence low]","path":".github/workflows/ci.yml","line":36,"fingerprint":"cache-poisoning:.github/workflows/ci.yml:36"},{"rule_id":"zizmor/cache-poisoning","severity":"high","message":"runtime artifacts potentially vulnerable to a cache poisoning attack [confidence low]","path":".github/workflows/ci.yml","line":54,"fingerprint":"cache-poisoning:.github/workflows/ci.yml:54"},{"rule_id":"zizmor/bot-conditions","severity":"high","message":"spoofable bot actor check [confidence high]","path":".github/workflows/dependabot-auto-merge.yml","line":12,"fingerprint":"bot-conditions:.github/workflows/dependabot-auto-merge.yml:12"},{"rule_id":"zizmor/dependabot-cooldown","severity":"medium","message":"insufficient cooldown in Dependabot updates [confidence high]","path":".github/dependabot.yml","line":17,"fingerprint":"dependabot-cooldown:.github/dependabot.yml:17"},{"rule_id":"zizmor/dependabot-cooldown","severity":"medium","message":"insufficient cooldown in Dependabot updates [confidence high]","path":".github/dependabot.yml","line":29,"fingerprint":"dependabot-cooldown:.github/dependabot.yml:29"},{"rule_id":"zizmor/dependabot-cooldown","severity":"medium","message":"insufficient cooldown in Dependabot updates [confidence high]","path":".github/dependabot.yml","line":41,"fingerprint":"dependabot-cooldown:.github/dependabot.yml:41"},{"rule_id":"zizmor/artipacked","severity":"low","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":35,"fingerprint":"artipacked:.github/workflows/ci.yml:35"},{"rule_id":"zizmor/artipacked","severity":"low","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":53,"fingerprint":"artipacked:.github/workflows/ci.yml:53"},{"rule_id":"zizmor/artipacked","severity":"low","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":73,"fingerprint":"artipacked:.github/workflows/ci.yml:73"},{"rule_id":"zizmor/artipacked","severity":"low","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/ci.yml","line":128,"fingerprint":"artipacked:.github/workflows/ci.yml:128"},{"rule_id":"zizmor/superfluous-actions","severity":"info","message":"action functionality is already included by the runner [confidence high]","path":".github/workflows/ci.yml","line":131,"fingerprint":"superfluous-actions:.github/workflows/ci.yml:131"}],"evidence":[],"data":{},"error":null},{"analyzer":"sec-posture","pillar":"security","status":"ok","tool_version":null,"metrics":{"check:security_policy":0.0,"check:dependency_updates":1.0,"check:signed_commits":1.0,"check:lockfiles":1.0,"signed_commit_share":0.97,"unpinned_manifests":0.0},"findings":[],"evidence":[{"kind":"posture","description":"Dependency updates: .github/dependabot.yml","ref":".github/dependabot.yml","url":null,"weight":0.0}],"data":{},"error":null},{"analyzer":"sec-distribution","pillar":"security","status":"ok","tool_version":null,"metrics":{"signals":0.0,"binary_assets":0.0,"suspicious":0.0},"findings":[],"evidence":[],"data":{"signals":[],"suspicious":false,"unusual_traction":false,"metadata":true},"error":null},{"analyzer":"qual-complexity","pillar":"quality","status":"ok","tool_version":"lizard 1.25.1","metrics":{"functions":404.0,"function_nloc":3829.0,"mean_ccn":2.74,"p90_ccn":6.0,"complex_functions":3.0,"long_functions":5.0,"many_param_functions":0.0,"risky_nloc_share":0.2058},"findings":[],"evidence":[{"kind":"complex-function","description":"HistoryTable in frontend/src/pages/ItemDetail.jsx: complexity 31, 189 lines","ref":"frontend/src/pages/ItemDetail.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/pages/ItemDetail.jsx#L362","weight":0.5166666666666667},{"kind":"complex-function","description":"alerts in app/notify.py: complexity 28, 30 lines","ref":"app/notify.py","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/app/notify.py#L46","weight":0.4666666666666667},{"kind":"complex-function","description":"_call_model in app/ai.py: complexity 17, 40 lines","ref":"app/ai.py","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/app/ai.py#L288","weight":0.2833333333333333},{"kind":"complex-function","description":"Items in frontend/src/pages/Items.jsx: complexity 14, 104 lines","ref":"frontend/src/pages/Items.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/pages/Items.jsx#L37","weight":0.23333333333333334},{"kind":"complex-function","description":"SettingsForm in frontend/src/pages/Settings.jsx: complexity 10, 153 lines","ref":"frontend/src/pages/Settings.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/pages/Settings.jsx#L70","weight":0.16666666666666666},{"kind":"complex-function","description":"ItemForm in frontend/src/components/ItemForm.jsx: complexity 9, 112 lines","ref":"frontend/src/components/ItemForm.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/components/ItemForm.jsx#L63","weight":0.15},{"kind":"complex-function","description":"AISavings in frontend/src/pages/Settings.jsx: complexity 3, 160 lines","ref":"frontend/src/pages/Settings.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/pages/Settings.jsx#L327","weight":0.05}],"data":{},"error":null},{"analyzer":"qual-duplication","pillar":"quality","status":"ok","tool_version":"repotrust-dup-w6","metrics":{"compared_lines":4805.0,"duplicated_lines":38.0,"duplicated_share":0.0079,"files":44.0},"findings":[],"evidence":[{"kind":"duplicate-code","description":"6+ duplicated lines: app/api.py:287 and app/checks.py:165","ref":"app/api.py","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/app/api.py#L287","weight":0.3},{"kind":"duplicate-code","description":"6+ duplicated lines: frontend/src/components/ItemCard.jsx:240 and frontend/src/pages/ItemDetail.jsx:153","ref":"frontend/src/components/ItemCard.jsx","url":"https://github.com/ds-sebastian/pricecious/blob/a086bb9696af822d8352f5a20ca441fb4c0fd5fe/frontend/src/components/ItemCard.jsx#L240","weight":0.3}],"data":{},"error":null},{"analyzer":"qual-lint","pillar":"quality","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":17.0,"weighted_findings":15.5,"scanned_lines":6426.0,"category:correctness":3.0,"category:maintainability":14.0},"findings":[{"rule_id":"opengrep/python.lang.maintainability.return-not-in-function","severity":"medium","message":"`return` only makes sense inside a function","path":"app/api.py","line":43,"fingerprint":"python.lang.maintainability.return-not-in-function:app/api.py:43"},{"rule_id":"opengrep/python.lang.maintainability.code-after-unconditional-return","severity":"medium","message":"code after return statement will not be executed","path":"app/api.py","line":43,"fingerprint":"python.lang.maintainability.code-after-unconditional-return:app/api.py:43"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant data.is_active() because data.is_active is always true.","path":"app/api.py","line":98,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/api.py:98"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant item.is_active() because item.is_active is always true.","path":"app/api.py","line":98,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/api.py:98"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant Item.is_active() because Item.is_active is always true.","path":"app/api.py","line":127,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/api.py:127"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_refreshing\" a function or an attribute? If it is a function, you may have meant Item.is_refreshing() because Item.is_refreshing is always true.","path":"app/checks.py","line":83,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:83"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant Item.is_active() because Item.is_active is always true.","path":"app/checks.py","line":89,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:89"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant Item.is_active() because Item.is_active is always true.","path":"app/checks.py","line":102,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:102"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_refreshing\" a function or an attribute? If it is a function, you may have meant Item.is_refreshing() because Item.is_refreshing is always true.","path":"app/checks.py","line":116,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:116"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_refreshing\" a function or an attribute? If it is a function, you may have meant item.is_refreshing() because item.is_refreshing is always true.","path":"app/checks.py","line":210,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:210"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant item.is_active() because item.is_active is always true.","path":"app/checks.py","line":336,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:336"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_refreshing\" a function or an attribute? If it is a function, you may have meant item.is_refreshing() because item.is_refreshing is always true.","path":"app/checks.py","line":339,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/checks.py:339"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_active\" a function or an attribute? If it is a function, you may have meant Item.is_active() because Item.is_active is always true.","path":"app/forecast.py","line":88,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/forecast.py:88"},{"rule_id":"opengrep/python.lang.correctness.common-mistakes.string-concat-in-list","severity":"medium","message":"Detected strings that are implicitly concatenated inside a list. Python will implicitly concatenate strings when not explicitly delimited. Was this supposed to be individual elements of the list?","path":"app/scraper.py","line":28,"fingerprint":"python.lang.correctness.common-mistakes.string-concat-in-list:app/scraper.py:28"},{"rule_id":"opengrep/python.lang.maintainability.is-function-without-parentheses","severity":"medium","message":"Is \"is_global\" a function or an attribute? If it is a function, you may have meant ipaddress.ip_address(a).is_global() because ipaddress.ip_address(a).is_global is always true.","path":"app/urls.py","line":41,"fingerprint":"python.lang.maintainability.is-function-without-parentheses:app/urls.py:41"},{"rule_id":"opengrep/javascript.lang.correctness.missing-template-string-indicator","severity":"low","message":"This looks like a JavaScript template string. Are you missing a '$' in front of '{...}'?","path":"frontend/src/pages/ItemDetail.jsx","line":383,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:frontend/src/pages/ItemDetail.jsx:383"},{"rule_id":"opengrep/javascript.lang.correctness.missing-template-string-indicator","severity":"low","message":"This looks like a JavaScript template string. Are you missing a '$' in front of '{...}'?","path":"frontend/src/pages/ItemDetail.jsx","line":383,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:frontend/src/pages/ItemDetail.jsx:383"}],"evidence":[],"data":{},"error":null},{"analyzer":"qual-testing","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:has_tests":1.0,"check:test_ratio":0.6162,"check:ci_present":1.0,"check:ci_runs_tests":1.0,"check:ci_runs_lint":1.0,"check:tests_cochange":1.0,"test_lines":1980.0,"source_lines":6426.0,"test_ratio":0.3081,"ci_files":2.0,"cochange_share":0.7778,"cochange_commits":18.0},"findings":[],"evidence":[{"kind":"ci","description":"CI config: .github/workflows/ci.yml","ref":".github/workflows/ci.yml","url":null,"weight":0.0},{"kind":"ci","description":"CI config: .github/workflows/dependabot-auto-merge.yml","ref":".github/workflows/dependabot-auto-merge.yml","url":null,"weight":0.0},{"kind":"ci","description":"CI runs tests (pytest)","ref":null,"url":null,"weight":0.0},{"kind":"ci","description":"CI runs linters (ruff, biome)","ref":null,"url":null,"weight":0.0}],"data":{"test_commands":["pytest"],"lint_commands":["ruff","biome"]},"error":null},{"analyzer":"qual-docs","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:readme":1.0,"check:license":1.0,"check:contributing":0.0,"check:changelog":1.0,"readme_lines":173.0},"findings":[],"evidence":[{"kind":"docs","description":"README.md","ref":"README.md","url":null,"weight":0.0},{"kind":"docs","description":"LICENSE","ref":"LICENSE","url":null,"weight":0.0},{"kind":"docs","description":"CHANGELOG.md","ref":"CHANGELOG.md","url":null,"weight":0.0}],"data":{},"error":null},{"analyzer":"qual-type-safety","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:strict_config":0.0,"check:low_escape_density":0.0,"escapes":17.0,"escapes_per_kloc":5.296},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"x-blame","pillar":"ai_provenance","status":"ok","tool_version":"git-blame","metrics":{"ai_lines":5705.0,"other_lines":721.0,"files_blamed":44.0,"blame_failures":0.0,"quality:ai_findings":17.0,"quality:ai_per_kloc":2.98,"quality:other_findings":0.0,"quality:other_per_kloc":0.0,"security:ai_findings":3.0,"security:ai_per_kloc":0.526,"security:other_findings":0.0,"security:other_per_kloc":0.0},"findings":[],"evidence":[],"data":{"sampled":false,"comparable":true},"error":null}],"flags":[]}