Repository navigation
chore(release): bump server to v0.0.98 for clean R2 publish - #1128
Conversation
|
Greptile (@greptileai) review |
|
Claude (@claude) review |
|
Claude finished Nikhil (@shadowfax92)'s task in 57s —— View job Code Review
LGTM — this is a clean, minimal version bump with a solid rationale. What was reviewed
FindingsNo issues. The change is correct and complete:
One note worth keeping in mindThe test plan has one open checkbox:
|
Greptile SummaryBumps
Confidence Score: 5/5Safe to merge — only two lines change and both are in lockstep. The entire change is a single version string updated in package.json and the corresponding bun.lock entry. A workspace-wide grep confirms no 0.0.97 references remain, the lockfile is internally consistent, and the PR description explains the release-pipeline contract clearly. There is nothing functional at risk. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["nightly-macos-build.yml\nreads version from package.json"] --> B["release-server.yml\nreads & validates version"]
B --> C{"version matches?"}
C -- yes --> D["scripts/build/server/config.ts\nderives R2 object keys"]
C -- no --> E["Build FAILS"]
D --> F["R2: artifacts/server/latest/…\n(always overwritten)"]
D --> G["R2: artifacts/server/0.0.98/…\n(new versioned key)"]
Reviews (1): Last reviewed commit: "fix: sync bun.lock to server v0.0.98 (lo..." | Re-trigger Greptile |
Greptile SummaryBumps
Confidence Score: 5/5Safe to merge — the change is a minimal, self-contained version bump with no logic changes. Both changed files touch only the version string. The lockfile entry is consistent with package.json, no stale 0.0.97 references remain in the workspace, and the pipeline's version-agreement check will enforce correctness at release time. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[nightly-macos-build.yml\nreads package.json version] --> B{version == 0.0.98?}
B -- yes --> C[release-server.yml\nreads package.json again]
C --> D{versions agree?}
D -- yes --> E[Build artifacts]
E --> F[Upload to R2:\nartifacts/server/latest/…]
E --> G[Upload to R2:\nartifacts/server/0.0.98/…\nnew key – no overwrite]
D -- no --> H[Build fails]
B -- no --> H
Reviews (2): Last reviewed commit: "fix: sync bun.lock to server v0.0.98 (lo..." | Re-trigger Greptile |
✅ Tests passed — 1004/1010
|
The branch recorded whose a change was; it never stopped two bees, or a bee and the build, from writing the same bytes. make check failed with 'cannot find result in scope' on a snapshot of a file bee browseros-ai#1128 was halfway through writing, and the same file compiled seconds later. Nothing was wrong with either side. The variant split (browseros-ai#1276) fixed the state collision; this is the source one, and it became routine the day the Queen started picking up work unprompted. git worktree add -B cuts the branch as it makes the checkout, so the branch and the edits cannot end up in different places. The worker's workingDirectory and its standing orders both name that path. createVirtualBranch is now only reached when a worktree could not be made - the pre-worktree behaviour, kept on purpose: a bee that cannot get a directory should still work, just without isolation. The same change closes the stale-base defect. createVirtualBranch treats 'the branch already exists' as success so a resumed task does not fail, and that adopted queen/1127 from a run 140 commits earlier: its diff against the tip read as 641 insertions against 12,508 deletions - the Makefile, the night log, every fixture - while the bee's own change was 34 lines. A diff is not a merge, but QueenBranchCommitter assembles by overlay, and an overlay onto a base that old drops everything newer. A branch cut before HEAD is now refused by name and sidestepped with a suffix. Never deleted: a leftover may hold the only copy of somebody's work, and this code cannot know. Cleanup is a sweep, not a hook on each terminal transition. There are six places a task can settle and a cleanup wired to five leaves directories on disk in exactly the case nobody tested. Removal is guarded by isOwnedWorktree, because this hands a path to git worktree remove and the shape of that mistake is deleting the checkout somebody is sitting in. Driven live: autonomy.tick -> chose browseros-ai#1127 -> approved -> delegated -> 'Not reusing queen/1127: the branch was cut before the current HEAD (c9d5926). Cutting queen/1127-r1' -> checkout created at .worktrees/queen-1127 on queen/1127-r1 at the current tip. Three minutes of bee work later the shared tree's status hash was byte-identical. Also carries bee browseros-ai#1128's interface-divergence watchdog in ChatViewModel - her work, inside her boundary, interleaved with mine in one file and not separable by git. Named here rather than silently absorbed. 757 e2e checks, +18: when a leftover branch may be adopted, and which paths may be handed to git worktree remove. Closes browseros-ai#1277 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…does Bee browseros-ai#1128's interface-divergence watchdog ran before the contract, with a stated reason: criteria are judged inside a tree, and a tree that does not compile is no place to judge them. True of criteria. Not true of the contract's own refusals - "the reviewer was asked and gave no answer" is a fact about the reviewer, established without any tree at all. Running the watchdog first replaced that answer with "does not build together" and lost the distinction browseros-ai#1117 exists to keep: asked-and-silent is not never-checked. Both requirements are right; only the order was wrong. Refusals that need no tree now come first, and the watchdog guards the case where the contract is satisfied and something is about to land. Two smaller ones from the same live run: - releaseWorktree refused a path recorded before worktrees were scoped by variant, and would have refused it on every sweep forever. A path that does not exist is now simply forgotten. - the e2e script's worktree cleanup sat after the run under `set -e`, so a failing suite skipped it - which is exactly when leftover checkouts are most likely. 760 e2e checks, 0 checkouts left behind.
…finishes Three tasks sat in awaitingReview for fourteen hours. The sweep that asks the reviewer about parked tasks lived inside handleWorkerFinished, so it was reachable only when a worker finished - and nothing was finishing. The log proves it never ran: `queen.review.posted` (a report) appeared eleven times and `queen.review.sweep` not once. Extracted and called from the autonomy tick as well, so the Queen looks at what is parked every five minutes whether or not anything just completed. Same shape as the defect beside it, fixed an hour earlier: the autonomy tick chose the same issue every cycle, was correctly refused with "already delegated", and treated that as the end of the tick instead of "try the next one" - twenty-three delegations in ten minutes, all the same refusal, one slot of four free the whole time. Live issues are now excluded before the choice rather than discovered by being told no. Driven: she skipped browseros-ai#1127, browseros-ai#1128, browseros-ai#1129 with "a worker already has it" and delegated browseros-ai#1130. 770 e2e checks green.
The dev registry held nineteen tasks and fourteen failures. browseros-ai#1127 had been attempted seven times, browseros-ai#1129 five, browseros-ai#1128 four - every one the same brief against the same issue. Nothing counted the attempts and nothing told the next worker that anyone had been there before it, so a retry was not a second attempt; it was the first attempt run again by someone who did not know. The reason it could not count is that the registry had one word for two different endings. Ten of those fourteen had `streamOutcome: open` and no completed turns - the signature of a process that went away under the worker, which on this machine tonight was me rebuilding the app. The other four had done real work. Both were spelled `failed`, and afterwards nothing could tell them apart. Counting the first group would retire issues for the crime of being open during a rebuild; not counting the second lets one run forever. So the ending is now recorded rather than inferred later. `reconcileOrphaned- Workers` already knew it was reconciling a dead process and threw that away; it writes `interrupted`. The review path had the failure text in hand and stored only the state; it classifies from what the runner measured. An interruption never counts against an issue. Two real failures and the issue stops being chosen - `queen.choose.exhausted` says so with the kinds named, because a third identical attempt is evidence about the issue, not the bees. And when a retry does happen, the brief opens with what the earlier attempts ran into and says not to repeat the approach. That is the half that makes it a second attempt. Driven, not read. Live in the dev app: `Skipping browseros-ai#1131: 2 attempts have already failed on their own merits (workedButFailed, workedButFailed)`, and she took browseros-ai#1132 instead. Three tasks orphaned by my own restarts were recorded `interrupted` and did not count. 805 e2e checks in 71 scenarios, up from 790. Both new guards proven red: making interruptions count breaks four of them, dropping the briefing from the worker's brief breaks two.
…is looking Of the eight disagreements the startup pass raised, four asserted conclusions the code had no way to observe. browseros-ai#1128-r5's single commit was in HEAD patch-for-patch under another SHA, and the blob comparison read it as unaccounted work. browseros-ai#1132-r2's branch sat in the review queue under a sibling record, and the per-record view printed "nobody is looking at it" about a branch literally awaiting review. browseros-ai#1280's branch was called gone while alive on origin with the claimed work. Three new findings measure what those messages guessed: landedElsewhere (git cherry - every branch commit present in HEAD as an equivalent patch), heldBySibling (the caller passes whether another record on the same issue or branch is in an expect-work state; git cannot know the registry), and branchOnlyOnRemote (refs/remotes/origin checked before "gone"). All three are non-urgent stale-record cases with no proposed correction: sending them to review would double-claim a boundary, and clearing a count that HAS something behind it would erase a true statement. The summary buckets them instead of hiding them. The test suite gains the quarantine-recovery scenario and the three refinements, at 942 checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`queend` answers "who is next" from the Queen's live registry, decoded as the
app writes it rather than summarised for the trip:
candidates [1111, 1128, 1129], the running registry
-> chosen: none, "nothing to choose"
browseros-ai#1111: its files are held by Trinity-S-AI-DNA/trios#1286, browseros-ai#1127, browseros-ai#1174
browseros-ai#1128: same
browseros-ai#1129: same
That is capacity, then boundaries, then order - the three rules that decide
which bee starts next, and the last part of the supervision loop still
reasoning on a laptop about a filesystem it cannot see. The rule naming the
holders is the one this session repaired from the Mac side; it now gives the
same answer from the other side, out of one implementation.
Made possible by the visibility pass on QueenDelegation, QueenSalience,
QueenCriterionVerdict and ModelPricing: 158 annotations, converged in three
compiler-driven rounds. The app builds unchanged - `public` on an internal
declaration is additive.
Two defects found by doing it:
Dates. The registry writes ISO 8601 and JSONDecoder defaults to a numeric
interval, so the whole question failed with "could not decode" - a message
naming neither the field nor the reason. The strategy now matches the
registry's own reader, and a decode failure carries the error.
A 17 KB command to `filesystem_bash` returns 500 INTERNAL_SERVER_ERROR. Worked
around by writing the payload with filesystem_write first, which is what that
tool is for, but the 500 is a real limit and is not documented anywhere.
What is still on the Mac is now plumbing rather than policy: a timer, a GitHub
client, and the call that dispatches a turn.
…browseros-ai#1111) (#308) Two bees ran in parallel with disjoint boundaries (browseros-ai#1110 owned rings/SR-02/QueenBranchCommitter.swift, browseros-ai#1109 owned rings/SR-02/ChatViewModel.swift and rings/SR-00/QueenReviewVerdictRequest.swift). browseros-ai#1110 made baseBranch() return String?, exactly as its criterion asked; the call site lived in the other bee's file. Both honoured the one-owner-per-path rule and the build broke: rings/SR-02/ChatViewModel.swift:4142: error: value of optional type 'String?' must be unwrapped to a value of type 'String' The boundary rule protects against a conflict of writes. It says nothing about a conflict of interfaces: a signature changed in one file breaks a different file, and only a build of the two states together can see it. The acceptance-side half landed with browseros-ai#1128 (runInterfaceDivergenceWatchdog compiles the combined state before any acceptance; transitionToAccepted takes the proof as a parameter, so no path to .accepted can skip it). What remained open was the issue's second criterion: drift-guard judges two worktrees it builds itself, not two states of this tree, so returning the former behaviour moved nothing. This file closes that gap with the decision itself, as a pure rule: - QueenInterfaceDivergence.verdict(between:) takes the interface facts of each lane (declarations whose shape changed, calls and the shapes they expect), overlays the lanes the way verifyCombinedBuild overlays branches, and reports every call that no longer matches, plus the two-changers-one- declaration case. Findings name both sides - who changed what, and who still calls the old shape - because a refusal that does not name its subject sends the reader hunting for the wrong problem. - The single-file suite rides in the same file behind QUEEN_INTERFACE_DIVERGENCE_SELFTEST and runs on the incident's own facts: the browseros-ai#1110/browseros-ai#1109 pair is refused, while a change whose call moved with it, a body-only change, and a new call written against the new shape all pass. The block holds declarations only: -emit-module typechecks even inactive #if branches (measured on the container), so a top-level entry would break the app build; the documented one-line driver keeps the file buildable and the suite runnable where no linker exists. - The revert proof is executable: formerIsolatedVerdict restates the pre-browseros-ai#1111 loop (each lane judged alone, nothing crosses a boundary) and the suite shows it accepts the incident pair that the rule refuses. Revert the rule to that judgement and the incident scenario fails its first check - the check breaks. Verified live against two mutants (the isolated revert and a blanket-refuse revert): both fail the suite loudly and non-zero. Nothing is imported, not even Foundation, so the rule compiles anywhere the Swift standard library does and the suite runs interpreted on the Linux container: 17 checks, 0 failures, parse/typecheck/emit-module green with the flag both off and on. Co-authored-by: queen-1111 bee <bee@trios.local>
Summary
@browseros/serverversion0.0.97 → 0.0.98so the next release publishes a new versioned artifact to Cloudflare R2 instead of overwriting the already-published0.0.97.apps/server/package.jsonandbun.lockin lockstep (matching the canonical bump shape of prior commit2403c0d9).Design
The release pipeline treats
apps/server/package.json#versionas the single source of truth:nightly-macos-build.ymlreads it and passes it torelease-server.yml, which re-reads the same file and fails the build if they disagree.scripts/build/server/{config.ts,archive.ts}read the same field and derive the R2 object keys —artifacts/server/latest/…(always overwritten) andartifacts/server/<version>/…. Bumping the one field is therefore sufficient and complete: a re-run at0.0.97would mutate the published0.0.97/objects, whereas0.0.98creates a fresh versioned key and cleanly repointslatest/.The
"…(e.g. 0.0.97)"strings inrelease-server.ymlare input description doc-text, not functional defaults, so they are intentionally left untouched.Test plan
apps/server/package.jsonandbun.lockboth read0.0.98(no0.0.97remaining)bun install --frozen-lockfile→ "no changes" (lockfile consistent)bun run typecheck→ greenbun test scripts/build/server/stage.test.ts→ 11 pass