tuner-testkit 5.2.0__tar.gz → 5.3.1__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 (285) hide show
  1. {tuner_testkit-5.2.0/tuner_testkit.egg-info → tuner_testkit-5.3.1}/PKG-INFO +2 -2
  2. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/README.md +1 -1
  3. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/pyproject.toml +1 -1
  4. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/__init__.py +1 -1
  5. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +4 -3
  6. tuner_testkit-5.3.1/tuner_testkit/apps/dna/dna_payload/.cursor/rules/testcases.mdc +29 -0
  7. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/work-task.mdc +2 -2
  8. tuner_testkit-5.3.1/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-testcases/SKILL.md +124 -0
  9. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +5 -3
  10. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
  11. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/agent-task-log.md +1 -1
  12. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/artifacts-layout.md +3 -2
  13. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +4 -1
  14. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/metadata-conventions.md +3 -2
  15. tuner_testkit-5.3.1/tuner_testkit/apps/dna/dna_payload/docs/spec/testcase-syntax.md +120 -0
  16. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/work-task.md +3 -1
  17. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/scaffold.py +1 -0
  18. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/store.py +46 -18
  19. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/tests/test_store.py +23 -0
  20. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/scan.py +11 -1
  21. tuner_testkit-5.3.1/tuner_testkit/testcases/__init__.py +5 -0
  22. tuner_testkit-5.3.1/tuner_testkit/testcases/__main__.py +25 -0
  23. tuner_testkit-5.3.1/tuner_testkit/testcases/tests/test_validate.py +76 -0
  24. tuner_testkit-5.3.1/tuner_testkit/testcases/validate.py +141 -0
  25. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1/tuner_testkit.egg-info}/PKG-INFO +2 -2
  26. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit.egg-info/SOURCES.txt +5 -0
  27. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/LICENSE +0 -0
  28. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/setup.cfg +0 -0
  29. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/__init__.py +0 -0
  30. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/__main__.py +0 -0
  31. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/__init__.py +0 -0
  32. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/api.py +0 -0
  33. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/db.py +0 -0
  34. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/generators.py +0 -0
  35. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/ids.py +0 -0
  36. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/_internal/wait.py +0 -0
  37. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/base.py +0 -0
  38. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/context.py +0 -0
  39. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/action_words/registry.py +0 -0
  40. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/__init__.py +0 -0
  41. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/app.py +0 -0
  42. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/errors.py +0 -0
  43. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/router.py +0 -0
  44. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/spec.py +0 -0
  45. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_mock/store.py +0 -0
  46. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/__init__.py +0 -0
  47. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/auth.py +0 -0
  48. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/__init__.py +0 -0
  49. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/capture.py +0 -0
  50. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/codegen.py +0 -0
  51. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/freeze.py +0 -0
  52. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/mocks.py +0 -0
  53. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/normalize.py +0 -0
  54. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
  55. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
  56. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_test/__init__.py +0 -0
  57. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_test/client.py +0 -0
  58. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_test/errors.py +0 -0
  59. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_test/jsonpath.py +0 -0
  60. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/api_test/model.py +0 -0
  61. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/__init__.py +0 -0
  62. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/_shared/__init__.py +0 -0
  63. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/_shared/changelog.py +0 -0
  64. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
  65. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
  66. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/addon.py +0 -0
  67. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/cli.py +0 -0
  68. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
  69. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
  70. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
  71. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/__init__.py +0 -0
  72. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/__main__.py +0 -0
  73. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/build.py +0 -0
  74. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/cli.py +0 -0
  75. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +0 -0
  76. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-self-learning.md +0 -0
  77. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +0 -0
  78. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
  79. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
  80. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/agent-task-log.mdc +0 -0
  81. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
  82. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
  83. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +0 -0
  84. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -0
  85. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
  86. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +0 -0
  87. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +0 -0
  88. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +0 -0
  89. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
  90. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
  91. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
  92. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
  93. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +0 -0
  94. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +0 -0
  95. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
  96. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +0 -0
  97. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +0 -0
  98. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-test-design/SKILL.md +0 -0
  99. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
  100. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +0 -0
  101. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
  102. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +0 -0
  103. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +0 -0
  104. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/generate-test-report/SKILL.md +0 -0
  105. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +0 -0
  106. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +0 -0
  107. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +0 -0
  108. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
  109. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
  110. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +0 -0
  111. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-test-execution/SKILL.md +0 -0
  112. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
  113. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +0 -0
  114. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
  115. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -0
  116. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
  117. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
  118. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +0 -0
  119. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +0 -0
  120. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
  121. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +0 -0
  122. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/docs/spec/test-design-syntax.md +0 -0
  123. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
  124. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
  125. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-commit +0 -0
  126. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
  127. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/secret_scan.py +0 -0
  128. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +0 -0
  129. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/paths.py +0 -0
  130. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/source.py +0 -0
  131. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/targets.py +0 -0
  132. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/tests/test_cli.py +0 -0
  133. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dna/tests/test_targets.py +0 -0
  134. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/dump_ddl.py +0 -0
  135. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/__init__.py +0 -0
  136. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/__main__.py +0 -0
  137. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/cli.py +0 -0
  138. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/persist.py +0 -0
  139. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/tests/__init__.py +0 -0
  140. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/tests/test_cli.py +0 -0
  141. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/evidence/tests/test_persist.py +0 -0
  142. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/index_ai/__init__.py +0 -0
  143. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/index_ai/__main__.py +0 -0
  144. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/index_ai/registry.py +0 -0
  145. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/__init__.py +0 -0
  146. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/__main__.py +0 -0
  147. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/manifest.py +0 -0
  148. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/INDEX.project.md +0 -0
  149. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
  150. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
  151. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/config/env.py +0 -0
  152. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/data/sut-accounts.example.yaml +0 -0
  153. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/gitignore +0 -0
  154. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
  155. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
  156. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
  157. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
  158. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
  159. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
  160. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
  161. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
  162. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
  163. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
  164. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
  165. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/api_environment.py +0 -0
  166. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/given.py +0 -0
  167. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/then.py +0 -0
  168. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/api_steps/when.py +0 -0
  169. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_environment.py +0 -0
  170. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/given.py +0 -0
  171. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/then.py +0 -0
  172. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/features/ui_steps/when.py +0 -0
  173. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/tests/pytest/conftest.py +0 -0
  174. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/workbench.cmd +0 -0
  175. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/stubs/workbench.sh +0 -0
  176. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/tests/test_git_hooks.py +0 -0
  177. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +0 -0
  178. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/mock_server/__init__.py +0 -0
  179. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/mock_server/__main__.py +0 -0
  180. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/mock_server/cli.py +0 -0
  181. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/mock_server/seed.py +0 -0
  182. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/mock_server/tool.py +0 -0
  183. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
  184. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
  185. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/capture.py +0 -0
  186. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/cli.py +0 -0
  187. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
  188. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
  189. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/inject.py +0 -0
  190. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/session.py +0 -0
  191. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/tests/__init__.py +0 -0
  192. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
  193. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
  194. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
  195. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/recorder/__init__.py +0 -0
  196. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/recorder/__main__.py +0 -0
  197. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/recorder/cli.py +0 -0
  198. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
  199. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
  200. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/__init__.py +0 -0
  201. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/__main__.py +0 -0
  202. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/cli.py +0 -0
  203. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/apps/task/validate.py +0 -0
  204. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/artifacts.py +0 -0
  205. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/__init__.py +0 -0
  206. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/build.py +0 -0
  207. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/directory.py +0 -0
  208. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/front_matter.py +0 -0
  209. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/tests/test_build.py +0 -0
  210. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/tests/test_directory.py +0 -0
  211. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/catalog/tests/test_front_matter.py +0 -0
  212. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/config.py +0 -0
  213. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/db/__init__.py +0 -0
  214. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/db/client.py +0 -0
  215. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/db/connection.py +0 -0
  216. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/excel/__init__.py +0 -0
  217. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/excel/workbook.py +0 -0
  218. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/__init__.py +0 -0
  219. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/__main__.py +0 -0
  220. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/catalog.py +0 -0
  221. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/china.py +0 -0
  222. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/cli.py +0 -0
  223. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/core.py +0 -0
  224. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/medical.py +0 -0
  225. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/fake/wrappers.py +0 -0
  226. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/__init__.py +0 -0
  227. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/context.py +0 -0
  228. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/core.py +0 -0
  229. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/helpers.py +0 -0
  230. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/hooks.py +0 -0
  231. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/logging/scenario_file.py +0 -0
  232. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/__init__.py +0 -0
  233. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/__main__.py +0 -0
  234. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/base.py +0 -0
  235. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/driver.py +0 -0
  236. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/errors.py +0 -0
  237. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/harvest.py +0 -0
  238. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/health.py +0 -0
  239. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/locator.py +0 -0
  240. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/model.py +0 -0
  241. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/registry.py +0 -0
  242. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/session.py +0 -0
  243. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/steps.py +0 -0
  244. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/page_test/testing.py +0 -0
  245. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/project.py +0 -0
  246. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/tools/__init__.py +0 -0
  247. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/tools/manifest.py +0 -0
  248. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/tools/runner.py +0 -0
  249. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/tools/tests/test_manifest.py +0 -0
  250. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/tools/tests/test_runner.py +0 -0
  251. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/__init__.py +0 -0
  252. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/__main__.py +0 -0
  253. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/app.py +0 -0
  254. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/cli.py +0 -0
  255. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/kinds/__init__.py +0 -0
  256. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/kinds/app_generic.py +0 -0
  257. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/kinds/word_db_seed.py +0 -0
  258. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/kinds/word_generic.py +0 -0
  259. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/static/app.css +0 -0
  260. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/_params_form.html +0 -0
  261. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/ai.html +0 -0
  262. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/ai_detail.html +0 -0
  263. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/base.html +0 -0
  264. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/env.html +0 -0
  265. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/history.html +0 -0
  266. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/home.html +0 -0
  267. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/knowledge.html +0 -0
  268. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/run.html +0 -0
  269. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/tool.html +0 -0
  270. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/tools.html +0 -0
  271. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/word.html +0 -0
  272. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/word_db_seed.html +0 -0
  273. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/templates/words.html +0 -0
  274. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workbench/tests/test_app.py +0 -0
  275. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/__init__.py +0 -0
  276. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/__main__.py +0 -0
  277. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/cli.py +0 -0
  278. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/index_render.py +0 -0
  279. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/meta.py +0 -0
  280. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/tests/test_index_render.py +0 -0
  281. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit/workspace/tests/test_meta.py +0 -0
  282. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit.egg-info/dependency_links.txt +0 -0
  283. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit.egg-info/entry_points.txt +0 -0
  284. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/tuner_testkit.egg-info/requires.txt +0 -0
  285. {tuner_testkit-5.2.0 → tuner_testkit-5.3.1}/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: 5.2.0
3
+ Version: 5.3.1
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
@@ -221,4 +221,4 @@ uv sync --extra all
221
221
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
222
222
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
223
223
 
224
- 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)。
224
+ 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)。
@@ -173,4 +173,4 @@ uv sync --extra all
173
173
  (被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
174
174
  验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
175
175
 
176
- 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)。
176
+ 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 = "5.2.0"
3
+ version = "5.3.1"
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__ = "5.2.0"
5
+ __version__ = "5.3.1"
@@ -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.1.0
5
+ version: 1.2.0
6
6
  ---
7
7
 
8
8
  # assets — 知识层硬约束
@@ -25,8 +25,9 @@ SUT 自学习见 `docs/spec/sut-self-learning.md`;design schema 见
25
25
  ## 目录与元数据
26
26
 
27
27
  - 目录分类固定:`ddl/<datasource>/`、`sql/`、`usecases/<domain>/`、
28
- `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testreport/`
29
- (新增类别前先改 spec,再改本 rule)。
28
+ `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testdesign/`、
29
+ `testcases/<模块>/`、`testreport/`
30
+ (新增类别前先改 spec,再改本 rule)。功能用例集见 `docs/spec/testcase-syntax.md`。
30
31
  - 人工/半自动区文件头必须带元数据:`domain / source / date / version / confidence`
31
32
  (Markdown 用 YAML front-matter,SQL 用顶部 `--` 注释)。
32
33
  - `explore/` 与 `design/` 还应填 `evidence`(run_id 列表)。
@@ -0,0 +1,29 @@
1
+ ---
2
+ description: Functional testcases live under assets/testcases/<module>/<feature>.md with four heading levels and stable CASE IDs
3
+ globs: assets/testcases/**
4
+ alwaysApply: false
5
+ version: 1.1.0
6
+ ---
7
+
8
+ # testcases — 功能用例集
9
+
10
+ 完整规范:`docs/spec/testcase-syntax.md`。生成或改写走 skill `maintain-testcases`。
11
+
12
+ ## 位置
13
+
14
+ - 总索引:`assets/testcases/README.md`
15
+ - 模块说明:`assets/testcases/<模块>/README.md`
16
+ - 一个功能一个文件:`assets/testcases/<模块>/<功能>.md`
17
+ - 不要写到 `usecases/`、`testdesign/` 或 `tests/features/`。
18
+
19
+ ## 功能文件
20
+
21
+ - `# 测试用例` → `## <模块>` → `### <功能>` → `#### <缩写><四位序号> 正向-|反向-<测试点>`
22
+ - 二级标题等于目录名,三级标题等于文件名。
23
+ - 每条用例必填 `- 步骤:` 与 `- 预期:`。
24
+ - ID 形如 `User-Login0001`:`id_prefix` 是功能英文缩写,后接 4 位序号。全库唯一;不改号、不复用、不重排。
25
+
26
+ ## 禁止
27
+
28
+ - 密码、token、Cookie、Authorization。账号只写 `account_id`。
29
+ - 没有出处的业务规则。出处是用户本次说明,或索引能指向的知识。
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  description: Work tasks live in work/tasks. When a human must choose a missing evidence channel, write an inbox question and block the task instead of inventing the channel.
3
3
  alwaysApply: true
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  ---
6
6
 
7
7
  # 工作任务与人类提问
@@ -15,7 +15,7 @@ version: 1.0.0
15
15
  - 端到端点击用 `type: test-execution`,`design` 指向已有测试设计;报告写入 `assets/testreport/`,证据用 `tuner-evidence persist` 或 `attach` 挂上 `task_id`、截图、脱敏日志、接口 JSON。
16
16
  - 执行结束后把结果写入该测试设计的「执行反馈」,只引用证据路径。
17
17
  - 仓库没有写明的证据通道(典型是后端日志:SSH 目录、日志接口、Rancher API)立刻 `tuner-task ask`。日志主题用 `sut-log-source`。
18
- - 提问写入 `artifacts/inbox/questions/` 后停止这一支,把任务保持在 `blocked`,直到 `tuner-task answer`。
18
+ - 提问写入 `artifacts/inbox/questions/` 后停止这一支,把任务保持在 `blocked`,直到 `tuner-task answer`。回答后的问题文件在 `artifacts/inbox/archived-question/`。
19
19
 
20
20
  ## Must not
21
21
 
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: maintain-testcases
3
+ version: 1.1.0
4
+ description: Creates and updates the functional testcase set under assets/testcases/<module>/<feature>.md using the four-level heading template and stable feature-prefixed IDs such as User-Login0001. Use when the user asks to 编写/生成/维护测试用例, add a module or feature case file, or mentions assets/testcases or case ID. Do not use for testdesign click-paths or behave .feature files.
5
+ ---
6
+
7
+ # Maintain testcases
8
+
9
+ ## Scope
10
+
11
+ - **Write**: `assets/testcases/**` only.
12
+ - **Must follow**: `docs/spec/testcase-syntax.md`.
13
+ - **Out of scope**: `assets/testdesign/`(用 `derive-test-design`)、`tests/features/**`(用 `feature-authoring`)、pytest。
14
+
15
+ ## Before writing
16
+
17
+ 1. 读 `assets/testcases/README.md` 与目标模块的 `README.md`(没有就先按下面的模板建)。
18
+ 2. 读 `INDEX.md`;存在 `INDEX.project.md` 时一并读。只采用已有 usecase / domain-notes / explore / design,或用户本次给出的事实。
19
+ 3. 功能文件已有 `id_prefix` 就沿用,不要另起缩写。新建功能时用功能名的英文词,每词首字母大写、`-` 连接(`用户登录` → `User-Login`),写入 `id_prefix`。确认这个前缀没有被别的功能占用。
20
+ 4. 序号只在该前缀内递增:`rg -N "^#### User-Login[0-9]{4} " assets/testcases`。下一条 = 最大序号 + 1,4 位补零。该前缀还没有用例时从 `0001` 起,得到 `User-Login0001`。
21
+
22
+ ## Where a case goes
23
+
24
+ - 已有同名 `<模块>/<功能>.md`:只追加或修改四级标题,不新建第二份文件。
25
+ - 模块已存在、功能没有:新建 `assets/testcases/<模块>/<功能>.md`,并在该模块 README 的功能清单加一行。
26
+ - 模块也没有:新建目录和模块 README,再在总索引的模块表加一行,然后写功能文件。
27
+
28
+ ## Templates
29
+
30
+ 功能文件:
31
+
32
+ ```markdown
33
+ ---
34
+ kind: testcase
35
+ id: <ascii-slug>
36
+ id_prefix: <Feature-Name>
37
+ title: <功能>
38
+ module: <模块>
39
+ source: <依据路径或需求名>
40
+ version: 1.0.0
41
+ confidence: medium
42
+ ---
43
+
44
+ # 测试用例
45
+ ## <模块>
46
+ ### <功能>
47
+ #### <Feature-Name>0001 正向-<测试点>
48
+ - 步骤:<操作>
49
+ - 预期:<可观察结果>
50
+ #### <Feature-Name>0002 反向-<测试点>
51
+ - 步骤:<操作>
52
+ - 预期:<可观察结果>
53
+ ```
54
+
55
+ 总索引 `assets/testcases/README.md`:
56
+
57
+ ```markdown
58
+ ---
59
+ kind: testcase-index
60
+ title: 测试用例模块索引
61
+ version: 1.0.0
62
+ confidence: high
63
+ ---
64
+
65
+ # 测试用例模块索引
66
+
67
+ 规范:`docs/spec/testcase-syntax.md`。一个功能一个文件,用例写在四级标题下,ID 全库唯一且不重排。
68
+
69
+ ## 放置规则
70
+
71
+ - 新用例归入已有模块的功能文件;对不上时才新增模块目录。
72
+ - 目录名 = 二级标题;文件名 = 三级标题。
73
+ - 不写密码、token、Cookie。账号只写 `account_id`。
74
+
75
+ ## 模块
76
+
77
+ | 模块 | 目录 | 范围 | 状态 |
78
+ | --- | --- | --- | --- |
79
+ | <模块> | `assets/testcases/<模块>/` | <一句话> | 在用 |
80
+ ```
81
+
82
+ 模块 README:
83
+
84
+ ```markdown
85
+ ---
86
+ kind: testcase-module
87
+ id: <ascii-slug>
88
+ title: <模块>
89
+ module: <模块>
90
+ version: 1.0.0
91
+ confidence: high
92
+ ---
93
+
94
+ # <模块>
95
+
96
+ ## 范围
97
+
98
+ ## 不测
99
+
100
+ ## 功能
101
+
102
+ | 功能 | 文件 |
103
+ | --- | --- |
104
+ | <功能> | [<功能>.md](<功能>.md) |
105
+
106
+ ## 相关知识
107
+
108
+ 无
109
+ ```
110
+
111
+ ## Update rules
112
+
113
+ - 改步骤或预期:保留原 ID 和 `id_prefix`,bump 该文件 `version`。
114
+ - 废弃:标题加 `(废弃)`,补 `- 状态:废弃` 与原因。不删除该四级标题,不把 ID 让给新用例。
115
+ - 拆文件或改功能名:用例带着原 ID 搬家,并改两边 README 的链接。
116
+
117
+ ## Finish
118
+
119
+ ```bash
120
+ python -m tuner_testkit.testcases assets/testcases
121
+ uv run tuner-workspace meta stamp <改过的.md> --kind <testcase|testcase-module|testcase-index>
122
+ ```
123
+
124
+ 校验失败就改文件再跑,通过后再停。有 `INDEX.project.md` 时在其知识表登记新功能文件的路径(只读 front-matter);平台仓没有业务用例时不要往根 `INDEX.md` 填模块明细。
@@ -1,4 +1,4 @@
1
- <!-- version: 1.6.0 -->
1
+ <!-- version: 1.7.1 -->
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 / testreport)。见 `docs/spec/assets-knowledge-syntax.md`。 | 只读引用 |
16
+ | 知识层 | `assets/` | 给人和 LLM 阅读、生成测试代码的基础知识(ddl / sql / usecases / domain-notes / explore / design / testdesign / testcases / 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>`(仅项目工具) |
@@ -21,7 +21,7 @@
21
21
  | 测试层 | `tests/` | 自动化测试代码(behave `features/` + `pytest/`)。 | behave / pytest |
22
22
  | 文档层 | `docs/` | 仓库使用说明与规范(`docs/spec/**`)。 | 只读 |
23
23
 
24
- 配套:`config/`(环境/数据源)、`.cursor/`(AI 组件,见下)、`work/tasks/`(入库的任务上下文,规范 `docs/spec/work-task.md`)、`artifacts/`·`logs/`(运行产出,规范 `docs/spec/artifacts-layout.md`:MCP evidence 落 `artifacts/evidence/<run_id>/`;agent 任务记录落 `artifacts/inbox/`;阻塞式人类提问落 `artifacts/inbox/questions/`;工具运行落 `artifacts/runs/<run_id>/`;回归报告落 `artifacts/reports/<run_id>/`,每个 run 目录带 `manifest.json`)。SUT 登录本机文件:`data/sut-accounts.local.yaml`(gitignore)。
24
+ 配套:`config/`(环境/数据源)、`.cursor/`(AI 组件,见下)、`work/tasks/`(入库的任务上下文,规范 `docs/spec/work-task.md`)、`artifacts/`·`logs/`(运行产出,规范 `docs/spec/artifacts-layout.md`:MCP evidence 落 `artifacts/evidence/<run_id>/`;agent 任务记录落 `artifacts/inbox/`;阻塞式人类提问未回答时落 `artifacts/inbox/questions/`,回答后移到 `artifacts/inbox/archived-question/`;工具运行落 `artifacts/runs/<run_id>/`;回归报告落 `artifacts/reports/<run_id>/`,每个 run 目录带 `manifest.json`)。SUT 登录本机文件:`data/sut-accounts.local.yaml`(gitignore)。
25
25
 
26
26
  ## 2. 三角色
27
27
 
@@ -51,6 +51,7 @@ flowchart TD
51
51
  Q -->|"新建/更新项目仓"| Init["tuner-init / tuner-dna / release-template"]
52
52
  Q -->|"读/策展/索引知识"| Idx["查 INDEX.md + maintain-index skill"]
53
53
  Q -->|"发布任务 / 测试设计 / 端到端执行"| Task["work/tasks + tuner-task\ndocs/spec/work-task.md"]
54
+ Q -->|"生成或维护功能测试用例"| Cases["maintain-testcases skill\ndocs/spec/testcase-syntax.md"]
54
55
  ```
55
56
 
56
57
  - **学习被测系统** → `.cursor/agents/sut-self-learning.md`(编排 explore → freeze → design;规格 `docs/spec/sut-self-learning.md`;任务 log 见 `docs/spec/agent-task-log.md`)。
@@ -61,6 +62,7 @@ flowchart TD
61
62
  - **仓库初始化/发布** → `tuner-init scaffold`(骨架 + 依赖 `tuner-testkit` + 一次 `tuner-dna sync`)+ `release-template` skill。下游升 kit:`uv add tuner-testkit==x.y.z` 然后 `tuner-dna sync`,再提交。
62
63
  - **读/索引知识** → 先查 `INDEX.md`;若存在 `INDEX.project.md` 则一并查。索引维护用 `maintain-index` skill。
63
64
  - **发布任务** → `tuner-task create` 写入 `work/tasks/`。测试设计走 `derive-test-design`;端到端点击报告走 `run-test-execution`。缺人才能决定的通道(如后端日志)用 `tuner-task ask`,不要猜。
65
+ - **功能测试用例** → skill `maintain-testcases`,落在 `assets/testcases/<模块>/<功能>.md`(规格 `docs/spec/testcase-syntax.md`)。这不是测试设计,也不直接产出 `.feature`。
64
66
 
65
67
  ## 5. 全程硬约束(跨分支)
66
68
 
@@ -1,5 +1,5 @@
1
1
  {
2
- "files": 62,
2
+ "files": 65,
3
3
  "paths": [
4
4
  ".cursor/rules",
5
5
  ".cursor/skills",
@@ -72,7 +72,7 @@ evidence:
72
72
  artifacts/inbox/questions/Q-<YYYYMMDD>-<nnn>.md
73
73
  ```
74
74
 
75
- 字段与命令见 `docs/spec/work-task.md`。提问后把对应 `work/tasks` 标为 `blocked`。回答写入任务的 `## Decisions`;可复用的通道说明策展到 `assets/domain-notes/`。
75
+ 回答后同一文件移到 `artifacts/inbox/archived-question/`。字段与命令见 `docs/spec/work-task.md`。提问后把对应 `work/tasks` 标为 `blocked`。回答写入任务的 `## Decisions`;可复用的通道说明策展到 `assets/domain-notes/`。
76
76
 
77
77
  ## 5. 密钥
78
78
 
@@ -16,7 +16,8 @@ description: 交付物目录 artifacts/ 的子目录职责、run 级 manifest.js
16
16
  artifacts/
17
17
  ├── evidence/<run_id>/ # Playwright MCP / 网络 dump(tuner-evidence persist);脱敏;gitignore
18
18
  ├── inbox/<utc>-<agent>-<slice>.md # agent 任务记录(agent-task-log.md);gitignore
19
- ├── inbox/questions/Q-<YYYYMMDD>-<nnn>.md # 阻塞式人类提问(work-task.md);gitignore
19
+ ├── inbox/questions/Q-<YYYYMMDD>-<nnn>.md # 未回答的人类提问(work-task.md);gitignore
20
+ ├── inbox/archived-question/Q-<YYYYMMDD>-<nnn>.md # 已回答的提问;gitignore
20
21
  ├── runs/<run_id>/ # 工具 / 动作词的一次运行(tuner-workspace run、工作台);gitignore
21
22
  ├── reports/<run_id>/ # 一次回归(behave / pytest)的报告与摘要;gitignore
22
23
  ├── catalogs/workspace.json # tuner-workspace catalog 产物;gitignore
@@ -68,7 +69,7 @@ artifacts/
68
69
  | behave(`*_environment.py` 钩子) | `reports/<run_id>/` | `summary.json`(feature/scenario 状态)、`manifest.json`;`-f html-pretty -o $TUNER_REPORT_DIR/report.html` 时 html 同目录 |
69
70
  | pytest | `reports/<run_id>/` | `pytest --junitxml artifacts/reports/<run_id>/junit.xml`,再 `tuner_testkit.artifacts.finish_run` 写 manifest |
70
71
  | `tuner-evidence persist` / `attach` | `evidence/<run_id>/` | `network.jsonl` / `actions.jsonl` / `run_summary.md` / `screenshots/` / `logs/` / `api/`;`manifest.params.task_id` 指向 `work/tasks` |
71
- | agent(编排) | `inbox/` | 会话流水见 `agent-task-log.md`;人类提问见 `inbox/questions/` 与 `work-task.md` |
72
+ | agent(编排) | `inbox/` | 会话流水见 `agent-task-log.md`;未回答提问见 `inbox/questions/`,已回答见 `inbox/archived-question/` |
72
73
  | `tuner-workspace catalog` | `catalogs/workspace.json` | 见 `tuner_testkit/workspace/README.md` |
73
74
 
74
75
  环境变量 `TUNER_REPORT_DIR` 指定本次回归的 run 目录(不设则钩子自动生成 `reports/<run_id>/`);
@@ -17,13 +17,16 @@ assets/
17
17
  ├── explore/<app>/<name>.md # 探索式测试产出的能力清单 / 站点地图(半自动)
18
18
  ├── design/<app>/<route-slug>.md # API↔DB effects 收敛知识(见 design-knowledge-syntax)
19
19
  ├── testdesign/<sut>/<slug>.md # 测试设计(见 test-design-syntax);执行反馈回写在此
20
+ ├── testcases/README.md # 功能用例集总索引(见 testcase-syntax)
21
+ ├── testcases/<模块>/README.md # 模块范围与功能清单
22
+ ├── testcases/<模块>/<功能>.md # 该功能的全部用例(四级标题 + CASE ID)
20
23
  ├── testreport/<name>.md # 测试报告类原始资产
21
24
  └── CHANGELOG.md # 自动区变更流水(供 maintain-index 读取 delta)
22
25
  ```
23
26
 
24
27
  - **自动区**(工具产出,可被覆盖重写):`ddl/`、以及每次生成会追加 `CHANGELOG.md`。
25
28
  人不手改这些文件的内容语义;要更新就重跑工具。
26
- - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testreport/`。
29
+ - **人工/半自动区**:`sql/`、`usecases/`、`domain-notes/`、`explore/`、`design/`、`testdesign/`、`testcases/`、`testreport/`。
27
30
  - `apidoc/` **不单列**:人工导入的接口说明放 `domain-notes/` 或 `usecases/`;
28
31
  运行时冻结的契约在 `packages/api_objects/`。是否再拆目录留给下游实践决定。
29
32
 
@@ -13,7 +13,7 @@ description: 统一 front-matter / run manifest 字段家族,供 catalog、工
13
13
 
14
14
  | 字段 | 类型 | 含义 |
15
15
  | --- | --- | --- |
16
- | `kind` | string | `app` / `action_word` / `testreport` / `inbox` / `question` / `task` / `testdesign` / `explore` / `design` / `usecase` / `domain-note` |
16
+ | `kind` | string | `app` / `action_word` / `testreport` / `inbox` / `question` / `task` / `testdesign` / `testcase` / `testcase-module` / `testcase-index` / `explore` / `design` / `usecase` / `domain-note` |
17
17
  | `id` | string | 稳定标识(`tool_id` / `word_id` / 报告 slug) |
18
18
  | `title` | string | 短标题 |
19
19
  | `author` | email | 创建者,来自 `git config user.email` |
@@ -54,8 +54,9 @@ catalog 同时用 `git log --diff-filter=A --format=%ae -- <path>` 算首次提
54
54
  ### 任务与测试设计
55
55
 
56
56
  - `kind: task` 落在 `work/tasks/TASK-*.md`,字段见 `docs/spec/work-task.md`。
57
- - `kind: question` 落在 `artifacts/inbox/questions/Q-*.md`(不入库)。
57
+ - `kind: question` 未回答落在 `artifacts/inbox/questions/Q-*.md`,回答后移到 `artifacts/inbox/archived-question/`(不入库)。
58
58
  - `kind: testdesign` 落在 `assets/testdesign/<sut>/<slug>.md`,字段见 `docs/spec/test-design-syntax.md`。
59
+ - `kind: testcase` 落在 `assets/testcases/<模块>/<功能>.md`;模块说明是 `testcase-module`,总索引是 `testcase-index`。字段见 `docs/spec/testcase-syntax.md`。
59
60
 
60
61
  ### run manifest
61
62
 
@@ -0,0 +1,120 @@
1
+ ---
2
+ name: testcase-syntax
3
+ version: 1.1.0
4
+ description: assets/testcases 的目录、四级标题、功能缩写用例 ID 与模块 README。功能用例集的唯一事实源。
5
+ ---
6
+
7
+ # 测试用例(testcase-syntax)
8
+
9
+ > 一份功能文件收齐该功能的全部用例。给人读,也给 LLM 按同一棵树增删改。
10
+ > 维护流程见 skill `maintain-testcases`。编辑约束见 `.cursor/rules/testcases.mdc`。
11
+
12
+ ## 1. 和相邻知识的分工
13
+
14
+ | 路径 | 记什么 |
15
+ | --- | --- |
16
+ | `assets/usecases/` | 导入或讲解过的业务场景,不是带稳定 ID 的用例集 |
17
+ | `assets/testdesign/` | 一次任务的范围、策略和点击路径 |
18
+ | `assets/testcases/` | 按模块 / 功能维护的用例集,每条用例一个稳定 `CASE` ID |
19
+ | `tests/features/` | 已自动化的 Gherkin。本规范不写 `.feature` |
20
+
21
+ ## 2. 目录
22
+
23
+ ```text
24
+ assets/testcases/README.md # 模块总索引:规划、模块一览、给人和 LLM 的放置规则
25
+ assets/testcases/<模块>/README.md # 该模块的范围、边界、功能清单
26
+ assets/testcases/<模块>/<功能>.md # 该功能的全部用例
27
+ ```
28
+
29
+ 例子:`assets/testcases/用户系统/用户登录.md`。
30
+
31
+ - 目录名 = 模块显示名 = 功能文件里的二级标题。
32
+ - 文件名(不含 `.md`)= 功能显示名 = 三级标题。
33
+ - 只允许这一层:模块目录里不再套子目录。
34
+ - 名称不要用 `\ / : * ? " < > |`。
35
+
36
+ ## 3. 标题层级
37
+
38
+ 功能文件正文只用这四级。一个功能的全部用例都放在四级标题下。
39
+
40
+ ```markdown
41
+ # 测试用例
42
+ ## 用户系统
43
+ ### 用户登录
44
+ #### User-Login0001 正向-正确账号密码
45
+ - 步骤:输入已注册账号与正确密码点击登录
46
+ - 预期:登录成功进入首页或个人中心
47
+ #### User-Login0002 反向-正确账号错误密码
48
+ - 步骤:输入已注册账号与错误密码点击登录
49
+ - 预期:停留在登录页并提示账号或密码错误
50
+ ```
51
+
52
+ | 级别 | 含义 | 规则 |
53
+ | --- | --- | --- |
54
+ | `#` | 中心主题 | 固定为 `测试用例` |
55
+ | `##` | 模块 | 全文件只有一个,且等于父目录名 |
56
+ | `###` | 功能 | 全文件只有一个,且等于文件名 |
57
+ | `####` | 一条用例 | 功能缩写 ID + 空格 + `正向-` 或 `反向-` + 测试点名称 |
58
+
59
+ ## 4. 用例 ID
60
+
61
+ ID 是全库唯一键,由功能缩写和该功能内的序号组成:`<缩写><四位序号>`。
62
+
63
+ - 缩写:功能名的英文词,每词首字母大写,用 `-` 连接。`用户登录` → `User-Login`。只含字母和连字符,不含数字。
64
+ - 序号:4 位数字,从 `0001` 起。`User-Login0001`、`User-Login0002`。
65
+ - 缩写写在功能文件 front-matter 的 `id_prefix`,之后不得改。同一 `id_prefix` 只能属于一个功能文件。
66
+ - 新增时只扫描这个前缀:`rg -N "^#### User-Login[0-9]{4} " assets/testcases`,取最大序号 + 1。
67
+ - 不同功能的前缀不同,所以 `User-Login0001` 与 `Reset-Password0001` 不会撞键。
68
+ - 已发出的 ID 不改、不复用、不因为删用例而重排。
69
+ - 废弃:标题末尾加 `(废弃)`,并在该条下写 `- 状态:废弃` 与原因。保留标题,不要删掉这一节。
70
+
71
+ ## 5. 每条用例的子弹
72
+
73
+ 必填,且用中文冒号:
74
+
75
+ - `- 步骤:` 测试人员或 LLM 能照做的操作
76
+ - `- 预期:` 可观察结果
77
+
78
+ 可选,仍放在同一条四级标题下:
79
+
80
+ - `- 前置:`
81
+ - `- 数据:` 用账号 `account_id` 或数据文件路径,不写密码、token、Cookie
82
+ - `- 备注:`
83
+
84
+ 没有依据的业务规则不要写进步骤或预期。依据来自用户说明,或 `INDEX.md` / `INDEX.project.md` 能指向的 usecase、domain-notes、explore、design。
85
+
86
+ ## 6. Front-matter
87
+
88
+ 功能文件:
89
+
90
+ ```yaml
91
+ ---
92
+ kind: testcase
93
+ id: user-login
94
+ id_prefix: User-Login
95
+ title: 用户登录
96
+ module: 用户系统
97
+ sut: <sut 短名,未知可省略>
98
+ source: <assets/… 或需求名>
99
+ version: 1.0.0
100
+ confidence: medium
101
+ ---
102
+ ```
103
+
104
+ 模块 README 用 `kind: testcase-module`。总索引用 `kind: testcase-index`。
105
+ 人工修改后 bump `version`。署名用 `tuner-workspace meta stamp <path> --kind testcase`(模块 README 用 `testcase-module`,总索引用 `testcase-index`)。
106
+
107
+ ## 7. 两份 README
108
+
109
+ `assets/testcases/README.md` 告诉人和 LLM:模块怎么划分、新功能该进哪个目录、当前有哪些模块。至少包含:
110
+
111
+ - 放置规则(指向本 spec)
112
+ - 模块表:模块名、目录、一句话范围、状态(`在用` / `规划中`)
113
+
114
+ `assets/testcases/<模块>/README.md` 至少包含:
115
+
116
+ - 这个模块测什么、不测什么
117
+ - 功能清单:每个 `<功能>.md` 一行链接
118
+ - 相关知识路径(没有就写「无」)
119
+
120
+ 新增或重命名功能文件时,两份 README 一起改。总索引的模块表与模块目录一致;模块 README 的功能清单与该目录下的功能文件一致。
@@ -14,7 +14,8 @@ description: 入库任务 work/tasks、阻塞式人类提问,以及和测试
14
14
 
15
15
  ```text
16
16
  work/tasks/TASK-<YYYYMMDD>-<nnn>.md # 入库
17
- artifacts/inbox/questions/Q-<YYYYMMDD>-<nnn>.md # gitignore,本机异步信箱
17
+ artifacts/inbox/questions/Q-<YYYYMMDD>-<nnn>.md # 未回答;gitignore
18
+ artifacts/inbox/archived-question/Q-<YYYYMMDD>-<nnn>.md # 已回答;gitignore
18
19
  ```
19
20
 
20
21
  `work/**` 的提交 scope 是 `work`。问题文件不入库;人答完后的结论写回任务的 `## Decisions`,需要留下的通道说明再策展到 `assets/domain-notes/`。
@@ -73,6 +74,7 @@ tuner-task answer Q-20260924-001 --option rancher-api \
73
74
  ```
74
75
 
75
76
  - 提问立刻落盘,并把任务标为 `blocked`。只挡住依赖该答案的回写;不依赖日志的点击可以先做完,但在回答前不要编写取日志实现,也不要选定通道。
77
+ - `tuner-task answer` 把问题文件从 `questions/` 移到 `archived-question/`,未回答的问题仍只留在 `questions/`。同一天的新问题编号会计入归档,避免复用已回答的 ID。
76
78
  - `--note` 只留可入库的指向。CLI 拒绝 `password=` / `token:` / `Bearer …` 这类赋值。
77
79
  - `skip` 表示报告里日志证据写「无」,设计上的日志断言保持未验证。
78
80
  - `tuner-task finish` 在仍有 `status: open` 且 `blocking: true` 的问题时失败。
@@ -13,6 +13,7 @@ SKELETON_DIRS: tuple[str, ...] = (
13
13
  "assets/explore",
14
14
  "assets/design",
15
15
  "assets/testreport",
16
+ "assets/testcases",
16
17
  "packages/action_words/db_seed",
17
18
  "packages/action_words/db_assert",
18
19
  "packages/action_words/api_request",
@@ -49,6 +49,10 @@ def questions_dir(root: Path) -> Path:
49
49
  return root / "artifacts" / "inbox" / "questions"
50
50
 
51
51
 
52
+ def archived_questions_dir(root: Path) -> Path:
53
+ return root / "artifacts" / "inbox" / "archived-question"
54
+
55
+
52
56
  def _utc_day() -> str:
53
57
  return datetime.now(timezone.utc).strftime("%Y%m%d")
54
58
 
@@ -57,6 +61,19 @@ def _today() -> str:
57
61
  return datetime.now(timezone.utc).strftime("%Y-%m-%d")
58
62
 
59
63
 
64
+ def _next_question_id(repo: Path) -> str:
65
+ """Next Q-id for today, counting both the open inbox and the archive."""
66
+ day = _utc_day()
67
+ pat = re.compile(rf"^Q-{day}-(\d+)$")
68
+ nums: list[int] = []
69
+ for directory in (questions_dir(repo), archived_questions_dir(repo)):
70
+ if not directory.is_dir():
71
+ continue
72
+ nums.extend(int(m.group(1)) for path in directory.glob(f"Q-{day}-*.md") if (m := pat.match(path.stem)))
73
+ questions_dir(repo).mkdir(parents=True, exist_ok=True)
74
+ return f"Q-{day}-{max(nums, default=0) + 1:03d}"
75
+
76
+
60
77
  def _next_seq(directory: Path, prefix: str, day: str) -> str:
61
78
  directory.mkdir(parents=True, exist_ok=True)
62
79
  pat = re.compile(rf"^{re.escape(prefix)}-{day}-(\d+)$")
@@ -300,7 +317,7 @@ def ask_question(
300
317
  ids = [item["id"] for item in chosen]
301
318
  if len(ids) != len(set(ids)):
302
319
  raise ValueError("option ids must be unique")
303
- question_id = _next_seq(questions_dir(repo), "Q", _utc_day())
320
+ question_id = _next_question_id(repo)
304
321
  prompt_one = " ".join(prompt.split())
305
322
  meta: dict[str, Any] = {
306
323
  "kind": "question",
@@ -347,25 +364,31 @@ def ask_question(
347
364
 
348
365
  def list_questions(*, root: Path | None = None, status: str | None = "open") -> list[dict[str, Any]]:
349
366
  repo = Path(root) if root is not None else project_root()
350
- directory = questions_dir(repo)
351
- if not directory.is_dir():
352
- return []
367
+ if status == "answered":
368
+ directories = [archived_questions_dir(repo)]
369
+ elif status == "open":
370
+ directories = [questions_dir(repo)]
371
+ else:
372
+ directories = [questions_dir(repo), archived_questions_dir(repo)]
353
373
  rows = []
354
- for path in sorted(directory.glob("Q-*.md")):
355
- meta, _ = _read(path)
356
- if status and meta.get("status") != status:
374
+ for directory in directories:
375
+ if not directory.is_dir():
357
376
  continue
358
- rows.append(
359
- {
360
- "id": meta.get("id"),
361
- "task_id": meta.get("task_id"),
362
- "topic": meta.get("topic"),
363
- "status": meta.get("status"),
364
- "blocking": meta.get("blocking"),
365
- "prompt": meta.get("prompt"),
366
- "path": path.relative_to(repo).as_posix(),
367
- }
368
- )
377
+ for path in sorted(directory.glob("Q-*.md")):
378
+ meta, _ = _read(path)
379
+ if status and meta.get("status") != status:
380
+ continue
381
+ rows.append(
382
+ {
383
+ "id": meta.get("id"),
384
+ "task_id": meta.get("task_id"),
385
+ "topic": meta.get("topic"),
386
+ "status": meta.get("status"),
387
+ "blocking": meta.get("blocking"),
388
+ "prompt": meta.get("prompt"),
389
+ "path": path.relative_to(repo).as_posix(),
390
+ }
391
+ )
369
392
  return rows
370
393
 
371
394
 
@@ -432,6 +455,10 @@ def answer_question(
432
455
  "answered": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
433
456
  }
434
457
  _write(path, meta, text)
458
+ dest = archived_questions_dir(repo) / path.name
459
+ dest.parent.mkdir(parents=True, exist_ok=True)
460
+ path.replace(dest)
461
+ path = dest
435
462
  task_id = str(meta.get("task_id") or "")
436
463
  task_path = _task_path(repo, task_id)
437
464
  task_meta, task_text = _read(task_path)
@@ -454,6 +481,7 @@ def answer_question(
454
481
  "id": question_id,
455
482
  "status": "answered",
456
483
  "option": option,
484
+ "path": path.relative_to(repo).as_posix(),
457
485
  "task_id": task_id,
458
486
  "task_status": task_meta.get("status"),
459
487
  "curated": curated or None,