fix(cli): skip DB probe when nested subcommand requests --help - #726
fix(cli): skip DB probe when nested subcommand requests --help#726syf2211 wants to merge 2 commits into
Conversation
Detect --help in remaining Click args during TjGroup/TjCommand invoke and set a context flag so the root callback skips open_db(). Fixes nested invocations like `tj optimize downsize --help` failing with a database-lock error while tj serve is running. Fixes Metabuilder-Labs#580.
|
| Filename | Overview |
|---|---|
| tokenjam/cli/tj_status.py | Detects inherited help-option tokens during command invocation and records the help-only state in the shared Click context. |
| tokenjam/cli/main.py | Routes help-only invocations through the existing no-database initialization path. |
| tests/integration/test_cli.py | Verifies representative nested help invocations complete without calling open_db. |
Sequence Diagram
sequenceDiagram
participant User
participant Invoke as TjCommand.invoke
participant Root as cli callback
participant Click
User->>Invoke: tj group command --help
Invoke->>Invoke: Detect help token
Invoke->>Root: Set shared skip-DB marker
Root->>Root: Load config without open_db()
Root->>Click: Continue command dispatch
Click-->>User: Render nested command help
Reviews (2): Last reviewed commit: "Merge branch 'main' into fix/group-subco..." | Re-trigger Greptile
anilmurty
left a comment
There was a problem hiding this comment.
Approving. I reproduced the original failure against a genuinely held DuckDB write lock (second process on an r/w connection, [api] port pointed at a dead port so the API fallback couldn't mask it) and confirmed the fix across the tree.
It fixes more than the issue claimed. #580 says top-level tj <group> --help is unaffected — it wasn't. tj cost --help and tj optimize --help were broken too. So this covers --help for every command not already in no_db_commands, at any depth. The no_db_commands set and the eager tj --help / --version paths are unchanged, as expected.
The seam is right: cli is a TjGroup, which resolves invoke to TjCommand.invoke, so the hook runs before the root callback fires and before the sub-context is built — the only point where the flag can be set in time. There's no separate TjGroup.invoke needing the same patch.
The detail worth calling out: reading ctx.help_option_names off the context chain rather than hardcoding "--help". -h isn't wired in this app today, and this picks it up for free the day someone adds context_settings. That's the kind of choice that stops a fix rotting.
Tests are load-bearing — reverting only the two source hunks fails all three parametrized cases — and they use the open_db(side_effect=AssertionError) pattern CLAUDE.md prescribes.
Two nits, non-blocking:
- The scan can trip on a token Click will consume as an option value.
tj loop annotate SID --note --helpsets the skip flag, runs withdb=None, and dies withAttributeError: 'NoneType' object has no attribute 'execute'. It needs the token to be exactly--help, and I checked that no command in the tree usesignore_unknown_options/allow_extra_args, so there's no pass-through command legitimately forwarding a--helpto a subprocess — which was my main worry and it's clean. Nonsense input, nothing written on the crash path. Filing the general form as a follow-up rather than holding this. - Setting the flag unconditionally (
ctx.obj["_skip_db_for_help"] = self._tokens_request_help(ctx)) rather than only onTruewould make it self-clearing if a long-lived process ever reused oneobjdict. Safe, since the leaf'sinvokeruns after the root callback has read it.
Test gaps worth a line each if you're already in here: nothing asserts the inverse — that a non-help invocation still opens the DB, which is the direction that would actually break the product — and nothing pins the newly-fixed single-level shape (tj cost --help), which is the broader win.
Summary
Skip the DuckDB probe in the root CLI callback when the invocation requests
--help, so nested commands liketj optimize downsize --helpwork whiletj serveholds the write lock.Motivation
Fixes #580. Running
--helpon a group subcommand failed with "Database is locked" whenever the daemon was running, becauseopen_db()ran before Click rendered help.Changes
ctx.argsduringTjCommand.invokeand setctx.obj["_skip_db_for_help"].open_db()in the rootcli()callback when that flag is set (same path asno_db_commands).optimize downsize,backfill langfuse, andloop annotate.Tests
All passed.
Notes
--helpstill probe the DB as before.tj <cmd> --helpunder the same lock condition.