eklavya 1.13.1 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/ask.js +25 -43
  2. package/dist/ask.js.map +1 -1
  3. package/dist/assets/tutor/SKILL.md +180 -0
  4. package/dist/assets/tutor/references/focus-and-level.md +156 -0
  5. package/dist/assets/tutor/references/grading.md +113 -0
  6. package/dist/assets/tutor/references/writing-mcq.md +133 -0
  7. package/dist/cli.js +136 -5
  8. package/dist/cli.js.map +1 -1
  9. package/dist/eval/extract-json.js +81 -0
  10. package/dist/eval/extract-json.js.map +1 -0
  11. package/dist/eval/extraction-score.js +115 -0
  12. package/dist/eval/extraction-score.js.map +1 -0
  13. package/dist/eval/history-stats.js +230 -0
  14. package/dist/eval/history-stats.js.map +1 -0
  15. package/dist/eval/question-checks.js +220 -0
  16. package/dist/eval/question-checks.js.map +1 -0
  17. package/dist/hooks/checkpoint-quiz.js +1 -1
  18. package/dist/hooks/lib.js +38 -13
  19. package/dist/hooks/lib.js.map +1 -1
  20. package/dist/hooks/prompt-submit-nudge.js +155 -0
  21. package/dist/hooks/prompt-submit-nudge.js.map +1 -0
  22. package/dist/hooks/session-start.js +32 -14
  23. package/dist/hooks/session-start.js.map +1 -1
  24. package/dist/hooks/stop-quiz-check.js +6 -7
  25. package/dist/hooks/stop-quiz-check.js.map +1 -1
  26. package/dist/plugin/.claude-plugin/plugin.json +1 -1
  27. package/dist/plugin/agents/tutor.md +19 -5
  28. package/dist/plugin/hooks/CLAUDE.md +83 -2
  29. package/dist/plugin/hooks/hooks.json +12 -0
  30. package/dist/plugin/hooks/run.mjs +3 -3
  31. package/dist/plugin/skills/CLAUDE.md +140 -37
  32. package/dist/plugin/skills/setup/SKILL.md +1 -1
  33. package/dist/plugin/skills/tutor/SKILL.md +119 -299
  34. package/dist/plugin/skills/tutor/references/focus-and-level.md +156 -0
  35. package/dist/plugin/skills/tutor/references/grading.md +113 -0
  36. package/dist/plugin/skills/tutor/references/writing-mcq.md +133 -0
  37. package/dist/slug.js +63 -0
  38. package/dist/slug.js.map +1 -1
  39. package/dist/statusline.js +33 -0
  40. package/dist/statusline.js.map +1 -0
  41. package/dist/stdin.js +131 -0
  42. package/dist/stdin.js.map +1 -0
  43. package/dist/store.js +16 -2
  44. package/dist/store.js.map +1 -1
  45. package/dist/tools/get_session_quiz_plan.js +1 -24
  46. package/dist/tools/get_session_quiz_plan.js.map +1 -1
  47. package/dist/tools/record_attempt.js +15 -3
  48. package/dist/tools/record_attempt.js.map +1 -1
  49. package/package.json +1 -1
  50. package/dist/assets/tutor-skill.md +0 -360
@@ -0,0 +1,133 @@
1
+ # Writing the question
2
+
3
+ Required reading before you write a question. `SKILL.md` decides *whether* to
4
+ ask and *at what tier*; this is how to build the thing itself.
5
+
6
+ ## Build it in this order
7
+
8
+ Six parts, then the call. Build them in the order below — not the order they
9
+ appear on screen — because each one constrains the next.
10
+
11
+ **1. The stem.** One question about one idea, in about 25 words, grounded per
12
+ the plan's `framing`. Ordinary words: "sent with the request" rather than
13
+ "transmitted alongside the request context". Expand an acronym the first time it
14
+ appears for this learner — CSRF once, then CSRF. The answer lives in the
15
+ options, so the stem asks and stops.
16
+
17
+ Ask the positive form, and ask it once: negation makes the stem a reading test
18
+ rather than a question about the idea, and a stem needing a second clause to be
19
+ precise is doing two jobs — ask the first one and keep the other for later.
20
+
21
+ > Why is `httpOnly` set on the refresh cookie here but not on the access token?
22
+
23
+ **2. The correct option.** Write it before the distractors. It sets the length
24
+ and the grammar the other three have to match.
25
+
26
+ **3. Three distractors**, each drawn from one of these:
27
+
28
+ | Source | Written against the stem above |
29
+ |---|---|
30
+ | the right answer to an *adjacent* concept | "It stops the cookie going to another origin" — true of `SameSite`, not this |
31
+ | true, but not what was asked | "The access token is short-lived, so it expires quickly" — true, and not why the flag is there |
32
+ | the misconception you would correct in review | "It encrypts the value, so an attacker cannot read it" |
33
+ | right mechanism, wrong direction or actor | "It stops the *server* reading the cookie, so only the browser can" |
34
+
35
+ Every row answers the stem as printed. Row two is the one to get right: it is
36
+ the only source whose option must be a **true** statement, and swapping in a
37
+ false claim about a neighbouring flag collapses it into row one — leaving three
38
+ sources instead of four, and making a learner who had the shape right
39
+ indistinguishable from one holding a misconception when you come to grade it.
40
+
41
+ Each one should be something a competent person could believe. Three that a
42
+ learner can dismiss without thinking is a free point, and it teaches nothing.
43
+ When three that good will not come, the stem is too vague to have a near-miss:
44
+ rewrite the stem and the distractors follow.
45
+
46
+ **4. One clause of `description` per option.** This is where a near-miss earns
47
+ its place — the sentence that makes the wrong answer tempting.
48
+
49
+ **5. Placement.** The plan gives each question an `answer_position`, 1 to 4. Put
50
+ the correct option in that slot. Left to your own judgement you will put the
51
+ right answer first nearly every time, and a learner needs only a handful of
52
+ questions to notice that and start picking A without reading; the quiz keeps
53
+ looking fine and stops measuring anything.
54
+
55
+ **6. `header`.** Set it to `Eklavya`. That chip is the only thing on screen
56
+ saying who is asking. A question arriving mid-task with no attribution reads as
57
+ Claude going off-piste, and the developer answers a stranger.
58
+
59
+ The tool appends an **"Other"** choice of its own, and that is the route for
60
+ *"I don't know"* — which `grading.md` treats as the clearest request for
61
+ teaching there is. When a question is one someone could plausibly blank on, say
62
+ so in a `description` so the route is visible: a learner who cannot see it
63
+ guesses instead, and a guess records as a wrong answer rather than as a blank,
64
+ so the teaching sequence never fires.
65
+
66
+ Then one call to `AskUserQuestion` with all four options. One question per call:
67
+ the tool accepts up to four, and four at once is a test rather than teaching.
68
+ Use `preview` when the options are *code* — four snippets side by side is a far
69
+ better question than four sentences describing snippets. A renderer without
70
+ `AskUserQuestion` lays the same four options out as lettered text; everything
71
+ here still holds, only the rendering changes.
72
+
73
+ ## What a finished question looks like
74
+
75
+ Read yours against this. Each line is a property of the question, so a "no" is
76
+ telling you which part to rebuild.
77
+
78
+ - The stem asks one thing, and it fits in one breath.
79
+ - The answer appears among the options and nowhere in the stem.
80
+ - All four options are within a few words of the same length and use the same
81
+ grammar. A visibly longer or more careful option reads as the correct one, and
82
+ gets picked without engaging — the same leak as always answering first.
83
+ - Each of the three wrong options came from a different row of the table above.
84
+ - The correct option sits at `answer_position`.
85
+ - The tool renders the labels, so the stem does not number them.
86
+ - The stem is the question and nothing else — the dials are in the developer's
87
+ status bar.
88
+ - The stem reads correctly in one pass, with no stacked negation.
89
+
90
+ A tier-4 failure-mode question can be asked in fifteen ordinary words, and it is
91
+ a better question for it. Plain language is a property of the sentence, not of
92
+ the difficulty.
93
+
94
+ ## A second question about the same concept
95
+
96
+ `asked_before` tells you what is spent. What it does not tell you is which
97
+ direction to go next, and the grade decides that:
98
+
99
+ - Scored 4 or 5: `tier_to_ask` has already moved up, so ask for something the
100
+ old question did not — mechanism, then judgement, then failure mode.
101
+ - Scored 1 or 2: come at the *same* level from a different angle. Same tier,
102
+ different door — a concrete scenario instead of an abstraction, or their own
103
+ code instead of a hypothetical.
104
+ - Scored 0 with `outcome: "dont_know"`: you already taught this. Ask the thing
105
+ your explanation set up, and say so — it should sound like the second half of
106
+ a conversation.
107
+ - `asked_before` empty: clean slate. Use `tier_to_ask` and `description`.
108
+
109
+ ## Unmet prerequisites
110
+
111
+ `prereqs_unmet` is a warning that a question would be **unfair**, not hard. If a
112
+ concept has unmet prerequisites:
113
+
114
+ - Ask about the prerequisite instead, if it is in the plan — the plan already
115
+ orders foundations first.
116
+ - Otherwise drop the question a tier and make it mechanism-level. "Why this
117
+ rather than the alternative" is not answerable by someone who does not yet
118
+ have the alternative.
119
+ - Say the dependency out loud in your feedback. Knowing *what to learn next* is
120
+ half of what the graph is for.
121
+
122
+ ## Recording it
123
+
124
+ `record_attempt` with `format: "mcq"`, `options` as the labels you offered,
125
+ `answer` as the one they picked, and `question` as the **stem only**.
126
+
127
+ Options belong in `options`. The stem is what gets fingerprinted, so options
128
+ baked into it would make every reshuffle look like a brand-new question and
129
+ quietly undo *never the same question twice*. The same arithmetic is why the
130
+ stem carries nothing decorative: a bracketed settings line inside it would make
131
+ one question look new every time a dial moved. The server strips such a line
132
+ from either end if one appears — that is a backstop for rows recorded before
133
+ 1.14, not a licence to add one.
package/dist/cli.js CHANGED
@@ -9,8 +9,12 @@ import path from 'node:path';
9
9
  import { fileURLToPath } from 'node:url';
10
10
  import { openDb } from './db.js';
11
11
  import { dbPath, eklavyaHome } from './paths.js';
12
+ import { readStdinBounded, stripBom, STATUSLINE_STDIN } from './stdin.js';
12
13
  import { loadConfig, writeConfigFile, REPO_CONFIG_FILE, DEFAULT_CONFIG } from './config.js';
13
14
  import { levelStanding } from './store.js';
15
+ import { statusLine } from './statusline.js';
16
+ import { START_LEVEL } from './srs.js';
17
+ import Database from 'better-sqlite3';
14
18
  import { startDashboard, openInBrowser } from './dashboard.js';
15
19
  import { install, uninstall, health } from './install.js';
16
20
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
@@ -29,6 +33,7 @@ Usage:
29
33
  add --topic <topic> when setting focus to "learn"
30
34
  eklavya dashboard [--port <n>] Serve the learning dashboard and open it in your browser
31
35
  (--no-open serves it and just prints the URL)
36
+ eklavya statusline Print the dials for a status bar (one line, or nothing)
32
37
  eklavya doctor Check the install and say what to fix if it broke
33
38
  eklavya db-path Print the database location
34
39
 
@@ -41,24 +46,82 @@ function fail(message) {
41
46
  process.stderr.write(`${message}\n`);
42
47
  process.exit(1);
43
48
  }
44
- function exportRules(args) {
45
- const skillPath = path.join(moduleDir, 'assets', 'tutor-skill.md');
49
+ /**
50
+ * The pedagogy is one SKILL.md plus `references/*.md`, and Claude Code reads
51
+ * those on demand -- SKILL.md says "read references/grading.md before you
52
+ * grade" and the model opens the file.
53
+ *
54
+ * A Cursor rules file has no such mechanism. It is one document with
55
+ * `alwaysApply: true`, so a pointer to a sibling path is a pointer to nothing.
56
+ * The references are therefore inlined here, and the preamble says so: without
57
+ * that, the split would have quietly cut four fifths of the pedagogy out of
58
+ * Cursor while every test still passed.
59
+ *
60
+ * Alphabetical, deliberately. In an always-apply document the whole thing is in
61
+ * context at once so order carries no meaning, and a hand-maintained order is
62
+ * one more place a new reference file gets forgotten.
63
+ */
64
+ const FRONTMATTER = /^---\n[\s\S]*?\n---\n/;
65
+ function tutorSections() {
66
+ const tutorDir = path.join(moduleDir, 'assets', 'tutor');
67
+ const skillPath = path.join(tutorDir, 'SKILL.md');
46
68
  if (!fs.existsSync(skillPath)) {
47
69
  fail('The bundled tutor skill is missing. Run `npm run build` in the mcp/ directory.');
48
70
  }
49
- const skill = fs.readFileSync(skillPath, 'utf8').replace(/^---\n[\s\S]*?\n---\n/, '');
71
+ const skill = fs.readFileSync(skillPath, 'utf8').replace(FRONTMATTER, '');
72
+ const refsDir = path.join(tutorDir, 'references');
73
+ // Which references are required is not a list kept here -- it is whatever
74
+ // SKILL.md tells the model to read. Anything it names has to be inlined, or
75
+ // the preamble below is a lie: it promises the material is further down the
76
+ // document, so a reader who cannot find it hunts instead of falling back.
77
+ //
78
+ // Hence a hard failure rather than a warning. `copy-assets.mjs` only warns
79
+ // when it cannot bundle the skill, so a half-copied directory is reachable,
80
+ // and a rules file carrying the dispatch logic and none of the craft is worse
81
+ // than no rules file at all -- the split's whole failure mode, re-created at
82
+ // the last step.
83
+ const cited = [...skill.matchAll(/references\/([a-z0-9-]+\.md)/g)].flatMap((m) => (m[1] ? [m[1]] : []));
84
+ const required = [...new Set(cited)];
85
+ const missing = required.filter((name) => !fs.existsSync(path.join(refsDir, name)));
86
+ if (missing.length > 0) {
87
+ fail(`The tutor skill's reference files are missing: ${missing.join(', ')}.\n` +
88
+ 'Run `npm run build` in the mcp/ directory.');
89
+ }
90
+ const sections = [skill.trim()];
91
+ // Read from the directory rather than from `required`, so a reference that
92
+ // ships without being pointed at is still inlined. Frontmatter stripped from
93
+ // each: a stray YAML block mid-document renders as content in a rules file,
94
+ // and the natural instinct for a file inside a skill directory is to give it
95
+ // some.
96
+ if (fs.existsSync(refsDir)) {
97
+ for (const name of fs.readdirSync(refsDir).sort()) {
98
+ if (!name.endsWith('.md'))
99
+ continue;
100
+ const body = fs.readFileSync(path.join(refsDir, name), 'utf8').replace(FRONTMATTER, '');
101
+ sections.push(body.trim());
102
+ }
103
+ }
104
+ return sections;
105
+ }
106
+ function exportRules(args) {
50
107
  const rules = `---
51
108
  description: Eklavya tutor — teach the concepts behind the code being written
52
109
  alwaysApply: true
53
110
  ---
54
111
 
55
112
  <!-- Generated by \`eklavya export-rules\`. Do not edit by hand; edit the plugin's
56
- skills/tutor/SKILL.md and regenerate, so Claude Code and Cursor never drift. -->
113
+ skills/tutor/SKILL.md and its references/ and regenerate, so Claude Code and
114
+ Cursor never drift. -->
57
115
 
58
116
  The Eklavya MCP server is available in this editor. Its tools are the source of
59
117
  truth for what this developer already knows.
60
118
 
61
- ${skill.trim()}
119
+ The first section below is the skill itself; the ones after it are its
120
+ reference files, inlined, because this editor has no way to open one on demand.
121
+ Read them as part of the whole: wherever the first section says to read
122
+ \`references/something.md\`, that material is further down this same file.
123
+
124
+ ${tutorSections().join('\n\n')}
62
125
  `;
63
126
  const outIndex = args.indexOf('--out');
64
127
  if (outIndex >= 0) {
@@ -185,6 +248,71 @@ function doctor() {
185
248
  if (!ok)
186
249
  process.exit(1);
187
250
  }
251
+ /**
252
+ * `eklavya statusline` — the dials, for the host's status bar.
253
+ *
254
+ * Runs on every status-bar refresh, so the contract is stricter than any other
255
+ * command's: fast, silent on every failure path, and it must never hang. It
256
+ * prints one line or nothing at all, and exits 0 either way — a status bar is
257
+ * not a place to report that Eklavya is unwell.
258
+ *
259
+ * Only the earned level needs the database. The dials themselves come from
260
+ * `.eklavya.json`, and a pinned difficulty *is* the level, so a pinned setup
261
+ * never opens the file at all and an install with no database yet still shows
262
+ * its dials rather than nothing.
263
+ */
264
+ async function statuslineCommand(argv) {
265
+ try {
266
+ // Claude Code writes a JSON blob to stdin (cwd, model, session). We want
267
+ // the cwd, so the repo-scoped .eklavya.json is the one that answers.
268
+ //
269
+ // Bounded deliberately. On Windows the host may wrap a command in a
270
+ // PowerShell block that swallows the pipe, so `end` never fires and a naive
271
+ // read waits forever -- which in a status bar means every refresh blocks.
272
+ // `unref` keeps the timer off the normal path, where `end` arrives first.
273
+ const raw = await readStdinBounded(STATUSLINE_STDIN);
274
+ let cwd = process.cwd();
275
+ // Parsed in its own try: input we cannot read is a reason to fall back to
276
+ // the working directory, not a reason to show the developer nothing. The
277
+ // dials are still true; only the choice of .eklavya.json was in doubt.
278
+ try {
279
+ if (raw.trim()) {
280
+ // Strip a BOM: some Windows shells prepend one, and JSON.parse throws
281
+ // on input that looks perfectly well-formed.
282
+ const parsed = JSON.parse(stripBom(raw));
283
+ const input = (parsed ?? {});
284
+ cwd = input.workspace?.current_dir ?? input.cwd ?? cwd;
285
+ }
286
+ }
287
+ catch {
288
+ /* Unreadable stdin: process.cwd() it is. */
289
+ }
290
+ const resolved = loadConfig(cwd);
291
+ const pinned = resolved.config.difficulty !== 'auto';
292
+ let level = pinned ? resolved.config.difficulty : START_LEVEL;
293
+ if (!pinned && fs.existsSync(dbPath())) {
294
+ // `levelStanding` rather than a query of our own: the banner learned this
295
+ // the hard way, and a second implementation of the band rules is a second
296
+ // thing to keep in step with the planner.
297
+ const db = new Database(dbPath(), { readonly: true });
298
+ try {
299
+ level = levelStanding(db, resolved.config, resolved.repoRoot).level;
300
+ }
301
+ finally {
302
+ db.close();
303
+ }
304
+ }
305
+ // NO_COLOR is the cross-tool convention, and some bars render the string
306
+ // literally rather than through a terminal.
307
+ const color = !process.env.NO_COLOR && !argv.includes('--no-color');
308
+ const line = statusLine({ config: resolved.config, level, pinned, color });
309
+ if (line)
310
+ process.stdout.write(`${line}\n`);
311
+ }
312
+ catch {
313
+ /* A status bar with nothing to say says nothing. */
314
+ }
315
+ }
188
316
  function dashboardCommand(argv) {
189
317
  const i = argv.indexOf('--port');
190
318
  const port = i === -1 ? undefined : Number(argv[i + 1]);
@@ -227,6 +355,9 @@ function main() {
227
355
  return exportRules(rest);
228
356
  case 'config':
229
357
  return configCommand(rest);
358
+ case 'statusline':
359
+ void statuslineCommand(rest);
360
+ return;
230
361
  case 'dashboard':
231
362
  return dashboardCommand(rest);
232
363
  case 'doctor':
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Pull the JSON object out of a model's reply.
3
+ *
4
+ * Lives here rather than in the harness because it is the only part of the eval
5
+ * with parsing logic, and the harness is a script whose command dispatch runs on
6
+ * import -- so a copy there is a copy no test can reach. That is not
7
+ * hypothetical: the first version hung forever on a reply beginning with `{`,
8
+ * and nothing could have caught it.
9
+ *
10
+ * Two rules, both learned from the shape of the replies:
11
+ *
12
+ * - **Last object first.** A model asked for JSON often narrates before it, so
13
+ * scanning back from the end finds the answer rather than an example inside
14
+ * the preamble.
15
+ * - **Strings are not structure.** A question about code contains braces --
16
+ * `retry(() => {...})` in a stem, `${...}` in an option -- and counting those
17
+ * as depth is what made the first version fail to terminate. The scan tracks
18
+ * quoting and escaping, so a brace inside a string is just a character.
19
+ */
20
+ /** Parse one candidate object starting at `start`, or `undefined` if it is not one. */
21
+ function objectAt(text, start) {
22
+ let depth = 0;
23
+ let inString = false;
24
+ let escaped = false;
25
+ for (let i = start; i < text.length; i++) {
26
+ const ch = text[i];
27
+ if (inString) {
28
+ if (escaped)
29
+ escaped = false;
30
+ else if (ch === '\\')
31
+ escaped = true;
32
+ else if (ch === '"')
33
+ inString = false;
34
+ continue;
35
+ }
36
+ if (ch === '"') {
37
+ inString = true;
38
+ }
39
+ else if (ch === '{') {
40
+ depth++;
41
+ }
42
+ else if (ch === '}') {
43
+ depth--;
44
+ if (depth === 0) {
45
+ try {
46
+ return { end: i, value: JSON.parse(text.slice(start, i + 1)) };
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ }
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ export function extractJson(text) {
57
+ // Every candidate is parsed, rather than walking back with lastIndexOf:
58
+ // `lastIndexOf('{', -1)` clamps to 0 and returns 0 again, so the obvious loop
59
+ // never advances past a leading brace and cannot terminate.
60
+ const found = [];
61
+ for (let i = 0; i < text.length; i++) {
62
+ if (text[i] !== '{')
63
+ continue;
64
+ const parsed = objectAt(text, i);
65
+ if (parsed)
66
+ found.push({ start: i, end: parsed.end, value: parsed.value });
67
+ }
68
+ if (found.length === 0)
69
+ return null;
70
+ // Outermost first, then latest. "Last object in the text" alone was wrong the
71
+ // moment a reply nested one: for `{"concepts":[{...},{...}]}` the last `{` is
72
+ // the final array element, and it parses perfectly -- so the caller got one
73
+ // concept instead of the list and read it as an empty extraction.
74
+ //
75
+ // So: discard any object contained inside another, which leaves the wrappers;
76
+ // then take the last of those, which is still the rule that skips an example
77
+ // in a model's preamble.
78
+ const outermost = found.filter((a) => !found.some((b) => b !== a && b.start <= a.start && a.end <= b.end));
79
+ return outermost[outermost.length - 1]?.value ?? null;
80
+ }
81
+ //# sourceMappingURL=extract-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-json.js","sourceRoot":"","sources":["../../src/eval/extract-json.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,uFAAuF;AACvF,SAAS,QAAQ,CAAC,IAAY,EAAE,KAAa;IAC3C,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEnB,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,OAAO;gBAAE,OAAO,GAAG,KAAK,CAAC;iBACxB,IAAI,EAAE,KAAK,IAAI;gBAAE,OAAO,GAAG,IAAI,CAAC;iBAChC,IAAI,EAAE,KAAK,GAAG;gBAAE,QAAQ,GAAG,KAAK,CAAC;YACtC,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;gBAChB,IAAI,CAAC;oBACH,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;gBACjE,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,SAAS,CAAC;gBACnB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,wEAAwE;IACxE,8EAA8E;IAC9E,4DAA4D;IAC5D,MAAM,KAAK,GAAqD,EAAE,CAAC;IACnE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,SAAS;QAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7E,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,8EAA8E;IAC9E,8EAA8E;IAC9E,4EAA4E;IAC5E,kEAAkE;IAClE,EAAE;IACF,8EAA8E;IAC9E,6EAA6E;IAC7E,yBAAyB;IACzB,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAC5B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAC3E,CAAC;IACF,OAAO,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC;AACxD,CAAC"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Does `log_session_concepts` name the concepts a diff actually exercises?
3
+ *
4
+ * This sits upstream of everything else the eval measures. If extraction picks
5
+ * the wrong concepts, every question after it is well-formed and about the
6
+ * wrong thing -- and `question-checks.ts` would score that run perfectly clean,
7
+ * because a good question about an irrelevant concept is still a good question.
8
+ *
9
+ * Scored with the product's own matcher. `findFuzzyMatch` and
10
+ * `FUZZY_MATCH_THRESHOLD` are what the server uses to decide two slugs mean the
11
+ * same concept, so a model that logs `wal-mode` against a label of
12
+ * `wal-journal-mode` is credited here exactly as the server would credit it.
13
+ * A second opinion invented for the eval would measure the eval.
14
+ *
15
+ * Pure: labels and extractions in, numbers out.
16
+ */
17
+ import { findFuzzyMatch, isValidSlug, normalizeSlug } from '../slug.js';
18
+ /** The skill asks for 3-8 concepts the work genuinely exercises. */
19
+ export const MIN_CONCEPTS = 3;
20
+ export const MAX_CONCEPTS = 8;
21
+ function ratio(numerator, denominator) {
22
+ return denominator === 0 ? 0 : numerator / denominator;
23
+ }
24
+ export function scoreExtraction(fixture, labels, extracted) {
25
+ const candidates = labels.map((slug) => ({ slug }));
26
+ const matched = new Set();
27
+ const unlabelled = [];
28
+ for (const item of extracted) {
29
+ const slug = normalizeSlug(item.slug);
30
+ // Exact first, then the server's fuzzy rules -- the same order
31
+ // `log_session_concepts` resolves a slug in.
32
+ const hit = labels.includes(slug) ? { slug } : findFuzzyMatch(slug, candidates);
33
+ // A second logged slug matching an already-credited label is not a second
34
+ // hit. Counting it would let a model inflate recall by logging one concept
35
+ // five different ways.
36
+ if (hit && !matched.has(hit.slug))
37
+ matched.add(hit.slug);
38
+ else if (!hit)
39
+ unlabelled.push(slug);
40
+ }
41
+ const precision = ratio(matched.size, extracted.length);
42
+ const recall = ratio(matched.size, labels.length);
43
+ return {
44
+ fixture,
45
+ matched: [...matched],
46
+ missed: labels.filter((l) => !matched.has(l)),
47
+ unlabelled,
48
+ precision,
49
+ recall,
50
+ f1: precision + recall === 0 ? 0 : (2 * precision * recall) / (precision + recall),
51
+ };
52
+ }
53
+ /**
54
+ * What the skill asks for, checked without a model.
55
+ *
56
+ * The count and the context line are instructions with an exact form, so they
57
+ * are countable -- and the context line is the one that decays silently. A
58
+ * concept logged with `"used cookies"` still produces a question, just an
59
+ * ungrounded one, and nothing downstream notices.
60
+ */
61
+ export function checkExtractionShape(extracted, diff) {
62
+ const checks = [];
63
+ const n = extracted.length;
64
+ checks.push({
65
+ id: 'count_in_range',
66
+ ok: n >= MIN_CONCEPTS && n <= MAX_CONCEPTS,
67
+ detail: `${n} concept(s) (asked for ${MIN_CONCEPTS}-${MAX_CONCEPTS})`,
68
+ });
69
+ const invalid = extracted.filter((e) => !isValidSlug(normalizeSlug(e.slug)));
70
+ checks.push({
71
+ id: 'slugs_valid',
72
+ ok: invalid.length === 0,
73
+ detail: invalid.length === 0 ? 'all slugs normalize cleanly' : `${invalid.length} unusable slug(s)`,
74
+ });
75
+ const contextless = extracted.filter((e) => !e.context || e.context.trim().length === 0);
76
+ checks.push({
77
+ id: 'every_concept_has_context',
78
+ ok: contextless.length === 0,
79
+ detail: contextless.length === 0 ? 'every concept carries a context line' : `${contextless.length} without context`,
80
+ });
81
+ // "One line naming the actual decision, in the actual file." A context that
82
+ // shares no identifier with the diff is the `"used cookies"` case the skill
83
+ // calls useless -- it reads fine and grounds nothing.
84
+ const identifiers = new Set((diff.match(/[A-Za-z_][A-Za-z0-9_]{3,}/g) ?? []).map((w) => w.toLowerCase()));
85
+ const ungrounded = extracted.filter((e) => {
86
+ const words = (e.context ?? '').toLowerCase().match(/[a-z_][a-z0-9_]{3,}/g) ?? [];
87
+ return !words.some((w) => identifiers.has(w));
88
+ });
89
+ checks.push({
90
+ id: 'context_names_the_code',
91
+ ok: ungrounded.length === 0,
92
+ detail: ungrounded.length === 0
93
+ ? 'every context line names something from the diff'
94
+ : `${ungrounded.length} context line(s) name nothing in the diff`,
95
+ });
96
+ return checks;
97
+ }
98
+ export function summarizeExtraction(results) {
99
+ const matched = results.reduce((n, r) => n + r.matched.length, 0);
100
+ const labels = results.reduce((n, r) => n + r.matched.length + r.missed.length, 0);
101
+ const extracted = results.reduce((n, r) => n + r.matched.length + r.unlabelled.length, 0);
102
+ const precision = ratio(matched, extracted);
103
+ const recall = ratio(matched, labels);
104
+ return {
105
+ fixtures: results.length,
106
+ labels,
107
+ extracted,
108
+ matched,
109
+ precision,
110
+ recall,
111
+ f1: precision + recall === 0 ? 0 : (2 * precision * recall) / (precision + recall),
112
+ unlabelled: results.reduce((n, r) => n + r.unlabelled.length, 0),
113
+ };
114
+ }
115
+ //# sourceMappingURL=extraction-score.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extraction-score.js","sourceRoot":"","sources":["../../src/eval/extraction-score.ts"],"names":[],"mappings":"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"}