scip-query 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -1
- package/README.md +15 -1
- package/dist/{chunk-U3VMUDXJ.js → chunk-4SCMYKD6.js} +1 -1
- package/dist/chunk-YBGC7HTY.js +3 -0
- package/dist/cli.js +255 -248
- package/dist/{config-types-BrHl3Bge.d.ts → config-types-aCgyLrvE.d.ts} +2 -0
- package/dist/{db-_Bdx0E1W.d.ts → db-DwCdT3rv.d.ts} +1 -1
- package/dist/{health-BEZ1Rt0S.d.ts → health-nJUidasZ.d.ts} +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/queries/affected.d.ts +2 -2
- package/dist/queries/bottlenecks.d.ts +2 -2
- package/dist/queries/by-kind.d.ts +2 -2
- package/dist/queries/call-graph.d.ts +2 -2
- package/dist/queries/change-surface.d.ts +2 -2
- package/dist/queries/cleanup-plan.d.ts +2 -2
- package/dist/queries/co-change.d.ts +2 -2
- package/dist/queries/code.d.ts +2 -2
- package/dist/queries/complexity-hotspots.d.ts +2 -2
- package/dist/queries/complexity.d.ts +2 -2
- package/dist/queries/convergence.d.ts +2 -2
- package/dist/queries/coupling.d.ts +2 -2
- package/dist/queries/cycles.d.ts +2 -2
- package/dist/queries/dataflow.d.ts +2 -2
- package/dist/queries/dead.d.ts +2 -2
- package/dist/queries/decorative-checkers.d.ts +2 -2
- package/dist/queries/deep-chains.d.ts +2 -2
- package/dist/queries/deps.d.ts +2 -2
- package/dist/queries/diff-gate.d.ts +2 -2
- package/dist/queries/diff-gate.js +1 -1
- package/dist/queries/diff-impact.d.ts +2 -2
- package/dist/queries/doc-drift.d.ts +2 -2
- package/dist/queries/drift.d.ts +2 -2
- package/dist/queries/duplicate-bodies.d.ts +2 -2
- package/dist/queries/extract-candidates.d.ts +2 -2
- package/dist/queries/fan.d.ts +2 -2
- package/dist/queries/files.d.ts +2 -2
- package/dist/queries/health.d.ts +3 -3
- package/dist/queries/health.js +1 -1
- package/dist/queries/hierarchy.d.ts +2 -2
- package/dist/queries/hotspots.d.ts +2 -2
- package/dist/queries/imports.d.ts +2 -2
- package/dist/queries/incomplete-migration.d.ts +2 -2
- package/dist/queries/index.d.ts +3 -3
- package/dist/queries/index.js +1 -1
- package/dist/queries/isolated.d.ts +2 -2
- package/dist/queries/locality-candidates.d.ts +2 -2
- package/dist/queries/members.d.ts +2 -2
- package/dist/queries/methods.d.ts +2 -2
- package/dist/queries/not-implemented.d.ts +2 -2
- package/dist/queries/outline.d.ts +2 -2
- package/dist/queries/passthrough-candidates.d.ts +2 -2
- package/dist/queries/plan-context.d.ts +2 -2
- package/dist/queries/react-component-duplicates.d.ts +2 -2
- package/dist/queries/react-hook-candidates.d.ts +2 -2
- package/dist/queries/react-large-component-pressure.d.ts +2 -2
- package/dist/queries/recent-duplicates.d.ts +2 -2
- package/dist/queries/redundant-reexports.d.ts +2 -2
- package/dist/queries/refs.d.ts +2 -2
- package/dist/queries/self-audit.d.ts +2 -2
- package/dist/queries/similar-chains.d.ts +2 -2
- package/dist/queries/similar-files.d.ts +2 -2
- package/dist/queries/similar-signatures.d.ts +2 -2
- package/dist/queries/similar.d.ts +2 -2
- package/dist/queries/slice.d.ts +2 -2
- package/dist/queries/stale-abstractions.d.ts +2 -2
- package/dist/queries/stats.d.ts +2 -2
- package/dist/queries/surface.d.ts +2 -2
- package/dist/queries/symbols.d.ts +2 -2
- package/dist/queries/system.d.ts +2 -2
- package/dist/queries/test-quality.d.ts +2 -2
- package/dist/queries/trace.d.ts +2 -2
- package/dist/queries/twin-ab.d.ts +2 -2
- package/dist/queries/twin-drift.d.ts +2 -2
- package/dist/queries/unused-imports.d.ts +2 -2
- package/dist/queries/unused-params.d.ts +2 -2
- package/dist/queries/vue-component-duplicates.d.ts +2 -2
- package/dist/queries/vue-composable-candidates.d.ts +2 -2
- package/dist/queries/vue-large-view-pressure.d.ts +2 -2
- package/dist/queries/wrapper-candidates.d.ts +2 -2
- package/dist/reindex.d.ts +3 -3
- package/dist/runtime.d.ts +3 -3
- package/dist/runtime.js +2 -2
- package/dist/{scip-cli-C7cg4ZHR.d.ts → scip-cli-DeAbuJ2b.d.ts} +1 -1
- package/docs/COMMAND_REFERENCE.md +2 -1
- package/package.json +1 -1
- package/skills/_shared/SKILL.md +3 -1
- package/skills/scip-calibrate/SKILL.md +7 -3
- package/skills/scip-verify/SKILL.md +6 -1
- package/dist/chunk-XC2PJOVM.js +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `scip-query` are documented here. This file starts at 0.11.0; everything below covers behavior changes made since the 0.10.12 release.
|
|
4
4
|
|
|
5
|
-
## [0.
|
|
5
|
+
## [0.15.0]
|
|
6
|
+
|
|
7
|
+
### Breaking (behavior change for one command)
|
|
8
|
+
|
|
9
|
+
- **`suppress` writes one file per suppression instead of appending to `.scipquery.json`.** New suppressions land in `.scipquery/suppressions/<finding-id>.json` (check-level suppressions get a stable `CHECK-<hash>.json` name), stamped with `createdAt`. One-file-per-suppression makes concurrent branches merge without conflict and stops the config file from churning on every acceptance. Existing `suppressions[]` entries in `.scipquery.json` keep working (the gate reads both stores, identical matching semantics) — they are just no longer written. Commit the suppression files with your change.
|
|
10
|
+
|
|
11
|
+
### Notable (new capabilities)
|
|
12
|
+
|
|
13
|
+
- **Committed outcome-event ledger.** Hook-mode `diff-gate` runs now mirror finding transitions (caught / resolved / suppressed / reopened) into `.scipquery/ledger/events.jsonl` — an append-only, one-event-per-line log stamped with the HEAD commit and, when known, the finding's SCIP symbol. A scoped `.gitattributes` (`merge=union`) is written alongside it, so concurrent appends from different branches merge without conflict; read-side dedupe by `(check, findingId, event, commit)` absorbs replays. Unlike the per-machine `evidence.db` ledger, this file is meant to be committed: outcome history survives re-clones and aggregates across every machine and agent working the repo. Ledger writes never block the hook — failures degrade to a stderr note.
|
|
14
|
+
- **New command: `effectiveness`.** Reads the committed event ledger and reports, per diff-gate check: findings caught, fixed by code changes (disappeared without a suppression), suppressed, still open, reopened, `moved` (rename noise — a resolved id whose symbol was re-caught under a new id at the same commit), precision (fixed ÷ concluded), and median days-to-fix. `--since 30d|12w|<ISO date>` windows by when the finding was caught, `--check <name>` filters, `--json` emits the standard envelope. This is the tool keeping score on itself: suppressions count against a detector's precision, fixes count for it.
|
|
6
15
|
|
|
7
16
|
### Breaking (behavior change for one config key)
|
|
8
17
|
|
package/README.md
CHANGED
|
@@ -224,7 +224,21 @@ Accepted findings can be recorded without weakening the rest of the gate:
|
|
|
224
224
|
scip-query suppress SQABC123DEF456 --check echo --reason "intentional compatibility shim"
|
|
225
225
|
```
|
|
226
226
|
|
|
227
|
-
This
|
|
227
|
+
This writes one file per suppression under `.scipquery/suppressions/` — commit it with your change. One-file-per-suppression means two branches suppressing different findings merge without conflict; the legacy `suppressions[]` array in `.scipquery.json` is still honored (read-only). Every suppression requires a reason plus either a stable finding id or a `check` (optionally narrowed by `file`). Check+file suppressions are allowed but warn because they waive every matching finding in that file. `diff-gate --json` reports both active and suppressed findings.
|
|
228
|
+
|
|
229
|
+
**12. Measure whether the gate is earning its keep.** Every hook-mode `diff-gate` run appends finding transitions to a committed, merge-conflict-free ledger (`.scipquery/ledger/events.jsonl`, one JSON event per line under a scoped `merge=union` gitattribute). A finding that disappears without a suppression was fixed; a suppressed finding was noise or an accepted trade-off — the tool keeps score on itself:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
scip-query effectiveness --since 30d
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
check caught fixed suppressed open moved precision median-days-to-fix
|
|
237
|
+
echo 14 11 2 1 0 85% 0.8
|
|
238
|
+
new-dead 6 5 0 1 0 100% 0.3
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
`precision` is fixed ÷ (fixed + suppressed) — how often acting on the check was the right call. `moved` separates rename churn from real fixes. Filter with `--check <name>`, window with `--since 30d|12w|<ISO date>`, and get machine-readable output with `--json`. Because the ledger is committed, the numbers survive re-clones and aggregate across every machine and agent working the repo.
|
|
228
242
|
|
|
229
243
|
Before any edit, `plan-context <target>` bundles the structural picture — definitions, references, call graph, blast radius — plus a HISTORY section: churn, fix-commit density, and the files that usually change together with the target ("editing this usually means editing these").
|
|
230
244
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{a as ae}from"./chunk-7JZRFDCU.js";import{a as ue}from"./chunk-R5336VHZ.js";import{a as ne}from"./chunk-ZMGBWSFZ.js";import{a as se}from"./chunk-URSSPS5H.js";import{a as ce}from"./chunk-TG7QSYCJ.js";import{a as ie}from"./chunk-5AAAEZ2Z.js";import{a as oe}from"./chunk-J5WVNZ6O.js";import{b as G,e as m}from"./chunk-ZEO4CXQR.js";import{a as te}from"./chunk-27XEGMCT.js";import{a as Z}from"./chunk-6JUAGXR4.js";import{a as ee}from"./chunk-C2QSK7E7.js";import{a as Q}from"./chunk-6KMTPNZL.js";import{a as X}from"./chunk-JJUX2OAP.js";import{a as Y}from"./chunk-X3DTIEMU.js";import{a as K}from"./chunk-2XRXEIRK.js";import{b as W}from"./chunk-HZZQKNVE.js";import{a as U}from"./chunk-3AMWF6V5.js";import{a as A,b as q}from"./chunk-QVGFVRKD.js";import{b as N}from"./chunk-IUSSGHJO.js";import{a as z}from"./chunk-7COVQPQQ.js";import{a as re}from"./chunk-XDESMVOL.js";import{f as J}from"./chunk-KSJ544IV.js";import{a as j}from"./chunk-LY7NMOBW.js";import{f as k,g as M}from"./chunk-BZXE3HO4.js";import{h as _}from"./chunk-WS3Z6W3M.js";function de(e,r){let t=new Map;for(let o of e){let n=t.get(o.check)??[];n.push(o),t.set(o.check,n)}let i=[];for(let[o,n]of t){let c=n.filter(d=>d.outcome==="resolved").length,s=n.filter(d=>d.outcome==="suppressed").length,l=n.filter(d=>d.outcome==="still-open").length,h=n.length,C=n.filter(d=>d.outcome==="still-open").sort((d,b)=>d.firstSeen-b.firstSeen)[0];i.push({check:o,seen:h,resolved:c,suppressed:s,stillOpen:l,resolutionRate:h>0?c/h:0,suppressionRate:h>0?s/h:0,oldestOpenAgeDays:C?Math.floor((r-C.firstSeen)/Ie):null})}return i.sort((o,n)=>o.check.localeCompare(n.check))}var Ie=864e5;function le(e){return _(e).map(r=>({check:r.check,findingId:r.findingId,firstSeen:r.firstSeen,lastSeen:r.lastSeen,timesShown:r.timesShown,outcome:r.outcome}))}function f(e){return e.scoreCount??e.count}function B(e){let r=ze(e),{breakdown:t,pressure:i}=Ne(e),o=me(t,"risk"),n=me(t,"hygiene");return{score:Math.min(o,n),riskScore:o,hygieneScore:n,scoreBreakdown:t,overview:{documents:e.statsResult.documents,symbols:e.statsResult.symbols,indexSizeBytes:e.statsResult.indexSizeBytes},findings:{deadSymbols:e.dead.count,deadLoc:e.dead.loc,isolatedSymbols:e.isolated.count,isolatedLoc:e.isolated.loc,cycles:e.realCycleCount,similarPairs:e.similarCount,duplicateBodyGroups:e.duplicateBodies.count,duplicateBodyLoc:e.duplicateBodies.loc,twinDriftGroups:e.twinDrift.count,twinDriftLoc:e.twinDrift.loc,reactComponentDuplicatePairs:e.reactComponentDuplicates.count,reactHookCandidatePairs:e.reactHookCandidates.count,reactHookCandidateScoreCount:f(e.reactHookCandidates),reactLargeComponentPressureFiles:e.reactLargeComponentPressure.count,vueComponentDuplicatePairs:e.vueComponentDuplicates.count,vueComposableCandidatePairs:e.vueComposableCandidates.count,vueComposableCandidateScoreCount:f(e.vueComposableCandidates),vueLargeViewPressureFiles:e.vueLargeViewPressure.count,extractionCandidates:e.extractCount,wrappers:e.wrappers.count,wrapperScoreCount:f(e.wrappers),passthroughs:e.passthroughs.count,staleTypes:e.stale.count,driftedFiles:e.drift.count,complexityHotspotCount:e.complexity.extremeCount,hiddenCouplingPairs:e.gitEvidence?.hiddenCoupling.pairCount??null,hiddenCouplingScoreCount:e.gitEvidence?.hiddenCoupling.scoreCount??null,coverageContractViolations:e.coverageContracts.count},axes:Oe(e),validation:_e(e),suppressions:e.suppressions,actions:r,pressure:i,topComplexity:e.complexity.top,warnings:e.warnings.length>0?e.warnings:void 0,detectorPrecision:[]}}function Oe(e){return{deletable:{loc:e.dead.loc+e.isolated.loc,symbols:e.dead.count+e.isolated.count},cycles:{count:e.realCycleCount},changeAmplification:e.gitEvidence?.amplification??null,hiddenCoupling:e.gitEvidence?.hiddenCoupling??null,churnWeightedComplexity:Ve(e),evidenceQuality:{graphFindings:e.dead.count+e.isolated.count+e.realCycleCount,heuristicFindings:e.similarCount+e.duplicateBodies.count+e.twinDrift.count+e.reactComponentDuplicates.count+e.reactHookCandidates.count+e.reactLargeComponentPressure.count+e.vueComponentDuplicates.count+e.vueComposableCandidates.count+e.vueLargeViewPressure.count+e.extractCount+e.wrappers.count+e.passthroughs.count+e.stale.count+e.drift.count,userSuppressed:e.suppressions?.total??0}}}function Ve(e){let r=e.gitEvidence?.fileStats;return r?e.complexity.top.map(t=>{let i=t.file?r[t.file]?.changes??0:0;return{...t,changes:i,weighted:g(t.score*Math.log2(1+i))}}).sort((t,i)=>i.weighted-t.weighted):null}function _e(e){let r=e.gitEvidence?.fileStats;if(!r)return null;let t={dead:e.dead.files??[],isolated:e.isolated.files??[],twinDrift:e.twinDrift.files??[],wrappers:e.wrappers.files??[],passthroughs:e.passthroughs.files??[],stale:e.stale.files??[],reactComponents:e.reactComponentDuplicates.files??[],reactHooks:e.reactHookCandidates.files??[],reactLargeComponents:e.reactLargeComponentPressure.files??[],vueComponents:e.vueComponentDuplicates.files??[],vueComposables:e.vueComposableCandidates.files??[],vueLargeViews:e.vueLargeViewPressure.files??[]},i=new Set(Object.values(t).flat()),o=0,n=0,c=0;for(let[C,d]of Object.entries(r))i.has(C)?o+=d.fixChanges:(n+=d.fixChanges,c+=1);let s=i.size>0?g(o/i.size):0,l=c>0?g(n/c):0,h={};for(let[C,d]of Object.entries(t)){let b=new Set(d);if(b.size===0)continue;let S=0;for(let R of b)S+=r[R]?.fixChanges??0;let x=g(S/b.size);h[C]={flaggedFiles:b.size,fixDensity:x,lift:l>0?g(x/l):null}}return{flaggedFiles:i.size,flaggedFixDensity:s,baselineFixDensity:l,ratio:i.size>0&&l>0?g(s/l):null,byCategory:h,validationBasis:{method:"subject-regex",commitsScanned:e.gitEvidence?.commitsScanned??0}}}function g(e){return Math.round(e*100)/100}function he(e){return Number.isInteger(e)?String(e):e.toFixed(2).replace(/0+$/,"").replace(/\.$/,"")}function y(e,r="existing shared infrastructure discount"){let t=f(e);return Math.abs(t-e.count)<.01?"":` (${he(t)} score-weighted after ${r})`}function w(e,r){let t=f(e),i=`${e.count} ${r}`;return Math.abs(t-e.count)<.01?i:`${i} (${he(t)} score-weighted)`}function ze(e){let r=[];if(e.dead.count>0&&r.push({category:"Dead code",evidence:"graph-fact",description:`${e.dead.count} symbols with zero references anywhere -- deletion candidates; confirm with cleanup-plan --verify before deleting`,effort:"low",impact:"high",count:e.dead.count,locRecoverable:e.dead.loc}),e.isolated.count>0&&r.push({category:"Isolated symbols",evidence:"graph-fact",description:`${e.isolated.count} symbols completely disconnected from the codebase graph`,effort:"low",impact:"medium",count:e.isolated.count,locRecoverable:e.isolated.loc}),e.realCycleCount>0&&r.push({category:"Circular dependencies",evidence:"graph-fact",description:`${e.realCycleCount} cycle(s) \u2014 break with dependency inversion or module restructuring`,effort:"medium",impact:"high",count:e.realCycleCount,locRecoverable:0}),e.similarCount>0&&r.push({category:"Similar functions",evidence:"heuristic",description:`${e.similarCount} pairs with real logic overlap (beyond shared imports) \u2014 consolidation candidates`,effort:"medium",impact:"medium",count:e.similarCount,locRecoverable:0}),e.duplicateBodies.count>0&&r.push({category:"Duplicate function bodies",evidence:"heuristic",description:`${e.duplicateBodies.count} exact small-body group(s) across files \u2014 consolidate only when the domain concept matches`,effort:"low",impact:"medium",count:e.duplicateBodies.count,locRecoverable:e.duplicateBodies.loc}),e.twinDrift.count>0&&r.push({category:"Drifted twin implementations",evidence:"heuristic",description:`${e.twinDrift.count} same-name (or near-name) function group(s) across files with diverged or identical bodies \u2014 the same concept implemented twice; consolidate or verify the drift is intentional`,effort:"medium",impact:"medium",count:e.twinDrift.count,locRecoverable:0}),e.reactComponentDuplicates.count>0&&r.push({category:"Duplicated React components",evidence:"heuristic",description:`${e.reactComponentDuplicates.count} React component pair(s) share JSX structure \u2014 extract or reuse the shared UI concept`,effort:"medium",impact:"medium",count:e.reactComponentDuplicates.count,locRecoverable:e.reactComponentDuplicates.loc}),e.reactHookCandidates.count>0&&r.push({category:"Duplicated React hook behavior",evidence:"heuristic",description:`${e.reactHookCandidates.count} React component pair(s) share state/effect/request behavior${y(e.reactHookCandidates)} \u2014 extract or reuse a hook`,effort:"medium",impact:"medium",count:e.reactHookCandidates.count,locRecoverable:e.reactHookCandidates.loc}),e.reactLargeComponentPressure.count>0&&r.push({category:"Large React components",evidence:"heuristic",description:`${e.reactLargeComponentPressure.count} React component(s) concentrate JSX/behavior pressure \u2014 split by reason to change`,effort:"medium",impact:"medium",count:e.reactLargeComponentPressure.count,locRecoverable:0}),e.vueComponentDuplicates.count>0&&r.push({category:"Duplicated Vue components",evidence:"heuristic",description:`${e.vueComponentDuplicates.count} Vue component pair(s) share template structure \u2014 extract or reuse the shared UI concept`,effort:"medium",impact:"medium",count:e.vueComponentDuplicates.count,locRecoverable:e.vueComponentDuplicates.loc}),e.vueComposableCandidates.count>0&&r.push({category:"Duplicated Vue behavior",evidence:"heuristic",description:`${e.vueComposableCandidates.count} Vue component pair(s) share state/effect/request behavior${y(e.vueComposableCandidates)} \u2014 extract or reuse a composable`,effort:"medium",impact:"medium",count:e.vueComposableCandidates.count,locRecoverable:e.vueComposableCandidates.loc}),e.vueLargeViewPressure.count>0&&r.push({category:"Large Vue views",evidence:"heuristic",description:`${e.vueLargeViewPressure.count} Vue file(s) concentrate template/script/style pressure \u2014 split by reason to change`,effort:"medium",impact:"medium",count:e.vueLargeViewPressure.count,locRecoverable:0}),e.extractCount>0&&r.push({category:"Extraction candidates",evidence:"heuristic",description:`${e.extractCount} large functions with isolated callee clusters \u2014 review same-file or feature-local extraction seams`,effort:"medium",impact:"medium",count:e.extractCount,locRecoverable:0}),e.wrappers.count>0&&r.push({category:"Wrapper functions",evidence:"heuristic",description:`${e.wrappers.count} single-consumer symbols${y(e.wrappers,"boundary-evidence discount")} \u2014 inline direct wrappers or review boundary signals`,effort:"low",impact:"low",count:e.wrappers.count,locRecoverable:e.wrappers.loc}),e.passthroughs.count>0&&r.push({category:"Passthrough functions",evidence:"heuristic",description:`${e.passthroughs.count} functions that just forward to one callee \u2014 unnecessary indirection`,effort:"low",impact:"low",count:e.passthroughs.count,locRecoverable:e.passthroughs.loc}),e.stale.count>0){let o=[];e.stale.unused>0&&o.push(`${e.stale.unused} unused`),e.stale.singleUse>0&&o.push(`${e.stale.singleUse} single-consumer (not in types file)`),r.push({category:"Stale abstractions",evidence:"heuristic",description:`${o.join(", ")} \u2014 remove unused abstractions; review single-consumer ownership before moving or inlining`,effort:"low",impact:"medium",count:e.stale.count,locRecoverable:e.stale.loc})}if(e.drift.count>0){let o=[];e.drift.unusedImports>0&&o.push(`${e.drift.unusedImports} unused imports`),e.drift.layerViolations>0&&o.push(`${e.drift.layerViolations} layer violations`),r.push({category:"Structural drift",evidence:"heuristic",description:`${o.join(", ")} \u2014 remove direct drift; review signal drift against layer ownership`,effort:e.drift.layerViolations>0?"medium":"low",impact:e.drift.layerViolations>0?"medium":"low",count:e.drift.count,locRecoverable:0})}if(e.coverageContracts.count>0&&r.push({category:"Coverage contract drift",evidence:"graph-fact",description:`${e.coverageContracts.count} configured coverage contract(s) drifted from their ground-truth source (enumeration rot) \u2014 run \`scip-query diff-gate\` or \`scip-query health --json\` for the missing/extra keys`,effort:"low",impact:"medium",count:e.coverageContracts.count,locRecoverable:0}),e.gitEvidence&&e.gitEvidence.hiddenCoupling.pairCount>0){let o=e.gitEvidence.hiddenCoupling.top[0];r.push({category:"Hidden coupling",evidence:"change-graph",description:`${e.gitEvidence.hiddenCoupling.pairCount} file pair(s) co-change without a structural link`+y({count:e.gitEvidence.hiddenCoupling.pairCount,scoreCount:e.gitEvidence.hiddenCoupling.scoreCount},"broad/stale-history discount")+(o?` (e.g. ${o.fileA} \u2194 ${o.fileB})`:"")+" \u2014 name the shared concept or enforce the sync",effort:"medium",impact:"high",count:e.gitEvidence.hiddenCoupling.pairCount,locRecoverable:0})}let t={high:3,medium:2,low:1},i={low:3,medium:2,high:1};return r.sort((o,n)=>{let c=t[o.impact]*i[o.effort];return t[n.impact]*i[n.effort]-c}),r}var pe={"dead-code":"risk",isolated:"risk",cycles:"risk",complexity:"risk","hidden-coupling":"risk","cycles-pressure":"risk","complexity-pressure":"risk","hidden-coupling-pressure":"risk",similar:"hygiene","duplicate-bodies":"hygiene","twin-drift":"hygiene","react-component-duplicates":"hygiene","react-hook-candidates":"hygiene","react-large-component-pressure":"hygiene","vue-component-duplicates":"hygiene","vue-composable-candidates":"hygiene","vue-large-view-pressure":"hygiene",extract:"hygiene",wrappers:"hygiene",passthroughs:"hygiene","stale-abstractions":"hygiene",drift:"hygiene","similar-pressure":"hygiene","duplicate-bodies-pressure":"hygiene","twin-drift-pressure":"hygiene","react-component-duplicates-pressure":"hygiene","react-hook-candidates-pressure":"hygiene","react-large-component-pressure-pressure":"hygiene","vue-component-duplicates-pressure":"hygiene","vue-composable-candidates-pressure":"hygiene","vue-large-view-pressure-pressure":"hygiene","extract-pressure":"hygiene","wrappers-pressure":"hygiene","passthroughs-pressure":"hygiene","stale-abstractions-pressure":"hygiene","drift-pressure":"hygiene"};function me(e,r){let t=e.filter(i=>i.kind===r).reduce((i,o)=>i+o.points,0);return Math.max(0,Math.min(100,100-t))}function Ne(e){let r=Math.max(e.statsResult.documents,1),t=Math.max(e.statsResult.symbols,1),i=[],o=[],n=(p,H,v)=>{H>0&&i.push({axis:p,points:H,detail:v,kind:pe[p]??"hygiene"})},c=(p,H,v,Ae,Be,Te,Fe)=>{let L=Math.max(Ae,1);if(v<=L)return;let P=v/L,E=Math.min(Be,Math.ceil(Math.log2(P)*Te));if(E<=0)return;let $e=pe[p]??"hygiene";o.push({axis:p,category:H,kind:$e,count:v,threshold:g(L),ratio:g(P),extraPenalty:E}),n(p,E,`${v} ${Fe} exceed pressure threshold ${g(L)} (${g(P)}x)`)},s=e.dead.count/t;n("dead-code",Math.min(20,Math.round(s*200)),`${e.dead.count} dead symbols (${e.dead.loc} LOC deletable)`);let l=e.isolated.count/t;n("isolated",Math.min(10,Math.round(l*200)),`${e.isolated.count} isolated symbols (${e.isolated.loc} LOC deletable)`),n("cycles",Math.min(15,e.realCycleCount*5),`${e.realCycleCount} real dependency cycle(s)`);let h=e.similarCount/t*1e3;n("similar",Math.min(10,Math.round(h)),`${e.similarCount} similar function pair(s)`);let C=e.duplicateBodies.count/t*1e3;n("duplicate-bodies",Math.min(10,Math.round(C*2)),`${e.duplicateBodies.count} exact duplicate small-body group(s) (${e.duplicateBodies.loc} duplicate LOC)`);let d=e.twinDrift.count/t*1e3;n("twin-drift",Math.min(10,Math.round(d*2)),`${e.twinDrift.count} drifted twin implementation group(s) (same or near-same name, diverged or identical bodies)`);let b=e.reactComponentDuplicates.count/r*1e3;n("react-component-duplicates",Math.min(10,Math.round(b)),`${e.reactComponentDuplicates.count} duplicated React component pair(s)`);let S=f(e.reactHookCandidates),x=S/r*1e3;n("react-hook-candidates",Math.min(10,Math.round(x)),w(e.reactHookCandidates,"duplicated React behavior pair(s)"));let R=e.reactLargeComponentPressure.count/r*1e3;n("react-large-component-pressure",Math.min(5,Math.round(R/2)),`${e.reactLargeComponentPressure.count} large React component pressure file(s)`);let Pe=e.vueComponentDuplicates.count/r*1e3;n("vue-component-duplicates",Math.min(10,Math.round(Pe)),`${e.vueComponentDuplicates.count} duplicated Vue component pair(s)`);let I=f(e.vueComposableCandidates),Ee=I/r*1e3;n("vue-composable-candidates",Math.min(10,Math.round(Ee)),w(e.vueComposableCandidates,"duplicated Vue behavior pair(s)"));let ke=e.vueLargeViewPressure.count/r*1e3;n("vue-large-view-pressure",Math.min(5,Math.round(ke/2)),`${e.vueLargeViewPressure.count} large Vue view pressure file(s)`);let O=f(e.wrappers);n("wrappers",Math.min(3,O),w(e.wrappers,"wrapper candidate(s)"));let V=f(e.passthroughs);n("passthroughs",Math.min(3,V),w(e.passthroughs,"passthrough candidate(s)")),n("stale-abstractions",Math.min(8,e.stale.unused),`${e.stale.unused} unused stale abstraction(s); ${e.stale.singleUse} single-consumer signal(s)`);let Me=e.drift.direct/r;if(n("drift",Math.min(5,Math.round(Me*50)),`${e.drift.direct} direct drift finding(s); ${e.drift.signal} signal drift finding(s)`),n("complexity",Math.min(5,e.complexity.extremeCount*2),`${e.complexity.extremeCount} extreme complexity hotspot(s)`),e.gitEvidence){let p=e.gitEvidence.hiddenCoupling.scoreCount;n("hidden-coupling",Math.min(5,Math.ceil(p/10)),w({count:e.gitEvidence.hiddenCoupling.pairCount,scoreCount:p},"co-changing pair(s) without a structural link"))}if(c("cycles-pressure","Circular dependencies",e.realCycleCount,3,10,3,"cycle(s)"),c("complexity-pressure","Extreme complexity",e.complexity.extremeCount,3,5,2,"extreme complexity hotspot(s)"),e.gitEvidence){let p=e.gitEvidence.hiddenCoupling.scoreCount;c("hidden-coupling-pressure","Hidden coupling",p,50,10,4,"score-weighted co-changing pair(s)")}return c("similar-pressure","Similar functions",e.similarCount,Math.max(50,t*.01),8,4,"similar function pair(s)"),c("duplicate-bodies-pressure","Duplicate function bodies",e.duplicateBodies.count,Math.max(20,t*.005),8,4,"exact duplicate small-body group(s)"),c("twin-drift-pressure","Drifted twin implementations",e.twinDrift.count,Math.max(20,t*.005),8,4,"drifted twin implementation group(s)"),c("react-component-duplicates-pressure","Duplicated React components",e.reactComponentDuplicates.count,Math.max(10,r*.01),8,4,"duplicated React component pair(s)"),c("react-hook-candidates-pressure","Duplicated React hook behavior",S,Math.max(10,r*.01),8,4,"duplicated React behavior pair(s)"),c("react-large-component-pressure-pressure","Large React components",e.reactLargeComponentPressure.count,Math.max(10,r*.01),4,2,"large React component pressure file(s)"),c("vue-component-duplicates-pressure","Duplicated Vue components",e.vueComponentDuplicates.count,Math.max(10,r*.01),8,4,"duplicated Vue component pair(s)"),c("vue-composable-candidates-pressure","Duplicated Vue behavior",I,Math.max(10,r*.01),8,4,"duplicated Vue behavior pair(s)"),c("vue-large-view-pressure-pressure","Large Vue views",e.vueLargeViewPressure.count,Math.max(10,r*.01),4,2,"large Vue view pressure file(s)"),c("extract-pressure","Extraction candidates",e.extractCount,Math.max(50,t*.01),4,2,"extraction candidate(s)"),c("wrappers-pressure","Wrapper functions",O,50,4,2,"wrapper candidate(s)"),c("passthroughs-pressure","Passthrough functions",V,50,4,2,"passthrough candidate(s)"),c("stale-abstractions-pressure","Single-consumer stale abstraction signals",e.stale.singleUse,Math.max(50,t*.02),4,2,"single-consumer stale abstraction signal(s)"),c("drift-pressure","Structural drift signals",e.drift.signal,Math.max(10,r*.1),4,2,"signal drift finding(s)"),{breakdown:i,pressure:o}}import{getHeapStatistics as Ue}from"v8";var We=64*1024*1024;function T(){let e=globalThis.gc;if(!e)return;let r=Ue();r.heap_size_limit-r.used_heap_size<We||e()}var Ge=50,je=25e3,qe=2500,ge=2500,fe=50,Ye=10,Ke=["overview","dead","isolated","cycles","similar","duplicate-bodies","twin-drift","react-component-duplicates","react-hook-candidates","react-large-component-pressure","vue-component-duplicates","vue-composable-candidates","vue-large-view-pressure","extract-candidates","wrapper-candidates","passthrough-candidates","stale-abstractions","drift","complexity-hotspots","git-evidence","suppressions","coverage-contracts"],ve={overview:(e,r,t,i)=>({phase:"overview",statsResult:i,warnings:t.warnings}),dead:(e,r,t)=>({phase:"dead",dead:Je(e,r,t)}),isolated:(e,r,t)=>({phase:"isolated",isolated:Ze(e,r,t)}),cycles:(e,r,t)=>({phase:"cycles",realCycleCount:et(e,r,t)}),similar:(e,r,t)=>({phase:"similar",similarCount:tt(e,r,t)}),"duplicate-bodies":(e,r,t)=>({phase:"duplicate-bodies",duplicateBodies:it(e,r,t)}),"twin-drift":(e,r,t)=>({phase:"twin-drift",twinDrift:ot(e,r,t)}),"react-component-duplicates":(e,r,t)=>({phase:"react-component-duplicates",reactComponentDuplicates:nt(e,r,t)}),"react-hook-candidates":(e,r,t)=>({phase:"react-hook-candidates",reactHookCandidates:ct(e,r,t)}),"react-large-component-pressure":(e,r,t)=>({phase:"react-large-component-pressure",reactLargeComponentPressure:st(e,r,t)}),"vue-component-duplicates":(e,r,t)=>({phase:"vue-component-duplicates",vueComponentDuplicates:at(e,r,t)}),"vue-composable-candidates":(e,r,t)=>({phase:"vue-composable-candidates",vueComposableCandidates:ut(e,r,t)}),"vue-large-view-pressure":(e,r,t)=>({phase:"vue-large-view-pressure",vueLargeViewPressure:dt(e,r,t)}),"extract-candidates":(e,r,t)=>({phase:"extract-candidates",extractCount:rt(e,r,t)}),"wrapper-candidates":(e,r,t)=>({phase:"wrapper-candidates",wrappers:lt(e,r,t)}),"passthrough-candidates":(e,r,t)=>({phase:"passthrough-candidates",passthroughs:pt(e,r,t)}),"stale-abstractions":(e,r,t)=>({phase:"stale-abstractions",stale:mt(e,r,t)}),drift:(e,r,t)=>({phase:"drift",drift:Ct(e,r,t)}),"complexity-hotspots":(e,r,t)=>({phase:"complexity-hotspots",complexity:bt(e,r,t)}),"git-evidence":(e,r,t)=>({phase:"git-evidence",gitEvidence:ht(e,t)}),suppressions:(e,r,t)=>({phase:"suppressions",suppressions:gt(e,t)}),"coverage-contracts":(e,r,t)=>({phase:"coverage-contracts",coverageContracts:ft(e,t)})};function dr(e,r={}){return Se(e,r.full!==!1,(t,i)=>{let o=Qe(e,r.scope,t,i),n=B(o);return n.detectorPrecision=de(le(e),Date.now()),n})}function lr(e,r,t={}){return Xe(e,[r],t)[0]}function Xe(e,r,t={}){return Se(e,t.full!==!1,(i,o)=>{let n={...o,releaseCachesBetweenPhases:!1};return r.map(c=>ve[c](e,t.scope,n,i))})}function Se(e,r,t){let i=ee(e),o=vt(i,r);try{return t(i,o)}finally{A(e,{semanticProvider:!0}),T()}}function pr(e){return B(we(e))}function we(e){let r=u(e,"overview");return{statsResult:r.statsResult,warnings:r.warnings,dead:u(e,"dead").dead,isolated:u(e,"isolated").isolated,realCycleCount:u(e,"cycles").realCycleCount,similarCount:u(e,"similar").similarCount,duplicateBodies:u(e,"duplicate-bodies").duplicateBodies,twinDrift:u(e,"twin-drift").twinDrift,reactComponentDuplicates:u(e,"react-component-duplicates").reactComponentDuplicates,reactHookCandidates:u(e,"react-hook-candidates").reactHookCandidates,reactLargeComponentPressure:u(e,"react-large-component-pressure").reactLargeComponentPressure,vueComponentDuplicates:u(e,"vue-component-duplicates").vueComponentDuplicates,vueComposableCandidates:u(e,"vue-composable-candidates").vueComposableCandidates,vueLargeViewPressure:u(e,"vue-large-view-pressure").vueLargeViewPressure,extractCount:u(e,"extract-candidates").extractCount,wrappers:u(e,"wrapper-candidates").wrappers,passthroughs:u(e,"passthrough-candidates").passthroughs,stale:u(e,"stale-abstractions").stale,drift:u(e,"drift").drift,complexity:u(e,"complexity-hotspots").complexity,gitEvidence:Ce(e,"git-evidence")?.gitEvidence??null,suppressions:Ce(e,"suppressions")?.suppressions??null,coverageContracts:u(e,"coverage-contracts").coverageContracts}}function Ce(e,r){return e.find(t=>t.phase===r)}function u(e,r){let t=e.find(i=>i.phase===r);if(!t)throw new Error(`Missing health phase result: ${r}`);return t}function Qe(e,r,t,i){return we(Ke.map(o=>ve[o](e,r,i,t)))}function Je(e,r,t){return a(e,t,"dead",()=>{let i=q(e,{scope:r,...m.dead,scanLimit:t.candidateScanLimit});return D(xt(e,i.symbols))})}function Ze(e,r,t){return a(e,t,"isolated",()=>{let i=X(e,{scope:r,...m.isolated,scanLimit:t.candidateScanLimit});return D(Ht(e,i))})}function et(e,r,t){return a(e,t,"cycles",()=>j(e,{scope:r}).filter(o=>o.kind==="real").length)}function tt(e,r,t){let i=a(e,t,"similar",()=>J(e,{scope:r,...m.similar,scanLimit:t.candidateScanLimit}));return Math.min(i,t.candidateResultLimit)}function rt(e,r,t){return a(e,t,"extract-candidates",()=>K(e,{scope:r,...m.extract,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit}).length)}function it(e,r,t){return a(e,t,"duplicate-bodies",()=>{let i=U(e,{scope:r,...m.duplicateBodies,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit}),o=new Set,n=0;for(let c of i)for(let s of c.functions.slice(1))o.add(s.file),n+=s.loc;return{count:i.length,loc:n,files:[...o]}})}function ot(e,r,t){return a(e,t,"twin-drift",()=>{let i=W(e,{scope:r,...m.twinDrift,scanLimit:t.candidateScanLimit}).filter(c=>c.relationship==="divergent"||c.relationship==="identical"),o=new Set,n=0;for(let c of i)for(let s of c.members)o.add(s.file),n+=s.loc;return{count:i.length,loc:n,files:[...o].sort()}})}function nt(e,r,t){return a(e,t,"react-component-duplicates",()=>{let i=ie(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return F(i)})}function ct(e,r,t){return a(e,t,"react-hook-candidates",()=>{let i=oe(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return He(i,yt)})}function st(e,r,t){return a(e,t,"react-large-component-pressure",()=>{let i=ne(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return Lt(i)})}function at(e,r,t){return a(e,t,"vue-component-duplicates",()=>{let i=ce(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return F(i)})}function ut(e,r,t){return a(e,t,"vue-composable-candidates",()=>{let i=se(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return He(i,Dt)})}function dt(e,r,t){return a(e,t,"vue-large-view-pressure",()=>{let i=ae(e,{scope:r,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return D(i)})}function lt(e,r,t){return a(e,t,"wrapper-candidates",()=>{let i=te(e,{scope:r,...m.wrappers,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return xe(i,Rt)})}function pt(e,r,t){return a(e,t,"passthrough-candidates",()=>{let i=Q(e,{scope:r,...m.passthroughs,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit});return xe(i,Pt)})}function mt(e,r,t){return a(e,t,"stale-abstractions",()=>{let i=Z(e,{scope:r,...m.stale,limit:t.candidateResultLimit,scanLimit:t.candidateScanLimit}),o=i.filter(n=>n.consumers===0).length;return{count:i.length,loc:i.reduce((n,c)=>n+c.loc,0),files:[...new Set(i.map(n=>n.file))],unused:o,singleUse:i.length-o}})}function ht(e,r){return a(e,r,"git-evidence",()=>{let t=z(e),i=t.fileChurn();if(!i)return null;let o=t.commitHistory(),n=N(e,void 0,{limit:r.candidateResultLimit}),c={};for(let[s,l]of i)c[s]={changes:l.changes,fixChanges:l.fixChanges};return{amplification:t.changeAmplification(),hiddenCoupling:{pairCount:n.findings.length,scoreCount:$(n.findings.reduce((s,l)=>s+be(l),0)),top:n.findings.slice(0,5).map(s=>({fileA:s.fileA,fileB:s.fileB,together:s.together,confidence:s.confidence,focusedTogether:s.focusedTogether,broadTogether:s.broadTogether,broadCommitRatio:s.broadCommitRatio,lastTogetherAt:s.lastTogetherAt,recentTogether:s.recentTogether,commitScope:s.commitScope,recency:s.recency,scoreWeight:be(s),subjectContext:s.subjectContext}))},fileStats:c,commitsScanned:o?.commits.length??0}})}function gt(e,r){return a(e,r,"suppressions",()=>{let t=ue(e);return{total:t.total,byCategory:{...t.byCategory}}})}function ft(e,r){return a(e,r,"coverage-contracts",()=>{let t=e.config.coverageContracts??[],o=G(e,t).filter(n=>n.status!=="ok");return{count:o.length,loc:0,files:[...new Set(o.map(n=>n.file))].sort()}})}function Ct(e,r,t){return a(e,t,"drift",()=>{let i=Y(e,{scope:r,...m.drift,includePatternDeviations:!1,limit:Number.POSITIVE_INFINITY}),o=i.results.filter(s=>s.kind!=="pattern-deviation"),n=o.filter(s=>s.actionTier==="direct").length,c=o.length-n;return{count:o.length,unusedImports:i.unusedImports,layerViolations:i.layerViolations,direct:n,signal:c}})}function bt(e,r,t){return a(e,t,"complexity-hotspots",()=>{let i=re(e,{scope:r,minLoc:10,limit:t.complexityResultLimit,scanLimit:t.candidateScanLimit,semantic:!1});return{top:i.slice(0,5).map(o=>({symbol:o.shortName,score:o.score,file:o.file})),extremeCount:i.filter(o=>o.score>Ge).length}})}function vt(e,r){let t=e.symbols>=je||e.documents>=qe,i=r?Number.POSITIVE_INFINITY:fe,o=r?Number.POSITIVE_INFINITY:Ye;return!t||r?{candidateScanLimit:void 0,candidateResultLimit:i,complexityResultLimit:o,releaseCachesBetweenPhases:!0,warnings:r&&t?["Large index detected; running health without candidate scan or result caps because full mode is enabled."]:[]}:{candidateScanLimit:ge,candidateResultLimit:i,complexityResultLimit:o,releaseCachesBetweenPhases:!0,warnings:[`Large index detected; candidate-style health checks scanned their highest-priority ${ge} symbols and reported their top ${fe} findings. Enable full mode for unbounded candidate counts.`]}}function St(e,r){r.releaseCachesBetweenPhases&&(A(e),T())}function a(e,r,t,i){wt(t);try{return i()}finally{St(e,r)}}function wt(e){process.env.SCIP_QUERY_HEALTH_TRACE==="1"&&console.error(`[health] ${e}`)}function xt(e,r){return r.filter(t=>!k(e,t.relativePath)&&!M(e,t.symbol,t.relativePath)&&t.kind==="dead-code")}function Ht(e,r){return r.filter(t=>!k(e,t.relativePath)&&!M(e,t.symbol,t.relativePath))}function D(e){let r=new Set;for(let t of e){let i=t.relativePath??t.file;i&&r.add(i)}return{count:e.length,loc:e.reduce((t,i)=>t+i.loc,0),files:[...r]}}function xe(e,r){return{...D(e),scoreCount:$(e.reduce((i,o)=>i+r(o),0))}}function Lt(e){let r=new Map;for(let t of e)r.set(t.file,Math.max(r.get(t.file)??0,t.loc));return{count:r.size,loc:[...r.values()].reduce((t,i)=>t+i,0),files:[...r.keys()]}}function F(e){let r=new Map;for(let t of e)r.set(t.fileA,Math.max(r.get(t.fileA)??0,t.locA)),r.set(t.fileB,Math.max(r.get(t.fileB)??0,t.locB));return{count:e.length,loc:[...r.values()].reduce((t,i)=>t+i,0),files:[...r.keys()]}}function He(e,r){return{...F(e),scoreCount:$(e.reduce((i,o)=>i+r(o),0))}}function yt(e){let r=e.sharedHooks.length>0,t=Le({namedState:e.sharedState,requests:e.sharedRequests,lifecycle:e.sharedEffects,functions:e.sharedHandlers});return r&&t<=2?0:r?.5:ye(e.sharedState,e.sharedHandlers,e.sharedHandlerVerbs)?.25:t>=2?1:.5}function Dt(e){let r=e.sharedComposables.length+e.sharedStores.length>0,t=Le({namedState:e.sharedBindings,requests:e.sharedRequests,lifecycle:e.sharedLifecycle,functions:e.sharedFunctions});return r&&t<=2?0:r?.5:ye(e.sharedBindings,e.sharedFunctions,e.sharedFunctionVerbs)?.25:t>=2?1:.5}function Le(e){return e.requests.length*2+e.lifecycle.length+e.namedState.filter(r=>!Re.has(De(r))).length+Math.min(e.functions.length,3)}function ye(e,r,t){let i=[...e,...r,...t].map(De);return i.length>0&&i.every(o=>Re.has(o))}function De(e){return e.replace(/^handle/,"").replace(/^is/,"").replace(/^has/,"").toLowerCase()}function Rt(e){return e.actionTier==="signal"?.25:1}function Pt(e){return e.actionTier==="signal"?.25:1}function be(e){return e.commitScope==="broad-sweep"?e.recency==="recent"?.25:0:e.commitScope==="mixed"?e.recency==="recent"?.5:.25:e.recency==="recent"?1:.5}function $(e){return Math.round(e*100)/100}var Re=new Set(["add","apply","cancel","change","clear","close","create","delete","draft","edit","error","filter","form","load","loading","name","open","refresh","remove","reset","save","saving","search","select","selected","submit","toggle","update","value"]);export{Ke as a,dr as b,lr as c,Xe as d,pr as e};
|
|
2
|
-
//# sourceMappingURL=chunk-
|
|
2
|
+
//# sourceMappingURL=chunk-4SCMYKD6.js.map
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{a as Se}from"./chunk-M7EEHYSU.js";import{a as Ce}from"./chunk-N2OTJWC2.js";import{a as re,c as se,d as ae,e as w}from"./chunk-ZEO4CXQR.js";import{a as be}from"./chunk-27XEGMCT.js";import{a as pe}from"./chunk-6JUAGXR4.js";import{a as ye}from"./chunk-C2QSK7E7.js";import{a as he}from"./chunk-6KMTPNZL.js";import{a as ue}from"./chunk-JJUX2OAP.js";import{a as de}from"./chunk-X3DTIEMU.js";import{a as fe}from"./chunk-2XRXEIRK.js";import{b as oe}from"./chunk-HZZQKNVE.js";import{a as te,b as ne}from"./chunk-3AMWF6V5.js";import{a as Z,b as Q,c as X,g as B,h as M}from"./chunk-KYB7FPXT.js";import{a as ee,b as v,e as ie}from"./chunk-Q7PWDXL5.js";import{b as le}from"./chunk-QVGFVRKD.js";import{a as N,c as V,d as J,e as Y}from"./chunk-IUSSGHJO.js";import{a as W}from"./chunk-7COVQPQQ.js";import{a as ge,e as me}from"./chunk-KSJ544IV.js";import{a as ce}from"./chunk-LY7NMOBW.js";import{a as q}from"./chunk-IMQFJ53K.js";import{f as R,g as T}from"./chunk-BZXE3HO4.js";import{i as U}from"./chunk-GULVO6NF.js";import{e as F,f as O,g as I}from"./chunk-X5C43YVI.js";import{a as z}from"./chunk-JZBGTSAB.js";import{a as _}from"./chunk-ISLWJ4PY.js";import{l as H}from"./chunk-WS3Z6W3M.js";import{createHash as Xe}from"crypto";import{existsSync as P}from"fs";function $e(e){let[i,t]=G(e,":"),o=i||"unknown",n=(a={})=>{let s=a.actionTier??Be(o);return{sourceAnalyzer:o,actionTier:s,rootCauseKey:a.rootCauseKey??(t||e),label:a.label??`${o} finding`,relatedFiles:a.relatedFiles??[],why:a.why??[],remediation:a.remediation??Me(s,o),file:a.file}};if(!t)return n({rootCauseKey:e,why:["Baseline identity did not include analyzer payload."]});if(["dead","isolated","extract","wrapper","passthrough","stale"].includes(o)){let[a,s]=G(t,":");return n({file:a,relatedFiles:a?[a]:[],rootCauseKey:s?`${a}:${s}`:t,label:`${o} finding`,why:s?[`Baseline subject: ${s}.`]:[]})}if(o==="cycle"){let a=t.split(">").filter(Boolean);return n({relatedFiles:a,rootCauseKey:t,label:"cycle finding",why:a.length>0?[`Cycle path: ${a.join(" > ")}.`]:[]})}if(o==="similar"){let a=t.split("|").filter(Boolean);return n({relatedFiles:[],rootCauseKey:t,label:"similarity finding",why:a.length>0?[`Similar symbols: ${a.join(" | ")}.`]:[]})}if(o==="drift"){let[a,s]=G(t,":"),[l,c]=G(s,":");return n({actionTier:a==="unused-import"?"direct":"signal",file:l,relatedFiles:[...new Set([l,c].filter(Boolean))],rootCauseKey:t,label:`${a||"drift"} finding`,why:[...a?[`Drift kind: ${a}.`]:[],...c?[`Related dependency: ${c}.`]:[]]})}return n({why:["Baseline analyzer prefix is not recognized by this diff-gate version."]})}function Be(e){switch(e){case"dead":case"isolated":case"cycle":case"passthrough":return"direct";case"similar":case"extract":case"wrapper":case"stale":return"signal";default:return"signal"}}function Me(e,i){return e==="direct"?`Fix the new ${i} baseline finding, or knowingly accept it via health --write-baseline.`:`Review the new ${i} baseline signal; fix it if it reflects real debt, or knowingly accept it via health --write-baseline.`}function G(e,i){let t=e.indexOf(i);return t<0?[e,""]:[e.slice(0,t),e.slice(t+i.length)]}import{existsSync as Ke,readFileSync as Le,writeFileSync as Pe}from"fs";import{isAbsolute as _e,join as He}from"path";var ze=25e3,Oe=2500,Ue=2500;function qe(e){let i=ye(e);return i.symbols>=ze||i.documents>=Oe?Ue:void 0}var We=".scipquery-baseline.json";function E(e,i){return i&&_e(i)?i:He(e.config.projectRoot,i??We)}function we(e,i={}){let{scope:t}=i,o=qe(e),n=[],a=le(e,{scope:t,...w.dead,scanLimit:o});for(let s of a.symbols)R(e,s.relativePath)||T(e,s.symbol,s.relativePath)||s.kind==="dead-code"&&n.push(`dead:${s.relativePath}:${s.shortName}`);for(let s of ue(e,{scope:t,...w.isolated,scanLimit:o}))R(e,s.relativePath)||T(e,s.symbol,s.relativePath)||n.push(`isolated:${s.relativePath}:${s.shortName}`);for(let s of ce(e,{scope:t}))s.kind==="real"&&n.push(`cycle:${Ve(s.path)}`);for(let s of me(e,{scope:t,...w.similar,scanLimit:o}))n.push(`similar:${[s.symbolA,s.symbolB].sort().join("|")}`);for(let s of te(e,{scope:t,...w.duplicateBodies,scanLimit:o}))n.push(`duplicate-bodies:${s.hash}:${s.functions.map(l=>l.symbol).sort().join("|")}`);for(let s of fe(e,{scope:t,...w.extract,scanLimit:o}))n.push(`extract:${s.relativePath}:${s.shortName}`);for(let s of be(e,{scope:t,...w.wrappers,scanLimit:o}))n.push(`wrapper:${s.file}:${s.shortName}`);for(let s of he(e,{scope:t,...w.passthroughs,scanLimit:o}))n.push(`passthrough:${s.file}:${s.shortName}`);for(let s of pe(e,{scope:t,...w.stale,scanLimit:o}))n.push(`stale:${s.file}:${s.shortName}`);for(let s of de(e,{scope:t,...w.drift,includePatternDeviations:!1,limit:Number.POSITIVE_INFINITY}).results)n.push(`drift:${s.kind}:${s.file}:${s.dep}`);return[...new Set(n)].sort()}function Ve(e){if(e.length===0)return"";let i=0;for(let t=1;t<e.length;t++)e[t]<e[i]&&(i=t);return[...e.slice(i),...e.slice(0,i)].join(">")}function Ui(e,i={}){let t=we(e,{scope:i.scope}),o=E(e,i.path);return Pe(o,JSON.stringify({version:1,findings:t},null,2)+`
|
|
2
|
+
`),{path:o,findingCount:t.length}}function De(e,i={}){let t=E(e,i.path);if(!Ke(t))throw new Error(`No baseline found at ${t}. Create one with: scip-query health --write-baseline`);let o=JSON.parse(Le(t,"utf-8")),n=new Set(o.findings??[]),a=we(e,{scope:i.scope}),s=new Set(a);return{baselinePath:t,baselineCount:n.size,current:a,newFindings:a.filter(l=>!n.has(l)),fixedFindings:[...n].filter(l=>!s.has(l))}}import{existsSync as Je,mkdirSync as Vi,readdirSync as Ye,readFileSync as Ze,writeFileSync as Ji}from"fs";import{createHash as Zi}from"crypto";import{join as K}from"path";var A=K(".scipquery","suppressions");function Qe(e){return K(e,A)}function ke(e){let i=Qe(e);if(!Je(i))return{suppressions:[],warnings:[]};let t=[],o=[];for(let n of Ye(i).sort()){if(!n.endsWith(".json"))continue;let a=K(i,n),s;try{s=JSON.parse(Ze(a,"utf-8"))}catch{o.push(`${A}/${n}: malformed JSON \u2014 ignored`);continue}if(typeof s!="object"||s===null||Array.isArray(s)){o.push(`${A}/${n}: not a suppression object \u2014 ignored`);continue}let l=s;if(typeof l.reason!="string"||l.reason.trim()===""){o.push(`${A}/${n}: missing reason \u2014 ignored`);continue}if(!l.id&&!l.check){o.push(`${A}/${n}: needs an id or a check \u2014 ignored`);continue}t.push(l)}return{suppressions:t,warnings:o}}var Dt=["echo","incomplete-migration","co-change-partner","twin-partner","coverage-contract","doc-reference","unused-params","new-dead","baseline"];function kt(e,i={}){let t=i.base??"HEAD",{minTogether:o=6,minConfidence:n=.6,maxEchoChecks:a=Number.POSITIVE_INFINITY,maxHelpers:s=Number.POSITIVE_INFINITY,minSimilarity:l=.8,includeBaseline:c=!1,scanLimit:r}=i,f=i.semantic!==!1,h=new Set(i.skip??[]),u=X(e,{base:t}),p=Q(e,{base:t,plan:u}),m=p.changedFiles,b=new Set(m),$=new Set(u.changedFileLines),d=new Set([...b,...$]),C=B(e.config.projectRoot,t,M(u,m)),S=Fi(e.config.projectRoot,t,u,C),g={base:t,changedFiles:m,changedSymbols:p.changedSymbols.length,checksRun:[],skipped:[],suppressed:[],findings:[],attributionNotes:p.attributionNotes,rootCauseGroups:[],note:p.summary.note};if(m.length===0)return g;let D=(x,Ee)=>{if(h.has(x)){g.skipped.push({check:x,reason:"skipped via --skip"});return}let je=g.findings.length,Ie=g.skipped.length,Ne=g.checksRun.length;H(`diff-gate.check.${x}`,Ee,()=>({check:x,changedFiles:m.length,changedSymbols:p.changedSymbols.length,findingsAdded:g.findings.length-je,skippedAdded:g.skipped.length-Ie,checksRunAdded:g.checksRun.length-Ne}))};return D("echo",()=>ni(e,p.changedSymbols,b,S,a,l,r,f,g)),D("incomplete-migration",()=>li(e,t,u,s,r,f,C,g)),D("co-change-partner",()=>di(e,d,o,n,g)),D("twin-partner",()=>fi(e,p.changedSymbols,b,r,g)),D("coverage-contract",()=>ui(e,d,g)),D("doc-reference",()=>yi(e,b,$,u.changedRanges,u.renamedFiles,g)),D("unused-params",()=>$i(e,m,g)),D("new-dead",()=>wi(e,p.changedSymbols,S,g)),c&&D("baseline",()=>Ti(e,g)),ii(g,[...e.config.suppressions??[],...ke(e.config.projectRoot).suppressions]),g.rootCauseGroups=ei(g.findings),g}function vt(e){return e.checksRun.length===0&&e.note===Z}function Ft(e){return e.filter(i=>!i.advisory)}function ei(e){let i=new Map;for(let t of e){let o=t.groupKey??`${t.check}:${t.id}`,n=i.get(o);n||(n={groupKey:o,check:t.check,severity:t.severity,actionTier:t.actionTier,sourceAnalyzer:t.sourceAnalyzer,rootCauseKey:t.rootCauseKey,count:0,findingIds:[],files:new Set,relatedFiles:new Set,message:t.message,remediation:t.remediation},i.set(o,n)),n.count+=1,n.findingIds.push(t.id),n.severity=xe(n.severity,t.severity),n.actionTier=Ge(n.actionTier,t.actionTier),t.file&&n.files.add(t.file);for(let a of t.relatedFiles??[])n.relatedFiles.add(a)}return[...i.values()].map(t=>({...t,files:[...t.files].sort(),relatedFiles:[...t.relatedFiles].sort()})).sort((t,o)=>o.count-t.count||j(o.severity)-j(t.severity)||t.groupKey.localeCompare(o.groupKey))}function xe(e,i){return j(i)>j(e)?i:e}function j(e){return e==="error"?2:e==="warning"?1:0}function Ge(e,i){return e?i&&ve(i)>ve(e)?i:e:i}function ve(e){return e==="direct"?2:e==="signal"?1:0}function ii(e,i){if(i.length===0||e.findings.length===0)return;let t=[];for(let o of e.findings){let n=i.find(a=>ti(a,o));n?e.suppressed.push({finding:o,suppression:n}):t.push(o)}e.findings=t}function ti(e,i){return!e.reason||e.reason.trim()===""||e.expiresAt&&Date.parse(e.expiresAt)<=Date.now()||e.id&&e.id!==i.id&&!i.legacySuppressionIds?.includes(e.id)||e.check&&e.check!==i.check||e.file&&e.file!==i.file?!1:!!(e.id||e.check)}function k(e,i){e.findings.push({...i,suppressionHint:`scip-query: ignore ${i.check} ${i.id} -- <reason>`})}function ni(e,i,t,o,n,a,s,l,c){c.checksRun.push("echo");for(let r of i.slice(0,n)){if(!I(r.symbol)||o(r))continue;let f=ne(e,r.symbol,{maxLoc:15,scanLimit:s}).filter(d=>!t.has(d.file)).slice(0,5).map(d=>({otherFile:d.file,otherShort:d.shortName,otherSymbol:d.symbol,similarity:1,similarityBasis:"exact-body",sharedEvidence:[`exact normalized body (${d.loc} LOC)`]}));if(f.length>0){let d=y("echo",r.symbol,r.file),C=y("echo",r.symbol,r.file,...f.map(g=>`${g.otherSymbol}|${g.otherFile}`).sort()),S=f[0];k(c,{id:d,legacySuppressionIds:C===d?void 0:[C],groupKey:d,actionTier:"direct",check:"echo",severity:"warning",evidence:"heuristic",confidence:1,file:r.file,symbol:r.symbol,relatedFiles:[...new Set(f.map(g=>g.otherFile))].sort(),sourceAnalyzer:"duplicate-bodies",rootCauseKey:`${r.symbol}:${S.otherSymbol}`,message:Re(r,f),why:Te(r,f),remediation:Ae("direct",r.shortName,S.otherShort)});continue}let h=ge(e,r.symbol,{minSimilarity:a,limit:5,scanLimit:s,semantic:l,sourceCandidateMode:"target-pruned"}),u=[];for(let d of h){let C=d.fileA===r.file?d.fileB:d.fileA,S=d.fileA===r.file?d.shortNameB:d.shortNameA,g=d.fileA===r.file?d.symbolB:d.symbolA;t.has(C)||u.push({otherFile:C,otherShort:S,otherSymbol:g,similarity:d.similarity,similarityBasis:d.similarityBasis??"callees",sharedEvidence:d.sharedCallees})}if(u.length===0)continue;let p=u[0],m=y("echo",r.symbol,r.file,...u.map(d=>`${d.otherSymbol}|${d.otherFile}`).sort()),b=y("echo",r.symbol,r.file),$=oi(r,u);k(c,{id:b,legacySuppressionIds:m===b?void 0:[m],groupKey:b,actionTier:$,check:"echo",severity:"warning",evidence:"heuristic",confidence:p.similarity,file:r.file,symbol:r.symbol,relatedFiles:[...new Set(u.map(d=>d.otherFile))].sort(),message:Re(r,u),why:Te(r,u),remediation:Ae($,r.shortName,p.otherShort)})}i.length>n&&c.skipped.push({check:"echo",reason:`echo check capped at ${n} of ${i.length} changed symbols`})}function oi(e,i){return i.some(o=>ri(e.symbol,o))?"direct":"signal"}function ri(e,i){if(i.similarityBasis==="exact-body")return!0;if(i.similarityBasis!=="source-tokens"||i.similarity<.98||i.sharedEvidence.length>8)return!1;let t=F(e),o=F(i.otherSymbol);return!t||!o?!1:t===o?!0:ci(i.sharedEvidence)?!1:si(t,o)}function si(e,i){let t=Fe(e),o=Fe(i);if(t.length===0||o.length===0)return!1;let n=new Set(o),a=t.filter(s=>n.has(s)).length;return a>=2&&a/Math.min(t.length,o.length)>=.5}function Fe(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").split(/[^A-Za-z0-9]+/).map(i=>i.toLowerCase()).filter(i=>i.length>=2)}var ai=new Set(["bytes","crypto","hex","num","random","secret","to","token"]);function ci(e){return e.length>=3&&e.every(i=>ai.has(i.toLowerCase()))}function Re(e,i){let t=i[0],o=Math.round(t.similarity*100);return i.length===1?`${e.shortName} (${e.file}) is ${o}% similar to established ${t.otherShort} (${t.otherFile})`:`${e.shortName} (${e.file}) resembles ${i.length} established symbol(s); strongest is ${o}% similar to ${t.otherShort} (${t.otherFile})`}function Te(e,i){let t=[`${e.shortName} was changed in this diff.`];for(let o of i.slice(0,3))t.push(`${o.otherShort} is outside this diff and scored ${Math.round(o.similarity*100)}% similar by ${o.similarityBasis} evidence.`),t.push(`Shared evidence: ${o.sharedEvidence.slice(0,5).join(", ")||"(none listed)"}.`);return i.length>3&&t.push(`${i.length-3} additional similar match(es) grouped into this finding.`),t}function Ae(e,i,t){return e==="direct"?`Extract or reuse the shared behavior with ${t}, or keep the duplicate with a suppression reason.`:`Review whether ${i} is intentionally parallel to the established implementation(s); extract shared behavior only if the product semantics match.`}function li(e,i,t,o,n,a,s,l){let c=Ce(e,{base:i,maxHelpers:o,diffPlan:t,scanLimit:n,semantic:a,baseContentAt:s});if(!c.available){l.skipped.push({check:"incomplete-migration",reason:"no git history"});return}l.checksRun.push("incomplete-migration"),c.note&&l.skipped.push({check:"incomplete-migration",reason:c.note});for(let r of c.findings){let f=r.leftovers.map(d=>`${d.shortName} (${d.file}, ${Math.round(d.containment*100)}% helper / ${Math.round(d.siteCoverage*100)}% site, ${d.migrationScope})`).join(", "),h=r.leftovers.map(d=>`${d.shortName}: ${d.migrationScope} (${d.migrationScopeReasons[0]})`).join("; "),u=[...r.migratedFiles,...r.leftovers.map(d=>d.file)],p=r.leftovers.length===0?void 0:Math.max(...r.leftovers.map(d=>Math.min(d.containment,d.siteCoverage))),m=r.leftovers.some(d=>d.migrationScope==="possible-subtype"),b=y("incomplete-migration",r.helperSymbol,r.helperFile,u.join("|")),$=y("incomplete-migration",r.helperSymbol,r.helperFile);k(l,{id:$,legacySuppressionIds:b===$?void 0:[b],check:"incomplete-migration",severity:"warning",evidence:"heuristic",confidence:p,file:r.helperFile,symbol:r.helperSymbol,relatedFiles:u,message:`new helper ${r.helperShortName} (${r.helperFile}) is wired into ${r.migratedFiles.length} file(s), but ${r.leftovers.length} similar un-migrated site(s) remain: ${f}`,why:[`${r.helperShortName} is new in this diff and already referenced by ${r.migratedFiles.join(", ")}.`,`Helper shape: ${r.helperShape}; ${r.specificHelperCalleeCount}/${r.helperCalleeCount} helper callees are specific enough to score.`,`Unchanged site(s) still contain the helper's callee pattern: ${f}.`,`Migration scope hints: ${h}.`],remediation:m?`Migrate same-scope sites to ${r.helperShortName}; review possible subtype/variant sites before applying the helper.`:`Migrate the remaining sites to ${r.helperShortName}, or confirm they are intentionally different.`})}}function di(e,i,t,o,n){let a=W(e).directionalCoChangePairsForFiles(i,{minTogether:t,minConfidence:0,maxFilesPerCommit:20});if(!a){n.skipped.push({check:"co-change-partner",reason:"no git history"});return}n.checksRun.push("co-change-partner");let s=new Set,l;for(let c of a){let r=i.has(c.fileA),f=i.has(c.fileB);if(r===f)continue;let h=r?c.fileA:c.fileB,u=r?c.fileB:c.fileA,p=r?c.changesA:c.changesB,m=p>0?c.together/p:0;if(m<o||N(u)||N(h)||!P(`${e.config.projectRoot}/${u}`))continue;let b=`${h}|${u}`;if(s.has(b))continue;s.add(b);let $=y("co-change-partner",h,u,String(c.together)),d=y("co-change-partner",h,u),C=V(h,u),S=J({fileA:h,fileB:u,together:c.together,confidence:m,commitScope:c.commitScope,recency:c.recency,subjectContext:c.subjectContext},C,(l??=Y(e))(h,u)),g=[h,u].sort().join("|");n.findings.push({id:d,legacySuppressionIds:$===d?void 0:[$],check:"co-change-partner",severity:"warning",evidence:"change-graph",actionTier:"signal",groupKey:`co-change-partner:${g}`,confidence:m,file:h,relatedFiles:[u],sourceAnalyzer:"co-change",rootCauseKey:g,partnerClass:C.partnerClass,partnerClassReasons:C.reasons,commitScope:c.commitScope,recency:c.recency,focusedTogether:c.focusedTogether,broadTogether:c.broadTogether,broadCommitRatio:c.broadCommitRatio,lastTogetherAt:c.lastTogetherAt,recentTogether:c.recentTogether,subjectContext:c.subjectContext,...S?{declaredCouplingSuggestion:S}:{},message:`${h} changed, but ${u} did not \u2014 they change together ${c.together}x (${Math.round(m*100)}% of the time)`,why:[`${h} is in this diff and ${u} is not.`,`Git history shows ${c.together} co-change(s), which is ${Math.round(m*100)}% of changes to the edited side.`,`History context: ${hi(c)}.`,`Subject context: ${gi(c.subjectContext)}.`,...mi(c),`Partner class: ${C.partnerClass} (${C.reasons.join("; ")}).`],remediation:S?`Update ${u} alongside this change, declare the coupling "${S.name}", or confirm the coupling no longer holds.`:`Update ${u} alongside this change, or confirm the coupling no longer holds.`})}}function fi(e,i,t,o,n){n.checksRun.push("twin-partner");let a=oe(e,{scanLimit:o}).filter(c=>c.relationship==="divergent"||c.relationship==="identical");if(a.length===0)return;let s=new Map;for(let c of a)for(let r of c.members)s.set(r.symbol,c);let l=new Set;for(let c of i){if(!I(c.symbol))continue;let r=s.get(c.symbol);if(!r)continue;let f=r.members.filter(m=>m.symbol!==c.symbol&&!t.has(m.file));if(f.length===0)continue;let h=[c.symbol,...f.map(m=>m.symbol)].sort().join("|");if(l.has(h))continue;l.add(h);let u=f[0],p=y("twin-partner",c.symbol,c.file,u.symbol);k(n,{id:p,groupKey:`twin-partner:${h}`,check:"twin-partner",severity:"warning",evidence:"heuristic",actionTier:"signal",advisory:!0,confidence:r.relationship==="identical"?1:Math.max(0,1-r.maxDivergence),file:c.file,symbol:c.symbol,relatedFiles:f.map(m=>m.file).sort(),sourceAnalyzer:"twin-drift",rootCauseKey:h,message:`${c.shortName} (${c.file}) changed but its same-name twin ${u.shortName} (${u.file}) did not \u2014 verify the change shouldn't apply to both, or consolidate them.`,why:[`${c.symbol} is in this diff.`,`${u.symbol} shares its (near-)name and is classified '${r.relationship}' with it, but ${u.file} is not in this diff.`,r.relationship==="divergent"?`The two bodies already diverge (~${Math.round(r.maxDivergence*100)}% token difference) \u2014 this diff may widen or narrow that drift.`:"The two bodies were byte-identical before this diff.","Advisory: twin-partner never fails the gate by itself \u2014 see the twin-partner entry in the diff-gate checks table."],remediation:`Update ${u.file} alongside this change, consolidate ${c.shortName}/${u.shortName} into one helper, or confirm the twin should diverge on purpose.`})}}function ui(e,i,t){t.checksRun.push("coverage-contract");let o=e.config.coverageContracts??[];for(let n of o){if(!se(n,i))continue;let a=re(e,n);if(a.status==="ok")continue;let s=y("coverage-contract",n.name,n.file);k(t,{id:s,groupKey:`coverage-contract:${n.name}`,check:"coverage-contract",severity:a.status==="unavailable"?"warning":"error",evidence:"graph-fact",actionTier:"direct",file:n.file,sourceAnalyzer:"coverage-contracts",rootCauseKey:n.name,message:ae(a),why:[`Contract "${n.name}" declares that ${n.file} (${n.keys.type}) must track ${n.mustEqual.type}.`,a.status==="unavailable"?`The declared side could not be evaluated: ${a.unavailableReason}.`:`Missing: ${a.missing.join(", ")||"none"}. Extra: ${a.extra.join(", ")||"none"}.`,"Either side of this contract changed in this diff."],remediation:a.status==="unavailable"?"Investigate why the declared key set could not be parsed (see the reason above) \u2014 do not treat this as a pass.":`Update ${n.file} so its ${n.keys.type==="object-literal-keys"||n.keys.type==="string-array"?n.keys.identifier:n.keys.marker} matches ${n.mustEqual.type}, or fix the ground-truth source if the declared set is right.`})}}function hi(e){return`${e.commitScope}/${e.recency}; ${e.focusedTogether} focused, ${e.broadTogether} broad-sweep (${Math.round(e.broadCommitRatio*100)}% broad), ${e.recentTogether} recent, last ${pi(e.lastTogetherAt)}`}function gi(e){let i=e.subjectLabels.length>0?e.subjectLabels.slice(0,5).join(", "):"none inferred",t=e.issueRefs.length>0?e.issueRefs.slice(0,5).join(", "):"none",o=e.sampleSubjects.length>0?e.sampleSubjects.slice(0,3).map(n=>`"${n}"`).join("; "):"none";return`labels ${i}; refs ${t}; samples ${o}; external issue/PR labels ${e.externalIssueLabelStatus}`}function mi(e){let i=[];return e.commitScope==="broad-sweep"&&i.push("Broad-sweep history is weaker than focused co-edits; confirm this is a real coordination contract."),e.recency==="stale"&&i.push("The pair has no co-change in the recent history window; confirm the coupling still holds."),i}function pi(e){return e<=0?"unknown":new Date(e*1e3).toISOString().slice(0,10)}var L=3;function yi(e,i,t,o,n,a){a.checksRun.push("doc-reference");let s=v.referenceTargets(e,i,o);if(s.size===0)return;let l=new Set(n.map(r=>r.from)),c=[];for(let r of ie(e,s))t.has(r.doc)||ee(e,r.doc)||c.push(bi(e,r,l));for(let r of Ci(c))k(a,r)}function bi(e,i,t){let o=i.citedClaims.length>0?i.citedClaims:v.citationContexts(e,i.doc,i.cited),n=v.classifyCitation(o),a=v.hasLineAnchoredCitation(i.citations),s=i.cited.some(h=>t.has(h)||!P(`${e.config.projectRoot}/${h}`)),l=!(a||s),c=i.cited[0]??"",r=y("doc-reference",i.doc,i.cited.join("|")),f=y("doc-reference",i.doc,c);return{id:f,legacySuppressionIds:r===f?void 0:[r],check:"doc-reference",severity:"warning",evidence:"change-graph",actionTier:n.actionTier,groupKey:`doc-reference:${c}`,rootCauseKey:c,confidence:1,file:i.doc,relatedFiles:i.cited,citationKind:n.citationKind,citationKindReasons:n.reasons,citedClaims:o,...l?{advisory:!0}:{},message:`${i.doc} cites ${i.cited.join(", ")} as ${v.citationKindLabel(n.citationKind)} \u2014 changed in this diff, doc untouched`,why:[`${i.cited.join(", ")} changed in this diff.`,`${i.doc} cites the changed file(s) but was not updated in the same diff.`,...n.reasons.map(h=>`Citation kind evidence: ${h}`),l?"Advisory: bare file-mention citation (no line anchor, cited file still present under the same path) \u2014 21.2 calibration found this citation shape low-precision; verify at your leisure.":a?"Blocking: citation includes a line anchor that may now point at the wrong lines.":"Blocking: the cited file was deleted or renamed in this diff \u2014 the citation almost certainly needs an update."],remediation:v.citationRemediation(n.citationKind,i.doc)}}function Ci(e){let i=new Map;for(let o of e){let n=o.rootCauseKey??"",a=i.get(n);a?a.push(o):i.set(n,[o])}let t=[];for(let[o,n]of i)n.length<=L?t.push(...n):t.push(Si(o,n));return t}function Si(e,i){let t=[...i].sort((f,h)=>(f.file??"").localeCompare(h.file??"")),o=t.slice(0,L).map(f=>({doc:f.file??"",citedClaims:f.citedClaims??[]})),n=t.length-o.length,a=t.every(f=>f.advisory===!0),s=t.reduce((f,h)=>xe(f,h.severity),"info"),l=t.reduce((f,h)=>Ge(f,h.actionTier),void 0),c=t.map(f=>f.file??"").filter(f=>f.length>0),r=[...new Set(t.flatMap(f=>[f.id,...f.legacySuppressionIds??[]]))];return{id:y("doc-reference","hub-cluster",e),memberFindingIds:r,check:"doc-reference",severity:s,evidence:"change-graph",actionTier:l,groupKey:`doc-reference:${e}`,rootCauseKey:e,confidence:1,file:o[0]?.doc,relatedFiles:[e],citationCount:t.length,citationExemplars:o,suppressedCount:n,...a?{advisory:!0}:{},message:`${e} is cited by ${t.length} doc(s) changed in this diff, doc(s) untouched \u2014 showing ${o.length} example(s), ${n} more damped`,why:[`${e} changed in this diff.`,`${t.length} doc(s) cite it but were not updated in the same diff: ${c.join(", ")}.`,...o.map(f=>`Example \u2014 ${f.doc}: ${f.citedClaims[0]??"(no captured citation text)"}`),`${n} additional doc(s) also cite this file, past the per-hub-file cascade cap (${L}) \u2014 not silently dropped: counted in citationCount/suppressedCount and individually addressable via memberFindingIds.`,a?"Advisory: every citation in this cluster is a bare file-mention (no line anchor, cited file still present).":"Blocking: at least one citation in this cluster is line-anchored or cites a deleted/renamed file."],remediation:`Review the ${o.length} example doc(s) above; ${t.length} total doc(s) cite ${e} the same way \u2014 see citationExemplars and memberFindingIds in --json for the complete list.`}}function $i(e,i,t){t.checksRun.push("unused-params");for(let o of Se(e,{files:i,limit:50})){let n=y("unused-params",o.symbol,o.file,o.unusedTrailing.join("|")),a=y("unused-params",o.symbol,o.file);k(t,{id:a,legacySuppressionIds:n===a?void 0:[n],check:"unused-params",severity:"warning",evidence:"heuristic",confidence:.85,file:o.file,startLine:o.startLine,endLine:o.endLine,symbol:o.symbol,message:`${o.shortName} (${o.file}) has trailing unused parameter(s): ${o.unusedTrailing.join(", ")}`,why:[`${o.shortName} is in a changed file.`,`The trailing parameter(s) ${o.unusedTrailing.join(", ")} are not referenced in the function body.`],remediation:"Drop the unused trailing parameters and their call-site arguments."})}}function wi(e,i,t,o){o.checksRun.push("new-dead");let n=new q(e),a=_(e.config.projectRoot),s=a.length>1;for(let l of i){if(t(l)||l.fanIn>0||n.fileKind(l.file)==="test"||R(e,l.file)||T(e,l.symbol,l.file)||vi(l.symbol))continue;let c=y("new-dead",l.symbol,l.file),r=s&&Di(a,l.file)&&ki(e,l.symbol);k(o,{id:c,check:"new-dead",severity:"warning",evidence:r?"heuristic":"graph-fact",confidence:r?.4:.9,file:l.file,symbol:l.symbol,message:r?`${l.shortName} (${l.file}) unconfirmed (cross-package ambiguous-name resolution gap): zero indexed consumers found, but this name is ambiguous project-wide and lives in a workspace package \u2014 verify manually before treating as dead`:`${l.shortName} (${l.file}) was changed but has zero indexed consumers`,why:r?[`${l.shortName} is a changed production symbol in a workspace package.`,"The index, semantic, and source-fallback layers all report zero consumers for this symbol.","Its leaf name is ambiguous project-wide (a same-named definition exists elsewhere), and cross-package consumers reached only through a re-exporting barrel are a known unresolvable shape for this tool \u2014 see docs/plans/2026-07-02-followups.md item 2."]:[`${l.shortName} is a changed production symbol.`,"The index reports zero consumers for this symbol.","The symbol is not in a detected entry surface or configured live root."],remediation:r?"Verify with a direct code search before deleting; this tool cannot confidently resolve this symbol.":"Wire it up, or remove it before it becomes permanent dead code."})}}function Di(e,i){return e.some(t=>i===t.relativeDir||i.startsWith(`${t.relativeDir}/`))}function ki(e,i){let t=F(i);return t?(U(e).get(t)?.length??0)>1:!1}function vi(e){if(O(e)!=="type")return!1;let i=F(e);return i.startsWith("_Assert")||i.startsWith("Assert")}function Fi(e,i,t,o){let n=new Map(t.renamedFiles.map(s=>[s.to,s.from])),a=o??B(e,i,M(t));return s=>{let l=n.get(s.file)??s.file,c=F(s.symbol);if(!c)return!1;let r=a(l);return r!==null&&Ri(r,c)}}function Ri(e,i){return new RegExp(`\\b${z(i)}\\b`).test(e)}function Ti(e,i){if(!P(E(e))){i.skipped.push({check:"baseline",reason:"no .scipquery-baseline.json \u2014 run health --write-baseline to enable"});return}i.checksRun.push("baseline");let t=De(e);for(let o of t.newFindings){let n=$e(o),a=y("baseline",o);k(i,{id:a,groupKey:`baseline:${n.sourceAnalyzer}:${n.rootCauseKey}`,check:"baseline",severity:"error",evidence:"baseline",actionTier:n.actionTier,confidence:1,file:n.file,relatedFiles:n.relatedFiles.length>0?n.relatedFiles:void 0,sourceAnalyzer:n.sourceAnalyzer,rootCauseKey:n.rootCauseKey,message:`new ${n.label} vs committed baseline: ${o}`,why:["A committed health baseline exists.","The current health result contains a finding not present in that baseline.",`Underlying analyzer: ${n.sourceAnalyzer}.`,`Inherited action tier: ${n.actionTier}.`,`Root cause key: ${n.rootCauseKey}.`,...n.why],remediation:n.remediation})}}function y(e,...i){return`SQ${Xe("sha256").update([e,...i].join("\0")).digest("hex").slice(0,12).toUpperCase()}`}export{we as a,Ui as b,De as c,Dt as d,kt as e,vt as f,Ft as g,Fi as h};
|
|
3
|
+
//# sourceMappingURL=chunk-YBGC7HTY.js.map
|