knowledge: non-interactive CLI stdin, LLM response completeness, externally-owned defaults - #12
Open
dch0202-rsquare wants to merge 3 commits into
Conversation
…up precondition, function_call, routing row)
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.
Knowledge flush — 3 insight(s)
Drained from
~/.dev-loop/queue(3 pending candidates, harvested 2026-07-31 fromsessions in
~/.claude/tmpandmeetingSummary). Result: 3 new pages (one of themopening a new
backend/common/integrationscategory) plus one merge-edit into anexisting infrastructure page. No auto-merge.
Verified best-practice
1. A non-interactive flag does not stop a CLI reading stdin
Claim. When invoking a prompt-capable CLI from a script/CI/agent harness, pass the
non-interactive flag and detach fd 0 (
</dev/nullornohup); if it still hangs,split client-vs-server by whether the request appears in the server's access log.
Sources checked (all fetched live, 2026-07-31):
nohup— "If standard input is a terminal, redirect it so that terminal sessions do not
mistakenly consider the terminal to be used by the command. Make the substitute file
descriptor unreadable, so that commands that mistakenly attempt to read from standard
input can report an error." Documents this as a GNU extension with the portable form
nohup command 0>/dev/null— which is what makes the page's BSD edge case correct.ssh(1)—-n"Redirects stdin from /dev/null(actually, prevents reading from stdin). This must be used when ssh is run in the
background." Primary evidence that mature CLIs ship an explicit stdin-detach flag
because background invocation otherwise blocks.
gitdocs,GIT_TERMINAL_PROMPT— "If this Booleanenvironment variable is set to false, git will not prompt on the terminal (e.g., when
asking for HTTP authentication)." Second independent instance of a CLI shipping an
explicit opt-out for terminal prompting. (The doc does not state the default; an
earlier draft asserted "default is to prompt" as sourced — removed by cross-check.)
ssh_config—BatchMode=yes: "userinteraction such as password prompts and host key confirmation requests will be
disabled";
StrictHostKeyChecking=accept-newadds new host keys without permittingchanged ones. Added by cross-check:
ssh -ndetaches stdin but the same man page notesit "does not work if ssh needs to ask for a password or passphrase", so the prompt
channel needs its own directive.
Reproduction from the session:
pi 0.79.1 --toolsin the foreground hung twice(300s, 150s; 0 bytes written), while the LiteLLM gateway log showed zero requests from
that IP in the window — so the fault was local, not the model. The identical command
under
nohup(stdin/dev/null) completed a tool call immediately.confidence: verified — mechanism documented by three primary sources, plus a local
reproduction.
2. HTTP 200 from
/chat/completionsis not a complete answerClaim. Before using LLM output as an artifact, fail on
finish_reason == "length"and on blank
content; whencontentis blank and a reasoning field is populated,report that a reasoning model spent the output budget rather than publishing the
reasoning text.
Sources checked (all fetched live, 2026-07-31):
reasoning tokens "still occupy space in the model's context window and are billed as
output tokens"; truncation "might occur before any visible output tokens are produced,
meaning you could incur costs for input and reasoning tokens without receiving a
visible response"; detect via
status == incomplete/max_output_tokens; reserve≥25,000 tokens while calibrating. This is exactly the failure mode the candidate claimed.
—
finish_reason: "length"= "the maximum number of tokens specified in the requestwas reached"; the full set is five values —
stop,length,tool_calls,content_filter, and the deprecatedfunction_call. Both tool-calling values returnblank
contentby design, which is why the page carves them out of theblank-content failure path (the
function_callhalf was added by cross-check).— reasoning goes in
reasoning(renamed fromreasoning_content), final answer incontent.normalizes to
message.reasoning_content(+thinking_blocksfor Anthropic).The two gateways disagreeing on the field name is a fact the candidate did not contain;
it became an edge-case row ("check both keys before concluding no reasoning").
Reproduction from the session (2026-07-28, LiteLLM on dgx): alias
chat-defaultwith a9,317-token prompt returned HTTP 200,
finish_reason=length,content0 chars,reasoning_content8,173 chars; the same request to the non-reasoningcoder-fastreturned
finish=stopwith 2,418 complete chars.confidence: verified — the mechanism and every field name are documented; the
measurement matches.
3. Defaults naming repo-external resources need a re-check at merge time
Claim. When a default names a resource the repo does not own, re-query the owner's
catalog at review/merge time and resolve the name at startup.
Sources checked (all fetched live, 2026-07-31):
shutdown date a model "will no longer be accessible"; notice is ≥6 months (GA),
≥3 months (specialized variants), and as little as 2 weeks for preview models. That
last number is what makes "verified in the PR body" a perishable claim, and it is now
the page's rule for tracking shutdown dates.
GET /v1/models—"Lists the currently available models, and provides basic information about each one
such as the owner and availability." Confirms the review-time check is a real,
documented endpoint.
the proxy's own
/v1/modelsreports what is actually available behind that gateway(
check_provider_endpoint: truefor wildcards). This corrected the candidate: thecatalog to query is the gateway's, not the upstream provider's.
Field evidence: PR #15 review (2026-07-28) — default summary alias
dgxb/kananahaddisappeared from the LiteLLM catalog and returned 400, while the PR's own end-to-end
measurement (7/12, 857 chars in 11s) had been true when written; code, tests, and build
all still passed.
confidence: verified — the retirement mechanism and both catalog endpoints are
documented; the incident supplies the review-timing lesson.
Existing-layer check
Pages read in full before writing anything:
INDEX.md,AGENTS.md,templates/page.md,skills/wiki-ingest/SKILL.mdInstead ofpairing, ≤120 body lines, sourced frontmatter)wiki/platforms/index.md+processes/background-services.mdrelated:added both wayswiki/platforms/shells/portable-shell-scripts.md,environment/path-resolution.md,toolchains/version-management.md,tools/bsd-vs-gnu-cli.mdwiki/platforms+wiki/debuggingforstdin|/dev/null|tty|interactive: every hit is about non-interactive shells not loading rc files (PATH/shims), never about a blocked stdin read. Confirmed gap. Linked to bsd-vs-gnu-cli for the macOStimeoutgap, and to path-resolution in an edge casewiki/debugging/index.md(+ methodology/signals rows)debugging-methodology-hypothesis-testingrather than duplicating itwiki/backend/index.mdand everybackend/common/**load-when lineapi-design/*governs the API you publish;reliability/timeouts-and-retriesgoverns transport (its "never retry 400" row is why the new page frames alengthretry as a new request — cross-linked). Confirmed gapbackend/node/boundaries/runtime-validation.md,backend/python/boundaries/runtime-validation.mdwiki/infrastructure/config/environment-config.mdrelated:link;last_verifiedbumped to 2026-07-31wiki/qa/process/release-gates.mdgrep -rn 'llm|openai|finish_reason|model alias' wiki/security/secrets-in-codeon pasting secrets into an LLM). No prior LLM-integration coverage anywherelog.mdcontradictionor overlapping ingest for these cases. The 2026-07-11 gap entry proposingcommon/ingestion/external-source-sync.mdis a different case (idempotent re-ingestion) and is left untouchedConflicts found: none. Nothing in the wiki contradicts these three directives.
Self-lint before commit (re-run after the cross-check fixes): all 3 new pages are 66–77
lines (limit 120); zero banned vague
qualifiers (
usually|generally|consider|might want|as appropriate|typically|probably|ideally);all 11
related:/inline page ids resolve to exactly one existing page each.Routing decision
platforms/processes/ new pagenon-interactive-cli-invocation.md(platforms-processes-non-interactive-cli-invocation)processesalready owns "how a process is started and kept alive outside an interactive session", and this is the sibling case (how it is invoked). Domain choice — the artifact changed is a shell/CI invocation, and the OS-level fact (a terminal fd 0 blocks a read) is platforms' subject; debugging is linked, not duplicatedbackend/ NEW categorycommon/integrations/llm-response-completeness.mdcommon/(notnode//python/) because the decision is language-agnostic;applies_to: [openai-compatible]scopes itbackend/common/integrations/externally-owned-defaults.mdinfrastructure-config-environment-configandqa-process-release-gatesCross-check
Cross-Check: independent headless
claude -p --permission-mode planadversarial review ofall three pages + this report returned VERDICT: FAIL with 12 findings; 8 were confirmed
against the primary sources and applied, 2 were already clean, 2 were declined with reasons.
Applied:
ssh -nwas miscategorised as a prompt-channel control. ssh(1) itself says-n"does not work if ssh needs to ask for a password or passphrase" — it is a stdin detach.
Moved to directive 1; directive 2 now uses
-o BatchMode=yes(+StrictHostKeyChecking=accept-new), verified against ssh_config and cited.this page's own CI/hook triggers fd 0 is often a pipe, so nohup redirects nothing. The
page now states that
</dev/nullis the unconditional guarantee.proxy failures also produce no access-log entry. Row and
Instead ofrow widened to"pre-log rejection", with
curl -vas the discriminator.function_callalso returns blankcontentby design and would have hitthe fail path. Added to the carve-out.
finish_reasonenumeration was incomplete (4 of 5) in both the page's Sourcesbullet and this report. Corrected in both.
GIT_TERMINAL_PROMPT"default is to prompt" was inference presented as sourced — thedoc states only the false case. Removed.
wiki/backend/index.md's concern-first subtree row was not updated — routing protocolstep 2 reads that row before the category tables, so an agent would have landed on
reliabilityinstead of the newintegrationscategory. Row extended (the real routingdefect in this batch).
environment-config'slast_verifiedbump was unearned — a one-row edge-case additiondoes not re-verify its three 12factor sources. Reverted to 2026-07-10 so lint's staleness
clock is not reset.
Also applied for format: four anti-patterns phrased as negations inside
Do this/Edge casestables were restated positively (AGENTS.md keeps negations in
Instead of), andexternally-owned-defaults' pure-pointer row and startup directive were given app-sidesubstance.
Declined, with reasons: (a) splitting
externally-owned-defaultsby trigger — thecorpus norm (
environment-config,release-gates) is several related triggers plus anumbered list and a case table on one page, and the three triggers here are one case seen
at review time, boot time, and failure time; (b) relocating it to
infrastructure/config— its primary trigger is reviewing application-code defaults and its resolution rule lives
in the client wrapper, so
backendowns it; the config-shape half is delegated by link andenvironment-configcarries the reciprocal row.Plumbing updated:
wiki/backend/index.md(new### integrationssection, 2 rows, plus theconcern-first subtree row),
wiki/platforms/index.md(1 row underprocesses),INDEX.md(both domains' "routehere when" lines extended so the new cases are reachable from the root map),
log.md(2
ingest+ 2reviseentries, the second recording the cross-check), andbackground-services/environment-configrelated:back-links.Queue rows for these 3 candidates are retired to
~/.dev-loop/queue/.processed.jsonlonce this PR is opened.
Decision Log (AI 생성)
의도 — 무엇을 / 왜
confidence: verified로 확정했고, 후보에 없던 사실(게이트웨이별reasoningvsreasoning_content필드명 차이, 게이트웨이 자체 카탈로그를 조회해야 함)은 검증 과정에서 발견해 반영.infrastructure/config/environment-config의 "필수 키엔 default 없음" 규칙과 형제 케이스라 그 페이지에 edge case 1행 + 양방향related로 연결하고, 본체는 리뷰시점 체크라는 별개 트리거이므로 별 페이지로 분리.backend/common/integrations를 새 카테고리로 신설 — 기존 8개 공통 카테고리는 "내가 발행하는 API"(api-design)와 "전송"(reliability)만 다루고, 외부 소유 서비스의 응답 스펙·이름 카탈로그에 의존하는 것을 담을 자리가 없었다.배제한 대안 — 무엇을 안 했나 / 왜
debugging에 두기 — 클라이언트/서버 가르기가 진단이라 후보였지만, 바뀌는 산출물이 호출 방식이고 "터미널 fd 0은 읽기를 막는다"는 OS 사실이라platforms. 진단 단계는debugging-methodology-hypothesis-testing링크로 처리(중복 금지).qa/process/release-gates에 병합 — release-gates는 의도적으로 릴리즈마다 동일한 고정 체크리스트인데 이건 특정 diff 유형에 걸리는 per-PR 체크라 게이트를 희석시킴. 링크만.infrastructure/config로 이전(적대검증 제안) — 거절. 1차 트리거가 애플리케이션 코드 default 리뷰이고 해소 지점이 호출을 만드는 client wrapper라backend소유가 맞음. config 형태는 링크로 위임.last_verified일괄 bump — 12factor 출처를 재검증하지 않았으므로environment-config는 2026-07-10 유지(적대검증 지적 반영).리뷰어가 볼 곳 — 신뢰성 판단 포인트
wiki/platforms/processes/non-interactive-cli-invocation.md:26-38—ssh -n(stdin 분리)과BatchMode=yes(프롬프트 차단)를 분리한 부분. 1차 초안은-n을 프롬프트 차단으로 잘못 분류했고 적대검증이 man page 인용으로 잡음.:45,:64— "서버 로그에 요청 없음"의 결론 범위. DNS/TLS/프록시 선차단을 포함하도록 약화했는데, 이 정도가 적정한지 판단 필요.wiki/backend/common/integrations/llm-response-completeness.md:31-38— 수용/실패 판정 테이블. 특히tool_calls/deprecatedfunction_call에서 blank content가 정상인 carve-out.wiki/backend/index.md:8— concern-first subtree 행. 라우팅 프로토콜 2단계가 카테고리 테이블보다 먼저 읽는 줄이라, 여기 누락되면 새 카테고리에 도달하지 못한다(적대검증이 잡은 유일한 실제 라우팅 결함).wiki/backend/common/integrations/externally-owned-defaults.md도메인 선택 — 위 "배제한 대안"의 판단이 맞는지가 이 PR에서 가장 논쟁적인 지점.log.md마지막 2줄 — 적대검증 결과와 거절 항목을 기록으로 남긴 부분.