Change blueprint format to git and enable receiving blueprint updates - #659
Conversation
Started from my prompt: > I'd like to revise how blueprints work. > > 1. The current format is based on Yjs. This is vestigial, from when gadget code was stored in Yjs, but we now store it in git. A blueprint today ought to encode a git commit. The obvious format is a git packfile, plus some metadata(?). > 2. When someone has created a gadget from a blueprint, and then the blueprint later gets an update, people should have the option to update their gadget. If they've made their own changes to the code, they should be able to merge (with the agent resolving conflicts). > > Please outline how this might work, at a high level. Followed by additional discussion and rounds of feedback.
This is commit 1 of plans/git-blueprints.md.
This is commit 2 of plans/git-blueprints.md.
This is commit 3 of plans/git-blueprints.ts.
When we don't have a git object locally yet but we know it can be pulled from a particular gatekeeper, we record metadata saying so. The object may also be marked for inclusion in a push, still without being present, since it can be fetched lazily. When the object finally does arrive, we need to propagate this metadata to its children. E.g. when we fetch a tree object, we then want to mark all the files and subdirectories within it as being pullable from the same gatekeepers that the tree itself is marked pullable from. And if the tree was marked to be part of a push, its children should be too. This was all implemented with the git worktrees changes, but there was a bug: The propagation only occurred if the object was explicitly pulled, not when the object arrived by some other means. This commit ensures that propagation takes place regardless of how the object arrived. This is particularly important as objects can now arrive from instantiating blueprints. It would be an unusual situation for a blueprint to contain a tree that had previously been marked pullable from a gatekeeper and then marked to push to some other gatekeeper... but it's possible.
This is commit 4 of plans/git-blueprints.md.
This is commit 5 of plans/git-blueprints.md.
This is commit 6 of plans/git-blueprints.md.
This is commit 7 from plans/git-blueprints.md.
…onflicts. The agent is only run if there was something to merge. If the user never changed the code locally, we can just "fast-forward". This is commit 8 of plans/git-blueprints.md.
This is commit 9 of plans/git-blueprints.md.
This notifies you when an update to the upsteam blueprint is available and provides the UI to request an update (including switching blueprints). This is commit 10 of plans/git-blueprints.md
After you've chosen to apply the update, the UI shows the proposed changes, shows the agent tasked with managing the merge, and potentially blocks you from accepting if not all merge conflicts are resolved. This is commit 11 of plans/git-blueprints.md.
This is commit 12 of plans/git-blueprints.md. This completes the plan.
This scans the chat history to try to determine each gadget's starting blueprint from the `createGadget` tool calls that created them. The scan is bounded to avoid spending too much time for workspaces with long chat histories. From this we can only figure out which blueprint to use as the upstream, but not which version was used. So, we can't actually tell whether there's updates available. This just guides the UI better if the user tries to do a manual update.
In this case we can hide the "update" option in the UI since we know it can't possibly be useful.
We no longer offer a picker among all known blueprints. Instead, if you switch blueprints you must specify the new source blueprint using copy/paste.
It was a bit too technical before, talking about "merge conflicts". The wording is now simpler, but advanced details can be shown by clicking.
|
Review: 2 findings. Posted 2 actionable inline comments in a single review. |
0a739a1 to
5c09e58
Compare
Preview:
|
|
Review: 1 finding. Posted 1 new actionable inline comment in a single review. Existing findings were not duplicated. |
From my prompt: > This branch implements plans/git-blueprints.md. There's a problem, though, with the way merges are handled, which applies not just to blueprint updates but also "update from mainline" (pre-existing, before this branch). The changes being pulled from the blueprint / mainline are delivered as a "changes" message, meaning they need to be encoded as a pile of operational transforms. That requires performing a diff, which is done character-by-character and can take quite a while. It's also somewhat difficult for the agent to examine what changed. > > I think we should develop an alternative where the initial merge is actually committed, and the chat log only indicates that the pinned commit was updated to this new commit. The new commit, of course, does not become mainline until it is accepted (and if the user/agent mkaes further changes first, e.g. fixing conflicts, that creates another new commit on top of the merge commit, and that is what actually becomes mainline). > > Please read the code and develop a plan for this. Consider whether there might be overlap with the way worktrees work (they also have a notion of commits that aren't "accepeted" yet), but only combine concepts if it makes things simpler. Followed by a bit of discussion.
This is needed in order to compute blueprint exports later. Earlier in this branch we assumed that any merge was merging a blueprint release, but that will change soon. This is part 2, commit 1 of plans/git-blueprints.md
A "changes" message may introduce a merge, which replaces the code content of that gadget so far with a new commit (previous OTs are no longer relevant). This is commit 2 of plans/git-blueprints.md.
updateChatFromMainline() now creates a commit from the merged state and switches the chat's pinned commit for the gadget to it. The new commit does not land on mainline until the user clicks "accept" -- hopefully after fixing any conflicts. This is part 2, commit 3 from plans/git-blueprints.md
This was the main point of part 2: no longer generating a bunch of OTs when applying a blueprint update. This means we can get rid of the splitting of changes and the `messageCount` hack. This is part 2, commit 4 from plans/git-blueprints.md
We'll want this for the subsequent UI changes. This is commit 5 of plans/git-blueprints.md.
This is part 2, commit 6 of plans/git-blueprints.md
This is part 2, commit 7 of plans/git-blueprints.md.
This is part 2, commit 8 of plans/git-blueprints.md.
|
Added a second round to this ("part 2" in the plan doc) to fix the way merges are done -- both for blueprint updates and when merging changes in a chat back to the workspace's mainline. Previously we would encode the entire diff as OTs in a "changes" message, which could be very expensive to construct (it was a character-by-character diff) and required hacks to split it across multiple messages if the payload was too large for one row. Part 2 of the PR makes it so we instead just introduce the changes in the form of a new commit, which subsequent OTs are based off of. Much cleaner. I decided to add it to this PR rather than later because it allowed removing some complexity that had been added to the storage format earlier in the PR -- before anyone actually stored data in that format. |
|
LGTM! |
|
LGTM! |
Eval resultsVerdict: ⚪ Unchanged. No task moved beyond what 10 runs can tell apart from noise.
Failed checks
|
🔬 Eval runs reviewPerformanceAcross 10 runs per task, pass rates were calendar 80% → 100%, chess 90% → 90%, incident desk 90% → 100%, and worker logs 90% → 80%; comparison.json labels these changes unchanged, not beyond noise. Chess remained the largest expense, averaging about $0.053 → $0.066 and 59.6 → 68.4 model steps, with PGN implementation and exact-text editing retries driving detours; worker logs fell from about $0.023 → $0.019 and 26.7 → 20.4 steps, partly because two candidate runs stopped after turn 1. Cache hits stayed broadly similar, and chess’s significant reduction in cache breaks does not demonstrate fewer misses; the PR’s new merge-conflict guidance also prompted unnecessary conflict searches in freshly built gadgets. ⚪ VERDICT: NO REGRESSION FROM THIS PRNeither the candidate’s generated-code failures nor its cache and cost changes establish a beyond-noise regression caused by the blueprint-format or merge changes. TriageFailure modes
Tool errors
Prompt cache
What to do
|
|
🤖 comment ( feel free to refute! )
|
This is all stuff every model already knows, and we already inform the agent in context when merge conflicts actually exist.
|
@Maximo-Guk Known pre-existing issue: OTs don't detect when a name has been created both as a file and a directory; an error is raised only when you try to commit. Worth fixing eventually but not in this PR I think. |
|
Review: 1 finding. Posted 1 new actionable inline comment in a single review. Existing findings were not duplicated. |
A blueprint now encodes a git packfile instead of a Yjs snapshot.
When you update a blueprint, people who have created gadgets from the old blueprint are now given the option to update it. For now, this does not happen automatically -- you just see a dot on the blueprints button and from there can choose to update. (We can consider implementing auto-update later perhaps.)
If local changes have been made since the blueprint was first instantiated, an agent is spawned to review the merge and fix any conflicts.
You can also choose to switch blueprints when updating. This allows you to e.g. switch from an original blueprint to some other user's customized version of it.
Update dialog:
Agent fixing merge conflicts: