tuner-testkit 6.0.0__tar.gz → 6.2.0__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 (286) hide show
  1. {tuner_testkit-6.0.0/tuner_testkit.egg-info → tuner_testkit-6.2.0}/PKG-INFO +11 -5
  2. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/README.md +10 -4
  3. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/pyproject.toml +1 -1
  4. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/__init__.py +1 -1
  5. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +4 -3
  6. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-testcases/SKILL.md +51 -3
  7. tuner_testkit-6.2.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-testsheet/SKILL.md +116 -0
  8. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +4 -2
  9. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
  10. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +4 -1
  11. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/__main__.py +20 -7
  12. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/scaffold.py +73 -7
  13. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +48 -1
  14. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0/tuner_testkit.egg-info}/PKG-INFO +11 -5
  15. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/LICENSE +0 -0
  16. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/setup.cfg +0 -0
  17. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/__init__.py +0 -0
  18. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/__main__.py +0 -0
  19. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/__init__.py +0 -0
  20. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/api.py +0 -0
  21. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/db.py +0 -0
  22. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/generators.py +0 -0
  23. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/ids.py +0 -0
  24. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/_internal/wait.py +0 -0
  25. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/base.py +0 -0
  26. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/context.py +0 -0
  27. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/action_words/registry.py +0 -0
  28. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/__init__.py +0 -0
  29. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/app.py +0 -0
  30. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/errors.py +0 -0
  31. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/router.py +0 -0
  32. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/spec.py +0 -0
  33. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_mock/store.py +0 -0
  34. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/__init__.py +0 -0
  35. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/auth.py +0 -0
  36. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/__init__.py +0 -0
  37. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/capture.py +0 -0
  38. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/codegen.py +0 -0
  39. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/freeze.py +0 -0
  40. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/mocks.py +0 -0
  41. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/normalize.py +0 -0
  42. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
  43. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
  44. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_test/__init__.py +0 -0
  45. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_test/client.py +0 -0
  46. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_test/errors.py +0 -0
  47. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_test/jsonpath.py +0 -0
  48. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/api_test/model.py +0 -0
  49. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/__init__.py +0 -0
  50. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/_shared/__init__.py +0 -0
  51. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/_shared/changelog.py +0 -0
  52. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
  53. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
  54. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/addon.py +0 -0
  55. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/cli.py +0 -0
  56. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
  57. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
  58. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
  59. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/__init__.py +0 -0
  60. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/__main__.py +0 -0
  61. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/build.py +0 -0
  62. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/cli.py +0 -0
  63. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +0 -0
  64. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-self-learning.md +0 -0
  65. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +0 -0
  66. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
  67. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
  68. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/agent-task-log.mdc +0 -0
  69. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
  70. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
  71. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +0 -0
  72. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -0
  73. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
  74. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +0 -0
  75. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +0 -0
  76. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +0 -0
  77. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
  78. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
  79. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
  80. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
  81. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/testcases.mdc +0 -0
  82. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/work-task.mdc +0 -0
  83. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +0 -0
  84. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +0 -0
  85. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
  86. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +0 -0
  87. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +0 -0
  88. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-test-design/SKILL.md +0 -0
  89. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
  90. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +0 -0
  91. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
  92. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +0 -0
  93. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +0 -0
  94. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/generate-test-report/SKILL.md +0 -0
  95. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +0 -0
  96. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +0 -0
  97. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +0 -0
  98. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
  99. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
  100. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +0 -0
  101. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-test-execution/SKILL.md +0 -0
  102. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
  103. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/agent-task-log.md +0 -0
  104. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +0 -0
  105. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
  106. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/artifacts-layout.md +0 -0
  107. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -0
  108. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
  109. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
  110. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +0 -0
  111. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +0 -0
  112. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/metadata-conventions.md +0 -0
  113. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
  114. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +0 -0
  115. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/test-design-syntax.md +0 -0
  116. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/testcase-syntax.md +0 -0
  117. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/work-task.md +0 -0
  118. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
  119. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
  120. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-commit +0 -0
  121. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
  122. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/secret_scan.py +0 -0
  123. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +0 -0
  124. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/paths.py +0 -0
  125. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/source.py +0 -0
  126. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/targets.py +0 -0
  127. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/tests/test_cli.py +0 -0
  128. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dna/tests/test_targets.py +0 -0
  129. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/dump_ddl.py +0 -0
  130. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/__init__.py +0 -0
  131. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/__main__.py +0 -0
  132. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/cli.py +0 -0
  133. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/persist.py +0 -0
  134. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/tests/__init__.py +0 -0
  135. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/tests/test_cli.py +0 -0
  136. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/evidence/tests/test_persist.py +0 -0
  137. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/index_ai/__init__.py +0 -0
  138. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/index_ai/__main__.py +0 -0
  139. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/index_ai/registry.py +0 -0
  140. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/__init__.py +0 -0
  141. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/manifest.py +0 -0
  142. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/INDEX.project.md +0 -0
  143. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
  144. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
  145. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/config/env.py +0 -0
  146. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/data/sut-accounts.example.yaml +0 -0
  147. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/gitignore +0 -0
  148. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
  149. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
  150. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
  151. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
  152. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
  153. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
  154. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
  155. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
  156. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
  157. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
  158. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
  159. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_environment.py +0 -0
  160. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/given.py +0 -0
  161. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/then.py +0 -0
  162. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/when.py +0 -0
  163. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_environment.py +0 -0
  164. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/given.py +0 -0
  165. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/then.py +0 -0
  166. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/when.py +0 -0
  167. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/tests/pytest/conftest.py +0 -0
  168. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/workbench.cmd +0 -0
  169. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/stubs/workbench.sh +0 -0
  170. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/init_repo/tests/test_git_hooks.py +0 -0
  171. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/mock_server/__init__.py +0 -0
  172. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/mock_server/__main__.py +0 -0
  173. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/mock_server/cli.py +0 -0
  174. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/mock_server/seed.py +0 -0
  175. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/mock_server/tool.py +0 -0
  176. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
  177. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
  178. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/capture.py +0 -0
  179. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/cli.py +0 -0
  180. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
  181. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
  182. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/inject.py +0 -0
  183. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/session.py +0 -0
  184. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/tests/__init__.py +0 -0
  185. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
  186. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
  187. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
  188. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/recorder/__init__.py +0 -0
  189. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/recorder/__main__.py +0 -0
  190. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/recorder/cli.py +0 -0
  191. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
  192. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
  193. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/__init__.py +0 -0
  194. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/__main__.py +0 -0
  195. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/cli.py +0 -0
  196. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/store.py +0 -0
  197. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/tests/test_store.py +0 -0
  198. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/apps/task/validate.py +0 -0
  199. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/artifacts.py +0 -0
  200. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/__init__.py +0 -0
  201. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/build.py +0 -0
  202. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/directory.py +0 -0
  203. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/front_matter.py +0 -0
  204. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/scan.py +0 -0
  205. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/tests/test_build.py +0 -0
  206. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/tests/test_directory.py +0 -0
  207. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/catalog/tests/test_front_matter.py +0 -0
  208. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/config.py +0 -0
  209. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/db/__init__.py +0 -0
  210. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/db/client.py +0 -0
  211. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/db/connection.py +0 -0
  212. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/excel/__init__.py +0 -0
  213. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/excel/workbook.py +0 -0
  214. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/__init__.py +0 -0
  215. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/__main__.py +0 -0
  216. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/catalog.py +0 -0
  217. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/china.py +0 -0
  218. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/cli.py +0 -0
  219. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/core.py +0 -0
  220. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/medical.py +0 -0
  221. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/fake/wrappers.py +0 -0
  222. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/__init__.py +0 -0
  223. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/context.py +0 -0
  224. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/core.py +0 -0
  225. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/helpers.py +0 -0
  226. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/hooks.py +0 -0
  227. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/logging/scenario_file.py +0 -0
  228. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/__init__.py +0 -0
  229. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/__main__.py +0 -0
  230. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/base.py +0 -0
  231. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/driver.py +0 -0
  232. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/errors.py +0 -0
  233. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/harvest.py +0 -0
  234. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/health.py +0 -0
  235. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/locator.py +0 -0
  236. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/model.py +0 -0
  237. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/registry.py +0 -0
  238. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/session.py +0 -0
  239. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/steps.py +0 -0
  240. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/page_test/testing.py +0 -0
  241. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/project.py +0 -0
  242. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/testcases/__init__.py +0 -0
  243. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/testcases/__main__.py +0 -0
  244. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/testcases/tests/test_validate.py +0 -0
  245. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/testcases/validate.py +0 -0
  246. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/tools/__init__.py +0 -0
  247. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/tools/manifest.py +0 -0
  248. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/tools/runner.py +0 -0
  249. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/tools/tests/test_manifest.py +0 -0
  250. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/tools/tests/test_runner.py +0 -0
  251. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/__init__.py +0 -0
  252. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/__main__.py +0 -0
  253. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/app.py +0 -0
  254. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/cli.py +0 -0
  255. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/kinds/__init__.py +0 -0
  256. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/kinds/app_generic.py +0 -0
  257. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/kinds/word_db_seed.py +0 -0
  258. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/kinds/word_generic.py +0 -0
  259. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/static/app.css +0 -0
  260. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/_params_form.html +0 -0
  261. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/ai.html +0 -0
  262. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/ai_detail.html +0 -0
  263. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/base.html +0 -0
  264. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/env.html +0 -0
  265. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/history.html +0 -0
  266. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/home.html +0 -0
  267. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/knowledge.html +0 -0
  268. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/run.html +0 -0
  269. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/tool.html +0 -0
  270. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/tools.html +0 -0
  271. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/word.html +0 -0
  272. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/word_db_seed.html +0 -0
  273. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/templates/words.html +0 -0
  274. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workbench/tests/test_app.py +0 -0
  275. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/__init__.py +0 -0
  276. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/__main__.py +0 -0
  277. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/cli.py +0 -0
  278. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/index_render.py +0 -0
  279. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/meta.py +0 -0
  280. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/tests/test_index_render.py +0 -0
  281. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit/workspace/tests/test_meta.py +0 -0
  282. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit.egg-info/SOURCES.txt +0 -0
  283. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit.egg-info/dependency_links.txt +0 -0
  284. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit.egg-info/entry_points.txt +0 -0
  285. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit.egg-info/requires.txt +0 -0
  286. {tuner_testkit-6.0.0 → tuner_testkit-6.2.0}/tuner_testkit.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tuner-testkit
3
- Version: 6.0.0
3
+ Version: 6.2.0
4
4
  Summary: Shared test runtime, recorders, and DNA overlay for SUT test repos
5
5
  Author: tuner-testkit contributors
6
6
  License-Expression: MIT
@@ -69,12 +69,18 @@ uv tool install tuner-testkit
69
69
  ### 2. 初始化测试仓
70
70
 
71
71
  ```bash
72
- tuner-init scaffold ../my-sut-tests
73
- cd ../my-sut-tests
72
+ tuner-init scaffold ../balance
73
+ cd ../balance
74
74
  uv sync
75
75
  ```
76
76
 
77
- `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
77
+ `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]>=<当前 kit 版本>` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
78
+
79
+ 生成的文件夹名就是 `target` 路径的最后一段。`pyproject.toml` 里的项目名默认取这个文件夹名(`Balance` 会写成 `balance`)。需要另起项目名时加 `--name`:
80
+
81
+ ```bash
82
+ tuner-init scaffold ../clients/acme --name acme-billing
83
+ ```
78
84
 
79
85
  `uv sync` 把 **db / api 装进业务仓 `.venv`**,不是 tool 域。已有项目仓则在该仓根目录:
80
86
 
@@ -221,4 +227,4 @@ uv sync --extra all
221
227
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
222
228
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
223
229
 
224
- 6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
230
+ 6.2.0 发行说明(测试单)见 [`docs/changelog/TEMPLATE-6.2.0.md`](docs/changelog/TEMPLATE-6.2.0.md);6.1.0 发行说明(scaffold 项目名)见 [`docs/changelog/TEMPLATE-6.1.0.md`](docs/changelog/TEMPLATE-6.1.0.md);6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
@@ -21,12 +21,18 @@ uv tool install tuner-testkit
21
21
  ### 2. 初始化测试仓
22
22
 
23
23
  ```bash
24
- tuner-init scaffold ../my-sut-tests
25
- cd ../my-sut-tests
24
+ tuner-init scaffold ../balance
25
+ cd ../balance
26
26
  uv sync
27
27
  ```
28
28
 
29
- `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
29
+ `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]>=<当前 kit 版本>` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
30
+
31
+ 生成的文件夹名就是 `target` 路径的最后一段。`pyproject.toml` 里的项目名默认取这个文件夹名(`Balance` 会写成 `balance`)。需要另起项目名时加 `--name`:
32
+
33
+ ```bash
34
+ tuner-init scaffold ../clients/acme --name acme-billing
35
+ ```
30
36
 
31
37
  `uv sync` 把 **db / api 装进业务仓 `.venv`**,不是 tool 域。已有项目仓则在该仓根目录:
32
38
 
@@ -173,4 +179,4 @@ uv sync --extra all
173
179
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
174
180
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
175
181
 
176
- 6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
182
+ 6.2.0 发行说明(测试单)见 [`docs/changelog/TEMPLATE-6.2.0.md`](docs/changelog/TEMPLATE-6.2.0.md);6.1.0 发行说明(scaffold 项目名)见 [`docs/changelog/TEMPLATE-6.1.0.md`](docs/changelog/TEMPLATE-6.1.0.md);6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tuner-testkit"
3
- version = "6.0.0"
3
+ version = "6.2.0"
4
4
  description = "Shared test runtime, recorders, and DNA overlay for SUT test repos"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -2,4 +2,4 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "6.0.0"
5
+ __version__ = "6.2.0"
@@ -2,7 +2,7 @@
2
2
  description: assets/ is the knowledge base for humans and the LLM; enforce provenance metadata, raw-vs-curated boundaries, and grounding (consult INDEX before generating)
3
3
  globs: assets/**
4
4
  alwaysApply: false
5
- version: 1.2.1
5
+ version: 1.2.2
6
6
  ---
7
7
 
8
8
  # assets — 知识层硬约束
@@ -26,10 +26,11 @@ SUT 自学习见 `docs/spec/sut-self-learning.md`;design schema 见
26
26
 
27
27
  - 目录分类固定:`ddl/<datasource>/`、`sql/`、`usecases/<domain>/`、
28
28
  `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testdesign/`、
29
- `testcases/<模块>/<套件>/`、`testreport/`
29
+ `testcases/<模块>/<套件>/`、`testsheet/<轮次>/`、`testreport/`
30
30
  (新增类别前先改 spec,再改本 rule)。功能用例集见 `docs/spec/testcase-syntax.md`。
31
+ 测试单见 skill `maintain-testsheet`:`testsheet.md` 不写 YAML 头;`testcase/` 是当次从用例库复制的步骤。
31
32
  - 人工/半自动区文件头必须带元数据:`domain / source / date / version / confidence`
32
- (Markdown 用 YAML front-matter,SQL 用顶部 `--` 注释)。
33
+ (Markdown 用 YAML front-matter,SQL 用顶部 `--` 注释)。`testsheet.md` 除外。
33
34
  - `explore/` 与 `design/` 还应填 `evidence`(run_id 列表)。
34
35
  - `confidence: high` 表示人工核实过——LLM 应优先采信。
35
36
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: maintain-testcases
3
- version: 1.3.0
4
- description: Creates and updates functional testcases so each case is its own Markdown file under assets/testcases/<module>/<suite>/<Case-ID>.md, with suite notes in that folder's README. Uses a TestLink-style template (summary, preconditions, numbered steps, expected results, status). Use when the user asks to 编写/生成/维护测试用例, add a module or suite, or mentions assets/testcases or a case ID. Do not use for testdesign click-paths or behave .feature files.
3
+ version: 1.5.0
4
+ description: Creates and updates functional testcases so each case is its own Markdown file under assets/testcases/<module>/<suite>/<Case-ID>.md, with suite notes in that folder's README. Uses a TestLink-style template (summary, preconditions, numbered steps, expected results, status). One maintain-testcases session is one git commit; the body lists each case as 首次创建 or 变更原因 so the IDE Timeline on that file shows the changelog. Use when the user asks to 编写/生成/维护测试用例, add a module or suite, or mentions assets/testcases or a case ID. Do not use for testdesign click-paths or behave .feature files.
5
5
  ---
6
6
 
7
7
  # Maintain testcases
@@ -156,6 +156,54 @@ confidence: high
156
156
  - 删除:删掉该 `<用例ID>.md`,并从套件用例表去掉这一行。不改其他用例的 ID。
157
157
  - 废弃:`status` 改为 `废弃`,在备注写原因。不删除文件,不把 ID 让给新用例,标题不加 `(废弃)`。
158
158
  - 拆套件或改套件名:用例带着原 ID 搬家,并改两边 README 的链接。每条用例的 `suite` 改成新目录名。
159
+ - 上面每一种落盘(新建、修改、废弃、删除、搬家)都记在同一次维护的那一个提交里。文件变更日志以 git 为准,不要另写变更日志。
160
+
161
+ ## Commit
162
+
163
+ 同一次 `maintain-testcases` 工作只做 **一个** commit。目的是让每个被改到的用例文件,在 IDE 的 Timeline 里都能看到这次变更日志。用户没有再说「提交」也要做。不要 push。不要改 git config,不要 `--no-verify`。不要按用例拆成多次提交。
164
+
165
+ 校验前的来回修改并进这一个提交。没有文件变化就不提交。
166
+
167
+ 这次提交只暂存本次维护动过的路径:
168
+
169
+ - 新建或修改的 `<用例ID>.md`(含删除)
170
+ - 因此改动的套件 `README.md`、模块 `README.md`、`assets/testcases/README.md`
171
+ - 因此在 `INDEX.project.md` 新增或修改的行
172
+
173
+ 工作区里其他改动不要放进来。
174
+
175
+ 提交信息遵循 `docs/spec/commit-convention.md`。`scope` 必须盖住暂存路径:只有 `assets/testcases/**` 时用 `assets`;同一次还改了 `INDEX.project.md` 时用 `assets,index`。subject 概括这一次(套件或模块,加上新建或更新)。全是新建用 `feat`;只改正错误的操作或预期用 `fix`;只做废弃、删除、搬家或索引调整用 `chore`;几种混在一起用 `feat`。
176
+
177
+ 正文每个用例文件一段,打开该文件的 Timeline 时能对上自己的那一段。原词不要改:
178
+
179
+ - 新文件:`<用例ID>:首次创建。<一句测试点>`。换 slug 的新文件在这句里写 `曾用:<旧 ID>`。
180
+ - 已有文件:`<用例ID>:变更原因:<改了什么、为什么>`。
181
+ - 只改了套件详情或索引、没有动用例正文:`<套件名>:变更原因:<改了什么、为什么>`。
182
+
183
+ ```bash
184
+ git add -- <本次维护相关路径>
185
+ git commit -m "<type>(<scope>): <subject>" -m "<用例ID>:首次创建。<测试点>" -m "<用例ID>:变更原因:<改了什么、为什么>"
186
+ ```
187
+
188
+ 多个用例就多个 `-m`,一段一个文件。只有一条时保留一段即可。
189
+
190
+ 例子:
191
+
192
+ ```text
193
+ feat(assets): 新增用户登录用例 2 条
194
+
195
+ User-Login-valid-credentials:首次创建。已注册账号与正确密码可以登录。
196
+
197
+ User-Login-wrong-password:首次创建。错误密码不能登录。
198
+ ```
199
+
200
+ ```text
201
+ fix(assets): 更新 User-Login-valid-credentials 正确账号密码
202
+
203
+ User-Login-valid-credentials:变更原因:登录成功后的预期由首页改为个人中心。
204
+ ```
205
+
206
+ 提交前看 `git status` 和 `git diff --cached`,确认暂存只有这次维护的文件。`commit-msg` 失败就改正后再提交一次,不要 amend 那次失败的提交。说明里不写密码、token、Cookie。
159
207
 
160
208
  ## Finish
161
209
 
@@ -164,4 +212,4 @@ python -m tuner_testkit.testcases assets/testcases
164
212
  uv run tuner-workspace meta stamp <改过的.md> --kind <testcase|testcase-suite|testcase-module|testcase-index>
165
213
  ```
166
214
 
167
- 校验失败就改文件再跑,通过后再停。有 `INDEX.project.md` 时在其知识表登记新套件 README 的路径(只读 front-matter);平台仓没有业务用例时不要往根 `INDEX.md` 填模块明细。
215
+ 校验失败就改文件再跑。本次要写的用例都通过后,按 Commit 做这一个提交,然后停。有 `INDEX.project.md` 时在其知识表登记新套件 README 的路径(只读 front-matter),放进同一次提交;平台仓没有业务用例时不要往根 `INDEX.md` 填模块明细。
@@ -0,0 +1,116 @@
1
+ ---
2
+ name: maintain-testsheet
3
+ version: 1.0.0
4
+ description: Builds and updates a test sheet under assets/testsheet/<round>/testsheet.md, copying the selected ready cases from assets/testcases into that round's testcase/ folder and linking only those copies. Use when the user asks to 生成测试单, 维护测试单, 测试单, or mentions assets/testsheet or testsheet.md. Do not use to edit the case library, write a testdesign, or curate assets/testreport.
5
+ ---
6
+
7
+ # Maintain testsheet
8
+
9
+ ## Scope
10
+
11
+ - **Write**: `assets/testsheet/<轮次>/testsheet.md`,以及同目录 `testcase/` 里的用例副本。
12
+ - **Read**: `assets/testcases/`。有 `INDEX.project.md` 时先读,只采用已有事实。
13
+ - **Out of scope**: 改 `assets/testcases/`(用 `maintain-testcases`)、写 `assets/testdesign/`、写 `assets/testreport/`(用 `generate-test-report`)。已有的 `assets/testreports/**/测试单.md` 不搬,除非用户明确要求迁移。
14
+
15
+ ## Layout
16
+
17
+ ```text
18
+ assets/testsheet/<轮次>/
19
+ testsheet.md
20
+ testcase/<模块>/README.md
21
+ testcase/<模块>/<套件>/README.md
22
+ testcase/<模块>/<套件>/<用例ID>.md
23
+ evidence/
24
+ ```
25
+
26
+ `<轮次>` 用用户给的目录名。没给就用 `yyMMdd` 加模块名,例如 `261015预入库管控`。一轮一个目录。
27
+
28
+ ## Generate
29
+
30
+ 1. 读模块 README 和相关套件 README。范围按用户点名的模块、套件或用例 ID。没点名到单条时,纳入该范围内 `status: 就绪` 的用例。`status: 废弃` 不复制、不进表,在测试单开头点名。
31
+ 2. 用文件复制,不要重写正文。用例文件、该模块 README、被选中套件的 README 都复制到上面的 `testcase/` 路径。复制后不再从用例库刷新,除非用户要求重新提取。
32
+ 3. 写 `testsheet.md`。不写 YAML 头。用例列只链副本:
33
+
34
+ ```text
35
+ [Admin-View-columns-shown](testcase/预入库管控/管控情况查看/Admin-View-columns-shown.md)
36
+ ```
37
+
38
+ 不要链 `assets/testcases/` 或 `../../testcases/`。
39
+
40
+ 从副本填列,不要另编业务规则:
41
+
42
+ | 列 | 来源 |
43
+ | --- | --- |
44
+ | 用例 | 副本文件名,链到副本 |
45
+ | 测试点 | `<type>-<title>`,如 `正向-清单展示约定列` |
46
+ | 数据 | `## 测试数据` 的第一句。没有则用 `## 前置条件` 的第一句 |
47
+ | 预期要点 | 第一步 `预期` 收成一句 |
48
+ | 结果 | `未执行` |
49
+ | 实测记录 | 空 |
50
+
51
+ 分组:模块 README 的 `## 范围` 已有编号块时,用那些块做 `##`。块内按套件 README 的顺序各做一个 `###` 和一张表。没有范围编号时,一个套件一个 `##`。不要把一个套件拆进两张表,除非用户要求。
52
+
53
+ ## Sheet
54
+
55
+ ```markdown
56
+ # <主题>测试单
57
+
58
+ 共 N 条。步骤在本目录 `testcase/`。`<废弃ID>` 已废弃,不在本单。
59
+
60
+ 依据:<用户给出的需求或来源路径>。
61
+
62
+ ## 怎么填
63
+
64
+ - 「结果」只写:通过、失败、部分通过、未执行、阻塞。
65
+ - 「实测记录」写看到的文案、单号、库存状态。不写密码、token、Cookie。账号只写 `account_id` 或登录名。
66
+ - 截图放本目录,文件名用用例 ID。
67
+
68
+ ## 本轮信息
69
+
70
+ | 项 | 填写 |
71
+ | --- | --- |
72
+ | 测试人 | |
73
+ | 日期 | |
74
+ | 环境 | |
75
+ | 证据 | 本目录 `evidence/` |
76
+ | 通过 | 0 |
77
+ | 失败 | 0 |
78
+ | 部分通过 | 0 |
79
+ | 未执行 | N |
80
+ | 阻塞 | 0 |
81
+
82
+ ## 测的时候先记住
83
+
84
+ - <会改变通过或失败判定的规则。来自套件 README 的「详情」,或用户本轮原话。没有就写「无」。>
85
+
86
+ ## 1. <范围块>
87
+
88
+ ### 1.1 <套件名>
89
+
90
+ | 用例 | 测试点 | 数据 | 预期要点 | 结果 | 实测记录 |
91
+ | --- | --- | --- | --- | --- | --- |
92
+ | [<用例ID>](testcase/<模块>/<套件>/<用例ID>.md) | 正向-<title> | <数据> | <预期要点> | 未执行 | |
93
+
94
+ ## 缺陷
95
+
96
+ | 编号 | 用例 | 现象 | 是否阻塞后续 |
97
+ | --- | --- | --- | --- |
98
+ | 无 | | | |
99
+ ```
100
+
101
+ 五个计数之和等于表内行数。新建时未执行等于 N,其余为 0。
102
+
103
+ ## Update
104
+
105
+ - 回写时只改 `testsheet.md` 的结果、实测记录、计数和缺陷。结果只用那五个词。
106
+ - 增删一行后立刻重算「共 N 条」和五个计数。
107
+ - 从本单移除一条:删表行,删 `testcase/` 里对应副本。开头写明 ID 和原因。菜单权限这类配置问题、以及改由别的页面跟踪的条目,是移除,不记失败,也不进缺陷表。
108
+ - 缺陷只记产品行为。
109
+ - 本轮步骤缺前置或判定规则:改 `testcase/` 里的副本。要沉淀回用例库时另走 `maintain-testcases`,改完不要把测试单的链接改回用例库。
110
+ - 截图放本目录,文件名用用例 ID。一组结果的图放在对应小节下,写成 `![](文件名.png)`。接口 JSON 放 `evidence/`。造数写 `packages/action_words/db_seed/`,不在 `assets/testsheet/` 里放可执行脚本。
111
+
112
+ ## Hard rules
113
+
114
+ - 不写密码、token、Cookie。
115
+ - 不编用例库和套件详情里没有、用户本轮也没说的业务规则。
116
+ - 测试单生成后,步骤以副本为准。
@@ -1,4 +1,4 @@
1
- <!-- version: 1.7.1 -->
1
+ <!-- version: 1.7.2 -->
2
2
  # AGENTS — 平台总入口(轻量 DM)
3
3
 
4
4
  > 本文件是"repo as a platform"的**稳定世界观**:只写不常变的分层结构与角色。
@@ -13,7 +13,7 @@
13
13
 
14
14
  | 层 | 目录 | 职责 | 谁运行 |
15
15
  | --- | --- | --- | --- |
16
- | 知识层 | `assets/` | 给人和 LLM 阅读、生成测试代码的基础知识(ddl / sql / usecases / domain-notes / explore / design / testdesign / testcases / testreport)。见 `docs/spec/assets-knowledge-syntax.md`。 | 只读引用 |
16
+ | 知识层 | `assets/` | 给人和 LLM 阅读、生成测试代码的基础知识(ddl / sql / usecases / domain-notes / explore / design / testdesign / testcases / testsheet / testreport)。见 `docs/spec/assets-knowledge-syntax.md`。 | 只读引用 |
17
17
  | 运行库 | `tuner_testkit/`(PyPI:`tuner-testkit`) | 公共运行时与 CLI(db / logging / api_test / page_test / fake / recorders / dna)。SUT 用 `uv` 锁版本。 | `import tuner_testkit`;`tuner-recorder` 等 scripts |
18
18
  | 组件层 | `packages/` | **本仓业务资产**(api_objects / page_objects / action_words),不是 kit 运行库。 | 被 import |
19
19
  | 工具层 | `apps/` | **本仓私有**工具。公共工具在 `tuner_testkit.apps`。见 `docs/spec/apps-authoring-syntax.md`。 | `python -m apps.<name>`(仅项目工具) |
@@ -52,6 +52,7 @@ flowchart TD
52
52
  Q -->|"读/策展/索引知识"| Idx["查 INDEX.md + maintain-index skill"]
53
53
  Q -->|"发布任务 / 测试设计 / 端到端执行"| Task["work/tasks + tuner-task\ndocs/spec/work-task.md"]
54
54
  Q -->|"生成或维护功能测试用例"| Cases["maintain-testcases skill\ndocs/spec/testcase-syntax.md"]
55
+ Q -->|"生成或维护测试单"| Sheet["maintain-testsheet skill\nassets/testsheet/"]
55
56
  ```
56
57
 
57
58
  - **学习被测系统** → `.cursor/agents/sut-self-learning.md`(编排 explore → freeze → design;规格 `docs/spec/sut-self-learning.md`;任务 log 见 `docs/spec/agent-task-log.md`)。
@@ -63,6 +64,7 @@ flowchart TD
63
64
  - **读/索引知识** → 先查 `INDEX.md`;若存在 `INDEX.project.md` 则一并查。索引维护用 `maintain-index` skill。
64
65
  - **发布任务** → `tuner-task create` 写入 `work/tasks/`。测试设计走 `derive-test-design`;端到端点击报告走 `run-test-execution`。缺人才能决定的通道(如后端日志)用 `tuner-task ask`,不要猜。
65
66
  - **功能测试用例** → skill `maintain-testcases`,落在 `assets/testcases/<模块>/<套件>/<用例ID>.md`(规格 `docs/spec/testcase-syntax.md`)。这不是测试设计,也不直接产出 `.feature`。
67
+ - **测试单** → skill `maintain-testsheet`,落在 `assets/testsheet/<轮次>/`。步骤用该目录 `testcase/` 里的用例副本,不链回 `assets/testcases/`。
66
68
 
67
69
  ## 5. 全程硬约束(跨分支)
68
70
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "files": 65,
2
+ "files": 66,
3
3
  "paths": [
4
4
  ".cursor/rules",
5
5
  ".cursor/skills",
@@ -21,13 +21,16 @@ assets/
21
21
  ├── testcases/<模块>/README.md # 模块范围与套件清单
22
22
  ├── testcases/<模块>/<套件>/README.md # 套件说明与用例索引
23
23
  ├── testcases/<模块>/<套件>/<用例ID>.md # 一条用例一个文件
24
+ ├── testsheet/<轮次>/testsheet.md # 一次测试单。步骤链接本目录副本
25
+ ├── testsheet/<轮次>/testcase/<模块>/<套件>/<用例ID>.md # 从用例库复制的本次步骤
24
26
  ├── testreport/<name>.md # 测试报告类原始资产
25
27
  └── CHANGELOG.md # 自动区变更流水(供 maintain-index 读取 delta)
26
28
  ```
27
29
 
28
30
  - **自动区**(工具产出,可被覆盖重写):`ddl/`、以及每次生成会追加 `CHANGELOG.md`。
29
31
  人不手改这些文件的内容语义;要更新就重跑工具。
30
- - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testcases/`、`testreport/`。
32
+ - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testcases/`、`testsheet/`、`testreport/`。
33
+ - `testsheet/<轮次>/testsheet.md` 不写 YAML 头,正文按测试单格式。同目录 `testcase/` 是用例库的原样副本,保留复制时的文件头。维护方式见 skill `maintain-testsheet`。
31
34
  - `apidoc/` **不单列**:人工导入的接口说明放 `domain-notes/` 或 `usecases/`;
32
35
  运行时冻结的契约在 `packages/api_objects/`。是否再拆目录留给下游实践决定。
33
36
 
@@ -1,6 +1,6 @@
1
1
  """CLI for init_repo: scaffold a new repo or manage the release manifest.
2
2
 
3
- python -m tuner_testkit.apps.init_repo scaffold <target> [--no-ai] [--overwrite]
3
+ python -m tuner_testkit.apps.init_repo scaffold <target> [--name NAME] [--no-ai] [--overwrite]
4
4
  python -m tuner_testkit.apps.init_repo manifest --write [--version X.Y.Z]
5
5
  python -m tuner_testkit.apps.init_repo manifest --check
6
6
  """
@@ -15,11 +15,16 @@ from tuner_testkit.apps.init_repo import scaffold as sc
15
15
 
16
16
 
17
17
  def _cmd_scaffold(args: argparse.Namespace) -> int:
18
- actions = sc.scaffold(
19
- pathlib.Path(args.target),
20
- with_ai=not args.no_ai,
21
- overwrite=args.overwrite,
22
- )
18
+ try:
19
+ actions = sc.scaffold(
20
+ pathlib.Path(args.target),
21
+ with_ai=not args.no_ai,
22
+ overwrite=args.overwrite,
23
+ project_name=args.name,
24
+ )
25
+ except ValueError as exc:
26
+ print(str(exc), file=sys.stderr)
27
+ return 2
23
28
  for line in actions:
24
29
  print(line)
25
30
  print(f"\nScaffolded {len(actions)} entries into {args.target}")
@@ -68,7 +73,15 @@ def main(argv: list[str] | None = None) -> int:
68
73
  sub = parser.add_subparsers(dest="cmd", required=True)
69
74
 
70
75
  p_sc = sub.add_parser("scaffold", help="create six-layer skeleton (+ platform DNA)")
71
- p_sc.add_argument("target", help="target directory for the new project repo")
76
+ p_sc.add_argument(
77
+ "target",
78
+ help="directory to create; its name is the generated folder name and the default project name",
79
+ )
80
+ p_sc.add_argument(
81
+ "--name",
82
+ default=None,
83
+ help="pyproject project name (default: normalized target folder name, e.g. Balance -> balance)",
84
+ )
72
85
  p_sc.add_argument("--no-ai", action="store_true", help="do not copy .cursor/docs-spec/packages DNA")
73
86
  p_sc.add_argument("--overwrite", action="store_true", help="overwrite existing files when copying DNA")
74
87
  p_sc.set_defaults(func=_cmd_scaffold)
@@ -2,6 +2,7 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  import pathlib
5
+ import re
5
6
  import shutil
6
7
  import textwrap
7
8
 
@@ -14,6 +15,7 @@ SKELETON_DIRS: tuple[str, ...] = (
14
15
  "assets/design",
15
16
  "assets/testreport",
16
17
  "assets/testcases",
18
+ "assets/testsheet",
17
19
  "packages/action_words/db_seed",
18
20
  "packages/action_words/db_assert",
19
21
  "packages/action_words/api_request",
@@ -88,6 +90,39 @@ def _stub_root() -> pathlib.Path | None:
88
90
  return None
89
91
 
90
92
 
93
+ # PEP 503 / 426 name: start and end with an alphanumeric; dots, underscores, hyphens inside.
94
+ _PROJECT_NAME_RE = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?$")
95
+
96
+
97
+ def project_name_from_directory(directory_name: str) -> str:
98
+ """Turn a generated folder name into a ``pyproject.toml`` project name.
99
+
100
+ ``Balance`` becomes ``balance``. Characters outside the project-name
101
+ alphabet become hyphens. Pass ``--name`` when the folder name cannot
102
+ produce a valid name.
103
+ """
104
+ slug = directory_name.strip().lower()
105
+ slug = re.sub(r"[^a-z0-9._-]+", "-", slug)
106
+ slug = re.sub(r"[-_.]{2,}", "-", slug).strip("-._")
107
+ if not slug:
108
+ raise ValueError(
109
+ f"cannot derive a project name from directory {directory_name!r}; pass --name"
110
+ )
111
+ return normalize_project_name(slug)
112
+
113
+
114
+ def normalize_project_name(raw: str) -> str:
115
+ """Accept an explicit ``--name`` or raise ``ValueError``."""
116
+ name = raw.strip()
117
+ if not _PROJECT_NAME_RE.fullmatch(name):
118
+ raise ValueError(
119
+ "invalid project name "
120
+ f"{raw!r}: use letters, digits, '.', '_' or '-', "
121
+ "and do not start or end with punctuation"
122
+ )
123
+ return name
124
+
125
+
91
126
  def _copy_file(src: pathlib.Path, dst: pathlib.Path, *, overwrite: bool) -> bool:
92
127
  if dst.exists() and not overwrite:
93
128
  return False
@@ -96,20 +131,26 @@ def _copy_file(src: pathlib.Path, dst: pathlib.Path, *, overwrite: bool) -> bool
96
131
  return True
97
132
 
98
133
 
99
- def _write_pyproject(target: pathlib.Path, *, overwrite: bool) -> bool:
134
+ def _write_pyproject(
135
+ target: pathlib.Path,
136
+ *,
137
+ overwrite: bool,
138
+ project_name: str,
139
+ kit_version: str,
140
+ ) -> bool:
100
141
  dest = target / "pyproject.toml"
101
142
  if dest.exists() and not overwrite:
102
143
  return False
103
144
  dest.write_text(
104
145
  textwrap.dedent(
105
- """\
146
+ f"""\
106
147
  [project]
107
- name = "sut-test-repo"
148
+ name = "{project_name}"
108
149
  version = "0.1.0"
109
150
  description = "Test repo created from tuner-testkit"
110
151
  requires-python = ">=3.12,<3.14"
111
152
  dependencies = [
112
- "tuner-testkit[db,api]>=4.3.0",
153
+ "tuner-testkit[db,api]>={kit_version}",
113
154
  ]
114
155
 
115
156
  [project.optional-dependencies]
@@ -139,9 +180,29 @@ def _write_pyproject(target: pathlib.Path, *, overwrite: bool) -> bool:
139
180
  return True
140
181
 
141
182
 
142
- def scaffold(target: pathlib.Path, *, with_ai: bool = True, overwrite: bool = False) -> list[str]:
183
+ def scaffold(
184
+ target: pathlib.Path,
185
+ *,
186
+ with_ai: bool = True,
187
+ overwrite: bool = False,
188
+ project_name: str | None = None,
189
+ ) -> list[str]:
190
+ """Create a SUT test repo at ``target``.
191
+
192
+ The directory's own name is the generated folder name. ``project_name``
193
+ (CLI ``--name``) is the ``[project] name`` written into ``pyproject.toml``.
194
+ When omitted, that name is derived from the folder name.
195
+ """
143
196
  actions: list[str] = []
144
197
  target = target.resolve()
198
+ explicit = (project_name or "").strip()
199
+ resolved_name = (
200
+ normalize_project_name(explicit)
201
+ if explicit
202
+ else project_name_from_directory(target.name)
203
+ )
204
+ from tuner_testkit import __version__
205
+
145
206
  target.mkdir(parents=True, exist_ok=True)
146
207
  src_root = _stub_root()
147
208
 
@@ -153,8 +214,13 @@ def scaffold(target: pathlib.Path, *, with_ai: bool = True, overwrite: bool = Fa
153
214
  keep.write_text("", encoding="utf-8")
154
215
  actions.append(f"dir {rel}")
155
216
 
156
- if _write_pyproject(target, overwrite=overwrite):
157
- actions.append("write pyproject.toml")
217
+ if _write_pyproject(
218
+ target,
219
+ overwrite=overwrite,
220
+ project_name=resolved_name,
221
+ kit_version=__version__,
222
+ ):
223
+ actions.append(f"write pyproject.toml ({resolved_name})")
158
224
  else:
159
225
  actions.append("skip pyproject.toml (exists)")
160
226
 
@@ -4,6 +4,10 @@ from __future__ import annotations
4
4
 
5
5
  from pathlib import Path
6
6
 
7
+ import pytest
8
+
9
+ from tuner_testkit import __version__
10
+ from tuner_testkit.apps.init_repo.__main__ import main
7
11
  from tuner_testkit.apps.init_repo.scaffold import scaffold
8
12
 
9
13
  _REPO_ROOT = Path(__file__).resolve().parents[4]
@@ -21,7 +25,10 @@ def test_scaffold_from_non_project_cwd(tmp_path: Path, monkeypatch):
21
25
  actions = scaffold(dest, with_ai=True, overwrite=False)
22
26
  assert dest.is_dir()
23
27
  assert (dest / "pyproject.toml").is_file()
24
- assert "[tool.tuner-testkit]" in (dest / "pyproject.toml").read_text(encoding="utf-8")
28
+ pyproject = (dest / "pyproject.toml").read_text(encoding="utf-8")
29
+ assert 'name = "new-sut"' in pyproject
30
+ assert f'"tuner-testkit[db,api]>={__version__}"' in pyproject
31
+ assert "[tool.tuner-testkit]" in pyproject
25
32
  assert 'requires-python = ">=3.12,<3.14"' in (dest / "pyproject.toml").read_text(encoding="utf-8")
26
33
  assert (dest / ".python-version").read_text(encoding="utf-8") == "3.12\n"
27
34
  assert (dest / "config" / "env.py").is_file()
@@ -47,6 +54,46 @@ def test_scaffold_from_non_project_cwd(tmp_path: Path, monkeypatch):
47
54
  assert any(line.startswith("write .cursor/REGISTRY.md") for line in actions)
48
55
 
49
56
 
57
+ def test_scaffold_project_name_follows_folder(tmp_path: Path):
58
+ dest = tmp_path / "Balance"
59
+ actions = scaffold(dest, with_ai=False)
60
+ text = (dest / "pyproject.toml").read_text(encoding="utf-8")
61
+ assert 'name = "balance"' in text
62
+ assert any(line == "write pyproject.toml (balance)" for line in actions)
63
+
64
+
65
+ def test_scaffold_name_override(tmp_path: Path):
66
+ dest = tmp_path / "clients"
67
+ scaffold(dest, with_ai=False, project_name="Hospital-Billing")
68
+ text = (dest / "pyproject.toml").read_text(encoding="utf-8")
69
+ assert 'name = "Hospital-Billing"' in text
70
+
71
+
72
+ def test_scaffold_rejects_invalid_name_before_creating_the_folder(tmp_path: Path):
73
+ dest = tmp_path / "balance"
74
+ with pytest.raises(ValueError, match="invalid project name"):
75
+ scaffold(dest, with_ai=False, project_name="bad name")
76
+ assert not dest.exists()
77
+
78
+
79
+ def test_cli_name_flag(tmp_path: Path, capsys: pytest.CaptureFixture[str]):
80
+ dest = tmp_path / "Balance"
81
+ code = main(["scaffold", str(dest), "--name", "balance", "--no-ai"])
82
+ captured = capsys.readouterr()
83
+ assert code == 0
84
+ assert "write pyproject.toml (balance)" in captured.out
85
+ assert 'name = "balance"' in (dest / "pyproject.toml").read_text(encoding="utf-8")
86
+
87
+
88
+ def test_cli_rejects_invalid_name(tmp_path: Path, capsys: pytest.CaptureFixture[str]):
89
+ dest = tmp_path / "balance"
90
+ code = main(["scaffold", str(dest), "--name", "bad name", "--no-ai"])
91
+ captured = capsys.readouterr()
92
+ assert code == 2
93
+ assert "invalid project name" in captured.err
94
+ assert not dest.exists()
95
+
96
+
50
97
  def test_scaffold_uses_packaged_stubs_when_not_editable(tmp_path: Path, monkeypatch):
51
98
  """Simulate `uv tool install` (no template checkout beside site-packages)."""
52
99
  monkeypatch.chdir(tmp_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tuner-testkit
3
- Version: 6.0.0
3
+ Version: 6.2.0
4
4
  Summary: Shared test runtime, recorders, and DNA overlay for SUT test repos
5
5
  Author: tuner-testkit contributors
6
6
  License-Expression: MIT
@@ -69,12 +69,18 @@ uv tool install tuner-testkit
69
69
  ### 2. 初始化测试仓
70
70
 
71
71
  ```bash
72
- tuner-init scaffold ../my-sut-tests
73
- cd ../my-sut-tests
72
+ tuner-init scaffold ../balance
73
+ cd ../balance
74
74
  uv sync
75
75
  ```
76
76
 
77
- `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
77
+ `scaffold` 会铺六层目录、写入依赖 `tuner-testkit[db,api]>=<当前 kit 版本>` 的 `pyproject.toml`,并执行一次 `tuner-dna sync`(把 `.cursor/`、`docs/spec/`、`tools/git-hooks/` 放进**项目树**)。可在任意目录运行,不必先有测试仓。不要用 `tuner-testkit init repo`。
78
+
79
+ 生成的文件夹名就是 `target` 路径的最后一段。`pyproject.toml` 里的项目名默认取这个文件夹名(`Balance` 会写成 `balance`)。需要另起项目名时加 `--name`:
80
+
81
+ ```bash
82
+ tuner-init scaffold ../clients/acme --name acme-billing
83
+ ```
78
84
 
79
85
  `uv sync` 把 **db / api 装进业务仓 `.venv`**,不是 tool 域。已有项目仓则在该仓根目录:
80
86
 
@@ -221,4 +227,4 @@ uv sync --extra all
221
227
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
222
228
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
223
229
 
224
- 6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
230
+ 6.2.0 发行说明(测试单)见 [`docs/changelog/TEMPLATE-6.2.0.md`](docs/changelog/TEMPLATE-6.2.0.md);6.1.0 发行说明(scaffold 项目名)见 [`docs/changelog/TEMPLATE-6.1.0.md`](docs/changelog/TEMPLATE-6.1.0.md);6.0.0 发行说明(一条用例一个文件)见 [`docs/changelog/TEMPLATE-6.0.0.md`](docs/changelog/TEMPLATE-6.0.0.md);5.3.1 发行说明(已回答提问归档)见 [`docs/changelog/TEMPLATE-5.3.1.md`](docs/changelog/TEMPLATE-5.3.1.md);5.3.0 发行说明(功能用例集 `assets/testcases/`)见 [`docs/changelog/TEMPLATE-5.3.0.md`](docs/changelog/TEMPLATE-5.3.0.md);5.2.0 发行说明(work task / 测试设计 / 证据附件)见 [`docs/changelog/TEMPLATE-5.2.0.md`](docs/changelog/TEMPLATE-5.2.0.md);5.1.0 发行说明(工作台 / meta stamp / `--json`)见 [`docs/changelog/TEMPLATE-5.1.0.md`](docs/changelog/TEMPLATE-5.1.0.md);5.0.0(Plane Job 协议退场、`tuner-workspace`)见 [`TEMPLATE-5.0.0.md`](docs/changelog/TEMPLATE-5.0.0.md);4.3.0 见 [`TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。