Searches
A search has an agent propose changed configs for a work station, called candidates, and replays each on a replay set's searched tasks. The best are then replayed on the set's held-out tasks. Picking a candidate opens a pull request in the line's Terraform repository. The same data is read and written through the Searches API. A search's candidates also show under Candidates on the Insights Stations tab, beside the team's other replayed candidates.
Only people on the team, the workspace's owners and admins, and workspace
tokens with the read scope can read a team's searches. Anyone else is
answered 404, and the web app reads Only team members can see its searches. Starting and stopping a search and picking a candidate also need
plan. See Team outcomes.
Station page
A work station's "Improve" tab has a "Searches" card under "Try a change",
beside "Replay sets", at #searches. It lists the station's searches, newest
first, one row each:
| Column | Shows |
|---|---|
| Search | Search <n>, numbered from the station's first search, linked to its page. |
| State | Its state. Hovering over it shows its ending, once it has one. |
| Replay set | The set it searches on, or –. |
| Best | Its best candidate's name, or "Live config", with its reading when it has one. Without one, "No best candidate yet", or No candidate holds its success yet for a search that aims for the same success for less. |
| Success | The best candidate's score as a percentage, or –. Hovering over it shows This score is from the held-out tasks. or This score is from the searched tasks., with Likely range: <range>. |
| Iterations | <run> / <budget>. |
| Spent | <spent> / <ceiling>. |
| Started | When it started. |
"Start a search" opens the Start a search dialog. It is
refused, with the reason on hover, while a search of the station is under way
(A search of this station is underway.), when the station has no set
(Create a replay set first.), or when no set covers runs of 5 different tasks
(No replay set covers 5 different tasks yet.). While the station's sets load,
it is disabled with Loading the replay sets…, and when they cannot be read,
with Sorry, the replay sets couldn't be loaded. Please try again later.
With no searches, the card reads "No searches yet" and
An agent tries configs on a replay set to find a better, cheaper one., with
"Start a search". With no searches and no replay set, it reads
Searches need a replay set to try configs on., with no action.
Start a search
The dialog's description reads An agent proposes configs for this station. Each config replays on most of the set's tasks. Then the best configs replay on held-out tasks to check that they hold up. The station doesn't change until you pick a config.
| Field | Values |
|---|---|
| Search on | One of the station's replay sets, with how many different tasks it covers, as in 12 tasks. A set whose station has left its line reads The station is gone from its line., and a set of fewer than 5 tasks The set covers <n> tasks. A search holds some tasks out. Minimum different tasks: 5; neither can be chosen. The first set that can be is chosen at first. Starting with no set chosen reads Choose a replay set. |
| Iterations | How many times its agent runs, 1 to 10. 3 at first. |
| Candidates per iteration | How many each agent run may propose, 1 to 5. 2 at first. |
| At once | Replay runs it runs together, 1 to 10. 4 at first. |
| Repeats | How many times each of its replays replays each run, 1 to 5: the live config's, every candidate's and the held-out replays. 1 at first. |
| Ceiling | The most the whole search may spend, its replays and its agent's runs, above 0 and at most 1,000, with 20.00 as its placeholder, and a three-letter currency, USD at first. Under it: The most that the whole search can spend. Its replays and its agent's runs count. |
| Aim for | "More success": Spotlight ranks candidates by how often they succeed. Or "The same success for less": Spotlight ranks candidates by cost per run. Only candidates that match the live config's success, within noise, count. See Aims. |
| Its agent | The harness the search's agent runs on, the first harness at first, and its model and effort. Without a model or effort, the harness's own defaults. |
A count out of bounds reads Please enter a whole number from <least> to <most>.
A ceiling of 0 or less reads Please enter a ceiling above 0., a ceiling over
1,000 Maximum ceiling: 1,000, and a currency that is not three capital
letters Please enter a three-letter currency code, like USD.
"Aim for" is preselected until a person chooses: "The same success for less"
when the newest finished replay of the live config, as it is now, over every
run of the set, other than a search's, succeeded on more than 95% of it, and "More success" otherwise. This can differ from the
set's room to improve, which a
replay with the answer decides once there is one. Once the estimate arrives,
its aim is preselected instead. Until a person chooses, such a set shows
Suggested: the live config already succeeds on <share> of this set. The set has little room for more success. under the choices. The aim is sent with the search only once a person
picks one or the estimate has arrived; otherwise the search
chooses it as it starts.
Until a set and a valid budget are given, the estimate reads Choose a replay set and budget to see the estimated runs and spend. Then it shows what the
estimate endpoint answers:
| Label | Shows |
|---|---|
| Tasks | <n> searched · <n> held out. |
| Copies | Each run once, or Each run <n> times. |
| At most | <n> runs, then <n> of the live config · <n> of candidates · <n> held out · <n> of the agent. |
| Spends at most | The ceiling, then <amount> for the live config · <amount> per candidate · <amount> per held-out replay · <amount> per agent run. |
| Takes | About <duration>, from how long the set's runs took, or Unknown. None of the set's runs was timed. |
The estimate always holds out as many tasks as the search will, and assumes
the choice of tasks whose runs cost most, so the search's own split costs as
much or less. Its counts of runs and its allotments count every copy. Under
it: An agent run may slightly overspend. The search may end a little over its ceiling. When the endpoint refuses, the estimate shows the refusal, or Please fix the marked field to see an estimate. when every problem it names is at
a field.
Under the estimate, the dialog may warn, from the set's
health and the line's min_gain:
| Warning | When |
|---|---|
The set's noise isn't measured. A small gain can be chance. Please replay each run more than once, or replay a set of 5 or more runs to measure it. | The set's noise is not measured. |
Success moved <n> pts between copies of the same runs. This is more than the line's minimum real gain. If you replay each run <n> times, the noise falls below it. Minimum real gain: +<n> pts | The copies needed to bring the noise under min_gain are more than "Repeats" and at most 5: the spread divided by min_gain, squared, rounded up. |
Success moved <n> pts between copies of the same runs. This is more than the line's minimum real gain. Even the maximum of 5 repeats won't bring the noise below it. Read small gains with care, or raise the line's min_gain. Minimum real gain: +<n> pts | The copies needed are more than 5. |
The live config already succeeds on <share> of this set. Aim for the same success for less, or add tasks that the live config fails. | The live config succeeds on more than 95% of the set. |
The judge gave the same verdict twice on only <share> of <n> changes. Make the rubric more specific before you search. ("change" for 1) | The set's newest check found the judge agreeing with itself less than 80% of the time. |
The check flipped on <n> of <m> changes that it ran twice. It can flip a candidate's result by chance. The set page lists these changes. | The set's newest check found a flaky check. |
With each run's answer, the live config gained only <gain> pts on <n> runs. The likely range is <low> to <high>. A better config has little room to show a gain here. Please add tasks that the live config fails. ("run" for 1) | The newest replay with the answer was compared, its gain covers at least 5 tasks paired on both sides, and it is not better. |
Under either Success moved warning, unless "Repeats" is the suggestion
already, Replay each run <n> times sets "Repeats" to the copies needed, at
most 5. A warning does not stop the search from starting. "Start search",
which cannot be selected until the harnesses are known, reads "Starting…" while
it is sent, then opens the new search's page. A refusal is shown at its field, such as a
ceiling too low to give each replay run at least 0.01 of its currency.
Search page
/w/<slug>/team/<teamId>/lines/<lineId>/stations/<stationId>/searches/<searchId>
To someone who may read the team's searches, an unknown search, or one of
another station, reads "Search not found" and No search at this address. It may belong to another station., with "See the station's searches", which
opens the station's Searches card. When the search cannot be
loaded for another reason, the page reads The search could not be loaded.,
with "Try again".
The header shows Search <n>, or "Search" while its number is not known, and, for some endings, a pill,
such as "Stalled", whose hover gives the ending in words. Under it are the
replay set's name, linked to its page ("Its replay set" until the name is
loaded), and how long ago the search ended, or
started while it has not ended. Hovering over that shows Started <when>, ended <when>, or Started <when>. While the search is under way, "Stop"
opens Stop this search?: The search agent stops and no more candidates replay. Finished replays keep their scores, and you can still pick them.,
with "Keep it searching" and "Stop search", which reads "Stopping…" while it
is sent.
Below the header are its tiles, a "Why it stalled" card per reflection, the "Candidates" card and the "Success against cost" card.
Tiles
An ⓘ beside a tile's label shows its note on hover.
| Tile | Shows | Note |
|---|---|---|
| Best | The best candidate's name, or "Live config", then its score as a percentage with held out or searched, and its reading when it has one. Without one, – and "No best candidate yet". Labelled "Cheapest" when the search aims for the same success for less, and then No candidate holds its success yet without one. | The search aims for <aim>. and the aim's note, as under "Aim for", then Likely range: <range>. |
| Live config | The live config's search score as a percentage, and of <n> runs scored; or – and "Not scored yet". | Likely range: <range>. and Minimum real gain: <min_gain>., as in +5 pts. |
| Iterations | <n> of <m>, the iterations run of its budget, and <n> candidates proposed ("candidate" for 1). | Each iteration tries <n> candidates, <n> at once. Each run once. Search agent: <harness> · <model> · <effort>, with Each run <n> times for more copies, and only the parts its agent has. |
| Tasks | The searched tasks, and searched · <n> held out. | The search agent sees only the searched tasks and their scores. It doesn't see the held-out tasks. After the search, the best candidates replay on the held-out tasks to check that they don't only fit what the agent saw., then Held out: <titles>. with each held-out task's title in the set, or Task <first 8 characters of its id>. |
| Spent | What it spent, and of <ceiling>. |
Why it stalled
One card per reflection, newest first, under the tiles,
headed Why it stalled (iteration <n>). The page opened with
#why-it-stalled-<n> scrolls to it.
| Part | Shows |
|---|---|
| Whose failures | Looked at why <name> failed, or Looked at why the live config failed, once the reflection knows the config it looks into. |
| While it runs | Two iterations in a row found nothing better. The search agent is looking into why the remaining tasks fail. |
| Once it ended | Two iterations in a row found nothing better. The search agent sorted the <n> tasks that the best config still failed by cause. ("task" for 1) when it had tasks, then its outcome. |
| Causes | One group per cause recorded, in the order task, judge, check, infra, config: its title, what it means and what to do, then each task the cause was given for. |
| No cause recorded | Once it ended, the tasks it looked into without recording a cause: The search agent looked into these tasks but recorded no cause. |
Each task shows its title in the set, or Task <first 8 characters of its id>,
"Open the failed replay run", linked to the Run page of the replay run that
failed it, the agent's evidence, and Suggested: <suggestion> when it gave
one.
Candidates
The "Candidates" card's note reads Configs that the search agent proposed, by iteration. Pick a candidate to see its reasoning, replays and pull request.
It is one table:
| Column | Shows |
|---|---|
| Candidate | Its name, or "Live config"; a dot for a frontier point, whose hover reads On the frontier: no other candidate succeeds more for the same cost or less.; and its reading when it has one. Selecting the row opens its details, and selecting it again closes them. |
| Searched | Its replay's state until that replay has finished, "Not scored yet", or its search score as a percentage, with Likely range: <range> · of <n> runs scored on hover. |
| Held out | Its held-out score, with its range on hover; "Replaying" while its held-out replay is queued or running; "Not held out" for a candidate that was not replayed there; else –. |
| Gain | Its gain over the live config on the searched tasks, as in +12 pts, green when its verdict is better and red when worse. Hovering shows Gain over the live config, searched: <gain>, likely <low> to <high> pts., then the same for held out once known. – without one. |
| Cost per run | What it spent per scored searched run, or "Unpriced". |
| Pull request | – until it is picked, "Opening…", "Opened", linked to the pull request on GitHub, or "Not opened" with a warning icon, "Why", whose hover reads <reason>. <message>: the reason in words, then Spotlight's message. |
The first row, "Started from", holds the live config. Then each iteration has
a row Iteration <n>, followed by its candidates. An iteration's row reads
· Looked for why it stalled for a reflection, its
state unless it ended, and "Agent run", linked to the
agent run's Run page, titled Iteration <n> of Search <m>. Hovering over Iteration <n> shows
<state>. The search took <n> of <m> proposals. The search agent spent <spent>.: refused proposals count among the second, a reflection has no
count of proposals, and what its agent spent shows once known.
An iteration with no candidates reads Nothing proposed yet. while its agent
run waits or runs, and The search agent proposed nothing replayable. after.
A reflection reads This iteration proposes nothing. The search agent is looking into why the remaining tasks fail. until it ends, then This iteration proposed nothing. The search agent looked into <n> tasks that the best config still failed. Causes recorded: <n>. Both are followed by "See
why it stalled", which scrolls to its card.
With no iteration yet, the card reads "No candidates yet" and The live config replays first. The search agent proposes candidates after that replay finishes. while the search is seeding, Spotlight couldn't replay the live config. The search agent never ran. once it ended seed-failed, or else The search agent proposed no candidates., with "Watch the live config's replay".
The page opened with #candidate-<candidateId> scrolls to that candidate's
row. A searched candidate's "Changes" link on the Insights
Candidates section opens it so,
unless picking it opened a pull request.
Candidate details
Selecting a candidate opens a side pane, which can be resized and closed. Its heading is the candidate's name, "On the frontier" for a frontier point, its reading when it has one, and its replay's state until that replay has finished. Under it:
- its agent's hypothesis: what the candidate should improve, and why;
- for the live config,
Station as configured when the search started.; for a candidate,Changed from live:with one phrase per change, as Config words them, orSame as the live config.; - "Searched", its score with its range and
of <n> runs scored, or "Not scored yet"; "Held out", its held-out score with its range, or as in the table; and "Cost per run"; - once it has them,
Gain over the live config, searchedandGain over the live config, held out, each its gain with its range, as in+12 pts (+3 to +21), its verdict, "Better", "Worse" or "within noise", and its side-by-side wins, losses and ties; - "Replay", linked to its replay on the searched tasks ("Replay of the set" for the live config), and "Held-out replay" when it has one;
- for a candidate, what picking it does: see Picking a candidate.
Success against cost
The card's note says what the frontier joins for the search's aim:
Success on the searched tasks and cost per run of each candidate. Frontier: candidates that no other candidate beats for less. The live config is always on the frontier. For the same success for less, the second sentence reads
Frontier: candidates that match the live config's success, within noise, and that no other candidate matches for less. Its header has a "Chart" and
"Table" switch, on "Chart" at first.
The chart draws each candidate with a search score whose searched replay has
finished, and the live config once it has a search score: its
search score up the side, its cost per run along the bottom. Points
on the frontier are joined by a dashed line, and the live config
is drawn as a diamond. The legend reads "On the frontier", "Other candidates"
and "Live config". Hovering over a point shows its name,
<share> succeeded · <cost> a run, and on the frontier for a frontier
point. The live config is always on the frontier, so its point reads
where it started · on the frontier.
When any frontier candidate is marked, a note above the
chart, shown on "Chart" only, reads <n> frontier candidates gained only on searched tasks, not on held-out tasks. ("candidate" for 1). With no priced point, the chart reads
No candidate has a priced score yet. Show the table to see the rest. Points
not priced are listed under the chart after Hidden, not priced:, each as its
name with its search score and range.
"Table" lists every candidate instead:
| Column | Shows |
|---|---|
| Candidate | Its name, or "Live config", frontier for a frontier point, and its reading when it has one. |
| Iteration | The iteration that proposed it, or – for the live config. |
| Searched | Its search score with its range, of <n> runs scored, counting replay runs, copies included, or "Not scored yet". |
| Gain on searched | Its gain over the live config on the searched tasks with its range and verdict, then its side-by-side wins, losses and ties there, or –. |
| Held out | Its held-out score with its range, "Replaying" while its held-out replay is queued or running, "Not held out" for a candidate that was not replayed there, or –. |
| Gain on held out | Its gain over the live config on the held-out tasks, once its held-out replay has finished, then its side-by-side wins, losses and ties there, else –. |
| Cost per run | What it spent per scored searched run, or "Unpriced". |
Search states
| State | Shown | Final |
|---|---|---|
seeding | Replaying the live config | no |
searching | Searching | no |
holding-out | Checking on held-out tasks | no |
finished | Finished | yes |
stopped | Stopped | yes |
A search starts seeding: the station's live config is replayed on every run
of the set, as many times as "Repeats" asks, and this replay becomes the set's
baseline. Once it finishes, the search is
searching, and wants its first iteration. Each iteration runs its agent once;
the agent proposes up to "Candidates per iteration" candidates, each replayed on
the searched runs. An iteration closes once its agent run has ended, its spend
is known, and its candidates' replays have ended. Then the next iteration
starts, unless the search has run its iterations, stalled, or
cannot afford one more. It then holds out: holding-out while the best candidates are
replayed on the held-out runs, then finished. A search with no candidate
whose replay finished goes straight to finished.
Search endings
| Ending | Shown | Pill | State |
|---|---|---|---|
iterations-spent | Ran every iteration it was given | None | finished |
ceiling-reached | Reached its ceiling | Hit its ceiling | finished |
stalled | Found nothing better twice in a row | Stalled | finished |
stopped | Stopped by a person | Stopped | stopped |
station-gone | Station is gone from the line | Station gone | stopped |
set-gone | Replay set was deleted | Set deleted | stopped |
seed-failed | Live config couldn't be replayed | Couldn't start | stopped |
The pill shows in the search page's header. Hovering over it, or over the search's state on the station page, shows the ending in words.
ceiling-reached also ends a search whose replay of the live config ran over
its ceiling. stalled ends a search that stalled with no room to
look into why, or whose reflection found nothing the config can fix. A stopped
search withdraws its agent's run
and stops its replays.
Iteration states
| State | Shown | Meaning |
|---|---|---|
wanted | Waiting for a runner | Its agent run is not yet queued, or no runner has taken it. |
running | Running | Its agent run is queued or running, and may propose candidates. |
ended | Ended | Its agent run ended. |
failed | Failed | Its agent run failed, asked a person, or could not start. |
Each iteration is of one kind: propose, whose agent proposes candidates, or
reflect, a reflection, whose agent proposes nothing and
records causes. A reflection counts toward "Iterations" like any other.
An agent run no runner takes within 60 minutes is withdrawn, and its iteration fails. An agent run whose spend is not known 15 minutes after it ended is counted as unpriced.
The search's agent run
Each iteration's agent run is a run of its own kind:
| Search agent run | |
|---|---|
| Task | Holds no task. |
| Placement | Where the station's runs go: the station's runners, else the line's. Its priority is below every task run and chat run. |
| Workspace | No repository is checked out, and no skills, settings files or team memories are laid out. |
| Briefing | The station's live config as the search started, the budget left, how many candidates it may propose, how many tasks are held out, what counts as better for the search's aim, what a candidate may change, and how to propose one. After a reflection that went on, also each config cause it recorded, with its task, evidence and suggestion. A reflection's briefing instead names the config whose failures it looks into, lists each failing task with its original run and the replay run that failed it, describes the five causes, and says how to record one. |
spotlight history | Only the searched station. The held-out tasks' runs are left out; the searched runs are always written. A candidates/ folder holds each candidate so far. See spotlight history. |
spotlight candidate | Proposes a candidate. Refused in a reflection. See spotlight candidate. |
spotlight cause | Records a task's cause, in a reflection only. See spotlight cause. |
| Refused | Messages from people, git, tools, spotlight reply, spotlight recall and spotlight remember. spotlight trace finds no held-out task. |
| Asking a person | Ends the run, and its iteration fails. |
Stalls
A propose iteration found something better when one of its candidates' replays on the searched tasks finished with a gain, paired task by task on the searched runs against the best config of the iterations before it, that the search's aim counts:
| Aim | Better than the best before |
|---|---|
| More success | Its gain reads "Better". |
| The same success for less | Its gain does not read "Worse", and it costs less per run, both costs known. |
The best before is the first in the order of the aim among the live config and the candidates of earlier iterations whose replays finished. An iteration whose agent run failed, or none of whose candidates' replays finished, found nothing better.
When an iteration closes, the search ends iterations-spent once it has run
every iteration. Otherwise, if its last two iterations were both propose
iterations that found nothing better, it has stalled:
- With at least 2 iterations left, and room under the ceiling for what it has spent, what the held-out replays need, one more iteration and one more agent run, its next iteration is a reflection.
- Otherwise it ends
stalled, and its starter gets a notice.
A reflection is not a propose iteration, so after one that went on, two more propose iterations must find nothing better before the search stalls again.
Reflections
A reflection looks into the failures of the best config so far: the first in the order of the search's aim among the live config and every candidate whose searched replay finished. It looks into each searched run of the set on which that config's success, the share of its scored copies that succeeded, is below one half and at least one copy failed. A held-out task is never among them. The first failed copy is the replay run it links to.
With no such task, the reflection ends at once, without an agent run, and the
search ends stalled. Otherwise its agent records one cause per
task with spotlight cause.
Recording a task's cause again replaces the one before. Once its agent run
ends, or fails:
| Recorded | The search |
|---|---|
At least one config cause | Wants a propose iteration, whose briefing lists the config causes, if it can afford one; else ends ceiling-reached, or iterations-spent with none left. |
No config cause | Ends stalled. |
Causes
cause | Title | Means | Shown to do |
|---|---|---|---|
task | The task itself | The task is unclear, out of date, or can't be done as asked. No config would get it right. | Fix the task, or take it out of the replay set. |
judge | The judge | The work can be fine, but the judge scored it wrong. The judge's rubric asks for the wrong thing. | Fix the judge's rubric. |
check | The check | The check failed for a reason that the change didn't cause, such as a broken or flaky test. | Fix the check. |
infra | Around the work | Something around the work failed the run, such as the runner, the network or a missing tool. | Replay it again. If it keeps failing, fix what the run needs. |
config | The station's config | A change to the station's config, such as prompt, model or skills, could still fix it. | You don't need to do anything. The search keeps trying configs for these tasks. |
Only config lets the search go on.
Reflection outcomes
outcome | When | Shown |
|---|---|---|
went-on | A config cause, and the search wanted a propose iteration. | The search continued. A config change can still fix some of these tasks. |
out-of-budget | A config cause, but the search could not afford a propose iteration or had none left. | The search ended with no budget left. A config change can still fix some of these tasks. |
no-config-cause | No config cause. | The search ended. No config change can fix the tasks that are left. The rest of the budget stays unspent. |
no-failures | No searched task failed. | The search ended. No searched task failed. |
did-not-run | Its agent run failed before it recorded any cause. | The search ended. The search agent's run failed before it recorded a cause. |
Notices
The person who started the search, or for a search started with a workspace token, the person who issued the token, gets an inbox notice linked to the search, "Open the search", while they are a member of the team's workspace:
| When | Form | Headline |
|---|---|---|
| A reflection ended the search | ended | By outcome: <search> ended with nothing the config can fix, <search> ended with every searched task passing, <search> ended after its reflection failed, or <search> ran out of budget. |
A reflection went on and recorded a cause other than config | advice | <search> goes on after finding failures outside the config |
| The search stalled with no room for a reflection | ended | <search> ended with no budget left to reflect |
<search> is The search for a better <station> config, or The search for a better station config when the station has no name to give. The first point
says what happened. After it, one point per cause other than config, as
<what to do>, for "<task title>": <suggestion>, or the evidence without a
suggestion: "Take the task out of the replay set, or reword it", "Fix the
judge's rubric", "Fix the station's check" or "Fix what the run needed around
the work". A task with no title reads "one of the searched tasks". A point is
cut at 1,000 characters; past 20 points, the last reads The search page shows <n> more. A reflection that went on with only config causes sends no
notice. Each reflection sends at most one.
Scores
| Score | Meaning |
|---|---|
| Search score | Its success on the searched tasks: per task, the share of its scored copies that succeeded, averaged over the tasks scored, with its 95% range. For the live config, from its replay's searched runs only. |
| Held-out score | Its success on the held-out tasks, worked out the same way, once its held-out replay has finished. For the live config, from its replay's held-out runs. |
| Cost per run | What its replay on the searched tasks spent per scored run, in the ceiling's currency. Unknown, "Unpriced", while any of that spend was not priced or was in another currency. |
Results and their reasons are a replay's: see Results.
Gains
Each candidate other than the live config reads its gain over the live
config's replay twice: on the searched tasks, and on the held-out tasks once
both its held-out replay and the live config's replay have finished. Each is
paired task by task, with its range and a verdict of "Better", "Worse" or "within
noise", as a replay's gain is, against the
line's min_gain. The frontier and the best candidate do not depend on it.
Side by side with the live config
Each candidate's replays, on the searched and on the held-out tasks, are
set side by side with the search's
replay of the live config once they finish, when the candidate has a judge.
Each reads Side by side with the search's starting config: <n> wins, <n> losses, <n> ties, counting the tasks of that replay, once any was compared. They never change its score, its
gain, the frontier or the best candidate.
Only on seen tasks
Once a candidate's held-out gain is known, a candidate whose searched gain reads "Better" gets a reading from it:
| Held-out gain | Shown | Note |
|---|---|---|
better | Nothing | |
within-noise or worse, over at least 5 tasks scored on both sides | "Only on seen tasks": the candidate is marked | This candidate beat the live config on searched tasks but not on held-out tasks. The gain may not carry over to new work. |
| Over fewer than 5 tasks scored on both sides | "Too few held-out tasks to tell" | This candidate beat the live config on searched tasks. Too few held-out tasks have a score to tell if the gain carries over. |
In the "Best" tile and the candidates table, the reading is a warning icon, amber when marked, named by the reading. In the candidate's details and the frontier table, a marked candidate shows an "Only on seen tasks" pill, and the other reading its words. Hovering over or focusing the reading opens its note. A candidate whose searched gain does not read "Better" has no reading, nor does one before its held-out gain is known, nor the live config. Only marked candidates are counted above the chart and warned about when picked. A marked candidate stays on the frontier, can still be the best candidate, and can still be picked.
Aims
A search aims for one of two things, chosen when it starts and kept for its life:
| Aim | objective | Ranks |
|---|---|---|
| More success | success | Every scored candidate, by score, then the cheaper. |
| The same success for less | cost | The live config, and the candidates whose gain over the live config reads "Better" or "within noise", by cost per run, then by score. A candidate whose gain reads "Worse", or is not known yet, is left out. |
Left unset, a search aims for the same success for less when the newest finished replay of the live config, as it is now, over every run of the set, other than a search's, succeeded on more than 95% of it, and for more success otherwise.
Frontier
The frontier is every candidate with a finished searched replay and a search score that no other candidate beats on both counts: succeeding at least as often for no more cost per run, and better on one. An unpriced cost counts as the highest. The live config is always on the frontier. When the search aims for the same success for less, only candidates whose gain on the searched tasks reads "Better" or "within noise" can be on it.
When a search stops searching, the frontier's candidates, the live config aside, are replayed on the held-out runs, as many as "Candidates per iteration", in the order of its aim. When it aims for the same success for less, only candidates that cost less per run than the live config are.
Best candidate
The candidate first in the order of the search's aim: by held-out score and held-out gain once any candidate has a held-out score, else by search score and searched gain. When it aims for more success, that is the one that succeeds most, then the cheaper; when it aims for the same success for less, the cheapest that holds its success, read "Cheapest". When the live config comes first, the best reads "Live config".
Spend and ceiling
A search's spend is what its replays and its agent's runs spent, in the ceiling's currency. A tenth of the ceiling is for the agent's runs; the rest gives each replay its own ceiling. A replay run whose cost was not reported or is in another currency counts as the full share a replay run is given, and an agent run whose spend is unpriced as the full share an agent run is given. A new iteration starts only while what was spent, what the held-out replays need and one more iteration fit under the ceiling. An agent run may go over its share, so a search can end a little over its ceiling.
A search's replays run up to "At once" at a time, apart from the team's own limit of 2 replay runs. See Limits and timeouts.
Picking a candidate
A candidate is picked from its details. It can be picked once its replay on the searched tasks has finished, while the search runs or after. The live config's details have no "Pick".
| State | Shown | Can change |
|---|---|---|
| not picked | "Pick", with Picking opens a pull request that changes the station to this config. A marked candidate also reads The gain showed only on searched tasks. You can still pick this candidate, but the gain may not carry over to new work. | "Pick" |
opening | Opening a pull request… | |
opened | "Pull request opened", linked to it | |
refused | "No pull request opened", the reason in words, Spotlight's message, and, for an attribute, At <attribute>, computed by <expression>. Please set it by hand to <value>, each part only when known | "Retry" |
While the pick is sent, the button reads "Picking…". "Retry" tries again,
reading the line's source afresh.
Until its replay on the searched tasks has finished, "Pick" cannot be selected, and the reason is beside it:
| Replay | Shown |
|---|---|
queued or running | After its replay on the searched tasks finishes, you can pick this candidate. |
stopped | You can't pick this candidate. Its replay stopped before it finished. |
over-budget | You can't pick this candidate. Its replay reached its ceiling before it finished. |
| Gone | You can't pick this candidate. Its replay is gone. |
The pull request
Spotlight reads the file named by the line's
source on the repository's
default branch, edits the station's block, commits to its own branch and opens
the pull request against the default branch.
| Value | |
|---|---|
| Branch | spotlight/search-<first 8 characters of the search id>-<candidate name> |
| Title | <station key>: <candidate name> |
| Commit message | The title, then Picked from a Spotlight search of the <station key> station. |
| Body | What the search found and what the candidate changes, then a paragraph on its held-out result when there is one to give, the agent's hypothesis, a table of its and the live config's success on the searched and held-out tasks, each with its range, and cost per run, a sentence for each gain, as in On the held-out tasks it gained +12 points (+3 to +21) on the live config, more than the 5-point gain the line counts as real., a sentence for its side-by-side wins, losses and ties on the searched and on the held-out tasks once any was compared, as in Set side by side with the live config's change on the searched tasks, without the judge knowing which was which, its change was better on 4 tasks, worse on 1 task and as good on 2 tasks., how many tasks it regressed on against the live config, any attribute Spotlight could not check, and a link to the search. |
The paragraph on the held-out result says one of:
| When | Says |
|---|---|
| The candidate has a held-out replay, and it or the live config's had not finished when the pull request opened | Its held-out replay had not finished when this pull request opened, so Spotlight could not yet check whether its gain also shows on the held-out tasks the search never showed its agent. |
| The candidate is marked | Its gain showed only on the tasks the search could see: +20 points on the searched tasks, but −3 points on the held-out tasks the search never showed its agent. It may fit the searched tasks rather than work better in general, so weigh that before merging. |
| It reads "Too few held-out tasks to tell" | It gained +20 points on the searched tasks, but only 3 held-out tasks scored on both sides, too few to tell whether the gain also shows on tasks the search never showed its agent. |
Any other candidate's body has no such paragraph.
The edit finds exactly one resource "spotlight_line" whose key is the
line's, written as a plain string, preferring the one whose team_id refers to
the team's spotlight_team, and in it exactly one station block whose key
is the station's. It changes only the attributes the candidate changes:
| Attribute written as | Edit |
|---|---|
| A plain value or heredoc | Replaced in place. |
file("${path.module}/<path>"), for prompt, description, harness, model, effort or profile | The new value is written to the station's own file beside the .tf file: prompts/<team>/<line>/<station>.md for prompt, the file the export writes, and prompts/<team>/<line>/<station>.<attribute>.md for the others. If the attribute was already read from that file, and nothing else reads it, the file is changed in place. Otherwise a new file is written, with -2, -3 and on added to its name when one is taken, and file() is pointed at it. |
A reference to a resource in the same file, as for profile, skills and tools | Followed to its value. A new value is written as a reference when a resource in the file holds it. |
| Not written | Added after the block's last attribute. |
| Anything else, such as a variable or a local | Refused, computed-attribute. |
Before it writes, the edit checks that every attribute the candidate may change,
the station's check and passes_to, and its judge block hold the values the
search started from, and refuses with drifted otherwise. An attribute it
cannot read and the candidate does not change is listed in the pull request
as not checked. An attribute read through file() with a path not built on
${path.module} cannot be followed, so changing it is refused with
computed-attribute. A file() path outside the repository is refused with
file-missing. The edited
file is read back, and refused with edit-failed if it does not parse or does
not hold the candidate's values.
GitHub refusing a request with a 4xx status, other than for a rate limit,
refuses the pull request at once with github-refused. An attempt that fails
for another reason, such as GitHub not answering or a rate limit, is tried
again after 30 seconds, 2 minutes, 8 minutes and 32 minutes, and then refused
with github-refused.
Config pull request reasons
| Code | Shown |
|---|---|
no-source | Line names no repository for its Terraform |
repository-unreachable | Spotlight's GitHub App can't reach the line's repository |
file-missing | Line's Terraform file isn't in its repository |
file-unparsable | Line's Terraform file couldn't be read |
block-not-found | Station's block isn't in the file |
blocks-ambiguous | Station's block appears more than once |
computed-attribute | Attribute is computed in Terraform. Please set it by hand. |
drifted | File changed since the search began |
edit-failed | Edited file wouldn't parse as Terraform. Please make the change by hand. |
branch-taken | Pull request branch already exists |
file-unwritable | File couldn't be written to its repository |
github-refused | GitHub refused the change |
Each comes with Spotlight's message, such as
Terraform computes `prompt` from `local.build_prompt`. Please change it by hand..
block-not-found also covers a station no longer on its line, and
file-missing a file a file() reads that the repository does not hold.
file-unwritable is a file that is a symbolic link in the repository.
branch-taken means the branch holds commits Spotlight did not write.
Guarding a station's changes
A replay set's page has a "Guards config changes" switch, at the bottom left
of its "Checks" panel. When it is on,
spotlight replay check
replays a planned change of the station on this set. A station has at most one
such set: turning it on while another set guards the station is refused. The switch cannot be changed once the set's station has left its
line. Turning it off leaves checks already started running.
The "Checks" panel's ⓘ reads spotlight replay check replays a pull request's change of this station on this set. One guarding set per station.,
then the line's
replay_check,
read-only: Fails past <n> regressions. Ceiling per check: <ceiling> · Minimum real gain: <min_gain>, or, for a line without one, Line sets no replay_check. Its pull requests aren't checked.
The panel lists the checks replayed on the set, as Change, Verdict,
Regressions and When. Change is the pull request (Pull request #<n>) or
commit (Commit <sha>) that planned the change, or "A planned change", with
attempt <n> from the second attempt on; the row opens the check's replay.
Verdict is the check's
verdict in words, such as
Undecided: replay reached its ceiling. With none, it reads "No checks yet"
and This set checks pull requests that change this station., or The set doesn't guard config changes. when the switch is off. "Show older checks"
loads more.
Search replays
A search's replays are replays of its set, and each replay page and replay run
reads as any other replay. A candidate's replay covers only the searched runs,
and a held-out replay only the held-out runs. The replay page's header, and
the Run page of each of its replay runs, read candidate <name> in its search,
or the live config it started from in its search, linked to the search.
While a search is under way, its set takes no runs, gives none up, and cannot
be deleted. The set's page disables "Add runs" and the X beside each run, with
A search of this set is running. Add or take out runs after the search ends or a person stops it. on hover, and "Delete", with A replay or search of this set is running. Please delete the set after it ends. on hover.