mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-01 15:47:41 +08:00
docs: Share lang-tracer URLs and propose gap tickets in the eval skill (no-changelog) (#37092)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -53,7 +53,7 @@ trim), **calibration** (classify each red and resolve keep/loosen/drop), and
|
||||
|
||||
| Level | Who decides when to stop | Behaviour |
|
||||
|---|---|---|
|
||||
| **autonomous** | agent | Runs all four gates start-to-finish; reports a **decision log** at the end for the driver to review. |
|
||||
| **autonomous** | agent | Runs all four gates start-to-finish; reports a **decision log** at the end for the driver to review — with the pushed case, its suite, and the source thread as **links** ([Share links, never bare ids](#share-links-never-bare-ids)), and a Linear ticket **proposal** for any kept capability-gap red ([Capability gap → propose a Linear ticket](#capability-gap--propose-a-linear-ticket)). |
|
||||
| **checkpoint** | driver, per gate | Stops at each gate with a compact **proposal + recommendation**; driver says "go" or redirects. At the **calibration** gate, hands the driver a link to the just-built thread on the live instance plus login credentials so they can review the real conversation and workflow themselves before confirming (below). |
|
||||
|
||||
**Calibration is special-cased at both levels.** A calibration verdict that
|
||||
@@ -82,6 +82,39 @@ keep/loosen/drop, and the review link. The driver logs in, reads the thread and
|
||||
the workflow, and confirms or redirects before you write the verdict back into
|
||||
the case `description`.
|
||||
|
||||
## Share links, never bare ids
|
||||
|
||||
Every lang-tracer entity has a shareable web page, but the CLI and the MCP hand
|
||||
you **numeric ids** — `eval:langtracer-push` prints `+ created <slug> (#621)`,
|
||||
`get_eval_run` returns a run number, `list_conversations` returns thread ids.
|
||||
An id is unclickable: the driver has to go find it. **Whenever you name a case,
|
||||
suite, thread, cluster, or run in anything a human reads** — a checkpoint
|
||||
proposal, the end-of-run decision log, a PR description, a Linear ticket, a Slack
|
||||
message — render it as a link, keeping the id in the label:
|
||||
|
||||
```
|
||||
pushed as [#621](https://lang-tracer.n8n-maintenance.workers.dev/test-cases/621)
|
||||
```
|
||||
|
||||
Build links off the **web base** (`LANGTRACER_URL`, in production
|
||||
`https://lang-tracer.n8n-maintenance.workers.dev`). Never off the API bases —
|
||||
`${LANGTRACER_URL}/api/v1` and `/api/mcp` are machine endpoints, and a link into
|
||||
either 404s for the driver or dumps JSON.
|
||||
|
||||
| Entity | URL | Where the id comes from |
|
||||
|---|---|---|
|
||||
| Test case | `<base>/test-cases/<id>` | push output `(#<id>)`; `create_test_case` / `search_test_cases` |
|
||||
| Suite | `<base>/suites/<suiteId>` | push header `Suite "<slug>" (#<id>)`; `list_suites` |
|
||||
| Source conversation | `<base>/conversations/<threadId>` | `list_conversations` / `get_conversation` |
|
||||
| Cluster report | `<base>/clusters/<id>` | `list_cluster_runs` / `get_latest_cluster_run` |
|
||||
| Eval run (sweep) | `<base>/results?sweep=<runId>` | `list_eval_runs` / `get_eval_run` (`runId` *is* `sweeps.id`, the "run #N") |
|
||||
|
||||
Two links that are **not** lang-tracer and don't take this base: the built thread
|
||||
(`<base-url>/assistant/<threadId>`) and workflow (`<base-url>/workflow/<id>`) live
|
||||
on the **n8n instance** the eval ran against. When both are relevant — reviewing a
|
||||
calibration red, writing a capability-gap ticket — give both, labelled, so nobody
|
||||
has to guess which host a link points at.
|
||||
|
||||
## Where the best cases come from
|
||||
|
||||
The strongest cases encode a **real** failure, not an invented premise. Two
|
||||
@@ -166,7 +199,7 @@ the combinatorial bulk. A case that never builds tests nothing.
|
||||
|
||||
These steps map to the four gates from [Set the autonomy level first](#set-the-autonomy-level-first):
|
||||
sourcing (before step 1) is the **selection** gate; steps 1–2 are the **shape +
|
||||
expectations** gate; steps 5–6 are the **calibration** gate; step 7 is the
|
||||
expectations** gate; steps 5–6 are the **calibration** gate; steps 7–8 are the
|
||||
**push** gate. In *autonomous* mode you flow through all of them and summarize in
|
||||
a decision log; in *checkpoint* mode you pause at each with a proposal, and at
|
||||
calibration you hand the driver the thread link + login to review the real build
|
||||
@@ -212,6 +245,12 @@ calibration you hand the driver the thread link + login to review the real build
|
||||
[`case-shapes.md`](case-shapes.md).) For a sourced case,
|
||||
finish by **linking it to its source thread/finding** over the MCP — see
|
||||
[Link the pushed case to its source](#link-the-pushed-case-to-its-source-provenance-step--always-do-this).
|
||||
8. **Hand back links, and a ticket proposal if the case found a gap.** Report the
|
||||
pushed case as `<base>/test-cases/<id>`, not `#<id>` ([Share links, never bare
|
||||
ids](#share-links-never-bare-ids)), and if calibration kept a real
|
||||
capability-gap red, propose a Linear ticket for it ([Capability gap → propose a
|
||||
Linear ticket](#capability-gap--propose-a-linear-ticket)) rather than leaving the
|
||||
gap as a red case nobody owns.
|
||||
|
||||
`--iterations N` is available to measure flakiness (pass@k / pass^k) — reach for
|
||||
it when you suspect a case is non-deterministic or before promoting it to a
|
||||
@@ -284,7 +323,9 @@ failures are excluded do the three categories below apply:
|
||||
something the user asked for (a miswired branch, a missing retry, wrong field
|
||||
keys). This is exactly what the eval is for. **Keep it red.** Don't loosen the
|
||||
assertion or drop the scenario; a currently-red gap is the capability signal
|
||||
today, and a re-introduction guard once the builder improves.
|
||||
today, and a re-introduction guard once the builder improves. Then **propose a
|
||||
Linear ticket** for the gap — see [Capability gap → propose a Linear
|
||||
ticket](#capability-gap--propose-a-linear-ticket).
|
||||
- **Harness limitation** — the build is correct but the mock/execution layer
|
||||
can't exercise the path (see "Known harness limitations", below). **Keep the
|
||||
scenario and say so in its `description`** — that this red is harness-caused,
|
||||
@@ -321,6 +362,62 @@ classification is stated in the open, never silently committed — misreading a
|
||||
harness red as a real gap (or the reverse) is the one calibration mistake that
|
||||
quietly corrupts the suite.
|
||||
|
||||
### Capability gap → propose a Linear ticket
|
||||
|
||||
A kept capability-gap red is a **product bug you just characterised better than
|
||||
any bug report would**. But a red case in a suite doesn't assign itself to anyone:
|
||||
without a ticket the gap sits in CI as permanent noise, and the next person to
|
||||
read the run assumes someone already owns it. So once a red is classified as a
|
||||
real gap (and the driver has confirmed it, per the autonomy level), **propose a
|
||||
Linear ticket for it.**
|
||||
|
||||
**Propose, don't create.** Per [AGENTS.md](../../../AGENTS.md), never open a
|
||||
Linear ticket unasked. Put the draft in front of the driver — interactively in
|
||||
checkpoint mode, in the decision log in autonomous mode — with a title, a team,
|
||||
and the body, and let them say go. Skip the proposal in two cases:
|
||||
|
||||
- **The gap already has a ticket.** Check the case's linked issues on its page,
|
||||
and run `get_linear_ticket_context <TEAM-N>` on any candidate identifier the
|
||||
driver or the source thread mentions, before you draft a duplicate.
|
||||
- **The red isn't a capability gap.** A `Harness note:` red is a
|
||||
lang-tracer/harness issue, and genuine non-determinism is a case-hygiene chore.
|
||||
Neither belongs in the builder's queue.
|
||||
|
||||
The draft body should carry what makes the gap actionable, all of it already in
|
||||
hand from calibration:
|
||||
|
||||
- **The eval case**, as a link — `<base>/test-cases/<id>` (see [Share links, never
|
||||
bare ids](#share-links-never-bare-ids)). This is the reproducer; it's the most
|
||||
valuable line in the ticket.
|
||||
- **What failed, verbatim** — the failing `outcomeExpectation` /
|
||||
`processExpectation` or scenario name, plus the judge's stated reason. Not a
|
||||
paraphrase: the exact text is what the fixer will grep for.
|
||||
- **What the build did instead** — the specific defect (miswired branch, wrong
|
||||
field key, missing gate), and links to the real evidence: the source conversation
|
||||
(`<base>/conversations/<threadId>`) and the built thread + workflow on the eval
|
||||
instance (`<base-url>/assistant/<threadId>`, `<base-url>/workflow/<id>`).
|
||||
- **Blast radius, if you know it** — the cluster theme or the number of real
|
||||
conversations behind the gap (`<base>/clusters/<id>`) is what turns "one red
|
||||
case" into a prioritisable bug.
|
||||
|
||||
**File it from the case page so the link is made.** The `<base>/test-cases/<id>`
|
||||
page has a *Create Linear issue* dialog that creates the ticket **and** links it to
|
||||
the case; that link is what makes `get_linear_ticket_context <TEAM-N>` later return
|
||||
the case, its scenarios, the source conversation, and its analysis in one call. The
|
||||
case↔ticket link is only writable from that UI — lang-tracer's MCP and `/api/v1`
|
||||
are read-only for it — so if the ticket gets created some other way (a Linear MCP,
|
||||
if your harness has one, or Linear directly), say plainly that it isn't linked, ask
|
||||
the driver to link it on the case page, and meanwhile put the identifier + URL in
|
||||
the case `description` via `update_test_case` so the provenance isn't lost.
|
||||
|
||||
Then extend the description prefix with the ticket, so the corpus stays greppable
|
||||
in both directions: `Capability-gap finding: current build reds because <X> — a
|
||||
real builder bug (flips to a regression guard once fixed). Tracked in
|
||||
[<TEAM-123>](<ticket url>)`. And when the *build itself* is wrong — not just a
|
||||
scenario red under a correct build — push it with `--set-kind capability_gap` into
|
||||
a suite of that kind (see
|
||||
[Push to a lang-tracer suite](#push-to-a-lang-tracer-suite)).
|
||||
|
||||
## Example
|
||||
|
||||
Minimal build case:
|
||||
@@ -668,6 +765,12 @@ npx dotenvx run -f .env.eval -- pnpm eval:langtracer-push --suite baseline --cha
|
||||
lang-tracer #48), so scenario edits re-push like any other field. A lang-tracer
|
||||
deployment predating that change silently ignores the key; if a pushed scenario
|
||||
edit doesn't land, update the scenario in the lang-tracer UI.
|
||||
- **Report what was pushed as links, not `#ids`.** The CLI prints `+ created
|
||||
<slug> (#621)` / `~ updated <slug> (#621, rev 3)` and a suite header — that's the
|
||||
id, and nothing more. Turn each one into `<base>/test-cases/<id>` (and the suite
|
||||
into `<base>/suites/<suiteId>`) in whatever you hand the driver, so they can open
|
||||
the case they just authored instead of hunting for it. See [Share links, never
|
||||
bare ids](#share-links-never-bare-ids).
|
||||
- **An `inline` seed pushes with the case:** the case-write API stores it
|
||||
verbatim, so a seeded case lives in a suite like any other. Only a `replay`
|
||||
case is refused — the push lists it under `skipped:`, because it's
|
||||
|
||||
@@ -36,6 +36,12 @@ claude mcp add --scope local --transport http langtracer-hosted \
|
||||
session start, so reconnect to pick it up. (The LangSmith MCP is usually already
|
||||
connected.)
|
||||
|
||||
The MCP returns ids; the driver needs pages. Every thread, cluster, and case you
|
||||
cite while sourcing has a web URL off the same base — `<base>/conversations/<threadId>`,
|
||||
`<base>/clusters/<id>`, `<base>/test-cases/<id>` — so cite them as links, not bare
|
||||
ids. Full table in
|
||||
[Share links, never bare ids](SKILL.md#share-links-never-bare-ids).
|
||||
|
||||
## Discover → verify → encode
|
||||
|
||||
1. **Scan cluster themes** — `list_cluster_runs` / `get_latest_cluster_run`
|
||||
|
||||
Reference in New Issue
Block a user