lastlight 0.7.8 → 0.9.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.
- package/package.json +1 -1
- package/plugins/lastlight/.claude-plugin/plugin.json +1 -1
- package/plugins/lastlight/README.md +5 -1
- package/plugins/lastlight/skills/lastlight-evals/SKILL.md +81 -12
- package/plugins/lastlight/skills/lastlight-evals/references/authoring-from-pr.md +19 -12
- package/plugins/lastlight/skills/lastlight-evals/references/authoring-pr-review.md +110 -0
- package/plugins/lastlight/skills/lastlight-evals/references/instance-schema.md +37 -1
- package/plugins/lastlight/skills/lastlight-evals-loop/SKILL.md +159 -0
- package/plugins/lastlight/skills/lastlight-evals-loop/references/guardrails.md +86 -0
- package/plugins/lastlight/skills/lastlight-evals-loop/references/journal-format.md +54 -0
- package/plugins/lastlight/skills/lastlight-evals-loop/references/levers.md +80 -0
- package/plugins/lastlight/skills/lastlight-guide/SKILL.md +97 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin.json",
|
|
3
3
|
"name": "lastlight",
|
|
4
4
|
"displayName": "Last Light",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.9.0",
|
|
6
6
|
"description": "Install, configure and operate Last Light (GitHub maintenance agent) — its server, CLI client, deployment overlay, and the Last Light Evals harness.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Clifton Cunningham"
|
|
@@ -13,10 +13,12 @@ Light's *internal* sandbox skills under the repo's top-level `skills/` dir
|
|
|
13
13
|
|
|
14
14
|
| Skill | Use it when you want to… |
|
|
15
15
|
|-------|--------------------------|
|
|
16
|
+
| `lastlight-guide` | **Not sure which of the below you need** — orientation & router across all the Last Light skills. Start here (or `/lastlight-guide`). |
|
|
16
17
|
| `lastlight-server` | Install & configure a Last Light **server** (the agent + docker stack) on a host. |
|
|
17
18
|
| `lastlight-client` | Point the `lastlight` **CLI client** at an existing server and log in. |
|
|
18
19
|
| `lastlight-overlay` | Create a deployment **overlay** instance and fork/customize workflows, prompts, skills, or the agent persona. |
|
|
19
20
|
| `lastlight-evals` | Scaffold and run a **Last Light Evals** workspace (datasets, models, model comparisons). |
|
|
21
|
+
| `lastlight-evals-loop` | **Drive an eval toward a target score** with a disciplined, anti-gaming improvement loop — diagnose on a train split, validate on a blind held-out split, propose one generic fix at a time. |
|
|
20
22
|
|
|
21
23
|
## Install
|
|
22
24
|
|
|
@@ -41,4 +43,6 @@ claude plugin install lastlight@lastlight-skills
|
|
|
41
43
|
auto-discovers them on the next session.
|
|
42
44
|
|
|
43
45
|
After installing, start a new Claude Code session and say e.g. *"set up a Last
|
|
44
|
-
Light server"* or *"scaffold a Last Light evals workspace"
|
|
46
|
+
Light server"* or *"scaffold a Last Light evals workspace"* — or, if you're not
|
|
47
|
+
sure where to start, *"help me with Last Light"* (or `/lastlight-guide`) and the
|
|
48
|
+
guide skill will route you.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lastlight-evals
|
|
3
|
-
description: Scaffold, configure and run a Last Light EVALS workspace — the harness that runs Last Light's real workflows against a mocked GitHub and grades them deterministically. Use when the user wants to "set up / scaffold Last Light Evals", "create an evals workspace or instance", "run evals", "compare models", or author new eval cases — including "create an eval dataset/case from this PR/issue <github url>" (triage / code-fix instances). GitHub is mocked when running, so no real GitHub token is needed — only a model provider API key (the one exception is `add-case`, which reads real PRs/issues via `gh`).
|
|
4
|
-
version: 1.
|
|
3
|
+
description: Scaffold, configure and run a Last Light EVALS workspace — the harness that runs Last Light's real workflows against a mocked GitHub and grades them deterministically. Use when the user wants to "set up / scaffold Last Light Evals", "create an evals workspace or instance", "run evals", "compare models", or author new eval cases — including "create an eval dataset/case from this PR/issue <github url>" and "create a PR-review eval dataset from these gold PRs" (triage / code-fix / pr-review instances, via `add-case --pr <url> --review|--code-fix` / `--issue`). GitHub is mocked when running, so no real GitHub token is needed — only a model provider API key (the one exception is `add-case`, which reads real PRs/issues via `gh`).
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
tags: [lastlight, evals, benchmark, models, swe-bench]
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -14,6 +14,25 @@ thin CLI on top of the `lastlight` core package (via the `lastlight/evals`
|
|
|
14
14
|
barrel), so it exercises the same workflows/skills production does. SWE-bench
|
|
15
15
|
compatible. **Node 24+.**
|
|
16
16
|
|
|
17
|
+
## Start here — what do you want to do?
|
|
18
|
+
|
|
19
|
+
If the user's evals goal is clear, jump to the section. If it's vague ("help me
|
|
20
|
+
with the evals", "what can this do?"), **ask** (`AskUserQuestion`) which of these
|
|
21
|
+
they want, then go:
|
|
22
|
+
|
|
23
|
+
| Goal | Section |
|
|
24
|
+
|---|---|
|
|
25
|
+
| Set up an evals workspace (first time) | **§2 Scaffold** (+ §1 prereqs, §3 providers) |
|
|
26
|
+
| Run evals / compare models | **§4 Run** |
|
|
27
|
+
| Look at past runs (no models run) | **§4** — `lastlight-evals serve` |
|
|
28
|
+
| Author one case from a GitHub PR or issue | **§6** |
|
|
29
|
+
| **Build a PR-review dataset from my own gold PRs** | **§6 → "Build a PR-review dataset"** |
|
|
30
|
+
| Add cases by hand / understand the schema | **§5** + `references/instance-schema.md` |
|
|
31
|
+
| **Iteratively improve the score toward a target** | the **`lastlight-evals-loop`** skill |
|
|
32
|
+
|
|
33
|
+
New to the whole plugin (server / overlay / client, not just evals)? That's the
|
|
34
|
+
**`lastlight-guide`** skill — this one is evals-only.
|
|
35
|
+
|
|
17
36
|
## 1. Check prerequisites
|
|
18
37
|
|
|
19
38
|
```bash
|
|
@@ -102,9 +121,10 @@ lastlight-evals run triage --model openai/gpt-5.5,anthropic/claude-opus-4-8
|
|
|
102
121
|
lastlight-evals run --compare # cross-vendor set (only models whose envKey is present)
|
|
103
122
|
lastlight-evals run triage --runs 3 # repeat each case 3× (worst-case verdict, mean metrics)
|
|
104
123
|
lastlight-evals run pr-review --limit 3 # only the first 3 cases of the tier (controlled/cheap run)
|
|
105
|
-
lastlight-evals run triage --instance <id>
|
|
124
|
+
lastlight-evals run triage --instance <id[,id2]> # only these exact instance_id(s), comma-separated (or set EVAL_INSTANCE)
|
|
106
125
|
lastlight-evals run pr-review --f-beta 0.5 # pr-review F-beta β (default 1=F1; 0.5=precision 2×). Or EVAL_F_BETA
|
|
107
126
|
lastlight-evals run pr-review --judge-with-diff # feed the PR diff to the judge (higher fidelity; off by default)
|
|
127
|
+
lastlight-evals run pr-review --no-inject-context # DON'T inject synthetic repo-context into the checkout (clean A/B control)
|
|
108
128
|
lastlight-evals run pr-review --sandbox gondolin # isolate the agent's tools in a QEMU micro-VM (anti-spoil). Or EVAL_SANDBOX
|
|
109
129
|
lastlight-evals run triage --no-open # don't open the report
|
|
110
130
|
# Plain layout: add --overlay . (e.g. lastlight-evals run triage --overlay .)
|
|
@@ -144,26 +164,49 @@ Quick shape (paths are relative to the workspace's `evals/` dir):
|
|
|
144
164
|
`evals/datasets/code-fix/tests/<instance_id>/` (held-out tests applied at grade time).
|
|
145
165
|
- **PR-review case:** a `SweBenchInstance` with a `pr` fixture (base/head refs +
|
|
146
166
|
commits, checked out at the PR head) and a `review_gold` set (severity +
|
|
147
|
-
description).
|
|
167
|
+
description). Populate the full Martian
|
|
148
168
|
[Code Review Bench](https://codereview.withmartian.com/) 50 with
|
|
149
|
-
`npx tsx scripts/import-martian.ts
|
|
169
|
+
`npx tsx scripts/import-martian.ts`, **or author your *own* gold-PR dataset**
|
|
170
|
+
with `add-case --pr <url> --review` (see §6 and
|
|
171
|
+
**`references/authoring-pr-review.md`**). Grading needs a judge model
|
|
150
172
|
(`EVAL_JUDGE_MODEL`, else a strong default per provider key).
|
|
173
|
+
- **Repo-context injection (pr-review).** The harness can drop a synthetic
|
|
174
|
+
`AGENTS.md`/`CLAUDE.md` into the checked-out repo so the reviewing agent reads
|
|
175
|
+
it — a **generic** block from `<overlay>/repo-context/AGENTS.md` (every repo)
|
|
176
|
+
plus a **per-repo** block from `datasets/pr-review/context/<instance_id>/AGENTS.md`.
|
|
177
|
+
Presence-based (just create the file), on by default; `--no-inject-context`
|
|
178
|
+
(or `EVAL_INJECT_CONTEXT=0`) forces a clean control for an A/B. It appends to
|
|
179
|
+
a real `AGENTS.md`/`CLAUDE.md` if the repo ships one (never shadowing it). This
|
|
180
|
+
is how you prove *"adding this to your repo improves review quality"* — and the
|
|
181
|
+
lever the **`lastlight-evals-loop`** skill drives.
|
|
151
182
|
- **Custom tier:** a new `evals/datasets/<tier>/` with `tier.json` +
|
|
152
183
|
`instances.json` (+ `repos/` & `tests/` for code-fix-style tiers). Discovery is
|
|
153
184
|
automatic — no code change.
|
|
154
185
|
|
|
155
186
|
## 6. Author a case from a real GitHub PR or issue
|
|
156
187
|
|
|
157
|
-
When the user says **"create an eval dataset/case from this PR/issue <url>"
|
|
158
|
-
|
|
159
|
-
fuzzy parts.
|
|
188
|
+
When the user says **"create an eval dataset/case from this PR/issue <url>"** or
|
|
189
|
+
**"create a PR-review eval dataset from these gold PRs"**, use the `add-case`
|
|
190
|
+
subcommand — it does the mechanical extraction; you refine the fuzzy parts.
|
|
191
|
+
|
|
192
|
+
A PR seeds two different evals, so `--pr` requires a kind — `--review` (the PR's
|
|
193
|
+
human review is the gold set) or `--code-fix` (hide the fix, the agent must
|
|
194
|
+
reproduce it):
|
|
160
195
|
|
|
161
196
|
```bash
|
|
162
|
-
lastlight-evals add-case --pr <github-pr-url> --dry-run
|
|
163
|
-
lastlight-evals add-case --pr <github-pr-url>
|
|
164
|
-
lastlight-evals add-case --
|
|
197
|
+
lastlight-evals add-case --pr <github-pr-url> --review --dry-run # propose a pr-review case; don't write
|
|
198
|
+
lastlight-evals add-case --pr <github-pr-url> --review # write into ./datasets/pr-review (or --overlay)
|
|
199
|
+
lastlight-evals add-case --pr <github-pr-url> --code-fix --dry-run # propose a code-fix case
|
|
200
|
+
lastlight-evals add-case --issue <github-issue-url> --dry-run # propose a triage case
|
|
165
201
|
```
|
|
166
202
|
|
|
203
|
+
- **From a PR (pr-review):** derives the `pr` fixture (base/head refs + commits,
|
|
204
|
+
from the PR's `baseRefOid`/`headRefOid`) and a **candidate `review_gold`** from
|
|
205
|
+
the PR's *human* review — inline comments + substantive review bodies, with
|
|
206
|
+
bot/nit/reply/outdated noise filtered out. Prints an evidence block; **you**
|
|
207
|
+
assign real severities and prune non-actionable comments. Byte-compatible with
|
|
208
|
+
`import-martian.ts`, so authored cases sit alongside imported ones. Leak-safe:
|
|
209
|
+
the review lands only in `review_gold`, never in the seeded PR the agent sees.
|
|
167
210
|
- **From a PR (code-fix):** derives `repo`, `base_commit` (merge-base of base &
|
|
168
211
|
head) + `head_commit`, the PR's **test** diff as the held-out `test_patch`, and
|
|
169
212
|
auto-detects `FAIL_TO_PASS` / `PASS_TO_PASS` by running the tests at base (red)
|
|
@@ -176,9 +219,35 @@ lastlight-evals add-case --issue <github-issue-url> --dry-run # propose a triag
|
|
|
176
219
|
**reviewer comments** — the raw triage signal. You then assign
|
|
177
220
|
`triage_gold` (category/state) from those labels per the deployment's taxonomy.
|
|
178
221
|
|
|
222
|
+
### Build a PR-review dataset from gold PRs (interactive)
|
|
223
|
+
|
|
224
|
+
When the user says **"I want to create a PR-review eval dataset"** (from *their*
|
|
225
|
+
PRs, to track review quality as they evolve models/prompts):
|
|
226
|
+
|
|
227
|
+
1. **Get the PRs.** If they didn't paste URLs, **ask** for them — "give me the
|
|
228
|
+
gold PR URL(s) — one or many, whose human review is the standard you want a
|
|
229
|
+
model to reproduce." Also confirm *where* to write: the current workspace's
|
|
230
|
+
`./datasets` (or `--overlay <dir>` for a deployment's own dataset).
|
|
231
|
+
2. **One PR at a time.** For each URL run
|
|
232
|
+
`add-case --pr <url> --review --dry-run`, read the evidence block, then
|
|
233
|
+
**curate** the candidate `review_gold` — set real severities and drop
|
|
234
|
+
comments that aren't concrete findings — and write it
|
|
235
|
+
(`add-case --pr <url> --review [--datasets/--overlay …]`). Re-running the same
|
|
236
|
+
PR **replaces by id**, so curation is idempotent.
|
|
237
|
+
- For **many** PRs, spawn a **curation sub-agent per PR** (each handed one URL
|
|
238
|
+
+ the target dir, returning the curated instance) so the judgement stays
|
|
239
|
+
isolated and they run in parallel.
|
|
240
|
+
3. **Smoke-run** the new tier with the cheapest model to confirm the seed + judge
|
|
241
|
+
plumbing (needs a judge-model key): `lastlight-evals run pr-review --limit 1 --model haiku`.
|
|
242
|
+
|
|
243
|
+
See **`references/authoring-pr-review.md`** for the full extract→curate→write
|
|
244
|
+
flow, the `--severity` / `--include-bots` knobs, and the anti-spoil guarantee.
|
|
245
|
+
|
|
179
246
|
The full flow, what you refine for each, the `test_cmd` / `setup_cmd` options for
|
|
180
247
|
non-`node --test` runners, and the trust/offline caveats are in
|
|
181
|
-
**`references/authoring-from-pr.md`**
|
|
248
|
+
**`references/authoring-from-pr.md`** (PR code-fix + issue triage) and
|
|
249
|
+
**`references/authoring-pr-review.md`** (PR review) — read the relevant one
|
|
250
|
+
before authoring.
|
|
182
251
|
|
|
183
252
|
## Done when
|
|
184
253
|
|
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
# Author
|
|
1
|
+
# Author a code-fix or triage eval case from a real GitHub PR or issue
|
|
2
2
|
|
|
3
|
-
`lastlight-evals add-case` turns a real GitHub **PR** into a
|
|
4
|
-
|
|
5
|
-
extraction with `gh` + `git`; **you** refine the
|
|
6
|
-
**git-source** case — no fixture repo is
|
|
7
|
-
|
|
8
|
-
the `instance-schema.md`
|
|
3
|
+
`lastlight-evals add-case --pr <url> --code-fix` turns a real GitHub **PR** into a
|
|
4
|
+
code-fix (build) case; `--issue <url>` turns an **issue** into a triage case. It
|
|
5
|
+
does the mechanical, reproducible extraction with `gh` + `git`; **you** refine the
|
|
6
|
+
judgement parts. The result is a **git-source** case — no fixture repo is
|
|
7
|
+
vendored; at run time the harness clones the repo into the gitignored
|
|
8
|
+
`./.eval-cache/` and checks out `base_commit` (see the `instance-schema.md`
|
|
9
|
+
"Git-source" flavor).
|
|
10
|
+
|
|
11
|
+
> A PR seeds two different evals. Use `--code-fix` (this doc) to hide the fix and
|
|
12
|
+
> have the agent reproduce it; use `--review` (see **`authoring-pr-review.md`**)
|
|
13
|
+
> to grade a review of the PR against its human review. `--pr` **requires** one of
|
|
14
|
+
> the two — it no longer defaults to code-fix.
|
|
9
15
|
|
|
10
16
|
## Two grading modes (default: suite)
|
|
11
17
|
|
|
@@ -34,7 +40,7 @@ the `instance-schema.md` "Git-source" flavor).
|
|
|
34
40
|
## Command
|
|
35
41
|
|
|
36
42
|
```bash
|
|
37
|
-
lastlight-evals add-case --pr <github-pr-url> [options]
|
|
43
|
+
lastlight-evals add-case --pr <github-pr-url> --code-fix [options]
|
|
38
44
|
lastlight-evals add-case --issue <github-issue-url> [options]
|
|
39
45
|
```
|
|
40
46
|
|
|
@@ -42,9 +48,10 @@ Options:
|
|
|
42
48
|
|
|
43
49
|
| flag | meaning |
|
|
44
50
|
|---|---|
|
|
45
|
-
| `--pr <url>` | a GitHub PR url
|
|
51
|
+
| `--pr <url>` | a GitHub PR url (pair with `--code-fix` here, or `--review` for a pr-review case) |
|
|
52
|
+
| `--code-fix` | with `--pr` → a **code-fix** (build) case |
|
|
46
53
|
| `--issue <url>` | a GitHub issue url → a **triage** case |
|
|
47
|
-
| `--tier <name>` | target tier dir (default `code-fix` for `--pr`, `triage` for `--issue`) |
|
|
54
|
+
| `--tier <name>` | target tier dir (default `code-fix` for `--pr --code-fix`, `triage` for `--issue`) |
|
|
48
55
|
| `--id <slug>` | `instance_id` (default derived from repo + number) |
|
|
49
56
|
| `--datasets <dir>` | datasets root to write into (a `<tier>/` subdir). Default `./datasets`, else `./evals/datasets` |
|
|
50
57
|
| `--overlay <dir>` | write into `<dir>/evals/datasets` instead |
|
|
@@ -57,8 +64,8 @@ Options:
|
|
|
57
64
|
|
|
58
65
|
## The recommended flow (CLI extracts → you refine)
|
|
59
66
|
|
|
60
|
-
1. **Dry-run first.** `add-case --pr <url> --dry-run` prints the proposed
|
|
61
|
-
The CLI derives:
|
|
67
|
+
1. **Dry-run first.** `add-case --pr <url> --code-fix --dry-run` prints the proposed
|
|
68
|
+
instance. The CLI derives:
|
|
62
69
|
- `repo`, `base_commit` (the **merge-base** of the base branch and the PR head —
|
|
63
70
|
the true fork point, not the base-branch tip), and `head_commit`;
|
|
64
71
|
- gold `patch` — the diff of the non-test files (reference only, never graded);
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Author a pr-review eval case from a real GitHub PR
|
|
2
|
+
|
|
3
|
+
`lastlight-evals add-case --pr <url> --review` turns a real GitHub **PR** into a
|
|
4
|
+
`pr-review` case: the PR's **human review is the gold set** the model's review is
|
|
5
|
+
scored against (precision / recall / F-beta, via an LLM judge). It does the
|
|
6
|
+
mechanical, reproducible extraction with `gh`; **you** curate the gold. The output
|
|
7
|
+
is **byte-compatible** with `scripts/import-martian.ts`, so cases you author sit
|
|
8
|
+
alongside the Martian Code Review Bench cases in the same `pr-review/instances.json`.
|
|
9
|
+
|
|
10
|
+
This is the path for *"I want to create a PR-review eval dataset from these gold
|
|
11
|
+
PRs"* — PRs whose human reviews are the standard you want a model (or an evolving
|
|
12
|
+
prompt/skill) to reproduce.
|
|
13
|
+
|
|
14
|
+
## What it extracts
|
|
15
|
+
|
|
16
|
+
- **The `pr` fixture** — `base_ref`/`head_ref` + `base_commit`/`head_commit` (from
|
|
17
|
+
the PR's `baseRefOid`/`headRefOid`), `title`, `body` (truncated), `user`. At run
|
|
18
|
+
time the harness clones the repo and checks out the PR **head**; the review
|
|
19
|
+
workflow diffs `base..head`. No repo clone happens at author time.
|
|
20
|
+
- **A candidate `review_gold`** from the PR's *human* review: inline review
|
|
21
|
+
comments (`path` + `line` + body) and substantive top-level review bodies. The
|
|
22
|
+
CLI filters the obvious noise — reply threads, `LGTM`/approve-only comments, and
|
|
23
|
+
bot comments (unless `--include-bots`) — and defaults every entry's `severity`
|
|
24
|
+
to `medium` (GitHub comments carry none). Outdated comments (whose hunk moved)
|
|
25
|
+
are kept via `original_line` and flagged.
|
|
26
|
+
|
|
27
|
+
> **Anti-spoil.** The human review is written **only** into `review_gold` (the
|
|
28
|
+
> held-out judge gold). The CLI never puts it in `pr.reviews` / `pr.review_comments`
|
|
29
|
+
> — those seed the mocked GitHub the agent can read, which would hand it the
|
|
30
|
+
> answer. This mirrors `import-martian.ts`, and the run-time seeding
|
|
31
|
+
> (`seedWorkspacePrReview`) only checks out git, never the prior discussion.
|
|
32
|
+
|
|
33
|
+
## Prerequisites
|
|
34
|
+
|
|
35
|
+
- `gh` on PATH and authenticated (`gh auth login`) — used to read PR metadata + review comments.
|
|
36
|
+
- Node 24+ (same as the rest of the harness). A **judge model** at run time
|
|
37
|
+
(`EVAL_JUDGE_MODEL`, else a strong default per provider key).
|
|
38
|
+
|
|
39
|
+
## Command
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
lastlight-evals add-case --pr <github-pr-url> --review [options]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Options:
|
|
46
|
+
|
|
47
|
+
| flag | meaning |
|
|
48
|
+
|---|---|
|
|
49
|
+
| `--pr <url>` | a GitHub PR url (pair with `--review` here, or `--code-fix` for a build case) |
|
|
50
|
+
| `--review` | with `--pr` → a **pr-review** case (gold = the PR's human review) |
|
|
51
|
+
| `--severity <level>` | default severity for candidate gold comments (`low`\|`medium`\|`high`\|`critical`; default `medium`) |
|
|
52
|
+
| `--include-bots` | keep review comments from bots (default: skipped) |
|
|
53
|
+
| `--tier <name>` | target tier dir (default `pr-review`) |
|
|
54
|
+
| `--id <slug>` | `instance_id` (default `prreview__<repo>-<n>`) |
|
|
55
|
+
| `--datasets <dir>` | datasets root to write into (a `<tier>/` subdir). Default `./datasets`, else `./evals/datasets` |
|
|
56
|
+
| `--overlay <dir>` | write into `<dir>/evals/datasets` instead |
|
|
57
|
+
| `--dry-run` | print the proposed instance JSON + evidence block; don't write |
|
|
58
|
+
|
|
59
|
+
## The recommended flow (CLI extracts → you refine)
|
|
60
|
+
|
|
61
|
+
1. **Dry-run first.** `add-case --pr <url> --review --dry-run` prints the proposed
|
|
62
|
+
instance and an **evidence block** listing every candidate gold comment
|
|
63
|
+
(`author · file:line [severity] first-line`, tagged `(outdated)` / `(bot)`).
|
|
64
|
+
2. **Read the evidence and curate `review_gold`** — this is the whole point of a
|
|
65
|
+
*gold* dataset:
|
|
66
|
+
- **Severity.** Every candidate defaults to `medium`. Set each to its real
|
|
67
|
+
impact (`critical`/`high`/`medium`/`low`) — the judge is severity-aware.
|
|
68
|
+
- **Prune noise.** Drop comments that aren't concrete findings — questions,
|
|
69
|
+
style nits, "why not X?", praise, anything `(outdated)` that no longer applies
|
|
70
|
+
to the head diff.
|
|
71
|
+
- **Add what the humans missed** (optional). If you know of a real issue the
|
|
72
|
+
human reviewer didn't post, add a `review_gold` entry by hand (`severity` +
|
|
73
|
+
`description`; `file`/`line` optional — the judge matches on substance).
|
|
74
|
+
- **Empty gold?** If the PR had no usable review comments, the CLI warns and
|
|
75
|
+
leaves `review_gold: []` — author it by hand from the PR diff, or the case
|
|
76
|
+
can't be judged.
|
|
77
|
+
3. **Write it.** Re-run without `--dry-run` (add `--datasets <dir>` / `--overlay
|
|
78
|
+
<dir>` to target a workspace). The instance is appended to
|
|
79
|
+
`<root>/pr-review/instances.json` (creating `tier.json` if the tier is new);
|
|
80
|
+
re-running with the same PR **replaces by `instance_id`**, so curation is
|
|
81
|
+
idempotent.
|
|
82
|
+
4. **Verify end-to-end** with the cheapest model — confirms the seed + judge
|
|
83
|
+
plumbing (needs a judge-model key):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
EVAL_INSTANCE=<instance_id> lastlight-evals run pr-review --model haiku
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Inspect the judge trace in the dashboard (the **judge** button) to see the
|
|
90
|
+
finding↔gold pairing behind the precision/recall/F score.
|
|
91
|
+
|
|
92
|
+
## Authoring from a list of gold PRs
|
|
93
|
+
|
|
94
|
+
Run `add-case --pr <url> --review` **once per URL** — each appends into the same
|
|
95
|
+
`pr-review/instances.json`. Because `review_gold` curation is per-PR judgement,
|
|
96
|
+
do one curation pass per PR rather than a bulk import: dry-run → refine → write.
|
|
97
|
+
Spawning a **curation sub-agent per PR** (each handed one URL, returning the
|
|
98
|
+
curated instance) keeps the judgement isolated and parallelizes cleanly, while the
|
|
99
|
+
CLI's replace-by-id write makes accumulation safe.
|
|
100
|
+
|
|
101
|
+
## Tuning knobs
|
|
102
|
+
|
|
103
|
+
- **`--severity <level>`** sets the default for *all* candidates in one PR — handy
|
|
104
|
+
when a PR's review is uniformly high- or low-stakes; you still refine per entry.
|
|
105
|
+
- **`--include-bots`** keeps bot review comments (CodeRabbit, Greptile, etc.).
|
|
106
|
+
Off by default because bot comments are noisy and rarely the human gold; include
|
|
107
|
+
them only if the bot's review *is* the standard you're grading against.
|
|
108
|
+
|
|
109
|
+
See `instance-schema.md` for the full `pr` / `review_gold` field reference and the
|
|
110
|
+
pr-review grading model.
|
|
@@ -44,12 +44,23 @@ Datasets are discovered from (overlay > user > built-in): `<overlay>/evals/datas
|
|
|
44
44
|
"state": "open"
|
|
45
45
|
},
|
|
46
46
|
"triage_gold": { "category": "bug", "state": "ready-for-agent" }, // triage grading
|
|
47
|
+
"pr": { // pr-review: the PR fixture (base/head refs + SHAs)
|
|
48
|
+
"number": 37429, "title": "...", "body": "...",
|
|
49
|
+
"base_ref": "main", "head_ref": "feature-x",
|
|
50
|
+
"base_commit": "f3c8e8f...", "head_commit": "02f48f7...",
|
|
51
|
+
"user": "author" // do NOT put the human review here — see below
|
|
52
|
+
},
|
|
53
|
+
"review_gold": [ // pr-review: the held-out judge gold
|
|
54
|
+
{ "file": "src/x.ts", "line": 42, "severity": "high", "description": "..." },
|
|
55
|
+
{ "severity": "medium", "description": "..." } // file/line optional (judge matches on substance)
|
|
56
|
+
],
|
|
47
57
|
"expect_github": { // behavioral assertions on recorded GitHub calls
|
|
48
58
|
"labels_added": ["bug"],
|
|
49
59
|
"labels_absent": ["wontfix"],
|
|
50
60
|
"issue_closed": false,
|
|
51
61
|
"comment_matches": "(?i)thanks",
|
|
52
|
-
"pr_opened": { "base": "main", "head_is_branch": true, "title_matches": "(?i)fix" }
|
|
62
|
+
"pr_opened": { "base": "main", "head_is_branch": true, "title_matches": "(?i)fix" },
|
|
63
|
+
"review_submitted": {} // pr-review: proxy check that a review was posted
|
|
53
64
|
}
|
|
54
65
|
}
|
|
55
66
|
```
|
|
@@ -83,6 +94,26 @@ hand-build these — use `lastlight-evals add-case --pr <url>` (see
|
|
|
83
94
|
**`authoring-from-pr.md`**), which fills `base_commit`, `head_commit`,
|
|
84
95
|
`test_patch`, and the verdicts for you.
|
|
85
96
|
|
|
97
|
+
## Add a pr-review case
|
|
98
|
+
|
|
99
|
+
A pr-review instance has a **`pr`** fixture + a **`review_gold`** set and
|
|
100
|
+
`workflow: "pr-review"`. The `pr` fixture drives both the mocked PR endpoints and
|
|
101
|
+
the workspace checkout: at run time the harness checks out the PR **head**, and
|
|
102
|
+
the review workflow diffs `base..head`. `review_gold` is the held-out gold the
|
|
103
|
+
posted review is scored against by an LLM judge (each entry: `severity` ∈
|
|
104
|
+
`low`|`medium`|`high`|`critical` + `description`; `file`/`line` optional — the
|
|
105
|
+
judge matches on substance). Set `expect_github.review_submitted: {}` (a cheap
|
|
106
|
+
proxy that a review was posted).
|
|
107
|
+
|
|
108
|
+
> **Never** put the human/gold review in `pr.reviews` / `pr.review_comments` —
|
|
109
|
+
> those seed the mocked GitHub the agent can read, spoiling the case. The gold
|
|
110
|
+
> lives only in `review_gold`.
|
|
111
|
+
|
|
112
|
+
Don't hand-build these — use `lastlight-evals add-case --pr <url> --review` (see
|
|
113
|
+
**`authoring-pr-review.md`**), which pins the `pr` fixture and seeds a candidate
|
|
114
|
+
`review_gold` from the PR's human review for you to curate. Or bulk-import the
|
|
115
|
+
Martian Code Review Bench with `npx tsx scripts/import-martian.ts`.
|
|
116
|
+
|
|
86
117
|
## Add a custom tier
|
|
87
118
|
|
|
88
119
|
Create `datasets/<tier-name>/` with `tier.json` (`name`, `defaultWorkflow`,
|
|
@@ -95,6 +126,11 @@ and `tests/<id>/`. Discovery auto-finds it — no code change. Run it with
|
|
|
95
126
|
- **Behavioral:** did the workflow take the expected GitHub actions
|
|
96
127
|
(`expect_github`)?
|
|
97
128
|
- **Triage:** did the decision match `triage_gold`?
|
|
129
|
+
- **Review (pr-review):** an LLM judge matches the posted review's findings against
|
|
130
|
+
`review_gold` → **precision / recall / F-beta** (β via `EVAL_F_BETA` or
|
|
131
|
+
`--f-beta`; default F1). Needs a judge model (`EVAL_JUDGE_MODEL`, else a strong
|
|
132
|
+
default per provider key); independent of the model under test. The judge trace
|
|
133
|
+
is inspectable in the dashboard.
|
|
98
134
|
- **Execution (code-fix)** — two modes:
|
|
99
135
|
- **Suite (default).** Nothing held out: run the repo's own `test_cmd` against the
|
|
100
136
|
agent's final tree, **resolved iff it exits 0**. Grades "did the agent leave the
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lastlight-evals-loop
|
|
3
|
+
description: Drive a Last Light EVAL toward a target score with a disciplined, anti-gaming improvement loop — run → diagnose → propose ONE generic fix → re-measure → keep or revert → repeat. Use when the user wants to "improve / raise the pr-review F1", "make the reviewer better against the eval", "close the loop on evals", "iterate on prompts/skills to pass more cases", or "tune the workflow to hit a score target". The loop diagnoses on a TRAIN split and validates on a BLIND held-out split so fixes must generalize, not overfit; it prefers generic overlay prompt/skill edits, and stops for human sign-off before editing any gold answer. For a one-off run/compare use lastlight-evals; to hand-fork a workflow/prompt use lastlight-overlay. Needs an already-scaffolded evals workspace (lastlight-evals) with a pr-review dataset.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [lastlight, evals, loop, improvement, overfitting, pr-review]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Improve an eval, honestly
|
|
9
|
+
|
|
10
|
+
A loop that raises an eval score **without gaming it**. The trap: the loop can see
|
|
11
|
+
both the gold answer and the agent's answer for every case, so it could overfit —
|
|
12
|
+
hardcode a repo's finding into a prompt, or edit a gold answer to force a pass.
|
|
13
|
+
That lifts the number and ruins the reviewer. Every guardrail here exists to force
|
|
14
|
+
**generic, cross-cutting** changes that would help on repos the loop has never seen.
|
|
15
|
+
|
|
16
|
+
Scope: the **pr-review** tier (its judge trace gives you the agent-vs-gold detail
|
|
17
|
+
diagnosis needs). The pattern extends to triage/code-fix, but start here.
|
|
18
|
+
|
|
19
|
+
## Prerequisites
|
|
20
|
+
|
|
21
|
+
- A scaffolded evals workspace with a **pr-review** dataset and a working provider
|
|
22
|
+
key — set up via **`lastlight-evals`** first if you don't have one. Confirm a
|
|
23
|
+
bare `lastlight-evals run pr-review --limit 1 --no-open` grades a case.
|
|
24
|
+
- An **`instance/` overlay** (the deployment overlay) to receive generic edits —
|
|
25
|
+
see **`lastlight-overlay`**. The loop edits copies here, never core.
|
|
26
|
+
- The `diff-runs.ts` helper ships with the evals package
|
|
27
|
+
(`scripts/diff-runs.ts`) — it compares two runs and calls keep/revert.
|
|
28
|
+
|
|
29
|
+
## The one rule
|
|
30
|
+
|
|
31
|
+
**One change per iteration.** Propose a single hypothesis, measure its effect in
|
|
32
|
+
isolation, keep or revert, then move on. No batching — batching hides which edit
|
|
33
|
+
moved the number and invites scattershot overfitting.
|
|
34
|
+
|
|
35
|
+
## Start here
|
|
36
|
+
|
|
37
|
+
| You have… | Go to |
|
|
38
|
+
|---|---|
|
|
39
|
+
| Never run this loop on this dataset | **§1 Set up the split** then §2 |
|
|
40
|
+
| A split + baseline already recorded | **§3 Diagnose** |
|
|
41
|
+
| A proposed change ready to test | **§5 Audit → §6 Apply → §7 Measure → §8 Decide** |
|
|
42
|
+
|
|
43
|
+
## 1. Set up the split (once per dataset)
|
|
44
|
+
|
|
45
|
+
Split the tier's `instance_id`s into **TRAIN** (you diagnose on these — traces
|
|
46
|
+
visible) and **HELD-OUT** (blind — you NEVER read their traces; only their
|
|
47
|
+
aggregate F1 gates a keep). ~70/30, deterministic (sort ids, take the first 70%
|
|
48
|
+
as train). Record both lists at the top of the journal (§9) — they must stay
|
|
49
|
+
fixed across the whole loop, or the held-out gate means nothing.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# list the ids (jq over instances.json), then split deterministically
|
|
53
|
+
lastlight-evals run pr-review --instance <all-ids> --no-open # or omit --instance for the whole tier
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Set a **target**: an F1 goal (e.g. 0.55) or "improve until plateau" (N=3
|
|
57
|
+
consecutive no-keep iterations).
|
|
58
|
+
|
|
59
|
+
## 2. Baseline
|
|
60
|
+
|
|
61
|
+
Run both splits and record `avgFbeta` for each in the journal. Use the cheapest
|
|
62
|
+
adequate model while iterating on prompts; switch to the real target model only to
|
|
63
|
+
confirm a kept change.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
lastlight-evals run pr-review --overlay instance --instance <train-ids> --no-open
|
|
67
|
+
lastlight-evals run pr-review --overlay instance --instance <heldout-ids> --no-open
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Each writes `eval-results/pr-review/<runId>/scorecard.json`. Note the two runIds.
|
|
71
|
+
|
|
72
|
+
## 3. Diagnose (TRAIN only)
|
|
73
|
+
|
|
74
|
+
Read the TRAIN scorecard's `results[].review` and `review.trace`. **Do not open
|
|
75
|
+
held-out traces.** For each failing case:
|
|
76
|
+
- `falseNegatives` (with `severity`) = **recall** loss — real issues the agent missed.
|
|
77
|
+
- `falsePositives` = **precision** loss — noise the agent posted that matched no gold.
|
|
78
|
+
|
|
79
|
+
Cluster across cases and name the **systematic pattern** — not a one-off. Good
|
|
80
|
+
patterns generalize: *"misses security-relevant findings"*, *"posts style nits the
|
|
81
|
+
rubric says to suppress"*, *"confidence bar too low → noise"*, *"no awareness of the
|
|
82
|
+
repo's conventions → wrong-fit findings"*. See **references/levers.md** for how
|
|
83
|
+
each pattern maps to an edit.
|
|
84
|
+
|
|
85
|
+
## 4. Hypothesis — ONE change, lowest lever first
|
|
86
|
+
|
|
87
|
+
Pick the **lowest** lever that could move the whole cluster (full detail in
|
|
88
|
+
**references/levers.md**):
|
|
89
|
+
|
|
90
|
+
- **(a) generic — auto.** Edit an overlay prompt/skill/persona, or add a generic
|
|
91
|
+
`instance/repo-context/AGENTS.md` injected into every repo. Must be general.
|
|
92
|
+
- **(b) per-repo context — signed-off.** A `datasets/pr-review/context/<id>/AGENTS.md`
|
|
93
|
+
the harness injects only for that repo — the portable *"add this to your repo"*
|
|
94
|
+
finding. Human approves before writing.
|
|
95
|
+
- **(c) the eval itself — rare, signed-off.** Edit `review_gold[]` ONLY when the
|
|
96
|
+
gold is demonstrably wrong/incomplete; name the evidence. Human approves.
|
|
97
|
+
|
|
98
|
+
Escalate only when a lower lever genuinely can't address the pattern, and write
|
|
99
|
+
down why.
|
|
100
|
+
|
|
101
|
+
## 5. Audit the change (adversarial sub-agent)
|
|
102
|
+
|
|
103
|
+
Before applying, spawn a **generality + leak auditor** sub-agent (prompt template
|
|
104
|
+
in **references/guardrails.md**). It **REJECTS** if the change:
|
|
105
|
+
- names a specific repo / `instance_id` / file path (lever a must be generic), or
|
|
106
|
+
- **encodes the gold answer** — injected repo context that describes the specific
|
|
107
|
+
findings is cheating. It must read as plausible maintainer guidance written
|
|
108
|
+
*without* knowledge of this PR's bug (conventions, architecture, review
|
|
109
|
+
priorities), never "look for bug X".
|
|
110
|
+
|
|
111
|
+
Rejected → back to §4.
|
|
112
|
+
|
|
113
|
+
## 6. Apply (hybrid autonomy)
|
|
114
|
+
|
|
115
|
+
- **Lever (a)** (incl. generic `repo-context/AGENTS.md`): apply automatically to
|
|
116
|
+
`instance/…` once the auditor passes.
|
|
117
|
+
- **Lever (b)/(c)**: **STOP.** Present the diff + the written justification and ask
|
|
118
|
+
the human to approve before writing to the dataset.
|
|
119
|
+
|
|
120
|
+
## 7. Re-measure
|
|
121
|
+
|
|
122
|
+
Re-run both splits (§2) with the change, then diff against the baseline:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npx tsx scripts/diff-runs.ts <baseline-train.json> <candidate-train.json> \
|
|
126
|
+
--train <train-ids> --heldout <heldout-ids>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Point it at the run pair that covers both splits (or run the two splits in one
|
|
130
|
+
`--instance <all-ids>` run so a single scorecard holds both). It prints per-case
|
|
131
|
+
F1 deltas, the arm-summary delta, and a **KEEP / REVERT verdict**.
|
|
132
|
+
|
|
133
|
+
## 8. Decide
|
|
134
|
+
|
|
135
|
+
- **KEEP** iff train F1 improved **and** held-out did **not** regress (the helper's
|
|
136
|
+
verdict). Train ↑ with held-out ↓ = **overfit → revert**.
|
|
137
|
+
- **Lever (b)** per-repo edits are case-scoped: keep iff that case improved, the
|
|
138
|
+
auditor passed, and the human approved — recorded as a per-repo recommendation,
|
|
139
|
+
not a workflow change (no held-out claim is made for it).
|
|
140
|
+
- Else **REVERT**: `git checkout` the overlay file, or remove the sidecar.
|
|
141
|
+
|
|
142
|
+
## 9. Journal, then repeat
|
|
143
|
+
|
|
144
|
+
Append one entry per iteration (schema in **references/journal-format.md**):
|
|
145
|
+
pattern, lever, the diff/context, auditor verdict, train Δ, held-out Δ, decision,
|
|
146
|
+
running best. Then return to §3. Stop at the target or the plateau.
|
|
147
|
+
|
|
148
|
+
Run the loop on a cadence with the built-in `/loop` if you want it to keep going
|
|
149
|
+
unattended between your check-ins — but the lever-(b)/(c) sign-off stops still
|
|
150
|
+
apply.
|
|
151
|
+
|
|
152
|
+
## Done when
|
|
153
|
+
|
|
154
|
+
The target F1 is reached or the loop plateaus, the journal records every
|
|
155
|
+
hypothesis and its train/held-out deltas, kept changes live in `instance/` (and,
|
|
156
|
+
with sign-off, per-repo `context/` sidecars), and **no** change was kept that
|
|
157
|
+
regressed the blind held-out set. Report: baseline → final F1 (train and
|
|
158
|
+
held-out), the kept changes, any per-repo recommendations, and anything that
|
|
159
|
+
needed human sign-off.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Guardrails — keeping the loop honest
|
|
2
|
+
|
|
3
|
+
The loop sees the gold answer and the agent's answer, so it *could* game the score.
|
|
4
|
+
These guardrails make that hard and, where it isn't automatable, put a human in the
|
|
5
|
+
way. None is optional.
|
|
6
|
+
|
|
7
|
+
## 1. Held-out split (empirical anti-overfit gate)
|
|
8
|
+
|
|
9
|
+
Diagnose on TRAIN; validate on a BLIND HELD-OUT split whose traces you never read.
|
|
10
|
+
A generic (lever a) change is kept only if **train F1 improves AND held-out F1 does
|
|
11
|
+
not regress** beyond a small epsilon. A train gain with a held-out regression is
|
|
12
|
+
overfitting — revert it. `scripts/diff-runs.ts` computes this verdict for you; do
|
|
13
|
+
not override it by eyeballing train alone.
|
|
14
|
+
|
|
15
|
+
The split ids are fixed for the whole loop. If you re-split (e.g. to add cases),
|
|
16
|
+
say so in the journal and treat prior held-out results as no longer comparable.
|
|
17
|
+
|
|
18
|
+
## 2. One change per iteration
|
|
19
|
+
|
|
20
|
+
Isolates causal effect. If two edits ship together and the number moves, you can't
|
|
21
|
+
attribute it — and you can't tell an overfit edit riding along with a good one.
|
|
22
|
+
|
|
23
|
+
## 3. The generality + leak auditor (adversarial sub-agent)
|
|
24
|
+
|
|
25
|
+
Before applying ANY change, spawn a fresh sub-agent to try to reject it. It is
|
|
26
|
+
adversarial on purpose — its job is to find the reason this is gaming, not to
|
|
27
|
+
approve. Give it the diff (or the injected-context text), the diagnosed pattern,
|
|
28
|
+
and this instruction:
|
|
29
|
+
|
|
30
|
+
> You are auditing a proposed change to a code-review agent that is being tuned
|
|
31
|
+
> against an eval. Your job is to REJECT changes that game the eval instead of
|
|
32
|
+
> genuinely improving the reviewer. Default to REJECT when unsure.
|
|
33
|
+
>
|
|
34
|
+
> REJECT if the change:
|
|
35
|
+
> 1. names or targets a specific repository, `instance_id`, file path, function,
|
|
36
|
+
> or PR — a generic prompt/skill/persona edit (lever a) must apply to any repo;
|
|
37
|
+
> 2. encodes the eval's gold answer — e.g. injected repo context or a prompt that
|
|
38
|
+
> describes the specific findings the agent is "supposed to" make. Injected
|
|
39
|
+
> repo context must read as plausible standing maintainer guidance written
|
|
40
|
+
> WITHOUT knowledge of this PR's bug (conventions, architecture, review
|
|
41
|
+
> priorities), never "check for <the specific issue>";
|
|
42
|
+
> 3. hard-codes an answer, a magic string, or a case count to pass a known case;
|
|
43
|
+
> 4. (for a gold/eval edit) lacks concrete evidence that the existing gold is
|
|
44
|
+
> wrong — "it makes a case pass" is not evidence.
|
|
45
|
+
>
|
|
46
|
+
> Otherwise ACCEPT. Reply with a verdict (ACCEPT/REJECT) and a one-line reason.
|
|
47
|
+
|
|
48
|
+
A REJECT sends you back to reformulating a more general change. Record the verdict
|
|
49
|
+
either way.
|
|
50
|
+
|
|
51
|
+
## 4. The lever ladder + sign-off
|
|
52
|
+
|
|
53
|
+
Generic (a) edits auto-apply once the auditor passes. Per-repo context (b) and any
|
|
54
|
+
gold/PR-text edit (c) **stop for human sign-off** with a written justification —
|
|
55
|
+
they are the game-able levers, so a human always ratifies them. Never edit
|
|
56
|
+
`review_gold` to make a failing case pass; only when the gold is demonstrably wrong.
|
|
57
|
+
|
|
58
|
+
## 5. Never touch core
|
|
59
|
+
|
|
60
|
+
Edits live in `instance/` (overlay) and, with sign-off, dataset sidecars / gold.
|
|
61
|
+
Core workflow code is never modified — the whole value of the harness is that the
|
|
62
|
+
*real* workflow runs. If a fix seems to require a core change, it's out of scope
|
|
63
|
+
for the loop; note it for the maintainers instead.
|
|
64
|
+
|
|
65
|
+
## 6. Auditable journal + provenance
|
|
66
|
+
|
|
67
|
+
Every hypothesis → diff → train/held-out deltas → decision is recorded
|
|
68
|
+
(references/journal-format.md), and every run records which injected context it saw
|
|
69
|
+
(`injectedContext` on each result). A reviewer can reconstruct exactly what changed
|
|
70
|
+
and why the number moved — no silent wins.
|
|
71
|
+
|
|
72
|
+
## The keep/revert decision, precisely
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
lever (a) generic:
|
|
76
|
+
KEEP iff trainΔ > epsilon AND heldoutΔ >= -epsilon (else REVERT)
|
|
77
|
+
lever (b) per-repo:
|
|
78
|
+
KEEP iff that case improved AND auditor ACCEPTED AND human approved
|
|
79
|
+
(recorded as a per-repo recommendation; no held-out claim)
|
|
80
|
+
lever (c) gold/eval:
|
|
81
|
+
APPLY iff auditor ACCEPTED AND human approved AND evidence recorded
|
|
82
|
+
(this changes what "correct" means — it's a dataset fix, not a score win)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
If a split is missing (e.g. you forgot to run held-out), the helper says
|
|
86
|
+
INCONCLUSIVE / REVIEW rather than KEEP — don't keep on train alone.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Journal format — the auditable ledger
|
|
2
|
+
|
|
3
|
+
The loop appends one entry per iteration to a single Markdown file, by default
|
|
4
|
+
`eval-results/loop-journal.md` in the workspace (next to the runs it references).
|
|
5
|
+
It is the record that lets a human reconstruct every change and why the score
|
|
6
|
+
moved — keep it complete even for reverted iterations (a revert is a result).
|
|
7
|
+
|
|
8
|
+
## Header (write once, at the top)
|
|
9
|
+
|
|
10
|
+
```markdown
|
|
11
|
+
# pr-review improvement loop
|
|
12
|
+
|
|
13
|
+
- Model under test: anthropic/claude-sonnet-5 (iterating cheap: haiku)
|
|
14
|
+
- Judge model: <EVAL_JUDGE_MODEL or default>
|
|
15
|
+
- Target: F1 >= 0.55 (or: improve until 3 consecutive no-keep iterations)
|
|
16
|
+
- Split (FIXED for this loop):
|
|
17
|
+
- TRAIN (n): id1, id2, id3, ...
|
|
18
|
+
- HELDOUT (n): idA, idB, ...
|
|
19
|
+
- Baseline: train F1 = 0.33, heldout F1 = 0.31 (runIds: <train>, <heldout>)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Per-iteration entry
|
|
23
|
+
|
|
24
|
+
```markdown
|
|
25
|
+
## Iteration <N> — <one-line hypothesis>
|
|
26
|
+
|
|
27
|
+
- Pattern: <the systematic failure named in §3, e.g. "posts style nits the rubric suppresses (precision loss across 4 train cases)">
|
|
28
|
+
- Lever: (a) generic | (b) per-repo | (c) gold — <why this lever; why not lower>
|
|
29
|
+
- Change:
|
|
30
|
+
file: instance/skills/code-review/SKILL.md
|
|
31
|
+
diff: |
|
|
32
|
+
<the actual diff, or the injected-context text>
|
|
33
|
+
- Auditor: ACCEPT | REJECT — <one-line reason>
|
|
34
|
+
- Applied: auto | human-approved (<who/when>) | not applied (auditor rejected)
|
|
35
|
+
- Result (diff-runs.ts):
|
|
36
|
+
train: 0.33 -> 0.41 (Δ +0.08)
|
|
37
|
+
heldout: 0.31 -> 0.31 (Δ +0.00)
|
|
38
|
+
per-case regressions: 0
|
|
39
|
+
- Decision: KEEP | REVERT | (b) recorded as per-repo recommendation
|
|
40
|
+
- Running best: train F1 = 0.41, heldout F1 = 0.31
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Rules
|
|
44
|
+
|
|
45
|
+
- **One entry per iteration**, including reverts and auditor rejections — the tail
|
|
46
|
+
of no-keep iterations is the plateau signal.
|
|
47
|
+
- Paste the **actual diff / context text**, not a paraphrase — the point is
|
|
48
|
+
reproducibility.
|
|
49
|
+
- Always record **both** train and held-out deltas. A missing held-out number
|
|
50
|
+
means the decision is INCONCLUSIVE, not KEEP.
|
|
51
|
+
- For lever (b)/(c), record the **human sign-off** and, for (c), the **evidence**
|
|
52
|
+
that the gold was wrong.
|
|
53
|
+
- Keep the **Running best** line current — it's the at-a-glance progress toward
|
|
54
|
+
the target and the input to the plateau check.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# The three levers — what to edit, and the escalation ladder
|
|
2
|
+
|
|
3
|
+
All three levers change eval outcomes **without touching core** — the real
|
|
4
|
+
production workflow always runs unmodified. You only edit the deployment overlay
|
|
5
|
+
(`instance/`) and, with sign-off, the dataset. Prefer the lowest lever that can
|
|
6
|
+
move the whole failure cluster; escalate only with a written reason.
|
|
7
|
+
|
|
8
|
+
## Pattern → lever map
|
|
9
|
+
|
|
10
|
+
| Diagnosed pattern (from TRAIN traces) | Most likely lever |
|
|
11
|
+
|---|---|
|
|
12
|
+
| Posts noise / nits the rubric says to suppress (precision loss) | (a) tighten the severity/precision bar in `code-review` skill |
|
|
13
|
+
| Misses a whole class of real issues, e.g. security, concurrency (recall loss) | (a) add that class to the reviewer's what-to-check rubric/prompt |
|
|
14
|
+
| Reviews against the wrong conventions for a repo | (a) generic repo-context, or (b) per-repo context |
|
|
15
|
+
| Wrong-fit findings because it lacks a repo's build/test/domain norms | (b) per-repo `AGENTS.md` (a portable recommendation) |
|
|
16
|
+
| A gold comment is a non-actionable nit, or a clear real finding scores as a false positive because gold omits it | (c) fix the gold — rare, evidence required |
|
|
17
|
+
|
|
18
|
+
## (a) Prompts / skills / persona + generic repo-context — *generic, auto*
|
|
19
|
+
|
|
20
|
+
The preferred lever. A change here must generalize to every repo. Edit copies in
|
|
21
|
+
the overlay (fork with `lastlight fork <workflow>` / `lastlight fork agent-context`,
|
|
22
|
+
or create the shadowing file at the same logical path — see the **lastlight-overlay**
|
|
23
|
+
skill). Common targets:
|
|
24
|
+
|
|
25
|
+
- `instance/skills/code-review/SKILL.md` — the severity rubric + precision bar
|
|
26
|
+
(what findings survive). The highest-leverage file for precision problems.
|
|
27
|
+
- `instance/skills/pr-review/SKILL.md` — the review procedure (confidence gate,
|
|
28
|
+
findings-file contract).
|
|
29
|
+
- `instance/workflows/prompts/reviewer.md` — the reviewer prompt text.
|
|
30
|
+
- `instance/workflows/pr-review.yaml` — phase wiring (which skills a phase loads).
|
|
31
|
+
- `instance/agent-context/rules.md` / `soul.md` — global persona/rules the agent
|
|
32
|
+
reads via the workspace `AGENTS.md`.
|
|
33
|
+
- `instance/repo-context/AGENTS.md` — **generic** synthetic repo context the
|
|
34
|
+
harness injects into *every* seeded pr-review repo. Use for guidance that would
|
|
35
|
+
help a reviewer on any codebase (e.g. "prefer concrete, line-anchored findings;
|
|
36
|
+
suppress pure style nits"). Held-out gates a keep, so it must genuinely
|
|
37
|
+
generalize.
|
|
38
|
+
|
|
39
|
+
## (b) Per-repo injected context — *portable finding, signed-off*
|
|
40
|
+
|
|
41
|
+
A dataset sidecar the harness injects **only for that case's repo**:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
datasets/pr-review/context/<instance_id>/AGENTS.md (or CLAUDE.md)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This is the *"add this to your repo and your reviews improve by X"* recommendation
|
|
48
|
+
— honest because it's exactly what a maintainer could commit. It is **case-scoped**,
|
|
49
|
+
so the held-out generalization gate doesn't apply; instead it needs human sign-off
|
|
50
|
+
and must pass the no-gold-leak auditor (it must NOT describe this PR's specific
|
|
51
|
+
findings — only standing repo conventions, architecture, and review priorities).
|
|
52
|
+
|
|
53
|
+
How injection works (so you can trust it lands): the harness writes the block into
|
|
54
|
+
the file the agent's runtime actually reads — it appends to an existing
|
|
55
|
+
`AGENTS.md`, else an existing `CLAUDE.md` (never creating an `AGENTS.md` that would
|
|
56
|
+
shadow it), else creates a fresh `AGENTS.md`. Pi auto-loads that file walking up
|
|
57
|
+
from the agent's cwd, so it reaches the model every phase with no prompt change.
|
|
58
|
+
Toggle off for a clean control run with `--no-inject-context` (or
|
|
59
|
+
`EVAL_INJECT_CONTEXT=0`). Provenance is recorded on each result
|
|
60
|
+
(`injectedContext`).
|
|
61
|
+
|
|
62
|
+
## (c) The eval itself — *rare, signed-off*
|
|
63
|
+
|
|
64
|
+
Edit the case in `datasets/pr-review/instances.json`:
|
|
65
|
+
|
|
66
|
+
- `review_gold[]` (`{ file?, line?, severity, description }`) — the correct answer.
|
|
67
|
+
- `pr.body` / `problem_statement` — what the agent is told about the PR.
|
|
68
|
+
|
|
69
|
+
Only when the gold is **demonstrably wrong or incomplete** — never to force a
|
|
70
|
+
failing case to pass. The justification must name the evidence (e.g. "the human
|
|
71
|
+
PR review made this exact point; gold omitted it, so a correct finding scored as a
|
|
72
|
+
false positive"). Martian's gold set is known-incomplete by design, so a
|
|
73
|
+
real-but-unlisted finding scoring as a false positive is expected — that is *not*
|
|
74
|
+
on its own grounds to edit gold; it's why the headline metric is F1, not F0.5.
|
|
75
|
+
|
|
76
|
+
## Escalation ladder
|
|
77
|
+
|
|
78
|
+
Try (a) first. Escalate to (b) only when the pattern is genuinely repo-specific
|
|
79
|
+
(a convention that doesn't generalize). Escalate to (c) only when the eval is
|
|
80
|
+
wrong. Record the reason for every escalation in the journal.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: lastlight-guide
|
|
3
|
+
description: Orientation & router for the Last Light skills. Use ONLY when the user has NOT named a concrete Last Light task — i.e. they're unsure which skill/flow they need, ask "what can Last Light do / where do I start", say "help me with Last Light" with no specific goal, or want a guided tour across server / client / overlay / evals. Do NOT use when the ask already names a task — "set up/deploy a server" → lastlight-server, "connect/log in my CLI" → lastlight-client, "customize a workflow/prompt/persona/config" → lastlight-overlay, "run evals / compare models / author a case / build a PR-review dataset" → lastlight-evals, "iteratively improve an eval toward a target score" → lastlight-evals-loop: invoke that skill directly. This skill only routes and, when the goal is ambiguous, asks. Also invocable as /lastlight-guide.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
tags: [lastlight, guide, router, orientation, help]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Last Light — where do you want to go?
|
|
9
|
+
|
|
10
|
+
You don't need to know which skill you need — describe what you want and this
|
|
11
|
+
maps you onto it.
|
|
12
|
+
|
|
13
|
+
> **If the user already named a concrete task, don't linger here** — hand off to
|
|
14
|
+
> the matching skill immediately (see the menu below). This guide is for
|
|
15
|
+
> *"which one do I need?"*, not for doing the work.
|
|
16
|
+
|
|
17
|
+
There are two big things people do with Last Light:
|
|
18
|
+
|
|
19
|
+
- **Operate a deployment** — stand up the agent, connect to it, customize it.
|
|
20
|
+
- **Measure its quality** — run its real workflows as evals, compare models,
|
|
21
|
+
build datasets.
|
|
22
|
+
|
|
23
|
+
**If the user's goal is ambiguous, ask** (use `AskUserQuestion`) rather than
|
|
24
|
+
guessing which flow they mean — "are you setting up a server, connecting a CLI to
|
|
25
|
+
one, customizing workflows, or running evals?" Then hand off to the skill below;
|
|
26
|
+
each is a full runbook, so **invoke it and follow it** rather than re-deriving its
|
|
27
|
+
steps here.
|
|
28
|
+
|
|
29
|
+
## Flow 1 — operate a Last Light deployment
|
|
30
|
+
|
|
31
|
+
The route from nothing to a running, customized agent. Do these in order the
|
|
32
|
+
first time; each is also usable on its own later.
|
|
33
|
+
|
|
34
|
+
1. **`lastlight-server`** — install & configure the **server**: Docker stack, a
|
|
35
|
+
GitHub App, model provider key, and the repos it may manage. Start here to
|
|
36
|
+
stand one up for the first time. Config lives in a private **overlay** at
|
|
37
|
+
`instance/`.
|
|
38
|
+
2. **`lastlight-client`** — point the `lastlight` **CLI** at an existing server
|
|
39
|
+
and log in (saves URL + token to `~/.lastlight/config.json`). For people who
|
|
40
|
+
*use* a server someone else runs — no Docker, no GitHub App.
|
|
41
|
+
3. **`lastlight-overlay`** — create & customize the `instance/` **overlay**: fork
|
|
42
|
+
built-in **workflows**, **prompts**, **skills**, or the agent **persona**
|
|
43
|
+
(`agent-context`), and tune `config.yaml` — overriding only what you name,
|
|
44
|
+
layered over the packaged defaults. Reach for it whenever you want to change
|
|
45
|
+
*what the agent does or how it behaves* on an existing deployment.
|
|
46
|
+
|
|
47
|
+
## Flow 2 — measure quality with Last Light Evals
|
|
48
|
+
|
|
49
|
+
Not required to run a deployment — this is how you **tell if a model or a
|
|
50
|
+
workflow/prompt change is any good** before shipping it.
|
|
51
|
+
|
|
52
|
+
- **`lastlight-evals`** — run Last Light's **real** workflows against a mocked
|
|
53
|
+
GitHub and grade them deterministically; compare models on pass rate / cost /
|
|
54
|
+
latency; author eval cases; **build a PR-review dataset from your own gold
|
|
55
|
+
PRs**. Its own front door lists the sub-flows (scaffold · run/compare · browse
|
|
56
|
+
past runs · author a case from a PR/issue · build a PR-review dataset). If the
|
|
57
|
+
user just hands you PR URLs and says "make a review eval set", that skill's
|
|
58
|
+
interactive flow prompts for the URLs and does the rest.
|
|
59
|
+
|
|
60
|
+
## The bridge — overlay ↔ evals
|
|
61
|
+
|
|
62
|
+
The **overlay is shared** by both flows. `lastlight-evals --overlay <dir>` points
|
|
63
|
+
the harness at a *deployment's own* workflows **and** datasets, so you evaluate
|
|
64
|
+
exactly what you ship. The loop that ties it together:
|
|
65
|
+
|
|
66
|
+
> customize in **`lastlight-overlay`** → measure the change with
|
|
67
|
+
> **`lastlight-evals --overlay .`** → keep it or revert.
|
|
68
|
+
|
|
69
|
+
To run that loop *toward a target score* — automatically, and without overfitting
|
|
70
|
+
to specific cases — use **`lastlight-evals-loop`**: it diagnoses on a train split,
|
|
71
|
+
validates on a blind held-out split, and proposes one generic overlay fix at a
|
|
72
|
+
time (stopping for sign-off before it touches a gold answer).
|
|
73
|
+
|
|
74
|
+
## Quick menu — "I want to…"
|
|
75
|
+
|
|
76
|
+
| …do this | go to |
|
|
77
|
+
|---|---|
|
|
78
|
+
| Stand up / install / deploy a server for the first time | **`lastlight-server`** |
|
|
79
|
+
| Connect my CLI to a server / log in / run commands against it | **`lastlight-client`** |
|
|
80
|
+
| Customize a workflow, prompt, skill, or the agent's persona; tune config | **`lastlight-overlay`** |
|
|
81
|
+
| Run evals, compare models, browse past runs | **`lastlight-evals`** |
|
|
82
|
+
| Author an eval case from a GitHub PR or issue | **`lastlight-evals`** (§6) |
|
|
83
|
+
| Build a PR-review eval dataset from a list of gold PRs | **`lastlight-evals`** (§6) |
|
|
84
|
+
| Iteratively improve a workflow/prompt to raise an eval score | **`lastlight-evals-loop`** |
|
|
85
|
+
|
|
86
|
+
## Preconditions (what every flow assumes)
|
|
87
|
+
|
|
88
|
+
- **Node 24+** and the CLI: `lastlight` (server/client/overlay) or
|
|
89
|
+
`lastlight-evals` (evals) — `npm i -g` either.
|
|
90
|
+
- **Docker + a GitHub App** — server only.
|
|
91
|
+
- **`gh` authenticated** — only for `lastlight-evals add-case` (reads real
|
|
92
|
+
PRs/issues); running evals mocks GitHub and needs no token.
|
|
93
|
+
- **A model provider API key** — server and evals (`OPENAI_API_KEY` /
|
|
94
|
+
`ANTHROPIC_API_KEY` / …).
|
|
95
|
+
|
|
96
|
+
Not sure which you have? Ask the user what they're trying to accomplish, confirm
|
|
97
|
+
the precondition for that flow, then hand off to the skill.
|