@tangle-network/charts 0.1.0 → 0.1.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Tangle Network
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -15,6 +15,14 @@ The library draws and never decides.
15
15
  Ranks, intervals, frontier membership, estimate labels and pass counts come from the producer: a board record, a VerticalBench report or an agent-eval lens.
16
16
  A figure function returns a `Refusal` in place of a figure it cannot draw honestly, for example a bar over too few units, an interval that names no method, or a frontier the producer did not compute.
17
17
 
18
+ The producer's `estimate` controls rate marks: `descriptive` draws a rate bar and may show a named Wilson score interval when that estimate meets the producer's unit threshold.
19
+ Task-clustered bootstrap intervals require a `bootstrap` estimate.
20
+ Intervals without support are marked as not drawn in the data table and note.
21
+ A missing, zero, or unproven cost prints `unknown`; zero passes print `no pass`.
22
+ Rank numbers require every row to carry both a rank and a `bootstrap` estimate.
23
+ Malformed rates, intervals, matrix counts, and breakdown counts return a refusal instead of a misleading mark.
24
+ An interval whisker is omitted when its bounds exclude the row's rate.
25
+
18
26
  It has no runtime dependencies and uses no DOM, so it runs in a Worker, a build step or a browser.
19
27
 
20
28
  ## Use
@@ -55,5 +63,4 @@ pnpm --filter @tangle-network/charts build # fails when src/css.generated.ts
55
63
 
56
64
  ## Release
57
65
 
58
- The package is private until its first npm publish.
59
- npm trusted publishing needs the package to exist before a trusted publisher can be added, so the first version is published once by an owner, then `npm trust github @tangle-network/charts --file release.yml --repo tangle-network/brand --allow-publish` hands later versions to the release workflow.
66
+ Versions publish from the brand release workflow through npm trusted publishing, like `@tangle-network/brand` and `@tangle-network/ui`.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ //#region src/types.d.ts
1
2
  /**
2
3
  * Inputs and outputs of the figure functions.
3
4
  *
@@ -15,10 +16,10 @@ type IntervalMethod = "task-cluster-bootstrap" | "mcnemar-exact" | "wilson";
15
16
  * interval that does not name both.
16
17
  */
17
18
  interface Interval {
18
- lower: number;
19
- upper: number;
20
- level: number | null;
21
- method: IntervalMethod | null;
19
+ lower: number;
20
+ upper: number;
21
+ level: number | null;
22
+ method: IntervalMethod | null;
22
23
  }
23
24
  /** The App Grade ladder, lowest first. U (unable to measure) is not on it. */
24
25
  type Tier = "F" | "C" | "B" | "A" | "S";
@@ -27,255 +28,187 @@ type TierCounts = Record<Tier, number>;
27
28
  type CostBasis = "receipts" | "estimated" | "unknown";
28
29
  /** A column or row identity: an AgentProfile, a model, a judge, a search node. */
29
30
  interface Setup {
30
- id: string;
31
- label: string;
32
- /** Null when the order is a sort, not a ranking backed by comparisons. */
33
- rank: number | null;
31
+ id: string;
32
+ label: string;
33
+ /** Null when the order is a sort, not a ranking backed by comparisons. */
34
+ rank: number | null;
34
35
  }
35
36
  /** One setup's rate. Field names follow the board record's `BoardProfile`. */
36
37
  interface RateRow extends Setup {
37
- solved: number;
38
- attempts: number;
39
- rate: number;
40
- /** The producer's label for what `attempts` supports; the library holds no threshold. */
41
- estimate: Estimate;
42
- interval: Interval | null;
43
- tiers: TierCounts | null;
44
- cost: {
45
- perSolvedUsd: number | null;
46
- basis: CostBasis;
47
- receipts: number | null;
48
- };
49
- medianWallMs: number | null;
50
- /** Null when the producer computed no frontier. */
51
- onFront: boolean | null;
38
+ solved: number;
39
+ attempts: number;
40
+ rate: number;
41
+ /** The producer's label for what `attempts` supports; the library holds no threshold. */
42
+ estimate: Estimate;
43
+ interval: Interval | null;
44
+ tiers: TierCounts | null;
45
+ cost: {
46
+ perSolvedUsd: number | null;
47
+ basis: CostBasis;
48
+ receipts: number | null;
49
+ };
50
+ medianWallMs: number | null;
51
+ /** Null when the producer computed no frontier. */
52
+ onFront: boolean | null;
52
53
  }
53
54
  /** One task × setup cell. */
54
55
  interface MatrixCell {
55
- task: string;
56
- setup: string;
57
- /** Attempts that count; null when the cell never ran. */
58
- attempts: number | null;
59
- /** Attempts that passed; null when no pass rule applies. */
60
- solved: number | null;
61
- /** Attempts graded on the App Grade ladder. */
62
- tiers: TierCounts | null;
63
- /** Attempts graded U: no floor check failed, but one could not be observed. */
64
- unmeasured?: number;
65
- /** Attempts whose grade failed an integrity check and awaits human review. */
66
- flagged?: number;
67
- /** A lens cell's mean score; null when the setup never scored the task. */
68
- mean: number | null;
69
- costUsd: number | null;
56
+ task: string;
57
+ setup: string;
58
+ /** Attempts that count; null when the cell never ran. */
59
+ attempts: number | null;
60
+ /** Attempts that passed; null when no pass rule applies. */
61
+ solved: number | null;
62
+ /** Attempts graded on the App Grade ladder. */
63
+ tiers: TierCounts | null;
64
+ /** Attempts graded U: no floor check failed, but one could not be observed. */
65
+ unmeasured?: number;
66
+ /** Attempts whose grade failed an integrity check and awaits human review. */
67
+ flagged?: number;
68
+ /** A lens cell's mean score; null when the setup never scored the task. */
69
+ mean: number | null;
70
+ costUsd: number | null;
70
71
  }
71
72
  interface ComparisonRow {
72
- /** Setup ids. */
73
- favored: string;
74
- other: string;
75
- pairs: number | null;
76
- minimumEffect: number | null;
77
- /** The clustered interval on the difference, in the measure's units. */
78
- interval: Interval | null;
79
- /** The exact interval, drawn under the clustered one when present. */
80
- exactInterval: Interval | null;
73
+ /** Setup ids. */
74
+ favored: string;
75
+ other: string;
76
+ pairs: number | null;
77
+ minimumEffect: number | null;
78
+ /** The clustered interval on the difference, in the measure's units. */
79
+ interval: Interval | null;
80
+ /** The exact interval, drawn under the clustered one when present. */
81
+ exactInterval: Interval | null;
81
82
  }
82
83
  interface BreakdownInput {
83
- reasons: string[];
84
- setups: Array<{
85
- id: string;
86
- label: string;
87
- n: number | null;
88
- }>;
89
- counts: Array<{
90
- reason: string;
91
- setup: string;
92
- count: number | null;
93
- }>;
94
- excluded: {
95
- count: number;
96
- why: string;
97
- } | null;
98
- /** True when one attempt can count under several reasons. */
99
- overlapping?: boolean;
84
+ reasons: string[];
85
+ setups: Array<{
86
+ id: string;
87
+ label: string;
88
+ n: number | null;
89
+ }>;
90
+ counts: Array<{
91
+ reason: string;
92
+ setup: string;
93
+ count: number | null;
94
+ }>;
95
+ excluded: {
96
+ count: number;
97
+ why: string;
98
+ } | null;
99
+ /** True when one attempt can count under several reasons. */
100
+ overlapping?: boolean;
100
101
  }
101
102
  /** Attempts left out of a figure, stated in its note. */
102
103
  interface Exclusion {
103
- count: number;
104
- why: string;
104
+ count: number;
105
+ why: string;
105
106
  }
106
107
  interface Figure {
107
- id: string;
108
- /** Generated from the input; no function accepts heading text. */
109
- finding: string;
110
- /** One quantified sentence. */
111
- lede: string;
112
- /** How to read the marks. */
113
- read: string;
114
- /** 720 px and 358 px renders; a null narrow render means the table is the phone view. */
115
- svg: {
116
- wide: string;
117
- narrow: string | null;
118
- };
119
- /** An HTML table with every number the plot shows. */
120
- table: string;
121
- note: {
122
- method: string;
123
- n: string;
124
- exclusions: string[];
125
- };
108
+ id: string;
109
+ /** Generated from the input; no function accepts heading text. */
110
+ finding: string;
111
+ /** One quantified sentence. */
112
+ lede: string;
113
+ /** How to read the marks. */
114
+ read: string;
115
+ /** 720 px and 358 px renders; a null narrow render means the table is the phone view. */
116
+ svg: {
117
+ wide: string;
118
+ narrow: string | null;
119
+ };
120
+ /** An HTML table with every number the plot shows. */
121
+ table: string;
122
+ note: {
123
+ method: string;
124
+ n: string;
125
+ exclusions: string[];
126
+ };
126
127
  }
127
128
  interface Refusal {
128
- id: string;
129
- refused: string;
129
+ id: string;
130
+ refused: string;
130
131
  }
131
- declare function isRefusal(value: Figure | Refusal): value is Refusal;
132
-
133
- /**
134
- * The figure block: one markup for every figure on every surface.
135
- *
136
- * In order: the finding as a heading with a note reference, a one-sentence
137
- * lede, the plot (both widths, swapped by `figure.css` on the figure's own
138
- * width), a reading line, and the data table in a disclosure. Notes render
139
- * once per page, numbered, each with a way back to its figure.
140
- */
141
-
142
- declare function renderFigure(f: Figure, noteNumber: number): string;
132
+ export declare function isRefusal(value: Figure | Refusal): value is Refusal;
133
+ //#endregion
134
+ //#region src/block.d.ts
135
+ export declare function renderFigure(f: Figure, noteNumber: number): string;
143
136
  /** Numbered notes for `figures`, in the order their blocks were numbered (1-based). */
144
- declare function renderNotes(figures: Figure[]): string;
137
+ export declare function renderNotes(figures: Figure[]): string;
145
138
  /** What a page leaves out, and why. */
146
- declare function renderRefusals(refusals: Refusal[]): string;
147
-
148
- /**
149
- * `breakdown`: why attempts fail.
150
- *
151
- * Rows are reasons (a failure layer, cause or check); columns are setups with
152
- * `n=` under each name. Each cell prints its count over a neutral tint of
153
- * count / n, capped at 50% so ink keeps its contrast. The accent never marks a
154
- * failure. On a phone the table is the view.
155
- *
156
- * Refuses: a share without its column n (the count prints with no tint);
157
- * counting excluded attempts (they are stated in the note); hiding a zero.
158
- */
159
-
139
+ export declare function renderRefusals(refusals: Refusal[]): string;
140
+ //#endregion
141
+ //#region src/breakdown.d.ts
160
142
  interface BreakdownOptions {
161
- /** What a row counts, lower case: "failed checks". */
162
- measure: string;
163
- id?: string;
143
+ /** What a row counts, lower case: "failed checks". */
144
+ measure: string;
145
+ id?: string;
164
146
  }
165
- declare function breakdown(input: BreakdownInput, o: BreakdownOptions): Figure | Refusal;
166
-
167
- /**
168
- * `comparisonIntervals`: is each step in an order real.
169
- *
170
- * One row per comparison, "{favored} over {other}", with the pair count. x is
171
- * the difference in points with a muted zero line. The clustered interval is a
172
- * 6 px accent bar, the exact interval a 2 px muted bar under it, and a dashed
173
- * ink tick marks the row's registered minimum effect. There is no point
174
- * estimate, because the record carries none.
175
- *
176
- * Refuses: a row whose interval names no level or method, or that has no pair
177
- * count or no registered minimum effect (each is listed in the note); the
178
- * whole figure when no row can be drawn.
179
- */
180
-
147
+ export declare function breakdown(input: BreakdownInput, o: BreakdownOptions): Figure | Refusal;
148
+ //#endregion
149
+ //#region src/comparison-intervals.d.ts
181
150
  interface ComparisonIntervalsOptions {
182
- /** The measure the difference is in, lower case: "solve rate". */
183
- measure: string;
184
- id?: string;
151
+ /** The measure the difference is in, lower case: "solve rate". */
152
+ measure: string;
153
+ id?: string;
185
154
  }
186
- declare function comparisonIntervals(rows: ComparisonRow[], setups: Setup[], o: ComparisonIntervalsOptions): Figure | Refusal;
187
-
188
- /**
189
- * `costFrontier`: which setup gives the most passes per dollar.
190
- *
191
- * y is the measure on a fixed 0–1 axis. x is cost per pass on a log
192
- * scale, reversed so cheaper sits right and better is always up and right. A
193
- * point on the producer's frontier is an accent disc; any other point is a
194
- * hollow muted circle, and an estimated cost is never a filled disc. An ink
195
- * line joins frontier points. Every point is labelled directly; a label that
196
- * collides everywhere becomes a number listed in the table. A setup with no
197
- * pass or an unknown cost is listed under the axis, never placed at an
198
- * origin a log axis does not have. On a phone the plot becomes a list sorted
199
- * by the measure, with the same point marks, a rate bar and the cost as text.
200
- *
201
- * Refuses: the whole figure when fewer than two setups have a cost per pass; the frontier line unless two or more rows carry `onFront: true` (it
202
- * never computes dominance itself).
203
- */
204
-
155
+ export declare function comparisonIntervals(rows: ComparisonRow[], setups: Setup[], o: ComparisonIntervalsOptions): Figure | Refusal;
156
+ //#endregion
157
+ //#region src/cost-frontier.d.ts
205
158
  interface CostFrontierOptions {
206
- /** The y measure, lower case: "solve rate". */
207
- measure: string;
208
- id?: string;
159
+ /** The y measure, lower case: "solve rate". */
160
+ measure: string;
161
+ id?: string;
209
162
  }
210
- declare function costFrontier(rows: RateRow[], o: CostFrontierOptions): Figure | Refusal;
211
-
163
+ export declare function costFrontier(rows: RateRow[], o: CostFrontierOptions): Figure | Refusal;
164
+ //#endregion
165
+ //#region src/css.generated.d.ts
212
166
  /** The figure block and mark styles (src/figure.css), for documents that inline their CSS. */
213
- declare const figureCss: string;
167
+ export declare const figureCss: string;
214
168
  /** --chart-* resolved per theme, for documents without brand tokens: light, dark by preference or [data-theme="dark"], light in print. */
215
- declare const chartTokensCss: string;
216
-
169
+ export declare const chartTokensCss: string;
170
+ //#endregion
171
+ //#region src/format.d.ts
217
172
  /**
218
- * `rankedRates`: which setup passes most, and how uncertain is each rate.
219
- *
220
- * One row per setup: rank (only when every row is ranked), label, an accent
221
- * bar on a shared 0–1 axis with the interval as an ink whisker, `passed/n`,
222
- * cost per pass and median run. An App Grade grader adds a tier strip under
223
- * the bar with a tick at the pass tier. Ranked rows keep their rank order;
224
- * unranked rows sort by rate, and the finding says no comparison backs it.
225
- *
226
- * Refuses: a bar when the producer labels the estimate `none` or
227
- * `insufficient` (the row prints its count only); a whisker whose interval
228
- * names no level or method; a rank number unless every row carries one; any
229
- * cost it was not given. It never prints "winner", "best" or "#1".
173
+ * The order rows are drawn in. Ranked rows keep their rank. Otherwise rows
174
+ * with enough units to draw a rate come first, highest rate first; rows with
175
+ * too few units follow, most units first, so a 1/1 row never heads the list.
230
176
  */
231
-
177
+ export declare function rateOrder<T extends Pick<RateRow, "rank" | "rate" | "estimate" | "attempts">>(rows: readonly T[]): T[];
178
+ //#endregion
179
+ //#region src/ranked-rates.d.ts
232
180
  interface RankedRatesOptions {
233
- /** What the rate measures, lower case: "solve rate". */
234
- measure: string;
235
- /** The App Grade tier a pass needs; marks the tier strip. */
236
- passTier?: Tier;
237
- /** Singular, lower-case nouns: what one unit of `attempts` is, and what a row is. */
238
- nouns?: {
239
- attempt: string;
240
- setup: string;
241
- };
242
- id?: string;
243
- excluded?: Exclusion[];
181
+ /** What the rate measures, lower case: "solve rate". */
182
+ measure: string;
183
+ /** The App Grade tier a pass needs; marks the tier strip. */
184
+ passTier?: Tier;
185
+ /** Singular, lower-case nouns: what one unit of `attempts` is, and what a row is. */
186
+ nouns?: {
187
+ attempt: string;
188
+ setup: string;
189
+ };
190
+ id?: string;
191
+ excluded?: Exclusion[];
244
192
  }
245
- declare function rankedRates(input: RateRow[], o: RankedRatesOptions): Figure | Refusal;
246
-
247
- /**
248
- * `taskMatrix`: where each setup succeeds and fails.
249
- *
250
- * Rows are tasks in the given (registered) order; columns are setups in rank
251
- * order when every setup is ranked, otherwise in the given order. Each cell
252
- * draws one 12 px tile per attempt, best first, then `solved/attempts`.
253
- * App Grade tiles fill by tier and F is an outline; U (unable to measure) is a
254
- * dashed outline and an integrity-flagged grade is a struck outline. Runner
255
- * verification fills solved tiles with the accent. A lens matrix (`show:
256
- * "means"`) prints each mean with a bar on one shared scale.
257
- *
258
- * Refuses: a fill for an attempt without a grade (outline with a dot); a zero
259
- * for a cell that never ran ("·"); counts that do not add up; any column order
260
- * but the given rank.
261
- */
262
-
193
+ export declare function rankedRates(input: RateRow[], o: RankedRatesOptions): Figure | Refusal;
194
+ //#endregion
195
+ //#region src/task-matrix.d.ts
263
196
  interface TaskMatrixOptions {
264
- /** The App Grade tier a pass needs; named in the legend. */
265
- passTier?: Tier;
266
- /** "attempts" draws a tile per attempt; "means" draws one tinted cell per mean. */
267
- show?: "attempts" | "means";
268
- /** Singular, lower-case nouns for rows, columns and one attempt. */
269
- nouns?: {
270
- task: string;
271
- setup: string;
272
- attempt?: string;
273
- };
274
- /** The columns grade the same attempts (judges on one set of plants): the finding reports agreement. */
275
- agreement?: boolean;
276
- id?: string;
277
- excluded?: Exclusion[];
197
+ /** The App Grade tier a pass needs; named in the legend. */
198
+ passTier?: Tier;
199
+ /** "attempts" draws a tile per attempt; "means" draws one tinted cell per mean. */
200
+ show?: "attempts" | "means";
201
+ /** Singular, lower-case nouns for rows, columns and one attempt. */
202
+ nouns?: {
203
+ task: string;
204
+ setup: string;
205
+ attempt?: string;
206
+ };
207
+ /** The columns grade the same attempts (judges on one set of plants): the finding reports agreement. */
208
+ agreement?: boolean;
209
+ id?: string;
210
+ excluded?: Exclusion[];
278
211
  }
279
- declare function taskMatrix(tasks: string[], setupsIn: Setup[], cells: MatrixCell[], o?: TaskMatrixOptions): Figure | Refusal;
280
-
281
- export { type BreakdownInput, type BreakdownOptions, type ComparisonIntervalsOptions, type ComparisonRow, type CostBasis, type CostFrontierOptions, type Estimate, type Exclusion, type Figure, type Interval, type IntervalMethod, type MatrixCell, type RankedRatesOptions, type RateRow, type Refusal, type Setup, type TaskMatrixOptions, type Tier, type TierCounts, breakdown, chartTokensCss, comparisonIntervals, costFrontier, figureCss, isRefusal, rankedRates, renderFigure, renderNotes, renderRefusals, taskMatrix };
212
+ export declare function taskMatrix(tasks: string[], setupsIn: Setup[], cells: MatrixCell[], o?: TaskMatrixOptions): Figure | Refusal;
213
+ //#endregion
214
+ export type { BreakdownInput, BreakdownOptions, ComparisonIntervalsOptions, ComparisonRow, CostBasis, CostFrontierOptions, Estimate, Exclusion, Figure, Interval, IntervalMethod, MatrixCell, RankedRatesOptions, RateRow, Refusal, Setup, TaskMatrixOptions, Tier, TierCounts };