Skip to content

Docs: align the threading model with the single progress owner - #1761

Merged
ChaoWao merged 1 commit into
mainfrom
docs-async-pipeline-threading-debt
Aug 10, 2026
Merged

Docs: align the threading model with the single progress owner#1761
ChaoWao merged 1 commit into
mainfrom
docs-async-pipeline-threading-debt

Conversation

@ChaoWao

@ChaoWao ChaoWao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

The async-pipeline track (W1a #1650 → W1b #1748 → W1c #1750 → W1d #1754, plus E1′ #1739) changed who runs endpoint progress and what it costs. Five places in the tree still describe the previous world.

Two of them are reasoning, not description, which is why this is worth a PR rather than a drive-by:

  • docs/worker-manager.md §5.3 asked "Why one WorkerThread per child?" and justified it with "one child = one thread that drives it" and "zero contention on queue access". Both describe machinery Refactor: centralize endpoint progress in Scheduler #1754 deleted — and the alternative that section rejects ("N children share one dispatch queue") is close to the design that was then adopted. Refactor: centralize endpoint progress in Scheduler #1754 updated §2 but left §5.3 arguing against its own change.
  • docs/scheduler.md explained the missed-edge hazard by saying the change happens "outside the Scheduler thread", and closed by crediting the on_idle callback for the retry. Completion is now published on the Scheduler thread, and on_idle no longer exists.

A reader trusting either draws a wrong conclusion about thread safety. That is worse than the docs saying nothing.

The one item that is mine

I raised the mailbox_mu_ stall widening as a Should-fix on my #1754 review and asked for it to be recorded before merge. It merged without it, so the behavior change is on main with nothing describing it. This PR closes that.

submit_progress takes mailbox_mu_ and now runs on the Scheduler thread, which holds loop_mu_ and is the sole progress owner for every endpoint. run_control_command holds that same mutex while blocking on the child, with no deadline by default. So an outstanding control command on any one endpoint stops progress on all of them and keeps loop_mu_ held — which Orchestrator::set_scheduler_loop_mutex shares with allocator compaction.

To be precise about provenance: this is not a defect being introduced or fixed. The wait already existed per endpoint before #1754; only the set of work it blocks got wider. Removing it needs a wakeup primitive on the mailbox, which changes the host↔child contract and is deliberately out of scope for W1d and for this PR.

Changes

File What was wrong
src/common/hierarchical/worker_manager.cpp (nothing recorded) — now states the stall invariant at the acquisition where it happens
docs/worker-manager.md §5.3 rationale for a design that was replaced; now asks why one progress owner, and states the two costs that answer carries
docs/scheduler.md false premise + deleted on_idle + deleted active_inflight_; ordering conclusion preserved because it is still load-bearing for the stop path
docs/orchestrator.md "Each WorkerThread runs worker->run" — WorkerEndpoint::run retired by #1739
docs/remote-l3-worker-design.md "blocks until TASK_DONE" — same, and it sits in a current file-map section

orchestrator.md and remote-l3-worker-design.md trace to my own #1739; worker-manager.md and scheduler.md to #1754, which I reviewed and approved.

No behavior change

The only edit under src/ is a comment. Verified mechanically — the diff contains no non-comment lines there:

git diff cf0fbc06 -- src/ | grep -E "^[+-]" | grep -vE "^[+-]{3}" | grep -vE "^[+-]\s*//"   # empty

Testing

  • 91/91 C++ unit tests (ctest -LE requires_hardware, CI's filter) after rebuilding
  • clang-format --dry-run --Werror clean
  • markdownlint-cli2 clean against tests/lint/.markdownlint.yaml
  • Grep audit: none of the five stale spellings survive (one thread that drives it, active_inflight_, worker->run, blocks until TASK_DONE, on_idle) — each 0-hit result paired with a non-zero positive control, so an empty result cannot pass for a correct one

Python UT and the onboard sweep were not run: nothing executable changes, and running them would be theatre rather than evidence.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d509a6c-92ad-4e2d-98b3-016f40a96ccd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The changes update documentation and comments for the non-blocking Scheduler and worker-endpoint model. They clarify retry progress, polling behavior, single-threaded child progress, and mailbox synchronization effects.

Changes

Scheduler and worker progress

Layer / File(s) Summary
Non-blocking progress model
docs/orchestrator.md, docs/remote-l3-worker-design.md, docs/scheduler.md, docs/worker-manager.md, src/common/hierarchical/worker_manager.cpp
The documentation describes task submission, non-blocking endpoint polling, retry progress, single-threaded child progress, and mailbox blocking behavior.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Poem

A rabbit reads the Scheduler’s chart,
Each endpoint hops its turn.
No worker thread runs apart;
Poll, submit, and progress burn.
Mailbox waits can pause the lane—
Then all resume again.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main documentation change: aligning the threading model with the single progress owner.
Description check ✅ Passed The description directly explains the stale documentation, source comment, scope, and verification for this changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/remote-l3-worker-design.md`:
- Around line 140-141: Update the WorkerThread design description to remove the
`run()` references unless they represent a separately supported interface; align
the documented progress flow with the endpoint methods `submit_progress`,
`activate_progress`, and `poll_progress` used by `WorkerEndpoint`,
`LocalMailboxEndpoint`, and `RemoteL3Endpoint`.

In `@docs/worker-manager.md`:
- Around line 451-457: Qualify the opening description of submit_progress and
poll_progress in the “one thread per child” alternative to state that they do
not wait for child completion, while acknowledging they may block on mailbox_mu_
contention. Keep the existing explanation of run_control_command and the
resulting stall unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: dbcdf737-055d-4e21-ad40-f1ce87434c9e

📥 Commits

Reviewing files that changed from the base of the PR and between bd5ecb5 and f485c8c.

📒 Files selected for processing (5)
  • docs/orchestrator.md
  • docs/remote-l3-worker-design.md
  • docs/scheduler.md
  • docs/worker-manager.md
  • src/common/hierarchical/worker_manager.cpp

Comment thread docs/remote-l3-worker-design.md
Comment thread docs/worker-manager.md Outdated
The async-pipeline track changed who runs endpoint progress and what it costs.
Six places still described the previous world, and two of them were reasoning
rather than description — a rationale section arguing against the design that
was subsequently adopted, and a race explanation whose premise had become false
while its conclusion stayed true. Both lead a reader to the wrong conclusion
about thread safety, which is worse than saying nothing.

The stall window is recorded where it happens rather than described from
outside. submit_progress takes mailbox_mu_ and runs on the Scheduler thread,
which holds loop_mu_ and is the sole progress owner for every endpoint;
run_control_command holds that same mutex while it blocks on the child, with no
deadline by default. So an outstanding control command on any one endpoint stops
progress on all of them and keeps loop_mu_ held, which Orchestrator shares with
allocator compaction. Nothing in the function bounds that wait. This is a
property of the current arrangement, not a defect being introduced or fixed: the
wait already existed per endpoint, and only the set of work it blocks is wider.
Removing it needs a wakeup primitive on the mailbox, which is a change to the
host/child contract and out of scope here.

worker-manager.md 5.3 asked why each child had its own thread and answered with
zero queue contention and one-thread-per-child simplicity. Neither is a property
of the code any more, and the alternative it rejected is close to what now
exists. It now asks why there is one progress owner and answers with the reason
a dedicated thread cannot help: submit_progress and poll_progress never wait for
child completion, so such a thread has no completion to block on and spins for
as long as its child is busy. That is stated as the narrow claim it is —
not waiting for completion is not the same as never blocking, and the same
section names mailbox_mu_ as the case where it does block.

scheduler.md attributed the missed-edge hazard to changes landing outside the
Scheduler thread and closed by crediting the on_idle callback for the retry.
Completion is now published on the Scheduler thread and on_idle no longer
exists. The ordering it documents is still real and still load-bearing for the
stop path, so that survives; what replaces the edge is that the Scheduler does
not park while any lane is busy, so an occupied lane gets another round without
needing one. It also cited active_inflight_, removed when the lane array
replaced the parallel counters.

Four remaining references named endpoint entry points that no longer exist.
orchestrator.md described a group member through WorkerEndpoint::run;
remote-l3-worker-design.md used it for both the mailbox description and the
required parent-side completion behavior; buffers-and-transports.md listed
WorkerEndpoint::run and WorkerEndpoint::control as the surface the Orchestrator,
Scheduler and WorkerThread see. Each now names the progress calls that replaced
them. The PR-sequence entry in remote-l3-worker-design/implementation-plan.md
keeps its WorkerEndpoint::run wording: it records what that step delivered at
the time, and rewriting it would misstate the history rather than correct a
claim about the present.

No behavior change: the only edit under src/ is a comment, and the diff there
contains no non-comment lines.

Verification: 91/91 C++ unit tests (ctest -LE requires_hardware), clang-format
clean, markdownlint-cli2 clean against tests/lint/.markdownlint.yaml, and a grep
audit confirming no stale spelling survives -- searched by concept
(Endpoint::run, Endpoint::control, WorkerThread::run, worker->run) rather than
only the spellings already found, with every 0-hit result paired with a non-zero
positive control so an empty result cannot pass for a correct one. Python and
onboard suites were not run: nothing executable changes.
@ChaoWao
ChaoWao force-pushed the docs-async-pipeline-threading-debt branch from f485c8c to 7cd18ea Compare August 10, 2026 09:03
@ChaoWao

ChaoWao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Both inline findings were valid and both were mine — fixed, each answered on its thread.

  • remote-l3-worker-design.md run() references — you anchored at :141, which this PR had already fixed; the live ones were :521-522. Chasing it by concept instead of by the spellings I already knew about also turned up buffers-and-transports.md:335, which named WorkerEndpoint::run() and WorkerEndpoint::control() — both 0 hits. Left implementation-plan.md:26 alone deliberately: it is a PR-sequence entry marked "Implemented.", so it records history rather than asserting a present-tense contract.
  • worker-manager.md §5.3 over-broad "non-blocking" — a self-contradiction I introduced two paragraphs apart, and it undercut the exact stall this PR exists to record. Narrowed to "never wait for child completion", with an explicit sentence that this is not the same as never blocking.

The root cause of the miss is now fixed in the audit itself: it greps Endpoint::run / Endpoint::control / WorkerThread::run / worker->run rather than the spellings already found, with a non-zero positive control behind every 0-hit result.

Re-verified after the fixes and a rebase onto c2236d9e: 91/91 C++ UT, markdownlint clean across all five docs, and the diff under src/ still contains no non-comment lines.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@ChaoWao Confirmed. Both inline findings are addressed.

The revised wording distinguishes “never wait for child completion” from “never blocking.” The audit now checks the exact obsolete API spellings and validates each expected zero-hit result with a positive control. The historical entry in docs/implementation-plan.md remains appropriate.


✏️ Learnings added
Learnt from: ChaoWao
URL: https://github.com/hw-native-sys/simpler/pull/1761

Timestamp: 2026-08-10T09:05:10.097Z
Learning: For stale API documentation audits in this repository, search the exact obsolete spellings already identified, including `Endpoint::run`, `Endpoint::control`, `WorkerThread::run`, and `worker->run`. For each expected zero-hit search, include a non-zero positive control so that an incorrect grep pattern cannot silently pass.

Learnt from: ChaoWao
URL: https://github.com/hw-native-sys/simpler/pull/1761

Timestamp: 2026-08-10T09:05:10.097Z
Learning: In this repository, entries in `docs/implementation-plan.md` that are marked “Implemented.” are PR-sequence history. They do not assert a present-tense API contract and should not be treated as stale API documentation solely because they mention removed APIs.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@ChaoWao
ChaoWao merged commit 8616c73 into main Aug 10, 2026
49 of 51 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.

1 participant