Skip to content

fix(iwiki): stop fetchAllPages from rejecting every space walk before it starts - #849

Merged
jeff-r2026 merged 1 commit into
Tencent:mainfrom
ydflow:fix/iwiki-fetch-all-pages
Sep 28, 2026
Merged

jeff-r2026 merged 1 commit into
Tencent:mainfrom
ydflow:fix/iwiki-fetch-all-pages

Conversation

@ydflow

@ydflow ydflow commented Sep 27, 2026

Copy link
Copy Markdown
Contributor

Closes #848.

Problem

fetchAllPages rejects every call with fetchAllPages: rootId 队列为空 before the first request can return, so teamai import --from-iwiki <space-id> (and the iwiki-dual Space path) can never list a space's pages. Root cause and reproduction are in #848: the "initial queue is empty" guard runs after tryDrain(), which has already shifted the rootId, so the queue is always empty at that point and the promise rejects on every call. Zero-latency mocks hid it — the first response beat the rejection and populated allPages, letting the catch guard swallow the error; with real latency the rejection always wins.

Fix (src/utils/iwiki-client.ts)

  • Check the guard before tryDrain(), and seed the queue only for a non-empty rootId, so it now rejects exactly when there is nothing to walk (its original purpose) and every real walk gets to start.
  • Drop the dead && !stopped from the drain loop: tryDrain already returns when stopped, and stopped only changes inside async callbacks, so the condition never changes within the synchronous loop. This is the no-unmodified-loop-condition hit that oxlint rollout: bugs found in the baseline, and next rules to evaluate #836 says to check first — verified as redundant here, now removed so the planned lint rollout stays clean.
  • Write the file's user-facing messages in English per the repo rule ("CLI user-facing output must be English"): the reject message, the per-node failure warns, the max-pages warn and the MCP parse error. Comments stay as they were. No docs reference the old strings (grepped src/, docs/, skill-data/, README*).

Tests

New src/__tests__/iwiki-client.test.ts (6 tests) mocks getSpacePageTree with deferred promises (resolve on a later macrotask), which is what makes the suite able to catch a regression — the same tests fail 5/5 on main:

× returns the pages of a single-node space            → fetchAllPages: rootId 队列为空
× walks children breadth-first                        → fetchAllPages: rootId 队列为空
× keeps going when one node fails and warns about it  → fetchAllPages: rootId 队列为空
× stops at maxPages and warns in English              → fetchAllPages: rootId 队列为空
× rejects for an empty rootId without any request     → got 'fetchAllPages: rootId 队列为空'

On this branch: 6/6 pass, plus the existing iwiki-dual.test.ts (4) and iwiki-review-apply.test.ts (2). npx tsc --noEmit clean; npm run lint 0 warnings (--deny-warnings).

Real-CLI verification (b19682e)

npm run build, then node dist/index.js import --from-iwiki 12345 against a sandbox HOME, a local team-repo fixture and a placeholder token. The iWiki MCP endpoint is only reachable inside Tencent, so the network itself fails here — which is exactly what makes the two runs comparable: the same unreachable endpoint, the only difference being when the walk gives up.

Before (main): rejects instantly with the bogus guard error, before any request:

✖ Page tree fetch failed: Error: fetchAllPages: rootId 队列为空
✖ fetchAllPages: rootId 队列为空

After (this branch): the walk starts, the root request really goes out, its network failure is reported per node (in English), and the command ends the way a failed walk is designed to:

⚠ iWiki page tree request failed [parentid=12345]: Error: connect ETIMEDOUT 175.27.22.2:443
✔ Page tree fetched: 0 pages
⚠ no pages found, import aborted

… it starts

The 'initial queue is empty' guard ran after tryDrain(), which had
already dispatched the root request: tryDrain shifts the only queue
entry, so the queue is always empty by then and the promise rejected
with 'fetchAllPages: rootId 队列为空' on every call, before any
response could arrive. Zero-latency mocks hid it — the first response
beat the rejection and populated allPages, so the catch guard
(allPages.length === 0) swallowed the error.

Check the guard before tryDrain() and seed the queue only for a
non-empty rootId, so it rejects exactly when there is nothing to walk.
Also drop the dead '!stopped' from the drain loop (tryDrain already
returns when stopped, and stopped cannot change inside the synchronous
loop — oxlint no-unmodified-loop-condition, the hit Tencent#836 flags), and
write the file's user-facing messages in English per the repo rule.
@jeff-r2026 jeff-r2026 self-assigned this Sep 27, 2026
@jeff-r2026
jeff-r2026 self-requested a review September 27, 2026 02:36
@github-actions

Copy link
Copy Markdown

No findings.

The PR description includes sufficient testing, including a representative real-CLI verification for the runtime behavior change. The previously reported findings section is empty, so there are no earlier findings to mark resolved.

@jeff-r2026
jeff-r2026 merged commit 2169f2e into Tencent:main Sep 28, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] iWiki space import always fails: fetchAllPages rejects before any request

2 participants