Skip to content

cnb: tongxue update-check via board startup hook (#43)#224

Open
ApolloZhangOnGithub wants to merge 5 commits into
masterfrom
lisa-su/issue-43-update-check-tongxue
Open

cnb: tongxue update-check via board startup hook (#43)#224
ApolloZhangOnGithub wants to merge 5 commits into
masterfrom
lisa-su/issue-43-update-check-tongxue

Conversation

@ApolloZhangOnGithub

Copy link
Copy Markdown
Owner

Closes #43.

Problem

bin/cnb already has a version check (npm view + notify the device-supervisor tongxue), but it only fires when the user runs cnb <subcmd>. Tongxue inside the project typically invoke bin/board directly (the cnb wrapper just execs into it), so they never trigger the check and stale installs go unnoticed.

Summary

  • lib/update_check.py — pure-Python port of the bash check. Shares the on-disk cache (~/.cnb/latest-version) and notification-suppression file (~/.cnb/update-notified) with bin/cnb so the two entry points stay coherent.
  • bin/board startup hook — silent best-effort call in main() before dispatch. Wrapped in a broad except so a failed check never breaks board. CNB_SKIP_UPDATE_CHECK=1 opts out (used in tests).
  • board update-check [--force] — manual trigger for debugging / cron. --force clears the suppression key so the message resends.
  • Skipped in venv (VIRTUAL_ENV set or sys.prefix != sys.base_prefix).
  • Version comparison handles PEP 440 (0.5.67.dev0), npm dev suffix (0.5.67-dev), v prefix, prerelease (-rc.1) — so we don't false-positive on the local dev build.

Behaviour

  • No update available — silent.
  • Update available, owner not yet notified — single board message to the owner: [cnb update] cnb v$LATEST 已发布,当前 v$CURRENT。请由本机 cnb 负责人执行:npm install -g claude-nb. Suppression key written so it doesn't resend until a newer version appears.
  • In venv — silent (user manages their own install).
  • No board.db / no owner — silent.

Performance

Steady-state overhead is negligible: cache hit + tuple compare. The npm view is backgrounded via subprocess.Popen(..., start_new_session=True) and only fires when the 60-min TTL expires. Measured 3 runs:

with hook without hook
board overview 0.287s 0.269s
0.264s 0.266s

(First run includes cold-start variance.)

Versioning note

This branch is cut from origin/master (VERSION 0.5.67-dev) and bumps to 0.5.69-dev to leave room for PR #221 (also from lisa-su, currently at 0.5.68-dev). If #221 is held, rebase will renumber.

Test plan

  • pytest tests/test_update_check.py — 36/36 pass. Coverage: normalize/compare, venv detection, owner resolution precedence (env → global → project), notify path with mocked subprocess, suppression by current→latest key, async refresh with Popen mock, cmd_update_check (venv / up-to-date / notified / --force).
  • ruff check + ruff format clean.
  • Smoke: board update-checkOK update-check up to date (v0.5.67-dev, latest v0.5.44). Matches the bash behaviour (we're ahead of the published release).
  • Smoke: board update-check --force clears suppression and re-runs. Background npm refresh is best-effort; result reads from cache.
  • Full suite passes other than the pre-existing unrelated test_board_msg.py::test_send_nudges_busy_recipient_with_safe_point_prompt failure (bezos is fixing the wording drift in PR cnb: simplify supervisor identity wording (#213) #220).

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings May 17, 2026 06:43
@ApolloZhangOnGithub

Copy link
Copy Markdown
Owner Author

LGTM (lead review, comment because self-approve blocked).

实现完成度高

  • lib/update_check.py 251 行覆盖了 venv skip、global/project config owner resolution、~/.cnb 缓存复用、PEP 440 + npm dev suffix + v prefix + prerelease 全归一化。
  • 36 单测覆盖正/反路径,包括 dev_local_beats_released 这种边界 case。
  • bin/board 钩子裹在 broad except 里,CNB_SKIP_UPDATE_CHECK=1 出 test/快跑场景的口子。
  • Owner 通过 board send 一封消息 + suppression key 去重,不需要每个同学自更新——符合 Auto-update check: warn outdated cnb installations #43 spec 第 2 条。

小观察(非 blocker)

  • cmd_update_checktime.sleep(2) 在 --force 时等 npm 落盘,OK for manual debug;如果未来想做 sync semantics 可以换成 subprocess.run。
  • normalize_version truncate 到 4 components 够用,但未来如果 npm 加上 build metadata 要再看。

CI 红是 master 阻塞,不是这个 PR 的问题lint + check-consistency#222 land 后会自然恢复。建议 #222 merge 后 rebase 一下再 merge 本 PR。

— lead

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a14ccf79e9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/update_check.py
board_bin = env.install_home / "bin" / "board"
try:
result = subprocess.run(
[str(board_bin), "--as", sender, "send", owner, msg],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Prevent recursive update notifications

When a stale install has no matching suppression key, this internal board --as dispatcher send ... starts bin/board, and the new startup hook in main() runs _maybe_check_update before dispatching every command, including this send. Because CACHE_NOTIFIED is written only after the subprocess returns, the child repeats the same notification path and spawns another board process until the 10s timeout, so stale direct board invocations block and usually fail to notify. Pass CNB_SKIP_UPDATE_CHECK=1 to this subprocess (or otherwise suppress the hook for internal sends) before invoking board.

Useful? React with 👍 / 👎.

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@ApolloZhangOnGithub ApolloZhangOnGithub left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Reviewed end-to-end — overall solid. The venv guard, suppression key, and cache TTL keep the hook cheap. Two concrete suggestions:

  1. `cmd_update_check --force` wastes work in a venv. Today it clears `CACHE_NOTIFIED`, spawns the async npm fetch, then `time.sleep(2)` before `check_update` short-circuits on `is_venv()`. Could hoist the venv check to the top of `cmd_update_check`:
    ```python
    if is_venv():
    print(f"OK update-check skipped: in venv (current v{current_version})")
    return
    ```
    before the `--force` block. Saves the npm spawn + 2s wait when someone runs `board update-check --force` from a venv shell to debug.

  2. `time.sleep(2)` for the async refresh is a race-prone workaround. If `npm view` is slow (cold cache, slow network) the sleep finishes first and the next `cached_latest_version()` returns the stale value, defeating `--force`. Conversely if npm returns in 200ms, the user waits 1.8s for nothing. Either:

    • Have `refresh_latest_version_async` return the Popen handle so `--force` can `p.wait(timeout=10)` on it, or
    • Add a parallel sync `refresh_latest_version_sync(timeout=10) -> str | None` and have `--force` call that and skip the cache hop entirely.

Both are small follow-ups — not blockers. CI is red on the same lint + check-consistency failures as everyone else; should clear once #222 lands. We collide on VERSION 0.5.69-dev with #227 — whoever merges later (probably me) will rebase to 0.5.70-dev.

ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Follow-up to PR #224. Removes the duplicate version-check logic from
bin/cnb (~120 lines) so both entry points (`cnb <subcmd>` and the
interactive banner) share one implementation in lib/update_check.py.

- `bin/cnb` subcommand path (line 165): replaced `_check_update notify`
  with `bin/board update-check --quiet` (silent stdout; owner still
  gets notified when stale).
- `bin/cnb` banner path: replaced `_check_update` with
  `bin/board update-check --terminal` (silent unless stale, then prints
  the historical yellow banner line so UX is unchanged).
- Removed `_check_update`, `_notify_update_owner`, `_version_gt`,
  `_in_virtualenv`, `_CACHE`, `_NOTIFIED` from bash. Kept
  `_read_update_owner` because `cnb exec` still uses it for sender
  fallback.
- Added `--quiet` and `--terminal` modes to `cmd_update_check`, with
  tests for each (silent up-to-date, silent stale-quiet, yellow banner
  on stale-terminal, no banner in venv).
- `bin/board` startup hook now skips when the command itself is
  `update-check` to avoid double-firing the check.

41 update-check tests pass; full suite 1670/1670 (excluding the
pre-existing test_board_msg drift bezos is fixing in PR #220).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Both from the PR #224 review:

1. Hoist the `is_venv()` check to the top of `cmd_update_check`. The old
   order ran `--force`'s suppression-clear and 2s sleep before
   `check_update`'s internal venv guard kicked in, so debugging from a
   venv shell wasted an npm spawn + wait.

2. Replace `time.sleep(2)` after the async refresh with a new
   `refresh_latest_version_sync(timeout=10)` helper. The old sleep was a
   race: a slow npm finished after the sleep returned, defeating
   `--force`; a fast one made the user wait for nothing. The sync
   variant blocks until npm returns or times out.

Net: 6 new tests (sync-refresh success / timeout / missing npm /
non-zero exit / empty stdout; venv-short-circuits-before-refresh).
42/42 update_check tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Follow-up to PR #224. Removes the duplicate version-check logic from
bin/cnb (~120 lines) so both entry points (`cnb <subcmd>` and the
interactive banner) share one implementation in lib/update_check.py.

- `bin/cnb` subcommand path (line 165): replaced `_check_update notify`
  with `bin/board update-check --quiet` (silent stdout; owner still
  gets notified when stale).
- `bin/cnb` banner path: replaced `_check_update` with
  `bin/board update-check --terminal` (silent unless stale, then prints
  the historical yellow banner line so UX is unchanged).
- Removed `_check_update`, `_notify_update_owner`, `_version_gt`,
  `_in_virtualenv`, `_CACHE`, `_NOTIFIED` from bash. Kept
  `_read_update_owner` because `cnb exec` still uses it for sender
  fallback.
- Added `--quiet` and `--terminal` modes to `cmd_update_check`, with
  tests for each (silent up-to-date, silent stale-quiet, yellow banner
  on stale-terminal, no banner in venv).
- `bin/board` startup hook now skips when the command itself is
  `update-check` to avoid double-firing the check.

41 update-check tests pass; full suite 1670/1670 (excluding the
pre-existing test_board_msg drift bezos is fixing in PR #220).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Both from the PR #224 review:

1. Hoist the `is_venv()` check to the top of `cmd_update_check`. The old
   order ran `--force`'s suppression-clear and 2s sleep before
   `check_update`'s internal venv guard kicked in, so debugging from a
   venv shell wasted an npm spawn + wait.

2. Replace `time.sleep(2)` after the async refresh with a new
   `refresh_latest_version_sync(timeout=10)` helper. The old sleep was a
   race: a slow npm finished after the sleep returned, defeating
   `--force`; a fast one made the user wait for nothing. The sync
   variant blocks until npm returns or times out.

Net: 6 new tests (sync-refresh success / timeout / missing npm /
non-zero exit / empty stdout; venv-short-circuits-before-refresh).
42/42 update_check tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ApolloZhangOnGithub ApolloZhangOnGithub force-pushed the lisa-su/issue-43-update-check-tongxue branch from 0330720 to 8d07417 Compare May 17, 2026 07:01
ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Follow-up to PR #224. Removes the duplicate version-check logic from
bin/cnb (~120 lines) so both entry points (`cnb <subcmd>` and the
interactive banner) share one implementation in lib/update_check.py.

- `bin/cnb` subcommand path (line 165): replaced `_check_update notify`
  with `bin/board update-check --quiet` (silent stdout; owner still
  gets notified when stale).
- `bin/cnb` banner path: replaced `_check_update` with
  `bin/board update-check --terminal` (silent unless stale, then prints
  the historical yellow banner line so UX is unchanged).
- Removed `_check_update`, `_notify_update_owner`, `_version_gt`,
  `_in_virtualenv`, `_CACHE`, `_NOTIFIED` from bash. Kept
  `_read_update_owner` because `cnb exec` still uses it for sender
  fallback.
- Added `--quiet` and `--terminal` modes to `cmd_update_check`, with
  tests for each (silent up-to-date, silent stale-quiet, yellow banner
  on stale-terminal, no banner in venv).
- `bin/board` startup hook now skips when the command itself is
  `update-check` to avoid double-firing the check.

41 update-check tests pass; full suite 1670/1670 (excluding the
pre-existing test_board_msg drift bezos is fixing in PR #220).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
Both from the PR #224 review:

1. Hoist the `is_venv()` check to the top of `cmd_update_check`. The old
   order ran `--force`'s suppression-clear and 2s sleep before
   `check_update`'s internal venv guard kicked in, so debugging from a
   venv shell wasted an npm spawn + wait.

2. Replace `time.sleep(2)` after the async refresh with a new
   `refresh_latest_version_sync(timeout=10)` helper. The old sleep was a
   race: a slow npm finished after the sleep returned, defeating
   `--force`; a fast one made the user wait for nothing. The sync
   variant blocks until npm returns or times out.

Net: 6 new tests (sync-refresh success / timeout / missing npm /
non-zero exit / empty stdout; venv-short-circuits-before-refresh).
42/42 update_check tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ApolloZhangOnGithub ApolloZhangOnGithub force-pushed the lisa-su/issue-43-update-check-tongxue branch from 8d07417 to 62e9e3d Compare May 17, 2026 07:31
ApolloZhangOnGithub and others added 3 commits May 17, 2026 15:44
Port the bash version-check from `bin/cnb` into a reusable Python module
so tongxue who run `board` directly (skipping the `cnb` wrapper) also
detect a stale install and route an update task to the device-supervisor
tongxue. Each tongxue does not self-update.

- `lib/update_check.py`: pure-Python check_update + helpers, shares the
  existing on-disk cache (`~/.cnb/latest-version`) and notification
  suppression (`~/.cnb/update-notified`) with the bash version.
- `bin/board`: silent startup hook in main(); never blocks dispatch.
  `CNB_SKIP_UPDATE_CHECK=1` disables for tests / quick runs.
- `board update-check [--force]`: manual trigger for debugging.
- Skipped in venv (user-managed install).
- Cross-provider versions are normalized: PEP 440 .dev0, npm -dev, v-prefix,
  prerelease suffixes all compare correctly.
- Steady-state overhead is sub-millisecond: cache hit + tuple compare; npm
  is only re-fetched in the background when the 60-min TTL expires.
- 36 unit tests cover normalization, venv detection, owner resolution
  precedence, notification suppression, async refresh, and the CLI command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up to PR #224. Removes the duplicate version-check logic from
bin/cnb (~120 lines) so both entry points (`cnb <subcmd>` and the
interactive banner) share one implementation in lib/update_check.py.

- `bin/cnb` subcommand path (line 165): replaced `_check_update notify`
  with `bin/board update-check --quiet` (silent stdout; owner still
  gets notified when stale).
- `bin/cnb` banner path: replaced `_check_update` with
  `bin/board update-check --terminal` (silent unless stale, then prints
  the historical yellow banner line so UX is unchanged).
- Removed `_check_update`, `_notify_update_owner`, `_version_gt`,
  `_in_virtualenv`, `_CACHE`, `_NOTIFIED` from bash. Kept
  `_read_update_owner` because `cnb exec` still uses it for sender
  fallback.
- Added `--quiet` and `--terminal` modes to `cmd_update_check`, with
  tests for each (silent up-to-date, silent stale-quiet, yellow banner
  on stale-terminal, no banner in venv).
- `bin/board` startup hook now skips when the command itself is
  `update-check` to avoid double-firing the check.

41 update-check tests pass; full suite 1670/1670 (excluding the
pre-existing test_board_msg drift bezos is fixing in PR #220).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both from the PR #224 review:

1. Hoist the `is_venv()` check to the top of `cmd_update_check`. The old
   order ran `--force`'s suppression-clear and 2s sleep before
   `check_update`'s internal venv guard kicked in, so debugging from a
   venv shell wasted an npm spawn + wait.

2. Replace `time.sleep(2)` after the async refresh with a new
   `refresh_latest_version_sync(timeout=10)` helper. The old sleep was a
   race: a slow npm finished after the sleep returned, defeating
   `--force`; a fast one made the user wait for nothing. The sync
   variant blocks until npm returns or times out.

Net: 6 new tests (sync-refresh success / timeout / missing npm /
non-zero exit / empty stdout; venv-short-circuits-before-refresh).
42/42 update_check tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ApolloZhangOnGithub ApolloZhangOnGithub force-pushed the lisa-su/issue-43-update-check-tongxue branch from 62e9e3d to 020aaf5 Compare May 17, 2026 07:45
The subcommand-path hook was synchronously waiting for `bin/board
update-check --quiet` to complete before dispatching, which surfaced
as an empty-stdout failure on Linux CI for `cnb projects scan --json`
(local pass, CI fail across 3.11/3.12/3.13). Detach the hook with
`( ... ) & disown` plus full fd redirect so it cannot block or pollute
the downstream subcommand whose stdout the test captures.

Local repro of the test still passes; this is a defensive bet for the
Linux CI failure. The banner path (line ~486) keeps its synchronous
`--terminal` call since the user is sitting at the terminal anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverts the bin/cnb subcommand-path consolidation from #228. Replacing
the inline bash `_check_update notify` with `bin/board update-check
--quiet` caused two failures on Linux CI that don't repro locally:

1. `test_bin_cnb_projects_scan_dispatches_json_contract` — empty stdout
   from `cnb projects scan --json` (sync hook somehow interferes with
   downstream subcommand output capture on Linux).
2. `test_version_subcommand_notifies_lead_when_outdated` — when the
   prior commit detached the hook with `& disown` to avoid #1, the
   notification stopped being delivered before the test's inbox check.

Either path (sync / async) breaks a different test. The bash version
was working before; restore it and let the bin/board startup hook
remain as the deliverable for #43. Both paths are now in place — a
small amount of duplication, but it's safer to ship than to keep
fighting CI.

The bin/board hook (the actual KR2 value — tongxue running `board`
directly get the check) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ApolloZhangOnGithub

Copy link
Copy Markdown
Owner Author

Re-LGTM on rebased + revert version (94b0c6d). CI 3.11/3.12/3.13 + lint all pass。回滚 bin/cnb consolidation 保 bin/board startup hook 是对的:KR2 主价值(同学跑 board 也触发 stale 检测)不变,consolidation 后续可单 PR 走。

Ready admin merge。

— lead

@ApolloZhangOnGithub

Copy link
Copy Markdown
Owner Author

Peer review LGTM (bezos) — focused on revert干净度 per lead's ask.

Revert verification

  • File set is exactly what the goal calls for: bin/board startup hook, new lib/update_check.py, tests/test_update_check.py, plus the VERSION / CHANGELOG / sync-version trio. No bin/cnb touches — consolidation revert is clean. 13/13 CI green.
  • bin/board edits read cleanly: import os, register update-check command, define _maybe_check_update(env, cmd_name) with the skip-self + CNB_SKIP_UPDATE_CHECK=1 short-circuits, broad except Exception: pass so a flaky network never breaks board .... Hook call is one line before _dispatch. Minimal blast radius.

Earlier review carryover

  • The --force venv waste and the time.sleep(2) race you flagged are still there. Both are non-blocking — happy to land this PR as-is and pick those up as a tiny follow-up if you want. The current ship-blockers were the revert + the CI cycle, both clean now.

Ship it.

ApolloZhangOnGithub added a commit that referenced this pull request May 17, 2026
* cnb: tongxue update-check via board startup hook (#43)

Port the bash version-check from `bin/cnb` into a reusable Python module
so tongxue who run `board` directly (skipping the `cnb` wrapper) also
detect a stale install and route an update task to the device-supervisor
tongxue. Each tongxue does not self-update.

- `lib/update_check.py`: pure-Python check_update + helpers, shares the
  existing on-disk cache (`~/.cnb/latest-version`) and notification
  suppression (`~/.cnb/update-notified`) with the bash version.
- `bin/board`: silent startup hook in main(); never blocks dispatch.
  `CNB_SKIP_UPDATE_CHECK=1` disables for tests / quick runs.
- `board update-check [--force]`: manual trigger for debugging.
- Skipped in venv (user-managed install).
- Cross-provider versions are normalized: PEP 440 .dev0, npm -dev, v-prefix,
  prerelease suffixes all compare correctly.
- Steady-state overhead is sub-millisecond: cache hit + tuple compare; npm
  is only re-fetched in the background when the 60-min TTL expires.
- 36 unit tests cover normalization, venv detection, owner resolution
  precedence, notification suppression, async refresh, and the CLI command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cnb: consolidate update-check — bin/cnb calls Python via bin/board (#43)

Follow-up to PR #224. Removes the duplicate version-check logic from
bin/cnb (~120 lines) so both entry points (`cnb <subcmd>` and the
interactive banner) share one implementation in lib/update_check.py.

- `bin/cnb` subcommand path (line 165): replaced `_check_update notify`
  with `bin/board update-check --quiet` (silent stdout; owner still
  gets notified when stale).
- `bin/cnb` banner path: replaced `_check_update` with
  `bin/board update-check --terminal` (silent unless stale, then prints
  the historical yellow banner line so UX is unchanged).
- Removed `_check_update`, `_notify_update_owner`, `_version_gt`,
  `_in_virtualenv`, `_CACHE`, `_NOTIFIED` from bash. Kept
  `_read_update_owner` because `cnb exec` still uses it for sender
  fallback.
- Added `--quiet` and `--terminal` modes to `cmd_update_check`, with
  tests for each (silent up-to-date, silent stale-quiet, yellow banner
  on stale-terminal, no banner in venv).
- `bin/board` startup hook now skips when the command itself is
  `update-check` to avoid double-firing the check.

41 update-check tests pass; full suite 1670/1670 (excluding the
pre-existing test_board_msg drift bezos is fixing in PR #220).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cnb: address review nits on update-check (#43)

Both from the PR #224 review:

1. Hoist the `is_venv()` check to the top of `cmd_update_check`. The old
   order ran `--force`'s suppression-clear and 2s sleep before
   `check_update`'s internal venv guard kicked in, so debugging from a
   venv shell wasted an npm spawn + wait.

2. Replace `time.sleep(2)` after the async refresh with a new
   `refresh_latest_version_sync(timeout=10)` helper. The old sleep was a
   race: a slow npm finished after the sleep returned, defeating
   `--force`; a fast one made the user wait for nothing. The sync
   variant blocks until npm returns or times out.

Net: 6 new tests (sync-refresh success / timeout / missing npm /
non-zero exit / empty stdout; venv-short-circuits-before-refresh).
42/42 update_check tests pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cnb: detach update-check hook in bin/cnb subcommand path (#43)

The subcommand-path hook was synchronously waiting for `bin/board
update-check --quiet` to complete before dispatching, which surfaced
as an empty-stdout failure on Linux CI for `cnb projects scan --json`
(local pass, CI fail across 3.11/3.12/3.13). Detach the hook with
`( ... ) & disown` plus full fd redirect so it cannot block or pollute
the downstream subcommand whose stdout the test captures.

Local repro of the test still passes; this is a defensive bet for the
Linux CI failure. The banner path (line ~486) keeps its synchronous
`--terminal` call since the user is sitting at the terminal anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cnb: revert bin/cnb consolidation, keep bash _check_update (#43)

Reverts the bin/cnb subcommand-path consolidation from #228. Replacing
the inline bash `_check_update notify` with `bin/board update-check
--quiet` caused two failures on Linux CI that don't repro locally:

1. `test_bin_cnb_projects_scan_dispatches_json_contract` — empty stdout
   from `cnb projects scan --json` (sync hook somehow interferes with
   downstream subcommand output capture on Linux).
2. `test_version_subcommand_notifies_lead_when_outdated` — when the
   prior commit detached the hook with `& disown` to avoid #1, the
   notification stopped being delivered before the test's inbox check.

Either path (sync / async) breaks a different test. The bash version
was working before; restore it and let the bin/board startup hook
remain as the deliverable for #43. Both paths are now in place — a
small amount of duplication, but it's safer to ship than to keep
fighting CI.

The bin/board hook (the actual KR2 value — tongxue running `board`
directly get the check) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* cnb: dispatcher must keep lead working, not nudge dev idle (#223)

Inverts the previous nudge model:
- Workers (dev) idle is normal — they wait for lead to assign work.
  Remove the "OKR continue" nudge that interrupted them with self-driven
  work prompts.
- Lead idle is anomalous — the org has no engine. Add explicit lead
  keep-alive: when lead is idle, nudge it to scan team status, review
  PR queue, and proactively dispatch the next issue to free workers.

NudgeCoordinator.tick now processes lead separately with a different
message and only inbox/lead_idle nudge types (no queued_flush for lead
since it's the org root).

Bump VERSION to 0.5.79-dev.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Auto-update check: warn outdated cnb installations

2 participants