qaas-python 0.2.2__tar.gz → 0.2.3__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.
- {qaas_python-0.2.2 → qaas_python-0.2.3}/PKG-INFO +1 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/pyproject.toml +1 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/cli.py +16 -23
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/conductor.py +12 -7
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/config.py +4 -2
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/arbiter.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/cartographer.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/clerk.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/conduit.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/forge.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/mender.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/proof.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/surface.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/vault.yaml +0 -1
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/agents/warden.yaml +0 -4
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/defaults/config/system.yaml +5 -14
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_conductor.py +16 -6
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_config.py +19 -14
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_paths.py +3 -3
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_trace.py +19 -5
- {qaas_python-0.2.2 → qaas_python-0.2.3}/.gitignore +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/ARCHITECTURE.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/BUILD_PLAN.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/CLAUDE.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/LICENSE +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/README.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/config/targets/corvid.yaml +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/adapters/__init__.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/adapters/tracker.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/adapters/vcs.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/discover.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/envelope.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/guardrails.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/__init__.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/context.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/contract_diff.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/defect_memory.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/env_control.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/envelope_server.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/test_runner.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/tracker.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/mcp/vcs.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/paths.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/.claude-plugin/plugin.json +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/a11y-audit/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/adversarial-review/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/api-surface-extraction/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/authz-matrix-check/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/console-error-triage/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/contract-test-generation/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/dedupe-strategy/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/environment-pinning/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/error-taxonomy/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/exploratory-ui-walk/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/failing-test-authoring/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/flake-detection/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/form-state-probe/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/minimal-diff-discipline/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/openapi-diff/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/ownership-resolution/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/product-task-graph/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/regression-risk-scoring/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/regression-suite-selection/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/repo-cartography/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/repro-minimisation/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/rollback-plan-authoring/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/root-cause-vs-symptom/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/routing-rules/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/severity-rubric/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/test-first-fix/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/test-quality-audit/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/ticket-writer/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/verdict-reporting/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/verification-protocol/SKILL.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/ARBITER.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/CARTOGRAPHER.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/CLERK.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/CONDUIT.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/FORGE.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/MENDER.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/PROOF.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/SURFACE.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/VAULT.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/WARDEN.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/prompts/_shared.md +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/registry.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/runner.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/scorecard.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/sdk_compat.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/store.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/target.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/tasks.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/trace.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/CODEOWNERS +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/Dockerfile +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/__init__.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/auth.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/config.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/db.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/errors.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/main.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/models.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/routes/__init__.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/routes/auth.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/routes/invoices.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/routes/orders.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/routes/stream.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/app/schemas.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/migrations/001_init.sql +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/pyproject.toml +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/api/seed/fixtures.sql +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/defects.yaml +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/docker-compose.yml +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/openapi.yaml +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/.gitignore +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/Dockerfile +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/index.html +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/package-lock.json +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/package.json +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/api.ts +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/components/Button.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/components/Layout.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/components/SearchInput.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/main.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/routes/CheckoutReview.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/routes/Login.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/routes/NewOrder.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/routes/OrderDetail.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/routes/OrdersList.tsx +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/src/styles.css +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/tsconfig.json +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/target-app/web/vite.config.ts +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/adapters/test_github_vcs.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/adapters/test_jira_tracker.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/conftest.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/conftest.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_contract_diff.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_defect_memory.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_env_control.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_test_runner.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_tracker.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/mcp/test_vcs.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/support.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/target_app/test_seeded_defects.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_cli.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_discover.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_envelope.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_guardrails.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_hooks_and_skills.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_prompt_overrides.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_registry.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_scorecard.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_skills_actually_load.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_store.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_target_profile_is_honoured.py +0 -0
- {qaas_python-0.2.2 → qaas_python-0.2.3}/tests/test_user_mcp_servers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: qaas-python
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: A multi-agent QA system: finds real defects, reproduces them, files tickets, fixes them, and proves the fix
|
|
5
5
|
Project-URL: Homepage, https://github.com/allaabdella2-us/qa-multi-agent-system
|
|
6
6
|
Project-URL: Repository, https://github.com/allaabdella2-us/qa-multi-agent-system
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# Distribution name is `qaas-python` (`qaas` was taken); the import package and
|
|
3
3
|
# the CLI are both `qaas`.
|
|
4
4
|
name = "qaas-python"
|
|
5
|
-
version = "0.2.
|
|
5
|
+
version = "0.2.3"
|
|
6
6
|
description = "A multi-agent QA system: finds real defects, reproduces them, files tickets, fixes them, and proves the fix"
|
|
7
7
|
readme = "README.md"
|
|
8
8
|
license = "MIT"
|
|
@@ -500,14 +500,18 @@ def validate(config_dir: Path | None = ConfigDir) -> None:
|
|
|
500
500
|
# never dispatched. The mode meant for every pull request could not file a
|
|
501
501
|
# ticket. It took a live run to notice; this check makes it free.
|
|
502
502
|
for mode_name, mode in sorted(cfg.run_modes.items()):
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
503
|
+
# Only meaningful when both sides declare a cap. The shipped config
|
|
504
|
+
# declares none, so this check simply does not fire there.
|
|
505
|
+
agent_caps = [
|
|
506
|
+
cfg.agents[a].max_budget_usd for a in mode.agents
|
|
507
|
+
if a in cfg.agents and cfg.agents[a].max_budget_usd is not None
|
|
508
|
+
]
|
|
509
|
+
needed = sum(agent_caps)
|
|
510
|
+
if mode.max_budget_usd is not None and agent_caps and needed > mode.max_budget_usd:
|
|
507
511
|
missing = [a for a in mode.agents if a in cfg.agents][-1]
|
|
508
512
|
problems.append(
|
|
509
|
-
f"mode '{mode_name}': agents
|
|
510
|
-
f"
|
|
513
|
+
f"mode '{mode_name}': the agents' caps exceed the mode's cap, so "
|
|
514
|
+
f"its cap, so the run stops before it reaches "
|
|
511
515
|
f"{missing} and files nothing. Raise max_budget_usd or drop an agent"
|
|
512
516
|
)
|
|
513
517
|
|
|
@@ -567,7 +571,7 @@ def validate(config_dir: Path | None = ConfigDir) -> None:
|
|
|
567
571
|
filing = "" if rm.files_tickets else " [dim](no filing)[/dim]"
|
|
568
572
|
console.print(
|
|
569
573
|
f"[bold]{mode}[/bold]: {', '.join(rm.agents)} "
|
|
570
|
-
f"[dim]
|
|
574
|
+
f"[dim]{rm.max_wall_clock_s}s[/dim]{filing}"
|
|
571
575
|
)
|
|
572
576
|
|
|
573
577
|
if notes:
|
|
@@ -834,7 +838,7 @@ def runs(root: Path = Root, limit: int = 10) -> None:
|
|
|
834
838
|
console.print("[dim]no runs yet[/dim]")
|
|
835
839
|
return
|
|
836
840
|
table = Table(header_style="bold")
|
|
837
|
-
for col in ("run", "envelopes", "agents"
|
|
841
|
+
for col in ("run", "envelopes", "agents"):
|
|
838
842
|
table.add_column(col)
|
|
839
843
|
for run_id in ids:
|
|
840
844
|
store = RunStore(run_id, root)
|
|
@@ -843,7 +847,6 @@ def runs(root: Path = Root, limit: int = 10) -> None:
|
|
|
843
847
|
run_id,
|
|
844
848
|
str(len(store.envelopes())),
|
|
845
849
|
str(len(results)),
|
|
846
|
-
f"${store.total_cost_usd():.2f}",
|
|
847
850
|
)
|
|
848
851
|
console.print(table)
|
|
849
852
|
|
|
@@ -872,9 +875,6 @@ def show(run_id: str, root: Path = Root) -> None:
|
|
|
872
875
|
header.append(f"started {summary.started:%Y-%m-%d %H:%M:%S}Z")
|
|
873
876
|
if summary.duration_s is not None:
|
|
874
877
|
header.append(f"duration {summary.duration_s:.0f}s")
|
|
875
|
-
header.append(f"cost ${summary.cost_usd:.2f}")
|
|
876
|
-
if summary.budget_usd:
|
|
877
|
-
header.append(f"of ${summary.budget_usd:.2f} budget")
|
|
878
878
|
console.print(" " + " ".join(header))
|
|
879
879
|
if summary.target_sha:
|
|
880
880
|
dirty = " [yellow](dirty tree)[/yellow]" if summary.target_dirty else ""
|
|
@@ -960,7 +960,6 @@ def trace(
|
|
|
960
960
|
table.add_column("agent", style="cyan")
|
|
961
961
|
table.add_column("kind")
|
|
962
962
|
table.add_column("detail", overflow="fold")
|
|
963
|
-
table.add_column("cost", justify="right", style="dim")
|
|
964
963
|
for row in trace_mod.timeline(entries):
|
|
965
964
|
label = f"{row.kind} ×{row.count}" if row.count > 1 else row.kind
|
|
966
965
|
table.add_row(
|
|
@@ -968,7 +967,6 @@ def trace(
|
|
|
968
967
|
row.agent,
|
|
969
968
|
f"[{KIND_STYLE.get(row.kind, 'white')}]{label}[/]",
|
|
970
969
|
row.detail,
|
|
971
|
-
f"${row.cost_usd:.2f}" if row.cost_usd is not None else "",
|
|
972
970
|
)
|
|
973
971
|
console.print(table)
|
|
974
972
|
console.print(f"\n[dim]{len(entries)} entries[/dim]")
|
|
@@ -1082,7 +1080,7 @@ def run(
|
|
|
1082
1080
|
rm = cfg.run_modes[mode]
|
|
1083
1081
|
console.print(
|
|
1084
1082
|
f"[bold]{mode}[/bold] — {len(specs)} agents, "
|
|
1085
|
-
f"
|
|
1083
|
+
f"concurrency {rm.max_concurrency}"
|
|
1086
1084
|
)
|
|
1087
1085
|
|
|
1088
1086
|
if dry_run:
|
|
@@ -1093,7 +1091,7 @@ def run(
|
|
|
1093
1091
|
d = describe(spec, prompt_dirs)
|
|
1094
1092
|
console.print(
|
|
1095
1093
|
f" [bold]{spec.name:14s}[/bold] {spec.model:18s} effort={spec.effort:7s} "
|
|
1096
|
-
f"turns<={spec.max_turns
|
|
1094
|
+
f"turns<={spec.max_turns}"
|
|
1097
1095
|
)
|
|
1098
1096
|
console.print(f" tools: {', '.join(d['allowed_tools'])}")
|
|
1099
1097
|
console.print(f" prompt: {d['prompt_chars']} chars")
|
|
@@ -1101,11 +1099,11 @@ def run(
|
|
|
1101
1099
|
|
|
1102
1100
|
def on_event(kind: str, detail: dict) -> None:
|
|
1103
1101
|
if kind == "agent_started":
|
|
1104
|
-
console.print(f"[dim]->[/dim] {detail.get('agent')}
|
|
1102
|
+
console.print(f"[dim]->[/dim] {detail.get('agent')}")
|
|
1105
1103
|
elif kind == "finished":
|
|
1106
1104
|
console.print(
|
|
1107
1105
|
f"[dim]<-[/dim] {detail.get('agent')} "
|
|
1108
|
-
f"[dim]
|
|
1106
|
+
f"[dim]{detail.get('envelopes', 0)} findings[/dim]"
|
|
1109
1107
|
)
|
|
1110
1108
|
elif kind == "stopped":
|
|
1111
1109
|
console.print(f"[yellow]stopped: {detail.get('reason')}[/yellow]")
|
|
@@ -1172,11 +1170,6 @@ def score(
|
|
|
1172
1170
|
table.add_row("false positives", f"{s['false_positives']} ({s['false_positive_rate']:.0%})")
|
|
1173
1171
|
table.add_row("duplicates", f"{s['duplicates']} ({s['duplicate_rate']:.0%})")
|
|
1174
1172
|
table.add_row("severity agreement", f"{s['severity_agreement']:.0%}")
|
|
1175
|
-
table.add_row("cost", f"${s['cost_usd']:.2f}")
|
|
1176
|
-
table.add_row(
|
|
1177
|
-
"cost per accepted",
|
|
1178
|
-
f"${s['cost_per_accepted']:.2f}" if s["cost_per_accepted"] is not None else "-",
|
|
1179
|
-
)
|
|
1180
1173
|
console.print(table)
|
|
1181
1174
|
|
|
1182
1175
|
if card.matches:
|
|
@@ -110,7 +110,7 @@ class RunReport:
|
|
|
110
110
|
class Budget:
|
|
111
111
|
"""The spend and wall-clock governor. Checked before every dispatch."""
|
|
112
112
|
|
|
113
|
-
def __init__(self, max_usd: float, max_seconds: int, *, already_spent: float = 0.0):
|
|
113
|
+
def __init__(self, max_usd: float | None, max_seconds: int, *, already_spent: float = 0.0):
|
|
114
114
|
self.max_usd = max_usd
|
|
115
115
|
self.max_seconds = max_seconds
|
|
116
116
|
#: What this run has already cost, including earlier invocations.
|
|
@@ -130,23 +130,28 @@ class Budget:
|
|
|
130
130
|
return time.monotonic() - self.started
|
|
131
131
|
|
|
132
132
|
@property
|
|
133
|
-
def remaining_usd(self) -> float:
|
|
134
|
-
return max(0.0, self.max_usd - self.spent)
|
|
133
|
+
def remaining_usd(self) -> float | None:
|
|
134
|
+
return None if self.max_usd is None else max(0.0, self.max_usd - self.spent)
|
|
135
135
|
|
|
136
136
|
def spend(self, amount: float) -> None:
|
|
137
137
|
self.spent += amount
|
|
138
138
|
|
|
139
139
|
def check(self) -> None:
|
|
140
|
-
|
|
140
|
+
# `max_usd is None` means no spend ceiling -- the shipped config sets
|
|
141
|
+
# none, because a dollar figure bakes one vendor's pricing into a tool
|
|
142
|
+
# meant to run against local models too. The wall-clock cap and each
|
|
143
|
+
# agent's `max_turns` still bound a run; those are model-agnostic.
|
|
144
|
+
if self.max_usd is not None and self.spent >= self.max_usd:
|
|
141
145
|
raise BudgetExceeded(f"spend cap reached: ${self.spent:.2f} of ${self.max_usd:.2f}")
|
|
142
146
|
if self.elapsed >= self.max_seconds:
|
|
143
147
|
raise BudgetExceeded(
|
|
144
148
|
f"wall-clock cap reached: {self.elapsed:.0f}s of {self.max_seconds}s"
|
|
145
149
|
)
|
|
146
150
|
|
|
147
|
-
def allowance(self, spec: AgentSpec) -> float:
|
|
148
|
-
"""What this agent may spend
|
|
149
|
-
|
|
151
|
+
def allowance(self, spec: AgentSpec) -> float | None:
|
|
152
|
+
"""What this agent may spend, or None when neither it nor the run caps it."""
|
|
153
|
+
caps = [c for c in (spec.max_budget_usd, self.remaining_usd) if c is not None]
|
|
154
|
+
return max(0.01, min(caps)) if caps else None
|
|
150
155
|
|
|
151
156
|
|
|
152
157
|
class Conductor:
|
|
@@ -74,7 +74,8 @@ class AgentSpec(BaseModel):
|
|
|
74
74
|
model: str = "claude-opus-5"
|
|
75
75
|
effort: Literal["low", "medium", "high", "xhigh", "max"] = "high"
|
|
76
76
|
max_turns: int = 40
|
|
77
|
-
max_budget_usd: float =
|
|
77
|
+
max_budget_usd: float | None = None
|
|
78
|
+
|
|
78
79
|
|
|
79
80
|
mcp_servers: list[str] = Field(default_factory=list)
|
|
80
81
|
builtin_tools: list[str] = Field(default_factory=list)
|
|
@@ -165,7 +166,8 @@ class RunMode(BaseModel):
|
|
|
165
166
|
|
|
166
167
|
trigger: str
|
|
167
168
|
agents: list[str]
|
|
168
|
-
max_budget_usd: float =
|
|
169
|
+
max_budget_usd: float | None = None
|
|
170
|
+
|
|
169
171
|
max_wall_clock_s: int = 3600
|
|
170
172
|
max_concurrency: int = 3
|
|
171
173
|
files_tickets: bool = True
|
|
@@ -9,7 +9,6 @@ prompt: ARBITER.md
|
|
|
9
9
|
model: claude-opus-5
|
|
10
10
|
effort: high
|
|
11
11
|
max_turns: 50
|
|
12
|
-
max_budget_usd: 3.0
|
|
13
12
|
mcp_servers: [envelope, vcs, contract_diff, test_runner]
|
|
14
13
|
builtin_tools: [Read, Grep, Glob]
|
|
15
14
|
skills: [adversarial-review, root-cause-vs-symptom, regression-risk-scoring, test-quality-audit]
|
|
@@ -10,7 +10,6 @@ prompt: MENDER.md
|
|
|
10
10
|
model: claude-opus-5
|
|
11
11
|
effort: high
|
|
12
12
|
max_turns: 80
|
|
13
|
-
max_budget_usd: 5.0
|
|
14
13
|
mcp_servers: [envelope, test_runner, env_control, vcs, tracker, contract_diff]
|
|
15
14
|
builtin_tools: [Read, Grep, Glob, Write, Edit, Bash]
|
|
16
15
|
skills: [test-first-fix, minimal-diff-discipline, root-cause-vs-symptom, rollback-plan-authoring]
|
|
@@ -9,10 +9,6 @@ prompt: WARDEN.md
|
|
|
9
9
|
model: claude-opus-5
|
|
10
10
|
effort: high
|
|
11
11
|
max_turns: 60
|
|
12
|
-
# Measured: WARDEN exhausted $3.00 on its first real run against the demo app
|
|
13
|
-
# and was killed mid-audit. Building the endpoint-by-role matrix and actually
|
|
14
|
-
# impersonating each role costs more than reading a spec does.
|
|
15
|
-
max_budget_usd: 5.0
|
|
16
12
|
mcp_servers: [envelope, env_control, defect_memory]
|
|
17
13
|
builtin_tools: [Read, Grep, Glob]
|
|
18
14
|
policy: {}
|
|
@@ -9,6 +9,11 @@ target:
|
|
|
9
9
|
tracker: local # local | jira -- swap to file against real Jira
|
|
10
10
|
vcs: local # local | github
|
|
11
11
|
|
|
12
|
+
# No spend cap by default. A dollar figure bakes one vendor's pricing into
|
|
13
|
+
# the config, and this is meant to run against local models too. `max_turns`
|
|
14
|
+
# is the model-agnostic bound. Set `max_budget_usd` here if you want a
|
|
15
|
+
# ceiling; the governor enforces one whenever it is present.
|
|
16
|
+
|
|
12
17
|
thresholds:
|
|
13
18
|
min_confidence_to_file: 0.6 # §7 confidence gate
|
|
14
19
|
max_findings_per_agent_run: 25 # §8.3 loop breaker: pause and escalate, don't file
|
|
@@ -21,30 +26,18 @@ run_modes:
|
|
|
21
26
|
pr-check:
|
|
22
27
|
trigger: pull_request
|
|
23
28
|
agents: [CARTOGRAPHER, CONDUIT, SURFACE, FORGE, CLERK]
|
|
24
|
-
# Was 6.0, which this roster could not complete. Measured on a real run:
|
|
25
|
-
# CARTOGRAPHER $0.69 + CONDUIT $2.25 + SURFACE $3.16 = $6.09, so the governor
|
|
26
|
-
# stopped the run before FORGE or CLERK ever dispatched. The mode meant to
|
|
27
|
-
# run on every pull request could not file a ticket, and it failed silently:
|
|
28
|
-
# agents ran, findings landed in the ledger, nothing errored. `qaas validate`
|
|
29
|
-
# now refuses a mode whose agents cannot fit inside its cap.
|
|
30
|
-
max_budget_usd: 16.0
|
|
31
29
|
max_wall_clock_s: 900
|
|
32
30
|
max_concurrency: 2
|
|
33
31
|
|
|
34
32
|
nightly:
|
|
35
33
|
trigger: cron
|
|
36
34
|
agents: [CARTOGRAPHER, CONDUIT, SURFACE, VAULT, WARDEN, FORGE, CLERK]
|
|
37
|
-
# FORGE runs once per finding, so the deep sweep's budget scales with how
|
|
38
|
-
# much discovery found, not with the number of agents. Measured: discovery
|
|
39
|
-
# ~$6, then roughly $1-2 per finding reproduced.
|
|
40
|
-
max_budget_usd: 50.0
|
|
41
35
|
max_wall_clock_s: 7200
|
|
42
36
|
max_concurrency: 3
|
|
43
37
|
|
|
44
38
|
incident:
|
|
45
39
|
trigger: alert
|
|
46
40
|
agents: [CONDUIT]
|
|
47
|
-
max_budget_usd: 4.0
|
|
48
41
|
max_wall_clock_s: 600
|
|
49
42
|
max_concurrency: 2
|
|
50
43
|
files_tickets: false # §9: diagnostic only, read-only, no filing
|
|
@@ -55,7 +48,6 @@ run_modes:
|
|
|
55
48
|
fix-cycle:
|
|
56
49
|
trigger: agent_ready_ticket
|
|
57
50
|
agents: [PROOF, MENDER, ARBITER]
|
|
58
|
-
max_budget_usd: 20.0
|
|
59
51
|
max_wall_clock_s: 3600
|
|
60
52
|
max_concurrency: 1
|
|
61
53
|
|
|
@@ -64,6 +56,5 @@ run_modes:
|
|
|
64
56
|
full-loop:
|
|
65
57
|
trigger: on_demand
|
|
66
58
|
agents: [CARTOGRAPHER, CONDUIT, SURFACE, VAULT, WARDEN, FORGE, CLERK, MENDER, ARBITER, PROOF]
|
|
67
|
-
max_budget_usd: 70.0
|
|
68
59
|
max_wall_clock_s: 10800
|
|
69
60
|
max_concurrency: 3
|
|
@@ -168,10 +168,18 @@ async def test_each_forge_invocation_gets_its_own_finding(cfg, tmp_path, fake_ag
|
|
|
168
168
|
|
|
169
169
|
|
|
170
170
|
async def test_a_spend_blowout_stops_the_run_and_escalates(cfg, tmp_path, fake_agents):
|
|
171
|
+
"""The governor still works; it just no longer ships with a dollar figure.
|
|
172
|
+
|
|
173
|
+
Shipped config sets no `max_budget_usd` -- a price belongs to one vendor and
|
|
174
|
+
this runs against local models too -- so a test about spend has to declare
|
|
175
|
+
the cap it is testing.
|
|
176
|
+
"""
|
|
171
177
|
calls, behaviour = fake_agents
|
|
172
178
|
behaviour["CARTOGRAPHER"] = {"publish_map": True, "cost": 99.0}
|
|
173
179
|
|
|
174
|
-
|
|
180
|
+
mode = cfg.run_modes["pr-check"].model_copy(update={"max_budget_usd": 10.0})
|
|
181
|
+
capped = cfg.model_copy(update={"run_modes": {**cfg.run_modes, "pr-check": mode}})
|
|
182
|
+
report = await make_conductor(capped, tmp_path).run("pr-check")
|
|
175
183
|
assert report.stopped_early and "spend cap" in report.stopped_early
|
|
176
184
|
assert "CLERK" not in [n for n, _ in calls]
|
|
177
185
|
assert report.escalations
|
|
@@ -533,13 +541,15 @@ async def test_a_resumed_run_keeps_the_budget_it_already_spent(cfg, tmp_path, fa
|
|
|
533
541
|
store = RunStore.new(tmp_path)
|
|
534
542
|
|
|
535
543
|
# A first invocation that has already consumed most of the mode's cap.
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
assert store.total_cost_usd() == pytest.approx(
|
|
544
|
+
capped_mode = cfg.run_modes["pr-check"].model_copy(update={"max_budget_usd": 5.0})
|
|
545
|
+
capped = cfg.model_copy(update={"run_modes": {**cfg.run_modes, "pr-check": capped_mode}})
|
|
546
|
+
store.put_result(AgentResult(agent="CONDUIT", subtype="success", cost_usd=4.95, num_turns=1))
|
|
547
|
+
assert store.total_cost_usd() == pytest.approx(4.95)
|
|
540
548
|
|
|
541
549
|
behaviour["CARTOGRAPHER"] = {"cost": 1.0, "publish_map": True}
|
|
542
|
-
|
|
550
|
+
# The shipped config sets no cap, so this test supplies one -- the governor
|
|
551
|
+
# is still there, it just no longer bakes a dollar figure into defaults.
|
|
552
|
+
report = await make_conductor(capped, tmp_path).run("pr-check", run_id=store.run_id)
|
|
543
553
|
|
|
544
554
|
assert report.stopped_early, "the resumed run ignored what the run had already spent"
|
|
545
555
|
assert "spend cap" in report.stopped_early
|
|
@@ -121,12 +121,21 @@ def test_incident_mode_files_nothing(cfg):
|
|
|
121
121
|
assert "CLERK" not in incident.agents
|
|
122
122
|
|
|
123
123
|
|
|
124
|
-
def
|
|
124
|
+
def test_every_run_mode_is_bounded(cfg):
|
|
125
|
+
"""Every mode must have SOME bound. It used to be a dollar cap; the shipped
|
|
126
|
+
config sets none now, because a price belongs to one vendor and this is
|
|
127
|
+
meant to run against local models too. The wall clock is the bound that
|
|
128
|
+
survives that, and `max_turns` bounds each agent."""
|
|
125
129
|
for name, mode in cfg.run_modes.items():
|
|
126
|
-
assert mode.
|
|
127
|
-
assert mode.
|
|
130
|
+
assert mode.max_wall_clock_s > 0, f"{name} has no wall-clock bound"
|
|
131
|
+
assert mode.max_concurrency > 0, f"{name} has no concurrency bound"
|
|
128
132
|
|
|
129
133
|
|
|
134
|
+
def test_no_vendor_pricing_is_baked_into_the_shipped_config(cfg):
|
|
135
|
+
"""A dollar figure in the defaults is a bet on one provider's price list."""
|
|
136
|
+
assert all(s.max_budget_usd is None for s in cfg.agents.values())
|
|
137
|
+
assert all(m.max_budget_usd is None for m in cfg.run_modes.values())
|
|
138
|
+
|
|
130
139
|
def test_enabled_agents_resolves_a_mode(cfg):
|
|
131
140
|
names = [s.name for s in cfg.enabled_agents("pr-check")]
|
|
132
141
|
assert names == ["CARTOGRAPHER", "CONDUIT", "SURFACE", "FORGE", "CLERK"]
|
|
@@ -209,16 +218,12 @@ def test_a_nonsense_override_is_rejected_loudly(monkeypatch):
|
|
|
209
218
|
load_config(search=CONFIG_SEARCH)
|
|
210
219
|
|
|
211
220
|
|
|
212
|
-
def
|
|
213
|
-
"""
|
|
214
|
-
|
|
215
|
-
discovery alone spent $6.09, so FORGE and CLERK never dispatched and the
|
|
216
|
-
mode meant for every pull request could not file a ticket. Nothing errored,
|
|
217
|
-
which is what made it survive."""
|
|
221
|
+
def test_a_mode_that_cannot_afford_its_agents_is_rejected():
|
|
222
|
+
"""Still enforced -- but only when someone actually sets caps, since the
|
|
223
|
+
shipped config sets none."""
|
|
218
224
|
cfg = load_config(search=CONFIG_SEARCH)
|
|
219
225
|
for name, mode in cfg.run_modes.items():
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
)
|
|
226
|
+
caps = [cfg.agents[a].max_budget_usd for a in mode.agents
|
|
227
|
+
if a in cfg.agents and cfg.agents[a].max_budget_usd is not None]
|
|
228
|
+
if caps and mode.max_budget_usd is not None:
|
|
229
|
+
assert sum(caps) <= mode.max_budget_usd, f"mode '{name}' cannot finish"
|
|
@@ -114,12 +114,12 @@ def test_one_agent_file_can_be_shadowed_without_forking_the_rest(tmp_path):
|
|
|
114
114
|
override = tmp_path / "config" / "agents"
|
|
115
115
|
override.mkdir(parents=True)
|
|
116
116
|
shipped = (PACKAGED_CONFIG / "agents" / "mender.yaml").read_text()
|
|
117
|
-
(override / "mender.yaml").write_text(shipped.replace("
|
|
117
|
+
(override / "mender.yaml").write_text(shipped.replace("max_turns: 80", "max_turns: 99"))
|
|
118
118
|
|
|
119
119
|
cfg = load_config(search=(tmp_path / "config", *CONFIG_SEARCH))
|
|
120
|
-
assert cfg.agents["MENDER"].
|
|
120
|
+
assert cfg.agents["MENDER"].max_turns == 99, "the override did not win"
|
|
121
121
|
assert len(cfg.agents) == len(PACKAGED_AGENTS), "shadowing one agent must not drop the others"
|
|
122
|
-
assert cfg.agents["CONDUIT"].
|
|
122
|
+
assert cfg.agents["CONDUIT"].max_turns == 60, "an untouched agent changed"
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
def test_system_yaml_is_taken_whole_from_the_first_layer(tmp_path):
|
|
@@ -115,10 +115,24 @@ def test_the_timeline_carries_the_facts_not_just_the_kinds(runner, run):
|
|
|
115
115
|
assert "CORVID-1" in output
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
def
|
|
118
|
+
def test_cost_is_recorded_in_the_ledger_but_never_printed(runner, run):
|
|
119
|
+
"""Cost is data, not display.
|
|
120
|
+
|
|
121
|
+
`qaas trace` used to carry a running-total column. The shipped config sets
|
|
122
|
+
no spend cap now -- a dollar figure is one vendor's price list, and this is
|
|
123
|
+
meant to run against local models too -- so printing money everywhere made
|
|
124
|
+
a Claude-specific assumption look like a property of the tool. The ledger
|
|
125
|
+
still records `cost_usd` on every `agent_finished`, so nothing is lost and
|
|
126
|
+
`--json` still carries it.
|
|
127
|
+
"""
|
|
119
128
|
output = _trace(runner, run)
|
|
120
|
-
assert "$
|
|
121
|
-
|
|
129
|
+
assert "$" not in output, "a dollar figure reached the terminal"
|
|
130
|
+
|
|
131
|
+
entries = trace_mod.read_ledger(run)
|
|
132
|
+
finished = [e for e in entries if e.kind == "agent_finished"]
|
|
133
|
+
assert finished and any("cost_usd" in e.detail for e in finished), (
|
|
134
|
+
"cost stopped being recorded; it should only have stopped being printed"
|
|
135
|
+
)
|
|
122
136
|
|
|
123
137
|
|
|
124
138
|
def test_consecutive_tool_calls_fold_into_one_row(run):
|
|
@@ -204,11 +218,11 @@ def test_json_output_survives_a_detail_longer_than_the_console(runner, tmp_path)
|
|
|
204
218
|
# -- qaas show --------------------------------------------------------------
|
|
205
219
|
|
|
206
220
|
|
|
207
|
-
def
|
|
221
|
+
def test_show_reports_mode_duration_and_escalations(runner, run):
|
|
208
222
|
result = runner.invoke(cli.app, ["show", run.run_id, "--root", str(run.root)])
|
|
209
223
|
assert result.exit_code == 0, result.output
|
|
210
224
|
assert "fix-cycle" in result.output
|
|
211
|
-
assert "$
|
|
225
|
+
assert "$" not in result.output, "no dollar figure should be printed"
|
|
212
226
|
assert "duration" in result.output
|
|
213
227
|
assert "escalations" in result.output and "CORVID-2 needs a human" in result.output
|
|
214
228
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/api-surface-extraction/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/console-error-triage/SKILL.md
RENAMED
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/contract-test-generation/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/failing-test-authoring/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/minimal-diff-discipline/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/ownership-resolution/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/regression-risk-scoring/SKILL.md
RENAMED
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/regression-suite-selection/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/rollback-plan-authoring/SKILL.md
RENAMED
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/root-cause-vs-symptom/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qaas_python-0.2.2 → qaas_python-0.2.3}/src/qaas/plugin/skills/verification-protocol/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|