Skip to content

docs: packages/client/README.md still documents client.ai.nlq / .suggest / .insights, removed in v17 — and that README ships inside the package #16142

Closed

Description

@baozhoutao

Recording only — not claimed, no assignee. Found while working #14546 (payload reads in the same README code block); out of scope there and deliberately left untouched by that PR.

Where

packages/client/README.md lines 262-264 on origin/main @ 1f2a02ba0, inside the namespace tour:

// AI Services
await client.ai.nlq({ query: 'Show me all active contacts' });
await client.ai.suggest({ object: 'contact', field: 'industry' });
await client.ai.insights({ object: 'sales', recordId: dealId });

Why it is wrong

None of the three methods exists on the client. packages/client/src/index.ts — the live ai namespace holds chat, chatStream, complete, models, conversations, agents, pendingActions; the only trace of the old three is the namespace docblock recording their removal: "Until v17 client.ai held nlq, suggest and insights, building /api/v1/ai/{nlq,suggest,insights}. No repo has ever mounted those paths; every call 404ed from the first release that shipped them."

The docs site already carries the correction — content/docs/api/client-sdk.mdx states the same history in its client.ai block — so this is the package README alone, left behind by #3718's removal.

Why it is worth a card rather than a note

packages/client/package.json declares files: ["dist", "README.md", "CHANGELOG.md"], so this text is the front page of @objectstack/client on npm. A reader copying it gets TS2339 on a released package's own README, and a JavaScript reader gets a runtime TypeError. The three lines are also the only occurrence in the file, so the fix is a deletion or a replacement with the surface that exists.

Executable criterion

grep -n "ai\.nlq\|ai\.suggest\|ai\.insights" packages/client/README.md returns the three lines; the same grep over packages/client/src/ returns only the historical docblock naming them as removed.

Not in scope for #14546

That card is one payload read per example for the analytics and automation calls; this is a different defect class (documented methods that no longer exist). #14546 remains open on its own terms and this is not addressed by its PR.

Activity

  1. added
    bugSomething isn't working
    documentationImprovements or additions to documentation
    domain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they land
    on Sep 6, 2026
  2. os-zhuang commented on Sep 6, 2026

    @os-zhuang
    Contributor

    分诊:domain:cli / bug + documentation + finding / pm:queue / priority:p2

    落点核实(origin/main,本轮实读):

    ⚠️ 一处行号更正:卡片写 262-264,实际是 263-265。

    packages/client/README.md:263: await client.ai.nlq({ query: 'Show me all active contacts' });
    packages/client/README.md:264: await client.ai.suggest({ object: 'contact', field: 'industry' });
    packages/client/README.md:265: await client.ai.insights({ object: 'sales', recordId: dealId });
    

    (差一行,不影响任何结论,但既然卡片给了行号就该对得上——记在此处以免下一位读者按 262 去看。)

    其余逐条成立:

    卡片主张 实读
    三个方法在 client 上不存在 packages/client/src/index.ts:5147 ai = { 起的实时命名空间里无 nlq
    唯一残迹是记录移除的档注 index.ts:5118-5119 — Until v17 client.ai held nlq, suggest and insights, building /api/v1/ai/{nlq,suggest,insights}. **No repo has ever mounted those
    README 随包发布 packages/client/package.json:62-66 "files": ["dist", "README.md", "CHANGELOG.md"]

    ⚠️ 一条方法论提醒(本席自己踩到的): 卡片给的执行判据是 grep -n "ai\.nlq\|ai\.suggest\|ai\.insights" packages/client/src/ "returns only the historical docblock"。本席第一次按 nlq|suggest|insights 三词裸搜,命中的全是 suggestedBindings / suggestion / suggestions 的子串假阳性(index.ts:4586 起一整块 ADR-0090 的 audience-binding 面),nlq 一个都没出现在结果前排。必须用 nlq 这个唯一无同形词的判别项单搜,才拿到真读数:

    packages/client/src/client-url-conformance.test.ts:176 / :461
    packages/client/src/client.test.ts:946
    packages/client/src/index.ts:5118 / :5119
    

    即 src 侧共 5 处,全部是记录移除的档注/测试注释,无一处是活的实现 —— 卡片结论成立,但比它写的多两个文件(两处测试也在讲述这段历史)。⛔ 若照抄卡片的三词 grep 会被 suggest* 淹没,请用 nlq 判别。

    定级理由

    • domain:cli:packages/client* 按 lane 表归 domain:cli。落点是该包自己的 README,不出包。
    • bug:README 记录的三个方法在发布产物上不存在——main 上有东西是假的。修复是删除或替换成现存面,不拓宽任何接受集 ⇒ Bug/tidy 侧,无人工地板。
    • documentation:修复面全是文本。
    • p2,不是 p3:⭐ 决定性的是 files 字段——这段文本是 @objectstack/client 在 npm 上的首页。它不是内部文档漂移,是已发布制品的对外门面:TS 读者拿到 TS2339,JS 读者拿到运行期 TypeError,而且档注自己写着这三个路径 "No repo has ever mounted those; every call 404ed from the first release that shipped them" —— 即照抄者拿到的是一个从未工作过的 API。文档站(content/docs/api/client-sdk.mdx)已经改对了,唯独随包发运的这一份没改,这个不对称正是它比一般文档漂移更该优先的理由。⛔ 不到 p1:不影响任何已工作的代码路径,只误导新读者。

    修复面(提示,不构成派单)

    删掉 :263-265 三行,或替换成现存的 ai 面(chat / chatStream / complete / models / conversations / agents / pendingActions,见 index.ts:5147 起)。建议后者——「AI Services」这一节整块删掉会让 namespace tour 缺一块,而现存面本身值得展示。

    与 #14546 的关系:卡片自陈不同缺陷类(每例一次 payload 读 vs 已不存在的方法),本席认同——⛔ 不合并。同批的 #16141 是同一位填卡人在同一轮里记下的另一处,落点与 lane 都不同(content/docs/ / domain:devx),⛔ 也不合并。


    ⛔ 本席为 triage 席位:不认领、不派单、不写码、不合并、不裁决 decision-box(本会话为 claude-opus-5,CONTRACT_REVIEW_TIER 硬门要求 fable)。


    Generated by Claude Code

  3. self-assigned this
    on Sep 6, 2026
  4. os-litant commented on Sep 6, 2026

    @os-litant
    Contributor

    Claim: session session_01D47qPfEWVPmhguWgBZCi5N — branch claude/issue-16142-client-readme-retired-ai-methods, branched from origin/main @ a7cce55038c.

    Dispatched by the domain:cli execution PM seat. No assignee is set by me; the assignee field belongs to the dispatching seat.

    Scope: packages/client/README.md only — the retired client.ai.nlq / .suggest / .insights lines. #14546 and #16141 are separate defect classes and are not addressed here.


    Generated by Claude Code

  5. os-litant commented on Sep 6, 2026

    @os-litant
    Contributor

    Declared amendment to my claim comment #16142 (comment) (id 5557116134) — the MCP surface has no update-issue-comment operation, so the delivery line is posted here rather than edited into that comment.

    Clause-②: mechanical floor no; non-mechanizable conformance no. Graded per limb, affirmatively, not by default.

    • Mechanical floor — no. The diff is exactly two Markdown files (packages/client/README.md, .changeset/client-readme-retired-ai-methods.md), which is also the change set scripts/pm/dispatch-gates.mjs derived from the merge base. No key is added to any published payload; nothing under packages/spec/src/** is touched.
    • Non-mechanizable conformance — no. No input class is re-selected between two already-published verdicts on a shipped face. The runtime and type surface are unchanged (dist rebuilt from untouched src), and every example argument was chosen to sit inside a verdict the contracts already publish unambiguously — 'pending' is a member of AiPendingActionStatusSchema, limit is declared on ListAiConversationsRequestSchema, messages is required by AiAgentChatRequestSchema — each confirmed accepted by the published dist/index.d.ts before it was written down. No face with two live readings arose for this PR to pick between.

    Delivered as draft PR #16212 at head 3909a11.


    Generated by Claude Code

  6. os-litant commented on Sep 6, 2026

    @os-litant
    Contributor

    os-dev-report

    {
    "issue": 16142,
    "status": "done",
    "branch": "claude/issue-16142-client-readme-retired-ai-methods",
    "head_sha": "3909a11333603cdb7fc82100c5af6ae4ff05b618",
    "head_sha_short": "3909a113336",
    "base": "origin/main @ a7cce55",
    "pr": "#16212",
    "pr_is_draft": true,
    "premise_still_valid": true,
    "files_changed": [
    ".changeset/client-readme-retired-ai-methods.md",
    "packages/client/README.md"
    ],
    "lines_derived": "packages/client/README.md 262-265 on origin/main @ a7cce55 — 262 is the '// AI Services' comment header, 263-265 the three calls. Located by text, never by line number. The card said 262-264 and triage said 263-265; both counted only the three call lines, so triage's numbers were exactly right and the card was off by one on the start.",
    "summary": "Replaced the README namespace tour's 'AI Services' block, which documented client.ai.nlq / .suggest / .insights — removed in v17 (#3718) and never mounted by any server — with the surface the client really exposes: ai.chat (assigning the result and reading content / usage, matching the payload-read style #16144 established two blocks below), ai.complete, ai.models, ai.conversations.list, ai.agents.chat, ai.pendingActions.list. Took triage's replace-rather-than-delete recommendation: the replacement could be made correct in the neighbours' style, so deleting the section was not needed. Added a two-line caveat that /ai is served by service-ai (Cloud/EE) and that an environment without it answers 501 rather than 404 — without it the new block would have reproduced this card's own defect with fresher names, since every listed method 501s on a default open-source install. patch changeset on @objectstack/client, because README.md is a published file of the package.",
    "how_snippet_was_driven": "Type-checked against the package's OWN PUBLISHED DECLARATIONS, not against src: built the client dependency closure, then ran tsc --noEmit --strict --module nodenext against a scratch file importing from packages/client/dist/index.js. (a) The replacement snippet, verbatim, exit 0. (b) FALSIFIABILITY CONTROL: the three lines being removed, same harness, exit 2 with TS2339 'Property nlq does not exist on type ...' plus the same for suggest and insights — the card's claimed reader experience, reproduced as a measurement rather than inherited from triage. Argument shapes were checked against the contracts, not just the method names: AiPendingActionStatusSchema admits 'pending', ListAiConversationsRequestSchema declares limit, AiAgentChatRequestSchema requires messages. The 501 claim was read off packages/runtime/src/domains/ai.ts (capabilityUnavailable(deps,'ai')) and domains/unavailable.ts (deps.error(serviceUnavailableMessage(slot), 501)) — deliberately NOT off the client docblock, which still says 404 and is stale. Both scratch files were deleted before the commit; git status was clean at commit time.",
    "clause_2": {
    "mechanical_floor": {
    "grade": "no",
    "reason": "The diff is exactly two Markdown files — packages/client/README.md and .changeset/client-readme-retired-ai-methods.md — which is also the change set dispatch-gates derived from the merge base. No key is added to any published payload, and nothing under packages/spec/src/** is touched."
    },
    "non_mechanizable_conformance": {
    "grade": "no",
    "reason": "No input class is re-selected between two already-published verdicts on a shipped face. Runtime and type surface are unchanged (dist rebuilt from untouched src). Every example argument was chosen to sit inside a verdict the contracts already publish unambiguously ('pending' in AiPendingActionStatusSchema, limit on ListAiConversationsRequestSchema, messages required by AiAgentChatRequestSchema) and each was confirmed accepted by the published dist/index.d.ts before being written down. No face with two live readings arose to pick between. Graded affirmatively, not by default."
    }
    },
    "gate_union": {
    "asserted_against": "Reconciliation — 46 famil(ies): this card's WHOLE runnable answer, and the number to assert a harvest against.",
    "count": 46,
    "harvested": 46,
    "harvest_note": "--commands printed exactly 46 lines (29 node + 17 pnpm), matching the reconciliation line. NOTE for the seat: --commands does NOT itself print the Reconciliation line; the plain form must be run to obtain it.",
    "result": "46/46 green at head 3909a11, after a full pnpm build (72/72 turbo tasks). Every exit code captured before any pipe (redirect first, then EXIT=$?).",
    "not_measured_first_pass_then_remeasured_green": [
    "pnpm check:published-readme-exports — exit 3 PREREQUISITE NOT MET (16 packages unbuilt); green after full build",
    "pnpm check:dual-build-cjs-loads — exit 3 PREREQUISITE NOT MET (33 packages with no dist); green after full build",
    "pnpm --filter @objectstack/spec run check:skill-examples — exit 1, 'packages/client-react/dist holds no .d.ts declarations'; green after building client-react"
    ]
    },
    "artifact_rosters_run_separately": {
    "count": 39,
    "green": 36,
    "not_measured": [
    "node scripts/check-partof-closing-keyword.mjs — exit 2 NOT WIRED (no PR_BODY / PR_NUMBER). Driven separately with PR_BODY set to this PR's actual body: exit 0, 'this PR carries no Part-of/closing-keyword contradiction.'",
    "node scripts/check-single-claim-paths.mjs — exit 2 NOT WIRED (no PR_NUMBER). The pnpm wrapper form pnpm check:single-claim-paths exits 0.",
    "pnpm --filter @objectstack/spec run check:react-declaration-parity — exit 1, MANIFEST unset, 'This gate did NOT run'; no objectui sdui.manifest.json exists in this checkout."
    ],
    "note": "Also outside every total above: 10 families that declare a population too wide to place (lint.yml carries no paths filter, so CI runs them unconditionally). Not run locally, and their absence is not a clearance."
    },
    "tests": "All at head 3909a11 (final commit; the union and package checks were run on this exact tree). pnpm --filter @objectstack/client typecheck -> green, 'check:test-typecheck: OK — @objectstack/client's test layer compiles ... 0 file(s) / 0 error(s)'. pnpm --filter @objectstack/client exec vitest run --maxWorkers=2 -> 'Test Files 33 passed (33) / Tests 437 passed (437)'. Full pnpm build --concurrency=2 -> '72 successful, 72 total'. Gate union 46/46 green; artifact rosters 36/39 green with 3 NOT MEASURED named by exit code above. ABLATION (on #16209, the out-of-scope finding, not on this fix): restored the three retired lines into the README on a fully built tree and re-ran check:published-readme-exports — 'injected nlq lines: 1 (expect 1)', 'GATE EXIT ON MUTATED TREE = 0'. Restore leg proven, not assumed: git checkout HEAD -- ABSOLUTE_PATH under a trap, restored blob 891c27e3c07c7d5a9e3b8d13b945cb21d5e0b9b6 equal to git rev-parse HEAD:packages/client/README.md, git diff HEAD empty, injected count back to 0. Second ablation (import-bound receiver): import lines BEFORE 1 -> AFTER 2, gate exit 0, import half 324->325 while call-site half stayed 78 and NOT-read stayed 120; same restore proof. No build was needed for either leg (README is not a build input), and both mutation legs were proven on disk by grep counts before any reading was taken.",
    "mcp_calls": "11 — issue_read get, issue_read get_comments, add_issue_comment (claim), search_issues (one targeted dedupe query), issue_write x3 (the three findings), create_pull_request, pull_request_read (body read-back), add_issue_comment (Clause-② amendment), add_issue_comment (this report).",
    "zone2_assumptions": {
    "falsified": [
    "ZONE 2 #1 — FALSIFIED in its consequence. PR #16144 did merge (commit 92dc937) and does edit packages/client/README.md in this same namespace-tour fence, but its ONLY hunk header is @@ -269,12 +269,15 @@ — strictly below the AI block. So triage's 263-265 still held exactly on current origin/main, and the numbers did not move. Also origin/main was a7cce55 when I branched, not 4e090ec.",
    "ZONE 2 #5 — refined. The Reconciliation line is NOT printed by --commands; the plain (no-flag) form must be run to get it. Asserting a --commands harvest against that line requires two runs.",
    "ZONE 2 #4 — did not materialize here: dispatch-gates --commands exited 0 with a full 46-family reconciliation, because this diff is non-empty. NOT MEASURED families did occur, by exit 3 (two), exit 1 (two) and exit 2 (two), each named above and none folded into a green count."
    ],
    "confirmed_by_own_measurement": [
    "ZONE 2 #2 — CONFIRMED. grep -rn 'nlq' packages/client/src/ returns exactly 5 hits, exactly the five triage named (client-url-conformance.test.ts:176 and :461, index.ts:5118 and :5119, client.test.ts:946), every one a historical docblock or test comment and none a live implementation. The live ai namespace opens at index.ts:5147 and holds chat, chatStream, complete, models, conversations, agents, pendingActions.",
    "ZONE 2 #3 — CONFIRMED by reading the file, not the quote: packages/client/package.json lines 62-66 read files: [dist, README.md, CHANGELOG.md]. Package version 17.3.0.",
    "ZONE 2 #7 — CONFIRMED and acted on. Found a live instance of the defect class and filed it as #16209 with two ablations."
    ]
    },
    "hazards_hit": [
    "pnpm build -- --concurrency=2 forwards the flag to EVERY package's build script (turbo passes post---- args to tasks), which broke @objectstack/cli's shell-if build with 'sh: 1: Syntax error: word unexpected' and read exactly like a repo-level breakage on main. It was my invocation. Correct spelling is pnpm build --concurrency=2, with turbo consuming the flag: 72/72 green on the re-run.",
    "My first ablation-landing proof asserted a global grep count of 1 for an import line the README already carried elsewhere, so it read 2 and aborted the run (exit 90) even though the mutation had landed. The trap restored the tree cleanly. Re-run with a BEFORE/AFTER count instead of an absolute one. Recording it because the failure mode is the proof being wrong, not the mutation."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "filed as #16209: check:published-readme-exports cannot see a single call in packages/client/README.md's namespace tour — the receiver is built by new ObjectStackClient(...), landing all ~30 calls in the gate's own 'NOT read: 120 calls on 72 receivers' bucket. Proven by ablation: with this card's own defect restored the gate still exits 0, and binding the receiver by import moves only the import half (324->325), leaving call-site 78 / NOT-read 120 unchanged — so the obvious fix does not close it. This is why the defect survived from v17 inside the one gate meant to catch it. Labelled finding.",
    "filed as #16210: packages/client/README.md, same fence, documents client.approvals.approve(requestId, 'LGTM') and .reject(requestId, 'Incomplete'), but index.ts:4686/:4699 declare the second parameter as a decision object. Measured against the published dist/index.d.ts: two TS2559 errors. Different defect class from this card (wrong argument shape for a live method vs. methods that no longer exist), so deliberately not folded in. No label — left for PM triage.",
    "filed as #16211: packages/client/src/index.ts:5129-5133 and packages/runtime/src/route-ledger.ts:401 both still say the dispatcher 404s 'AI service is not configured' for /ai/*, but domains/ai.ts returns capabilityUnavailable(deps,'ai') = 501 and domains/unavailable.ts documents the 404-vs-501 distinction deliberately. The docs site is already correct. Caught because this card's replacement text needed the real behaviour; copying the client docblock would have shipped a fresh false statement. No label — left for PM triage."
    ],
    "notes_for_pm": "Draft PR is NOT flipped ready and auto-merge is NOT armed. No governed surface touched (nothing under docs/adr/, .claude/, skills/**, and neither AGENTS.md nor CLAUDE.md). No assignee set by me. No skip-changeset label applied and none is due: the README is a published file, so this diff publishes. Per the standing contract the report is delivered at draft-PR time and CI convergence is the PM seat's step; the local union is green but that is explicitly not a prediction of green CI. Worktree at /home/user/objectstack-issue-16142 is being torn down after this report."
    }


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentationdomain:cliRetired 2026-10-22, alias of domain:server (cli surface); in-flight cards keep it until they landfindingpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions