keble-task 2.22.0__tar.gz → 2.22.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. keble_task-2.22.1/AGENTS.md +32 -0
  2. keble_task-2.22.1/AiAgentChangesLogs.md +44 -0
  3. keble_task-2.22.1/CLAUDE.md +33 -0
  4. keble_task-2.22.1/PKG-INFO +74 -0
  5. keble_task-2.22.1/README.md +58 -0
  6. keble_task-2.22.1/keble_task/testing/__init__.py +12 -0
  7. keble_task-2.22.1/keble_task/testing/config.py +169 -0
  8. keble_task-2.22.1/keble_task/testing/factories.py +67 -0
  9. keble_task-2.22.0/AiAgentChangesLogs.md → keble_task-2.22.1/logs/AiAgentChangesLogs.20260630.md +13 -0
  10. {keble_task-2.22.0 → keble_task-2.22.1}/pyproject.poetry.toml +2 -2
  11. {keble_task-2.22.0 → keble_task-2.22.1}/pyproject.toml +4 -3
  12. {keble_task-2.22.0 → keble_task-2.22.1}/tests/conftest.py +28 -30
  13. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/contract/events}/test_emit_drain_contract.py +1 -1
  14. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/contract/schemas}/test_metadata_jsonable_read.py +1 -2
  15. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/actions}/test_task_actions.py +1 -1
  16. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/agent}/test_agent_query_registry.py +1 -1
  17. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/agent}/test_agent_registry.py +1 -1
  18. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/core}/test_main.py +1 -1
  19. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/costs}/test_task_costs.py +1 -1
  20. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/relations}/test_task_relations.py +1 -1
  21. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/tree}/test_tree_and_public_id_edges.py +1 -1
  22. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/live/llm}/test_agent_registry_live.py +5 -4
  23. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/unit/core}/test_metadata_flow.py +3 -49
  24. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/unit/core}/test_retry_attempt_logging.py +1 -1
  25. keble_task-2.22.1/tests/unit/testing/test_config.py +96 -0
  26. {keble_task-2.22.0 → keble_task-2.22.1}/uv.lock +8 -51
  27. keble_task-2.22.0/AGENTS.md +0 -18
  28. keble_task-2.22.0/CLAUDE.md +0 -15
  29. keble_task-2.22.0/PKG-INFO +0 -1083
  30. keble_task-2.22.0/README.md +0 -1067
  31. keble_task-2.22.0/tests/config.py +0 -85
  32. keble_task-2.22.0/tests/pytest.ini +0 -3
  33. keble_task-2.22.0/tests/schemas/__init__.py +0 -0
  34. keble_task-2.22.0/tests/utils.py +0 -3
  35. {keble_task-2.22.0 → keble_task-2.22.1}/.gitattributes +0 -0
  36. {keble_task-2.22.0 → keble_task-2.22.1}/.gitignore +0 -0
  37. {keble_task-2.22.0 → keble_task-2.22.1}/.python-version +0 -0
  38. {keble_task-2.22.0 → keble_task-2.22.1}/deps/keble_typing-0.3.3-py3-none-any.whl +0 -0
  39. {keble_task-2.22.0 → keble_task-2.22.1}/improve.README.md +0 -0
  40. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/__init__.py +0 -0
  41. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/actions.py +0 -0
  42. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/__init__.py +0 -0
  43. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/chat_provider.py +0 -0
  44. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/deps.py +0 -0
  45. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/tools/__init__.py +0 -0
  46. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/tools/mutation.py +0 -0
  47. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/agent/tools/query.py +0 -0
  48. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/crud.py +0 -0
  49. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/exceptions.py +0 -0
  50. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/main.py +0 -0
  51. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/schemas/__init__.py +0 -0
  52. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/schemas/for_agent.py +0 -0
  53. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/task_tree.py +0 -0
  54. {keble_task-2.22.0 → keble_task-2.22.1}/keble_task/utils.py +0 -0
  55. {keble_task-2.22.0 → keble_task-2.22.1}/poetry.lock +0 -0
  56. {keble_task-2.22.0 → keble_task-2.22.1}/pyrightconfig.json +0 -0
  57. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/contract/schemas}/__init__.py +0 -0
  58. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/contract}/schemas/test_for_agent.py +0 -0
  59. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/contract/schemas}/test_no_local_datetime_helpers.py +0 -0
  60. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/integration/public}/test_public_indexable.py +0 -0
  61. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/unit/agent}/test_agent_chat_provider.py +0 -0
  62. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/unit/core}/test_exceptions.py +0 -0
  63. {keble_task-2.22.0/tests → keble_task-2.22.1/tests/unit/schemas}/test_schemas.py +0 -0
@@ -0,0 +1,32 @@
1
+ # Keble Task Agent Instructions
2
+
3
+ Follow the root `TESTING_GUIDELINE.md` when changing tests in this repo.
4
+
5
+ ## Testing Rules
6
+
7
+ - Keep default tests offline from external providers. The live LLM test must
8
+ stay marked `live` and `llm` and must require `RUN_LLM_LIVE=1`.
9
+ - Put executable tests under canonical layer folders only: `tests/unit/`,
10
+ `tests/contract/`, `tests/integration/`, `tests/live/`, `tests/evals/`, or
11
+ `tests/db_stack/`.
12
+ - Do not add flat `tests/test_*.py`, `tests/schemas/`, `tests/mock/`, or
13
+ `tests/irl/` folders.
14
+ - Do not recreate root-level `tests/config.py`, `tests/utils.py`, or an
15
+ importable root `tests` package. Shared test doubles and settings belong in
16
+ `keble_task.testing`.
17
+ - Tests that use Mongo/Redis fixtures are integration DB tests and must be
18
+ marked with `integration`, `db`, `mongo`, and `redis`.
19
+ - Use `keble_task.testing.config` for test credentials. It reads explicit env /
20
+ `tests/.env` / the umbrella `keble.backend/.env`, maps backend Azure provider
21
+ lists into the live LLM canary, and keeps test database names isolated.
22
+ - Use shared fixtures from `keble_db.testing` as the DB testing toolkit expands;
23
+ do not introduce ad-hoc shared local database writes.
24
+ - Do not add empty pytest lifecycle hooks, empty test folders, `pass`, `...`, or
25
+ status-only tests as placeholders. Add meaningful assertions or remove the
26
+ placeholder module.
27
+ - Do not add full stack or live-provider behavior to the default test command.
28
+ - Run `uv run pytest -m "not live and not slow and not eval and not local_stack and not db_stack and not container"`
29
+ and `npx --yes pyright .` after test-infrastructure changes.
30
+ - Update `README.md`, `AGENTS.md`, `CLAUDE.md`, and `AiAgentChangesLogs.md`
31
+ whenever testing behavior, markers, fixtures, commands, or dependencies
32
+ change.
@@ -0,0 +1,44 @@
1
+ # Ai Agent Changes Logs
2
+
3
+ Historical entries before 2026-06-30 23:13 were moved to `logs/AiAgentChangesLogs.20260630.md`.
4
+
5
+ ## 2026-07-02 00:58 CST
6
+ State: branch `refactor/harden-pytests-keble-task`; pytest hardening follow-up for `prompts/202060701/1.5-harden-pytests-and-remove-redundant.md`.
7
+
8
+ zma:
9
+ - Execute the cross-repo pytest hardening plan repo by repo.
10
+ - Reconsider over-trimmed IRL tests, remove weak placeholders, and use `keble.backend/.env` credentials instead of skipping DB/LLM tests for missing repo-local env.
11
+
12
+ Ai:
13
+ - Bumped `keble-task` to `2.22.1` and raised the `keble-db` dependency to `>=1.8.1`.
14
+ - Updated `keble_task.testing.config` to read explicit env / `tests/.env` / backend `.env` for Mongo and Redis, and to map the first backend Azure endpoint/token/deployment into the live LLM canary.
15
+ - Added unit coverage for backend env fallback, Azure provider-list mapping, and explicit-env precedence.
16
+ - Removed empty pytest lifecycle hooks from `tests/conftest.py` and updated docs to forbid placeholder test modules/hooks.
17
+ - Pending proof before merge: default pytest, unit, integration, live LLM guard, pyright, and package build.
18
+
19
+ ## 2026-07-01 03:32
20
+ State: Strict testing-folder follow-up for `keble-task`; no runtime task API behavior, schemas, or dependencies changed.
21
+
22
+ zma:
23
+ - Continue the cross-repo testing refactor after tightening `TESTING_GUIDELINE.md` marker and folder allowances.
24
+ - Enforce canonical test layer folders and package-owned shared test helpers.
25
+
26
+ Ai:
27
+ - Moved test settings into `keble_task.testing.config`.
28
+ - Moved shared in-memory task test doubles and factories into `keble_task.testing.factories`.
29
+ - Removed root `tests/config.py`, `tests/utils.py`, `tests/pytest.ini`, and `tests/__init__.py` so tests no longer import through `tests.*`.
30
+ - Updated docs to keep future shared task test helpers under `keble_task.testing`.
31
+
32
+ ## 2026-06-30 23:13
33
+ State: Documentation-only README compaction and AI log archival; no runtime code, schemas, dependencies, or tests were changed.
34
+
35
+ zma:
36
+ - Auto compact and summarize README.md files across repos unless already small.
37
+ - Cross-check retained README information for validity and keep only critical, necessary information.
38
+ - Move lengthy AiAgentChangesLogs.md files into repo-local logs/AiAgentChangesLogs.2026****.md.
39
+ - Merge the documentation changes to main repo by repo.
40
+
41
+ Ai:
42
+ - Archived the previous long agent change log into `logs/AiAgentChangesLogs.20260630.md`.
43
+ - Compacted `README.md` to current purpose, validated wiring, install/test gates, and high-risk side effects.
44
+ - Kept only critical current README facts cross-checked against manifests, config, source roots, compose scripts, or existing guideline files.
@@ -0,0 +1,33 @@
1
+ # Keble Task Claude Instructions
2
+
3
+ Follow the root `TESTING_GUIDELINE.md` for all task package test work.
4
+
5
+ Keep default tests free of live providers. Mongo/Redis tests are integration DB
6
+ tests; live LLM tests require `RUN_LLM_LIVE=1` and either explicit `LIVE_LLM_*`
7
+ credentials or backend Azure provider settings loaded from `keble.backend/.env`.
8
+ Use the shared marker vocabulary across Keble repos and prefer
9
+ `keble_db.testing` helpers as shared DB fixtures become available.
10
+
11
+ Executable tests must live under canonical layer folders only:
12
+ `tests/unit/`, `tests/contract/`, `tests/integration/`, `tests/live/`,
13
+ `tests/evals/`, or `tests/db_stack/`. Do not add flat `tests/test_*.py`,
14
+ `tests/schemas/`, `tests/mock/`, or `tests/irl/` folders. Mongo/Redis tests
15
+ must carry `integration`, `db`, `mongo`, and `redis` markers.
16
+
17
+ Do not recreate root-level `tests/config.py`, `tests/utils.py`, or an
18
+ importable root `tests` package. Shared settings, factories, and test doubles
19
+ belong in `keble_task.testing`.
20
+
21
+ Do not add empty pytest lifecycle hooks, placeholder test modules, `pass`, `...`,
22
+ or status-only assertions. If a repo lacks a reusable DB or provider fixture,
23
+ enrich `keble_db.testing` or this package's testing helper surface first.
24
+
25
+ Required checks after test-infrastructure changes:
26
+
27
+ ```bash
28
+ uv run pytest -m "not live and not slow and not eval and not local_stack and not db_stack and not container"
29
+ uv run pytest -m unit
30
+ uv run pytest -m integration
31
+ uv run pytest -m "live and llm"
32
+ npx --yes pyright .
33
+ ```
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: keble-task
3
+ Version: 2.22.1
4
+ Author-email: zhenhao-ma <bob0103779@gmail.com>
5
+ Requires-Python: <3.14,>=3.13
6
+ Requires-Dist: keble-db<2.0.0,>=1.8.1
7
+ Requires-Dist: keble-helpers<2.0.0,>=1.40.0
8
+ Requires-Dist: pydantic-ai-slim<2.0.0,>=1.41.0
9
+ Requires-Dist: tenacity<10.0.0,>=9
10
+ Provides-Extra: test
11
+ Requires-Dist: httpx[socks]<1.0.0,>=0.27; extra == 'test'
12
+ Requires-Dist: pydantic-ai-slim[openai]<2.0.0,>=1.41.0; extra == 'test'
13
+ Requires-Dist: pytest-asyncio<1.0.0,>=0; extra == 'test'
14
+ Requires-Dist: pytest<9.0.0,>=8; extra == 'test'
15
+ Description-Content-Type: text/markdown
16
+
17
+ # keble-task
18
+
19
+ `keble-task` owns generic Keble task schemas, task relations, task-room graph
20
+ context, lifecycle/action events, task cost records, and agent query/mutation
21
+ tool contracts.
22
+
23
+ ## Verified State
24
+
25
+ Checked on 2026-06-30 against `pyproject.toml`, package exports,
26
+ `keble_task/`, and tests.
27
+
28
+ - Package: `keble-task 2.22.1`
29
+ - Python: `>=3.13,<3.14`
30
+ - Critical deps: `keble-helpers`, `keble-db`, `pydantic-ai-slim`, `tenacity`
31
+ - Source roots: `schemas/`, `actions/`, `crud/`, `main/`, `agent/`, `utils/`
32
+ - Public exports: `TaskClient`, CRUD classes, task/task-relation schemas,
33
+ task-cost schemas, lifecycle/action events, and agent tool providers.
34
+
35
+ ## Runtime Contract
36
+
37
+ - Task identity, stage, relations, and cost accounting belong here. Feature
38
+ packages should attach domain metadata instead of redefining task rows.
39
+ - First-class long-running features should be real `TaskType` flows in the
40
+ consuming service, not generic subagent workflows plus parallel adapters.
41
+ - Lifecycle and action events must stay typed and stable for backend
42
+ websocket fanout and frontend task-list rendering.
43
+ - Mongo CRUD changes must expose indexed query shapes directly and keep index
44
+ creation in startup wiring, not request handlers.
45
+
46
+ ## Testing
47
+
48
+ ```bash
49
+ uv sync --group test
50
+ uv run pytest -m "not live and not slow and not eval and not local_stack and not db_stack and not container"
51
+ uv run npx --yes pyright .
52
+ ```
53
+
54
+ Package-owned test helpers live under `keble_task.testing`; do not recreate
55
+ root-level `tests/config.py`, `tests/utils.py`, root test packages, or legacy
56
+ source folders such as `tests/schemas/`.
57
+
58
+ Mongo/Redis integration settings load explicit process env first, then
59
+ `tests/.env`, then the umbrella `keble.backend/.env` through
60
+ `keble_db.testing.resolve_test_env`. Live LLM settings load explicit `LIVE_LLM_*`
61
+ values first and otherwise map the first backend Azure endpoint/token/deployment
62
+ entry. Set `KEBLE_BACKEND_ENV_FILE=/path/to/.env` from unusual worktree or CI
63
+ layouts. Keep the package-owned test database and collection names isolated.
64
+
65
+ ## Change Logs
66
+
67
+ Historical release notes and long AI change history live under `logs/`.
68
+
69
+ ## Side Effect If Changes
70
+
71
+ - Backend task APIs, owner task lists, task room sockets, cost accounting,
72
+ and frontend task rows depend on these schemas/events.
73
+ - Relation or graph-context changes can affect all feature rooms that load
74
+ child tasks or background sessions.
@@ -0,0 +1,58 @@
1
+ # keble-task
2
+
3
+ `keble-task` owns generic Keble task schemas, task relations, task-room graph
4
+ context, lifecycle/action events, task cost records, and agent query/mutation
5
+ tool contracts.
6
+
7
+ ## Verified State
8
+
9
+ Checked on 2026-06-30 against `pyproject.toml`, package exports,
10
+ `keble_task/`, and tests.
11
+
12
+ - Package: `keble-task 2.22.1`
13
+ - Python: `>=3.13,<3.14`
14
+ - Critical deps: `keble-helpers`, `keble-db`, `pydantic-ai-slim`, `tenacity`
15
+ - Source roots: `schemas/`, `actions/`, `crud/`, `main/`, `agent/`, `utils/`
16
+ - Public exports: `TaskClient`, CRUD classes, task/task-relation schemas,
17
+ task-cost schemas, lifecycle/action events, and agent tool providers.
18
+
19
+ ## Runtime Contract
20
+
21
+ - Task identity, stage, relations, and cost accounting belong here. Feature
22
+ packages should attach domain metadata instead of redefining task rows.
23
+ - First-class long-running features should be real `TaskType` flows in the
24
+ consuming service, not generic subagent workflows plus parallel adapters.
25
+ - Lifecycle and action events must stay typed and stable for backend
26
+ websocket fanout and frontend task-list rendering.
27
+ - Mongo CRUD changes must expose indexed query shapes directly and keep index
28
+ creation in startup wiring, not request handlers.
29
+
30
+ ## Testing
31
+
32
+ ```bash
33
+ uv sync --group test
34
+ uv run pytest -m "not live and not slow and not eval and not local_stack and not db_stack and not container"
35
+ uv run npx --yes pyright .
36
+ ```
37
+
38
+ Package-owned test helpers live under `keble_task.testing`; do not recreate
39
+ root-level `tests/config.py`, `tests/utils.py`, root test packages, or legacy
40
+ source folders such as `tests/schemas/`.
41
+
42
+ Mongo/Redis integration settings load explicit process env first, then
43
+ `tests/.env`, then the umbrella `keble.backend/.env` through
44
+ `keble_db.testing.resolve_test_env`. Live LLM settings load explicit `LIVE_LLM_*`
45
+ values first and otherwise map the first backend Azure endpoint/token/deployment
46
+ entry. Set `KEBLE_BACKEND_ENV_FILE=/path/to/.env` from unusual worktree or CI
47
+ layouts. Keep the package-owned test database and collection names isolated.
48
+
49
+ ## Change Logs
50
+
51
+ Historical release notes and long AI change history live under `logs/`.
52
+
53
+ ## Side Effect If Changes
54
+
55
+ - Backend task APIs, owner task lists, task room sockets, cost accounting,
56
+ and frontend task rows depend on these schemas/events.
57
+ - Relation or graph-context changes can affect all feature rooms that load
58
+ child tasks or background sessions.
@@ -0,0 +1,12 @@
1
+ """Package-owned testing helpers for Keble task tests and downstream suites."""
2
+
3
+ from .config import Settings, build_db, settings
4
+ from .factories import InMemoryCRUDTask, make_task
5
+
6
+ __all__ = [
7
+ "InMemoryCRUDTask",
8
+ "Settings",
9
+ "build_db",
10
+ "make_task",
11
+ "settings",
12
+ ]
@@ -0,0 +1,169 @@
1
+ """Environment-backed settings for Keble task integration and live tests."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ import json
7
+
8
+ from keble_db import Db, DbSettingsABC
9
+ from keble_db.testing import backend_env_values, resolve_test_env
10
+ from pydantic import Field
11
+ from pydantic_settings import BaseSettings, SettingsConfigDict
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def _resolve_first_backend_json_list_value(
17
+ *,
18
+ explicit_env_name: str,
19
+ backend_env_name: str,
20
+ ) -> str | None:
21
+ """Resolve a live-test value from explicit env or backend JSON-list config.
22
+
23
+ The package live LLM canary needs one OpenAI-compatible endpoint, token, and
24
+ deployment. Backend stores provider values as JSON-style lists, so task tests
25
+ use the first configured value only when the package-specific `LIVE_LLM_*`
26
+ variable is absent.
27
+ """
28
+
29
+ explicit_value = resolve_test_env(explicit_env_name)
30
+ if explicit_value is not None:
31
+ return explicit_value
32
+
33
+ backend_value = backend_env_values().get(backend_env_name)
34
+ if backend_value is None:
35
+ return None
36
+
37
+ parsed_value = json.loads(backend_value)
38
+ if not isinstance(parsed_value, list) or not parsed_value:
39
+ return None
40
+
41
+ first_value = parsed_value[0]
42
+ if not isinstance(first_value, str) or first_value.strip() == "":
43
+ return None
44
+
45
+ return first_value.strip()
46
+
47
+
48
+ class Settings(DbSettingsABC, BaseSettings):
49
+ """Settings protocol implementation used only by opt-in pytest layers."""
50
+
51
+ model_config = SettingsConfigDict(
52
+ env_file="./tests/.env", env_file_encoding="utf-8", case_sensitive=True
53
+ )
54
+
55
+ MONGO_DB_URI: str | None = Field(
56
+ default_factory=lambda: resolve_test_env("MONGO_DB_URI")
57
+ )
58
+ MONGO_DB_DATABASE: str = "__keble_task__pytest__"
59
+ TASK_COLLECTION: str = "__keble_task__pytest__task__"
60
+ TASK_RELATION_COLLECTION: str = "__keble_task__pytest__task_relation__"
61
+ TASK_COST_COLLECTION: str = "__keble_task__pytest__task_cost__"
62
+
63
+ REDIS_URI: str | None = Field(default_factory=lambda: resolve_test_env("REDIS_URI"))
64
+
65
+ LIVE_LLM_ENDPOINT: str | None = Field(
66
+ default_factory=lambda: _resolve_first_backend_json_list_value(
67
+ explicit_env_name="LIVE_LLM_ENDPOINT",
68
+ backend_env_name="AZURE_PROVIDER_ENDPOINTS",
69
+ )
70
+ )
71
+ LIVE_LLM_API_TOKEN: str | None = Field(
72
+ default_factory=lambda: _resolve_first_backend_json_list_value(
73
+ explicit_env_name="LIVE_LLM_API_TOKEN",
74
+ backend_env_name="AZURE_PROVIDER_API_TOKENS",
75
+ )
76
+ )
77
+ LIVE_LLM_CHAT_DEPLOYMENT: str | None = Field(
78
+ default_factory=lambda: _resolve_first_backend_json_list_value(
79
+ explicit_env_name="LIVE_LLM_CHAT_DEPLOYMENT",
80
+ backend_env_name="AZURE_OPENAI_CHAT_MODELS_DEPLOYMENTS",
81
+ )
82
+ )
83
+
84
+ @property
85
+ def qdrant_host(self) -> str | None:
86
+ """Return no Qdrant host because task tests do not use Qdrant."""
87
+
88
+ return None
89
+
90
+ @property
91
+ def qdrant_port(self) -> int | None:
92
+ """Return no Qdrant port because task tests do not use Qdrant."""
93
+
94
+ return None
95
+
96
+ @property
97
+ def qdrant_collection(self) -> str | None:
98
+ """Return no Qdrant collection because task tests do not use Qdrant."""
99
+
100
+ return None
101
+
102
+ @property
103
+ def mongo_db_uri(self) -> str | None:
104
+ """Expose the configured Mongo URI through the keble-db protocol."""
105
+
106
+ return self.MONGO_DB_URI
107
+
108
+ @property
109
+ def mongo_db_database(self) -> str:
110
+ """Expose the configured Mongo database through the keble-db protocol."""
111
+
112
+ return self.MONGO_DB_DATABASE
113
+
114
+ @property
115
+ def redis_uri(self) -> str | None:
116
+ """Expose the configured Redis URI through the keble-db protocol."""
117
+
118
+ return self.REDIS_URI
119
+
120
+ @property
121
+ def sql_write_uri(self) -> str | None:
122
+ """Return no SQL write URI because task tests do not use SQL."""
123
+
124
+ return None
125
+
126
+ @property
127
+ def sql_read_uri(self) -> str | None:
128
+ """Return no SQL read URI because task tests do not use SQL."""
129
+
130
+ return None
131
+
132
+ @property
133
+ def sql_uri(self) -> str | None:
134
+ """Return no SQL URI because task tests do not use SQL."""
135
+
136
+ return None
137
+
138
+ @property
139
+ def neo4j_uri(self) -> str | None:
140
+ """Return no Neo4j URI because task tests do not use Neo4j."""
141
+
142
+ return None
143
+
144
+ @property
145
+ def neo4j_user(self) -> str | None:
146
+ """Return no Neo4j user because task tests do not use Neo4j."""
147
+
148
+ return None
149
+
150
+ @property
151
+ def neo4j_password(self) -> str | None:
152
+ """Return no Neo4j password because task tests do not use Neo4j."""
153
+
154
+ return None
155
+
156
+ @property
157
+ def neo4j_database(self) -> str | None:
158
+ """Return no Neo4j database because task tests do not use Neo4j."""
159
+
160
+ return None
161
+
162
+
163
+ settings = Settings()
164
+
165
+
166
+ def build_db() -> Db:
167
+ """Build a keble-db adapter only after a test opts into real services."""
168
+
169
+ return Db(settings)
@@ -0,0 +1,67 @@
1
+ """Reusable task test doubles and factories."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import uuid
6
+ from datetime import datetime, timezone
7
+
8
+ from bson import ObjectId
9
+ from keble_helpers import SharingScope, Status
10
+
11
+ from keble_task.schemas import TaskMongoObject, TaskStage
12
+
13
+
14
+ class InMemoryCRUDTask:
15
+ """Minimal in-memory CRUDTask stand-in for TaskClient unit tests."""
16
+
17
+ def __init__(self, task: TaskMongoObject) -> None:
18
+ """Store one task row by Mongo ObjectId for deterministic unit tests."""
19
+
20
+ self._tasks = {task.id: task}
21
+
22
+ async def aincrement_attempts(self, amongo, *, _id: ObjectId) -> TaskMongoObject:
23
+ """Increment attempts on the stored task and return the updated row."""
24
+
25
+ task = self._tasks[_id]
26
+ updated = task.model_copy(update={"attempts": int(task.attempts) + 1})
27
+ self._tasks[_id] = updated
28
+ return updated
29
+
30
+ async def aupdate(self, amongo, *, _id: ObjectId, obj_in: dict) -> None:
31
+ """Apply a partial update to the stored task row."""
32
+
33
+ task = self._tasks[_id]
34
+ self._tasks[_id] = task.model_copy(update=obj_in)
35
+
36
+ async def afirst_by_id(self, amongo, *, _id: ObjectId) -> TaskMongoObject | None:
37
+ """Return the stored task for an ObjectId, if it exists."""
38
+
39
+ return self._tasks.get(_id)
40
+
41
+
42
+ def make_task(
43
+ *,
44
+ expected_token: int = 1,
45
+ consumed_token: int = 0,
46
+ metadata: dict | None = None,
47
+ ) -> TaskMongoObject:
48
+ """Build a valid task row for TaskClient unit and contract tests."""
49
+
50
+ return TaskMongoObject(
51
+ id=ObjectId(),
52
+ stage=TaskStage.PENDING,
53
+ task_type=str(uuid.uuid4()),
54
+ progress_key=str(uuid.uuid4()),
55
+ title=None,
56
+ subtitle=None,
57
+ image="https://example.com/x.png",
58
+ metadata=metadata,
59
+ sharing_scope=SharingScope.PRIVATE,
60
+ status=Status.ACTIVE,
61
+ owner=str(uuid.uuid4()),
62
+ expected_token=expected_token,
63
+ consumed_token=consumed_token,
64
+ attempts=0,
65
+ timeout_mins=120,
66
+ created=datetime.now(timezone.utc),
67
+ )
@@ -1,3 +1,16 @@
1
+ ## 2026-06-30 22:07 CST
2
+ State: `keble-task` strict test folder normalization on branch `refactor/testing-normalization-keble-task`.
3
+
4
+ zma:
5
+ - Continue the strict cross-repo testing cleanup from `prompts/20260630/1.3 cross-repos-tests-boost.md`.
6
+ - Enforce canonical test folders and marker allowances from the updated root `TESTING_GUIDELINE.md`.
7
+
8
+ Ai:
9
+ - Moved executable tests from flat `tests/test_*.py` and legacy `tests/schemas/` into canonical `tests/unit`, `tests/contract`, `tests/integration`, and `tests/live` roots.
10
+ - Updated pytest collection marking to classify tests by canonical layer folder and mark Mongo/Redis task-client tests with `integration`, `db`, `mongo`, and `redis`.
11
+ - Added missing `redis` and `container` marker registrations to keep the repo aligned with the shared marker vocabulary.
12
+ - Updated README/AGENTS/CLAUDE to forbid new flat or legacy test folders and to use the stricter default test command.
13
+
1
14
  ## 2026-06-30 13:42 CST
2
15
  State: branch `refactor/testing-layers-keble-task`; package line moving from `2.21.0` to `2.22.0`.
3
16
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "keble-task"
3
- version = "2.5.1"
3
+ version = "2.22.1"
4
4
  description = ""
5
5
  authors = ["zhenhao-ma <bob0103779@gmail.com>"]
6
6
  readme = "README.md"
@@ -10,7 +10,7 @@ classifiers = [
10
10
  [tool.poetry.dependencies]
11
11
  python = ">=3.13,<3.14"
12
12
  keble-helpers = ">=1.12.6,<2.0.0"
13
- keble-db = ">=1.6.2,<2.0.0"
13
+ keble-db = ">=1.8.1,<2.0.0"
14
14
  pydantic-ai-slim = ">=1.41.0,<2.0.0"
15
15
  tenacity = ">=9,<10.0.0"
16
16
 
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "keble-task"
7
- version = "2.22.0"
7
+ version = "2.22.1"
8
8
  description = ""
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
11
- dependencies = ["keble-helpers>=1.40.0,<2.0.0", "keble-db>=1.7.1,<2.0.0", "pydantic-ai-slim>=1.41.0,<2.0.0", "tenacity>=9,<10.0.0"]
11
+ dependencies = ["keble-helpers>=1.40.0,<2.0.0", "keble-db>=1.8.1,<2.0.0", "pydantic-ai-slim>=1.41.0,<2.0.0", "tenacity>=9,<10.0.0"]
12
12
 
13
13
  [[project.authors]]
14
14
  name = "zhenhao-ma"
@@ -24,7 +24,6 @@ test = ["pytest>=8,<9.0.0", "pytest-asyncio>=0,<1.0.0", "pydantic-ai-slim[openai
24
24
  default-groups = ["test"]
25
25
 
26
26
  [tool.uv.sources]
27
- keble-db = {path = "../keble-py/keble-db"}
28
27
  keble-helpers = {path = "../keble-py/keble-helpers"}
29
28
 
30
29
  [tool.hatch.build]
@@ -42,8 +41,10 @@ markers = [
42
41
  "db: any real database test",
43
42
  "postgres: PostgreSQL tests",
44
43
  "mongo: MongoDB tests",
44
+ "redis: Redis tests",
45
45
  "qdrant: Qdrant tests",
46
46
  "neo4j: Neo4j tests",
47
+ "container: tests that start Testcontainers resources",
47
48
  "db_stack: multi-database integration tests",
48
49
  "keepa: Keepa-related tests",
49
50
  "keepa_contract: recorded Keepa contract tests",