@malloy-publisher/skills 0.1.28 → 0.1.30

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 (73) hide show
  1. package/package.json +1 -1
  2. package/skills/eval-answer/SKILL.md +1 -1
  3. package/skills/eval-answer/scripts/score_retrieval_test.py +15 -5
  4. package/skills/eval-diagnose/SKILL.md +1 -1
  5. package/skills/eval-import/SKILL.md +1 -1
  6. package/skills/eval-improve/SKILL.md +1 -1
  7. package/skills/eval-judge/SKILL.md +1 -1
  8. package/skills/eval-loop/SKILL.md +1 -1
  9. package/skills/eval-loop/reference/running-a-run.md +1 -1
  10. package/skills/eval-loop/scripts/build_run_package.py +4 -2
  11. package/skills/eval-loop/scripts/build_run_package_test.py +5 -0
  12. package/skills/eval-loop/scripts/run_baseline.py +1 -1
  13. package/skills/eval-loop/templates/eval-run-package/README.md +23 -17
  14. package/skills/eval-loop/templates/eval-run-package/eval_run.malloy +1 -1
  15. package/skills/eval-loop/templates/eval-run-package/{eval_run.malloynb → notebooks/eval_run.malloy} +55 -28
  16. package/skills/eval-loop/templates/eval-run-package/public/app.js +566 -141
  17. package/skills/eval-loop/templates/eval-run-package/public/index.html +347 -199
  18. package/skills/eval-report/SKILL.md +2 -2
  19. package/skills/malloy/SKILL.md +3 -2
  20. package/skills/malloy-analysis/SKILL.md +1 -1
  21. package/skills/malloy-analysis-pitfalls/SKILL.md +1 -1
  22. package/skills/malloy-analysis-report/SKILL.md +51 -17
  23. package/skills/malloy-analyze/SKILL.md +13 -13
  24. package/skills/malloy-charts/SKILL.md +1 -1
  25. package/skills/malloy-dashboards/SKILL.md +21 -7
  26. package/skills/malloy-data-app-design/SKILL.md +1 -1
  27. package/skills/malloy-debug/SKILL.md +1 -1
  28. package/skills/malloy-define/SKILL.md +2 -2
  29. package/skills/malloy-discover/SKILL.md +12 -3
  30. package/skills/malloy-document/SKILL.md +6 -6
  31. package/skills/malloy-getting-started/SKILL.md +1 -1
  32. package/skills/malloy-gotchas-modeling/SKILL.md +1 -1
  33. package/skills/malloy-gotchas-queries/SKILL.md +1 -1
  34. package/skills/malloy-gotchas-rendering/SKILL.md +1 -1
  35. package/skills/malloy-html-data-app-embedding/SKILL.md +1 -1
  36. package/skills/malloy-html-data-app-runtime/SKILL.md +1 -1
  37. package/skills/malloy-html-data-apps/SKILL.md +3 -3
  38. package/skills/malloy-lookml-review/SKILL.md +1 -1
  39. package/skills/malloy-materialization/SKILL.md +1 -1
  40. package/skills/malloy-materialization-tuning/SKILL.md +1 -1
  41. package/skills/malloy-model/SKILL.md +26 -61
  42. package/skills/malloy-model/reference/analysis-to-model.md +1 -1
  43. package/skills/malloy-model-as-you-go/SKILL.md +1 -1
  44. package/skills/malloy-modeling/SKILL.md +2 -2
  45. package/skills/malloy-notebook-chat/SKILL.md +1 -1
  46. package/skills/malloy-notebooks/SKILL.md +124 -109
  47. package/skills/malloy-patterns/SKILL.md +1 -1
  48. package/skills/malloy-phrase-detection/SKILL.md +1 -1
  49. package/skills/malloy-powerbi-review/NOTICE +24 -0
  50. package/skills/malloy-powerbi-review/SKILL.md +163 -0
  51. package/skills/malloy-powerbi-review/reference/_concepts.md +168 -0
  52. package/skills/malloy-powerbi-review/reference/cookbook-filter-context.md +425 -0
  53. package/skills/malloy-powerbi-review/reference/cookbook-structure.md +357 -0
  54. package/skills/malloy-powerbi-review/reference/cookbook-time.md +462 -0
  55. package/skills/malloy-powerbi-review/reference/corpus.md +103 -0
  56. package/skills/malloy-powerbi-review/reference/discover.md +190 -0
  57. package/skills/malloy-powerbi-review/reference/document.md +50 -0
  58. package/skills/malloy-powerbi-review/reference/limitations.md +137 -0
  59. package/skills/malloy-powerbi-review/reference/propose-fields.md +76 -0
  60. package/skills/malloy-powerbi-review/reference/review-coverage.md +75 -0
  61. package/skills/malloy-powerbi-review/reference/rls-roles.md +153 -0
  62. package/skills/malloy-powerbi-review/reference/translate-measures.md +315 -0
  63. package/skills/malloy-powerbi-review/scripts/classify_measures.py +1578 -0
  64. package/skills/malloy-powerbi-review/scripts/classify_measures_test.py +1448 -0
  65. package/skills/malloy-publish/SKILL.md +22 -5
  66. package/skills/malloy-queries/SKILL.md +27 -5
  67. package/skills/malloy-review/SKILL.md +1 -1
  68. package/skills/malloy-review/reference/output-template.md +2 -2
  69. package/skills/malloy-review/reference/rubric-correctness.md +2 -2
  70. package/skills/malloy-review/reference/rubric-structure.md +1 -1
  71. package/skills/malloy-review/reference/severity-taxonomy.md +1 -1
  72. package/skills/malloy-scope/SKILL.md +1 -1
  73. package/skills/malloy-source-unreachable/SKILL.md +3 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@malloy-publisher/skills",
3
3
  "description": "Agent skills for Malloy and the Malloy Publisher",
4
- "version": "0.1.28",
4
+ "version": "0.1.30",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-answer
3
3
  description: 'Score one analytical answer against a verified golden, and score which of the entities the golden depends on retrieval delivered to the answerer. Run the contamination checklist, re-execute the submitted query yourself, then spawn a judge subagent per skill:eval-judge. Append attempt, tool_call, score, and retrieval_score events to the file ledger (reference/ledger-schema.md). Never explain the failure (eval-diagnose) or edit the model (eval-improve). Use when asked whether an answer was correct, to score a run, or to baseline a model.'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # Evaluate One Answer
@@ -601,6 +601,16 @@ class LabelsMatchTheRunPackage(unittest.TestCase):
601
601
  "eval-run-package", *parts)) as fh:
602
602
  return fh.read()
603
603
 
604
+ def notebook_text(self):
605
+ """The notebook, at its `.malloy` path or the legacy `.malloynb` one that
606
+ run packages built before the switch still carry."""
607
+ for parts in (("notebooks", "eval_run.malloy"), ("eval_run.malloynb",)):
608
+ try:
609
+ return self.package_file(*parts)
610
+ except FileNotFoundError:
611
+ continue
612
+ raise FileNotFoundError("eval-run-package has no notebook")
613
+
604
614
  def emitted(self):
605
615
  from score_retrieval import (DELIVERED, MODEL, NEVER_ASKED,
606
616
  NOT_RETURNED, REFUSAL, UNMEASURED)
@@ -611,7 +621,7 @@ class LabelsMatchTheRunPackage(unittest.TestCase):
611
621
  """The legend is what a reader consults to interpret the column, so a
612
622
  label missing from it is worse than no legend. It named `documentation`
613
623
  -- a value that never appears -- and omitted `never asked` entirely."""
614
- text = self.package_file("eval_run.malloynb")
624
+ text = self.notebook_text()
615
625
  for label in self.emitted():
616
626
  self.assertIn(f"**{label}**", text, label)
617
627
 
@@ -643,11 +653,11 @@ class LabelsMatchTheRunPackage(unittest.TestCase):
643
653
 
644
654
  def test_no_retired_label_survives_in_the_package(self):
645
655
  # Each of these was a real value once; each now matches nothing.
646
- for f in (("eval_run.malloy",), ("eval_run.malloynb",),
647
- ("public", "app.js"), ("README.md",)):
648
- text = self.package_file(*f)
656
+ for text in (self.package_file("eval_run.malloy"), self.notebook_text(),
657
+ self.package_file("public", "app.js"),
658
+ self.package_file("README.md")):
649
659
  for retired in ("query construction", "retrieval ranking"):
650
- self.assertNotIn(retired, text, f"{f}: {retired}")
660
+ self.assertNotIn(retired, text, retired)
651
661
 
652
662
 
653
663
  class Summary(unittest.TestCase):
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-diagnose
3
3
  description: 'Diagnose why a scored answer failed and who owns the fix, then cluster the failures by shared root cause. Walk dataset, agent-call, get_context/model, get_context/retrieval, construction, then model-definition. Append issue events to the file ledger, linked by traceId, one per cluster. Use after eval-answer, when triaging a run, or before changing a model. Does not edit the model (eval-improve).'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # Diagnose One Answer
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-import
3
3
  description: 'Turn a list of questions into an eval set, whatever shape it arrived in: a JSONL a customer sent, a CSV, a spreadsheet export, a markdown doc, an email thread, or a pull from production logs. Classify each item by what came WITH the question (a query, a number, prose criteria, or nothing), write cases.jsonl and set.json per reference/case-format.md, keep the file as it arrived, and seal each question so a later edit is detectable. Never marks a value-bearing golden verified and never invents a question. Use when questions arrive from outside and need to become a set, or before the first run against a set nobody here authored.'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # Import questions into an eval set
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-improve
3
3
  description: 'Make the smallest safe Malloy model edit that closes a diagnosed model-owned gap, with a probe receipt for every factual claim. Use after eval-diagnose, or when asked to fix a model so an agent can discover the right answer. Never accepts its own edit; the acceptance check belongs to eval-loop. Does not decide whether an answer was wrong (eval-answer) or why (eval-diagnose).'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # Improve the Model
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-judge
3
3
  description: 'Decide whether ONE answer matches its golden, and say whether you believe the golden. Read this before emitting any verdict. Covers containment, column pairing, near_match, refusals, and the gold_status judgement. Use when scoring an attempt in an evaluation run; never to conduct a run (eval-loop), diagnose a failure (eval-diagnose) or edit a model (eval-improve).'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # The judge
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: eval-loop
3
3
  description: 'Conduct a local Publisher evaluation loop in five steps: scrape/run, eval, diagnose, improve, checkpoint. You are the conductor: import cases into the file ledger, spawn a blind answerer, then run eval-answer, eval-diagnose, and eval-improve. Persistence is plain files under the model package''s evals/ directory; checkpoints are git commits of the model repo. Use to score a model, diagnose failures, improve behind an acceptance check, or roll back a bad direction.'
4
- version: 0.1.28
4
+ version: 0.1.30
5
5
  ---
6
6
 
7
7
  # The Evaluation Loop
@@ -121,7 +121,7 @@ Three layers, in this order, and the order is what makes it readable:
121
121
  4. **DEEP DIVE.** A run directory is JSONL, which is a record and not a
122
122
  report, so this layer is the two commands that turn it into something you
123
123
  read: `build_run_package.py` (a Malloy model over the run's CSVs,
124
- `eval_run.malloynb` for the aggregate tables, and an in-package HTML app for
124
+ `notebooks/eval_run.malloy` for the aggregate tables, and an in-package HTML app for
125
125
  the case matrix and its per-case drawer), then a `POST .../packages` that
126
126
  registers it on the Publisher already running, with no restart. It prints
127
127
  the resulting URL with the run's own paths filled in.
@@ -10,7 +10,7 @@ an in-package HTML app for the case matrix.
10
10
  WHY BOTH A NOTEBOOK AND AN APP
11
11
 
12
12
  They are not redundant, and the split is not stylistic. Publisher renders a
13
- `.malloynb` natively, so the aggregate tables -- pass rate, effort, most-missed
13
+ `.malloy` notebook natively, so the aggregate tables -- pass rate, effort, most-missed
14
14
  entities, the backlog -- are best expressed as Malloy and left alone: no
15
15
  JavaScript to drift out of step with the model. What a notebook cannot do is
16
16
  open a drawer, and reading an eval is mostly drilling into one case. So the
@@ -530,9 +530,11 @@ def build(run_dirs: list[pathlib.Path], set_dir: pathlib.Path,
530
530
  "n_cases", "proposed_edit", "evidence", "confidence"])
531
531
  write_csv(data / "cluster_members.csv", member_rows, ["cluster_id", "qid"])
532
532
 
533
- for name in ("publisher.json", "eval_run.malloy", "eval_run.malloynb"):
533
+ for name in ("publisher.json", "eval_run.malloy"):
534
534
  if (TEMPLATE / name).exists():
535
535
  shutil.copy(TEMPLATE / name, out / name)
536
+ if (TEMPLATE / "notebooks").exists():
537
+ shutil.copytree(TEMPLATE / "notebooks", out / "notebooks", dirs_exist_ok=True)
536
538
  if (TEMPLATE / "public").exists():
537
539
  shutil.copytree(TEMPLATE / "public", out / "public", dirs_exist_ok=True)
538
540
 
@@ -75,6 +75,7 @@ class SourcesMatchTheCsvs(unittest.TestCase):
75
75
  capture_output=True, text=True, timeout=300)
76
76
  assert p.returncode == 0, p.stderr
77
77
  cls.data = out / "data"
78
+ cls.out = out
78
79
 
79
80
  @classmethod
80
81
  def tearDownClass(cls):
@@ -92,6 +93,10 @@ class SourcesMatchTheCsvs(unittest.TestCase):
92
93
  self.assertTrue(found, "no duckdb.table sources parsed from the model")
93
94
  return found
94
95
 
96
+ def test_the_package_carries_the_notebook_at_its_malloy_path(self):
97
+ self.assertTrue((self.out / "notebooks" / "eval_run.malloy").exists())
98
+ self.assertFalse((self.out / "eval_run.malloynb").exists())
99
+
95
100
  def test_every_declared_column_is_actually_written(self):
96
101
  for name, stem, block in self.sources():
97
102
  if not (self.data / f"{stem}.csv").exists():
@@ -1748,7 +1748,7 @@ def summary_lines(*, out: pathlib.Path, set_dir: pathlib.Path, events_n: int,
1748
1748
  lines += ["", "DEEP DIVE",
1749
1749
  " A run directory is JSONL, which is a record, not a report.",
1750
1750
  " build_run_package.py turns it into a servable Malloy package:",
1751
- " a model over the run's CSVs, eval_run.malloynb for the",
1751
+ " a model over the run's CSVs, notebooks/eval_run.malloy for the",
1752
1752
  " aggregate tables, and an in-package HTML app for the case",
1753
1753
  " matrix and its per-case drawer. Register it and open it:",
1754
1754
  "",
@@ -1,7 +1,7 @@
1
1
  # Eval-run package
2
2
 
3
3
  A finished run as a Malloy package you can open: the semantic model in
4
- `eval_run.malloy`, a notebook in `eval_run.malloynb`, an HTML data app in
4
+ `eval_run.malloy`, a notebook in `notebooks/eval_run.malloy`, an HTML data app in
5
5
  `public/`, and CSV under `data/` written by `../../scripts/build_run_package.py`.
6
6
 
7
7
  ```bash
@@ -32,22 +32,27 @@ product, found on data we control and understand.
32
32
 
33
33
  Both, and the split is not stylistic.
34
34
 
35
- **`eval_run.malloynb`** holds the analytical tables: pass rate, cost, effort,
35
+ **`notebooks/eval_run.malloy`** holds the analytical tables: pass rate, cost, effort,
36
36
  where the failures are, retrieval, the backlog. Publisher renders it natively, so
37
37
  these are Malloy reading the model directly with no JavaScript in between and
38
38
  nothing to drift.
39
39
 
40
- **`public/index.html`** is the case list -- one expandable row per case, with a
41
- verdict pill and a row of dots per arm (the entities the golden depends on: a
42
- ranked entity, a sibling-source alias, in a returned source's docs, or missing).
43
- Opening a row shows the golden as a table, then per arm: the effort line (turns,
44
- calls, errors, seconds, dollars), the judge's reasoning, the re-executed rows,
45
- and the attempt as a **timeline** -- every `get_context` and `execute_query` with
46
- its input and result, and the prose between them. That is the view a verdict
47
- cannot give: whether a wrong number came out of a wrong query or a right query
48
- read wrongly. A notebook cannot do that, and drilling into one case is most of
49
- what reading an eval consists of. Data comes from `steps.csv`, `required.csv`
50
- and the `prediction` column on attempts, all built from the run's transcripts.
40
+ **`public/index.html`** leads with the score and where every question landed,
41
+ then the diagnosis backlog (failures grouped by shared cause), an effort strip
42
+ (one dot per question), and the case list: one row per case, with a verdict pill
43
+ and a row of dots per arm (the entities the golden depends on: a ranked entity, a
44
+ sibling-source alias, in a returned source's docs, or missing). Clicking a row
45
+ opens that case in a side panel. Its **Summary** tab says why the judge decided
46
+ as it did, puts the golden beside the rows the agent's final query returns when
47
+ the harness re-runs it, shows the agent's final message, which required entities
48
+ search delivered, and what the attempt cost. Its **Step by step** tab is the
49
+ attempt as a list -- every `get_context` and `execute_query` and the prose
50
+ between them, one line each, opened in place to show the full query and its
51
+ result. That is the view a verdict cannot give: whether a wrong number came out
52
+ of a wrong query or a right query read wrongly. A notebook cannot do that, and
53
+ drilling into one case is most of what reading an eval consists of. Data comes
54
+ from `steps.csv`, `required.csv` and the `prediction` column on attempts, all
55
+ built from the run's transcripts.
51
56
 
52
57
  Both read the same model, which is what stops the two from disagreeing.
53
58
 
@@ -116,7 +121,7 @@ hole -- that exact bug is why the tables are cross-checked rather than trusted.
116
121
  ```bash
117
122
  publisher --server_root <parent-of-package> --mcp_port 4049
118
123
  # app http://localhost:4000/environments/evals/packages/eval-run/index.html
119
- # notebook http://localhost:4000/evals/eval-run/eval_run.malloynb
124
+ # notebook http://localhost:4000/evals/eval-run/notebooks/eval_run
120
125
  ```
121
126
 
122
127
  The two URLs are different on purpose and neither is guessable. `public/` is
@@ -133,13 +138,14 @@ file:
133
138
 
134
139
  ```bash
135
140
  curl -s .../api/v0/environments/<env>/packages/<pkg>/models # compiles the model
136
- curl -s .../api/v0/environments/<env>/packages/<pkg>/notebooks # lists .malloynb
141
+ curl -s .../api/v0/environments/<env>/packages/<pkg>/notebooks # lists the notebook
137
142
  ```
138
143
 
139
144
  `models` returns a 424 with the full compiler error when the Malloy is broken,
140
145
  which is the fastest way to see a compile failure. Notebooks are listed by
141
- `notebooks` and are **not** in `models`; asking for one under `models` returns
142
- `404 "<file> is a notebook"`. A notebook fetched from `notebooks/<file>` reports
146
+ `notebooks` and are **not** in the `models` list. A `.malloy` notebook still compiles
147
+ as a model, so `models/notebooks/eval_run.malloy` shows its compile errors; only a
148
+ legacy `.malloynb` returns `404 "<file> is a notebook"` there. A notebook fetched from `notebooks/<file>` reports
143
149
  its cells' compiled schemas under `modelInfo`, but only the cells it treats as
144
150
  anonymous queries -- do not read a low count there as cells failing to compile. To
145
151
  verify every cell, run each named query through `execute_query`.
@@ -775,7 +775,7 @@ query: case_matrix is scores -> {
775
775
  arms is count()
776
776
  arms_passed is passed
777
777
  nest: by_arm is {
778
- group_by: arm is runs.label, verdict, outcome, confidence,
778
+ group_by: arm is runs.label, verdict, outcome, confidence, counts,
779
779
  where_to_fix is retrieval.where_to_fix,
780
780
  recall is retrieval.recall
781
781
  order_by: arm
@@ -1,4 +1,8 @@
1
- >>>markdown
1
+ ##" One or more scored runs over one evaluation set: the analytical tables.
2
+ ## artifact { kind=notebook title="Eval run" }
3
+ import "../eval_run.malloy"
4
+
5
+ ##|(markdown)
2
6
  # Eval run
3
7
 
4
8
  One or more scored runs over one evaluation set. Publisher renders this natively,
@@ -12,9 +16,9 @@ open a drawer.
12
16
 
13
17
  Read it top to bottom: the headline, then whether the headline is trustworthy,
14
18
  then where the failures are, then what to do about them.
15
- >>>malloy
16
- import 'eval_run.malloy'
17
- >>>markdown
19
+ |##
20
+
21
+ ##|(markdown)
18
22
  ## 1. The headline
19
23
 
20
24
  Pass rate over **decided** verdicts -- `match` against `no_match`. Two things are
@@ -28,9 +32,11 @@ quietly depresses every arm:
28
32
  Read `confident_count` alongside the rate: two arms are only comparable when they
29
33
  answered the same cases. Read `near_matches` too. It is the leading indicator of
30
34
  rubrics going vague, and it moves before the pass rate does.
31
- >>>malloy
35
+ |##
36
+
32
37
  run: run_summary
33
- >>>markdown
38
+
39
+ ##|(markdown)
34
40
  ## 2. Is the headline trustworthy?
35
41
 
36
42
  A pass rate means nothing if the attempts behind it were contaminated, if the
@@ -39,7 +45,8 @@ harness fell over, or if the arms did not face the same set.
39
45
  Any contamination at all voids the run -- an attempt that saw the gold answer is
40
46
  not evidence about the model. Harness errors are excluded from the rate rather
41
47
  than counted as failures: a timeout is the eval failing, not the answerer.
42
- >>>malloy
48
+ |##
49
+
43
50
  run: attempts -> {
44
51
  group_by: arm is runs.label
45
52
  aggregate:
@@ -50,18 +57,21 @@ run: attempts -> {
50
57
  judge_version is runs.judge_version.max()
51
58
  set_version is runs.set_version.max()
52
59
  }
53
- >>>markdown
60
+
61
+ ##|(markdown)
54
62
  ## 3. What it cost
55
63
 
56
64
  The claim a semantic model makes is not only that the agent gets the right
57
65
  answer, but that it gets there quickly: fewer turns, fewer tokens, less money.
58
66
  An arm that wins on accuracy while costing three times as much has not obviously
59
67
  won.
60
- >>>malloy
68
+ |##
69
+
61
70
  run: cost
62
- >>>malloy
71
+
63
72
  run: effort
64
- >>>markdown
73
+
74
+ ##|(markdown)
65
75
  ## 4. Where the failures are
66
76
 
67
77
  Every failure carries exactly one **where to fix**, so these counts sum to the
@@ -82,9 +92,11 @@ tables below disagree with each other.
82
92
  - **coverage not measured** -- a miss on a case with no measured coverage label.
83
93
  Retrieval's or the model's, and nothing says which, so it is charged to
84
94
  neither.
85
- >>>malloy
95
+ |##
96
+
86
97
  run: failures_by_where_to_fix
87
- >>>markdown
98
+
99
+ ##|(markdown)
88
100
  ### Pass rate by coverage
89
101
 
90
102
  Coverage is the ceiling on what any agent can do. A model-shaped problem shows up
@@ -93,9 +105,11 @@ only by assembling it, and the agent could not.
93
105
 
94
106
  `absent` cases are scored on the **refusal** -- passing means the agent correctly
95
107
  declined.
96
- >>>malloy
108
+ |##
109
+
97
110
  run: pass_by_coverage
98
- >>>markdown
111
+
112
+ ##|(markdown)
99
113
  ## 5. Retrieval
100
114
 
101
115
  **Per-question entity recall**: of the entities each golden answer depends on, how
@@ -103,16 +117,20 @@ many the agent's own `get_context` calls delivered -- as a ranked entity, under
103
117
  sibling source, or named in a returned source's documentation. It uses the search
104
118
  terms the answerer chose, so it moves when the answerer changes; use it to
105
119
  attribute a failure *within* one arm, not to compare retrieval across arms.
106
- >>>malloy
120
+ |##
121
+
107
122
  run: retrieval_as_used
108
- >>>markdown
123
+
124
+ ##|(markdown)
109
125
  ### Entities most often needed and not returned
110
126
 
111
127
  The ranked retrieval backlog. An entity high on this list is one fix that several
112
128
  cases are waiting on.
113
- >>>malloy
129
+ |##
130
+
114
131
  run: most_missed_entities
115
- >>>markdown
132
+
133
+ ##|(markdown)
116
134
  ## 6. What to do next
117
135
 
118
136
  Failures grouped by shared root cause, ordered by how many cases one edit would
@@ -122,17 +140,21 @@ clear. Eight failures are rarely eight problems.
122
140
  proposal is an open question, and that is an honest state -- a generated proposal
123
141
  that nobody stands behind is worse than a blank, because a reviewer has to
124
142
  disprove it.
125
- >>>malloy
143
+ |##
144
+
126
145
  run: backlog
127
- >>>markdown
146
+
147
+ ##|(markdown)
128
148
  ### Coverage gaps in the set itself
129
149
 
130
150
  Independent of any run: cases the model cannot answer outright, with the entity
131
151
  that would close the gap. This is the model-improvement backlog even before an
132
152
  agent has attempted anything, and it is the part a customer can act on directly.
133
- >>>malloy
153
+ |##
154
+
134
155
  run: coverage_gaps
135
- >>>markdown
156
+
157
+ ##|(markdown)
136
158
  ## 7. Refusal behaviour
137
159
 
138
160
  Refusal is scored in both directions, and getting one right while getting the
@@ -143,9 +165,11 @@ other wrong is a common and misleading result.
143
165
  - A case tagged **answerable-sounds-unanswerable** passes by *answering*. An agent
144
166
  that has learned to refuse whenever a question sounds hard will fail these while
145
167
  looking well-calibrated on the ones above.
146
- >>>malloy
168
+ |##
169
+
147
170
  run: refusal_behaviour
148
- >>>markdown
171
+
172
+ ##|(markdown)
149
173
  ## 8. Comparing arms
150
174
 
151
175
  Only meaningful with two or more arms loaded.
@@ -156,12 +180,15 @@ one case. What matters is which cases actually moved, and in which direction.
156
180
 
157
181
  `arms_passed` between 1 and `arms` means the arms disagree. Read the nested
158
182
  verdicts to see who won each one.
159
- >>>malloy
183
+ |##
184
+
160
185
  run: flips
161
- >>>markdown
186
+
187
+ ##|(markdown)
162
188
  ### Cases every arm failed
163
189
 
164
190
  Changing the answerer will not move these. They are where model and retrieval
165
191
  work pays off, and they are the most durable finding in the whole run.
166
- >>>malloy
192
+ |##
193
+
167
194
  run: failed_everywhere