static-fire 0.0.0-stage → 0.54.1

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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +236 -2
  3. package/bin/static-fire.js +46 -0
  4. package/package.json +30 -4
  5. package/pricing.yaml +20 -0
  6. package/src/adapters/index.ts +153 -0
  7. package/src/api.ts +250 -0
  8. package/src/cli.ts +383 -0
  9. package/src/core/apkit-install.ts +47 -0
  10. package/src/core/authored.ts +47 -0
  11. package/src/core/batch-state.ts +25 -0
  12. package/src/core/batch.ts +450 -0
  13. package/src/core/batches.ts +221 -0
  14. package/src/core/checks.ts +63 -0
  15. package/src/core/commands.ts +43 -0
  16. package/src/core/compare.ts +206 -0
  17. package/src/core/config.ts +25 -0
  18. package/src/core/copying.ts +18 -0
  19. package/src/core/coverage.ts +84 -0
  20. package/src/core/db.ts +608 -0
  21. package/src/core/derived.ts +74 -0
  22. package/src/core/engine.ts +85 -0
  23. package/src/core/facets.ts +143 -0
  24. package/src/core/grade.ts +197 -0
  25. package/src/core/grading-versions.ts +281 -0
  26. package/src/core/identity.ts +263 -0
  27. package/src/core/init.ts +321 -0
  28. package/src/core/judge-schema.ts +37 -0
  29. package/src/core/judge.ts +166 -0
  30. package/src/core/label.ts +43 -0
  31. package/src/core/lock.ts +40 -0
  32. package/src/core/migrate.ts +288 -0
  33. package/src/core/new-task.ts +85 -0
  34. package/src/core/outside-tools.ts +129 -0
  35. package/src/core/plan.ts +84 -0
  36. package/src/core/profiles.ts +42 -0
  37. package/src/core/project.ts +140 -0
  38. package/src/core/regrade.ts +242 -0
  39. package/src/core/score.ts +148 -0
  40. package/src/core/settings.ts +44 -0
  41. package/src/core/task-file.ts +95 -0
  42. package/src/core/task-page.ts +54 -0
  43. package/src/core/trial-detail.ts +73 -0
  44. package/src/core/types.ts +195 -0
  45. package/src/core/view-query.ts +102 -0
  46. package/src/core/view.ts +576 -0
  47. package/src/guide.md +624 -0
  48. package/src/server.ts +28 -0
  49. package/web/api.ts +6 -0
  50. package/web/app.tsx +1162 -0
  51. package/web/brand/offset-tokens.css +126 -0
  52. package/web/charts.tsx +190 -0
  53. package/web/compare.tsx +317 -0
  54. package/web/encoding.tsx +55 -0
  55. package/web/filter-menu.ts +195 -0
  56. package/web/how-it-works.tsx +92 -0
  57. package/web/index-switches.ts +29 -0
  58. package/web/index.html +17 -0
  59. package/web/levels.tsx +15 -0
  60. package/web/notices.ts +74 -0
  61. package/web/output-view.ts +61 -0
  62. package/web/pages.ts +42 -0
  63. package/web/run-status.ts +51 -0
  64. package/web/styles.css +368 -0
  65. package/web/task-card.ts +6 -0
  66. package/web/tasks.tsx +122 -0
  67. package/web/wording.ts +38 -0
@@ -0,0 +1,84 @@
1
+ // Which suites a view's index covers, and why the others are left out (DEC-019, DEC-020). The rule that picks the
2
+ // default set is here, and so is the one line that `static-fire show` and the dashboard both print. No Node
3
+ // imports: the dashboard bundles this file.
4
+
5
+ /** A suite as the line names it. */
6
+ export interface SuiteRef { id: string; title: string }
7
+
8
+ /**
9
+ * Why a suite is not in view: the user did not pick it, no config has completed it, or too few configs have
10
+ * completed it together with the suites in view.
11
+ */
12
+ export type LeftOutReason = "not-picked" | "none-completed" | "too-few";
13
+
14
+ /** What a view's index covers. A view of tasks (no suites) has none. */
15
+ export interface Coverage {
16
+ /** True when the suites were picked; false when the view chose them by the default rule. */
17
+ picked: boolean;
18
+ /** The suites in view, in catalog order: the Agent Performance Index is the mean of their Suite Indexes. */
19
+ covered: SuiteRef[];
20
+ /**
21
+ * Every other suite of the catalog, in catalog order, with the reason and how many configs in view have completed
22
+ * it. That count is null for a suite left out because it was not picked: the view does not read its trials.
23
+ */
24
+ leftOut: (SuiteRef & { reason: LeftOutReason; completed: number | null })[];
25
+ /** How many configs have completed every covered suite: the configs that have an index. */
26
+ complete: number;
27
+ }
28
+
29
+ /**
30
+ * The default set of suites (DEC-019). `suites` are the suite ids in catalog order; `completedBy` gives, for each,
31
+ * the configs that have a valid score on every task of it. Start with every suite and drop the suite the fewest
32
+ * configs have completed (on a tie, the one listed last), until at least two configs have completed all that
33
+ * remain. When no set has two, keep the largest set that one config has completed (on a tie, the set that comes
34
+ * first in catalog order). When no config has completed any suite, keep every suite. The result is in catalog order, and the same input always gives the same set.
35
+ */
36
+ export function defaultSuites(suites: string[], completedBy: Map<string, Set<string>>): string[] {
37
+ const done = (id: string) => completedBy.get(id) ?? new Set<string>();
38
+ const completers = (ids: string[]) => {
39
+ if (!ids.length) return 0;
40
+ let all = new Set(done(ids[0]!));
41
+ for (const id of ids.slice(1)) all = new Set([...all].filter((c) => done(id).has(c)));
42
+ return all.size;
43
+ };
44
+ const left = [...suites];
45
+ while (left.length && completers(left) < 2) {
46
+ let drop = left[0]!;
47
+ for (const id of left) if (done(id).size <= done(drop).size) drop = id; // <=: on a tie the later one
48
+ left.splice(left.indexOf(drop), 1);
49
+ }
50
+ if (left.length && completers(left) >= 2) return left;
51
+
52
+ // No set has two configs: the largest set one config has completed.
53
+ const configs = [...new Set([...completedBy.values()].flatMap((s) => [...s]))].sort();
54
+ const pos = (ids: string[]) => ids.map((id) => suites.indexOf(id));
55
+ const earlier = (a: string[], b: string[]) => { const pa = pos(a), pb = pos(b); for (let i = 0; i < pa.length; i++) if (pa[i] !== pb[i]) return pa[i]! < pb[i]!; return false; };
56
+ let best: string[] = [];
57
+ for (const c of configs) {
58
+ const set = suites.filter((id) => done(id).has(c));
59
+ if (set.length > best.length || (set.length === best.length && earlier(set, best))) best = set;
60
+ }
61
+ return best.length ? best : [...suites];
62
+ }
63
+
64
+ const list = (names: string[]) => names.length <= 1 ? names.join("") : `${names.slice(0, -1).join(", ")} and ${names.at(-1)}`;
65
+
66
+ /**
67
+ * The one line a view gives about its index: which suites it covers and, grouped by reason, which it leaves out
68
+ * and why. `judge` is the label of the judge in view. Null for a view of tasks.
69
+ */
70
+ export function coverageLine(coverage: Coverage | null, judge: string): string | null {
71
+ if (!coverage) return null;
72
+ const parts = [`Covers ${list(coverage.covered.map((s) => s.title)) || "no suite"}.`];
73
+ const why: Record<LeftOutReason, (many: boolean) => string> = {
74
+ "none-completed": () => `no config has a score on every task under judge ${judge}`,
75
+ "too-few": (many) => `fewer than two configs have completed ${many ? "them" : "it"} with the suites covered`,
76
+ "not-picked": () => "not picked",
77
+ };
78
+ const groups = (["none-completed", "too-few", "not-picked"] as const)
79
+ .map((r) => [r, coverage.leftOut.filter((s) => s.reason === r)] as const).filter(([, s]) => s.length)
80
+ .map(([r, s]) => `${list(s.map((x) => x.title))} (${why[r](s.length > 1)})`);
81
+ if (groups.length) parts.push(`Left out: ${groups.join("; ")}.`);
82
+ if (!coverage.complete && coverage.covered.length) parts.push(`No config has a score on every task of ${coverage.covered.length > 1 ? "these suites" : "it"} yet.`);
83
+ return parts.join(" ");
84
+ }