kaiten-cli 0.3.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. kaiten_cli-0.3.3/.gitignore +29 -0
  2. kaiten_cli-0.3.3/AGENTS.md +97 -0
  3. kaiten_cli-0.3.3/API_BEHAVIOR_MATRIX.md +107 -0
  4. kaiten_cli-0.3.3/ARCHITECTURE.md +183 -0
  5. kaiten_cli-0.3.3/LIVE_VALIDATION.md +186 -0
  6. kaiten_cli-0.3.3/PKG-INFO +1110 -0
  7. kaiten_cli-0.3.3/README.md +1065 -0
  8. kaiten_cli-0.3.3/SECURITY.md +27 -0
  9. kaiten_cli-0.3.3/docs/LOCALIZATION_VERIFICATION.md +85 -0
  10. kaiten_cli-0.3.3/docs/PYPI_PUBLISHING.md +127 -0
  11. kaiten_cli-0.3.3/docs/RESTRICTIONS_VERIFICATION.md +55 -0
  12. kaiten_cli-0.3.3/docs/public-api/README.md +89 -0
  13. kaiten_cli-0.3.3/docs/public-api/automation-tables.json +10777 -0
  14. kaiten_cli-0.3.3/docs/public-api/contracts.json +39897 -0
  15. kaiten_cli-0.3.3/docs/public-api/coverage.json +2644 -0
  16. kaiten_cli-0.3.3/docs/public-api/decisions.json +366 -0
  17. kaiten_cli-0.3.3/pyproject.toml +102 -0
  18. kaiten_cli-0.3.3/scripts/audit_public_api.py +555 -0
  19. kaiten_cli-0.3.3/scripts/benchmark_reference_workflows.py +132 -0
  20. kaiten_cli-0.3.3/scripts/check_locales.py +190 -0
  21. kaiten_cli-0.3.3/scripts/check_release.py +149 -0
  22. kaiten_cli-0.3.3/scripts/extract_automation_docs.cjs +30 -0
  23. kaiten_cli-0.3.3/scripts/generate_reference_docs.py +418 -0
  24. kaiten_cli-0.3.3/scripts/normalize_automation_docs.py +148 -0
  25. kaiten_cli-0.3.3/skills/kaiten-cli-heavy-data/SKILL.md +247 -0
  26. kaiten_cli-0.3.3/skills/kaiten-cli-metrics/SKILL.md +188 -0
  27. kaiten_cli-0.3.3/skills/kaiten-cli-mutations/SKILL.md +142 -0
  28. kaiten_cli-0.3.3/src/kaiten_cli/__init__.py +5 -0
  29. kaiten_cli-0.3.3/src/kaiten_cli/__main__.py +9 -0
  30. kaiten_cli-0.3.3/src/kaiten_cli/agent_gateway.py +577 -0
  31. kaiten_cli-0.3.3/src/kaiten_cli/app.py +1636 -0
  32. kaiten_cli-0.3.3/src/kaiten_cli/completion.py +570 -0
  33. kaiten_cli-0.3.3/src/kaiten_cli/discovery.py +39 -0
  34. kaiten_cli-0.3.3/src/kaiten_cli/errors.py +79 -0
  35. kaiten_cli-0.3.3/src/kaiten_cli/i18n.py +92 -0
  36. kaiten_cli-0.3.3/src/kaiten_cli/locales/ru.json +2967 -0
  37. kaiten_cli-0.3.3/src/kaiten_cli/localized_click.py +160 -0
  38. kaiten_cli-0.3.3/src/kaiten_cli/models.py +202 -0
  39. kaiten_cli-0.3.3/src/kaiten_cli/profiles.py +316 -0
  40. kaiten_cli-0.3.3/src/kaiten_cli/registry/__init__.py +260 -0
  41. kaiten_cli-0.3.3/src/kaiten_cli/registry/addons.py +392 -0
  42. kaiten_cli-0.3.3/src/kaiten_cli/registry/audit_and_analytics.py +451 -0
  43. kaiten_cli-0.3.3/src/kaiten_cli/registry/automation_schema.py +44 -0
  44. kaiten_cli-0.3.3/src/kaiten_cli/registry/automation_schemas.json +7417 -0
  45. kaiten_cli-0.3.3/src/kaiten_cli/registry/automations.py +342 -0
  46. kaiten_cli-0.3.3/src/kaiten_cli/registry/base.py +62 -0
  47. kaiten_cli-0.3.3/src/kaiten_cli/registry/blockers.py +320 -0
  48. kaiten_cli-0.3.3/src/kaiten_cli/registry/boards.py +520 -0
  49. kaiten_cli-0.3.3/src/kaiten_cli/registry/card_relations.py +376 -0
  50. kaiten_cli-0.3.3/src/kaiten_cli/registry/card_types.py +363 -0
  51. kaiten_cli-0.3.3/src/kaiten_cli/registry/cards.py +1329 -0
  52. kaiten_cli-0.3.3/src/kaiten_cli/registry/charts.py +539 -0
  53. kaiten_cli-0.3.3/src/kaiten_cli/registry/checklists.py +600 -0
  54. kaiten_cli-0.3.3/src/kaiten_cli/registry/columns.py +558 -0
  55. kaiten_cli-0.3.3/src/kaiten_cli/registry/comments.py +224 -0
  56. kaiten_cli-0.3.3/src/kaiten_cli/registry/custom_directories.py +980 -0
  57. kaiten_cli-0.3.3/src/kaiten_cli/registry/custom_properties.py +1460 -0
  58. kaiten_cli-0.3.3/src/kaiten_cli/registry/dashboards.py +564 -0
  59. kaiten_cli-0.3.3/src/kaiten_cli/registry/documents.py +761 -0
  60. kaiten_cli-0.3.3/src/kaiten_cli/registry/external_links.py +128 -0
  61. kaiten_cli-0.3.3/src/kaiten_cli/registry/files.py +738 -0
  62. kaiten_cli-0.3.3/src/kaiten_cli/registry/github_addon.py +613 -0
  63. kaiten_cli-0.3.3/src/kaiten_cli/registry/iterations.py +397 -0
  64. kaiten_cli-0.3.3/src/kaiten_cli/registry/lanes.py +205 -0
  65. kaiten_cli-0.3.3/src/kaiten_cli/registry/live_contracts.py +361 -0
  66. kaiten_cli-0.3.3/src/kaiten_cli/registry/members.py +336 -0
  67. kaiten_cli-0.3.3/src/kaiten_cli/registry/module_docs.py +108 -0
  68. kaiten_cli-0.3.3/src/kaiten_cli/registry/projects.py +369 -0
  69. kaiten_cli-0.3.3/src/kaiten_cli/registry/query.py +129 -0
  70. kaiten_cli-0.3.3/src/kaiten_cli/registry/restrictions.py +249 -0
  71. kaiten_cli-0.3.3/src/kaiten_cli/registry/roles_and_groups.py +1102 -0
  72. kaiten_cli-0.3.3/src/kaiten_cli/registry/scim.py +263 -0
  73. kaiten_cli-0.3.3/src/kaiten_cli/registry/service_desk.py +1270 -0
  74. kaiten_cli-0.3.3/src/kaiten_cli/registry/snapshot.py +187 -0
  75. kaiten_cli-0.3.3/src/kaiten_cli/registry/spaces.py +272 -0
  76. kaiten_cli-0.3.3/src/kaiten_cli/registry/subscribers.py +168 -0
  77. kaiten_cli-0.3.3/src/kaiten_cli/registry/tags.py +193 -0
  78. kaiten_cli-0.3.3/src/kaiten_cli/registry/time_logs.py +353 -0
  79. kaiten_cli-0.3.3/src/kaiten_cli/registry/tree.py +352 -0
  80. kaiten_cli-0.3.3/src/kaiten_cli/registry/utilities.py +287 -0
  81. kaiten_cli-0.3.3/src/kaiten_cli/registry/webhooks.py +265 -0
  82. kaiten_cli-0.3.3/src/kaiten_cli/runtime/__init__.py +1 -0
  83. kaiten_cli-0.3.3/src/kaiten_cli/runtime/automation_validation.py +115 -0
  84. kaiten_cli-0.3.3/src/kaiten_cli/runtime/behaviors.py +787 -0
  85. kaiten_cli-0.3.3/src/kaiten_cli/runtime/cache.py +733 -0
  86. kaiten_cli-0.3.3/src/kaiten_cli/runtime/client.py +387 -0
  87. kaiten_cli-0.3.3/src/kaiten_cli/runtime/endpoints.py +59 -0
  88. kaiten_cli-0.3.3/src/kaiten_cli/runtime/executor.py +269 -0
  89. kaiten_cli-0.3.3/src/kaiten_cli/runtime/fs_security.py +168 -0
  90. kaiten_cli-0.3.3/src/kaiten_cli/runtime/input.py +310 -0
  91. kaiten_cli-0.3.3/src/kaiten_cli/runtime/output.py +59 -0
  92. kaiten_cli-0.3.3/src/kaiten_cli/runtime/public_validation.py +35 -0
  93. kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_build.py +527 -0
  94. kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_common.py +363 -0
  95. kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_query.py +306 -0
  96. kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshot_store.py +1192 -0
  97. kaiten_cli-0.3.3/src/kaiten_cli/runtime/snapshots.py +62 -0
  98. kaiten_cli-0.3.3/src/kaiten_cli/runtime/sqlite_errors.py +23 -0
  99. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/__init__.py +1 -0
  100. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/addons.py +953 -0
  101. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/audit.py +70 -0
  102. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/batch.py +234 -0
  103. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/card_move_url.py +213 -0
  104. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/cards.py +174 -0
  105. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/checklists.py +21 -0
  106. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/company_users.py +117 -0
  107. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/dashboards.py +35 -0
  108. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/documents.py +175 -0
  109. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/files.py +561 -0
  110. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/markdown_export.py +525 -0
  111. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/pagination.py +167 -0
  112. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/projects.py +66 -0
  113. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/relations.py +86 -0
  114. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/restrictions.py +62 -0
  115. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/spaces.py +20 -0
  116. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/time_logs.py +61 -0
  117. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/tree.py +140 -0
  118. kaiten_cli-0.3.3/src/kaiten_cli/runtime/support/tree_sharing.py +447 -0
  119. kaiten_cli-0.3.3/src/kaiten_cli/runtime/trace.py +500 -0
  120. kaiten_cli-0.3.3/src/kaiten_cli/runtime/transforms.py +128 -0
  121. kaiten_cli-0.3.3/src/kaiten_cli/schema_docs.py +22 -0
  122. kaiten_cli-0.3.3/src/kaiten_cli/update_check.py +519 -0
  123. kaiten_cli-0.3.3/tests/conftest.py +35 -0
  124. kaiten_cli-0.3.3/tests/data/mcp_aliases.txt +423 -0
  125. kaiten_cli-0.3.3/tests/live/conftest.py +221 -0
  126. kaiten_cli-0.3.3/tests/live/test_automation_contract.py +102 -0
  127. kaiten_cli-0.3.3/tests/live/test_restrictions_live.py +21 -0
  128. kaiten_cli-0.3.3/tests/live/test_sandbox_live_full.py +1757 -0
  129. kaiten_cli-0.3.3/tests/test_addons_and_github_addon.py +1613 -0
  130. kaiten_cli-0.3.3/tests/test_agent_gateway.py +487 -0
  131. kaiten_cli-0.3.3/tests/test_audit_and_analytics.py +198 -0
  132. kaiten_cli-0.3.3/tests/test_automation_schemas.py +195 -0
  133. kaiten_cli-0.3.3/tests/test_card_types_and_custom_properties.py +166 -0
  134. kaiten_cli-0.3.3/tests/test_cards_move_by_url.py +284 -0
  135. kaiten_cli-0.3.3/tests/test_charts.py +184 -0
  136. kaiten_cli-0.3.3/tests/test_cli_smoke.py +373 -0
  137. kaiten_cli-0.3.3/tests/test_column_settings.py +119 -0
  138. kaiten_cli-0.3.3/tests/test_command_resolution.py +14 -0
  139. kaiten_cli-0.3.3/tests/test_completion_tail.py +265 -0
  140. kaiten_cli-0.3.3/tests/test_dashboards.py +389 -0
  141. kaiten_cli-0.3.3/tests/test_developer_parity_gaps.py +284 -0
  142. kaiten_cli-0.3.3/tests/test_discovery.py +168 -0
  143. kaiten_cli-0.3.3/tests/test_docs_structure.py +59 -0
  144. kaiten_cli-0.3.3/tests/test_documents_and_tree.py +622 -0
  145. kaiten_cli-0.3.3/tests/test_domain_expansion.py +549 -0
  146. kaiten_cli-0.3.3/tests/test_entrypoints.py +57 -0
  147. kaiten_cli-0.3.3/tests/test_executor_architecture.py +12 -0
  148. kaiten_cli-0.3.3/tests/test_executor_http.py +575 -0
  149. kaiten_cli-0.3.3/tests/test_file_downloads.py +249 -0
  150. kaiten_cli-0.3.3/tests/test_file_uploads.py +130 -0
  151. kaiten_cli-0.3.3/tests/test_fs_security.py +58 -0
  152. kaiten_cli-0.3.3/tests/test_generated_docs.py +16 -0
  153. kaiten_cli-0.3.3/tests/test_input_parsing.py +227 -0
  154. kaiten_cli-0.3.3/tests/test_investigation_workflows.py +545 -0
  155. kaiten_cli-0.3.3/tests/test_iterations.py +299 -0
  156. kaiten_cli-0.3.3/tests/test_live_contracts.py +51 -0
  157. kaiten_cli-0.3.3/tests/test_local_snapshots.py +804 -0
  158. kaiten_cli-0.3.3/tests/test_localization.py +358 -0
  159. kaiten_cli-0.3.3/tests/test_markdown_export.py +230 -0
  160. kaiten_cli-0.3.3/tests/test_narrow_list_fields.py +23 -0
  161. kaiten_cli-0.3.3/tests/test_output_human.py +15 -0
  162. kaiten_cli-0.3.3/tests/test_output_json.py +61 -0
  163. kaiten_cli-0.3.3/tests/test_pagination.py +154 -0
  164. kaiten_cli-0.3.3/tests/test_private_files.py +327 -0
  165. kaiten_cli-0.3.3/tests/test_profiles.py +468 -0
  166. kaiten_cli-0.3.3/tests/test_public_api_cutover.py +128 -0
  167. kaiten_cli-0.3.3/tests/test_public_contract_parity.py +380 -0
  168. kaiten_cli-0.3.3/tests/test_public_input_transport.py +310 -0
  169. kaiten_cli-0.3.3/tests/test_rate_limit_policy.py +221 -0
  170. kaiten_cli-0.3.3/tests/test_registry_examples.py +49 -0
  171. kaiten_cli-0.3.3/tests/test_release.py +232 -0
  172. kaiten_cli-0.3.3/tests/test_restrictions.py +328 -0
  173. kaiten_cli-0.3.3/tests/test_roles_groups_and_subscribers.py +303 -0
  174. kaiten_cli-0.3.3/tests/test_runtime_cache.py +623 -0
  175. kaiten_cli-0.3.3/tests/test_service_desk.py +155 -0
  176. kaiten_cli-0.3.3/tests/test_shell_completion.py +431 -0
  177. kaiten_cli-0.3.3/tests/test_skills_structure.py +98 -0
  178. kaiten_cli-0.3.3/tests/test_timeout_policy.py +24 -0
  179. kaiten_cli-0.3.3/tests/test_transforms.py +26 -0
  180. kaiten_cli-0.3.3/tests/test_tree_entity_sharing.py +444 -0
  181. kaiten_cli-0.3.3/tests/test_update_check.py +532 -0
  182. kaiten_cli-0.3.3/tests/test_utilities_remainder.py +75 -0
  183. kaiten_cli-0.3.3/tests/test_webhooks_and_automations.py +129 -0
@@ -0,0 +1,29 @@
1
+ .venv/
2
+ .verify-venv/
3
+ __pycache__/
4
+ .pytest_cache/
5
+ .coverage
6
+ .coverage.*
7
+ coverage.xml
8
+ htmlcov/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ .claude-flow/
12
+ .bin/
13
+ .pipx/
14
+ .uv-tools/
15
+ build/
16
+ dist/
17
+ *.egg-info/
18
+ *.pyc
19
+ .env
20
+ .env_stage
21
+ .env_private
22
+ .DS_Store
23
+ /ARCHITECTURE_REVIEW.md
24
+ /docs/archive/
25
+ /docs/audits/
26
+ /scripts/analyze_codex_kaiten_sessions.py
27
+ /tests/test_analyze_codex_kaiten_sessions.py
28
+ /PLAN*.md
29
+ /PARITY_CHECKLIST.md
@@ -0,0 +1,97 @@
1
+ # kaiten-cli for Agents
2
+
3
+ This file only captures agent-specific guidance.
4
+
5
+ For install, human-oriented usage, and the full docs map, start with [README.md](README.md).
6
+ For the full command catalog, use [COMMAND_REFERENCE.md](COMMAND_REFERENCE.md).
7
+ For the system map, use [ARCHITECTURE.md](ARCHITECTURE.md).
8
+ For optimized LLM workflows, start with:
9
+
10
+ - [skills/kaiten-cli-heavy-data/SKILL.md](skills/kaiten-cli-heavy-data/SKILL.md)
11
+ - [skills/kaiten-cli-metrics/SKILL.md](skills/kaiten-cli-metrics/SKILL.md)
12
+ - [skills/kaiten-cli-mutations/SKILL.md](skills/kaiten-cli-mutations/SKILL.md)
13
+
14
+ ## Conversation locale
15
+
16
+ Pass `--locale ru` for Russian conversations and `--locale en` for English or
17
+ other languages, before the command name in every invocation, including help,
18
+ discovery and `--json`. Change it when the user changes the conversation language.
19
+ Explicit `--locale` overrides `KAITEN_CLI_LOCALE`; the default is `en`.
20
+ The CLI does not infer conversation language from the operating system.
21
+ Only CLI-owned prose is localized; command names, JSON keys, enum values and
22
+ Kaiten/user data remain unchanged. Examples below omit the locale for brevity;
23
+ add the current conversation locale when executing them.
24
+
25
+ ## Discovery-first flow
26
+
27
+ Prefer this sequence before calling mutations or heavy commands:
28
+
29
+ ```bash
30
+ kaiten --help
31
+ kaiten search-tools cards
32
+ kaiten describe cards.list
33
+ kaiten examples cards.list
34
+ ```
35
+
36
+ Run discovery once per unfamiliar command family, mutation workflow, or heavy
37
+ read. Reuse the discovered contract inside the same workflow instead of
38
+ repeating `describe` before every call.
39
+
40
+ Use `--json` by default for machine-safe parsing:
41
+
42
+ ```bash
43
+ kaiten --json spaces list --compact --fields id,title
44
+ ```
45
+
46
+ If the workflow will ask many questions about the same space or board set, switch early to the local-first path:
47
+
48
+ ```bash
49
+ kaiten --json snapshot build --name team-basic --space-id 10 --preset basic
50
+ kaiten --json query cards --snapshot team-basic --view summary --fields id,title,state
51
+ ```
52
+
53
+ ## Config and precedence
54
+
55
+ Credential resolution order:
56
+
57
+ 1. `--profile <name>`
58
+ 2. active profile from config
59
+ 3. `KAITEN_DOMAIN` + `KAITEN_TOKEN`
60
+
61
+ Recommended persistent setup:
62
+
63
+ ```bash
64
+ kaiten profile add main --domain <company-subdomain-or-url> --token <api-token> --set-active
65
+ ```
66
+
67
+ ## Safety and efficiency
68
+
69
+ - Start with read-only commands.
70
+ - Normal profiles can mutate; treat real credentials as real writes.
71
+ - For analysis-only workflows, use global `--read-only` or `KAITEN_CLI_READ_ONLY=1`; this blocks remote mutations while allowing local snapshot lifecycle operations and the POST-backed chart retrieval commands reported with `read_only_allowed=true`.
72
+ - `KAITEN_LIVE=1|true` is the explicit per-run gate for the live test suite.
73
+ - Prefer `--compact` and `--fields` to reduce payload and token cost.
74
+ - Request-scoped cache for safe GETs is built in; default `--cache-mode auto` also persists cacheable safe reads across CLI processes.
75
+ - Omit `--cache-mode` for ordinary workflows: this keeps the default `auto`.
76
+ - Use `--cache-mode refresh` once at a freshness boundary; never put it inside an entity loop. For a reused local working set, prefer `snapshot refresh`.
77
+ - Use `--cache-mode off` only for cache debugging, privacy-sensitive reads, or high-churn polling.
78
+ - Use `--cache-mode readwrite` only with an explicit, meaningful `--cache-ttl-seconds` when a fixed TTL is required.
79
+ - Heavy/batch reads and dense repeated entity reads get longer adaptive TTLs in `auto`; do not force tiny TTLs in wrapper scripts unless freshness is the main requirement.
80
+ - JSON responses include top-level `stats`; check `http_request_count`, `api_wait_ms`, cache counters, and grouped path families before repeating expensive calls.
81
+ - Use `--verbose` when you need request-path and execution diagnostics; diagnostics stay in `stderr`.
82
+ - Use `--trace-file` or `KAITEN_TRACE_FILE` when you need a JSONL trace of real command cost across a longer workflow.
83
+ - Trace is required for wrappers with at least three CLI commands, expected runs above ten HTTP requests, or unavoidable loops. Review it with `kaiten --json trace summarize --file <trace.jsonl>`.
84
+ - Treat `aggregated` and `synthetic` tools as potentially more expensive than `direct_http`.
85
+ - For high-cardinality reads, follow the heavy-data skill instead of inventing a per-entity loop.
86
+ - For metrics workflows, follow the metrics skill instead of reconstructing raw history one card at a time.
87
+ - For repeated report or analytics questions on one working set, prefer `snapshot build` plus `query cards` / `query metrics` over re-fetching the same population.
88
+ - Keep `query cards` in `summary` view by default; use `detail` or `evidence` only after local candidate reduction.
89
+ - Treat `query metrics` as a generic local metrics layer unless a workflow explicitly defines tenant-specific flow semantics outside the CLI.
90
+ - Prefer `space-topology.get`, `cards.batch-get`, `time-logs.batch-list`, `space-activity-all.get`, `card-children.batch-list`, `comments.batch-list`, and `card-location-history.batch-get` over manual orchestration loops.
91
+ - When two or more entity IDs are known and `describe` reports `bulk_alternative`, use the bulk command.
92
+ - When the same population is needed a second time, build a snapshot and continue with local `query cards` / `query metrics`.
93
+ - Before a live mutation, use `kaiten --json --profile <name> --read-only profile probe`, then follow the mutation skill: discovery, read-only investigation, exact preview, authorization, resumable manifest, small batches, and field-scoped readback.
94
+ - Addon state lives outside the normal card fields: use `card-addon-data` / `user-addon-data` for raw addon storage, and the `github-addon` commands for PRs, branches, commits and issues shown on a card.
95
+ - Attaching a PR to a card usually means the GitHub addon, not `external-links create`; check both sources when looking for every PR a card references.
96
+ - The GitHub addon UUID is derived from its mount path only on on-premises Kaiten; elsewhere it is random. `addons uid` returns the derived guess, `space-addons list` and `company-addons list` return the real one, and the `github-addon` commands re-resolve it from the card's space when the guess finds no data.
97
+ - Live validation is opt-in and documented in [LIVE_VALIDATION.md](LIVE_VALIDATION.md).
@@ -0,0 +1,107 @@
1
+ # API Behavior Matrix
2
+
3
+ Этот документ фиксирует API-контракты для `kaiten-cli`, ранее наблюдавшиеся на live test tenant и закодированные в текущем live harness.
4
+
5
+ Запуск live suite по-прежнему gated только через `KAITEN_LIVE=1|true`; special-case по домену или profile metadata для этого не используется.
6
+
7
+ ## Verification metadata
8
+
9
+ | Поле | Значение |
10
+ |------|----------|
11
+ | Contract baseline | `kaiten-cli v0.1.23` |
12
+ | Tenant class | Kaiten sandbox test tenant |
13
+ | Текущий аудит | `2026-07-09`; live suite **не запускался** |
14
+ | Последняя полная live campaign | `TBD`: дата и commit не подтверждены в репозитории |
15
+ | Источник до следующего live run | checked-in contracts и `tests/live/`; записи ниже нельзя считать повторно подтверждёнными текущим аудитом |
16
+
17
+ После следующей полной live campaign эту таблицу нужно обновить точными датой, commit SHA, версией CLI и tenant class. Secrets, tenant URL и идентификаторы тестовых сущностей сюда не записываются.
18
+
19
+ ## Default rule
20
+
21
+ Все canonical команды из registry, которые не перечислены ниже, считаются `live_passed`: они должны проходить по normal success-path в полном live suite.
22
+
23
+ ## Validated success-path contracts with special notes
24
+
25
+ | Command | Verb / Path | Status | Notes |
26
+ |---------|-------------|--------|-------|
27
+ | `automations.create` | `POST /spaces/{space_id}/automations` | `live_passed` | Успешно проходит на sandbox с known-good payload: `trigger.type=card_created`, `action.type=add_assignee`, `created`, `data.variant`, `data.userId`. |
28
+ | `automations.update` | `PATCH /spaces/{space_id}/automations/{automation_id}` | `live_passed` | Успешно проходит для automation, созданной с known-good payload. |
29
+ | `automations.delete` | `DELETE /spaces/{space_id}/automations/{automation_id}` | `live_passed` | Успешный cleanup подтверждён в live validation. |
30
+
31
+ ## Runtime-shaped contracts
32
+
33
+ | Command | Verb / Path | Status | Notes |
34
+ |---------|-------------|--------|-------|
35
+ | `boards.delete` | `DELETE /spaces/{space_id}/boards/{board_id}` | `live_passed_with_runtime_fix` | Sandbox требует `force`; CLI передаёт его в query и body. |
36
+
37
+ ## Synthetic reads
38
+
39
+ | Command | Primary endpoint | Status | Fallback |
40
+ |---------|------------------|--------|----------|
41
+ | `projects.cards.list` | `GET /projects/{project_id}/cards` | `synthetic_read` | При `405` CLI делает `GET /projects/{project_id}?with_cards_data=true` и извлекает embedded cards list. |
42
+ | `checklists.list` | `GET /cards/{card_id}` | `synthetic_read` | Extracts embedded `checklists` instead of the collection GET, which returned 405 on the tested tenant and was also reported on production in [kaiten-mcp PR #4](https://github.com/ViktorOgnev/kaiten-mcp/pull/4). |
43
+ | `checklist-items.list` | `GET /cards/{card_id}/checklists/{checklist_id}` | `synthetic_read` | Extracts `items` from the individual checklist, avoiding the unsupported collection GET. API errors are preserved. |
44
+
45
+ ## Stable expected-error contracts
46
+
47
+ | Command | Verb / Path | Status | Expected statuses | Notes |
48
+ |---------|-------------|--------|-------------------|-------|
49
+ | `removed-boards.list` | `GET /boards/removed` | `live_passed_as_expected_error` | `405` | Sandbox recycle-bin endpoint unsupported. |
50
+ | `removed-cards.list` | `GET /cards/removed` | `live_passed_as_expected_error` | `405` | Sandbox recycle-bin endpoint unsupported. |
51
+ | `card-subscribers.list` | `GET /cards/{card_id}/subscribers` | `live_passed_as_expected_error` | `405` | Direct subscriber listing unsupported on sandbox. |
52
+ | `column-subscribers.list` | `GET /columns/{column_id}/subscribers` | `live_passed_as_expected_error` | `405` | Direct subscriber listing unsupported on sandbox. |
53
+ | `service-desk.users.update` | `PATCH /service-desk/users/{user_id}` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Для текущего sandbox-аккаунта API возвращает `400 Should be service desk user`, если пользователь не является SD user. |
54
+ | `service-desk.organization-users.update` | `PATCH /service-desk/organizations/{organization_id}/users/{user_id}` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Обновление permissions для organization-user остаётся sandbox-dependent even after successful add. |
55
+
56
+ ## Conditional success-or-error contracts
57
+
58
+ Эти команды остаются live-correct, даже если sandbox вместо success-path возвращает ожидаемый `4xx`.
59
+
60
+ | Command family | Status | Expected statuses | Notes |
61
+ |----------------|--------|-------------------|-------|
62
+ | `sprints.create` | `live_passed_as_expected_error` | `403`, `405` | Создание спринта зависит от sandbox permissions/capabilities. |
63
+ | `sprints.list` | `live_passed_as_expected_error` | `403`, `405` | Чтение списка спринтов зависит от sandbox permissions/capabilities. |
64
+ | `service-desk.users.set-temp-password` | `live_passed_as_expected_error` | `403`, `404`, `405` | На sandbox может либо успешно сработать, либо вернуть documented `403/404/405`; live suite принимает оба исхода. |
65
+ | `sprints.get`, `sprints.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
66
+ | `sprints.update` | `live_passed_as_expected_error` | `403`, `404`, `405`, `500` | На sandbox update по sentinel sprint id может отдавать `500`; это зафиксировано как documented sandbox defect contract. |
67
+ | `automations.get` | `live_passed_as_expected_error` | `405` | GET-single для automation может быть unsupported даже после успешного create. |
68
+ | `automations.copy` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Даже при live-valid source automation copy остаётся sandbox-dependent. |
69
+ | `webhooks.get`, `webhooks.delete` | `live_passed_as_expected_error` | `404`, `405` | После create эти endpoints могут быть недоступны как отдельные singleton operations. |
70
+ | `workflows.create` | `live_passed_as_expected_error` | `403`, `405` | Создание workflow зависит от sandbox permissions/capabilities. |
71
+ | `workflows.get`, `workflows.update`, `workflows.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
72
+ | `service-desk.requests.create` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | Request creation permission-dependent. |
73
+ | `service-desk.requests.get`, `service-desk.requests.update`, `service-desk.requests.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
74
+ | `service-desk.sla-rules.create` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | SLA rule creation schema- and permission-dependent. |
75
+ | `service-desk.sla-rules.update`, `service-desk.sla-rules.delete` | `live_passed_as_expected_error` | `400`, `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
76
+ | `compute-jobs.cancel` | `live_passed_as_expected_error` | `400`, `404`, `409` | Cancel зависит от состояния compute job. |
77
+ | `user-timers.list` | `live_passed_as_expected_error` | `403`, `405` | Sandbox timer surface нестабилен. |
78
+ | `user-timers.create` | `live_passed_as_expected_error` | `400`, `403`, `405`, `409` | Timer creation зависит от sandbox semantics. |
79
+ | `user-timers.get`, `user-timers.update`, `user-timers.delete` | `live_passed_as_expected_error` | `403`, `404`, `405` | При недоступном create live suite валидирует sentinel error contract. |
80
+
81
+ ## Not yet live-validated
82
+
83
+ Эти команды добавлены после последней полной live campaign. Сценарии для них уже есть в
84
+ `tests/live/`, но прогона, подтверждающего контракт, не было, поэтому default rule
85
+ `live_passed` на них не распространяется.
86
+
87
+ | Command family | Verb / Path | Status | Notes |
88
+ |----------------|-------------|--------|-------|
89
+ | `restrictions.list`, `restrictions.get` | `GET /spaces/{space_id}/restrictions` | `live_not_validated` | Недокументированное расширение по серверному коду. Весь список без пагинации; `get` выбирает UUID из списка и возвращает явную ошибку при отсутствии. Ограничения workflow исключены. |
90
+ | `restrictions.create`, `restrictions.copy` | `POST /spaces/{space_id}/restrictions` | `live_not_validated` | Создание принимает `conditions` и `restrictions`; копирование передаёт `source_restriction_id` в целевое пространство и сохраняет фактический статус ответа, включая `broken`. |
91
+ | `restrictions.update`, `restrictions.delete` | `PATCH` / `DELETE /spaces/{space_id}/restrictions/{restriction_id}` | `live_not_validated` | PATCH передаёт только заданные поля; массивы заменяются целиком. `status=active\|disabled`. Для `error_text` необходимо ещё одно поле. DELETE может вернуть пустое тело. Opt-in lifecycle и проверяемая очистка добавлены, но не запускались. |
92
+ | `addons.list` | `GET /addons` | `live_not_validated` | Каталог опубликованных аддонов без фильтра по компании; live suite принимает success или `403/405`. |
93
+ | `company-addons.list` | `GET /company/addons` | `live_not_validated` | Аддоны, зарегистрированные самой компанией, включая неопубликованные. |
94
+ | `addons.uid` | локальная команда | `live_not_validated` | UUID v5 считается локально, обращения к API нет; проверяется совпадение с эталонным UID `/github`. |
95
+ | `space-addons.list` | `GET /spaces/{space_id}/addons` | `live_not_validated` | Требует права `space.addons.read`. |
96
+ | `space-addons.install`, `space-addons.uninstall` | `PATCH` / `DELETE /spaces/{space_id}/addons/{addon_uid}` | `live_not_validated` | В live suite проверяются только на sentinel UID, чтобы не менять набор аддонов реального пространства. Sentinel подобран так, чтобы проходить `uuidIdRule`, иначе probe подтверждал бы 404 от несовпадения маршрута, а не контракт эндпоинта. |
97
+ | `card-addon-data.get`, `user-addon-data.get` | `GET .../addons-data/{addon_uid}` | `live_not_validated` | Чтение; для неустановленного аддона возможен пустой ответ или `403/404/405`. |
98
+ | `card-addon-data.set`, `user-addon-data.set` | `PATCH .../addons-data/{addon_uid}` | `live_not_validated` | Запись проверяется только на sentinel UID: реальная запись требует установленного аддона и `card.update`. |
99
+ | `github-addon.*.list` | `GET /cards/{card_id}/addons-data/{addon_uid}` | `live_not_validated` | Чтение shared-ключей `attachedPulls`, `attachedBranches`, `attachedCommits`, `attachedIssues`. При пустом ответе на выведенный UID дополнительно читаются `GET /cards/{id}` и `GET /spaces/{id}/addons`, чтобы взять реально зарегистрированный UID. |
100
+ | `github-addon.*.attach`, `github-addon.*.detach` | `PATCH /cards/{card_id}/addons-data/{addon_uid}` | `live_not_validated` | Live suite покрывает только `--dry-run`: реальная запись изменила бы данные аддона на живой карточке. |
101
+
102
+ ## Policy exclusions
103
+
104
+ | Command | Status | Notes |
105
+ |---------|--------|-------|
106
+ | `api-keys.create` | `policy_excluded` | Создание ключей не тестируется live, потому что clean teardown потребовал бы testing delete. |
107
+ | `api-keys.delete` | `policy_excluded` | Явно исключено по пользовательской политике. |
@@ -0,0 +1,183 @@
1
+ # Architecture
2
+
3
+ `kaiten-cli` is organized around one core idea: the tool surface is declared once, in the registry, and every other layer consumes that metadata.
4
+
5
+ ## System Map
6
+
7
+ Runtime flow:
8
+
9
+ `registry -> discovery/app -> input merge -> executor -> client -> transforms/output`
10
+
11
+ For high-cardinality reads there is one more path:
12
+
13
+ `registry -> discovery/app -> input merge -> executor -> execution context -> runtime behavior -> bulk worker pool -> per-worker clients`
14
+
15
+ For repeated report and analytics workflows there is also a local-first path:
16
+
17
+ `registry -> discovery/app -> input merge -> executor -> local snapshot store -> local query/metrics`
18
+
19
+ Successful interactive commands have an independent post-command path:
20
+
21
+ `app -> install metadata -> cached Git tag check -> optional installer confirmation`
22
+
23
+ Main layers:
24
+
25
+ - `src/kaiten_cli/registry/`
26
+ Source of truth for the command catalog. Each tool is declared as a `ToolSpec` with canonical name, MCP alias, schema, examples, request metadata, response policy, and optional runtime behavior.
27
+ - `src/kaiten_cli/runtime/`
28
+ Execution layer. Builds requests, resolves profiles and cache settings, applies read-only mutation policies, runs HTTP calls, handles synthetic and aggregated reads, persists local snapshots, and serves local-only query commands.
29
+ - `src/kaiten_cli/runtime/support/`
30
+ Domain-specific helpers used by runtime behaviors for documents, projects, tree aggregation, cards bulk pagination, relation/comment batch reads, activity pagination, and space topology aggregation.
31
+ - top-level `src/kaiten_cli/`
32
+ Stable package surface and shared core: `app.py`, `discovery.py`, `profiles.py`, `models.py`, `errors.py`, entrypoints.
33
+
34
+ ## Registry vs Runtime
35
+
36
+ This repo does not have two different sets of tools.
37
+
38
+ - `registry` defines the tools.
39
+ - `runtime` executes the tools.
40
+
41
+ If a command looks “special”, it is still a registry-defined tool. The only difference is that its `ToolSpec.runtime_behavior` points to a request shaper or custom executor in `src/kaiten_cli/runtime/behaviors.py`.
42
+
43
+ That means:
44
+
45
+ - `cards.list` is a registry tool with direct HTTP execution
46
+ - `projects.cards.list` is a registry tool with synthetic execution
47
+ - `cards.list-all` is a registry tool with aggregated execution
48
+
49
+ The command catalog stays centralized even when runtime semantics differ.
50
+
51
+ ## Output Locale
52
+
53
+ `i18n.py` holds an invocation-scoped `ContextVar`. The root Click group and public
54
+ entrypoint resolve `--locale ru|en` before help and parser errors; the flag wins
55
+ over `KAITEN_CLI_LOCALE`, then `en`. OS locale and profiles do not participate.
56
+ The caller (agent) chooses the language from the conversation.
57
+
58
+ English source templates are stable message IDs. `locales/ru.json` is an offline
59
+ catalog shipped in the wheel. Runtime prose opts in with `tr`; discovery copies
60
+ only explicitly defined prose fields, including JSON Schema descriptions.
61
+ API payloads, user values, enum values, command identifiers and trace fields are
62
+ never passed through recursive translation. Raw API/OS/library diagnostics retain
63
+ their source language inside a localized CLI message.
64
+
65
+ `localized_click.py` binds Click's module-local gettext callbacks once to the
66
+ context-aware dispatcher. Help is rendered from command copies; Click's cached
67
+ help option remains English. Context tokens reset on success and failure, and
68
+ async workers inherit the invocation locale. Dependency updates must pass the
69
+ catalog check and sequential/concurrent locale regression tests.
70
+
71
+ Registry metadata stays canonical English for stable generated documentation.
72
+ Search uses both language descriptions plus private `search_terms`; changing the
73
+ output locale cannot change ranking. Agent instructions and gateway prompts
74
+ require an explicit locale per invocation. This is a language contract, not a
75
+ claim of improved model accuracy; that requires separate evaluation.
76
+
77
+ Run `python scripts/check_locales.py` for coverage, formatting placeholders and
78
+ command-flag preservation. Unknown messages fall back to English at runtime;
79
+ the check and tests fail for missing known translations. See
80
+ [localization verification](docs/LOCALIZATION_VERIFICATION.md) for invariants and evidence.
81
+
82
+ ## Execution Context and Cache
83
+
84
+ Each CLI invocation builds one execution context for the selected profile.
85
+
86
+ - request-scoped cache is always enabled for safe GET reads
87
+ - identical in-flight GETs are deduplicated inside the same execution context
88
+ - persistent disk cache defaults to `--cache-mode auto` for cacheable safe reads
89
+ - persistent cache scope includes a one-way credential fingerprint, so different users of the same tenant/profile cannot reuse each other's cached responses
90
+ - `auto` uses adaptive TTLs: small fresh reads stay short, while heavy batch/aggregated reads, closed historical windows, and dense same-family entity loops are retained longer
91
+ - worker clients share one execution-scoped rate limiter instead of multiplying the request budget by worker count
92
+ - every attempted remote mutation clears persistent cache for the current credential scope, including ambiguous failures, so verification reads cannot reuse pre-mutation data
93
+ - incompatible or corrupt local sqlite cache files are treated as disposable state and recreated automatically
94
+ - credential config, HTTP cache, snapshots, and trace files are stored with user-only file permissions (`0600`); application-owned parent directories are `0700`, while existing user-selected trace/config parent modes are preserved
95
+ - JSON success/error envelopes include runtime `stats` with duration, HTTP/API wait, cache counters, and grouped method/path-family aggregates
96
+ - optional JSONL trace output can be appended through `--trace-file` or `KAITEN_TRACE_FILE`
97
+
98
+ This keeps freshness controls explicit (`refresh` / `off`) while reducing repeated entity, page, and card-scoped reads in synthetic, aggregated, worker-pooled, and external-script paths.
99
+
100
+ ## Post-command Update Check
101
+
102
+ `update_check.py` is outside the Kaiten execution/runtime path. It recognizes only
103
+ remote Git installations described by standard Python `direct_url.json` metadata,
104
+ detects the owning `pipx`, `uv tool`, or pip environment, and compares the
105
+ installed version with stable `vX.Y.Z` tags from the same remote.
106
+
107
+ The check runs only after a successful interactive command, is cached for 24
108
+ hours, and is disabled for JSON/non-TTY/help/version/completion calls. Network and
109
+ metadata failures are fail-open. The cache stores a source hash rather than the
110
+ Git URL, and installer commands are passed directly to `subprocess` without a
111
+ shell. A confirmed update is a separate local side effect and does not alter the
112
+ already completed Kaiten command.
113
+
114
+ ## Mutation Safety
115
+
116
+ - Transport retries are limited to safe HTTP methods. An ambiguous timeout, connection failure, HTTP 5xx, or malformed successful response for a remote mutation is returned without retry and explicitly tells the caller to verify remote state.
117
+ - Global `--read-only` and `KAITEN_CLI_READ_ONLY=1` block registry tools that mutate Kaiten through `RuntimeBehavior.enforce_mutation_guard`.
118
+ - Local snapshot lifecycle commands opt out of that guard because they only write derived local sqlite state; their Kaiten API calls remain reads.
119
+ - Three POST-backed chart retrieval commands opt out because they only submit analytics filters; chart build commands remain guarded because they create transient compute jobs.
120
+ - Discovery exposes `read_only_allowed` separately from HTTP-method-derived `mutation`.
121
+ - The agent gateway passes remote and local-storage read-only environment policies, disables ambient Codex user config/rules, applies request limits, and requires bearer authentication for non-loopback binds. Existing snapshots use a SQLite read-only connection inside that sandbox; snapshot lifecycle writes are rejected. Because the child still has shell access and Kaiten credentials, this is a cooperative safety layer rather than a hard authorization boundary; untrusted/non-loopback deployments require server-side credential restrictions and an external TLS/connection-limiting proxy.
122
+
123
+ The trace layer records command-level facts such as duration, real HTTP request count, API wait time, retry/cache counters, grouped path families, and bulk metadata. It exists because outer Codex/session logs do not reliably see internal Kaiten subprocess calls from higher-level scripts.
124
+
125
+ ## Local-first Snapshot Layer
126
+
127
+ `snapshot.*` and `query.*` are still registry-defined tools. They differ from transport tools because their `custom` executor path persists and reads local sqlite state in `runtime/snapshots.py`.
128
+
129
+ Current intent:
130
+
131
+ - `snapshot.build` and `snapshot.refresh`
132
+ Fetch a bounded working set from Kaiten once, then persist topology, cards, activity, history, time logs, relations, comments, and derived fields locally.
133
+ - `query.cards`
134
+ Run local filtering and candidate reduction without new API calls. The default local view is `summary`; `detail` and `evidence` are explicit escalations.
135
+ - `query.metrics`
136
+ Compute local metrics over the stored working set instead of rebuilding the same population/history path on every run.
137
+
138
+ This shifts repeated headless analytics from `API-per-question` to `snapshot-per-window`.
139
+ The path stays explicit: normal transport commands are not silently rewritten to snapshot-backed reads.
140
+ The snapshot sqlite store is also treated as disposable derived state: incompatible or corrupt local files are dropped and recreated instead of migrated in place.
141
+
142
+ ## Execution Modes
143
+
144
+ - `direct_http`
145
+ One request derived directly from `OperationSpec`.
146
+ - `synthetic`
147
+ Runtime may use fallback logic or reshape API responses to preserve a stable tool contract.
148
+ - `aggregated`
149
+ Runtime performs bounded multi-request collection and returns one logical result.
150
+ - `custom`
151
+ Runtime uses a dedicated executor because the API contract does not map cleanly to a simple request/response flow.
152
+
153
+ `custom` now covers two families:
154
+
155
+ - transport-adjacent orchestration such as batch/history/topology paths
156
+ - local-first snapshot/query paths that do not map to one upstream endpoint
157
+
158
+ Bulk reads are still registry-defined tools. The difference is that some aggregated tools now use a dedicated bulk execution path instead of repeated one-shot CLI invocations. Current examples include `cards.list-all`, `cards.batch-get`, `time-logs.batch-list`, `space-activity-all.get`, `space-topology.get`, `card-children.batch-list`, `comments.batch-list`, and `card-location-history.batch-get`.
159
+
160
+ ## Docs Map
161
+
162
+ Primary docs:
163
+
164
+ - [README.md](README.md) for install, usage, config, and operator guidance
165
+ - [COMMAND_REFERENCE.md](COMMAND_REFERENCE.md) for the full generated command catalog
166
+ - [AGENTS.md](AGENTS.md) for agent-specific usage and safety shortcuts
167
+ - `skills/` for repo-local LLM workflows in `SKILL.md` format
168
+ - [LIVE_VALIDATION.md](LIVE_VALIDATION.md) for live test process
169
+ - [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md) for documented sandbox contracts
170
+ - `ARCHITECTURE.md` for the system map
171
+
172
+ `ARCHITECTURE_REVIEW.md` is intentionally kept out of tracked docs. It is an audit artifact, not the maintained architecture reference.
173
+
174
+ ## Known Tradeoffs
175
+
176
+ - The manual registry is easy to inspect, but large and maintenance-heavy.
177
+ - Runtime behaviors are now explicit, but still centralized in one behavior module.
178
+ - Request-scoped cache is built in, but persistent cache deliberately stays conservative and opt-in.
179
+ - Snapshot refresh is still rebuild-oriented in v1; there is no incremental sync yet.
180
+ - Local metric semantics are still generic; tenant-specific flow profiles are intentionally deferred.
181
+ - The default local card path is intentionally summary-first to reduce token and payload cost before LLM involvement.
182
+ - The CLI favors boundedness and predictability over maximum raw throughput, so bulk execution stays conservative by default.
183
+ - Live validation is explicit and well-documented, but sandbox contracts remain inherently unstable.
@@ -0,0 +1,186 @@
1
+ # Live Validation
2
+
3
+ Этот документ описывает, как устроена полная live-проверка `kaiten-cli` на реальных credentials с явным per-run gate.
4
+
5
+ Текущая матрица контрактов в основном собрана на sandbox tenant, но сам live harness не привязывается к домену, имени профиля или profile metadata автоматически.
6
+
7
+ ## Статус проверки
8
+
9
+ - На `2026-07-09` в рамках текущего аудита live suite **не запускался**.
10
+ - Текущий contract baseline — `kaiten-cli v0.1.23`; tenant class ранее зафиксированных контрактов — Kaiten sandbox test tenant.
11
+ - Дата и commit последней полной live campaign не подтверждены в репозитории и остаются `TBD`.
12
+ - До нового запуска [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md) описывает ранее наблюдавшиеся и закодированные контракты, а не свежую проверку production или sandbox API.
13
+
14
+ После каждой полной campaign нужно записать в оба документа дату, commit SHA, версию CLI и tenant class, не сохраняя credentials, tenant URL и идентификаторы временных сущностей.
15
+
16
+ ## Ограничения пространства
17
+
18
+ Группа `restrictions` — недокументированное расширение по серверному коду, со статусом
19
+ `live_not_validated`. На 2026-10-06 live-сценарий **не запускался**.
20
+ Отдельный opt-in сценарий создаёт два временных пространства, создаёт правило,
21
+ проверяет список и просмотр, отключение и включение с readback, копирование, удаление
22
+ и отсутствие удалённых правил в списках. Cleanup зарегистрирован сразу после создания
23
+ каждого правила и повторно проверяет его отсутствие. Существующие правила не используются.
24
+ Сценарий также включён в полную последовательную campaign.
25
+
26
+ После зелёных локальных проверок и выбора тестовых credentials:
27
+
28
+ ```bash
29
+ KAITEN_LIVE=1 python -m pytest -q -m live tests/live/test_restrictions_live.py
30
+ ```
31
+
32
+ Перед мутациями выполняется `profile probe` в режиме `--read-only`.
33
+ Отдельный сценарий записывает trace в временный каталог pytest. Успешные offline-тесты
34
+ не подтверждают доступность маршрутов на действующем сервере.
35
+
36
+ ## Базовые правила
37
+
38
+ - live suite запускается только после зелёного локального `pytest`
39
+ - live suite запускается только при явном `KAITEN_LIVE=1|true`
40
+ - live suite никогда не идёт в default test run
41
+ - выполнение строго последовательное, без параллельных API-вызовов
42
+ - между вызовами остаются паузы для соблюдения low-load discipline
43
+ - все mutation-сценарии обязаны иметь проверяемый teardown
44
+ - если cleanup падает, live test падает
45
+
46
+ ## Outcome classes
47
+
48
+ Для live verification используются следующие статусы:
49
+
50
+ - `live_passed`
51
+ Команда реально проходит по success-path на текущем live tenant.
52
+ - `live_passed_with_runtime_fix`
53
+ Команда проходит на текущем live tenant, но для этого понадобился runtime shaping в CLI.
54
+ - `live_passed_as_expected_error`
55
+ Живой API стабильно или условно возвращает ожидаемый `4xx`, и этот контракт проверяется как корректный.
56
+ - `synthetic_read`
57
+ Прямой endpoint нестабилен или unsupported, но CLI честно собирает эквивалентный read из другого безопасного endpoint.
58
+ - `policy_excluded`
59
+ Команда сознательно исключена из live validation по политике безопасности.
60
+ - `live_not_validated`
61
+ Команда добавлена после последней полной campaign. В live suite сценарий для неё есть, но
62
+ реального прогона, подтверждающего контракт, ещё не было.
63
+
64
+ ## Что считается успешной live-валидацией
65
+
66
+ Команда считается live-covered только если выполнено одно из условий:
67
+
68
+ 1. success-path реально отработал и postcondition подтверждён;
69
+ 2. documented expected-error-path реально отработал и статус соответствует контракту;
70
+ 3. synthetic fallback реально отработал и вернул ожидаемые данные;
71
+ 4. команда помечена `policy_excluded`.
72
+
73
+ Статус `live_not_validated` покрытием не считается: он честно фиксирует, что сценарий в
74
+ harness уже написан, но прогона ещё не было.
75
+
76
+ Скрытых “ну это вроде нормально” сценариев быть не должно.
77
+
78
+ ## Как устроен live harness
79
+
80
+ Файлы:
81
+
82
+ - [tests/live/conftest.py](tests/live/conftest.py)
83
+ - [tests/live/test_sandbox_live_full.py](tests/live/test_sandbox_live_full.py)
84
+
85
+ Harness делает следующее:
86
+
87
+ - создаёт run-scoped имена временных сущностей
88
+ - ведёт cleanup stack в обратном порядке
89
+ - использует только canonical commands для live coverage
90
+ - считает покрытие по всему registry surface, кроме policy exclusions
91
+ - различает normal success path и expected-error path
92
+
93
+ ## Policy exclusions
94
+
95
+ Сейчас live validation не включает:
96
+
97
+ - `api-keys.create`
98
+ - `api-keys.delete`
99
+
100
+ Причина: clean teardown невозможен без тестирования удаления ключей, а удаление ключей пользователь запретил проверять live.
101
+
102
+ ## Synthetic contracts
103
+
104
+ Явные synthetic reads:
105
+
106
+ - `projects.cards.list`
107
+ - сначала CLI пробует `GET /projects/{project_id}/cards`
108
+ - если live API отвечает `405`, CLI делает `GET /projects/{project_id}?with_cards_data=true`
109
+ - затем извлекает embedded cards list из project payload
110
+ - `checklists.list`
111
+ - direct `GET /cards/{card_id}/checklists` возвращает `405`
112
+ - CLI делает `GET /cards/{card_id}` и извлекает embedded `checklists`
113
+ - `checklist-items.list`
114
+ - direct `GET /cards/{card_id}/checklists/{checklist_id}/items` возвращает `405`
115
+ - CLI делает `GET /cards/{card_id}` и извлекает `items` из matching checklist
116
+
117
+ ## Expected-error contracts
118
+
119
+ Некоторые команды считаются live-correct именно через documented `4xx`:
120
+
121
+ - `removed-boards.list` -> `405`
122
+ - `removed-cards.list` -> `405`
123
+ - `card-subscribers.list` -> `405`
124
+ - `column-subscribers.list` -> `405`
125
+
126
+ Есть и условные tenant'ы, где live API может разрешить success-path или вернуть ожидаемый `4xx`:
127
+
128
+ - `automations.copy`
129
+ - `sprints.*`
130
+ - `workflows.*`
131
+ - `service-desk.requests.*`
132
+ - `service-desk.sla-rules.*`
133
+ - `user-timers.*`
134
+ - `compute-jobs.cancel`
135
+
136
+ Отдельно зафиксирован automation contract:
137
+
138
+ - `automations.create` и `automations.update` проходят на success-path при e2e-shaped payload:
139
+ - `trigger.type = card_created`
140
+ - `action.type = add_assignee`
141
+ - `action.created = <iso datetime>`
142
+ - `action.data.variant = specific`
143
+ - `action.data.userId = <current_user_id>`
144
+ - `automations.get` может возвращать `405` даже после успешного create
145
+ - `automations.copy` остаётся conditional sandbox contract
146
+
147
+ Также зафиксирован ещё один стабильный expected-error:
148
+
149
+ - `service-desk.users.update` -> `400`, если текущий live-пользователь не является Service Desk user
150
+
151
+ И один смешанный Service Desk contract:
152
+
153
+ - `service-desk.users.set-temp-password` может либо успешно отработать, либо вернуть `403/404/405`
154
+ - `service-desk.organization-users.update` может либо успешно отработать, либо вернуть `400/403/404/405` даже после успешного `organization-users.add`
155
+
156
+ Точные статусы и примечания см. в [API_BEHAVIOR_MATRIX.md](API_BEHAVIOR_MATRIX.md).
157
+
158
+ ## Запуск
159
+
160
+ ```bash
161
+ KAITEN_LIVE=true KAITEN_DOMAIN=<company-subdomain-or-url> KAITEN_TOKEN=... \
162
+ .venv/bin/pytest -m live -o addopts='--disable-socket --allow-unix-socket' \
163
+ tests/live/test_sandbox_live_full.py
164
+ ```
165
+
166
+ Если credentials уже сохранены в обычном active profile, достаточно выставить только `KAITEN_LIVE=1|true`.
167
+
168
+ ## Что делать при новом blocker-е
169
+
170
+ 1. Сначала определить, это runtime bug, live API limitation или synthetic-fallback candidate.
171
+ 2. Если это runtime bug — добавить/обновить offline test и чинить CLI.
172
+ 3. Если это корректный expected error — зафиксировать его в `API_BEHAVIOR_MATRIX.md` и, если меняется объяснение системы, в `ARCHITECTURE.md`.
173
+ 4. Если это честный synthetic candidate — сначала добавить failing offline test, потом реализовать fallback.
174
+
175
+ ## Изменения чтения чеклистов
176
+
177
+ `checklists.list` читает `GET /cards/{card_id}` и извлекает `checklists`.
178
+ Collection GET возвращал 405 на тестовом инстансе; такое же поведение на боевом
179
+ инстансе описано автором [kaiten-mcp PR #4](https://github.com/ViktorOgnev/kaiten-mcp/pull/4).
180
+ Это свидетельство автора PR, а не новая live-проверка CLI.
181
+
182
+ `checklist-items.list` теперь читает `GET /cards/{card_id}/checklists/{checklist_id}`
183
+ и извлекает `items`. Пустой чеклист возвращает `[]`, а ошибки API, включая 404,
184
+ сохраняются. Некорректный ответ без массива `items` считается ошибкой транспорта.
185
+ Оба обхода применяются ко всем профилям; тестовый инстанс — место наблюдения,
186
+ а не особый режим CLI. Изменение проверено офлайн через HTTP-моки.