waterplane 0.1.22 → 0.1.25
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 +39 -0
- package/SECURITY.md +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/commits.d.ts +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/commits.js +2 -2
- package/node_modules/@waterplane/shared/dist/healthindex/commits.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/coverage.d.ts +128 -0
- package/node_modules/@waterplane/shared/dist/healthindex/coverage.js +343 -0
- package/node_modules/@waterplane/shared/dist/healthindex/coverage.js.map +1 -0
- package/node_modules/@waterplane/shared/dist/healthindex/readings.d.ts +9 -1
- package/node_modules/@waterplane/shared/dist/healthindex/readings.js +122 -4
- package/node_modules/@waterplane/shared/dist/healthindex/readings.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/repoindex.d.ts +5 -0
- package/node_modules/@waterplane/shared/dist/healthindex/repoindex.js +2 -0
- package/node_modules/@waterplane/shared/dist/healthindex/repoindex.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/score.d.ts +3 -0
- package/node_modules/@waterplane/shared/dist/healthindex/score.js +52 -16
- package/node_modules/@waterplane/shared/dist/healthindex/score.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/types.d.ts +82 -6
- package/node_modules/@waterplane/shared/dist/healthindex/types.js +35 -2
- package/node_modules/@waterplane/shared/dist/healthindex/types.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex/words.js +65 -6
- package/node_modules/@waterplane/shared/dist/healthindex/words.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindex.d.ts +21 -7
- package/node_modules/@waterplane/shared/dist/healthindex.js +20 -7
- package/node_modules/@waterplane/shared/dist/healthindex.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthindexresponse.js +3 -2
- package/node_modules/@waterplane/shared/dist/healthindexresponse.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/healthspend.js +1 -1
- package/node_modules/@waterplane/shared/dist/hints.js +9 -0
- package/node_modules/@waterplane/shared/dist/hints.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/index.d.ts +2 -0
- package/node_modules/@waterplane/shared/dist/index.js +2 -0
- package/node_modules/@waterplane/shared/dist/index.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/intent/kind.d.ts +45 -1
- package/node_modules/@waterplane/shared/dist/intent/kind.js +60 -2
- package/node_modules/@waterplane/shared/dist/intent/kind.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/intent.d.ts +1 -1
- package/node_modules/@waterplane/shared/dist/intent.js +1 -1
- package/node_modules/@waterplane/shared/dist/intent.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/repohealth.d.ts +178 -0
- package/node_modules/@waterplane/shared/dist/repohealth.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/repohealthhabits.d.ts +15 -0
- package/node_modules/@waterplane/shared/dist/repohealthhabits.js +117 -0
- package/node_modules/@waterplane/shared/dist/repohealthhabits.js.map +1 -0
- package/node_modules/@waterplane/shared/dist/repohealthnative.d.ts +10 -0
- package/node_modules/@waterplane/shared/dist/repohealthnative.js +94 -0
- package/node_modules/@waterplane/shared/dist/repohealthnative.js.map +1 -0
- package/node_modules/@waterplane/shared/dist/repohealthread.js +23 -1
- package/node_modules/@waterplane/shared/dist/repohealthread.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/wire/agentreadings.d.ts +104 -0
- package/node_modules/@waterplane/shared/dist/wire/agentreadings.js +7 -0
- package/node_modules/@waterplane/shared/dist/wire/agentreadings.js.map +1 -0
- package/node_modules/@waterplane/shared/dist/wire/notify.d.ts +6 -1
- package/node_modules/@waterplane/shared/dist/wire/notify.js +6 -1
- package/node_modules/@waterplane/shared/dist/wire/notify.js.map +1 -1
- package/node_modules/@waterplane/shared/dist/wire/repo.d.ts +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/packages/extensions/android-apps/waterplane-plugin.json +4 -1
- package/packages/extensions/copilot-usage/waterplane-plugin.json +7 -2
- package/packages/extensions/desktop/waterplane-plugin.json +5 -0
- package/packages/extensions/ocr/waterplane-plugin.json +5 -1
- package/packages/extensions/requirements/waterplane-plugin.json +3 -3
- package/packages/extensions/scorecard/waterplane-plugin.json +2 -1
- package/packages/extensions/token-stats/waterplane-plugin.json +4 -3
- package/packages/host/dist/agentclass.d.ts +105 -0
- package/packages/host/dist/agentclass.js +189 -0
- package/packages/host/dist/agentclass.js.map +1 -0
- package/packages/host/dist/agentintents.d.ts +18 -0
- package/packages/host/dist/agentintents.js +40 -7
- package/packages/host/dist/agentintents.js.map +1 -1
- package/packages/host/dist/agentreadings.d.ts +40 -0
- package/packages/host/dist/agentreadings.js +254 -0
- package/packages/host/dist/agentreadings.js.map +1 -0
- package/packages/host/dist/agentscan.d.ts +8 -0
- package/packages/host/dist/agentscan.js +329 -0
- package/packages/host/dist/agentscan.js.map +1 -0
- package/packages/host/dist/backends/index.js +12 -1
- package/packages/host/dist/backends/index.js.map +1 -1
- package/packages/host/dist/binguard.d.ts +13 -1
- package/packages/host/dist/binguard.js +28 -2
- package/packages/host/dist/binguard.js.map +1 -1
- package/packages/host/dist/exposure.d.ts +10 -0
- package/packages/host/dist/exposure.js +25 -0
- package/packages/host/dist/exposure.js.map +1 -1
- package/packages/host/dist/plugins/pluginassets.d.ts +17 -0
- package/packages/host/dist/plugins/pluginassets.js +27 -1
- package/packages/host/dist/plugins/pluginassets.js.map +1 -1
- package/packages/host/dist/plugins/pluginregistry.d.ts +3 -1
- package/packages/host/dist/plugins/pluginregistry.js +8 -1
- package/packages/host/dist/plugins/pluginregistry.js.map +1 -1
- package/packages/host/dist/reposkilltext.d.ts +2 -0
- package/packages/host/dist/reposkilltext.js +8 -2
- package/packages/host/dist/reposkilltext.js.map +1 -1
- package/packages/host/dist/routes/apirepowork.js +13 -0
- package/packages/host/dist/routes/apirepowork.js.map +1 -1
- package/packages/host/dist/routes/apisystem.js +17 -1
- package/packages/host/dist/routes/apisystem.js.map +1 -1
- package/packages/host/dist/routes/apitable.d.ts +4 -0
- package/packages/host/dist/routes/apitable.js.map +1 -1
- package/packages/host/dist/server/http.js +2 -1
- package/packages/host/dist/server/http.js.map +1 -1
- package/packages/host/dist/server/intentDeps.js +14 -1
- package/packages/host/dist/server/intentDeps.js.map +1 -1
- package/packages/host/dist/sessions/tmux.js +6 -1
- package/packages/host/dist/sessions/tmux.js.map +1 -1
- package/packages/host/dist/weekburn.js +7 -5
- package/packages/host/dist/weekburn.js.map +1 -1
- package/packages/web/dist/assets/demo-mKJo0QVO.js +26 -0
- package/packages/web/dist/assets/index-B6f7Lcp1.js +170 -0
- package/packages/web/dist/assets/index-DQIK94fc.css +1 -0
- package/packages/web/dist/assets/shared-Cd69oxHd.js +51 -0
- package/packages/web/dist/assets/sheets-BImsk1_Y.js +256 -0
- package/packages/web/dist/build-id.txt +1 -1
- package/packages/web/dist/buildstamp.json +1 -1
- package/packages/web/dist/index.html +5 -5
- package/packages/web/dist/sw.js +2 -2
- package/release.json +3 -3
- package/tools/repohealth/constants.mjs +34 -1
- package/tools/repohealth/fixture.json +5374 -38
- package/tools/repohealth/git.mjs +77 -0
- package/tools/repohealth/lang/dart-analyze.mjs +181 -0
- package/tools/repohealth/lang/dart-lex.mjs +494 -0
- package/tools/repohealth/lang/dart-resolve.mjs +95 -0
- package/tools/repohealth/lang/python-ast.mjs +602 -0
- package/tools/repohealth/lang/python-resolve.mjs +228 -0
- package/tools/repohealth/metrics/habits.mjs +286 -0
- package/tools/repohealth/metrics/native.mjs +542 -0
- package/tools/repohealth/metrics/untested.mjs +20 -8
- package/tools/repohealth/metrics/workspace.mjs +256 -0
- package/tools/repohealth/own.mjs +67 -5
- package/tools/repohealth/packs/dart.mjs +153 -85
- package/tools/repohealth/packs/python.mjs +51 -14
- package/tools/repohealth/plot.mjs +143 -1
- package/tools/repohealth/reach.mjs +98 -0
- package/tools/repohealth/scope.mjs +14 -1
- package/tools/repohealth/series.mjs +5 -0
- package/tools/repohealth/types.mjs +4 -0
- package/tools/repohealth.mjs +39 -5
- package/packages/web/dist/assets/demo-ad3g3HDa.js +0 -26
- package/packages/web/dist/assets/index-BllRvpkw.js +0 -170
- package/packages/web/dist/assets/index-DUiYLEts.css +0 -1
- package/packages/web/dist/assets/shared-DBaaGttP.js +0 -51
- package/packages/web/dist/assets/sheets-CrfRr6Um.js +0 -256
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,45 @@ version — so entries are grouped by the release they shipped in. A fixed secur
|
|
|
5
5
|
vulnerability in what ships is listed under a **Security:** bullet of the release that
|
|
6
6
|
fixed it, with its CVE or GHSA id when one exists.
|
|
7
7
|
|
|
8
|
+
## 0.1.25
|
|
9
|
+
|
|
10
|
+
### New
|
|
11
|
+
|
|
12
|
+
- **A "proposals" strip on the launcher shows work that scripts have suggested.** It reads like "3 proposals wait for you" and sits above the lists. Tapping it opens exactly those backlog rows, and the filter bar says "n of N" with a clear button. Each row says who proposed it and offers schedule beside fire. The strip goes as each row is fired, scheduled or deleted.
|
|
13
|
+
- **A script with no session can propose work to an agent's backlog.** The row stays manual and you get one notification for it, which opens that row. Notification settings list the new `proposal` kind.
|
|
14
|
+
- **Every session pane now carries `WATERPLANE_SESSION_ID`.** An agent or its script can name its own session, which fixes the conflict error when several sessions run in one repo.
|
|
15
|
+
- **The repo readings sheet has an "agents" region.** It shows exploration cost, rework spend, compactions per committed session and escaped defects, per repo and per week. It reads your Claude session logs and says why when a reading can't be taken.
|
|
16
|
+
- **The health index has eleven new entries.** They cover duplicate code, dead exports, import cycles, co-change, fix-after-change and tests changed with code. A reading that can't be taken counts as unknown, never as 100.
|
|
17
|
+
- **Flutter repos now get import-graph, test-reach, clone and dead-export readings.** Before, they scored as nothing for these.
|
|
18
|
+
- **Two more readings of your own are available.** One counts shipped requirements that a test names. The other is the end-to-end flaky rate, which is absent with a reason when there are fewer than 10 logged runs.
|
|
19
|
+
- **Edit desktop has a test under each address.** The tailnet test says how long it took and which folder answered. The Wi-Fi test says whether this desktop proved itself, and offers the address the desktop reports now.
|
|
20
|
+
- **The re-cut option is offered for any engine that supports it.** Before, only the bundled engine had it.
|
|
21
|
+
- **The VS Code extension keeps the last scan for the next open.** It shows "loading" instead of "absent" and reports progress natively. A stopped first health read now says so.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **The re-cut button now sits under the refusal it answers, not above it.**
|
|
26
|
+
- **The VS Code extension no longer runs any program except git for its health readings.** Native readings there now show as absent with the reason, instead of stopping the extension.
|
|
27
|
+
|
|
28
|
+
## 0.1.24
|
|
29
|
+
|
|
30
|
+
Folds 0.1.23, which was tagged but never released.
|
|
31
|
+
|
|
32
|
+
### New
|
|
33
|
+
|
|
34
|
+
- **The installer ends with this desktop's URL and port and opens it in the browser.** It opens only when the host started, the doctor check passed and a screen is available, never over SSH. Pass `--no-open` to skip it.
|
|
35
|
+
- **A new session on an agent whose CLI is missing opens the Start sheet.** It lists "Use <agent>" for every agent that can start on this desktop. The failed-start card offers the same choice and sends your words along to the agent you pick. The backend list marks a missing CLI as unavailable, so the phone knows before you launch.
|
|
36
|
+
- **Plugin cards use coloured tags.** Stable is green, Beta orange, Experimental and failed red, Private purple, and Installed neutral.
|
|
37
|
+
- **Each place on a plugin card is a tap path plus what is there.** For example "Home screen › a repo's ⋯ menu". Only a place that really opens has an Open button.
|
|
38
|
+
- **An "About" fold on each plugin shows its README.** The READMEs now open with what the plugin does and where to find it, in plain words.
|
|
39
|
+
- **The Apps door is no longer listed as a second place when a launcher line opens the same sheet.** Its path names the Downloads, Build and Pull sheets, and the repo readings path uses the button's own name.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- **"GitHub Copilot is not installed" no longer reads like the editor extension.** The message now says "The GitHub Copilot CLI is not installed" and names the `copilot` command that is missing from the PATH.
|
|
44
|
+
- **The mark & send row no longer breaks labels mid-word.** The six actions form a grid of whole words, at most three across, and the primary button fills the gap in the last row.
|
|
45
|
+
- **Plugin status lines are no longer shortened.** They print as the plugin wrote them, so a path like `/opt/.../copilot` is no longer cut to "copilot".
|
|
46
|
+
|
|
8
47
|
## 0.1.22
|
|
9
48
|
|
|
10
49
|
Folds 0.1.21, which was tagged but never released.
|
package/SECURITY.md
CHANGED
|
@@ -267,7 +267,7 @@ They answer only a loopback caller that is neither a browser (any `Origin` or `S
|
|
|
267
267
|
is refused, same-origin included) nor proxied (same headers as above). They add no power: a posted row
|
|
268
268
|
goes through the same containment gate and store as the phone's `intent.post`, cannot bring a budget
|
|
269
269
|
waiver, and waits for the person's auto-fire switch and budget like any scheduled item. A backlog add
|
|
270
|
-
never starts until the person fires it.
|
|
270
|
+
never starts until the person fires it; a script's `proposedBy` only changes the row's origin mark and adds one push.
|
|
271
271
|
|
|
272
272
|
## The Android app
|
|
273
273
|
|
|
@@ -7,7 +7,7 @@ export interface HealthCommitPoint {
|
|
|
7
7
|
index: number;
|
|
8
8
|
mean: number;
|
|
9
9
|
cappedBy: HealthEntry | null;
|
|
10
|
-
/** Prereg or
|
|
10
|
+
/** Prereg, central or coverage (what was measured, which gates) differs from the previous scored row: do not join the line. */
|
|
11
11
|
gap: boolean;
|
|
12
12
|
}
|
|
13
13
|
export interface HealthCommitSeries {
|
|
@@ -39,9 +39,9 @@ export function healthIndexCommits(rows, contextWarnChars, max = 240) {
|
|
|
39
39
|
all.push({
|
|
40
40
|
sha7: typeof row.sha === "string" ? row.sha.slice(0, 7) : "",
|
|
41
41
|
day: row.day, ts: row.ts, week, index: s.index, mean: s.mean, cappedBy: s.cappedBy,
|
|
42
|
-
gap: prev !== null && (prev.prereg !== prereg || prev.central !== central),
|
|
42
|
+
gap: prev !== null && (prev.prereg !== prereg || prev.central !== central || prev.coverage !== s.coverage.key),
|
|
43
43
|
});
|
|
44
|
-
prev = { prereg, central };
|
|
44
|
+
prev = { prereg, central, coverage: s.coverage.key };
|
|
45
45
|
}
|
|
46
46
|
if (all.length === 0)
|
|
47
47
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commits.js","sourceRoot":"","sources":["../../src/healthindex/commits.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAqB5C,qIAAqI;AACrI,MAAM,UAAU,gBAAgB,CAAC,MAAoC,EAAE,GAAW;IAChF,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;IAC7C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC7C,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC;QAC5C,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK;gBAAE,EAAE,GAAG,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,KAAK;gBAAE,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACf,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,kBAAkB,CAAC,IAAgC,EAAE,gBAA+B,EAAE,GAAG,GAAG,GAAG;IAC7G,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7F,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"commits.js","sourceRoot":"","sources":["../../src/healthindex/commits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { type HealthEntry, type HealthSeriesRow } from "./types.js";
|
|
2
|
+
/** Every dimension the index is meant to judge. Order = the order words list them. */
|
|
3
|
+
export declare const HEALTH_DIMENSIONS: readonly ["size", "retouch", "hatches", "context", "untested", "dups", "deadExports", "cycles", "cochange", "fixAfterChange", "testsWithCode", "analyzer", "vulnDeps"];
|
|
4
|
+
export type HealthDimension = (typeof HEALTH_DIMENSIONS)[number];
|
|
5
|
+
export interface HealthDimensionDef {
|
|
6
|
+
/** Plain words, as a coverage line names it. */
|
|
7
|
+
label: string;
|
|
8
|
+
/** In the index today (an entry of `HEALTH_ENTRIES`). False = named, not counted. */
|
|
9
|
+
scored: boolean;
|
|
10
|
+
/** Needs a pack that reads the language (`reach.packs[].reads`). */
|
|
11
|
+
perLanguage: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The dimension table. A package that adds an index entry flips `scored` and,
|
|
15
|
+
* for a per-language one, teaches `tools/repohealth/reach.mjs` which packs
|
|
16
|
+
* read it. A test pins `scored` ⇔ membership of `HEALTH_ENTRIES`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const HEALTH_DIMENSION_DEFS: Record<HealthDimension, HealthDimensionDef>;
|
|
19
|
+
/** A per-language entry is unknown when languages that cannot read it hold MORE than this share of source files. */
|
|
20
|
+
export declare const HEALTH_COVERAGE_MAX_UNREAD = 0.2;
|
|
21
|
+
/** The headline with a failing gate is at most this: one under the alert warn line. */
|
|
22
|
+
export declare const HEALTH_GATE_CAP: number;
|
|
23
|
+
/** One applicable dimension (an entry or a gate) and whether it was measured. */
|
|
24
|
+
export interface HealthCoverageItem {
|
|
25
|
+
/** The dimension id, or `gate:<key>` for a repo gate. */
|
|
26
|
+
key: string;
|
|
27
|
+
kind: "entry" | "gate";
|
|
28
|
+
label: string;
|
|
29
|
+
state: "measured" | "unknown";
|
|
30
|
+
/** Why it is unknown (always set then), or a note on a measured entry with an unread minority. */
|
|
31
|
+
reason?: string;
|
|
32
|
+
}
|
|
33
|
+
/** One gate the repo declared, judged on this row. */
|
|
34
|
+
export interface HealthGate {
|
|
35
|
+
key: string;
|
|
36
|
+
name: string;
|
|
37
|
+
unit: string;
|
|
38
|
+
/** Absent where the declaration was refused. */
|
|
39
|
+
fails?: "below" | "above";
|
|
40
|
+
at?: number;
|
|
41
|
+
value: number | null;
|
|
42
|
+
state: "pass" | "fail" | "unknown";
|
|
43
|
+
/** Why an unknown gate is unknown; absent on a pass or fail. */
|
|
44
|
+
why?: string;
|
|
45
|
+
/** One sentence, phone and VS Code alike. */
|
|
46
|
+
text: string;
|
|
47
|
+
}
|
|
48
|
+
export interface HealthCoverage {
|
|
49
|
+
/** Index entries read. Gates never add to it: a passing gate cannot raise the cap. */
|
|
50
|
+
measured: number;
|
|
51
|
+
/** Index entries that apply, plus each UNKNOWN gate (a gate with no reading is unmeasured, never passed). */
|
|
52
|
+
applicable: number;
|
|
53
|
+
/** Whether the row said which languages each reading covers (engine `reach`); false = an older engine. */
|
|
54
|
+
reach: boolean;
|
|
55
|
+
items: HealthCoverageItem[];
|
|
56
|
+
gates: HealthGate[];
|
|
57
|
+
/** What was measured, as a fingerprint: a change of it marks the week a gap (the basket moved). */
|
|
58
|
+
key: string;
|
|
59
|
+
}
|
|
60
|
+
/** The row's `reach` packs, parsed field by field; null where the row carries none (an older engine). */
|
|
61
|
+
export declare function healthReachOf(row: HealthSeriesRow): {
|
|
62
|
+
name: string;
|
|
63
|
+
files: number;
|
|
64
|
+
reads: string[];
|
|
65
|
+
}[] | null;
|
|
66
|
+
/**
|
|
67
|
+
* The repo's gates on this row (`row.own.readings[].gate`), judged. [] where the
|
|
68
|
+
* row carries no `own`. A declaration that exists but could not be read in
|
|
69
|
+
* full is never a pass: a refused file is one UNKNOWN gate (we cannot know
|
|
70
|
+
* what it declared), each dropped entry that asked for a gate (`unreadGates`)
|
|
71
|
+
* is another, and a row measured with the repo's commands unapproved
|
|
72
|
+
* (`own.notRun`, `own.gates`) carries each declared gate with no value.
|
|
73
|
+
*/
|
|
74
|
+
export declare function healthGatesOf(row: HealthSeriesRow): HealthGate[];
|
|
75
|
+
/**
|
|
76
|
+
* What applies to this row and what was measured. `enabled` are the index
|
|
77
|
+
* entries the repo has not disabled; a core entry absent from the row is not
|
|
78
|
+
* this function's business (the week has no score then). `absent` names the
|
|
79
|
+
* OPTIONAL entries the row could not read (`readings.ts`), each with the
|
|
80
|
+
* engine's reason: those are unknown whatever the packs could read.
|
|
81
|
+
*
|
|
82
|
+
* A per-language entry whose value IS on the row while no pack in `reach`
|
|
83
|
+
* lists it was measured by an engine whose `reach` predates the entry (P2
|
|
84
|
+
* added `dups`/`deadExports`/`cycles` to `reach.mjs`): measured, with a note
|
|
85
|
+
* that its language coverage was not recorded — the P1 rule for a row with no
|
|
86
|
+
* `reach` at all, applied per dimension. Never unknown for that alone: the
|
|
87
|
+
* engine only writes a value when some pack read the files.
|
|
88
|
+
*/
|
|
89
|
+
export declare function healthCoverage(row: HealthSeriesRow, enabled: readonly HealthEntry[], absent?: Partial<Record<HealthEntry, string>>): HealthCoverage;
|
|
90
|
+
/** The coverage cap: `100 · measured / applicable`; 100 when everything (or nothing) applicable was read. */
|
|
91
|
+
export declare function healthCoverageCap(c: Pick<HealthCoverage, "measured" | "applicable">): number;
|
|
92
|
+
/** Which cap set the headline. */
|
|
93
|
+
export type HealthCapKind = "worst" | "coverage" | "gate";
|
|
94
|
+
/**
|
|
95
|
+
* The headline from its parts: `min(mean, worst + 30, coverage cap, gate cap)`.
|
|
96
|
+
* `capKind` is the cap that set it (null when the mean did); on a tie the
|
|
97
|
+
* gate is named first, then coverage — the cap the repo can do the most about
|
|
98
|
+
* by itself, then the one the engine owes it.
|
|
99
|
+
*/
|
|
100
|
+
export declare function healthHeadline(mean: number, worst: number, coverage: HealthCoverage | null): {
|
|
101
|
+
index: number;
|
|
102
|
+
capKind: HealthCapKind | null;
|
|
103
|
+
};
|
|
104
|
+
/** What `healthHeadlineWords` reads — a point, or the wire summary. */
|
|
105
|
+
export interface HealthHeadlineSubject {
|
|
106
|
+
value: number;
|
|
107
|
+
mean: number;
|
|
108
|
+
cappedBy: HealthEntry | null;
|
|
109
|
+
capKind?: HealthCapKind | null;
|
|
110
|
+
coverage?: HealthCoverage | null;
|
|
111
|
+
}
|
|
112
|
+
export interface HealthHeadlineWords {
|
|
113
|
+
/** The cap that set the number, said once; null when the mean did (or the host did not say). */
|
|
114
|
+
cap: string | null;
|
|
115
|
+
/** `3 of 5 dimensions measured. Unknown: …`; null where everything was measured (and recorded as such) or the host sent no coverage. */
|
|
116
|
+
coverage: string | null;
|
|
117
|
+
/** Measured entries with an unread minority, one sentence; null where none. */
|
|
118
|
+
notes: string | null;
|
|
119
|
+
/** Every failing or unknown gate's sentence, failing first. */
|
|
120
|
+
gates: string[];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* THE wording of the headline's caps and coverage — the phone card, the
|
|
124
|
+
* launcher chip's title and the VS Code Health view all print these. The
|
|
125
|
+
* worst-entry sentence is `healthCapWords`'s (score.ts), restated here so a
|
|
126
|
+
* caller needs this one function.
|
|
127
|
+
*/
|
|
128
|
+
export declare function healthHeadlineWords(s: HealthHeadlineSubject): HealthHeadlineWords;
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// healthindex/coverage: Which dimensions apply, which were measured, the repo's gates, and the caps both put on the headline. Barrel: ../healthindex.ts (read the header there).
|
|
2
|
+
/**
|
|
3
|
+
* **An honest headline: coverage and gates.**
|
|
4
|
+
*
|
|
5
|
+
* picture-app — a fully vibe-coded app, 60k lines of Dart and 20k of Python —
|
|
6
|
+
* read 100 (owner, 2026-11-09: "it can not be 100 good"). Two causes:
|
|
7
|
+
*
|
|
8
|
+
* 1. Each entry saturates at its good line, so clearing five size/hygiene
|
|
9
|
+
* lines reads 100. (More dimensions fix that; P2/P3/P6 add them.)
|
|
10
|
+
* 2. The index scored what the packs COULD read and said nothing about the
|
|
11
|
+
* rest. The Dart pack has no test rule, so `untested` skipped all 391 Dart
|
|
12
|
+
* files and divided the Python/Kotlin leftovers by all 537: 12%, "good".
|
|
13
|
+
* It has no Dart escape-hatch patterns either, so hatches per kLOC counted
|
|
14
|
+
* TODOs over most of the code.
|
|
15
|
+
*
|
|
16
|
+
* ── The dimensions ─────────────────────────────────────────────────────────
|
|
17
|
+
*
|
|
18
|
+
* `HEALTH_DIMENSIONS` is every reading the index is meant to judge. Only the
|
|
19
|
+
* ones with `scored: true` are APPLICABLE today — those are the index entries
|
|
20
|
+
* (`HEALTH_ENTRIES`). The rest are named so a later package flips one on when
|
|
21
|
+
* it adds the entry; until then they are not counted at all, neither as
|
|
22
|
+
* measured nor as unknown (a dimension nobody scores is not a hole in THIS
|
|
23
|
+
* repo's reading). `perLanguage` says the reading needs a pack that can read
|
|
24
|
+
* the language; the others (file length, rework, CLAUDE.md, git history) read
|
|
25
|
+
* any tree.
|
|
26
|
+
*
|
|
27
|
+
* ── Measured or unknown ────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* A per-language entry is UNKNOWN when the source files of languages whose
|
|
30
|
+
* pack cannot read it are more than `HEALTH_COVERAGE_MAX_UNREAD` (a fifth) of
|
|
31
|
+
* the source files. Under that it is measured, and the unread languages are
|
|
32
|
+
* still named in a note. A fifth, because a TypeScript repo with a handful
|
|
33
|
+
* of shell scripts must not lose its untested reading over them, while a
|
|
34
|
+
* repo where most of the code was never opened must not get one. The row's
|
|
35
|
+
* `reach` (engine `tools/repohealth/reach.mjs`) carries the pack facts; a row
|
|
36
|
+
* from an engine before `reach` STATES no coverage — its entries are taken as
|
|
37
|
+
* measured (as they always were) and the words say coverage was not recorded.
|
|
38
|
+
*
|
|
39
|
+
* An unknown entry is out of the mean, out of the worst-entry cap and out of
|
|
40
|
+
* the alerts: its value is real but its denominator is not, and an average
|
|
41
|
+
* that includes it would be a number about files nobody read.
|
|
42
|
+
*
|
|
43
|
+
* ── The coverage cap ───────────────────────────────────────────────────────
|
|
44
|
+
*
|
|
45
|
+
* `headline ≤ 100 · measured / applicable`. Arguments:
|
|
46
|
+
*
|
|
47
|
+
* - An unknown dimension could score anywhere from very bad to 100. The
|
|
48
|
+
* score over the measured part alone is therefore an UPPER bound on what
|
|
49
|
+
* could be claimed, and showing it as the headline claims the unread part
|
|
50
|
+
* is perfect. The cap credits an unknown dimension with nothing: the
|
|
51
|
+
* headline vouches for at most the share of the basket that was read.
|
|
52
|
+
* - It is monotone and sayable: "capped at 60, 3 of 5 dimensions measured".
|
|
53
|
+
* A range (low–high) was the alternative; its lower end is always near 0
|
|
54
|
+
* under the worst-entry cap, so it says nothing a person can act on, and
|
|
55
|
+
* it does not fit a ring or a chip.
|
|
56
|
+
* - It never raises a score: a fully measured repo is unaffected, and the
|
|
57
|
+
* score over the measured part still binds when it is lower.
|
|
58
|
+
*
|
|
59
|
+
* ── Gates ──────────────────────────────────────────────────────────────────
|
|
60
|
+
*
|
|
61
|
+
* A gate is one of the repo's OWN readings (`health.json`, engine `own.mjs`)
|
|
62
|
+
* that the repo marked critical: `gate: { fails: "below" | "above", at }`.
|
|
63
|
+
* A gate can only LOWER the headline, never raise it: a passing gate is not
|
|
64
|
+
* counted in the coverage cap at all (declaring easy gates would otherwise
|
|
65
|
+
* dilute the unread code: 3 of 5 → 6 of 8), a gate with no reading (or a
|
|
66
|
+
* refused declaration) is UNKNOWN — one more applicable dimension nobody
|
|
67
|
+
* measured, never passed — and an entry the repo overrode with its own
|
|
68
|
+
* whole-repo command (`central.override`) is measured by that command. A FAILING gate caps the headline at `HEALTH_GATE_CAP` (49): just
|
|
69
|
+
* under the alert warn line, so a repo failing a line it called critical
|
|
70
|
+
* never reads as healthy, whatever the averages say — the same idea as the
|
|
71
|
+
* worst-entry cap, at a fixed height because a gate is pass/fail with no
|
|
72
|
+
* score to add 30 to.
|
|
73
|
+
*
|
|
74
|
+
* `healthHeadlineWords` is the ONE wording of all three caps and the coverage
|
|
75
|
+
* line; the phone card and the VS Code Health view (the same chart) both call
|
|
76
|
+
* it, as does the launcher chip's title.
|
|
77
|
+
*/
|
|
78
|
+
import { centralOf } from "./readings.js";
|
|
79
|
+
import { HEALTH_ENTRIES, HEALTH_OPTIONAL_ENTRIES, HEALTH_ALERT_WARN, HEALTH_SCORE_CAP_GAP } from "./types.js";
|
|
80
|
+
/** Every dimension the index is meant to judge. Order = the order words list them. */
|
|
81
|
+
export const HEALTH_DIMENSIONS = [
|
|
82
|
+
"size", "retouch", "hatches", "context", "untested",
|
|
83
|
+
"dups", "deadExports", "cycles", "cochange", "fixAfterChange", "testsWithCode", "analyzer", "vulnDeps",
|
|
84
|
+
];
|
|
85
|
+
/**
|
|
86
|
+
* The dimension table. A package that adds an index entry flips `scored` and,
|
|
87
|
+
* for a per-language one, teaches `tools/repohealth/reach.mjs` which packs
|
|
88
|
+
* read it. A test pins `scored` ⇔ membership of `HEALTH_ENTRIES`.
|
|
89
|
+
*/
|
|
90
|
+
export const HEALTH_DIMENSION_DEFS = {
|
|
91
|
+
size: { label: "file length", scored: true, perLanguage: false },
|
|
92
|
+
retouch: { label: "re-touches", scored: true, perLanguage: false },
|
|
93
|
+
hatches: { label: "escape hatches", scored: true, perLanguage: true },
|
|
94
|
+
context: { label: "CLAUDE.md + skill descriptions", scored: true, perLanguage: false },
|
|
95
|
+
untested: { label: "untested modules", scored: true, perLanguage: true },
|
|
96
|
+
dups: { label: "duplicate code", scored: true, perLanguage: true },
|
|
97
|
+
deadExports: { label: "dead exports", scored: true, perLanguage: true },
|
|
98
|
+
cycles: { label: "import cycles", scored: true, perLanguage: true },
|
|
99
|
+
cochange: { label: "files that change together", scored: true, perLanguage: false },
|
|
100
|
+
fixAfterChange: { label: "fixes after a change", scored: true, perLanguage: false },
|
|
101
|
+
testsWithCode: { label: "tests changed with code", scored: true, perLanguage: false },
|
|
102
|
+
analyzer: { label: "analyzer findings", scored: false, perLanguage: true },
|
|
103
|
+
vulnDeps: { label: "vulnerable dependencies", scored: false, perLanguage: false },
|
|
104
|
+
};
|
|
105
|
+
/** A per-language entry is unknown when languages that cannot read it hold MORE than this share of source files. */
|
|
106
|
+
export const HEALTH_COVERAGE_MAX_UNREAD = 0.2;
|
|
107
|
+
/** The headline with a failing gate is at most this: one under the alert warn line. */
|
|
108
|
+
export const HEALTH_GATE_CAP = HEALTH_ALERT_WARN - 1;
|
|
109
|
+
const isNum = (v) => typeof v === "number" && Number.isFinite(v);
|
|
110
|
+
const isEntry = (k) => HEALTH_ENTRIES.includes(k);
|
|
111
|
+
/** `A`, `A and B`, `A, B and C`. */
|
|
112
|
+
const listWords = (xs) => xs.length <= 1 ? (xs[0] ?? "") : `${xs.slice(0, -1).join(", ")} and ${xs[xs.length - 1]}`;
|
|
113
|
+
const commas = (n) => Math.round(n).toLocaleString("en-US");
|
|
114
|
+
const LANG = {
|
|
115
|
+
typescript: "TypeScript", python: "Python", dart: "Dart", kotlin: "Kotlin", c: "C", shell: "shell",
|
|
116
|
+
};
|
|
117
|
+
const langName = (n) => LANG[n] ?? n;
|
|
118
|
+
/** The row's `reach` packs, parsed field by field; null where the row carries none (an older engine). */
|
|
119
|
+
export function healthReachOf(row) {
|
|
120
|
+
const v = row.reach?.value;
|
|
121
|
+
if (!v || !Array.isArray(v.packs))
|
|
122
|
+
return null;
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const p of v.packs) {
|
|
125
|
+
const o = p;
|
|
126
|
+
if (!o || typeof o.name !== "string" || !isNum(o.files) || o.files < 0 || !Array.isArray(o.reads))
|
|
127
|
+
return null;
|
|
128
|
+
out.push({ name: o.name, files: o.files, reads: o.reads.filter((r) => typeof r === "string") });
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
/** Why an unread dimension is unread, per dimension, in words. */
|
|
133
|
+
function unreadWhy(dim, langs) {
|
|
134
|
+
if (dim === "untested")
|
|
135
|
+
return `no rule for how a ${langs} test names a module`;
|
|
136
|
+
if (dim === "hatches")
|
|
137
|
+
return `no ${langs} escape-hatch patterns, only TODO/FIXME counted`;
|
|
138
|
+
if (dim === "dups" || dim === "deadExports")
|
|
139
|
+
return `no ${langs} parser`;
|
|
140
|
+
if (dim === "cycles")
|
|
141
|
+
return `no ${langs} import-graph rule`;
|
|
142
|
+
return `no ${langs} reader`;
|
|
143
|
+
}
|
|
144
|
+
function fmtGate(v, unit) {
|
|
145
|
+
const r = Math.abs(v) >= 100 ? Math.round(v) : Math.round(v * 10) / 10;
|
|
146
|
+
return `${r.toLocaleString("en-US")}${unit ? (unit === "%" ? "%" : ` ${unit}`) : ""}`;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* The repo's gates on this row (`row.own.readings[].gate`), judged. [] where the
|
|
150
|
+
* row carries no `own`. A declaration that exists but could not be read in
|
|
151
|
+
* full is never a pass: a refused file is one UNKNOWN gate (we cannot know
|
|
152
|
+
* what it declared), each dropped entry that asked for a gate (`unreadGates`)
|
|
153
|
+
* is another, and a row measured with the repo's commands unapproved
|
|
154
|
+
* (`own.notRun`, `own.gates`) carries each declared gate with no value.
|
|
155
|
+
*/
|
|
156
|
+
export function healthGatesOf(row) {
|
|
157
|
+
const own = row.own;
|
|
158
|
+
if (!own || typeof own !== "object")
|
|
159
|
+
return [];
|
|
160
|
+
const out = [];
|
|
161
|
+
if (typeof own.refused === "string") {
|
|
162
|
+
out.push({ key: "declaration", name: "health.json", unit: "", value: null, state: "unknown", why: own.refused, text: `The repo's gates are unknown: ${own.refused}.` });
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
const list = Array.isArray(own.readings) ? own.readings : Array.isArray(own.gates) ? own.gates : [];
|
|
166
|
+
if (isNum(own.unreadGates) && own.unreadGates > 0) {
|
|
167
|
+
const n = Math.floor(own.unreadGates);
|
|
168
|
+
const why = `${n} declared ${n === 1 ? "gate has" : "gates have"} no usable key and could not be read`;
|
|
169
|
+
out.push({ key: "unreadGates", name: "unreadable entries", unit: "", value: null, state: "unknown", why, text: `Gates are unknown: ${why}.` });
|
|
170
|
+
}
|
|
171
|
+
for (const raw of list) {
|
|
172
|
+
const r = raw;
|
|
173
|
+
if (!r || typeof r.key !== "string" || r.gate === undefined || r.gate === null)
|
|
174
|
+
continue;
|
|
175
|
+
const name = typeof r.name === "string" && r.name ? r.name : r.key;
|
|
176
|
+
const unit = typeof r.unit === "string" ? r.unit : "";
|
|
177
|
+
const g = r.gate;
|
|
178
|
+
const value = isNum(r.value) ? r.value : null;
|
|
179
|
+
const reason = typeof r.reason === "string" && r.reason ? r.reason : null;
|
|
180
|
+
if (typeof g !== "object" || (g.fails !== "below" && g.fails !== "above") || !isNum(g.at)) {
|
|
181
|
+
const why = typeof g?.invalid === "string" ? g.invalid : "the gate's declaration could not be read";
|
|
182
|
+
out.push({ key: r.key, name, unit, value, state: "unknown", why, text: `Gate "${name}" is unknown: ${why}.` });
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const fails = g.fails;
|
|
186
|
+
const at = g.at;
|
|
187
|
+
const need = `${fails === "below" ? "at least" : "at most"} ${fmtGate(at, unit)}`;
|
|
188
|
+
if (value === null) {
|
|
189
|
+
const why = `no reading${reason ? ` (${reason})` : ""}`;
|
|
190
|
+
out.push({ key: r.key, name, unit, fails, at, value, state: "unknown", why, text: `Gate "${name}" is unknown: ${why}; it needs ${need}.` });
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const failing = fails === "below" ? value < at : value > at;
|
|
194
|
+
out.push({
|
|
195
|
+
key: r.key, name, unit, fails, at, value, state: failing ? "fail" : "pass",
|
|
196
|
+
text: failing
|
|
197
|
+
? `Gate "${name}" fails: ${fmtGate(value, unit)}, the repo requires ${need}.`
|
|
198
|
+
: `Gate "${name}" passes: ${fmtGate(value, unit)}, needs ${need}.`,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return out;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* What applies to this row and what was measured. `enabled` are the index
|
|
205
|
+
* entries the repo has not disabled; a core entry absent from the row is not
|
|
206
|
+
* this function's business (the week has no score then). `absent` names the
|
|
207
|
+
* OPTIONAL entries the row could not read (`readings.ts`), each with the
|
|
208
|
+
* engine's reason: those are unknown whatever the packs could read.
|
|
209
|
+
*
|
|
210
|
+
* A per-language entry whose value IS on the row while no pack in `reach`
|
|
211
|
+
* lists it was measured by an engine whose `reach` predates the entry (P2
|
|
212
|
+
* added `dups`/`deadExports`/`cycles` to `reach.mjs`): measured, with a note
|
|
213
|
+
* that its language coverage was not recorded — the P1 rule for a row with no
|
|
214
|
+
* `reach` at all, applied per dimension. Never unknown for that alone: the
|
|
215
|
+
* engine only writes a value when some pack read the files.
|
|
216
|
+
*/
|
|
217
|
+
export function healthCoverage(row, enabled, absent = {}) {
|
|
218
|
+
const packs = healthReachOf(row);
|
|
219
|
+
// An entry the repo replaced with its own whole-repo command is measured by
|
|
220
|
+
// that command, whatever the packs can read (`readings.ts` uses its number).
|
|
221
|
+
const overridden = centralOf(row).overridden;
|
|
222
|
+
const total = packs ? packs.reduce((s, p) => s + p.files, 0) : 0;
|
|
223
|
+
const items = [];
|
|
224
|
+
for (const dim of HEALTH_DIMENSIONS) {
|
|
225
|
+
const def = HEALTH_DIMENSION_DEFS[dim];
|
|
226
|
+
if (!def.scored || !isEntry(dim) || !enabled.includes(dim))
|
|
227
|
+
continue;
|
|
228
|
+
const item = { key: dim, kind: "entry", label: def.label, state: "measured" };
|
|
229
|
+
const why = absent[dim];
|
|
230
|
+
if (why) {
|
|
231
|
+
item.state = "unknown";
|
|
232
|
+
item.reason = why;
|
|
233
|
+
}
|
|
234
|
+
else if (def.perLanguage && HEALTH_OPTIONAL_ENTRIES.includes(dim) && packs && total > 0 && !overridden.includes(dim) && !packs.some((p) => p.reads.includes(dim))) {
|
|
235
|
+
item.reason = "which languages it covers was not recorded by the engine that measured this week";
|
|
236
|
+
}
|
|
237
|
+
else if (def.perLanguage && packs && total > 0 && !overridden.includes(dim)) {
|
|
238
|
+
// Biggest unread language first: the one the absence is mostly about.
|
|
239
|
+
const unread = packs.filter((p) => p.files > 0 && !p.reads.includes(dim)).sort((a, b) => b.files - a.files);
|
|
240
|
+
const n = unread.reduce((s, p) => s + p.files, 0);
|
|
241
|
+
if (n > 0) {
|
|
242
|
+
const langs = listWords(unread.map((p) => langName(p.name)));
|
|
243
|
+
const why = `${unreadWhy(dim, langs)} (${commas(n)} of ${commas(total)} source files)`;
|
|
244
|
+
if (n / total > HEALTH_COVERAGE_MAX_UNREAD)
|
|
245
|
+
item.state = "unknown";
|
|
246
|
+
item.reason = why;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
items.push(item);
|
|
250
|
+
}
|
|
251
|
+
const gates = healthGatesOf(row);
|
|
252
|
+
for (const g of gates) {
|
|
253
|
+
items.push({
|
|
254
|
+
key: `gate:${g.key}`, kind: "gate", label: `gate "${g.name}"`,
|
|
255
|
+
state: g.state === "unknown" ? "unknown" : "measured",
|
|
256
|
+
...(g.why ? { reason: g.why } : {}),
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
// Gates only ever LOWER the cap: a passing gate is neither measured nor
|
|
260
|
+
// applicable here (declaring easy gates must not dilute unread code), a
|
|
261
|
+
// failing one caps at 49 (`healthHeadline`), an unknown one is an
|
|
262
|
+
// applicable dimension nobody measured.
|
|
263
|
+
const measured = items.filter((i) => i.kind === "entry" && i.state === "measured").length;
|
|
264
|
+
const applicable = items.filter((i) => i.kind === "entry" || i.state === "unknown").length;
|
|
265
|
+
const key = [
|
|
266
|
+
...items.map((i) => `${i.key}=${i.state === "measured" ? "m" : "u"}`),
|
|
267
|
+
...gates.map((g) => `${g.key}:${g.fails ?? "?"}${g.at ?? ""}`),
|
|
268
|
+
].join(",");
|
|
269
|
+
return { measured, applicable, reach: packs !== null, items, gates, key };
|
|
270
|
+
}
|
|
271
|
+
/** The coverage cap: `100 · measured / applicable`; 100 when everything (or nothing) applicable was read. */
|
|
272
|
+
export function healthCoverageCap(c) {
|
|
273
|
+
return c.applicable > 0 ? (100 * c.measured) / c.applicable : 100;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* The headline from its parts: `min(mean, worst + 30, coverage cap, gate cap)`.
|
|
277
|
+
* `capKind` is the cap that set it (null when the mean did); on a tie the
|
|
278
|
+
* gate is named first, then coverage — the cap the repo can do the most about
|
|
279
|
+
* by itself, then the one the engine owes it.
|
|
280
|
+
*/
|
|
281
|
+
export function healthHeadline(mean, worst, coverage) {
|
|
282
|
+
const caps = [];
|
|
283
|
+
if (coverage?.gates.some((g) => g.state === "fail"))
|
|
284
|
+
caps.push(["gate", HEALTH_GATE_CAP]);
|
|
285
|
+
if (coverage)
|
|
286
|
+
caps.push(["coverage", healthCoverageCap(coverage)]);
|
|
287
|
+
caps.push(["worst", worst + HEALTH_SCORE_CAP_GAP]);
|
|
288
|
+
let index = mean;
|
|
289
|
+
let capKind = null;
|
|
290
|
+
for (const [k, v] of caps) {
|
|
291
|
+
if (v < index - 1e-9) {
|
|
292
|
+
index = v;
|
|
293
|
+
capKind = k;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
return { index, capKind };
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* THE wording of the headline's caps and coverage — the phone card, the
|
|
300
|
+
* launcher chip's title and the VS Code Health view all print these. The
|
|
301
|
+
* worst-entry sentence is `healthCapWords`'s (score.ts), restated here so a
|
|
302
|
+
* caller needs this one function.
|
|
303
|
+
*/
|
|
304
|
+
export function healthHeadlineWords(s) {
|
|
305
|
+
const c = s.coverage ?? null;
|
|
306
|
+
const v = Math.round(s.value);
|
|
307
|
+
const unknown = c ? c.items.filter((i) => i.state === "unknown") : [];
|
|
308
|
+
// A gate's reason is its own sentence in `gates`; the coverage line only names it, so no fact is said twice.
|
|
309
|
+
const unknownWords = unknown.map((i) => (i.kind === "gate" ? i.label : `${i.label}: ${i.reason ?? "not read"}`));
|
|
310
|
+
const failing = c ? c.gates.filter((g) => g.state === "fail") : [];
|
|
311
|
+
let cap = null;
|
|
312
|
+
// An older host sends no capKind: the worst-entry cap is the only one it knew.
|
|
313
|
+
const kind = s.capKind === undefined ? (s.cappedBy && s.value < s.mean ? "worst" : null) : s.capKind;
|
|
314
|
+
if (kind === "gate" && failing.length) {
|
|
315
|
+
cap = `Capped at ${v}: ${failing.length === 1 ? "a gate the repo declared fails" : `${failing.length} gates the repo declared fail`} (${listWords(failing.map((g) => `"${g.name}"`))}), and a failing gate holds the score under ${HEALTH_ALERT_WARN}.`;
|
|
316
|
+
}
|
|
317
|
+
else if (kind === "coverage" && c) {
|
|
318
|
+
cap = `Capped at ${v}: only ${c.measured} of ${c.applicable} dimensions could be measured, and an unmeasured one counts for nothing, never for 100.`;
|
|
319
|
+
}
|
|
320
|
+
else if (kind === "worst" && s.cappedBy && s.value < s.mean) {
|
|
321
|
+
const worst = Math.round(s.value - HEALTH_SCORE_CAP_GAP);
|
|
322
|
+
cap = `Capped at ${v} by ${HEALTH_DIMENSION_DEFS[s.cappedBy]?.label ?? "an entry this app version cannot name"} (${worst} of 100): the entries average ${Math.round(s.mean)}, and the score stays within ${HEALTH_SCORE_CAP_GAP} of its worst entry.`;
|
|
323
|
+
}
|
|
324
|
+
let coverage = null;
|
|
325
|
+
if (c) {
|
|
326
|
+
// Full coverage is no news: a line only where something was not read, or where the engine could not say.
|
|
327
|
+
const notRecorded = "Which languages each reading covers was not recorded by the engine that measured this week.";
|
|
328
|
+
if (c.measured !== c.applicable) {
|
|
329
|
+
const head = `${c.measured} of ${c.applicable} dimensions measured. Unknown: ${unknownWords.join("; ")}.`;
|
|
330
|
+
coverage = c.reach ? head : `${head} ${notRecorded}`;
|
|
331
|
+
}
|
|
332
|
+
else if (!c.reach) {
|
|
333
|
+
coverage = notRecorded;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const partial = c ? c.items.filter((i) => i.state === "measured" && i.reason) : [];
|
|
337
|
+
const notes = partial.length
|
|
338
|
+
? `Read without part of the code: ${partial.map((i) => `${i.label}: ${i.reason}`).join("; ")}.`
|
|
339
|
+
: null;
|
|
340
|
+
const gates = c ? [...failing, ...c.gates.filter((g) => g.state === "unknown")].map((g) => g.text) : [];
|
|
341
|
+
return { cap, coverage, notes, gates };
|
|
342
|
+
}
|
|
343
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../src/healthindex/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type HealthEntry, type HealthSeriesRow } from "./types.js";
|
|
2
2
|
/** `100 · min(1, good / value)`; a value at or under 0 is 100. */
|
|
3
3
|
export declare function healthScore(value: number, good: number): number;
|
|
4
|
+
/** `100 · min(1, value / good)`, floored at `HEALTH_SCORE_FLOOR`: for an entry where more is better. */
|
|
5
|
+
export declare function healthScoreAtLeast(value: number, good: number): number;
|
|
6
|
+
/** One entry's score against its good line, in the entry's own direction. */
|
|
7
|
+
export declare function healthEntryScore(entry: HealthEntry, value: number, good: number): number;
|
|
4
8
|
/** The Monday (UTC) of the ISO week holding `day` (`YYYY-MM-DD`), or null for a malformed day. */
|
|
5
9
|
export declare function isoWeekOf(day: string): string | null;
|
|
6
10
|
/** The last row (greatest `ts`) of each ISO week, oldest week first. */
|
|
@@ -13,6 +17,10 @@ export declare function healthContextGood(contextWarnChars: number | null): numb
|
|
|
13
17
|
/** One week's readings: the five values (size's is `lineMean`), plus size's longest file. */
|
|
14
18
|
export interface HealthEntryReadings {
|
|
15
19
|
values: Partial<Record<HealthEntry, number>>;
|
|
20
|
+
/** An optional entry (`HEALTH_OPTIONAL_ENTRIES`) the row carries but could not read, with the engine's reason: UNKNOWN that week. */
|
|
21
|
+
absent?: Partial<Record<HealthEntry, string>>;
|
|
22
|
+
/** Optional entries the row has no field for at all (an engine that never took the reading): not applicable on that row. */
|
|
23
|
+
unrecorded?: HealthEntry[];
|
|
16
24
|
/** The longest file, read beside `lineMean`; absent where size is. */
|
|
17
25
|
max?: {
|
|
18
26
|
value: number;
|
|
@@ -34,7 +42,7 @@ export interface HealthEntryReadings {
|
|
|
34
42
|
* skills) counts as 0 descriptions.
|
|
35
43
|
*/
|
|
36
44
|
export declare function healthEntryReadings(row: HealthSeriesRow): HealthEntryReadings;
|
|
37
|
-
/** The
|
|
45
|
+
/** The values alone — `healthEntryReadings(row).values`. The warn line is not read here any more (scores read it). */
|
|
38
46
|
export declare function healthEntryValues(row: HealthSeriesRow, _contextWarnChars?: number | null): Partial<Record<HealthEntry, number>>;
|
|
39
47
|
/**
|
|
40
48
|
* What the repo applied on this row: its fingerprint and which entries it
|