Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions devlog/2026-08-13_fix-smoke-harness/REQ.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# REQ - Repair the root smoke harness

- Task ID: `2026-08-13_fix-smoke-harness`
- Home Repo: `billion-context-opencode`
- Created: 2026-08-13
- Status: Done
- Priority: P1
- Owner: 5258MF
- References: root `smoke.mjs`; PR #12

## 1. Background & Problem Statement

- **Context**: The monorepo build emits the public bundle under `packages/billion-context-opencode/dist/`, while the root smoke harness still uses the pre-monorepo bundle path.
- **Current behavior (symptom)**: `npm run build && node smoke.mjs` fails before loading the plugin. If the path is corrected locally, the harness assumes assistant ref tags are always visible and recursively deletes the user's entire ACP cache before running.
- **Expected behavior**: The root smoke loads the actual bundle, exercises compression with whichever visible boundary is available, and cleans up only the state file created by its unique session.
- **Impact**: Contributors can run the documented end-to-end check without stale path failures, coupling to V1 ref presentation, or loss of local plugin state.

## 2. Reproduction

- **Environment**: Node 22/24; any supported OS.
- **Minimal reproduction steps**:
1. Run `npm run build` from the repository root.
2. Run `node smoke.mjs` and observe that `./dist/index.js` does not exist.

## 3. Constraints & Non-Goals

- **Constraints**:
- Do not change package source, public APIs, persisted state schemas, or plugin behavior.
- Keep the smoke compatible with both current master and V1 assistant-tag omission from PR #12.
- **Non-Goals**: Real OpenCode process coverage, V2 behavior changes, or replacing the planned e2e harness.

## 4. Acceptance Criteria

- **Correctness**:
- [x] The smoke imports the bundle produced by `npm run build`.
- [x] Compression/search/decompression complete whether or not the assistant exposes a ref tag.
- [x] The smoke never recursively deletes the shared ACP cache.
- **Regression**:
- [x] `npm run typecheck`, `npm run test`, `npm run build`, and `node smoke.mjs` pass.

## 5. Proposed Approach

- Update the root harness path, select the assistant ref with a user-ref fallback, and remove only the unique smoke session state file.
- **Rollback strategy**: Revert the smoke-only commit; no application or state migration is involved.
61 changes: 61 additions & 0 deletions devlog/2026-08-13_fix-smoke-harness/WORKLOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# WORKLOG - Repair the root smoke harness

- Task ID: `2026-08-13_fix-smoke-harness`
- Home Repo: `billion-context-opencode`
- Status: Done
- Updated: 2026-08-13

## 1. Summary

- **What was done**: Repaired the root smoke bundle path, removed its destructive shared-cache reset, and made its compression boundary independent of assistant tag presentation.
- **Why**: Restore the documented post-build check while keeping it safe and compatible with the intentional V1 behavior in PR #12.
- **Behavior / compatibility changes**: Test harness only; no package or runtime behavior changes.
- **Risk level**: Low

## 2. Change Log

### Commits

| Commit | Description |
|--------|-------------|
| Pending | Repair root smoke harness |

### Key Files

- `smoke.mjs` - load the monorepo bundle, use a visible fallback boundary, and clean up only the smoke session state.
- `devlog/2026-08-13_fix-smoke-harness/` - task requirements and verification record.

## 3. Design & Implementation Notes

- **Entry point / key function**: Root `smoke.mjs` executed after `npm run build`.
- **Key configuration items**: None.
- **Key logic explanation**: Current master exposes an assistant ref, while PR #12 intentionally omits it. The smoke uses the assistant ref when present and otherwise the following user ref, so it tests the tool pipeline rather than enforcing presentation behavior already covered by converter unit tests.

## 4. Testing & Verification

### Build & Test Commands

```sh
npm run typecheck
npm run test
npm run build
node smoke.mjs
bash scripts/ci/check-pr.sh 2026-08-13_fix-smoke-harness upstream/master
git diff --check
```

### Test Coverage

- New/modified test files: `smoke.mjs`.
- Test count: 26 total, 26 pass, 0 fail.
- Key scenarios verified: The built bundle loads; current-master assistant refs are usable; with PR #12 stacked, the missing assistant ref falls back to the next user ref; compression, status, search, and decompression complete in both cases; the smoke-created state file is removed without touching other sessions.

### Results

- **PASS**: `npm run typecheck`, `npm run test` (26/26), `npm run build`, `node smoke.mjs`, PR validation, and `git diff --check`; a detached PR #12 + smoke-fix compatibility build/smoke also passed.

## 5. Risk Assessment & Rollback

- **Risk points**: The fallback boundary includes the next user message when assistant refs are intentionally hidden.
- **Rollback method**: Revert the smoke-only commit.
- **Compatibility notes**: No changes to dual-shape export, persisted state format, or config schema.
17 changes: 11 additions & 6 deletions smoke.mjs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import assert from "node:assert/strict"
import { rm } from "node:fs/promises"
import plugin from "./dist/index.js"
import { homedir } from "node:os"
import { join } from "node:path"
import plugin from "./packages/billion-context-opencode/dist/index.js"

await rm(process.env.HOME + "/.cache/opencode-bili-acp", { recursive: true, force: true })
const sid = "smoke-" + Date.now()
const stateFile = join(homedir(), ".cache", "opencode-bili-acp", `${sid}.acp.json`)
const now = Date.now()

function userMsg(id, text) {
Expand Down Expand Up @@ -55,16 +57,18 @@ function extractRef(msg) {
}
const u1Ref = extractRef(mout.messages[0])
const a1Ref = extractRef(mout.messages[1])
console.log(" u1 ref:", u1Ref, "| a1 ref:", a1Ref)
assert.ok(u1Ref && a1Ref, "refs extractable from tags")
const u2Ref = extractRef(mout.messages[2])
const endRef = a1Ref ?? u2Ref
console.log(" u1 ref:", u1Ref, "| compression end ref:", endRef)
assert.ok(u1Ref && endRef, "compression boundary refs extractable from tags")

// --- bili_status tool ---
const statusResult = await hooks.tool.bili_status.execute({}, { sessionID: sid, messageID: "m_status", callID: "call_status", agent: "build", directory: "/tmp", abort: new AbortController().signal, metadata: () => {}, ask: async () => ({}) })
console.log("✓ bili_status returned", typeof statusResult === "string" ? statusResult.slice(0, 80) + "..." : "object")

// --- bili_compress tool: compress u1..a1 (large) ---
// --- bili_compress tool: compress the oldest visible range ---
const compressResult = await hooks.tool.bili_compress.execute({
content: [{ startId: u1Ref, endId: a1Ref, summary: "User and assistant discussed topic A in detail, covering alpha concepts and beta implementations across many repetitions for testing the compression pipeline end to end." }],
content: [{ startId: u1Ref, endId: endRef, summary: "User and assistant discussed topic A in detail, covering alpha concepts and beta implementations across many repetitions for testing the compression pipeline end to end." }],
}, { sessionID: sid, messageID: "m_compress", callID: "call_compress", agent: "build", directory: "/tmp", abort: new AbortController().signal, metadata: () => {}, ask: async () => ({}) })
console.log("✓ bili_compress:", compressResult.slice(0, 100))

Expand All @@ -82,4 +86,5 @@ console.log("✓ bili_search:", searchResult.slice(0, 100))
const decompResult = await hooks.tool.bili_decompress.execute({ blockId: "b1", inline: true }, { sessionID: sid, messageID: "m_decomp", callID: "call_decomp", agent: "build", directory: "/tmp", abort: new AbortController().signal, metadata: () => {}, ask: async () => ({}) })
console.log("✓ bili_decompress:", decompResult.slice(0, 100))

await rm(stateFile, { force: true })
console.log("\n=== ALL SMOKE TESTS PASSED ===")
Loading