{"schema_version":"2","scorer_version":"0.1.0","scoring_version":"prov-5+qual-2+sec-2","generated_at":"2026-11-14T14:52:06.500052Z","repo":{"ref":{"host":"github.com","owner":"nathaishik","name":"time-table-formaliser"},"default_branch":"main","clone_url":"https://github.com/nathaishik/time-table-formaliser.git","html_url":"https://github.com/nathaishik/time-table-formaliser","description":"Vibe Coded App 🥀 Needed to make something for creating schedules.","stars":0,"forks":0,"is_fork":false,"is_archived":false,"is_private":false,"size_kb":229,"primary_language":"TypeScript","license_spdx":"MIT","created_at":"2026-07-29T16:09:22Z","pushed_at":"2026-07-30T17:04:05Z","security_policy_url":null,"distribution":{"owner_created_at":"2023-06-08T02:56:14Z","owner_type":"User","release_assets":[]}},"commit_sha":"c54b7edaeae4dd2907421958241406f07a691515","profile":{"lines_by_language":{"TypeScript":2841,"JavaScript":22},"files_by_category":{"source":30,"other":15,"config":6,"docs":2,"generated":1,"binary":1},"source_lines":2863,"test_lines":0},"pillars":{"ai_provenance":{"score":0.0,"confidence":0.43,"coverage":1.0,"label":"none-detected","breakdown":{"attributed_share":0.0,"suspected_share":0.0,"estimated_share":0.0,"ai_artifacts":0.0,"flagged_work_units":0.0,"flagged_releases":null,"style_index":0.0},"summary":"No AI attribution or AI-consistent velocity signals detected."},"quality":{"score":43.2,"confidence":0.9,"coverage":1.0,"label":"poor","breakdown":{"complexity":58.1,"duplication":81.3,"lint":32.1,"testing":15.0,"docs":65.0,"type_safety":0.0,"process":null},"summary":"Code quality is poor: test-to-source ratio 0.00, no CI test run detected; 18% of function code in complex or long functions; 3% duplicated lines. Weakest area: type safety."},"security":{"score":75.8,"confidence":0.85,"coverage":1.0,"label":"adequate","breakdown":{"secrets":100.0,"sast":100.0,"dependencies":42.7,"ci_actions":98.0,"posture":0.0,"scorecard":null},"summary":"Security posture is adequate: 15 known vulnerabilities in 7 dependencies. Weakest area: posture."}},"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":22.0,"checked":22.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":11.0,"attributed_commits":0.0,"attributed_commit_share":0.0,"effective_loc":3847.0,"attributed_loc":0.0,"attributed_loc_share":0.0,"tools_detected":0.0},"findings":[],"evidence":[],"data":{"attributed_loc_by_commit":{},"tools":{},"monthly":{"2026-07":{"loc":3847,"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":6.0,"flagged_units":0.0,"pre_ai_era_bursts":0.0,"pre_ai_era_measured_loc":0.0,"pre_ai_era_burst_loc":0.0,"measured_loc":932.0,"flagged_loc":0.0,"flagged_loc_share":0.0,"max_loc_per_hour":155.72207084468664,"median_loc_per_hour":92.84471252566735,"pr_timed_units":0.0,"excluded_import_loc":2915.0},"findings":[],"evidence":[],"data":{"flagged_loc_by_commit":{},"excluded_import_commits":["04091f21bfab760ccdf50f074bad40b7ab2b81a0"]},"error":null},{"analyzer":"ai-release-velocity","pillar":"ai_provenance","status":"skipped","tool_version":null,"metrics":{},"findings":[],"evidence":[],"data":{},"error":null},{"analyzer":"ai-stylometry","pillar":"ai_provenance","status":"ok","tool_version":null,"metrics":{"lines_scanned":2863.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":0.0,"findings_high":0.0,"findings_medium":0.0,"findings_low":0.0,"weighted_findings":0.0,"scanned_lines":2863.0,"parse_errors":0.0},"findings":[],"evidence":[],"data":{"rulesets":["typescript","javascript"]},"error":null},{"analyzer":"sec-deps","pillar":"security","status":"ok","tool_version":"osv-scanner version: 2.7.1","metrics":{"vulnerable_packages":7.0,"vulnerabilities":15.0,"vulns_critical":0.0,"vulns_high":9.0,"vulns_medium":5.0,"vulns_low":1.0,"vulns_unknown":0.0,"penalty":51.0},"findings":[{"rule_id":"osv/GHSA-6j4f-fj2g-mc7p","severity":"high","message":"brace-expansion@5.0.8 (npm) is affected by GHSA-6j4f-fj2g-mc7p","path":"package-lock.json","line":null,"fingerprint":"brace-expansion@5.0.8 (npm):GHSA-6j4f-fj2g-mc7p"},{"rule_id":"osv/GHSA-qhr7-859c-m2p7","severity":"high","message":"brace-expansion@5.0.8 (npm) is affected by GHSA-qhr7-859c-m2p7","path":"package-lock.json","line":null,"fingerprint":"brace-expansion@5.0.8 (npm):GHSA-qhr7-859c-m2p7"},{"rule_id":"osv/GHSA-rgw5-rvv9-x895","severity":"high","message":"brace-expansion@5.0.8 (npm) is affected by GHSA-rgw5-rvv9-x895","path":"package-lock.json","line":null,"fingerprint":"brace-expansion@5.0.8 (npm):GHSA-rgw5-rvv9-x895"},{"rule_id":"osv/GHSA-2v37-7h3g-55p8","severity":"high","message":"nanoid@3.3.16 (npm) is affected by GHSA-2v37-7h3g-55p8","path":"package-lock.json","line":null,"fingerprint":"nanoid@3.3.16 (npm):GHSA-2v37-7h3g-55p8"},{"rule_id":"osv/GHSA-rgj7-g3m4-5g8c","severity":"high","message":"sharp@0.35.3 (npm) is affected by GHSA-rgj7-g3m4-5g8c","path":"package-lock.json","line":null,"fingerprint":"sharp@0.35.3 (npm):GHSA-rgj7-g3m4-5g8c"},{"rule_id":"osv/GHSA-wq5f-xc86-pv6w","severity":"high","message":"sharp@0.35.3 (npm) is affected by GHSA-wq5f-xc86-pv6w","path":"package-lock.json","line":null,"fingerprint":"sharp@0.35.3 (npm):GHSA-wq5f-xc86-pv6w"},{"rule_id":"osv/GHSA-68fv-2mgg-jv7q","severity":"high","message":"source-map-js@1.2.1 (npm) is affected by GHSA-68fv-2mgg-jv7q","path":"package-lock.json","line":null,"fingerprint":"source-map-js@1.2.1 (npm):GHSA-68fv-2mgg-jv7q"},{"rule_id":"osv/GHSA-587h-7wmj-h5pm","severity":"high","message":"vite@8.1.5 (npm) is affected by GHSA-587h-7wmj-h5pm","path":"package-lock.json","line":null,"fingerprint":"vite@8.1.5 (npm):GHSA-587h-7wmj-h5pm"},{"rule_id":"osv/GHSA-mrhx-c7xc-m3w5","severity":"high","message":"zod@4.4.3 (npm) is affected by GHSA-mrhx-c7xc-m3w5","path":"package-lock.json","line":null,"fingerprint":"zod@4.4.3 (npm):GHSA-mrhx-c7xc-m3w5"},{"rule_id":"osv/GHSA-q2hr-2g5m-vwhr","severity":"medium","message":"brace-expansion@5.0.8 (npm) is affected by GHSA-q2hr-2g5m-vwhr","path":"package-lock.json","line":null,"fingerprint":"brace-expansion@5.0.8 (npm):GHSA-q2hr-2g5m-vwhr"},{"rule_id":"osv/GHSA-g3hv-75wg-m249","severity":"medium","message":"minimatch@10.2.6 (npm) is affected by GHSA-g3hv-75wg-m249","path":"package-lock.json","line":null,"fingerprint":"minimatch@10.2.6 (npm):GHSA-g3hv-75wg-m249"},{"rule_id":"osv/GHSA-698v-4r3x-3vcv","severity":"medium","message":"vite@8.1.5 (npm) is affected by GHSA-698v-4r3x-3vcv","path":"package-lock.json","line":null,"fingerprint":"vite@8.1.5 (npm):GHSA-698v-4r3x-3vcv"},{"rule_id":"osv/GHSA-r825-w8mm-5pxw","severity":"medium","message":"vite@8.1.5 (npm) is affected by GHSA-r825-w8mm-5pxw","path":"package-lock.json","line":null,"fingerprint":"vite@8.1.5 (npm):GHSA-r825-w8mm-5pxw"},{"rule_id":"osv/GHSA-rq7h-c2jc-7f22","severity":"medium","message":"vite@8.1.5 (npm) is affected by GHSA-rq7h-c2jc-7f22","path":"package-lock.json","line":null,"fingerprint":"vite@8.1.5 (npm):GHSA-rq7h-c2jc-7f22"},{"rule_id":"osv/GHSA-9jrq-w75r-8gcw","severity":"low","message":"vite@8.1.5 (npm) is affected by GHSA-9jrq-w75r-8gcw","path":"package-lock.json","line":null,"fingerprint":"vite@8.1.5 (npm):GHSA-9jrq-w75r-8gcw"}],"evidence":[],"data":{"ecosystems":["npm"]},"error":null},{"analyzer":"sec-actions","pillar":"security","status":"ok","tool_version":"zizmor 1.32.0","metrics":{"workflows":1.0,"findings":1.0,"findings_high":0.0,"findings_medium":1.0,"findings_low":0.0,"penalty":1.2},"findings":[{"rule_id":"zizmor/artipacked","severity":"medium","message":"credential persistence through GitHub Actions artifacts [confidence low]","path":".github/workflows/deploy.yml","line":31,"fingerprint":"artipacked:.github/workflows/deploy.yml:31"}],"evidence":[],"data":{},"error":null},{"analyzer":"sec-posture","pillar":"security","status":"ok","tool_version":null,"metrics":{"check:security_policy":0.0,"check:dependency_updates":0.0,"check:signed_commits":0.0,"check:lockfiles":1.0,"signed_commit_share":0.1818,"unpinned_manifests":0.0},"findings":[],"evidence":[],"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":172.0,"function_nloc":2196.0,"mean_ccn":3.48,"p90_ccn":8.0,"complex_functions":4.0,"long_functions":1.0,"many_param_functions":0.0,"risky_nloc_share":0.1808},"findings":[],"evidence":[{"kind":"complex-function","description":"ModelSelectionStep in src/components/ModelSelectionStep.tsx: complexity 41, 245 lines","ref":"src/components/ModelSelectionStep.tsx","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/components/ModelSelectionStep.tsx#L58","weight":0.6833333333333333},{"kind":"complex-function","description":"attemptGeneration in src/hooks/useLLM.ts: complexity 21, 51 lines","ref":"src/hooks/useLLM.ts","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/hooks/useLLM.ts#L202","weight":0.35},{"kind":"complex-function","description":"(anonymous) in src/utils/transformer.ts: complexity 21, 42 lines","ref":"src/utils/transformer.ts","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/utils/transformer.ts#L141","weight":0.35},{"kind":"complex-function","description":"SecondaryButton in src/components/ui/Button.tsx: complexity 18, 59 lines","ref":"src/components/ui/Button.tsx","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/components/ui/Button.tsx#L25","weight":0.3}],"data":{},"error":null},{"analyzer":"qual-duplication","pillar":"quality","status":"ok","tool_version":"repotrust-dup-w6","metrics":{"compared_lines":2087.0,"duplicated_lines":72.0,"duplicated_share":0.0345,"files":30.0},"findings":[],"evidence":[{"kind":"duplicate-code","description":"6+ duplicated lines: src/hooks/useLLM.ts:224 and src/hooks/useLLM.ts:332","ref":"src/hooks/useLLM.ts","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/hooks/useLLM.ts#L224","weight":0.3},{"kind":"duplicate-code","description":"6+ duplicated lines: src/utils/csvExporter.ts:6 and src/utils/transformer.ts:123","ref":"src/utils/csvExporter.ts","url":"https://github.com/nathaishik/time-table-formaliser/blob/c54b7edaeae4dd2907421958241406f07a691515/src/utils/csvExporter.ts#L6","weight":0.3}],"data":{},"error":null},{"analyzer":"qual-lint","pillar":"quality","status":"ok","tool_version":"opengrep 1.33.1; rules f1d2b562b414","metrics":{"findings":14.0,"weighted_findings":13.0,"scanned_lines":2863.0,"category:best-practice":4.0,"category:correctness":10.0},"findings":[{"rule_id":"opengrep/typescript.lang.correctness.useless-ternary","severity":"high","message":"It looks like no matter how elevated is evaluated, this expression returns 'card'. This is probably a copy-paste error.","path":"src/components/ui/GlassCard.tsx","line":11,"fingerprint":"typescript.lang.correctness.useless-ternary:src/components/ui/GlassCard.tsx:11"},{"rule_id":"opengrep/typescript.react.best-practice.react-props-in-state","severity":"medium","message":"Copying a prop into state in React -- this is bad practice as all updates to it are ignored. Instead, read props directly in your component and avoid copying props into state.","path":"src/components/DuplicatesReview.tsx","line":18,"fingerprint":"typescript.react.best-practice.react-props-in-state:src/components/DuplicatesReview.tsx:18"},{"rule_id":"opengrep/typescript.react.best-practice.react-props-spreading","severity":"medium","message":"It's best practice to explicitly pass props to an HTML component rather than use the spread operator. The spread operator risks passing invalid HTML props to an HTML element, which can cause console warnings or worse, give malicious actors a way to inject unexpected attributes.","path":"src/components/ui/Button.tsx","line":17,"fingerprint":"typescript.react.best-practice.react-props-spreading:src/components/ui/Button.tsx:17"},{"rule_id":"opengrep/typescript.react.best-practice.react-props-spreading","severity":"medium","message":"It's best practice to explicitly pass props to an HTML component rather than use the spread operator. The spread operator risks passing invalid HTML props to an HTML element, which can cause console warnings or worse, give malicious actors a way to inject unexpected attributes.","path":"src/components/ui/Button.tsx","line":61,"fingerprint":"typescript.react.best-practice.react-props-spreading:src/components/ui/Button.tsx:61"},{"rule_id":"opengrep/typescript.react.best-practice.react-props-spreading","severity":"medium","message":"It's best practice to explicitly pass props to an HTML component rather than use the spread operator. The spread operator risks passing invalid HTML props to an HTML element, which can cause console warnings or worse, give malicious actors a way to inject unexpected attributes.","path":"src/components/ui/Button.tsx","line":86,"fingerprint":"typescript.react.best-practice.react-props-spreading:src/components/ui/Button.tsx:86"},{"rule_id":"opengrep/javascript.lang.correctness.no-stringify-keys","severity":"medium","message":"JSON stringify does not produce a stable key ordering, and should not be relied on for producing object keys. Consider using json-stable-stringify instead.","path":"src/hooks/useLLM.ts","line":97,"fingerprint":"javascript.lang.correctness.no-stringify-keys:src/hooks/useLLM.ts:97"},{"rule_id":"opengrep/javascript.lang.correctness.no-stringify-keys","severity":"medium","message":"JSON stringify does not produce a stable key ordering, and should not be relied on for producing object keys. Consider using json-stable-stringify instead.","path":"src/hooks/useLLM.ts","line":109,"fingerprint":"javascript.lang.correctness.no-stringify-keys:src/hooks/useLLM.ts:109"},{"rule_id":"opengrep/javascript.lang.correctness.no-stringify-keys","severity":"medium","message":"JSON stringify does not produce a stable key ordering, and should not be relied on for producing object keys. Consider using json-stable-stringify instead.","path":"src/hooks/useLLM.ts","line":129,"fingerprint":"javascript.lang.correctness.no-stringify-keys:src/hooks/useLLM.ts:129"},{"rule_id":"opengrep/javascript.lang.correctness.no-stringify-keys","severity":"medium","message":"JSON stringify does not produce a stable key ordering, and should not be relied on for producing object keys. Consider using json-stable-stringify instead.","path":"src/hooks/useLLM.ts","line":228,"fingerprint":"javascript.lang.correctness.no-stringify-keys:src/hooks/useLLM.ts:228"},{"rule_id":"opengrep/javascript.lang.correctness.no-stringify-keys","severity":"medium","message":"JSON stringify does not produce a stable key ordering, and should not be relied on for producing object keys. Consider using json-stable-stringify instead.","path":"src/hooks/useLLM.ts","line":336,"fingerprint":"javascript.lang.correctness.no-stringify-keys:src/hooks/useLLM.ts:336"},{"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":"src/hooks/useLLM.ts","line":164,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:src/hooks/useLLM.ts:164"},{"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":"src/hooks/useLLM.ts","line":164,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:src/hooks/useLLM.ts:164"},{"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":"src/hooks/useLLM.ts","line":308,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:src/hooks/useLLM.ts:308"},{"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":"src/hooks/useLLM.ts","line":308,"fingerprint":"javascript.lang.correctness.missing-template-string-indicator:src/hooks/useLLM.ts:308"}],"evidence":[],"data":{},"error":null},{"analyzer":"qual-testing","pillar":"quality","status":"ok","tool_version":null,"metrics":{"check:has_tests":0.0,"check:test_ratio":0.0,"check:ci_present":1.0,"check:ci_runs_tests":0.0,"check:ci_runs_lint":0.0,"check:tests_cochange":0.0,"test_lines":0.0,"source_lines":2863.0,"test_ratio":0.0,"ci_files":1.0,"cochange_share":0.0,"cochange_commits":8.0},"findings":[],"evidence":[{"kind":"ci","description":"CI config: .github/workflows/deploy.yml","ref":".github/workflows/deploy.yml","url":null,"weight":0.0}],"data":{"test_commands":[],"lint_commands":[]},"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":0.0,"readme_lines":28.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}],"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":32.0,"escapes_per_kloc":11.264},"findings":[],"evidence":[],"data":{},"error":null}],"flags":[]}