Repository navigation
fix(cli): asking a command what it does must not run it - #42
Merged
Merged
Conversation
…h limit was hit
Two defects found in real use after 1.7.0. Neither is in the write path.
`jam setup --help` did not print help. It ran the setup wizard, re-registered
JAM with two hosts, and moved the recorded registration from one version to
another while the person was reading what they thought was documentation.
The cause was narrow: `--help` was recognised only as the command itself, so
`help`, `--help` and `-h` worked at the top level and nowhere else. Every
subcommand carrying the flag fell through to its handler — setup, update,
refresh, uninstall, runtime use, auth login, auth logout, and both write
commands. The report named setup because that is the one somebody typed.
One guard in the dispatcher rather than a flag per command: the property belongs
to the dispatcher, and a per-command list is a list that will be incomplete the
first time somebody adds a command. The launcher needs its own, because it
answers the runtime group itself and never reaches the dispatcher — `runtime
use --help` was writing the runtime selection.
The second is about what "incomplete" means. Three different situations were
collapsing into two codes that named the wrong cause:
```text
preview stops at page one was PARTIAL_API_RESPONSE — reads as "Jira gave
us less than we asked for". It gave us exactly
what we asked for
complete walk hits the page cap was OUTPUT_BUDGET — reads as "we dropped
something to fit a size". Nothing was dropped;
the walk stopped
result over the token budget already correct: complete stays true and the
size goes in notes
```
PREVIEW_LIMIT and PAGINATION_LIMIT now name those two, leaving OUTPUT_BUDGET for
payload actually dropped and PARTIAL_API_RESPONSE for Jira answering with less
than it was asked. `moreAvailable` and `returnedCount` join the metadata, which
is what a caller needs to decide whether to widen — and no more than that. The
continuation token still never leaves JAM; handing it out would move pagination
to the caller, which is the boundary this owns. JQL is passed through unchanged;
JAM does not narrow a query on the caller's behalf.
Nothing about the write path moves. plan → apply → read-back verify is
untouched, UNCERTAIN still refuses re-entry on the same plan, and no command
gained a step. A caller that never used a help flag and never read `reason` sees
no difference at all.
Regression: 582 pass / 0 fail (was 575). The help contract is asserted across
every mutating dispatcher path with both flag spellings, and asserts that the
mutating modules were not called — not merely that something was printed.
Co-Authored-By: Claude Opus 5 <[email protected]>
Merged
5 tasks done
colosair
added a commit
that referenced
this pull request
Sep 10, 2026
… which limit was hit (#43) Version, lockfile and release note for 1.8.0. No behaviour is added here — the change itself merged as #42. The three packages move to 1.8.0 in lockstep and depend on each other at that exact version. Contents of the release: - `--help` on any subcommand prints usage instead of running the command. The guard is in the dispatcher, ahead of the switch, so it covers every mutating path rather than a list that would go stale. - `PREVIEW_LIMIT` and `PAGINATION_LIMIT` replace two misleading reasons, and `moreAvailable` / `returnedCount` say what a caller needs to decide what to do next. Gate: npm run release:verify build · test · release:check · smoke — all green Recorded as not verified in the note: the reported `jam setup --help` incident was not reproduced (doing so would change this machine's registration again), the two new meta fields are optional in the type rather than enforced, and usage still goes to stdout from the server and stderr from the launcher. Published acceptance runs after release.yml, before the tag. Co-authored-by: Claude Opus 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
요약
실기계에서
jam setup --help가 도움말을 찍지 않고 setup 마법사를 돌렸다. 두 호스트에 JAM 을 재등록했고 기록된 등록을 한 판번호에서 다른 판번호로 옮겼다 — 사람이 문서라고 생각한 것을 읽는 동안에. 그 구멍과, 같은 성격의 완전성 표시 오류를 함께 닫는다.baseline: JAM 1.7.0.
변경 사항
A. 명령에게 무엇을 하는지 묻는 것이 그것을 돌리는 것과 같아서는 안 된다 (P0)
packages/server/src/cli-entry.ts—--help/-h를 dispatcher 앞에서 가로챈다. 원인은 좁고 여파는 좁지 않았다:--help를 명령 그 자체로만 알아봤기 때문에, 그것을 달고 온 모든 하위 명령이 자기 handler 로 그대로 떨어졌다. dispatcher 가 닿을 수 있는 모든 변경 경로가 거기 포함된다.packages/launcher/src/cli.ts— launcher 는runtime을 dispatcher 로 넘기기 전에 자기가 답하므로 같은 문을 따로 세웠다.명령별 목록을 만들지 않았다. 그런 목록은 누군가 명령을 하나 추가하는 첫 순간에 낡는다.
B. 완전성은 회수에 대한 것이지 출력 크기에 대한 것이 아니다
세 가지 다른 상황이 두 개의 틀린 코드로 접혀 있었다.
앞의 둘은 아닌 실패로 읽힌다. "partial API response" 는 Jira 가 요청보다 적게 답했다는 뜻이고, preview 는 호출자가 요청한 그대로를 받은 것이다. "output budget" 은 크기에 맞추려고 무언가를 버렸다는 뜻인데, page cap 은 읽기가 얼마나 멀리 걸었는가의 문제이고 아무것도 잘리지 않았다.
domain/completeness.ts—IncompleteReason에PREVIEW_LIMIT·PAGINATION_LIMIT추가.CompletenessMeta에moreAvailable·returnedCount추가.application/search-issues.ts— 둘을 가려 세우고, 두 새 필드를 항상 채운다.세 번째는 이미 옳았고 그대로 고정했다 — 결과는 완전하면서 동시에 원하지 않을 만큼 클 수 있고, 그렇게 말하는 것이
complete를 false 로 만들어서는 안 된다.pagination 은 JAM 안에 남는다. continuation token 은 호출자에게 나가지 않는다 — 그것을 내보내면 pagination 이 agent 의 일이 되고, 이 경계는 정확히 그것을 막으려고 있다.
테스트 / 검증
npm test— 582 pass · 0 failnpm run release:check— cleantests/unit/help-no-side-effect.test.ts(31, 신규) — 변경을 일으키는 모든 dispatcher 경로 ×--help/-h. 설정·등록·자격증명·Jira 를 바꾸는 모듈 전부를 mock 으로 세우고 호출되지 않았음을 단언한다. 도움말 없이 부르면 그대로 도는 것도 함께 고정tests/unit/completeness-semantics.test.ts(7, 신규) — 네 상황을 각각, 그리고 두 가지가 동시에 참일 때 서로 섞이지 않는 것.continuation token 이 호출자에게 나가지 않는다·JQL 은 그대로 Jira 로 간다포함리뷰 포인트
setup --help하나지만 구멍은 dispatcher 에 있었다. 명령별 방어는 다음 명령이 추가될 때 조용히 빠진다.PREVIEW_LIMIT과PAGINATION_LIMIT을 가른 이유는 호출자의 다음 행동이 다르기 때문이다. 전자는scope="complete"로 다시 부르면 되고, 후자는 안전 상한에 닿은 것이라 질의를 좁혀야 한다. 한 코드로 두 상황을 말하면 어느 쪽 조언도 정확하지 않다.complete=true+ notes 조합을 그대로 뒀다. 크기 때문에complete를 뒤집으면 "읽기가 끝났다" 는 사실이 사라진다.미결 / 후속
--help경로에 한해 CLI 쪽만 닫았다.🤖 Generated with Claude Code