Files
larksuite__cli/tests/cli_e2e/base/coverage.md
huarenmin13 9b231d9825 fix(base): improve record history output and validation (#2298)
* fix(base): make record history queries explicit and readable

1. Require an explicit confirmed record ID and document deterministic record resolution
2. Add shared-format pretty history output and projection aliases without changing default JSON
3. Reject explicitly non-positive history cursors and cover request, help, formatting,
    and dry-run behavior

```ai-signature
改动范围: 将 Codebase MR 1438 的最终十文件差异移植到 GitHub PR 2298,覆盖 record history 命令、record list 投影别名、Base 引导文档与对应单元及 dry-run 回归测试
思考过程: 以 GitHub 最新 main 为基线执行三方内容合并,保留 GitHub 独立演进;删除原 PR 针对 base_history_003 的 Skill 改动,并仅按 GitHub 当前分母重算 coverage 指标
改动原因: GitHub PR 原先承载的是已确认应撤回的单题文档方案,需要由已评审的 MR 1438 最终通用实现完整替换,同时避免复制 Codebase 的多轮提交与 revert 历史
Break Change: 行为 breaking | record history 要求显式确认的 record ID,且显式非正 --max-version 现在返回 typed validation error
```

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 5bf66267670f435c7d577d2444b61b209322eb5a73f15e47e671a5b8dd2603bf

* fix(base): validate history cursors and NDJSON dry runs

1. Reject missing or invalid next_max_version values before emitting pagination guidance
2. Use the execution page size in NDJSON dry runs and assert the requested output path
3. Cover valid and invalid history cursors and prove a 2000-row request is capped to a 500-row first
    page

```ai-signature
改动范围: shortcuts/base/record_history_list.go、record_ops.go 及邻近单元和 dry-run E2E 测试,仅处理 PR 2298 中有效 CodeRabbit 评论,不新增 live E2E 或修改主 Skill
思考过程: 分页提示只接受解码后的正整数游标;NDJSON dry-run 复用执行阶段的五百行页大小,并以两千行请求验证真实截断而非相等值偶然通过,同时直接断言导出路径契约
改动原因: 原实现可能把不可用的服务端游标打印成命令,同时 dry-run 对 201 到 500 条请求报告的首屏大小与真实执行不一致,初版测试也未真正证明五百行上限或 search 输出路径
Break Change: 否
```

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: a362c47d739d6de5676b87431fbc015d1eaa3d47d46d711e2535baa4dad7ffce

* docs(base): simplify record history prerequisites

1. Condense the record history prerequisites into generic record selection rules.
2. Remove the positive and negative examples from the reference.

```ai-signature
改动范围: 仅修改 skills/lark-base/references/lark-base-record-history-list.md,精简使用前置并删除正反例章节。
思考过程: 保留调用前确认同表 record_id、不得自行选择记录或扩展整表扫描的核心约束,移除具体链接、视图位置和命令示例以提升通用性。
改动原因: 用户要求使用前置更精简、表述更通用,并删除正反例;本次不涉及命令行为或测试。
Break Change: 否
```

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 7e69951d47c1535cd5fe0fa9ebd7018af2e17373e5851c229dac46d68eaefa84

* fix(base): align history guidance with affordance

* fix(base): keep history guidance in the existing reference

1. Remove the new Base affordance file and its Markdown-only tests
2. Keep selection and field quoting guidance in the existing record history reference
3. Restore the pre-existing command tips and retain only behavior-focused regressions

```ai-signature
改动范围: 删除新增 affordance/base.md 与对应 source/help 文案测试,调整 record-history 现有 reference、覆盖说明和原命令 Tips
思考过程: 用户要求不新增 Base affordance 文件且 Markdown 不需要专门测试,因此保留运行时代码测试,把跨命令选行和字段引号说明收敛到已有 reference
改动原因: 新增 affordance 与文案测试扩大了 PR 改动面,并重复承载已有 history reference 的 agent 工作流说明
Break Change: 否
```

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: 4c7e3db10025f412d4b2cb4443d94724b5997b72b7e8f97fafdae2f08633b5a2

* docs(base): clarify record history target selection

1. Describe the record ID as uniquely resolving the user-selected target
2. Avoid implying that users must confirm an opaque internal record ID directly

```ai-signature
改动范围: 仅调整现有 lark-base record-history reference 的一处目标记录选择表述
思考过程: CLI 运行时只要求有效 record_id,agent 工作流要求用户确认目标而不是直接确认内部 ID,因此需要区分产品事实和操作约束
改动原因: 原表述可能被误解为 base-cli 能验证 record_id 的用户确认来源,与实际产品边界不一致
Break Change: 否
```

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
AI-SHA256: bd6c9584cc38689e1c3d9f26514425e3e38ffe2f2cff7b2bb0c65ff316aaf8dc

* docs(base): preserve serial history queries

---------

Co-authored-by: BASE Infra Harness <ai@base-infra-harness.noreply.local>
2026-08-18 12:06:02 +08:00

14 KiB

Base CLI E2E Coverage

Metrics

  • Denominator: 89 leaf commands
  • Covered: 31
  • Coverage: 34.8%

Summary

  • TestBase_BasicWorkflow: proves +base-create, +base-get, +table-create, +table-get, and +table-list; key t.Run(...) proof points are get base as bot, get table as bot, and list tables and find created table as bot.
  • TestBaseBlockDryRun: proves the five +base-block-* shortcuts request shapes without touching live data.
  • TestBaseAppWorkflow: live user workflow in an isolated fixture Workspace covering Workspace entity listing, BaseApp create/get, Page create/list/get/update/delete, text Block create/list/get/update, and App cleanup through Drive delete (type=bitable). Set LARK_CLI_E2E_BASEAPP_WORKSPACE_TOKEN to enable it.
  • TestBaseFieldCreateDryRunArrayCompat: proves +field-create dry-run request shape for the internal JSON-array compatibility path.
  • TestBaseFormQuestionsCreateDryRun: proves +form-questions-create preserves its POST body and renders the existing-question guard in command help.
  • TestBaseFormDetailDryRun / TestBaseFormSubmitDryRun: prove shared-form detail and submission request shapes.
  • TestBaseDashboardBlockGetDataDryRun: proves dashboard block data request shapes and identifier handling.
  • TestBaseRecordBatchUpdatePerRecordDryRun: proves +record-batch-update preserves the per-record update_records request shape.
  • TestBaseRecordBatchUpdatePerRecordWorkflow: creates two records, updates different field types in one request, asserts the minimal response contract, reads both records back, verifies a missing record ID is not prevalidated, and cleans up the temporary Base.
  • TestBaseRecordHistoryListDryRunUsesExplicitRecordID / TestBaseRecordHistoryListDryRunRejectsNonPositiveMaxVersion: prove the history request keeps the explicit record ID and rejects explicitly non-positive cursors with a typed validation error.
  • TestBase_RoleWorkflow: proves +advperm-enable, +role-create, +role-list, +role-get, and +role-update; key t.Run(...) proof points are list as bot, get as bot, and update as bot.
  • TestBaseFormListDryRun_UsesBaseAndTableIdentifiers: proves +form-list dry-run request shape uses Base and table identifiers in the endpoint.
  • TestBaseFormQuestionsCreateVisibleRuleDryRun / TestBaseFormQuestionsUpdateVisibleRuleDryRun: prove +form-questions-create / +form-questions-update dry-run request shape and that the optional visible_rule display condition is transcribed verbatim into the request body.
  • TestBaseTableCopyDryRun: proves +table-copy and +table-copy-status request shapes, including the schema-safe default, table-name path escaping, explicit all+wait orchestration, Cobra duration parsing, and the opaque task ID body.
  • TestBaseTableCopyWorkflow: feature-gated by LARK_CLI_E2E_BASE_TABLE_COPY_READY=1 until the OpenAPI is deployed; creates a source table and record, proves schema-only copy, all no-wait plus status, all wait, record inclusion, and cleanup.
  • Cleanup note: +table-delete and +role-delete only run in cleanup and are intentionally left uncovered.
  • Blocked area: table-copy live integration remains deployment-gated; dashboard, field, most record operations, most form operations, view, and workflow operations still lack deterministic create/read/update workflows in this suite.

Command Table

Status Cmd Type Testcase Key parameter shapes Notes / uncovered reason
✕ base +advperm-disable shortcut none no disable workflow yet
✓ base +advperm-enable shortcut base_role_workflow_test.go::TestBase_RoleWorkflow --base-token
✕ base +base-copy shortcut none no copy workflow yet
✓ base +base-create shortcut base/helpers_test.go::createBaseWithRetry --name; --time-zone helper asserts created base token
✓ base +base-get shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/get base as bot --base-token
✓ base +base-block-create shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/create --base-token; --type; --name; --parent-id; dry-run only request shape only
✓ base +base-block-delete shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/delete --base-token; --block-id; dry-run only request shape only
✓ base +base-block-list shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/list all,list folder --base-token; optional --parent-id; optional --type; dry-run only request shape only
✓ base +base-block-move shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/move root,move after --base-token; --block-id; optional --parent-id; --after-id; dry-run only request shape only
✓ base +base-block-rename shortcut base_block_dryrun_test.go::TestBaseBlockDryRun/rename --base-token; --block-id; --name; dry-run only request shape only
✕ base +dashboard-arrange shortcut none dashboard workflows not covered
✕ base +dashboard-block-create shortcut none dashboard workflows not covered
✕ base +dashboard-block-delete shortcut none dashboard workflows not covered
✕ base +dashboard-block-get shortcut none dashboard workflows not covered
✓ base +dashboard-block-get-data shortcut base_dashboard_block_get_data_dryrun_test.go --base-token; --dashboard-id; --block-id; dry-run only request shape and identifier handling
✕ base +dashboard-block-list shortcut none dashboard workflows not covered
✕ base +dashboard-block-update shortcut none dashboard workflows not covered
✕ base +dashboard-create shortcut none dashboard workflows not covered
✕ base +dashboard-delete shortcut none dashboard workflows not covered
✕ base +dashboard-get shortcut none dashboard workflows not covered
✕ base +dashboard-list shortcut none dashboard workflows not covered
✕ base +dashboard-update shortcut none dashboard workflows not covered
✕ base +data-query shortcut none no data-query assertions yet
✓ base +field-create shortcut base_field_dryrun_test.go::TestBaseFieldCreateDryRunArrayCompat --base-token; --table-id; --json; dry-run only request shape only
✕ base +field-delete shortcut none field workflows not covered
✕ base +field-get shortcut none field workflows not covered
✕ base +field-list shortcut none field workflows not covered
✕ base +field-search-options shortcut none field workflows not covered
✕ base +field-update shortcut none field workflows not covered
✕ base +form-create shortcut none form workflows not covered
✕ base +form-delete shortcut none form workflows not covered
✓ base +form-detail shortcut base_form_detail_dryrun_test.go::TestBaseFormDetailDryRun --share-token; dry-run only shared-form request shape
✕ base +form-get shortcut none form workflows not covered
✓ base +form-list shortcut base_form_detail_dryrun_test.go::TestBaseFormListDryRun_UsesBaseAndTableIdentifiers --base-token; --table-id; dry-run only request shape only
✓ base +form-questions-create shortcut TestBaseFormQuestionsCreateVisibleRuleDryRun; base_form_questions_create_dryrun_test.go questions[].visible_rule; dry-run request body, visible_rule passthrough, and help guard covered
✕ base +form-questions-delete shortcut none form workflows not covered
✕ base +form-questions-list shortcut none form workflows not covered
✓ base +form-questions-update shortcut TestBaseFormQuestionsUpdateVisibleRuleDryRun questions[].visible_rule dry-run: request shape + visible_rule body passthrough
✓ base +form-submit shortcut base_form_submit_dryrun_test.go::TestBaseFormSubmitDryRun --share-token; --json; dry-run only submission request shape
✕ base +form-update shortcut none form workflows not covered
✓ base +record-batch-create shortcut base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --base-token; --table-id; --json.create_records seeds heterogeneous live workflow records
✓ base +record-batch-update shortcut base_record_batch_update_dryrun_test.go::TestBaseRecordBatchUpdatePerRecordDryRun; base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --base-token; --table-id; --json.update_records; dry-run + live heterogeneous select/number update with write-back verification
✕ base +record-delete shortcut none record workflows not covered
✓ base +record-get shortcut base_record_batch_update_workflow_test.go::TestBaseRecordBatchUpdatePerRecordWorkflow --record-id; repeated --field-id; --format json reads back select and number values after batch update
✓ base +record-history-list shortcut base_record_history_dryrun_test.go::TestBaseRecordHistoryListDryRunUsesExplicitRecordID; TestBaseRecordHistoryListDryRunRejectsNonPositiveMaxVersion --base-token; --table-id; --record-id; --page-size; --max-version; dry-run request shape and typed cursor validation
✕ base +record-list shortcut none record workflows not covered
✕ base +record-search shortcut none record workflows not covered
✕ base +record-share-link-create shortcut none record workflows not covered
✓ base +record-upload-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/upload dry-run only request shape only
✓ base +record-download-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/download dry-run only request shape only
✓ base +record-remove-attachment shortcut base_attachment_dryrun_test.go::TestBase_AttachmentDryRun/remove dry-run only request shape only
✕ base +record-upsert shortcut none record workflows not covered
✓ base +role-create shortcut base/helpers_test.go::createRole --base-token; --json helper asserts created role id
✕ base +role-delete shortcut none cleanup only
✓ base +role-get shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/get as bot --base-token; --role-id
✓ base +role-list shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/list as bot --base-token
✓ base +role-update shortcut base_role_workflow_test.go::TestBase_RoleWorkflow/update as bot --base-token; --role-id; --json
✓ base +table-create shortcut base/helpers_test.go::createTableWithRetry --base-token; --name; --fields; optional --view helper asserts table id
✓ base +table-copy shortcut base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow --table-id ID/name; default --range schema; explicit --range all --wait --timeout dry-run covered; live workflow is deployment-gated and not yet verified
✓ base +table-copy-status shortcut base_table_copy_dryrun_test.go::TestBaseTableCopyDryRun/status; base_table_copy_workflow_test.go::TestBaseTableCopyWorkflow/all no-wait and status opaque --task-id dry-run covered; live polling is deployment-gated and not yet verified
✕ base +table-delete shortcut none cleanup only
✓ base +table-get shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/get table as bot --base-token; --table-id
✓ base +table-list shortcut base_basic_workflow_test.go::TestBase_BasicWorkflow/list tables and find created table as bot --base-token
✕ base +table-update shortcut none no rename workflow yet
✕ base +title-resolve shortcut none resolver workflow not covered
✕ base +url-resolve shortcut none resolver workflow not covered
✕ base +view-create shortcut none view workflows not covered
✕ base +view-delete shortcut none view workflows not covered
✕ base +view-get shortcut none view workflows not covered
✕ base +view-get-card shortcut none view workflows not covered
✕ base +view-get-filter shortcut none view workflows not covered
✕ base +view-get-group shortcut none view workflows not covered
✕ base +view-get-sort shortcut none view workflows not covered
✕ base +view-get-timebar shortcut none view workflows not covered
✕ base +view-get-visible-fields shortcut none view workflows not covered
✕ base +view-list shortcut none view workflows not covered
✕ base +view-rename shortcut none view workflows not covered
✕ base +view-set-card shortcut none view workflows not covered
✕ base +view-set-filter shortcut none view workflows not covered
✕ base +view-set-group shortcut none view workflows not covered
✕ base +view-set-sort shortcut none view workflows not covered
✕ base +view-set-timebar shortcut none view workflows not covered
✕ base +view-set-visible-fields shortcut none view workflows not covered
✕ base +workflow-create shortcut none workflow CRUD not covered
✕ base +workflow-disable shortcut none workflow CRUD not covered
✕ base +workflow-enable shortcut none workflow CRUD not covered
✕ base +workflow-get shortcut none workflow CRUD not covered
✕ base +workflow-list shortcut none workflow CRUD not covered
✕ base +workflow-update shortcut none workflow CRUD not covered