fix(harness): move base to OpenCode 1.18.18 - #1393
Conversation
Sessions with history older than 2026-08-14 silently stopped responding. OpenCode message IDs pack a timestamp into a 48-bit field, so the value wraps every 795 days; the most recent wrap was 2026-08-14T11:19:55Z. After it, new IDs sort below every earlier one, which made the agent loop's exit guard permanently true — prompts were accepted and never sent to the model, with no error surfaced. Upstream fixed the ordering in anomalyco/opencode#40990 and #40991, merged two days after the 1.18.14 tag we were pinned to. Moving the base to 1.18.18 picks both up; no new integration refs are needed, and no session data has to be migrated. All twelve carried refs remain open or unmerged upstream, so the carry set is unchanged. DEFAULT_OPENCODE_VERSION stays put — sync-default-version moves it once a release produces a real integration SHA. The underlying truncation is still present upstream, so the wrap recurs around 2028-10-17.
The read-only clones under .slim/clonedeps/repos/ track the harness base_version so a source check reflects what we actually ship. They were still at 1.18.14 after the base moved. This staleness had teeth: a search of the 1.18.14 tree for the message-ID ordering bug found nothing and looked like evidence the bug was unreported, when upstream had already fixed it in 1.18.18. The re-pinned tree now shows the isAfter() helper in session/message-v2.ts and the structural parent guard in session/prompt.ts, with the old lexical comparison gone.
fro-bot
left a comment
There was a problem hiding this comment.
Verdict: PASS
This is a clean base-version bump from OpenCode 1.18.14 → 1.18.18. All six edits are internally consistent and correctly scoped; the deliberately-untouched pins are well-justified. I verified the coherence of every changed surface and confirmed the config-guarding test was updated.
What I verified
base_version→1.18.18(packages/harness/harness.config.json:4) is the authoritative pin, and every dependent surface tracks it:.slim/clonedeps.json(ref: v1.18.18, both entries),AGENTS.mdclone-source notes,docs/reference/carry-ledger.md("absent from stock through 1.18.18"), and the Renovate cap (allowedVersions: '<=1.18.18',renovate.json5:188).cli.test.ts:16—getProvenance()reads the liveharness.config.json, soexpect(p.baseVersion).toBe('1.18.18')genuinely guards the pin. This is the only test asserting the base literal, and it was correctly updated; without it the suite would fail. Good coverage discipline.- Deliberately-untouched pins are correct:
DEFAULT_OPENCODE_VERSIONandFALLBACK_VERSION(1.18.14), the@opencode-ai/sdkpins, and the eval baselines (u1.json,u1.test.ts) all still reference1.18.14+harness.202732ae. This matches the two-stage version model —base_versionis the source of truth for the next integration build, whileDEFAULT_OPENCODE_VERSIONtracks the last published build and is moved bysync-default-versiononly once a real integration SHA exists. Inventing a+harness.<sha>suffix here would be wrong. - Carry set unchanged (12 refs), correctly. Per the ledger's own rule, an unmerged upstream PR is not grounds to drop a carry; the PR description's re-gauge against 1.18.18 (4 open, 8 closed-unmerged, none superseded) is the right analysis.
Blocking issues
None.
Non-blocking concerns
- Bun cap left at
<=1.3.14unverified against the new base. The harness build gate requires an exact match with upstreamanomalyco/opencode'spackageManagerfield at the base version (renovate.json5:191-196). A base bump can move that field. If 1.18.18 declares a newer Bun, the build would fail the gate. The PR doesn't claim a Bun change, so this is likely fine — but it's the one dimension the config-only diff doesn't attest to. Worth a one-line confirmation that 1.18.18'spackageManageris stillbun@1.3.14. - Upstream source-level claims not independently verifiable here. The PR description asserts the
isAfter()helper insession/message-v2.ts, the parent-based guard insession/prompt.ts, and the removal of the old lexical comparison. The.slim/clonedeps/repos/clones are metadata-tracked and not materialized in this CI checkout, so I could not re-check them. These are validated by the maintainer during the actual harness integrate/build run (where the merge and CLI build/verify gate execute), not by this config PR — so this is a note, not a gap in this change.
Missing tests
None. The base-version pin is the only new behavioral assertion, and it is covered by cli.test.ts:16. No other test needed updating; the eval baselines correctly continue to pin the last-published build rather than the config base.
Risk assessment (LOW):
Config/documentation-only change (+11/-11 across 6 files) with no runtime code path touched. The actually-shipped binary is produced and verified in the separate maintainer-gated harness release workflow, not by merging this PR — so blast radius on merge is nil. The only latent risk is the unverified Bun/packageManager match, which surfaces as a hard build-gate failure (fail-closed, not silent) at the next release dispatch. Regression likelihood: low. Security exposure: none.
Run Summary
| Field | Value |
|---|---|
| Event | pull_request |
| Repository | fro-bot/agent |
| Run ID | 31849119088 |
| Cache | hit |
| Session | ses_ffd77eb12ffekI8Xh2dmkkcxhF |
Sessions with history older than 2026-08-14 silently stopped responding. A prompt would be accepted, no error surfaced, and the model was never called. The logs showed
loop step=0followed immediately byexiting loop, with nostreamline.Cause
OpenCode message IDs pack
Date.now() * 0x1000 + counterinto a serialized field, but only the low 6 bytes are written. That value needs 53 bits and the field holds 48, so the timestamp wraps every 2^36 ms — about 795 days. The most recent wrap was 2026-08-14T11:19:55Z.After a wrap, newly generated IDs sort lexically below every earlier one. The agent loop's exit guard compared
lastUser.id < lastAssistant.id, which became permanently true for any session holding a pre-wrap assistant message, so the loop exited before dispatching to the model.Fix
Upstream fixed the ordering in anomalyco/opencode#40990 and #40991, replacing the lexical comparison with a structural parent check and making "latest message" resolve by creation time. Both merged to
devon 2026-08-07 — two days after thev1.18.14tag we were pinned to, which is why we were exposed.Moving
base_versionto 1.18.18 picks up both. I confirmed by ancestry that each merge commit is contained in thev1.18.18tag and absent fromv1.18.14, and verified the resulting source carries theisAfter()helper insession/message-v2.tsand the parent-based guard insession/prompt.ts, with the old comparison gone.No new integration refs are needed and no session data has to be migrated.
Carry set
Unchanged. I checked all twelve carried refs against 1.18.18: four are still open upstream (#19961, #31859, #31638, #33713) and eight are closed without merging, so none has been superseded by the new base.
DEFAULT_OPENCODE_VERSIONis deliberately untouched —sync-default-versionmoves it once a release produces a real integration SHA, and inventing a+harness.<sha>suffix that no build emitted would be wrong.FALLBACK_VERSIONand the@opencode-ai/sdkdependency pin track separately and stay as they are.Verification
check-types,lint, and the harness suite (231 passing) all green against the new base.Known gap
Upstream fixed the ordering but not the truncation, so the field still wraps. The next occurrence is around 2028-10-17. Widening it is a separate upstream change and is not part of this PR.