tuner-testkit 4.2.0__tar.gz → 4.4.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.2.0/tuner_testkit.egg-info → tuner_testkit-4.4.0}/PKG-INFO +8 -4
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/README.md +7 -3
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/pyproject.toml +6 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/__init__.py +1 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_test/__init__.py +8 -2
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_test/model.py +27 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/build.py +12 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/cli.py +2 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/agents/bdd-asset-pipeline.md +3 -1
- tuner_testkit-4.4.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-self-learning.md +72 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/dna/dna_payload/.cursor/agents/sut-source-to-design.md +35 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/dna/dna_payload/.cursor/rules/agent-task-log.mdc +22 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/commit-convention.mdc +3 -2
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/index-hygiene.mdc +3 -2
- tuner_testkit-4.4.0/tuner_testkit/apps/dna/dna_payload/.cursor/skills/analyze-mcp-network/SKILL.md +30 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-design-knowledge/SKILL.md +5 -4
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/explore-sut/SKILL.md +18 -4
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/freeze-api-objects/SKILL.md +3 -2
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/run-feature-playwright-mcp/SKILL.md +2 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/AGENTS.md +8 -5
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/MANIFEST.txt +1 -1
- tuner_testkit-4.4.0/tuner_testkit/apps/dna/dna_payload/docs/spec/agent-task-log.md +70 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/api-objects-syntax.md +3 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/commit-convention.md +3 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/design-knowledge-syntax.md +15 -5
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/sut-self-learning.md +10 -4
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/validate_commit_msg.py +12 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/tests/test_cli.py +3 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/__init__.py +5 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/__main__.py +4 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/cli.py +89 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/persist.py +274 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/tests/test_cli.py +26 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/evidence/tests/test_persist.py +45 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/scaffold.py +16 -9
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/config/env.py +6 -1
- tuner_testkit-4.4.0/tuner_testkit/apps/init_repo/stubs/data/sut-accounts.example.yaml +18 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/tests/test_scaffold.py +7 -0
- tuner_testkit-4.4.0/tuner_testkit/apps/recorder/tests/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/config.py +3 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/driver.py +2 -1
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0/tuner_testkit.egg-info}/PKG-INFO +8 -4
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit.egg-info/SOURCES.txt +9 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit.egg-info/entry_points.txt +1 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/LICENSE +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/setup.cfg +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/api.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/db.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/generators.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/ids.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/_internal/wait.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/base.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/context.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/action_words/registry.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/app.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/errors.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/router.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/spec.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_mock/store.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/auth.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/capture.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/codegen.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/freeze.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/mocks.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/normalize.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/pipeline.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_objects/recording/sanitize.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_test/client.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_test/errors.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/api_test/jsonpath.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/changelog.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/plane_app.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/plane_asset.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/tests/test_plane_asset.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/_shared/tests/test_plane_collect.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/addon.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/playwright_tap.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/tests/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/api_recorder/tests/test_addon.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks/sync_registry.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/hooks.json +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-authoring.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/apps-handover.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/assets-knowledge.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-asset-layering.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-pipeline-gates.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/bdd-stage-layout.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/explore-safety.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-db.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-fake.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-logging.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/rules/packages-page-test.mdc +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-action-word/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/create-app/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/derive-feature-sets/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/dump-ddl/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-authoring/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/feature-review-lint/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-behave-steps/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-index/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/maintain-page-objects/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/release-template/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/.cursor/skills/reuse-analysis/SKILL.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/action-words-syntax.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/apps-authoring-syntax.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/assets-knowledge-syntax.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/bdd-run-gherkin-in-playwrightMCP.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-gerkin-syntax.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/behave-step-definitions.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/docs/spec/page-objects-syntax.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/README.md +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/commit-msg +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/dna_payload/tools/git-hooks/pre-push +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/paths.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dna/source.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/dump_ddl.py +0 -0
- {tuner_testkit-4.2.0/tuner_testkit/apps/page_recorder → tuner_testkit-4.4.0/tuner_testkit/apps/evidence}/tests/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_ai/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_ai/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_ai/registry.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/build.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/catalog.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/index_platform/tests/test_catalog.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/manifest.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/apps/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/behave.ini +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/_internal/params.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/action_words/models.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/auth.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/recording/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/api_objects/registry.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/init_repo/stubs/packages/page_objects/session.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/mock_server/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/mock_server/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/mock_server/cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/mock_server/plane.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/mock_server/seed.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/capture.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/codegen.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/freeze.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/inject.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/session.py +0 -0
- {tuner_testkit-4.2.0/tuner_testkit/apps/recorder → tuner_testkit-4.4.0/tuner_testkit/apps/page_recorder}/tests/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/tests/test_capture.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/tests/test_cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/page_recorder/tests/test_freeze.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/recorder/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/recorder/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/recorder/cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/apps/recorder/tests/test_cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/db/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/db/client.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/db/connection.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/excel/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/excel/workbook.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/catalog.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/china.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/cli.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/core.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/medical.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/fake/wrappers.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/context.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/core.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/helpers.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/hooks.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/logging/scenario_file.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/__init__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/__main__.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/base.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/errors.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/harvest.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/health.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/locator.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/model.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/registry.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/session.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/steps.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/page_test/testing.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit/project.py +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit.egg-info/dependency_links.txt +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.0}/tuner_testkit.egg-info/requires.txt +0 -0
- {tuner_testkit-4.2.0 → tuner_testkit-4.4.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.4.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,8 @@ uv sync --extra all
|
|
|
210
210
|
|
|
211
211
|
`uv sync --extra dev` 与 `--extra all` 等价(`dev` 只是引用 `[all]`)。
|
|
212
212
|
|
|
213
|
-
|
|
213
|
+
本仓是**平台仓**,不是 workspace。`dogfood/` 是用 `tuner-init scaffold dogfood --no-ai` 生成的 workspace 示范
|
|
214
|
+
(被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
|
|
215
|
+
验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
|
|
216
|
+
|
|
217
|
+
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,8 @@ uv sync --extra all
|
|
|
165
165
|
|
|
166
166
|
`uv sync --extra dev` 与 `--extra all` 等价(`dev` 只是引用 `[all]`)。
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
本仓是**平台仓**,不是 workspace。`dogfood/` 是用 `tuner-init scaffold dogfood --no-ai` 生成的 workspace 示范
|
|
169
|
+
(被测系统 = 平台本身,uv workspace 成员,共用 `.venv`):路线图在 `dogfood/assets/domain-notes/platform/roadmap.md`,
|
|
170
|
+
验收活文档在 `dogfood/tests/features/`。见 [`dogfood/README.md`](dogfood/README.md)。
|
|
171
|
+
|
|
172
|
+
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.4.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"]
|
|
@@ -89,6 +90,10 @@ include = ["tuner_testkit*"]
|
|
|
89
90
|
build_py = "tuner_testkit.apps.dna.build.BuildPyWithDna"
|
|
90
91
|
sdist = "tuner_testkit.apps.dna.build.SdistWithDna"
|
|
91
92
|
|
|
93
|
+
[tool.uv.workspace]
|
|
94
|
+
# dogfood/ is a workspace scaffolded by `tuner-init` from this repo (SUT = the platform itself).
|
|
95
|
+
members = ["dogfood"]
|
|
96
|
+
|
|
92
97
|
[tool.tuner-testkit]
|
|
93
98
|
page_objects = "packages/page_objects"
|
|
94
99
|
api_objects = "packages/api_objects"
|
|
@@ -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)
|
|
@@ -31,8 +31,19 @@ def _payload_ready(root: Path | None = None) -> bool:
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def _bundle() -> None:
|
|
34
|
+
"""Refresh ``dna_payload`` from the template tree when building a wheel.
|
|
35
|
+
|
|
36
|
+
A leftover ``dna_payload/`` from an older build must not short-circuit:
|
|
37
|
+
that shipped stale DNA (4.3.0 payload inside a 4.4.0 wheel).
|
|
38
|
+
"""
|
|
34
39
|
_ensure_src_on_path()
|
|
35
|
-
|
|
40
|
+
from tuner_testkit.project import template_source_root
|
|
41
|
+
|
|
42
|
+
if template_source_root() is None:
|
|
43
|
+
if not _payload_ready():
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
"no DNA payload in this install and no template checkout to bundle from"
|
|
46
|
+
)
|
|
36
47
|
return
|
|
37
48
|
|
|
38
49
|
from tuner_testkit.apps.dna.cli import cmd_bundle
|
|
@@ -47,6 +47,7 @@ def cmd_sync(args: argparse.Namespace) -> int:
|
|
|
47
47
|
continue
|
|
48
48
|
if dst.is_file() and not args.overwrite:
|
|
49
49
|
skipped += 1
|
|
50
|
+
print(f"skip {rel} (differs; pass --overwrite)")
|
|
50
51
|
continue
|
|
51
52
|
dst.parent.mkdir(parents=True, exist_ok=True)
|
|
52
53
|
shutil.copy2(src, dst)
|
|
@@ -82,7 +83,7 @@ def cmd_check(args: argparse.Namespace) -> int:
|
|
|
82
83
|
print(f" missing: {rel}", file=sys.stderr)
|
|
83
84
|
for rel in changed:
|
|
84
85
|
print(f" changed: {rel}", file=sys.stderr)
|
|
85
|
-
print("Run `tuner-dna sync` to refresh platform DNA.", file=sys.stderr)
|
|
86
|
+
print("Run `tuner-dna sync --overwrite` to refresh platform DNA.", file=sys.stderr)
|
|
86
87
|
return 1
|
|
87
88
|
|
|
88
89
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bdd-asset-pipeline
|
|
3
|
-
version: 2.0.
|
|
3
|
+
version: 2.0.1
|
|
4
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
5
|
---
|
|
6
6
|
|
|
@@ -104,3 +104,5 @@ Before writing Then-assertions, **read `assets/design/**`**:
|
|
|
104
104
|
- `behave --stage ui` succeeds for UI features that exist.
|
|
105
105
|
- `behave --stage api` succeeds for API features that exist (or `--dry-run`
|
|
106
106
|
with documented TODO).
|
|
107
|
+
- Task log written to `artifacts/inbox/` per `docs/spec/agent-task-log.md`
|
|
108
|
+
(no secrets).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sut-self-learning
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Orchestrate explore-first SUT self-learning — accounts → Playwright MCP explore → evidence → freeze API/page objects → design knowledge → index, with an artifacts/inbox task log. Hand off to bdd-asset-pipeline only when Feature Sets are in scope. Do NOT use when the user explicitly requests pytest-only work.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# SUT self-learning orchestrator (upper half + optional handoff)
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
串起「学习被测 Web 系统并生长测试资产」的**上半程**。规格
|
|
12
|
+
`docs/spec/sut-self-learning.md`。本文件是可执行编排;规格不是本 agent 的替代。
|
|
13
|
+
|
|
14
|
+
**下半程**(已有 feature set → steps / behave)交给
|
|
15
|
+
`.cursor/agents/bdd-asset-pipeline.md`,不要在本 agent 里硬造 Gherkin,除非用户明确要验收自动化。
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- 工程师说「探索 SUT / 学习某某模块 / 生成测试资产 / 再跑一轮自学习」。
|
|
20
|
+
- 下游仓已有 `tuner-init` 骨架,SUT 可访问。
|
|
21
|
+
|
|
22
|
+
## Inputs
|
|
23
|
+
|
|
24
|
+
1. `INDEX.md` + 若存在 `INDEX.project.md`(已有切片、勿重复冻登录接口)。
|
|
25
|
+
2. **账号**(只读,禁止拷进仓库/evidence/inbox):
|
|
26
|
+
1. `data/sut-accounts.local.yaml`(gitignore,首选)
|
|
27
|
+
2. 否则 `config/env_local.py` 的 `TEST_ACCOUNT`
|
|
28
|
+
3. 都没有则停,让工程师按 `data/sut-accounts.example.yaml` 补本机文件
|
|
29
|
+
3. 垂直切片(一个模块,不是全站爬)。
|
|
30
|
+
4. 可选:SUT 源码根(如 Plane `apps/api`)——有则跑 `sut-source-to-design`。
|
|
31
|
+
|
|
32
|
+
## Skills / agents(顺序)
|
|
33
|
+
|
|
34
|
+
| 步 | 组件 | 产出 |
|
|
35
|
+
| --- | --- | --- |
|
|
36
|
+
| 0 | 读账号 + `explore-safety` | 登录参数(内存) |
|
|
37
|
+
| 1 | `dump-ddl`(缺表才跑,禁 `--all`) | `assets/ddl/<ds>/` |
|
|
38
|
+
| 2 | `explore-sut` | `artifacts/evidence/<run_id>/` + `assets/explore/` |
|
|
39
|
+
| 3 | `analyze-mcp-network`(`tuner-evidence routes`) | 路由表 JSON |
|
|
40
|
+
| 4 | `reuse-analysis` | 复用 vs 新建 |
|
|
41
|
+
| 5 | `freeze-api-objects` | `packages/api_objects/`(跳过 sign-in) |
|
|
42
|
+
| 6 | `maintain-page-objects` | `packages/page_objects/` |
|
|
43
|
+
| 7 | `derive-design-knowledge`;有源码则 **`sut-source-to-design`** | `assets/design/` |
|
|
44
|
+
| 8 | `maintain-index` | `INDEX.project.md` 或 `INDEX.md` |
|
|
45
|
+
| 9 | **本 agent** 写 inbox | `artifacts/inbox/<utc>-sut-self-learning-<slice>.md` |
|
|
46
|
+
| 10 | 仅当用户要 `.feature` | `derive-feature-sets` → **`bdd-asset-pipeline`** |
|
|
47
|
+
|
|
48
|
+
每步先 **Read** 对应 `SKILL.md` / agent 正文再执行。不要跳过 evidence 落盘。
|
|
49
|
+
|
|
50
|
+
## Inbox(强制)
|
|
51
|
+
|
|
52
|
+
遵循 `docs/spec/agent-task-log.md`。SUT 自学习日志 **必须**含:
|
|
53
|
+
|
|
54
|
+
- `## Pages explored`(url pattern / title / 按钮)
|
|
55
|
+
- `## Assets added this run`(本任务新增或更新的 api/page/explore/design/ddl)
|
|
56
|
+
- `run_id`;`account_id`(无密码)
|
|
57
|
+
- 若这是第 N 轮 dogfood:`## Loop delta` 对比上一轮 inbox / 平台能力
|
|
58
|
+
|
|
59
|
+
## Hard rules
|
|
60
|
+
|
|
61
|
+
- 活体 SUT:`explore-safety`(throwaway 数据;不问不准删)。
|
|
62
|
+
- 密钥不入库、不进 evidence、不进 inbox。
|
|
63
|
+
- Web cookie session 的 path 占位用 `{workspace_slug}` 等,调用走 `set_path`。
|
|
64
|
+
- 页面资产 app 名对齐现有 `packages/page_objects/<app>/`,勿与装饰器模块重名。
|
|
65
|
+
- 未走 Gate 1 证据不得写 api/page/design。
|
|
66
|
+
|
|
67
|
+
## Done
|
|
68
|
+
|
|
69
|
+
- evidence 在磁盘且已脱敏。
|
|
70
|
+
- 切片的 explore +(若有写操作)design 已引用 `run_id`。
|
|
71
|
+
- 新路由已冻或书面说明跳过原因。
|
|
72
|
+
- inbox 已落盘,页面清单与资产增量齐全。
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sut-source-to-design
|
|
3
|
+
version: 1.0.1
|
|
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.
|
|
34
|
+
- Write `artifacts/inbox/<utc>-sut-source-to-design-<slice>.md` per
|
|
35
|
+
`docs/spec/agent-task-log.md` (outputs = design files; no secrets).
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Every agent run must leave a task log under artifacts/inbox/ (no secrets).
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent task log — `artifacts/inbox/`
|
|
8
|
+
|
|
9
|
+
每次按 `.cursor/agents/*.md` 编排执行(含 SUT 自学习),结束前必须写一份任务记录。
|
|
10
|
+
细则见 `docs/spec/agent-task-log.md`。
|
|
11
|
+
|
|
12
|
+
## Must
|
|
13
|
+
|
|
14
|
+
- 路径:`artifacts/inbox/<UTC>-<agent>-<slice>.md`(例 `20260914T031200Z-sut-self-learning-cycles.md`)。
|
|
15
|
+
- 必填:`agent`、意图、输入、产出文件列表、下一步。
|
|
16
|
+
- **SUT 自学习**额外必填:本次探索的页面(url pattern + 标题)、本次新增/更新的测试资产路径。
|
|
17
|
+
- 只写 `account_id` / workspace slug,**禁止**密码、token、Cookie。
|
|
18
|
+
|
|
19
|
+
## Must not
|
|
20
|
+
|
|
21
|
+
- 用聊天摘要代替 inbox 落盘。
|
|
22
|
+
- 把 inbox 当 evidence(网络 dump 仍走 `artifacts/evidence/<run_id>/`)。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Commits must follow Conventional Commits with a layer-aligned scope; the declared scope must cover the layers actually changed. Single source of truth is docs/spec/commit-convention.md.
|
|
3
3
|
alwaysApply: true
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# 提交规范(Conventional Commits + 六层 scope)
|
|
@@ -12,7 +12,8 @@ version: 1.0.0
|
|
|
12
12
|
- `type` ∈ `feat|fix|refactor|docs|test|perf|chore|build|ci|style|revert`。
|
|
13
13
|
- `scope` 用**对齐六层/资产类别**的值:`assets / apps / packages / api_objects /
|
|
14
14
|
page_objects / action_words / tests / docs / rules / skills / agents / hooks /
|
|
15
|
-
init_repo / index`(多层用逗号分隔,如 `feat(apps,packages):
|
|
15
|
+
init_repo / index / dogfood`(多层用逗号分隔,如 `feat(apps,packages): ...`;
|
|
16
|
+
`dogfood/**` 一律用 `dogfood`)。
|
|
16
17
|
- **scope 必须覆盖本次真实改动涉及的层**(`packages` 是三个子资产层的上位 scope)。
|
|
17
18
|
|
|
18
19
|
一眼可读优先:让人从提交信息就看出"更新了 assets、新增了 apps、录制了新的 api_objects"等。
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
---
|
|
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
|
-
globs: assets/**,packages/api_objects/**,packages/page_objects/**,apps/**,tuner_testkit/apps
|
|
3
|
+
globs: assets/**,packages/api_objects/**,packages/page_objects/**,apps/**,tuner_testkit/apps/**,dogfood/assets/**,dogfood/packages/**,dogfood/apps/**,dogfood/INDEX.project.md
|
|
4
4
|
alwaysApply: false
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 1.2.0
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# index-hygiene — 索引与留痕纪律
|
|
9
9
|
|
|
10
10
|
根 `INDEX.md` 是**平台**能力地图(发现入口)。若存在 `INDEX.project.md`,那是试验田 / 下游项目仓的**业务资产**地图;两份索引都必须与各自职责范围内的仓库状态一致。
|
|
11
|
+
平台仓内的 `dogfood/` 是用 scaffold 生成的 workspace,它的业务地图是 `dogfood/INDEX.project.md`。
|
|
11
12
|
|
|
12
13
|
## 留痕(changelog trail)
|
|
13
14
|
|
tuner_testkit-4.4.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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: derive-design-knowledge
|
|
3
|
-
version: 0.
|
|
3
|
+
version: 0.2.0
|
|
4
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
5
|
---
|
|
6
6
|
|
|
@@ -19,9 +19,10 @@ description: Compile assets/design/<app>/<route-slug>.md from open evidence chan
|
|
|
19
19
|
2. For each captured **non-static mutating** route (POST/PUT/PATCH/DELETE):
|
|
20
20
|
- Draft front-matter (`confidence`: `observed` only if DB/log proved it; else `inferred`).
|
|
21
21
|
- Fill `writes` / `noise` / `reads` from the **highest quality channel available**:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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`.
|
|
25
26
|
- Skip `operation_log` / `*_activities` / audit tables as `noise` unless the user says they are the assertion target.
|
|
26
27
|
3. Every `writes` row must cite evidence or a source path in `## notes`.
|
|
27
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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: explore-sut
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.2.0
|
|
4
4
|
description: Explore-first Playwright MCP session against a live SUT. Produces sanitized artifacts/evidence/<run_id>/ plus assets/explore capability notes. Use when learning a web SUT, mapping pages/buttons, or gathering evidence before any .feature exists. Do NOT use when the user already has a feature to implement — use run-feature-playwright-mcp instead.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -23,9 +23,23 @@ description: Explore-first Playwright MCP session against a live SUT. Produces s
|
|
|
23
23
|
## Steps
|
|
24
24
|
|
|
25
25
|
1. Read `INDEX.md` and `INDEX.project.md` if present. Note base URLs from `config`.
|
|
26
|
+
Load login from **`data/sut-accounts.local.yaml`** if it exists; else
|
|
27
|
+
`config/env_local.py` `TEST_ACCOUNT`. Copy `data/sut-accounts.example.yaml`
|
|
28
|
+
when neither exists and **stop**. Never write the password into evidence,
|
|
29
|
+
explore notes, inbox, or git.
|
|
26
30
|
2. Pick a **vertical slice** (e.g. workspace → project → issue), not a full-site crawl.
|
|
27
31
|
3. Navigate with Playwright MCP. After each meaningful action, dump network + snapshot.
|
|
28
|
-
4. Persist:
|
|
32
|
+
4. Persist with **`tuner-evidence persist`** (do not leave captures only in chat):
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
uv run python -m tuner_testkit.apps.evidence persist \
|
|
36
|
+
--run-id YYYYMMDDTHHMMSSZ-<slice> \
|
|
37
|
+
--scenario explore:<intent> \
|
|
38
|
+
--network captures.jsonl \
|
|
39
|
+
--intent "short vertical-slice intent"
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Manual fallback (same files):
|
|
29
43
|
- `artifacts/evidence/<run_id>/run_summary.md`
|
|
30
44
|
- `artifacts/evidence/<run_id>/network.jsonl` (sanitized)
|
|
31
45
|
- optional `actions.jsonl` / `snapshots/`
|
|
@@ -35,11 +49,11 @@ description: Explore-first Playwright MCP session against a live SUT. Produces s
|
|
|
35
49
|
- primary actions (button labels)
|
|
36
50
|
- APIs observed (method + path only)
|
|
37
51
|
- blockers / i18n / env notes
|
|
38
|
-
6. Stop.
|
|
52
|
+
6. Stop. Next: `tuner-evidence routes --run-id …` then freeze / derive-design / author feature.
|
|
39
53
|
|
|
40
54
|
## Output checklist
|
|
41
55
|
|
|
42
56
|
- `run_id` and evidence directory exist.
|
|
43
57
|
- Sanitizer applied statement in `run_summary.md`.
|
|
44
58
|
- Explore note cites `evidence`.
|
|
45
|
-
- Next-step
|
|
59
|
+
- Next-step: `tuner-evidence routes` then freeze / derive-design / author feature.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: freeze-api-objects
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.1.0
|
|
4
4
|
description: Freezes sanitized Playwright MCP network captures into route-aligned, deduped API Objects under packages/api_objects/ following api-objects-syntax.md and bdd-run-gherkin-in-playwrightMCP.md. Use when creating/updating APIModel assets.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -72,4 +72,5 @@ description: Freezes sanitized Playwright MCP network captures into route-aligne
|
|
|
72
72
|
- No forbidden header keys or raw tokens in file content.
|
|
73
73
|
- No host in APIModel path/url.
|
|
74
74
|
- No scenario-specific constants asserted in APIModel.
|
|
75
|
-
-
|
|
75
|
+
- Skip `POST /api/sign-in/` (and password-bearing login routes) unless explicitly required; never persist the password body.
|
|
76
|
+
- If the path contains a workspace/org **slug**, freeze `{workspace_slug}` (not the live slug) and document `set_path`..
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: run-feature-playwright-mcp
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.2.0
|
|
4
4
|
description: Runs behave Gherkin scenarios (or records an explore session) via Playwright MCP with Run→Capture→Freeze workflow and strict sanitization. Evidence always lands under artifacts/evidence/<run_id>/. Do NOT require this skill when the user explicitly requests pytest-only work with no MCP capture need.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -49,6 +49,7 @@ description: Runs behave Gherkin scenarios (or records an explore session) via P
|
|
|
49
49
|
- sanitizer applied statement
|
|
50
50
|
- **`artifacts/evidence/<run_id>/network.jsonl`** (required, sanitized):
|
|
51
51
|
- one capture per request (see spec minimum fields)
|
|
52
|
+
- Prefer writing it via `tuner-evidence persist --network captures.jsonl` so the sanitizer is deterministic.
|
|
52
53
|
- **`artifacts/evidence/<run_id>/actions.jsonl`** / `snapshots/` (optional)
|
|
53
54
|
|
|
54
55
|
## Verification checklist (must include in result)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- version: 1.
|
|
1
|
+
<!-- version: 1.5.0 -->
|
|
2
2
|
# AGENTS — 平台总入口(轻量 DM)
|
|
3
3
|
|
|
4
4
|
> 本文件是"repo as a platform"的**稳定世界观**:只写不常变的分层结构与角色。
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| 测试层 | `tests/` | 自动化测试代码(behave `features/` + `pytest/`)。 | behave / pytest |
|
|
22
22
|
| 文档层 | `docs/` | 仓库使用说明与规范(`docs/spec/**`)。 | 只读 |
|
|
23
23
|
|
|
24
|
-
配套:`config/`(环境/数据源)、`.cursor/`(AI 组件,见下)、`artifacts/`·`logs/`(运行产出;MCP evidence 落 `artifacts/evidence/<run_id
|
|
24
|
+
配套:`config/`(环境/数据源)、`.cursor/`(AI 组件,见下)、`artifacts/`·`logs/`(运行产出;MCP evidence 落 `artifacts/evidence/<run_id>/`;agent 任务记录落 `artifacts/inbox/`)。SUT 登录本机文件:`data/sut-accounts.local.yaml`(gitignore)。
|
|
25
25
|
|
|
26
26
|
## 2. 三角色
|
|
27
27
|
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
```mermaid
|
|
44
44
|
flowchart TD
|
|
45
45
|
Start[任务到达] --> Q{任务类型?}
|
|
46
|
-
Q -->|"学习被测系统 / 探索式测试"| Learn["SUT
|
|
46
|
+
Q -->|"学习被测系统 / 探索式测试"| Learn["SUT 自学习编排\n.cursor/agents/sut-self-learning.md"]
|
|
47
47
|
Q -->|"业务 UI/API 流自动化"| BDD["BDD 资产流水线(下半程)\n.cursor/agents/bdd-asset-pipeline.md"]
|
|
48
48
|
Q -->|"明确要求 pytest / 性能 / DB 核对"| Pytest["pytest 路径\n复用 tuner_testkit + packages,不产出 .feature"]
|
|
49
49
|
Q -->|"需要一个新的独立工具"| App["create-app skill\napps-authoring / apps-handover 规则"]
|
|
@@ -52,7 +52,7 @@ flowchart TD
|
|
|
52
52
|
Q -->|"读/策展/索引知识"| Idx["查 INDEX.md + maintain-index skill"]
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
- **学习被测系统** → `docs/spec/sut-self-learning.md
|
|
55
|
+
- **学习被测系统** → `.cursor/agents/sut-self-learning.md`(编排 explore → freeze → design;规格 `docs/spec/sut-self-learning.md`;任务 log 见 `docs/spec/agent-task-log.md`)。
|
|
56
56
|
- **业务 UI/API 流** → `.cursor/agents/bdd-asset-pipeline.md`(自学习的**下半程**;内部含三门禁,仅在此分支生效)。
|
|
57
57
|
- **明确 pytest** → 直接写 pytest,复用 `tuner_testkit` 与本仓 `packages/**` 业务资产,不要为满足分层而硬造 Gherkin。
|
|
58
58
|
- **造工具** → `create-app` skill;工具做好按 `apps-handover.mdc` 补交接文档。证据通道(日志/DB 日志取数)也落 `apps/`,遵守 CLI + JSON 输出约定。
|
|
@@ -65,11 +65,14 @@ flowchart TD
|
|
|
65
65
|
- 不得将 token / cookie / Authorization / 密码 / session 等敏感信息写入仓库(含 capture 与 api_objects)。
|
|
66
66
|
- 提交遵循 Conventional Commits + 六层 scope,见 `docs/spec/commit-convention.md`(`commit-msg` hook 会校验)。
|
|
67
67
|
- DB 只走 `tuner_testkit.db`,日志只走 `tuner_testkit.logging`(见对应 rule)。
|
|
68
|
-
- 密钥只放本机 `config/env_local.py` 或环境变量,**任何分支都不得提交**。多套 prd/uat/dev 写在 `env_local.ENVIRONMENTS` 里,用 `python -m tuner_testkit.config use <name>` 切换(或 `TUNER_ENV`)。
|
|
68
|
+
- 密钥只放本机 `config/env_local.py`、`data/**/*.local.yaml` 或环境变量,**任何分支都不得提交**。多套 prd/uat/dev 写在 `env_local.ENVIRONMENTS` 里,用 `python -m tuner_testkit.config use <name>` 切换(或 `TUNER_ENV`)。探索账号优先 `data/sut-accounts.local.yaml`(模板 `data/sut-accounts.example.yaml`)。
|
|
69
69
|
|
|
70
70
|
## 6. 分支与下游仓
|
|
71
71
|
|
|
72
72
|
本公开仓只维护**平台**:`tuner_testkit/`、`.cursor/**`、`docs/spec/**`、`INDEX.md`。
|
|
73
|
+
**本仓不是 workspace**:真正的个人 workspace 是 `tuner-init scaffold` 生成的下游仓。仓内 `dogfood/`
|
|
74
|
+
是用同一 scaffold 生成的 workspace 示范(被测系统 = 平台本身),存放路线图、验收剧本与活文档;
|
|
75
|
+
它是 uv workspace 成员,不带自己的 `.cursor/`(根 DNA 覆盖全树),提交 scope 用 `dogfood`。
|
|
73
76
|
|
|
74
77
|
| 分支 | 职责 | 谁改 |
|
|
75
78
|
| --- | --- | --- |
|