tuner-testkit 4.1.0__tar.gz → 4.3.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 (214) hide show
  1. {tuner_testkit-4.1.0/tuner_testkit.egg-info → tuner_testkit-4.3.0}/PKG-INFO +4 -4
  2. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/README.md +3 -3
  3. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/pyproject.toml +2 -1
  4. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/__init__.py +1 -1
  5. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/__init__.py +1 -1
  6. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/__main__.py +1 -1
  7. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/__init__.py +8 -2
  8. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/model.py +27 -0
  9. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +106 -0
  10. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +33 -0
  11. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +15 -10
  12. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +2 -2
  13. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +75 -0
  14. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +23 -0
  15. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +2 -2
  16. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +30 -0
  17. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +41 -0
  18. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +25 -0
  19. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +55 -0
  20. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +3 -2
  21. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +4 -4
  22. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +13 -12
  23. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +20 -19
  24. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
  25. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +3 -1
  26. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +26 -19
  27. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +159 -0
  28. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +112 -0
  29. tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +91 -0
  30. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/__init__.py +5 -0
  31. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/__main__.py +4 -0
  32. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/cli.py +89 -0
  33. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/persist.py +274 -0
  34. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/tests/test_cli.py +26 -0
  35. tuner_testkit-4.3.0/tuner_testkit/apps/evidence/tests/test_persist.py +45 -0
  36. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/scaffold.py +13 -2
  37. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/config/env.py +5 -1
  38. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +2 -0
  39. tuner_testkit-4.3.0/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
  40. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/config.py +3 -0
  41. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/__main__.py +1 -1
  42. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/driver.py +2 -1
  43. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0/tuner_testkit.egg-info}/PKG-INFO +4 -4
  44. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/SOURCES.txt +9 -0
  45. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/entry_points.txt +1 -0
  46. tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +0 -102
  47. tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -53
  48. tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -159
  49. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/LICENSE +0 -0
  50. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/setup.cfg +0 -0
  51. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/__init__.py +0 -0
  52. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/api.py +0 -0
  53. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/db.py +0 -0
  54. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/generators.py +0 -0
  55. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/ids.py +0 -0
  56. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/wait.py +0 -0
  57. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/base.py +0 -0
  58. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/context.py +0 -0
  59. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/plane.py +0 -0
  60. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/registry.py +0 -0
  61. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/__init__.py +0 -0
  62. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/app.py +0 -0
  63. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/errors.py +0 -0
  64. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/router.py +0 -0
  65. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/spec.py +0 -0
  66. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/store.py +0 -0
  67. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/__init__.py +0 -0
  68. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/auth.py +0 -0
  69. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/__init__.py +0 -0
  70. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/capture.py +0 -0
  71. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/codegen.py +0 -0
  72. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/freeze.py +0 -0
  73. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/mocks.py +0 -0
  74. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/normalize.py +0 -0
  75. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
  76. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
  77. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/client.py +0 -0
  78. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/errors.py +0 -0
  79. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/jsonpath.py +0 -0
  80. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/__init__.py +0 -0
  81. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/__init__.py +0 -0
  82. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/changelog.py +0 -0
  83. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane.py +0 -0
  84. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane_app.py +0 -0
  85. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane_asset.py +0 -0
  86. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/tests/test_plane_asset.py +0 -0
  87. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/tests/test_plane_collect.py +0 -0
  88. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
  89. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
  90. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/addon.py +0 -0
  91. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/cli.py +0 -0
  92. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
  93. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
  94. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
  95. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/__init__.py +0 -0
  96. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/__main__.py +0 -0
  97. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/build.py +0 -0
  98. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/cli.py +0 -0
  99. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
  100. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
  101. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
  102. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
  103. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
  104. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +0 -0
  105. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
  106. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
  107. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
  108. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
  109. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +0 -0
  110. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
  111. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
  112. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
  113. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +0 -0
  114. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +0 -0
  115. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +0 -0
  116. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
  117. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
  118. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
  119. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
  120. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
  121. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
  122. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +0 -0
  123. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
  124. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
  125. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
  126. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
  127. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +0 -0
  128. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/paths.py +0 -0
  129. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/source.py +0 -0
  130. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/tests/test_cli.py +0 -0
  131. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dump_ddl.py +0 -0
  132. {tuner_testkit-4.1.0/tuner_testkit/apps/page_recorder → tuner_testkit-4.3.0/tuner_testkit/apps/evidence}/tests/__init__.py +0 -0
  133. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/__init__.py +0 -0
  134. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/__main__.py +0 -0
  135. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/registry.py +0 -0
  136. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/__init__.py +0 -0
  137. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/__main__.py +0 -0
  138. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/build.py +0 -0
  139. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/catalog.py +0 -0
  140. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/plane.py +0 -0
  141. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/tests/test_catalog.py +0 -0
  142. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/__init__.py +0 -0
  143. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/__main__.py +0 -0
  144. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/manifest.py +0 -0
  145. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
  146. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
  147. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
  148. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
  149. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
  150. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
  151. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
  152. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
  153. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
  154. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/plane.py +0 -0
  155. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
  156. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
  157. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
  158. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/plane.py +0 -0
  159. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
  160. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/__init__.py +0 -0
  161. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/__main__.py +0 -0
  162. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/cli.py +0 -0
  163. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/plane.py +0 -0
  164. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/seed.py +0 -0
  165. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
  166. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
  167. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/capture.py +0 -0
  168. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/cli.py +0 -0
  169. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
  170. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
  171. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/inject.py +0 -0
  172. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/session.py +0 -0
  173. {tuner_testkit-4.1.0/tuner_testkit/apps/recorder → tuner_testkit-4.3.0/tuner_testkit/apps/page_recorder}/tests/__init__.py +0 -0
  174. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
  175. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
  176. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
  177. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/__init__.py +0 -0
  178. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/__main__.py +0 -0
  179. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/cli.py +0 -0
  180. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
  181. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/__init__.py +0 -0
  182. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/client.py +0 -0
  183. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/connection.py +0 -0
  184. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/excel/__init__.py +0 -0
  185. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/excel/workbook.py +0 -0
  186. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/__init__.py +0 -0
  187. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/__main__.py +0 -0
  188. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/catalog.py +0 -0
  189. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/china.py +0 -0
  190. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/cli.py +0 -0
  191. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/core.py +0 -0
  192. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/medical.py +0 -0
  193. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/wrappers.py +0 -0
  194. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/__init__.py +0 -0
  195. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/context.py +0 -0
  196. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/core.py +0 -0
  197. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/helpers.py +0 -0
  198. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/hooks.py +0 -0
  199. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/scenario_file.py +0 -0
  200. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/__init__.py +0 -0
  201. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/base.py +0 -0
  202. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/errors.py +0 -0
  203. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/harvest.py +0 -0
  204. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/health.py +0 -0
  205. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/locator.py +0 -0
  206. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/model.py +0 -0
  207. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/registry.py +0 -0
  208. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/session.py +0 -0
  209. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/steps.py +0 -0
  210. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/testing.py +0 -0
  211. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/project.py +0 -0
  212. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/dependency_links.txt +0 -0
  213. {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/requires.txt +0 -0
  214. {tuner_testkit-4.1.0 → tuner_testkit-4.3.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: 4.1.0
3
+ Version: 4.3.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
@@ -138,10 +138,10 @@ uv tool upgrade tuner-testkit
138
138
 
139
139
  ```bash
140
140
  # 钉到某一发行版(推荐,和团队 lock 一致)
141
- uv add "tuner-testkit[db,api]==4.1.0"
141
+ uv add "tuner-testkit[db,api]==4.3.0"
142
142
 
143
143
  # 或只抬下限,让解析器选允许范围内的最新
144
- # uv add "tuner-testkit[db,api]>=4.1.0"
144
+ # uv add "tuner-testkit[db,api]>=4.3.0"
145
145
 
146
146
  uv sync
147
147
  ```
@@ -210,4 +210,4 @@ uv sync --extra all
210
210
 
211
211
  `uv sync --extra dev` 与 `--extra all` 等价(`dev` 只是引用 `[all]`)。
212
212
 
213
- 4.1.0 发行说明见 [`docs/changelog/TEMPLATE-4.1.0.md`](docs/changelog/TEMPLATE-4.1.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
213
+ 4.3.0 发行说明见 [`docs/changelog/TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);4.2.0 见 [`TEMPLATE-4.2.0.md`](docs/changelog/TEMPLATE-4.2.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
@@ -93,10 +93,10 @@ uv tool upgrade tuner-testkit
93
93
 
94
94
  ```bash
95
95
  # 钉到某一发行版(推荐,和团队 lock 一致)
96
- uv add "tuner-testkit[db,api]==4.1.0"
96
+ uv add "tuner-testkit[db,api]==4.3.0"
97
97
 
98
98
  # 或只抬下限,让解析器选允许范围内的最新
99
- # uv add "tuner-testkit[db,api]>=4.1.0"
99
+ # uv add "tuner-testkit[db,api]>=4.3.0"
100
100
 
101
101
  uv sync
102
102
  ```
@@ -165,4 +165,4 @@ uv sync --extra all
165
165
 
166
166
  `uv sync --extra dev` 与 `--extra all` 等价(`dev` 只是引用 `[all]`)。
167
167
 
168
- 4.1.0 发行说明见 [`docs/changelog/TEMPLATE-4.1.0.md`](docs/changelog/TEMPLATE-4.1.0.md);3.x → 4.x 迁移见 [`TEMPLATE-4.0.0.md`](docs/changelog/TEMPLATE-4.0.0.md)。平台能力地图见 [`INDEX.md`](INDEX.md)。
168
+ 4.3.0 发行说明见 [`docs/changelog/TEMPLATE-4.3.0.md`](docs/changelog/TEMPLATE-4.3.0.md);4.2.0 见 [`TEMPLATE-4.2.0.md`](docs/changelog/TEMPLATE-4.2.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 = "4.1.0"
3
+ version = "4.3.0"
4
4
  description = "Shared test runtime, recorders, and DNA overlay for SUT test repos"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -73,6 +73,7 @@ tuner-index-platform = "tuner_testkit.apps.index_platform.__main__:main"
73
73
  tuner-fake = "tuner_testkit.fake.cli:main"
74
74
  tuner-page-test = "tuner_testkit.page_test.__main__:main"
75
75
  tuner-action-words = "tuner_testkit.action_words.__main__:main"
76
+ tuner-evidence = "tuner_testkit.apps.evidence.cli:main"
76
77
 
77
78
  [build-system]
78
79
  requires = ["setuptools>=77", "wheel"]
@@ -2,4 +2,4 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- __version__ = "4.1.0"
5
+ __version__ = "4.3.0"
@@ -15,7 +15,7 @@ CLI::
15
15
  uv run python -m tuner_testkit.action_words list
16
16
  uv run python -m tuner_testkit.action_words describe <word_id>
17
17
  uv run python -m tuner_testkit.action_words run <word_id> --params '{...}'
18
- uv run python -m tuner_testkit.action_words catalog --out report/action_words_catalog.json
18
+ uv run python -m tuner_testkit.action_words catalog --out artifacts/catalogs/action_words_catalog.json
19
19
  """
20
20
  from __future__ import annotations
21
21
 
@@ -7,7 +7,7 @@
7
7
  uv run python -m tuner_testkit.action_words run db_seed.create_example --params "{...}"
8
8
  uv run python -m tuner_testkit.action_words run db_seed.create_example --params-file p.json
9
9
  uv run python -m tuner_testkit.action_words run db_seed.create_example --example
10
- uv run python -m tuner_testkit.action_words catalog --out report/action_words_catalog.json
10
+ uv run python -m tuner_testkit.action_words catalog --out artifacts/catalogs/action_words_catalog.json
11
11
 
12
12
  ``run`` 未提供 ``--params`` 时使用 ``{}``(即全部默认值);``--example``
13
13
  使用 word 自带的 ``example_params`` 样例运行。
@@ -6,7 +6,13 @@ Primary entrypoints:
6
6
  """
7
7
 
8
8
  from .client import ApiClient
9
- from .model import APIModel, ApiResponse, AssertOperation, ExtractVariableOperation
9
+ from .model import (
10
+ APIModel,
11
+ ApiResponse,
12
+ AssertOperation,
13
+ ExtractVariableOperation,
14
+ interpolate_path,
15
+ )
10
16
 
11
17
  __all__ = [
12
18
  "APIModel",
@@ -14,5 +20,5 @@ __all__ = [
14
20
  "AssertOperation",
15
21
  "ExtractVariableOperation",
16
22
  "ApiClient",
23
+ "interpolate_path",
17
24
  ]
18
-
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import re
3
4
  from dataclasses import dataclass, field, replace
4
5
  from typing import Any, Dict, Iterable, List, Mapping, MutableMapping, Optional
5
6
 
@@ -102,6 +103,22 @@ def _required_file_fields(schema: Mapping[str, Any]) -> list[str]:
102
103
  return out
103
104
 
104
105
 
106
+ _PATH_PLACEHOLDER_RE = re.compile(r"\{([A-Za-z_][A-Za-z0-9_]*)\}")
107
+
108
+
109
+ def interpolate_path(path: str, params: Mapping[str, Any]) -> str:
110
+ """Replace ``{name}`` segments. Raises if any named placeholder remains."""
111
+ out = path
112
+ for key, value in params.items():
113
+ out = out.replace("{" + str(key) + "}", str(value))
114
+ leftover = _PATH_PLACEHOLDER_RE.findall(out)
115
+ if leftover:
116
+ raise SchemaValidationError(
117
+ f"path still has placeholders {leftover}; pass them via set_path"
118
+ )
119
+ return out
120
+
121
+
105
122
  @dataclass(frozen=True)
106
123
  class APIModel:
107
124
  # Identity
@@ -156,6 +173,9 @@ class APIModel:
156
173
  def set_headers(self, values: Optional[Mapping[str, Any]] = None) -> "APIInvocation":
157
174
  return APIInvocation(self).set_headers(values)
158
175
 
176
+ def set_path(self, values: Optional[Mapping[str, Any]] = None) -> "APIInvocation":
177
+ return APIInvocation(self).set_path(values)
178
+
159
179
  def override_query(self, values: Optional[Mapping[str, Any]] = None) -> "APIInvocation":
160
180
  return APIInvocation(self).override_query(values)
161
181
 
@@ -181,6 +201,7 @@ class APIInvocation:
181
201
  _set_json: Dict[str, Any] = field(default_factory=dict)
182
202
  _set_files: Dict[str, Any] = field(default_factory=dict)
183
203
  _set_headers: Dict[str, Any] = field(default_factory=dict)
204
+ _path_params: Dict[str, Any] = field(default_factory=dict)
184
205
  _override_query: Optional[Dict[str, Any]] = None
185
206
  _override_json: Any = None
186
207
  _override_json_set: bool = False
@@ -237,6 +258,10 @@ class APIInvocation:
237
258
  checked = _enforce_headers_policy(headers=values, allowlist=allowlist, forbidden=forbidden)
238
259
  return replace(self, _set_headers=_merge_shallow(self._set_headers, checked))
239
260
 
261
+ def set_path(self, values: Optional[Mapping[str, Any]] = None) -> "APIInvocation":
262
+ values = {str(k): v for k, v in dict(values or {}).items()}
263
+ return replace(self, _path_params=_merge_shallow(self._path_params, values))
264
+
240
265
  def override_query(self, values: Optional[Mapping[str, Any]] = None) -> "APIInvocation":
241
266
  values = dict(values or {})
242
267
  # override still must respect schema; allow autofill via set_query if needed
@@ -308,6 +333,8 @@ class APIInvocation:
308
333
  from .client import ApiClient # local import to avoid cycles
309
334
 
310
335
  m = self._effective_model()
336
+ if self._path_params:
337
+ m = replace(m, path=interpolate_path(m.path, self._path_params))
311
338
  use_client = client or m._client or ApiClient.default()
312
339
  files = self._final_files()
313
340
  self._validate_required_files(m, files)
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: bdd-asset-pipeline
3
+ version: 2.0.0
4
+ description: Lower-half of SUT self-learning — Feature Sets + design knowledge → Reuse Analysis → Freeze API Objects → Maintain Page Objects → Maintain Steps → behave regression. Use only for behave/BDD automation assets. Do NOT use when the user explicitly requests pytest. Do NOT use this agent as the explore-first entry; start from docs/spec/sut-self-learning.md instead.
5
+ ---
6
+
7
+ # BDD Asset Pipeline Agent (lower half)
8
+
9
+ ## Purpose
10
+
11
+ Coordinate the **lower half** of SUT self-learning once a feature-set entry
12
+ and (when available) design knowledge exist:
13
+
14
+ Feature Set item + `assets/design/**` → (optional MCP re-run) → Reuse vs
15
+ Create → Freeze API Objects → Update Page Objects → Implement Steps →
16
+ Regression run → Report.
17
+
18
+ The **upper half** (explore SUT → capability map + design knowledge) is
19
+ specified in `docs/spec/sut-self-learning.md`. Do not start this agent
20
+ when the task is still "learn the SUT / explore pages" with no feature
21
+ intent yet.
22
+
23
+ ## Applicability
24
+
25
+ - **Use this agent** when generating or maintaining `.feature` / behave
26
+ steps / BDD UI·API assets **from** a feature-set entry (and design notes).
27
+ - **Do not use this agent** when the user **explicitly** asks for **pytest**.
28
+ - **Do not use this agent** as the first step of explore-first learning.
29
+
30
+ ## Inputs (required)
31
+
32
+ - At least one feature-set entry (a `.feature` to write/update, or a
33
+ scenario intent grounded in `assets/explore/**` / `assets/usecases/**`).
34
+ - Prefer also: matching `assets/design/<app>/<route-slug>.md` so assertions
35
+ know which tables to check and which to skip as `noise`.
36
+
37
+ ## Non-negotiable workflow contract (hard gates)
38
+
39
+ Same three gates as `.cursor/rules/bdd-pipeline-gates.mdc` v3:
40
+
41
+ - **Gate 1: Evidence is mandatory** (explore session OR feature run). Cite
42
+ `artifacts/evidence/<run_id>/`. Do not skip MCP just because local
43
+ `sync_playwright` UI steps pass. If MCP is blocked, stop and report.
44
+ - **Gate 2: Freeze is mandatory when capture has eligible routes**.
45
+ - **Gate 3: Run the stages that actually exist** — do not fail a missing
46
+ API/UI stage that was never authored.
47
+
48
+ ## Skills to use (in order)
49
+
50
+ 1. **Feature authoring / rewrite** — `feature-authoring` → `tests/features/**/*.feature`
51
+ 2. **Feature review / lint** — `feature-review-lint`
52
+ 3. **Execute scenario & capture evidence** (if no reusable evidence) —
53
+ `run-feature-playwright-mcp` → sanitized `artifacts/evidence/<run_id>/`
54
+ 4. **Reuse analysis** — `reuse-analysis`
55
+ 5. **Freeze captures into API assets** — `freeze-api-objects`
56
+ 6. **Maintain UI assets** — `maintain-page-objects`
57
+ 7. **Implement/repair behave steps** — `maintain-behave-steps`
58
+
59
+ Before writing Then-assertions, **read `assets/design/**`**:
60
+
61
+ - Assert `writes` (business tables) via `db_assert` / API extracts.
62
+ - Never assert `noise` tables (audit / operation_log) as business outcomes.
63
+ - Use `correlate` / `identity` to locate rows; do not hardcode scenario ids
64
+ into APIModel asserts.
65
+
66
+ ## Cross-cutting constraints (must always hold)
67
+
68
+ - No secrets in repo: tokens/cookies/authorization/session secrets must never be written.
69
+ - Steps do not contain selectors or handcrafted requests.
70
+ - Assertions are stable and observable; no scenario constants inside API Object asserts.
71
+ - API execution is triggered via `APIModel.execute()` after `set_*` / `override_*`.
72
+ - **Binary / form APIs**: `tuner_testkit.api_test` always returns
73
+ `ApiResponse.content` (raw bytes). Use `APIModel.body_format="form"` when
74
+ capture shows `application/x-www-form-urlencoded`. For xlsx/CSV exports,
75
+ freeze a route-aligned asset that asserts HTTP 200 only; parse bodies with
76
+ `tuner_testkit.excel` in steps or `packages/<domain>` — not in
77
+ `packages/api_objects/`.
78
+
79
+ ## Repo conventions this agent must enforce
80
+
81
+ ### Stage mode (`behave --stage`)
82
+
83
+ - `behave --stage <name>` changes discovery:
84
+ - steps dir becomes `tests/features/<name>_steps/` (top-level `*.py` only)
85
+ - environment file becomes `tests/features/<name>_environment.py` (if present)
86
+ - Therefore `tests/features/ui_steps/` and `tests/features/api_steps/` **must**
87
+ have a top-level loader that imports the actual step modules.
88
+
89
+ ### Step file granularity (required)
90
+
91
+ - UI: `tests/features/ui_steps/given.py`, `when.py`, `then.py`
92
+ - API: `tests/features/api_steps/given.py`, `when.py`, `then.py`
93
+ - **Do not** create domain-split step files like `auth_api_then.py`.
94
+ Reuse is achieved by **phrases and functions**, not by multiplying files.
95
+
96
+ ## Done criteria
97
+
98
+ - Feature scenarios read well and pass lint rules.
99
+ - Steps are thin and reusable.
100
+ - `packages/api_objects/` and `packages/page_objects/` are the only place
101
+ with implementation details (per layer).
102
+ - Assertions consult design knowledge when it exists.
103
+ - Evidence is on disk under `artifacts/evidence/<run_id>/` (sanitized).
104
+ - `behave --stage ui` succeeds for UI features that exist.
105
+ - `behave --stage api` succeeds for API features that exist (or `--dry-run`
106
+ with documented TODO).
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: sut-source-to-design
3
+ version: 1.0.0
4
+ description: Walk SUT backend source (Django models/views/serializers, or equivalent) plus assets/ddl to draft assets/design/<app>/<route-slug>.md. Use when the engineer points at a source tree. Do not invent tables. Complements derive-design-knowledge; this agent is the source-channel playbook.
5
+ ---
6
+
7
+ # SUT source → design knowledge
8
+
9
+ ## Purpose
10
+
11
+ Highest-quality `writes` / `noise` / `reads` often come from **models.save / views**, not from MCP bodies. Plane dogfood: `Issue.save` showed `issue_sequences` + `_ensure_default_state` before any DB diff existed.
12
+
13
+ ## Inputs
14
+
15
+ - Source root the user named (e.g. `C:\dev\repo\plane\apps\api`)
16
+ - Matching `assets/ddl/<datasource>/` if present (dump missing tables rather than hallucinate)
17
+ - Optional `artifacts/evidence/<run_id>/` to fill `api_object_ref` / `page_ref`
18
+
19
+ ## Workflow
20
+
21
+ 1. Locate the route: urls.py / router → view/serializer.
22
+ 2. Locate the model `.save()` / service function for that write.
23
+ 3. List INSERT/UPDATE/DELETE tables. Audit / `*_activities` / operation_log → `noise`.
24
+ 4. If a table is named in source but missing from DDL, run `tuner-dump-ddl <table> --datasource …` then continue. Do not skip the table.
25
+ 5. Write one `assets/design/<app>/<route-slug>.md` per **route** (not per button) using `docs/spec/design-knowledge-syntax.md` v0.1.
26
+ 6. Record schema gaps under `## notes` (conditional writes, defaulted FKs, dual identity). Do **not** invent new top-level keys yet.
27
+
28
+ ## Hard rules
29
+
30
+ - Table/column names must appear in DDL or source. No guessed identifiers.
31
+ - `confidence: inferred` for source-only; `observed` only with DB/log evidence.
32
+ - No secrets.
33
+ - Do not generate action words here.
@@ -2,28 +2,34 @@
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.0.0
5
+ version: 1.1.0
6
6
  ---
7
7
 
8
8
  # assets — 知识层硬约束
9
9
 
10
10
  `assets/` 存放给人和 LLM 阅读、作为生成测试代码/工具依据的知识。完整规范见
11
11
  `docs/spec/assets-knowledge-syntax.md`;全局发现入口见根 `INDEX.md`。
12
+ SUT 自学习见 `docs/spec/sut-self-learning.md`;design schema 见
13
+ `docs/spec/design-knowledge-syntax.md`。
12
14
 
13
15
  ## Grounding(生成前必读)
14
16
 
15
17
  - **生成任何测试 / action word / api·page object / 工具之前**,先查根 `INDEX.md`
16
- 检索相关 domain 的知识(真实 DDL 列名、`assets/sql` 真实业务 SQL、`usecases` /
17
- `domain-notes`),以此为依据,**不要凭空臆造**列名、接口字段、业务规则。
18
- - 缺知识时先回填:`/dump-ddl` 或 `python -m tuner_testkit.apps.dump_ddl --all --datasource <alias>`(DDL)、
19
- `python -m tuner_testkit.apps.recorder`(合录)或 `python -m tuner_testkit.apps.api_recorder`(代理抓包),再进入生成。
18
+ (及存在时的 `INDEX.project.md`)检索相关 domain 的知识(真实 DDL 列名、
19
+ `assets/sql`、`usecases` / `domain-notes` / `explore` / `design`),
20
+ **不要凭空臆造**列名、接口字段、业务规则。
21
+ - 缺知识时先回填:`/dump-ddl` 或 `python -m tuner_testkit.apps.dump_ddl`、
22
+ Playwright MCP 探索(落盘 `artifacts/evidence/<run_id>/`)、
23
+ `python -m tuner_testkit.apps.recorder` / `api_recorder`,再进入生成。
20
24
 
21
25
  ## 目录与元数据
22
26
 
23
27
  - 目录分类固定:`ddl/<datasource>/`、`sql/`、`usecases/<domain>/`、
24
- `domain-notes/<domain>/`、`testreport/`(新增类别前先看 spec)。
28
+ `domain-notes/<domain>/`、`explore/<app>/`、`design/<app>/`、`testreport/`
29
+ (新增类别前先改 spec,再改本 rule)。
25
30
  - 人工/半自动区文件头必须带元数据:`domain / source / date / version / confidence`
26
31
  (Markdown 用 YAML front-matter,SQL 用顶部 `--` 注释)。
32
+ - `explore/` 与 `design/` 还应填 `evidence`(run_id 列表)。
27
33
  - `confidence: high` 表示人工核实过——LLM 应优先采信。
28
34
 
29
35
  ## raw vs curated
@@ -33,10 +39,9 @@ version: 1.0.0
33
39
 
34
40
  ## 变更留痕
35
41
 
36
- - 自动区(`ddl/`)更新由工具写 `assets/CHANGELOG.md`(见 `apps-authoring-syntax.md`);
37
- 人不手改自动区语义,要更新就重跑工具。
38
- - curated 更新 → bump `version` + 正文追加变更说明;随后由 `maintain-index` skill
39
- 增量更新根 `INDEX.md`。
42
+ - 自动区(`ddl/`)更新由工具写 `assets/CHANGELOG.md`;人不手改自动区语义。
43
+ - curated 更新 → bump `version` + 正文追加变更说明;随后由 `maintain-index`
44
+ 增量更新 `INDEX.md` / `INDEX.project.md`。
40
45
 
41
46
  ## 禁止
42
47
 
@@ -2,7 +2,7 @@
2
2
  description: Enforce layered boundaries between feature/steps/action_words/page_objects/api_objects and tuner_testkit runtime; no selector or request leakage across layers
3
3
  globs: **/*.py
4
4
  alwaysApply: false
5
- version: 1.3.0
5
+ version: 1.3.1
6
6
  ---
7
7
 
8
8
  # Asset Layering — boundary rules per layer
@@ -40,7 +40,7 @@ Each layer owns one responsibility. Leakage across layers (e.g. selectors in ste
40
40
 
41
41
  ## Cross-cutting
42
42
 
43
- - **No secrets in repo**, ever: `Authorization`, `Cookie`, `Set-Cookie`, `*token*`, `*secret*`, `*password*`, `*session*`. Also applies to captures under `report/` / `testcase/`.
43
+ - **No secrets in repo**, ever: `Authorization`, `Cookie`, `Set-Cookie`, `*token*`, `*secret*`, `*password*`, `*session*`. Also applies to captures under `artifacts/evidence/`.
44
44
  - **Evidence-driven edits**: Page/API object changes must be backed by Playwright MCP snapshots, `tuner-recorder` / `tuner-api-recorder` captures (`python -m tuner_testkit.apps.recorder` / `api_recorder`), or run_summary findings; avoid locator/path guesses.
45
45
  - **`tests/**` must not import `apps.*`**. Action words for BDD/pytest stay in
46
46
  `tuner_testkit.action_words`. Opt into Plane with `@plane_db_seed` (etc.) from
@@ -0,0 +1,75 @@
1
+ ---
2
+ description: Three gates for the BDD/self-learning asset pipeline (evidence capture, API-object freeze, stage regression); skipped when user explicitly requests pytest
3
+ globs: tests/features/**,packages/api_objects/**,packages/page_objects/**,assets/design/**
4
+ alwaysApply: false
5
+ version: 3.0.0
6
+ ---
7
+
8
+ # BDD / self-learning pipeline — three gates
9
+
10
+ > **Scope**: this rule governs **behave/BDD** asset work **and** explore-first
11
+ > writes into `packages/api_objects/**`, `packages/page_objects/**`,
12
+ > `assets/design/**`. Auto-attaches on those globs. It is **not** a
13
+ > platform-wide default. Task routing lives in [`AGENTS.md`](../../AGENTS.md);
14
+ > the BDD **lower half** is orchestrated by
15
+ > [`bdd-asset-pipeline`](../agents/bdd-asset-pipeline.md). Explore-first
16
+ > learning is specified in `docs/spec/sut-self-learning.md`.
17
+
18
+ ## Framework selection (read first)
19
+
20
+ - **Default** for UI/API business-flow automation assets is the behave path.
21
+ - **Exception — user-explicit pytest**: implement with pytest. Do **not**
22
+ force `.feature` / behave steps / `behave --stage` / these gates.
23
+ - When in doubt and the user did **not** name a framework, prefer behave for
24
+ scenario-style UI/API flows.
25
+ - Pytest tests should still reuse `tuner_testkit` and this repo's `packages/**`.
26
+
27
+ ## Gate 1 — Evidence is mandatory (explore-first OK)
28
+
29
+ Any write into `packages/api_objects/**`, `packages/page_objects/**`, or
30
+ `assets/design/**` **must** cite at least one `artifacts/evidence/<run_id>/`
31
+ record (sanitized). The evidence may come from:
32
+
33
+ - an **explore session** (no `.feature` yet) via Playwright MCP, or
34
+ - a **feature run** via `run-feature-playwright-mcp`.
35
+
36
+ Do **not** require a pre-existing `.feature` just to satisfy this gate.
37
+ Do **not** substitute MCP with local `sync_playwright` solely because UI
38
+ steps pass locally.
39
+
40
+ If capture is blocked (captcha, SSO, OTP, permission prompts, unreachable
41
+ env) → **stop**, and report: where it blocked, what human action is needed,
42
+ what evidence was collected, what assets can/cannot proceed. Do not write
43
+ API/design assets as if capture existed.
44
+
45
+ ## Gate 2 — Freeze API Objects when capture has eligible routes
46
+
47
+ - If evidence captured **any non-static** route related to the session or
48
+ scenarios, freeze them into `packages/api_objects/**` following
49
+ `freeze-api-objects` (route-aligned, deduped, sanitized).
50
+ - If you create zero API Objects, **state why** (pure SPA / all static /
51
+ blocked before login / etc.). Silence is not acceptable.
52
+ - Never commit real tokens, cookies, Authorization/Set-Cookie headers, or
53
+ sensitive values — neither in source nor in any evidence bundle.
54
+
55
+ ## Gate 3 — Prove the stages that actually exist
56
+
57
+ After **behave/BDD** asset changes under `tests/features/`:
58
+
59
+ - If a UI feature (or UI steps) exist → run `behave --stage ui <feature>`.
60
+ - If an API feature (or API steps) exist → run `behave --stage api <feature>`
61
+ (or `--dry-run` with an explicit TODO if the API feature is not yet authored).
62
+ - Do **not** fail the task for a stage that has no feature yet.
63
+ - For user-explicit **pytest** work, prove with `pytest <path>` instead.
64
+
65
+ When writing assertions, consult `assets/design/**` first: assert `writes`
66
+ tables, skip `noise` tables, use `correlate` / `identity` for locating rows.
67
+
68
+ ## Enforcement summary
69
+
70
+ - Asset writes are not done unless: sanitized evidence exists under
71
+ `artifacts/evidence/<run_id>/`, eligible routes are frozen (or explicit
72
+ zero-freeze justification), and every **existing** behave stage is exercised.
73
+ - User-explicit pytest tasks are done when the requested suite runs
74
+ successfully; do not invent a parallel behave feature unless asked.
75
+ - When any applicable gate would be violated, **stop and report the blocker**.
@@ -0,0 +1,23 @@
1
+ ---
2
+ description: Safety rails for live-SUT explore sessions (Playwright MCP). Attaches when writing evidence, explore notes, or design knowledge.
3
+ globs: artifacts/evidence/**,assets/explore/**,assets/design/**
4
+ alwaysApply: false
5
+ version: 1.0.0
6
+ ---
7
+
8
+ # Explore safety — live SUT
9
+
10
+ Exploring a running web SUT is a real side-effecting session.
11
+
12
+ ## Must
13
+
14
+ - Prefer create-on-throwaway-data over mutating shared fixtures.
15
+ - Stop and ask before DELETE / archive / permission-admin / billing actions.
16
+ - Persist only **sanitized** evidence (`artifacts/evidence/<run_id>/`).
17
+ - Cite `run_id` from any `assets/explore` or `assets/design` write.
18
+
19
+ ## Must not
20
+
21
+ - Persist Authorization / Cookie / Set-Cookie / tokens / passwords.
22
+ - Treat captcha/SSO/OTP bypass as something the agent should solve.
23
+ - Crawl the entire product in one session — stay on the agreed vertical slice.
@@ -2,7 +2,7 @@
2
2
  description: Keep the repo-level INDEX.md current and require managed assets to leave a changelog trail; index is the discovery entry for humans and the LLM
3
3
  globs: assets/**,packages/api_objects/**,packages/page_objects/**,apps/**,tuner_testkit/apps/**
4
4
  alwaysApply: false
5
- version: 1.1.2
5
+ version: 1.1.3
6
6
  ---
7
7
 
8
8
  # index-hygiene — 索引与留痕纪律
@@ -15,7 +15,7 @@ version: 1.1.2
15
15
  追加 changelog(`assets/CHANGELOG.md` / `packages/api_objects/CHANGELOG.md` /
16
16
  `packages/page_objects/CHANGELOG.md`),格式见
17
17
  `docs/spec/apps-authoring-syntax.md`。人不手改自动区语义,要更新就重跑工具。
18
- - **人工/半自动区**(`assets/usecases`、`domain-notes`、`sql`、新 page/api object、新 app):
18
+ - **人工/半自动区**(`assets/usecases`、`domain-notes`、`explore`、`design`、`sql`、新 page/api object、新 app):
19
19
  新增/变更后应在对应索引登记一行(或运行 `maintain-index` skill 增量补齐):
20
20
  平台工具/公共包 → `INDEX.md`;业务 DDL/用例/api_objects/page_objects/features → 有 `INDEX.project.md` 则写那里,否则写 `INDEX.md`。
21
21
 
@@ -0,0 +1,30 @@
1
+ ---
2
+ name: analyze-mcp-network
3
+ version: 1.0.0
4
+ description: Turn a persisted artifacts/evidence/<run_id>/network.jsonl into a unique method+path route table (JSON) for freeze-api-objects. Prefer tuner-evidence routes (deterministic). Use after explore-sut or run-feature-playwright-mcp. Do not invent routes that are not in the JSONL.
5
+ ---
6
+
7
+ # Analyze MCP network evidence
8
+
9
+ ## Scope
10
+
11
+ - **Primary goal**: list freeze candidates from on-disk evidence.
12
+ - **Write scope**: none (read-only). Optionally paste the JSON into the freeze handoff.
13
+ - **Must follow**: `docs/spec/bdd-run-gherkin-in-playwrightMCP.md` sanitizer — if the JSONL still contains Cookie/Authorization, stop and re-run `tuner-evidence persist`.
14
+
15
+ ## Steps
16
+
17
+ 1. Confirm `artifacts/evidence/<run_id>/network.jsonl` exists.
18
+ 2. Run (stdout is JSON):
19
+
20
+ ```bash
21
+ uv run python -m tuner_testkit.apps.evidence routes --run-id <run_id>
22
+ ```
23
+
24
+ 3. Hand the `routes[]` list to `freeze-api-objects`. Skip static/HTML. Skip `POST /api/sign-in/` (password body) unless the user explicitly wants a login API asset **without** persisting credentials.
25
+ 4. For slug paths that `normalize_path` left as literals (e.g. `/api/workspaces/tuner/...`), freeze with `{workspace_slug}` and tell callers to `set_path`.
26
+
27
+ ## Hard rules
28
+
29
+ - Do not re-fetch live traffic here.
30
+ - Do not write api_objects in this skill.
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: derive-design-knowledge
3
+ version: 0.2.0
4
+ description: Compile assets/design/<app>/<route-slug>.md from open evidence channels (MCP network, DDL, SUT source, optional logs). Schema is docs/spec/design-knowledge-syntax.md v0.1 (draft). Use after an explore session or API freeze when DB effects must ground assertions. Do not invent tables that are not in DDL or source.
5
+ ---
6
+
7
+ # Derive design knowledge
8
+
9
+ ## Scope
10
+
11
+ - **Primary goal**: one route → one `assets/design/<app>/<route-slug>.md`.
12
+ - **Write scope**: `assets/design/**` only.
13
+ - **Must follow**: `docs/spec/design-knowledge-syntax.md` (v0.1 draft — record schema gaps in `## notes`).
14
+ - **Evidence is open**: MCP `network.jsonl`, `assets/ddl/**`, SUT source trees the user pointed at, log dumps from `apps/*`. Do not require all channels.
15
+
16
+ ## Steps
17
+
18
+ 1. Collect inputs: `run_id`, frozen `api_object_ref` if any, page trigger if known, DDL dir, optional source path.
19
+ 2. For each captured **non-static mutating** route (POST/PUT/PATCH/DELETE):
20
+ - Draft front-matter (`confidence`: `observed` only if DB/log proved it; else `inferred`).
21
+ - Fill `writes` / `noise` / `reads` from the **highest quality channel available**:
22
+ 1. source (models/views/serializers) — see `.cursor/agents/sut-source-to-design.md`
23
+ 2. SQL logs / DB diff
24
+ 3. inference from response body + DDL names
25
+ - If source names a table that is not in `assets/ddl`, dump it (`tuner-dump-ddl`) before writing `writes`.
26
+ - Skip `operation_log` / `*_activities` / audit tables as `noise` unless the user says they are the assertion target.
27
+ 3. Every `writes` row must cite evidence or a source path in `## notes`.
28
+ 4. If the v0.1 schema cannot express something (multi-API button, external side effects), write it under `## notes` and do **not** invent new top-level keys yet — the draft must be stress-tested first.
29
+
30
+ ## Hard rules
31
+
32
+ - Ground table/column names in `assets/ddl` or source. No hallucinated identifiers.
33
+ - No secrets.
34
+ - Do not generate `db_assert` words here; only the knowledge file.
35
+
36
+ ## Output checklist
37
+
38
+ - File path matches method+normalized_path slug.
39
+ - `api_object_ref` / `page_ref` filled when those assets exist.
40
+ - `noise` vs `writes` explicitly split.
41
+ - Schema gaps listed for later spec bump.
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: derive-feature-sets
3
+ version: 1.0.0
4
+ description: Turn assets/explore capability notes (plus usecases/domain-notes) into behave Feature Sets under tests/features/. Use after explore-sut, before bdd-asset-pipeline. Do NOT use when the user explicitly requests pytest.
5
+ ---
6
+
7
+ # Derive Feature Sets
8
+
9
+ ## Scope
10
+
11
+ - **Primary goal**: write Gherkin that expresses the explored capability, not the click path.
12
+ - **Write scope**: `tests/features/**/*.feature` via `feature-authoring` rules.
13
+ - **Inputs**: `assets/explore/**`, optional `assets/usecases/**`, `assets/design/**` (so Then clauses stay honest).
14
+
15
+ ## Steps
16
+
17
+ 1. Read explore notes for the slice. List user-visible capabilities as candidate scenarios.
18
+ 2. Follow `docs/spec/behave-gerkin-syntax.md` (no selectors/SQL/URLs in the feature).
19
+ 3. Prefer one Feature per capability area; Rule groups around business rules if needed.
20
+ 4. Keep scenarios 5–12 steps. Tag `@smoke` only for the thinnest happy path.
21
+ 5. If design knowledge exists, Then steps should talk about **observable business results**, not audit tables.
22
+
23
+ ## Hand off
24
+
25
+ After files exist, continue with `bdd-asset-pipeline` (lower half) to freeze objects and implement steps.