#2547 · bb-plugin-authoring skill documents bb.sdk.threads.list as returning { threads }; it returns an array
Verdict: REPRODUCED · Root-cause confidence: high
1. TL;DR
The bundled skill tells an author to destructure { threads } from bb.sdk.threads.list().
The SDK returns a plain array, so TypeScript rejects the example.
JavaScript runs the same line without an exception, but the threads value becomes undefined.
The existing documentation test checks API names only, so it did not check the example return type.
2. Claims vs findings
| Claim from the issue | Status | Evidence |
|---|---|---|
The skill uses const { threads } = await bb.sdk.threads.list(...). |
Verified | The base skill contains that text at line 689. |
threads.list returns a plain array. |
Verified | The SDK aliases the result to ThreadListResponse. The contract defines that response with z.array(...). |
| TypeScript rejects the documented line. | Verified | The saved probe returned TS2339 at the destructured property. |
JavaScript returns undefined without an exception. |
Verified | The runtime proof used an array and printed destructured threads: undefined. |
| The existing documentation test cannot detect this error. | Verified | The base test uses toContain for API names. It does not compile skill examples. |
A later origin/main commit already fixed the issue. |
Refuted | The path log from the base commit to origin/main contained no fix. |
3. Environment
- bb base commit:
ad79bbb5ec909524f8f281e62d860c588a86f332. - OS: Linux 7.0.0-29-generic, x86_64.
- Node:
v24.18.0. pnpm:9.15.0. - No provider ran for this reproduction.
- No dev server, port, or data directory was necessary.
- The initial install met temporary inode exhaustion. A later isolated install passed.
4. Minimal reproduction
-
Check out and prepare the base revision.
git checkout ad79bbb5ec909524f8f281e62d860c588a86f332 pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build:types --filter=@get-bb/plugin-sdk
-
Save all three required files in one directory.
For verification from the local report checkout, run:
repo_root="$PWD" repro_dir=$(mktemp -d /tmp/bb-2547-repro-XXXXXX) cp /tmp/bb-reports/issues/2547/repro/documented-example.ts "$repro_dir/documented-example.ts" cp /tmp/bb-reports/issues/2547/repro/reproduce.mjs "$repro_dir/reproduce.mjs" cp /tmp/bb-reports/issues/2547/repro/runtime-proof.mjs "$repro_dir/runtime-proof.mjs" cd "$repro_dir"
After publication, the same files are available with these commands:
base_url="https://get-bb.github.io/reports/issues/2547/repro" curl -fsSL "$base_url/documented-example.ts" -o documented-example.ts curl -fsSL "$base_url/reproduce.mjs" -o reproduce.mjs curl -fsSL "$base_url/runtime-proof.mjs" -o runtime-proof.mjs
Files: documented-example.ts, reproduce.mjs, and runtime-proof.mjs.
-
Run the compiler probe and print its exit status.
set +e node ./reproduce.mjs "$repo_root" 2>&1 | sed -E $'s/\x1B\\[[0-9;]*[mGK]//g' tsc_exit=${PIPESTATUS[0]} printf 'tsc_exit=%s\n' "$tsc_exit"The command produced this complete output:
documented-example.ts:7:11 - error TS2339: Property 'threads' does not exist on type '{ activity: { activeBackgroundAgentCount: number; activeBackgroundCommandCount: number; activeGoalCount: number; activePlanModeCount: number; activeWorkflowCount: number; }; archivedAt: number | null; ... 25 more ...; visibility: "hidden" | "visible"; }[]'. 7 const { threads } = await bb.sdk.threads.list({ projectId, limit: 50 }); ~~~~~~~ tsc_exit=1The complete saved output is in compile-output.txt.
-
Run the JavaScript return-shape proof.
node ./runtime-proof.mjs
Array.isArray(result): true result.length: 1 destructured threads: undefined
See runtime-proof.mjs and runtime-output.txt.
The compile probe uses the actual bundled SDK declaration from the supplied bb checkout.
Probe source
import type { BbPluginApi } from "@get-bb/plugin-sdk";
declare const bb: BbPluginApi;
declare const projectId: string;
async function documentedExample(): Promise<void> {
const { threads } = await bb.sdk.threads.list({ projectId, limit: 50 });
console.log(threads);
}
void documentedExample;
5. Root cause
The fault is documentation drift, not an SDK or server response fault.
The skill treats the array response as an object with a threads property.
The SDK result type is a direct alias:
export type ThreadListResult = ThreadListResponse;
See packages/sdk/src/areas/threads.ts.
The public method returns that result:
list(args?: ThreadListArgs): Promise<ThreadListResult>;
The server contract defines the response as an array:
export const threadListResponseSchema = z.array(threadListEntrySchema);
See packages/server-contract/src/api/threads.ts.
The SDK implementation returns the route JSON without an object wrapper.
The deeper cause is a test gap.
The base test checks that the skill contains each API name.
It does not compile a code example against the SDK contract.
See the existing documentation assertions.
6. Proposed fix (first principles)
- Change the example to
const threads = await bb.sdk.threads.list(...). - Extract documented SDK calls during tests.
- Compile each documented destructuring pattern against
BbPluginApi["sdk"]. - Keep the SDK contract and server response unchanged.
This change needs no daemon protocol version increase because it changes no wire data.
7. PR review
PR #2550 · Unblock first-plugin authoring
Verdict: MERGE.
The PR changes the documented line to the correct array assignment.
It also adds a type-driven regression test for documented SDK destructuring.
I restored the bad line temporarily, and the new test failed with TS2339.
I restored the fix, and both documentation test files passed all 16 tests.
Current main was 1d97c63ed13b5231c1051b7af7ac36661d1f65ab during this review.
git merge-tree --write-tree merged PR head 0ee3c8bae68a8473a3b82e1c1b9f76686b26a2a4 with that commit without a conflict.
GitHub also reported the PR as mergeable. Its merge-state status was UNSTABLE, not conflicted.
| Severity | Finding | Result |
|---|---|---|
| Correct | SKILL.md:689 assigns the array directly. |
This change fixes the reported root cause. |
| Correct | The new test fails on the base example and passes after the fix. | The test protects the exact regression. |
| Low | The new probe does not compile method arguments or later property access. | This gap does not affect the reported destructuring error. A later test can compile complete code blocks. |
| Low | The scaffold source repeats the same dependency comment before cron-parser and hono. |
This duplication does not change behavior. |
Checks run on PR #2550
- The full Turbo build passed: 18 of 18 tasks.
- The full CLI suite passed: 50 files and 498 tests.
- The focused documentation suites passed: 2 files and 16 tests.
- The reverted documentation test failed as required.
- The full server suite passed 2,042 tests and timed out on eight unrelated tests.
I did not reproduce the eight timeout failures on the base revision.
The failures did not touch the changed files, and the focused server tests passed.
Logs: build, CLI tests, server tests, reverted test, and fixed tests.
8. Related issues
- #2546 reports a missing test-harness dependency.
- #2548 reports hidden npm failure output.
- #2550 contains fixes for all three issues.
9. Appendix
History
Commit 010ef9cd455382c0183d7d5784ece671ad601b18 introduced the wrong example.
That commit documented the SDK area map but did not compile the new example.
Commands run
gh issue view 2547 --comments gh issue view 2547 --json number,title,body,labels,projectItems,comments,state,url pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build git fetch origin main git log ad79bbb5ec90..origin/main --oneline -- <affected paths> git fetch origin refs/pull/2550/head:refs/remotes/origin/pr-2550 git merge-tree --write-tree origin/main refs/remotes/origin/pr-2550 node issues/2547/repro/reproduce.mjs <repo-root> node issues/2547/repro/runtime-proof.mjs gh pr view 2550 gh pr diff 2550 gh pr checkout 2550 pnpm exec turbo run build pnpm exec turbo run test --filter=@bb/cli --force pnpm exec turbo run test --filter=@bb/server --force pnpm exec vitest run test/services/plugins/plugin-authoring-doc-examples.test.ts test/services/plugins/plugin-authoring-docs.test.ts git blame ad79bbb5ec90 -L 685,697 -- apps/server/src/services/skills/builtin-skills/bb-plugin-authoring/SKILL.md
Saved reproduction artifacts
- documented-example.ts
- reproduce.mjs
- tsconfig.json
- compile-output.txt
- runtime-proof.mjs
- runtime-output.txt
Verification
The verifier reproduced TS2339 from Steps 1 through 3.
The verifier found that Step 4 lacked a command to save runtime-proof.mjs.
The revised steps now copy or download all three files before either probe runs.
I ran the revised local copy commands in a new directory.
The compiler returned status 1, and the runtime proof printed the saved output.
I also checked PR #2550 against current main with git merge-tree. The check found no conflict.