tcw-cli 3.0.0__tar.gz → 3.0.2__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 (178) hide show
  1. {tcw_cli-3.0.0/tcw_cli.egg-info → tcw_cli-3.0.2}/PKG-INFO +3 -2
  2. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/README.md +2 -1
  3. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/pyproject.toml +1 -1
  4. tcw_cli-3.0.2/tcw/__init__.py +1 -0
  5. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/project.py +2 -2
  6. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/tickets.py +3 -1
  7. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/unattended-work.md +1 -1
  8. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/plan.md +8 -2
  9. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/qa.md +10 -6
  10. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/request.md +12 -2
  11. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/spec.md +2 -0
  12. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/resolve.py +8 -2
  13. {tcw_cli-3.0.0 → tcw_cli-3.0.2/tcw_cli.egg-info}/PKG-INFO +3 -2
  14. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_project_registry.py +5 -6
  15. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_prompt_fallback.py +5 -0
  16. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_repo_lifecycle.py +1 -0
  17. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_shipped_prompts.py +47 -0
  18. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_store_provisioning.py +18 -18
  19. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_upstream_projects.py +22 -22
  20. tcw_cli-3.0.0/tcw/__init__.py +0 -1
  21. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/LICENSE +0 -0
  22. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/setup.cfg +0 -0
  23. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/capabilities/__init__.py +0 -0
  24. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/capabilities/cli.py +0 -0
  25. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/cli.py +0 -0
  26. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/cli_help.py +0 -0
  27. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/cli_suggest.py +0 -0
  28. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/config.py +0 -0
  29. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/config_cli.py +0 -0
  30. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/errors.py +0 -0
  31. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/exit.py +0 -0
  32. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/findings.py +0 -0
  33. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/output.py +0 -0
  34. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/projects_cli.py +0 -0
  35. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/refs.py +0 -0
  36. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/__init__.py +0 -0
  37. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/dist/client/assets/index-BGwvKkRc.js +0 -0
  38. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/dist/client/assets/index-DkarCRfj.css +0 -0
  39. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/dist/client/index.html +0 -0
  40. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/dist/client/theme-init.js +0 -0
  41. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/files.py +0 -0
  42. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/records.py +0 -0
  43. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/server.py +0 -0
  44. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/services.py +0 -0
  45. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/serve/work.py +0 -0
  46. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/stdin.py +0 -0
  47. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/__init__.py +0 -0
  48. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/base.py +0 -0
  49. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/checkouts.py +0 -0
  50. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/config_edit.py +0 -0
  51. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/fs.py +0 -0
  52. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/store/yaml_source.py +0 -0
  53. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/taxonomy/__init__.py +0 -0
  54. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/taxonomy/cli.py +0 -0
  55. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/validate.py +0 -0
  56. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/__init__.py +0 -0
  57. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/advance.py +0 -0
  58. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/backend.py +0 -0
  59. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/cli.py +0 -0
  60. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/config.py +0 -0
  61. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/fs_backend.py +0 -0
  62. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/gates.py +0 -0
  63. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/generate.py +0 -0
  64. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/hooks.py +0 -0
  65. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/__init__.py +0 -0
  66. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/backend.py +0 -0
  67. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/client.py +0 -0
  68. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/config.py +0 -0
  69. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/jql.py +0 -0
  70. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/mapping.py +0 -0
  71. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/jira/remote.py +0 -0
  72. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/layout.py +0 -0
  73. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/model.py +0 -0
  74. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/open.py +0 -0
  75. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/passages.py +0 -0
  76. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/audit-backlog.md +0 -0
  77. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/create-work.md +0 -0
  78. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/documentation-sync.md +0 -0
  79. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/pause-work.md +0 -0
  80. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/search.md +0 -0
  81. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/procedures/triage-issues.md +0 -0
  82. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/implement.md +0 -0
  83. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/inbox.md +0 -0
  84. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/postmortem.md +0 -0
  85. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/prompts/review.md +0 -0
  86. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/record.py +0 -0
  87. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw/work/references.py +0 -0
  88. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw_cli.egg-info/SOURCES.txt +0 -0
  89. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw_cli.egg-info/dependency_links.txt +0 -0
  90. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw_cli.egg-info/entry_points.txt +0 -0
  91. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw_cli.egg-info/requires.txt +0 -0
  92. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tcw_cli.egg-info/top_level.txt +0 -0
  93. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capabilities.py +0 -0
  94. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capabilities_cli_contract.py +0 -0
  95. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capabilities_federation.py +0 -0
  96. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capabilities_reset.py +0 -0
  97. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capabilities_rm.py +0 -0
  98. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_capability_ref_wording.py +0 -0
  99. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_check_versions.py +0 -0
  100. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_cli_contract.py +0 -0
  101. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_cli_guide.py +0 -0
  102. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_cli_handler.py +0 -0
  103. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_cli_help_standard.py +0 -0
  104. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_command_suggestions.py +0 -0
  105. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_committed_paths.py +0 -0
  106. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_config_edit.py +0 -0
  107. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_config_edit_writers.py +0 -0
  108. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_configuration_text_home.py +0 -0
  109. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_cut_version.py +0 -0
  110. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_doc_vocabulary.py +0 -0
  111. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_docs_describe_3_0.py +0 -0
  112. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_documentation_config.py +0 -0
  113. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_documentation_prompt.py +0 -0
  114. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_documentation_sync_wiring.py +0 -0
  115. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_documented_cli_surface.py +0 -0
  116. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_dynamic_skill_marker.py +0 -0
  117. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_environment_hardness.py +0 -0
  118. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_eval_coverage.py +0 -0
  119. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_eval_files_changed.py +0 -0
  120. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_eval_fixture.py +0 -0
  121. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_eval_grading.py +0 -0
  122. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_eval_runner.py +0 -0
  123. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_falsification_rule.py +0 -0
  124. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_findings_type.py +0 -0
  125. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_generate_hook.py +0 -0
  126. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_git_example.py +0 -0
  127. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_init_configured_tree_path.py +0 -0
  128. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_init_provision_contract.py +0 -0
  129. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_item_tags_read.py +0 -0
  130. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_ledger_3_0.py +0 -0
  131. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_legacy_store_config.py +0 -0
  132. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_lifecycle_config_tags.py +0 -0
  133. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_literal_store_names.py +0 -0
  134. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_migration_guide.py +0 -0
  135. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_multiproject.py +0 -0
  136. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_no_node.py +0 -0
  137. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_override_in_linked_worktree.py +0 -0
  138. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_override_letter_case.py +0 -0
  139. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_override_references.py +0 -0
  140. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_partial_removal.py +0 -0
  141. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_plugin_manifests.py +0 -0
  142. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_procedure_config.py +0 -0
  143. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_procedure_verb.py +0 -0
  144. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_project_graph_paths.py +0 -0
  145. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_project_overrides.py +0 -0
  146. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_projects_list.py +0 -0
  147. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_refs.py +0 -0
  148. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_remote_session_setup.py +0 -0
  149. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_require_artifact.py +0 -0
  150. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_routing_nodes.py +0 -0
  151. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_session_bootstrap.py +0 -0
  152. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_shipped_procedures.py +0 -0
  153. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_shipped_text.py +0 -0
  154. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_skill_flow.py +0 -0
  155. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_skill_path_pointers.py +0 -0
  156. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_smoke.py +0 -0
  157. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_stage_verb.py +0 -0
  158. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_static_guards.py +0 -0
  159. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_stdin.py +0 -0
  160. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_stdin_cli.py +0 -0
  161. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_store_bounds.py +0 -0
  162. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_store_editor.py +0 -0
  163. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_store_nodes.py +0 -0
  164. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_subprocess_stdin.py +0 -0
  165. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_suite_runs_its_own_tcw.py +0 -0
  166. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_taxonomy.py +0 -0
  167. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_taxonomy_cli_contract.py +0 -0
  168. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_taxonomy_rm_gaps.py +0 -0
  169. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_tree_store_files_only.py +0 -0
  170. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_tree_store_raises.py +0 -0
  171. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_unattended_work_skill.py +0 -0
  172. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_unpushed_version_script.py +0 -0
  173. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_upcoming_entries.py +0 -0
  174. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_validate.py +0 -0
  175. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_validate_command.py +0 -0
  176. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_validate_moved_stores.py +0 -0
  177. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_validate_target.py +0 -0
  178. {tcw_cli-3.0.0 → tcw_cli-3.0.2}/tests/test_worktree_sibling_nodes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tcw-cli
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -724,7 +724,8 @@ A change to the product is followed from the first request to the records:
724
724
  In filesystem mode, the agent working `qa` may record the verdict itself, unless
725
725
  the project's own instructions for `qa` ask for a person to decide. When they
726
726
  do, the agent still writes the round, recording the person's decision. In Jira
727
- mode, a person accepts or rejects on the ticket.
727
+ mode, a person accepts or rejects: on the ticket, or by telling the agent,
728
+ which then moves the ticket and records who decided.
728
729
 
729
730
  Work reaches taxonomy through those capabilities: a new capability names the
730
731
  vocabulary and feature it involves, and those entries must exist first.
@@ -508,7 +508,8 @@ A change to the product is followed from the first request to the records:
508
508
  In filesystem mode, the agent working `qa` may record the verdict itself, unless
509
509
  the project's own instructions for `qa` ask for a person to decide. When they
510
510
  do, the agent still writes the round, recording the person's decision. In Jira
511
- mode, a person accepts or rejects on the ticket.
511
+ mode, a person accepts or rejects: on the ticket, or by telling the agent,
512
+ which then moves the ticket and records who decided.
512
513
 
513
514
  Work reaches taxonomy through those capabilities: a new capability names the
514
515
  vocabulary and feature it involves, and those entries must exist first.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tcw-cli"
7
- version = "3.0.0"
7
+ version = "3.0.2"
8
8
  description = "Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1 @@
1
+ __version__ = "3.0.2"
@@ -39,8 +39,8 @@ def validate_project_id(project_id: str) -> str:
39
39
  def override_variable(project_id: str) -> str:
40
40
  """The environment variable that says where `project_id` lives on this machine.
41
41
 
42
- The id, uppercased, with `-` as `_`: `proposit-core` →
43
- `TCW_PROJECT_PROPOSIT_CORE`. **Project ids, not repository names** — the two are
42
+ The id, uppercased, with `-` as `_`: `app-repo` →
43
+ `TCW_PROJECT_APP_REPO`. **Project ids, not repository names** — the two are
44
44
  routinely different, and a workspace where they are crossed is what this
45
45
  mapping is most often got wrong against.
46
46
 
@@ -392,7 +392,9 @@ def delegate_to_jira(project_id: str, title: str, request: str | None,
392
392
  raise _named(BackendError(f"created {key} for {project_id}, but did not finish "
393
393
  f"making it the item {slug}: {error}; finish with "
394
394
  f"`tcw work tickets adopt {key}` there"), key) from None
395
- report(f"the new files in {backend.work_path / slug.folder} are left uncommitted")
395
+ report(f"the new files in {backend.work_path / slug.folder} are left uncommitted; "
396
+ f"record them in that project's version control before filing into "
397
+ f"{project_id} again, or the next ticket stays in its Jira inbox")
396
398
  return str(slug)
397
399
 
398
400
 
@@ -29,7 +29,7 @@ advisor alone.
29
29
 
30
30
  | The stage asks for | Do this instead |
31
31
  | --------------------------- | --------------- |
32
- | What the requester wants, at request | Do not ask the advisors: what the requester wants is not theirs to know. Write the request from the evidence available, marking each assumption, as the request prompt says when there is no user to ask. Where the backend keeps the request, as Jira does, post your questions with `tcw work comment <slug>` instead and leave its text alone. Then continue. |
32
+ | What the requester wants, at request | Do not ask the advisors: what the requester wants is not theirs to know. Write the request from the evidence available, marking each assumption, as the request prompt says when there is no user to ask. Where the backend keeps the request, as Jira does, post your questions with `tcw work comment <slug>` instead and leave its text alone, and leave the item at request unless the user's own instruction for this run explicitly said to move it out of request. Then move on to other work. |
33
33
  | One agent or several | Decide yourself. One, unless the parts are truly independent. |
34
34
  | An open question in a spec or plan | Ask the advisors, then write the answer into the document with the assumption stated in the text. |
35
35
  | Review | Run the review stage as its prompt says: a read-only reviewer, never the agent that implemented. Apply what you agree with; write down what you reject and why. |
@@ -36,8 +36,14 @@ tests cannot check.
36
36
  5. Record dependencies between items as blockers, not prose:
37
37
  `tcw work edit <slug> --blocked-by <ref>`.
38
38
  6. **Too large for one item?** Split it here: `tcw work new "<title>" --parent
39
- <slug>` for each part, the part's request on stdin, and plan this item as
40
- the parent that ties them together.
39
+ <slug>` per part, its request on stdin; this item is the parent. A part for
40
+ another project: `tcw work new "<title>" --project <id>` (no `--parent`). A
41
+ ticket key printed instead of a slug means no item exists there yet: report
42
+ it. Otherwise, from inside that project, set `--parent` (a Jira project
43
+ takes only a ticket on its own site) and `--blocked-by` with `tcw work edit`,
44
+ then record TCW's uncommitted changes in that project's version control
45
+ before filing there again: until then a filing is refused, or its Jira
46
+ ticket stays in the inbox.
41
47
  7. **No placeholders.** "TBD", "add error handling", "as in step 3": a step
42
48
  nobody can carry out without asking you a question is not a step.
43
49
  8. **Self-review.** Re-read the plan against the spec: every acceptance
@@ -52,7 +52,7 @@ QA plan scenario as passed, failed or not run, with the evidence for each.
52
52
  <!-- /backend -->
53
53
  <!-- backend: jira -->
54
54
  **Produce** findings, not a verdict. In Jira, qa happens on the ticket, and the
55
- ticket's status, which people move, is the verdict. You may run the scenarios
55
+ ticket's status, which a person decides, is the verdict. You may run the scenarios
56
56
  and post what you found with `tcw work comment <slug>`.
57
57
 
58
58
  ## Steps
@@ -60,11 +60,15 @@ and post what you found with `tcw work comment <slug>`.
60
60
  1. Run each scenario in the QA plan, in the environment it names.
61
61
  2. Post one comment listing each scenario as passed, failed or not run, with
62
62
  evidence. **No claim without output or an observation from just now.**
63
- 3. Leave the decision to a person. Tell them how to record it: accept by
64
- moving the ticket on in Jira, or with
65
- `tcw work advance <slug> --to completed --reason "<why>"`; reject with
66
- `tcw work advance <slug> --to implement --reason "<what to fix>"`, whose
67
- reason becomes the comment implement reads.
63
+ 3. A person decides the verdict, never you. Ask them for it. When the person
64
+ who decides gives you the verdict in this conversation, record it: accepted
65
+ with `tcw work advance <slug> --to completed --reason "accepted by <name>:
66
+ <why>"`, rejected with `tcw work advance <slug> --to implement --reason
67
+ "rejected by <name>: <what to fix>"`, whose reason becomes the comment
68
+ implement reads. A verdict comes after they have seen your findings: an
69
+ instruction given before that, such as "accept it if it passes", is not
70
+ one. They may instead move the ticket in Jira themselves. If they give no
71
+ verdict, stop at qa and say the item waits for them.
68
72
  <!-- /backend -->
69
73
 
70
74
  ## Exit badly
@@ -32,10 +32,20 @@ Write it to `tcw work path <slug> request`. Keep any dated `## Added`
32
32
  sections already there: they are amendments made after it was written.
33
33
  <!-- /backend -->
34
34
  <!-- backend: jira -->
35
- The request is the ticket's description, and Jira owns it: never rewrite it.
36
- When a section is missing or unclear, post a comment with
35
+ The request is the ticket's description, and Jira owns it: never rewrite it on
36
+ your own judgment. When a section is missing or unclear, post a comment with
37
37
  `tcw work comment <slug>` listing what is missing and proposing wording, for
38
38
  the requester to adopt.
39
+
40
+ The requester decides when the request is ready. When they tell you to move
41
+ the item on, in this conversation, do it. If they adopted changed wording,
42
+ first put it into the ticket's description: write it yourself if your harness
43
+ can edit Jira tickets, or ask them to paste it in. Change only what they
44
+ adopted, and keep everything else in the description. Then read it back and
45
+ confirm the description now says what they adopted. Then run
46
+ `tcw work advance <slug> --reason "<who told you to move it>"`. A question,
47
+ such as whether accepting the wording moves the item, is not an instruction to
48
+ move it.
39
49
  <!-- /backend -->
40
50
 
41
51
  ## Steps
@@ -51,6 +51,8 @@ it to `tcw work path <slug> spec --handoff`.
51
51
 
52
52
  - _The code contradicts the request._ Stop and return to request. A spec that
53
53
  quietly reinterprets the request is worse than one that refuses.
54
+ - _The requester revises the request._ It stays at spec: record it as an
55
+ amendment (a dated `## Added`; in Jira, an `Added` comment), and follow it.
54
56
  - _The work is too large for one item._ Say so; plan decomposes it.
55
57
  - _You cannot ground a claim._ Mark it as an assumption, not a fact.
56
58
  - _`tcw work comment` failed._ Report the command and its exit code, do not
@@ -450,8 +450,14 @@ def stage_footer(row, external, target: str) -> str | None:
450
450
  if row.artifact == NO_ARTIFACT:
451
451
  return None # how an arrival becomes work differs by backend
452
452
  if row.name in external:
453
- text = ("> **When this stage's work is done, a person moves the item on "
454
- "in the backend.** Do not move it yourself.")
453
+ # A person decides; the agent carries out the move once told (TCW-100).
454
+ move = (f"`tcw work advance {target} --to <stage> --reason \"<who decided, "
455
+ f"and why>\"`" if row.verdict else
456
+ f"`tcw work advance {target} --reason \"<who told you>\"`")
457
+ text = ("> **When this stage's work is done, a person decides whether the "
458
+ "item moves on.** Move it only when that person tells you to, in "
459
+ "this conversation; a question or an implied yes is not that. "
460
+ f"Then run {move}.")
455
461
  if row.verdict:
456
462
  text += " The verdict is that move."
457
463
  return text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tcw-cli
3
- Version: 3.0.0
3
+ Version: 3.0.2
4
4
  Summary: Taxonomy · Capabilities · Work — a storage-abstracted framework for describing and evolving a software project.
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -724,7 +724,8 @@ A change to the product is followed from the first request to the records:
724
724
  In filesystem mode, the agent working `qa` may record the verdict itself, unless
725
725
  the project's own instructions for `qa` ask for a person to decide. When they
726
726
  do, the agent still writes the round, recording the person's decision. In Jira
727
- mode, a person accepts or rejects on the ticket.
727
+ mode, a person accepts or rejects: on the ticket, or by telling the agent,
728
+ which then moves the ticket and records who decided.
728
729
 
729
730
  Work reaches taxonomy through those capabilities: a new capability names the
730
731
  vocabulary and feature it involves, and those entries must exist first.
@@ -66,13 +66,12 @@ def test_the_override_variable_name_follows_the_id():
66
66
  """The id, uppercased with `-` as `_` — node ids, never repository names.
67
67
 
68
68
  The distinction costs an hour when the two are crossed, which they are in
69
- the workspace that prompted this: the directory `proposit-orchestration`
70
- holds the node `proposit-app`, and the directory `proposit-app` holds the
71
- node `proposit-app-repo`.
69
+ the workspace that prompted this: the directory `workspace` holds the
70
+ node `product`, and the directory `app` holds the node `app-repo`.
72
71
  """
73
- assert override_variable("proposit-core") == "TCW_PROJECT_PROPOSIT_CORE"
74
- assert override_variable("proposit-app") == "TCW_PROJECT_PROPOSIT_APP"
75
- assert override_variable("proposit-app-repo") == "TCW_PROJECT_PROPOSIT_APP_REPO"
72
+ assert override_variable("app-repo") == "TCW_PROJECT_APP_REPO"
73
+ assert override_variable("product") == "TCW_PROJECT_PRODUCT"
74
+ assert override_variable("app-repo-web") == "TCW_PROJECT_APP_REPO_WEB"
76
75
  assert override_variable("a") == "TCW_PROJECT_A"
77
76
 
78
77
 
@@ -21,6 +21,11 @@ re-baselining to hide that is what this file exists to prevent.
21
21
  **Re-captured again by TCW-76**, for one paragraph only: TCW-74's review fixes
22
22
  (`e411e681`) added "Who reviews" to the review prompt after the capture, and
23
23
  the recorded bytes were never brought up to it. Nothing else moved.
24
+
25
+ **Re-captured again by TCW-101**, for two passages it added on purpose: the
26
+ spec prompt's "The requester revises the request" bullet, and the plan
27
+ prompt's step 6 on filing a part into another project. A diff of the old and
28
+ new bytes showed nothing else moved.
24
29
  """
25
30
 
26
31
  import json
@@ -47,6 +47,7 @@ DOCUMENTATION = {
47
47
  ("docs/changelogs/upcoming/<folder>.md", "Any-Code-Change"),
48
48
  ("skills/<component>/SKILL.md", "Skill-Driven-Component"),
49
49
  ("skills/configure/references/<document>.md", "Configuration-Key-Change"),
50
+ ("docs/use-cases.md", "Project-Setup-Change"),
50
51
  }
51
52
 
52
53
  # Programs a `command:` hook runs a script with; the script is then its
@@ -267,6 +267,26 @@ def test_jira_qa_records_no_verdict():
267
267
  assert "tcw work path <slug> qa" not in text and "verdict:" not in text
268
268
 
269
269
 
270
+ def test_jira_qa_moves_the_ticket_when_the_person_gives_the_verdict():
271
+ """TCW-100: the person decides; once they give the verdict in the
272
+ conversation, the agent records it with `advance`, and otherwise stops."""
273
+ paragraph = _paragraph_with(prompt("qa", "jira"), "gives you the verdict")
274
+ assert "--to completed --reason" in paragraph
275
+ assert "--to implement --reason" in paragraph
276
+ assert "after they have seen your findings" in paragraph
277
+ assert "stop at qa" in paragraph
278
+
279
+
280
+ def test_jira_request_writes_adopted_wording_before_moving():
281
+ """TCW-100: adopted wording goes into the description, is read back, and
282
+ only then is the item moved, with a reason naming who said to move it."""
283
+ paragraph = _paragraph_with(prompt("request", "jira"), "tell you to move")
284
+ for words in ("description", "paste", "read it back",
285
+ "tcw work advance <slug> --reason"):
286
+ assert words in paragraph, words
287
+ assert paragraph.index("read it back") < paragraph.index("tcw work advance")
288
+
289
+
270
290
  @pytest.mark.parametrize("sid", sorted(SHIPPED))
271
291
  def test_no_prompt_tells_the_agent_to_ask_what_it_is_reading(sid):
272
292
  """`tcw work lifecycle --stage <id>` inside the text that command reports
@@ -291,3 +311,30 @@ def test_the_self_review_pass_appears_in_exactly_three_prompts():
291
311
  prompts = load_builtins().stage_prompts
292
312
  found = {sid for sid, text in prompts.items() if "self-review" in text.lower()}
293
313
  assert found == {"spec", "plan", "implement"}
314
+
315
+
316
+ def test_jira_request_keeps_what_the_requester_did_not_change():
317
+ """TCW-101: adopted wording changes only what was adopted."""
318
+ paragraph = _paragraph_with(prompt("request", "jira"), "tell you to move")
319
+ assert "keep everything else in the description" in paragraph
320
+
321
+
322
+ @pytest.mark.parametrize("backend", BACKENDS)
323
+ def test_spec_says_what_to_do_when_the_requester_revises_the_request(backend):
324
+ """TCW-101: the item stays at spec, and the change is recorded where the
325
+ request lives, in either backend's form."""
326
+ paragraph = _paragraph_with(prompt("spec", backend), "The requester revises")
327
+ for words in ("stays at spec", "amendment", "## Added", "`Added` comment"):
328
+ assert words in paragraph, words
329
+
330
+
331
+ def test_plan_says_how_to_file_a_part_into_another_project():
332
+ """TCW-101: --project takes no --parent; the parent is set from inside
333
+ that project, and only then is everything recorded in its version
334
+ control, because the edit itself writes a file there; a ticket key in
335
+ place of a slug means there is no item to edit."""
336
+ paragraph = _paragraph_with(prompt("plan", "filesystem"), "Too large for one item")
337
+ order = [paragraph.index(w) for w in ("--project", "tcw work edit",
338
+ "version control")]
339
+ assert order == sorted(order), paragraph
340
+ assert "ticket key printed instead of a slug" in paragraph
@@ -320,25 +320,25 @@ def test_the_cache_key_is_unchanged():
320
320
  exactly what a shared normalizer would change.
321
321
  """
322
322
  expected = {
323
- ("https://github.com/Proposit-App/proposit-orchestration.git", "main"):
324
- "github.com-proposit-app-proposit-orchestration-73cbcd814e44",
325
- ("https://github.com/Proposit-App/proposit-orchestration", "main"):
326
- "github.com-proposit-app-proposit-orchestration-bc251d728153",
327
- ("git@github.com:Proposit-App/proposit-orchestration.git", "main"):
328
- "github.com-proposit-app-proposit-orchestration-d5bbabd1bdc8",
329
- ("https://github.com/Proposit-App/proposit-orchestration.git", "dev"):
330
- "github.com-proposit-app-proposit-orchestration-447264907fc6",
323
+ ("https://github.com/Example-Org/workspace.git", "main"):
324
+ "github.com-example-org-workspace-ec7917e6e4c3",
325
+ ("https://github.com/Example-Org/workspace", "main"):
326
+ "github.com-example-org-workspace-f86dcb6399fe",
327
+ ("git@github.com:Example-Org/workspace.git", "main"):
328
+ "github.com-example-org-workspace-1a37f0559bb2",
329
+ ("https://github.com/Example-Org/workspace.git", "dev"):
330
+ "github.com-example-org-workspace-c6c86f756591",
331
331
  }
332
332
  for (url, ref), key in expected.items():
333
333
  assert checkouts._cache_key(RepositoryDeclaration(url=url, ref=ref)) == key
334
334
 
335
335
 
336
336
  @pytest.mark.parametrize("spelling", [
337
- "https://github.com/Proposit-App/proposit-orchestration",
338
- "https://github.com/Proposit-App/proposit-orchestration.git",
339
- "https://github.com/Proposit-App/proposit-orchestration/",
340
- " https://github.com/Proposit-App/proposit-orchestration.git ",
341
- "git@github.com:Proposit-App/proposit-orchestration.git",
337
+ "https://github.com/Example-Org/workspace",
338
+ "https://github.com/Example-Org/workspace.git",
339
+ "https://github.com/Example-Org/workspace/",
340
+ " https://github.com/Example-Org/workspace.git ",
341
+ "git@github.com:Example-Org/workspace.git",
342
342
  ])
343
343
  def test_two_spellings_of_one_repository_normalize_alike(spelling):
344
344
  """The question `_cache_key` deliberately answers the other way.
@@ -348,18 +348,18 @@ def test_two_spellings_of_one_repository_normalize_alike(spelling):
348
348
  new resolution rung has to see through that.
349
349
  """
350
350
  canonical = checkouts.normalized_url(
351
- "https://github.com/Proposit-App/proposit-orchestration")
351
+ "https://github.com/Example-Org/workspace")
352
352
  assert checkouts.normalized_url(spelling) == canonical
353
353
 
354
354
 
355
355
  @pytest.mark.parametrize("other", [
356
- "https://github.com/Proposit-App/proposit-core",
357
- "https://github.com/Someone-Else/proposit-orchestration",
358
- "https://gitlab.invalid/Proposit-App/proposit-orchestration",
356
+ "https://github.com/Example-Org/core",
357
+ "https://github.com/Someone-Else/workspace",
358
+ "https://gitlab.invalid/Example-Org/workspace",
359
359
  ])
360
360
  def test_two_different_repositories_do_not_normalize_alike(other):
361
361
  assert checkouts.normalized_url(other) != checkouts.normalized_url(
362
- "https://github.com/Proposit-App/proposit-orchestration")
362
+ "https://github.com/Example-Org/workspace")
363
363
 
364
364
 
365
365
  def test_an_undeclared_component_is_a_no_op(tmp_path):
@@ -90,7 +90,7 @@ def test_the_upstream_does_not_see_its_reader(tmp_path):
90
90
 
91
91
 
92
92
  def test_an_upstream_reached_through_a_parent_is_found(tmp_path):
93
- """The proposit-app shape: a package reaches core through its parent."""
93
+ """The app-repository shape: a package reaches core through its parent."""
94
94
  config(tmp_path / "repo", "id: repo\nprojects:\n children:\n"
95
95
  " pkg: pkg\n upstream:\n core: ../core\n")
96
96
  config(tmp_path / "repo" / "pkg", "id: pkg\nprojects:\n parent:\n"
@@ -545,7 +545,7 @@ def test_an_incomplete_tracker_with_a_parent_does_not(tmp_path):
545
545
  assert "required" in text and _NO_PARENT not in text, text
546
546
 
547
547
 
548
- # ── the Proposit shape, end to end ───────────────────────────────────────────
548
+ # ── the workspace shape, end to end ──────────────────────────────────────────
549
549
 
550
550
  _ROOT_TRACKER = {
551
551
  "provider": "jira-cloud",
@@ -561,33 +561,33 @@ def _edit(node: Path, change) -> None:
561
561
  (node / "tcw-config.yaml").write_text(yaml.safe_dump(cfg, sort_keys=False))
562
562
 
563
563
 
564
- def _proposit(tmp_path: Path) -> dict[str, Path]:
565
- """The shape the request came from: an orchestration root `proposit-app` with
566
- children `proposit-core` and `proposit-app-repo`; a package `shared` below the
564
+ def _workspace(tmp_path: Path) -> dict[str, Path]:
565
+ """The shape the request came from: an orchestration root `product` with
566
+ children `core` and `app-repo`; a package `shared` below the
567
567
  app repository extending core's taxonomy; core's tracker block holding only
568
568
  `candidate-query` and inheriting the rest from the root."""
569
569
  root = tmp_path / "ws"
570
- nodes = {"root": root, "core": root / "proposit-core",
571
- "app": root / "proposit-app",
572
- "shared": root / "proposit-app" / "packages" / "shared"}
573
- for key, pid in (("root", "proposit-app"), ("core", "proposit-core"),
574
- ("app", "proposit-app-repo"), ("shared", "shared")):
570
+ nodes = {"root": root, "core": root / "core",
571
+ "app": root / "app",
572
+ "shared": root / "app" / "packages" / "shared"}
573
+ for key, pid in (("root", "product"), ("core", "core"),
574
+ ("app", "app-repo"), ("shared", "shared")):
575
575
  nodes[key].mkdir(parents=True)
576
576
  if key != "shared": # three repositories, as in the workspace
577
577
  _git(nodes[key], "init", "-q", "-b", "main")
578
578
  init(["taxonomy", "capabilities", "work"], nodes[key], pid)
579
579
  _edit(root, lambda c: c.update({"projects": {"children": {
580
- "proposit-core": "proposit-core", "proposit-app-repo": "proposit-app"}}}))
580
+ "core": "core", "app-repo": "app"}}}))
581
581
  _set_tracker(root, dict(_ROOT_TRACKER))
582
582
  _edit(nodes["core"], lambda c: c.update({"projects": {
583
- "parent": {"proposit-app": ".."}}}))
583
+ "parent": {"product": ".."}}}))
584
584
  _set_tracker(nodes["core"], {"candidate-query": "project = CORE"})
585
585
  _edit(nodes["app"], lambda c: c.update({"projects": {
586
- "parent": {"proposit-app": ".."}, "children": {"shared": "packages/shared"}}}))
586
+ "parent": {"product": ".."}, "children": {"shared": "packages/shared"}}}))
587
587
  _edit(nodes["shared"], lambda c: c.update({"projects": {
588
- "parent": {"proposit-app-repo": "../.."}}}))
588
+ "parent": {"app-repo": "../.."}}}))
589
589
  assert _tcw(nodes["core"], "taxonomy", "add", "Argument").returncode == 0
590
- out = _tcw(nodes["shared"], "taxonomy", "extends", "add", "proposit-core")
590
+ out = _tcw(nodes["shared"], "taxonomy", "extends", "add", "core")
591
591
  assert out.returncode == 0, out.stderr
592
592
  return nodes
593
593
 
@@ -605,16 +605,16 @@ def _assert_state(nodes, *, warned: set[str]) -> None:
605
605
  assert code == 0, (key, text)
606
606
  has_warning = "read as an upstream project" in text
607
607
  assert has_warning == (key in warned), (key, text)
608
- out = _tcw(nodes["shared"], "taxonomy", "show", "proposit-core/argument")
608
+ out = _tcw(nodes["shared"], "taxonomy", "show", "core/argument")
609
609
  assert out.returncode == 0, out.stderr
610
610
 
611
611
 
612
- def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
613
- nodes = _proposit(tmp_path)
612
+ def test_the_workspace_migration_passes_through_no_blocked_state(tmp_path):
613
+ nodes = _workspace(tmp_path)
614
614
  _assert_state(nodes, warned=set())
615
615
 
616
616
  step_2 = lambda c: c["projects"].update( # noqa: E731
617
- {"upstream": {"proposit-core": "../proposit-core"}})
617
+ {"upstream": {"core": "../core"}})
618
618
 
619
619
  # The forbidden middle state: step 2 before step 1.
620
620
  _edit(nodes["app"], step_2)
@@ -624,8 +624,8 @@ def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
624
624
 
625
625
  # Step 1: the root moves core from children to upstream, one edit.
626
626
  def step_1(c):
627
- c["projects"]["children"].pop("proposit-core")
628
- c["projects"]["upstream"] = {"proposit-core": "proposit-core"}
627
+ c["projects"]["children"].pop("core")
628
+ c["projects"]["upstream"] = {"core": "core"}
629
629
  _edit(nodes["root"], step_1)
630
630
  _assert_state(nodes, warned={"root", "core", "app", "shared"})
631
631
 
@@ -642,7 +642,7 @@ def test_the_proposit_migration_passes_through_no_blocked_state(tmp_path):
642
642
  _edit(nodes["core"], lambda c: c["work"].pop("tracker"))
643
643
  _assert_state(nodes, warned=set())
644
644
  out = _tcw(nodes["core"], "validate")
645
- assert "proposit-app" not in out.stdout + out.stderr, out.stdout
645
+ assert "product" not in out.stdout + out.stderr, out.stdout
646
646
 
647
647
 
648
648
  # ── the CLI's view of an absent upstream, and of what lies beyond one ────────
@@ -1 +0,0 @@
1
- __version__ = "3.0.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes