mirror of
https://github.com/storytold/craft-anything.git
synced 2026-11-05 20:47:45 +01:00
Merge branch 'main' into bugfix/721-stale-agent-path
This commit is contained in:
@@ -356,7 +356,8 @@ impl AgentLoop {
|
||||
if self.system.is_none() {
|
||||
self.emit(AgentEvent::Status { text: "Reading the investigation so far…".into() });
|
||||
let inv = self.host.investigation();
|
||||
self.system = Some(prompt::system_prompt(self.cfg.beginner, self.host.clean_room(), &inv));
|
||||
let memory = !(self.cfg.lean_for_local && self.chain.get(self.current).is_some_and(|s| s.local));
|
||||
self.system = Some(prompt::system_prompt(self.cfg.beginner, self.host.clean_room(), &inv, memory));
|
||||
}
|
||||
if let Some(text) = text {
|
||||
context::push_user_text(&mut self.history, text);
|
||||
|
||||
+23
-7
@@ -14,8 +14,10 @@ How to work:
|
||||
- Keep three lists apart in your answers: what was observed, what you infer, and what is still unknown.
|
||||
- Static analysis never shows that code actually ran. Only tools that run the target can show that, and they ask the user first.
|
||||
- Never repeat an identical call that already failed or already answered.
|
||||
- If a tool you need isn't in your list, call list_toolsets, then enable_toolset.
|
||||
- If a tool you need isn't in your list, call list_toolsets, then enable_toolset.";
|
||||
|
||||
/// The memory loop, for a model that has the Core tools it names (a lean local builder doesn't).
|
||||
const MEMORY: &str = "\
|
||||
Working memory (the investigation files):
|
||||
1. The current brief, plan, hypotheses, findings and handoff are below. Read them before acting; if a handoff exists, resume from it instead of starting over.
|
||||
2. On a new question, call core_brief_write and core_plan_update before any analysis tool.
|
||||
@@ -30,21 +32,24 @@ const EXPERIENCED: &str = "\
|
||||
The user is experienced. Be terse and precise: addresses, symbol names, evidence ids, no hand-holding.";
|
||||
|
||||
/// Build the system prompt. `investigation` is the JSON of `core_investigation_show` at conversation
|
||||
/// start (part of the stable, cached prefix).
|
||||
pub fn system_prompt(beginner: bool, clean_room: bool, investigation: &str) -> String {
|
||||
/// start (part of the stable, cached prefix). `memory` is false when the model isn't offered the
|
||||
/// memory tools: told to call `core_brief_write` first, a small model asks for it and does nothing
|
||||
/// else (#417).
|
||||
pub fn system_prompt(beginner: bool, clean_room: bool, investigation: &str, memory: bool) -> String {
|
||||
let mode = if clean_room {
|
||||
"Analysis mode: Clean room. Nothing inside a target is looked at (its code, files or page source): only the tools that work from outside run, and the rest are refused. If the question needs a look inside, say so: the person can switch on Deep mode."
|
||||
} else {
|
||||
"Analysis mode: Deep. Use every tool that helps: our own engines read a target's code, files and pages, and Ghidra adds its decompiler when it's installed. Evidence records which engine produced it."
|
||||
};
|
||||
format!("{METHOD}\n\n{}\n\n{mode}\n\n## Investigation so far\n{investigation}\n", if beginner { BEGINNER } else { EXPERIENCED })
|
||||
let memory = if memory { format!("\n\n{MEMORY}") } else { String::new() };
|
||||
format!("{METHOD}{memory}\n\n{}\n\n{mode}\n\n## Investigation so far\n{investigation}\n", if beginner { BEGINNER } else { EXPERIENCED })
|
||||
}
|
||||
|
||||
/// Preamble for an agent CLI, which brings its own system prompt: we add our method and memory
|
||||
/// loop, and point it at our MCP tools.
|
||||
pub fn cli_preamble(beginner: bool) -> String {
|
||||
format!(
|
||||
"{METHOD}\n\n{}\n\nUse the craft-anything MCP tools for all analysis (start with core_session_show, core_targets_list and core_investigation_show). The MCP server shares this investigation with the app; use its open targets and recorded findings rather than inventing ids or maintaining a separate findings file.\n\n## Request\n",
|
||||
"{METHOD}\n\n{MEMORY}\n\n{}\n\nUse the craft-anything MCP tools for all analysis (start with core_session_show, core_targets_list and core_investigation_show). The MCP server shares this investigation with the app; use its open targets and recorded findings rather than inventing ids or maintaining a separate findings file.\n\n## Request\n",
|
||||
if beginner { BEGINNER } else { EXPERIENCED }
|
||||
)
|
||||
}
|
||||
@@ -61,11 +66,22 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn prompt_switches_mode_and_effort() {
|
||||
let b = system_prompt(true, true, "{}");
|
||||
let b = system_prompt(true, true, "{}", true);
|
||||
assert!(b.contains("plain, everyday words") && b.contains("Clean room") && b.contains("core_handoff_write"));
|
||||
let e = system_prompt(false, false, "{\"brief\":null}");
|
||||
let e = system_prompt(false, false, "{\"brief\":null}", true);
|
||||
assert!(e.contains("terse") && e.contains("Deep") && e.contains("{\"brief\":null}"));
|
||||
assert_eq!(choose_effort(None), Effort::High, "high by default, even for a quick question");
|
||||
assert_eq!(choose_effort(Some(Effort::Medium)), Effort::Medium, "an explicit setting wins");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_prompt_without_memory_tools_names_none_of_them() {
|
||||
let lean = system_prompt(false, true, "{}", false);
|
||||
for tool in ["core_brief_write", "core_plan_update", "core_handoff_write", "core_finding_record"] {
|
||||
assert!(!lean.contains(tool), "{tool} isn't offered, so it isn't asked for");
|
||||
}
|
||||
assert!(lean.contains("Cite evidence ids") && lean.contains("Clean room"), "the method stays");
|
||||
let cli = cli_preamble(false);
|
||||
assert!(cli.contains("core_brief_write") && cli.contains("core_handoff_write"), "agent apps get the memory loop");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +505,8 @@ fn pictures_of_the_original_go_with_the_draft_then_into_the_project() {
|
||||
// "Nothing — start fresh" is picked: the request box offers pictures (not for websites).
|
||||
h.get_by_label("Add pictures of the original (optional: screenshots help it look right)");
|
||||
h.state_mut().add_pictures(vec![pic.clone(), notes, pic.clone()]);
|
||||
h.run_steps(3);
|
||||
// Their sizes are checked on a worker first (#720).
|
||||
assert!(wait(&mut h, |a| !a.state.make.pictures.is_empty()), "checked on a worker, then added");
|
||||
assert_eq!(h.state().state.make.pictures, vec![pic.clone()], "pictures only, once each");
|
||||
h.get_by_label("original.webp");
|
||||
h.get_by_label("Remove original.webp").click();
|
||||
@@ -1236,7 +1237,9 @@ fn claude_codes_account_folder_is_set_in_settings() {
|
||||
// Emptied, it's the usual folder again.
|
||||
h.state_mut().set_agent_folder("Claude Code", Some(String::new()));
|
||||
assert!(wait(&mut h, |a| chosen(a).is_none()));
|
||||
// Added already, so it's offered again under the next free name.
|
||||
// Added already, so it's offered again under the next free name, on the coding agents' tab.
|
||||
h.state_mut().state.detect_tab = Some(craft_anything_ui_egui::detect_tabs::DetectTab::Harnesses);
|
||||
h.run_steps(2);
|
||||
h.get_by_label("Add another").click();
|
||||
assert!(wait(&mut h, |a| a.backends.iter().any(|b| b.name == "Claude Code 2" && b.model == "claude-code")));
|
||||
}
|
||||
|
||||
+42
-17
@@ -97,17 +97,19 @@ Owner: maintainers · Status: todo
|
||||
Two reported failures, the Windows start-up crash (#414) and a builder resuming another's
|
||||
session (#471), are fixed on `main` and still broken for everyone on 0.3.0. This is the
|
||||
cheapest help we can give anyone, so nothing below should hold it up for long.
|
||||
- [ ] #490 has changes requested: a JSON object given to `--left` or `--right` becomes text, and
|
||||
its new test passes without the fix. Merge it once that's fixed, or decline it; it doesn't
|
||||
hold up the release. What it reports is 0.2.0's, fixed by #93 (`f6725c2`): on Windows the
|
||||
- [x] #490 merged (`549ae5e`) with the CLI fix the review asked for: a string-or-object input is
|
||||
`any`, so a JSON object given to `--left` stays an object (tested both ways). What it reports
|
||||
is 0.2.0's, fixed by #93 (`f6725c2`): on Windows the
|
||||
published 0.3.0 CLI with Claude Code 2.1.179 mounted 314 of 315 tools (the 315th is the
|
||||
approval tool, which Claude Code doesn't list but calls), and a real Deep build reached Ready
|
||||
with `core_action_approve` answering five prompts. The reporter was asked for `--version`.
|
||||
macOS is still owed (R5.7)
|
||||
- [ ] Cut the next release (`docs/releasing.md`). 0.3.0 lacks `0748ef1` (#414: Windows starts DX12
|
||||
only, the crash behind "it won't open"), `1e8f661` (#471: a builder never continues another
|
||||
builder's session) and `3357daf` (#430: Claude Code's message on stdin). Take #357 (R5.2) too
|
||||
if it's ready
|
||||
- [ ] Cut the next release (`docs/releasing.md`). The version is 0.4.0 (#526) and `main` at
|
||||
`fb7ac86` is green, but pushing `release` is refused: its ruleset blocks every update and
|
||||
lists no one who may bypass it. A maintainer who can push it (or adds a bypass) goes next.
|
||||
0.3.0 lacks `0748ef1` (#414: Windows starts DX12 only, the crash behind "it won't open"),
|
||||
`1e8f661` (#471: a builder never continues another builder's session) and `3357daf` (#430:
|
||||
Claude Code's message on stdin)
|
||||
- [ ] See that the launcher offers the new version: #74, #104 and #420 installed through it, and
|
||||
nothing in this repository says how it picks one
|
||||
- [ ] After it ships, close what it fixes: #166, #346, #420, #478. #74, #104 and #222 give no
|
||||
@@ -155,11 +157,10 @@ only when it's green and a maintainer has fully reviewed it, code as well as wor
|
||||
fails on a Mac for that. `real_binary_end_to_end_if_present` fails there too, expecting
|
||||
`/bin/ls` to be Linux: both fixed (#357)
|
||||
- [ ] **decision** First-time contributors' CI: GitHub holds their runs for approval, so their PRs
|
||||
show no `gate` run (#490 and #413 among them, and #413 holds up #455). Approve each push, or
|
||||
show no `gate` run (#490 and #413 were among them). Approve each push, or
|
||||
change the repository's approval setting
|
||||
- [ ] Merge order the PR list doesn't show: #413 before #455; #193 before #482 and #486 (all change
|
||||
the language list); #491 before #492 (same file). #433 and #468 look redundant with #421 and
|
||||
#500: ask their authors
|
||||
- [ ] #193 changes the language list that #486 (merged) changed too: it needs a rebase. #468 looks
|
||||
redundant with #500: ask its author
|
||||
- [ ] **decision** Wide PRs with no roadmap line: #416 (project goals, 34 files, cites an R2.11 that
|
||||
doesn't exist; that id stays free for it) and #503 (two asset providers and spending controls,
|
||||
37 files, cites the finished R1.4). Decide whether we want them before more is built on them
|
||||
@@ -211,23 +212,44 @@ Every round spends the person's money or quota. One that can't do anything shoul
|
||||
9.4M tokens in 19 minutes of the first stage, never compiled). Try again carries on
|
||||
- [ ] **decision** Whether a build gets a token or cost limit of its own, beyond rounds and that
|
||||
stop (#399): a model that changes code without ever running a build isn't caught by it
|
||||
- [ ] Check live that the stop fires on a real API-backend build and the message reads well
|
||||
- [ ] Check live that the stop fires on a real API-backend build and the message reads well. It
|
||||
fired on a local Ollama build (the same built-in loop) after two turns that changed nothing
|
||||
in `app/` ("The build stopped after two builder turns changed no files in app/…"); an
|
||||
API-key build is still owed
|
||||
|
||||
### R5.4 Local models can build
|
||||
Owner: open · Status: todo
|
||||
The built-in agent loop assumes a capable tool-calling model. Reports #24, #44, #110, #403, #417 and
|
||||
#498 say otherwise (#44's backend is a guess; #116 may be the same), and no local model build has
|
||||
been run live.
|
||||
- [ ] A live local build through Ollama, small target, to Ready or to a clear stop, and note in
|
||||
STATUS.md which models it worked with. Do this first: it shows which of the lines below matter
|
||||
- [x] A live local build through Ollama, small target, to Ready or to a clear stop, and note in
|
||||
STATUS.md which models it worked with: Ollama 0.40.7 with `qwen2.5-coder:14b` on Windows
|
||||
(RTX 5090, 32k context, no prompt cut) stops clearly at "No project to build found in app/
|
||||
yet", twice. The lines below say why
|
||||
- [x] A builder on a local model is offered 13 tools (about 10,000 characters of descriptions)
|
||||
instead of 33-41 (23,000-30,000): the Build tools and the Core tools the brief names, not the
|
||||
study set a model explores with instead of writing (#417, `LOCAL_BUILDER_CORE`). Measured as
|
||||
text, not on a model; Ollama's default context (4k) was too small for the old list alone
|
||||
- [ ] Run #417's case live (Ollama, `qwen2.5-coder:14b`, "a scientific calculator") before and
|
||||
after this: does it call `build_file_write` now? If it still doesn't, the model can't build
|
||||
- [ ] An assistant turn with no text sends `content: null` (`openai.rs`), which likely causes #403's
|
||||
`invalid message content type: <nil>`: send an empty string
|
||||
after this: does it call `build_file_write` now? If it still doesn't, the model can't build.
|
||||
Run so far: with the lean list it calls `build_checklist`, `build_command_run` and
|
||||
`build_file_edit` (as JSON text, which #554 runs), but not `build_file_write` yet; the two
|
||||
lines below stop it first
|
||||
- [x] The system prompt told every model to call `core_brief_write` and `core_plan_update` first and
|
||||
`core_handoff_write` last, tools a lean local builder isn't offered, so the model asked only
|
||||
for `core_brief_write` and did nothing else for three checks. A lean builder's prompt leaves
|
||||
the memory steps out; live, the same model then used the Build tools
|
||||
- [ ] A call written after a sentence ("Let's list the files.\n```json {…}```") isn't run: #554
|
||||
reads a reply that is only the JSON. Half the model's calls came this way and the turn ended
|
||||
with nothing done. Run a reply that ends in one fenced call to an offered tool, and say in
|
||||
the transcript that it was read from text
|
||||
- [ ] The model ran `cargo new app` in `app/` (commands run there), so the project landed in
|
||||
`app/app/` and every check said "No project to build found in app/ yet". Say in that check
|
||||
where a project was found one folder down, and have the Rust brief say `cargo init`
|
||||
- [ ] `usage.json` after a local build says about 4,200 input tokens and 6.5 s of work, while
|
||||
Ollama logged about six requests of 4,000-5,000 tokens each: find what it leaves out
|
||||
- [x] An assistant turn with no text sends an empty string, not `content: null`, which Ollama
|
||||
refused as `invalid message content type: <nil>` (#403, #536)
|
||||
- [x] Understand a tool call a model writes as JSON in its text (#417; implementation `dfe9a4db2dcb3e27edbd67311cbb4202584e7af6`). The fallback protocol reads
|
||||
only `Action:` and `Action Input:` lines, so anything else ends the turn with nothing done
|
||||
- [x] Preserve `length` and `content_filter` stop reasons on native tool-call streams; a parsed
|
||||
@@ -253,6 +275,9 @@ been run live.
|
||||
|
||||
### R5.5 API-key builds fail in words people can use
|
||||
Owner: open · Status: todo
|
||||
- [ ] `rebuild --backend <an API backend>` still adds the first agent app it finds to the person's
|
||||
settings and prints "Using Claude Code (…)": `ensure_agent` (`rebuild_cmd.rs`) runs whenever no
|
||||
agent app is set up, though this run won't use one. Run it only when the build needs one
|
||||
- [x] Bound accumulated data across all lines of one server-sent event, so short lines cannot
|
||||
grow a streamed API response without limit
|
||||
— claimed: Afloat16, branch bugfix/r5.5-bounded-sse-events-20261103
|
||||
|
||||
@@ -29,6 +29,7 @@ workspace clippy, layers, fmt and the secret scan of all history were clean. Chi
|
||||
| Electron window comparisons | `app_graphs_compare` retains every unassigned window and every construction with a reused local binding. Windows are paired by module, binding and occurrence, so inserting comments does not hide preference changes. Colliding display labels receive a separate `#N` suffix without changing literal binding names or occurrence indices | Synthetic applications parsed through the ordinary analyzer exercise anonymous and reused bindings, shifted source lines, unequal counts, literal names resembling occurrence or collision suffixes, and stable labels when only one window changes. Pairing remains positional within each binding group; reordered constructions and real application releases were not checked for this correction |
|
||||
| Rebuild workflow (Study → Build → Check → Refine) | `crates/ai/src/rebuild/` (kinds, checks and stacks are pluggable: docs/extending.md). Three kinds: website, app, game (a project whose stack is a game engine is always a game). The request decides how to build: a language, framework, engine or platform it names wins over the kind's default stack (Rust + egui for apps, Unity for games, the original's for websites), and the build check, the recorded stack and Play follow what was built (an Electron app opens in its own Electron; a plain static site has nothing to build and passes the build check as it is). Websites: Study also captures up to 4 other pages of the site; menus are opened on a computer and on a phone; the check serves the build on loopback and compares every page at 1440, 768 and 390 px (likeness = mean of layout and perceptual detail, SSIM, averaged over pages, leaving out the parts of the original that change by themselves, found by photographing it three times; the note adds text, page structure, the colours, font, text sizes and spacing the build misses, and per width a page that scrolls sideways, heading sizes and sections whose padding, items per row or content column differ, the errors, failed requests and accessibility gaps the build adds, and the opened menus and pop-ups). A stack or library named in the request (Next.js, shadcn/ui, Tailwind CSS…, `stacks.toml`) is what the builder uses; with none named, a website's stack is the builder's choice (told to match what the original is built with) and the stack it used is recorded from app/package.json. The builder leads: it studies, asks the tools follow-up questions, records what it can't find out as unknowns (`core_unknown_add`; the run reports the open ones), and tests its own build mid-turn with `rebuild_check` (the same checks, for every kind); a check with anything it couldn't compare, or any claim that fails (a website page that scrolls sideways, logs new errors, fails to load a file, lacks a landmark, or a menu that doesn't open; for games each self-test step, for Deep-mode sheets each original number in the code, for console apps the same exit and output as the original's runs), isn't good enough; apps and games by whether they build. Up to 6 refinement rounds, or until a website reaches 90% likeness. A turn cut off by a time limit, crash or dropped connection resumes (up to 3 times); builder turns may run 24 h. A project copied from another computer (or moved to another folder) keeps building with Claude Code: the project keeps a copy of the builder's session (`agent-session.jsonl`) after every turn and puts it back where Claude Code finds it on a computer without it, so the same conversation carries on (#451); when the session still isn't there, a new one starts from the brief, what's in app/ and the kept requests and replies (or the last summary), and questions about the build put the kept session back too, else are answered from the files and forget the missing session (#452). Live runs with Claude Code 2.1.316 on one Mac (2026-11-02), a second computer stood in for by a separate signed-in `CLAUDE_CONFIG_DIR`: a copied project's session was put back and resumed (the builder recalled its first reply from memory); a kept copy of another session was refused and the new session used the handoff; a real project synced from Windows whose session was missing started afresh and reached Ready. Not yet run between two real computers | Unit tests for prompts, stack choice, site detection, feed folding; live runs reached Build and decompiling (below) |
|
||||
| Context-summary usage | Successful API context summaries contribute to the message totals consumed by build usage and receive a `model_turn` journal entry with `purpose: context_summary`. Cached-token pricing is retained; an unknown summary price makes the total unknown, and a failed call adds no invented usage | Scripted-model tests exercise the real `ApiConversation`, transcript resumption, exact input/output and cache-price totals, journal entries, empty summaries, local zero cost, unknown prices and failed summaries. No live provider or end-to-end rebuild was used for this correction |
|
||||
| Local model builds | Not yet: Ollama 0.40.7 with `qwen2.5-coder:14b` (32k context) studies, plans and runs Build tools, written as JSON text, but its project lands one folder down (`app/app/`) and calls after a sentence aren't run, so it stops at "No project to build found in app/ yet" (R5.4). A lean local builder's prompt no longer asks for memory tools it isn't offered | Two live CLI builds of "a scientific calculator" on Windows (RTX 5090), 2026-11-04 |
|
||||
| Backend context budgets | `context_tokens` in `[[ai.backends]]` controls when an API conversation is trimmed and summarised. Zero or omission retains local/cloud defaults; a nonzero conversation override takes priority. Before each attempt, including a fallback, fitting adds estimated history growth since the last successful request to its reported input size. Trimming resets that reference, and successful requests refresh it; summary usage remains in message totals | Regressions cover settings and model construction, defaults/overrides, smaller fallback budgets, large-budget arithmetic and new tool output growing beyond a fallback budget even when the history estimate alone is below the reported input. The latest tool results are preserved, and a short follow-up does not count already-sent history twice. This does not set server context parameters or guarantee that a complete request fits; no live provider was used |
|
||||
| Games | Engine detection for 12 engines (Unreal, Unity, Godot, Source, GameMaker, RPG Maker, Ren'Py, MonoGame, LÖVE, CryEngine, Cocos, Cube) with versions. Unreal and Godot games are rebuilt in the same engine, others in Unity; installed engines are found, Godot installs itself, others get guided installs. Picking an inner folder (Engine, Binaries, Paks…) finds the game's folder. Just look inside a game shows what it's made of (`core_target_triage` on its folder: engine and version, how its code ships, the libraries its Unity assembly names give away, its own code, scenes and size) and opens it in the chat to ask about it. The builder keeps `app/MECHANICS.md` and its structured twin `app/mechanics.json` (checked after each build), in Deep mode only, may reuse the original's readable files for private use (never decrypting; generated pictures and 3D models replace its art when the person turns them on; Clean room copies none of its files), lists them in `CREDITS.md` (checked, with the private-use line in `README.md`); a game is ready only when its `--self-test` shows the player moving, acting and the HUD drawn, and the result can be started from the project page | Unit tests; live runs on Windows |
|
||||
| Clean room and Deep mode | Clean room (the default) runs only the tools in `engine/src/clean_room.rs`: ones that touch no target or watch from outside (the website as a visitor sees it, pictures of a window, its controls, recorded runs, a phone's screen). Every other tool, a plugin's included, is refused in the app, CLI, MCP and agents, with a way to turn on Deep mode. A Clean room build studies an app or a game only from the person's pictures and words (and a picture of its window when runtime study is on); its builder's reads and commands go through an approval rule that keeps it out of the original's folder and site (with Claude Code, and with ACP agents for what they ask about; other agents aren't held to it, see roadmap R2.2). Deep mode (`deep_mode` in Settings, `--deep` for one CLI run) uses every tool: the builder sees them all, and a website's study also reads its JavaScript and watches its start page for ten seconds (capture/how-it-works.md). Ghidra adds its decompiler in Deep mode when it's installed: it is found, or installed after asking. Study starts one analysis of the main program, saved and shared with the builder's tool server through a lock file (up to 8 h, Java gets half the machine's memory or the amount set in Settings → Engines, 4 to 31 GB, four slow passes skipped). The builder must decompile before the build is checked; addresses the built-in analysis can't place go to Ghidra, which makes a function on demand (for this run only) where its analysis has none, e.g. code reached only through tables of pointers. Without Ghidra, Deep mode uses the built-in engines | Live runs with Ghidra 12.1.4 on Windows (a shared analysis, and a decompile in seconds on a large program). Live runs with Ghidra 12.2 on Linux x86-64 (decompiles by name in position-independent programs and shared libraries, whose addresses Ghidra moves). The guided install of Ghidra and its Java is offered on Linux and macOS too, but has only been tried on Windows. Clean room and Deep mode: engine, AI, MCP, CLI and app tests; no live Clean room build run yet |
|
||||
|
||||
@@ -45,6 +45,9 @@ added an app the new rule rejected; both were green on their own branch.
|
||||
And again with a new catalog: #555 added "Pausing…" to every catalog there was, and #486 (Russian)
|
||||
merged after it without it. A new language and a new UI string merged together need the string
|
||||
in the new catalog too.
|
||||
And with a layout change: #687 moved coding agents onto their own tab of what Detect found, and
|
||||
#664, merged next, tested a button on that list without picking the tab. Checking that two PRs
|
||||
merge cleanly isn't checking that their tests pass together: run the UI tests on the merge.
|
||||
|
||||
**A dependency change merged without its lockfile.** Changes were staged with
|
||||
`git add -A crates apps docs`, which leaves out the root `Cargo.lock`, so a new dependency reached
|
||||
@@ -100,6 +103,11 @@ same temp directory, and game detection walked up and found the game. Give each
|
||||
For a refactor that must keep output identical, dump the outputs for every combination before and
|
||||
after and compare them byte for byte (done for every brief across 162 combinations in R1.1).
|
||||
|
||||
**A step moved to a worker, its test still counting frames.** #720 moved the picture size check
|
||||
off the UI thread; a UI test that added pictures, ran three frames and then looked kept passing on
|
||||
fast machines and failed in CI on unrelated PRs. When work moves to a worker, grep the tests that
|
||||
call it and make them `wait` for the result, not `run_steps(n)`.
|
||||
|
||||
## Building and running
|
||||
|
||||
**A model catalogue queried in the wrong project.** OpenCode V2's raw `api get /api/model` does
|
||||
|
||||
Reference in New Issue
Block a user