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.
- {tuner_testkit-4.1.0/tuner_testkit.egg-info → tuner_testkit-4.3.0}/PKG-INFO +4 -4
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/README.md +3 -3
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/pyproject.toml +2 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/__init__.py +1 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/__init__.py +1 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/__main__.py +1 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/__init__.py +8 -2
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/model.py +27 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +106 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +33 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +15 -10
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +2 -2
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +75 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +23 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +2 -2
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +30 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +41 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +25 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +55 -0
- {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
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +4 -4
- {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
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +20 -19
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +3 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +26 -19
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +159 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +112 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +91 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/__init__.py +5 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/__main__.py +4 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/cli.py +89 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/persist.py +274 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/tests/test_cli.py +26 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/evidence/tests/test_persist.py +45 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/scaffold.py +13 -2
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/config/env.py +5 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +2 -0
- tuner_testkit-4.3.0/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/config.py +3 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/__main__.py +1 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/driver.py +2 -1
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0/tuner_testkit.egg-info}/PKG-INFO +4 -4
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/SOURCES.txt +9 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/entry_points.txt +1 -0
- tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +0 -102
- tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -53
- tuner_testkit-4.1.0/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -159
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/LICENSE +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/setup.cfg +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/api.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/db.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/generators.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/ids.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/_internal/wait.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/base.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/context.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/action_words/registry.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/app.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/errors.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/router.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/spec.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_mock/store.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/auth.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/capture.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/codegen.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/freeze.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/mocks.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/normalize.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/client.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/errors.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/api_test/jsonpath.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/changelog.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane_app.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/plane_asset.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/tests/test_plane_asset.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/_shared/tests/test_plane_collect.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/addon.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/build.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
- {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
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
- {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
- {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
- {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
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
- {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
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/paths.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/source.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dna/tests/test_cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/dump_ddl.py +0 -0
- {tuner_testkit-4.1.0/tuner_testkit/apps/page_recorder → tuner_testkit-4.3.0/tuner_testkit/apps/evidence}/tests/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_ai/registry.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/build.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/catalog.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/index_platform/tests/test_catalog.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/manifest.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/plane.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/mock_server/seed.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/capture.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/inject.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/session.py +0 -0
- {tuner_testkit-4.1.0/tuner_testkit/apps/recorder → tuner_testkit-4.3.0/tuner_testkit/apps/page_recorder}/tests/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/client.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/db/connection.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/excel/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/excel/workbook.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/__main__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/catalog.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/china.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/cli.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/core.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/medical.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/fake/wrappers.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/context.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/core.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/helpers.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/hooks.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/logging/scenario_file.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/__init__.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/base.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/errors.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/harvest.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/health.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/locator.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/model.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/registry.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/session.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/steps.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/page_test/testing.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit/project.py +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/dependency_links.txt +0 -0
- {tuner_testkit-4.1.0 → tuner_testkit-4.3.0}/tuner_testkit.egg-info/requires.txt +0 -0
- {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.
|
|
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.
|
|
141
|
+
uv add "tuner-testkit[db,api]==4.3.0"
|
|
142
142
|
|
|
143
143
|
# 或只抬下限,让解析器选允许范围内的最新
|
|
144
|
-
# uv add "tuner-testkit[db,api]>=4.
|
|
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.
|
|
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.
|
|
96
|
+
uv add "tuner-testkit[db,api]==4.3.0"
|
|
97
97
|
|
|
98
98
|
# 或只抬下限,让解析器选允许范围内的最新
|
|
99
|
-
# uv add "tuner-testkit[db,api]>=4.
|
|
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.
|
|
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.
|
|
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"]
|
|
@@ -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
|
|
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
|
|
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
|
|
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.
|
|
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
|
-
|
|
17
|
-
`domain-notes
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
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.
|
|
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 `
|
|
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.
|
|
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
|
|
tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md
ADDED
|
@@ -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.
|
tuner_testkit-4.3.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md
ADDED
|
@@ -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.
|