aiogram-idle 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. aiogram_idle-0.1.0/.gitattributes +8 -0
  2. aiogram_idle-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +22 -0
  3. aiogram_idle-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  4. aiogram_idle-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +17 -0
  5. aiogram_idle-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
  6. aiogram_idle-0.1.0/.github/workflows/ci.yml +219 -0
  7. aiogram_idle-0.1.0/.github/workflows/nav-integration.yml +54 -0
  8. aiogram_idle-0.1.0/.github/workflows/publish.yml +91 -0
  9. aiogram_idle-0.1.0/.gitignore +20 -0
  10. aiogram_idle-0.1.0/CHANGELOG.md +53 -0
  11. aiogram_idle-0.1.0/CHANGES/README.md +17 -0
  12. aiogram_idle-0.1.0/CODE_OF_CONDUCT.md +14 -0
  13. aiogram_idle-0.1.0/CONTRIBUTING.md +41 -0
  14. aiogram_idle-0.1.0/LICENSE +21 -0
  15. aiogram_idle-0.1.0/PKG-INFO +123 -0
  16. aiogram_idle-0.1.0/README.md +96 -0
  17. aiogram_idle-0.1.0/SECURITY.md +33 -0
  18. aiogram_idle-0.1.0/coverage-nav.toml +6 -0
  19. aiogram_idle-0.1.0/docs/api.md +31 -0
  20. aiogram_idle-0.1.0/docs/architecture.md +32 -0
  21. aiogram_idle-0.1.0/docs/audit.md +52 -0
  22. aiogram_idle-0.1.0/docs/index.md +21 -0
  23. aiogram_idle-0.1.0/docs/installation.md +37 -0
  24. aiogram_idle-0.1.0/docs/navigation.md +199 -0
  25. aiogram_idle-0.1.0/docs/quickstart.md +36 -0
  26. aiogram_idle-0.1.0/docs/recovery.md +41 -0
  27. aiogram_idle-0.1.0/docs/redis-audit.md +79 -0
  28. aiogram_idle-0.1.0/docs/redis.md +156 -0
  29. aiogram_idle-0.1.0/docs/releasing.md +45 -0
  30. aiogram_idle-0.1.0/docs/standalone.md +70 -0
  31. aiogram_idle-0.1.0/docs/testing.md +65 -0
  32. aiogram_idle-0.1.0/docs/verification.md +154 -0
  33. aiogram_idle-0.1.0/examples/README.md +40 -0
  34. aiogram_idle-0.1.0/examples/demo.py +232 -0
  35. aiogram_idle-0.1.0/examples/navigation.py +193 -0
  36. aiogram_idle-0.1.0/mkdocs.yml +26 -0
  37. aiogram_idle-0.1.0/pyproject.toml +99 -0
  38. aiogram_idle-0.1.0/pyright-nav.json +8 -0
  39. aiogram_idle-0.1.0/reports/2026-11-10-repository-alignment.md +99 -0
  40. aiogram_idle-0.1.0/src/aiogram_idle/__init__.py +146 -0
  41. aiogram_idle-0.1.0/src/aiogram_idle/activity.py +122 -0
  42. aiogram_idle-0.1.0/src/aiogram_idle/clock.py +69 -0
  43. aiogram_idle-0.1.0/src/aiogram_idle/compat.py +72 -0
  44. aiogram_idle-0.1.0/src/aiogram_idle/config.py +71 -0
  45. aiogram_idle-0.1.0/src/aiogram_idle/controls.py +167 -0
  46. aiogram_idle-0.1.0/src/aiogram_idle/coordinator.py +146 -0
  47. aiogram_idle-0.1.0/src/aiogram_idle/effect_scope.py +27 -0
  48. aiogram_idle-0.1.0/src/aiogram_idle/effects.py +160 -0
  49. aiogram_idle-0.1.0/src/aiogram_idle/errors.py +61 -0
  50. aiogram_idle-0.1.0/src/aiogram_idle/events.py +21 -0
  51. aiogram_idle-0.1.0/src/aiogram_idle/failures.py +67 -0
  52. aiogram_idle-0.1.0/src/aiogram_idle/integration.py +275 -0
  53. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/__init__.py +20 -0
  54. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/adapters.py +187 -0
  55. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/codec.py +78 -0
  56. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/effects.py +98 -0
  57. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/engine.py +245 -0
  58. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/errors.py +25 -0
  59. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/installation.py +295 -0
  60. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/integration.py +245 -0
  61. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/lifecycle.py +143 -0
  62. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/mapping.py +106 -0
  63. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/overlay.py +71 -0
  64. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/policies.py +73 -0
  65. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/presentation.py +105 -0
  66. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/receipts.py +49 -0
  67. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/recovery.py +119 -0
  68. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/repository.py +375 -0
  69. aiogram_idle-0.1.0/src/aiogram_idle/integrations/nav/staging.py +195 -0
  70. aiogram_idle-0.1.0/src/aiogram_idle/machine.py +66 -0
  71. aiogram_idle-0.1.0/src/aiogram_idle/models.py +383 -0
  72. aiogram_idle-0.1.0/src/aiogram_idle/policies.py +87 -0
  73. aiogram_idle-0.1.0/src/aiogram_idle/presentation.py +299 -0
  74. aiogram_idle-0.1.0/src/aiogram_idle/protocols.py +68 -0
  75. aiogram_idle-0.1.0/src/aiogram_idle/py.typed +0 -0
  76. aiogram_idle-0.1.0/src/aiogram_idle/questions.py +184 -0
  77. aiogram_idle-0.1.0/src/aiogram_idle/receipts.py +129 -0
  78. aiogram_idle-0.1.0/src/aiogram_idle/runtime.py +385 -0
  79. aiogram_idle-0.1.0/src/aiogram_idle/storage/__init__.py +7 -0
  80. aiogram_idle-0.1.0/src/aiogram_idle/storage/base.py +118 -0
  81. aiogram_idle-0.1.0/src/aiogram_idle/storage/codec.py +292 -0
  82. aiogram_idle-0.1.0/src/aiogram_idle/storage/component_transaction.py +244 -0
  83. aiogram_idle-0.1.0/src/aiogram_idle/storage/control_tokens.py +61 -0
  84. aiogram_idle-0.1.0/src/aiogram_idle/storage/coordination.py +21 -0
  85. aiogram_idle-0.1.0/src/aiogram_idle/storage/memory.py +499 -0
  86. aiogram_idle-0.1.0/src/aiogram_idle/storage/queue.py +114 -0
  87. aiogram_idle-0.1.0/src/aiogram_idle/storage/receipts.py +99 -0
  88. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis.py +352 -0
  89. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_admin.py +78 -0
  90. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_coordinator.py +311 -0
  91. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_engine.py +239 -0
  92. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_jobs.py +226 -0
  93. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_quarantine.py +142 -0
  94. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_scripts.py +162 -0
  95. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_store.py +464 -0
  96. aiogram_idle-0.1.0/src/aiogram_idle/storage/redis_transport.py +121 -0
  97. aiogram_idle-0.1.0/src/aiogram_idle/storage/retention.py +47 -0
  98. aiogram_idle-0.1.0/src/aiogram_idle/storage/state.py +51 -0
  99. aiogram_idle-0.1.0/src/aiogram_idle/worker.py +442 -0
  100. aiogram_idle-0.1.0/tests/__init__.py +1 -0
  101. aiogram_idle-0.1.0/tests/conftest.py +28 -0
  102. aiogram_idle-0.1.0/tests/integration/test_examples.py +52 -0
  103. aiogram_idle-0.1.0/tests/runtime_helpers.py +193 -0
  104. aiogram_idle-0.1.0/tests/test_audit_engine.py +345 -0
  105. aiogram_idle-0.1.0/tests/test_audit_fsm.py +260 -0
  106. aiogram_idle-0.1.0/tests/test_audit_recovery.py +180 -0
  107. aiogram_idle-0.1.0/tests/test_audit_scale.py +49 -0
  108. aiogram_idle-0.1.0/tests/test_audit_storage.py +336 -0
  109. aiogram_idle-0.1.0/tests/test_component_ownership.py +45 -0
  110. aiogram_idle-0.1.0/tests/test_component_review.py +61 -0
  111. aiogram_idle-0.1.0/tests/test_component_transactions.py +239 -0
  112. aiogram_idle-0.1.0/tests/test_effect_scope_review.py +33 -0
  113. aiogram_idle-0.1.0/tests/test_memory.py +377 -0
  114. aiogram_idle-0.1.0/tests/test_memory_edges.py +166 -0
  115. aiogram_idle-0.1.0/tests/test_nav_atomic_recovery.py +274 -0
  116. aiogram_idle-0.1.0/tests/test_nav_boundary.py +72 -0
  117. aiogram_idle-0.1.0/tests/test_nav_example.py +69 -0
  118. aiogram_idle-0.1.0/tests/test_nav_matrix.py +194 -0
  119. aiogram_idle-0.1.0/tests/test_nav_projection.py +403 -0
  120. aiogram_idle-0.1.0/tests/test_nav_reply_restore.py +169 -0
  121. aiogram_idle-0.1.0/tests/test_nav_review_fsm.py +238 -0
  122. aiogram_idle-0.1.0/tests/test_nav_review_policies.py +23 -0
  123. aiogram_idle-0.1.0/tests/test_nav_review_recovery.py +228 -0
  124. aiogram_idle-0.1.0/tests/test_nav_runtime.py +457 -0
  125. aiogram_idle-0.1.0/tests/test_nav_schema_recovery.py +53 -0
  126. aiogram_idle-0.1.0/tests/test_redis_admin.py +46 -0
  127. aiogram_idle-0.1.0/tests/test_redis_atomicity.py +407 -0
  128. aiogram_idle-0.1.0/tests/test_redis_backend.py +305 -0
  129. aiogram_idle-0.1.0/tests/test_redis_codec.py +241 -0
  130. aiogram_idle-0.1.0/tests/test_redis_commit_audit.py +337 -0
  131. aiogram_idle-0.1.0/tests/test_redis_coord.py +162 -0
  132. aiogram_idle-0.1.0/tests/test_redis_corruption.py +184 -0
  133. aiogram_idle-0.1.0/tests/test_redis_dispatcher.py +120 -0
  134. aiogram_idle-0.1.0/tests/test_redis_effect_audit.py +186 -0
  135. aiogram_idle-0.1.0/tests/test_redis_fsm_audit.py +295 -0
  136. aiogram_idle-0.1.0/tests/test_redis_presentation.py +84 -0
  137. aiogram_idle-0.1.0/tests/test_redis_queue_audit.py +62 -0
  138. aiogram_idle-0.1.0/tests/test_redis_recovery.py +354 -0
  139. aiogram_idle-0.1.0/tests/test_telegram.py +312 -0
  140. aiogram_idle-0.1.0/tests/test_telegram_failures.py +347 -0
  141. aiogram_idle-0.1.0/tests/test_timeout_audit.py +137 -0
  142. aiogram_idle-0.1.0/tests/unit/__init__.py +1 -0
  143. aiogram_idle-0.1.0/tests/unit/test_contracts.py +251 -0
  144. aiogram_idle-0.1.0/tests/unit/test_lookup_audit.py +13 -0
  145. aiogram_idle-0.1.0/tests/unit/test_package_metadata.py +21 -0
  146. aiogram_idle-0.1.0/tests/unit/test_recovery_regressions.py +197 -0
  147. aiogram_idle-0.1.0/tests/unit/test_runtime.py +354 -0
  148. aiogram_idle-0.1.0/tests/unit/test_runtime_edges.py +223 -0
  149. aiogram_idle-0.1.0/tools/README.md +15 -0
  150. aiogram_idle-0.1.0/tools/check_artifacts.py +50 -0
  151. aiogram_idle-0.1.0/tools/check_version_tag.py +32 -0
  152. aiogram_idle-0.1.0/uv.lock +3446 -0
@@ -0,0 +1,8 @@
1
+ * text=auto eol=lf
2
+ *.png binary
3
+ *.jpg binary
4
+ *.jpeg binary
5
+ *.gif binary
6
+ *.ico binary
7
+ *.woff binary
8
+ *.woff2 binary
@@ -0,0 +1,22 @@
1
+ name: Bug report
2
+ description: Report reproducible behavior in aiogram-idle.
3
+ body:
4
+ - type: textarea
5
+ id: versions
6
+ attributes:
7
+ label: Environment
8
+ description: Python, aiogram-idle, aiogram and optional Redis/server versions.
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: reproduction
13
+ attributes:
14
+ label: Reproduction
15
+ description: Minimal code, expected behavior and actual behavior. Remove credentials and message content.
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: logs
20
+ attributes:
21
+ label: Sanitized diagnostics
22
+ description: Include storage backend, FSM isolation and worker configuration where relevant.
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: true
2
+ contact_links:
3
+ - name: Security reporting
4
+ url: https://github.com/ArmanAvanesyan/aiogram-idle/blob/main/SECURITY.md
5
+ about: Read the reporting guidance before disclosing a vulnerability.
@@ -0,0 +1,17 @@
1
+ name: Feature request
2
+ description: Propose an aiogram-idle improvement.
3
+ body:
4
+ - type: textarea
5
+ id: problem
6
+ attributes:
7
+ label: Problem
8
+ description: Explain the use case and current limitation.
9
+ validations:
10
+ required: true
11
+ - type: textarea
12
+ id: proposal
13
+ attributes:
14
+ label: Proposal
15
+ description: Describe the public behavior and alternatives considered.
16
+ validations:
17
+ required: true
@@ -0,0 +1,15 @@
1
+ ## Change
2
+
3
+ Describe the problem and resulting behavior. Link related issues.
4
+
5
+ ## Verification
6
+
7
+ List the checks run and any unverified behavior. Include recovery, ownership and
8
+ real-Redis tests when changing storage or coordination.
9
+
10
+ ## Checklist
11
+
12
+ - [ ] Tests cover changed behavior.
13
+ - [ ] Public API and compatibility changes are documented.
14
+ - [ ] A `CHANGES/` fragment is included where appropriate.
15
+ - [ ] No credentials, generated audit reports or local environment files are included.
@@ -0,0 +1,219 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ quality:
12
+ runs-on: ubuntu-latest
13
+ timeout-minutes: 30
14
+ services:
15
+ redis:
16
+ image: redis:7-alpine
17
+ ports: ["6379:6379"]
18
+ options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 10
19
+ env:
20
+ AIOGRAM_IDLE_REDIS_URL: redis://localhost:6379/0
21
+ AIOGRAM_IDLE_REQUIRE_REDIS: "1"
22
+ steps:
23
+ - uses: actions/checkout@v4
24
+ - uses: astral-sh/setup-uv@v6
25
+ with:
26
+ enable-cache: true
27
+ - run: uv sync --frozen --extra redis --python 3.12
28
+ - run: uv run --no-sync ruff check .
29
+ - run: uv run --no-sync ruff format --check .
30
+ - run: uv run --no-sync pyright
31
+ - name: Verify standalone dependency boundary
32
+ run: uv run --no-sync python -c 'import importlib.util; assert importlib.util.find_spec("aiogram_nav") is None'
33
+ - run: uv run --no-sync pytest --cov=aiogram_idle --cov-report=term-missing
34
+ - run: uv run --no-sync python tools/check_version_tag.py
35
+ - run: uv run --no-sync towncrier build --draft --version 0.1.0
36
+ - run: uv build
37
+ - run: uv run --no-sync twine check dist/*
38
+ - run: uv run --no-sync python tools/check_artifacts.py dist/*.whl dist/*.tar.gz
39
+ - name: Compile examples without sending messages
40
+ run: uv run --no-sync python -m compileall -q examples
41
+ - name: Smoke test Redis wheel and sdist independently
42
+ shell: bash
43
+ run: |
44
+ for artifact in dist/*.whl dist/*.tar.gz; do
45
+ smoke_dir=$(mktemp -d)
46
+ uv venv --python 3.12 "$smoke_dir/env"
47
+ uv pip install --python "$smoke_dir/env/bin/python" "${artifact}[redis]"
48
+ cd "$smoke_dir"
49
+ "$smoke_dir/env/bin/python" - <<'PYREDIS'
50
+ import asyncio, importlib.util, os, uuid
51
+ from aiogram_idle.storage.redis import RedisIdleBackend
52
+ assert importlib.util.find_spec("aiogram_nav") is None
53
+ async def check():
54
+ backend = RedisIdleBackend.from_url(os.environ["AIOGRAM_IDLE_REDIS_URL"], prefix="artifact:" + uuid.uuid4().hex)
55
+ try:
56
+ await backend.initialize()
57
+ finally:
58
+ await backend.close()
59
+ asyncio.run(check())
60
+ PYREDIS
61
+ cd "$GITHUB_WORKSPACE"
62
+ done
63
+
64
+ documentation:
65
+ runs-on: ubuntu-latest
66
+ timeout-minutes: 10
67
+ steps:
68
+ - uses: actions/checkout@v4
69
+ - uses: astral-sh/setup-uv@v6
70
+ with:
71
+ enable-cache: true
72
+ - run: uv sync --frozen --python 3.12
73
+ - run: uv run --no-sync mkdocs build --strict
74
+
75
+ security:
76
+ runs-on: ubuntu-latest
77
+ timeout-minutes: 15
78
+ steps:
79
+ - uses: actions/checkout@v4
80
+ - uses: astral-sh/setup-uv@v6
81
+ with:
82
+ enable-cache: true
83
+ - run: uv sync --frozen --extra redis --python 3.12
84
+ - name: Audit source security
85
+ if: ${{ !cancelled() }}
86
+ run: uv run --no-sync bandit -r src -f json -o bandit-report.json
87
+ - name: Audit installed dependencies
88
+ if: ${{ !cancelled() }}
89
+ run: uv run --no-sync pip-audit --skip-editable --format json --output pip-audit-report.json
90
+ - name: Retain security reports
91
+ if: always()
92
+ uses: actions/upload-artifact@v4
93
+ with:
94
+ name: security-reports
95
+ path: |
96
+ bandit-report.json
97
+ pip-audit-report.json
98
+ if-no-files-found: error
99
+
100
+ compatibility:
101
+ runs-on: ubuntu-latest
102
+ timeout-minutes: 30
103
+ services:
104
+ redis:
105
+ image: redis:7-alpine
106
+ ports: ['6379:6379']
107
+ options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 10
108
+ env:
109
+ AIOGRAM_IDLE_REDIS_URL: redis://localhost:6379/0
110
+ AIOGRAM_IDLE_REQUIRE_REDIS: '1'
111
+ strategy:
112
+ fail-fast: false
113
+ matrix:
114
+ python: ['3.10', '3.11', '3.12', '3.13', '3.14']
115
+ aiogram: [minimum, latest]
116
+ exclude:
117
+ # aiogram 3.22 pins pydantic before Python 3.14 wheel support.
118
+ - python: '3.14'
119
+ aiogram: minimum
120
+ steps:
121
+ - uses: actions/checkout@v4
122
+ - uses: astral-sh/setup-uv@v6
123
+ with:
124
+ enable-cache: true
125
+ - run: uv sync --frozen --extra redis --python '${{ matrix.python }}'
126
+ - name: Select aiogram compatibility endpoint
127
+ shell: bash
128
+ run: |
129
+ if [ '${{ matrix.aiogram }}' = minimum ]; then
130
+ uv pip install 'aiogram==3.22.0'
131
+ else
132
+ uv pip install --upgrade 'aiogram>=3.22,<4'
133
+ fi
134
+ - run: uv run --no-sync pytest
135
+ - run: uv run --no-sync python examples/demo.py --help
136
+
137
+ redis-compatibility:
138
+ runs-on: ubuntu-latest
139
+ timeout-minutes: 20
140
+ strategy:
141
+ fail-fast: false
142
+ matrix:
143
+ redis: ['redis:7-alpine', 'redis:8-alpine']
144
+ client: [minimum, latest]
145
+ services:
146
+ redis:
147
+ image: ${{ matrix.redis }}
148
+ ports: ['6379:6379']
149
+ options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 10
150
+ env:
151
+ AIOGRAM_IDLE_REDIS_URL: redis://localhost:6379/0
152
+ AIOGRAM_IDLE_REQUIRE_REDIS: '1'
153
+ steps:
154
+ - uses: actions/checkout@v4
155
+ - uses: astral-sh/setup-uv@v6
156
+ - run: uv sync --frozen --extra redis --python 3.12
157
+ - name: Select Redis client endpoint
158
+ shell: bash
159
+ run: |
160
+ if [ '${{ matrix.client }}' = minimum ]; then
161
+ uv pip install 'redis==5.0.8'
162
+ else
163
+ uv pip install --upgrade 'redis>=5.0.8,<8'
164
+ fi
165
+ - run: uv run --no-sync pytest tests/test_redis*.py
166
+
167
+ navigation-integration:
168
+ runs-on: ubuntu-latest
169
+ timeout-minutes: 30
170
+ defaults:
171
+ run:
172
+ working-directory: aiogram-idle
173
+ services:
174
+ redis:
175
+ image: redis:7-alpine
176
+ ports: ['6379:6379']
177
+ options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 10
178
+ env:
179
+ AIOGRAM_IDLE_REDIS_URL: redis://localhost:6379/0
180
+ AIOGRAM_IDLE_REQUIRE_REDIS: '1'
181
+ steps:
182
+ - uses: actions/checkout@v4
183
+ with:
184
+ path: aiogram-idle
185
+ - uses: actions/checkout@v4
186
+ with:
187
+ repository: ArmanAvanesyan/aiogram-nav
188
+ ref: main
189
+ path: aiogram-nav
190
+ - uses: astral-sh/setup-uv@v6
191
+ with:
192
+ enable-cache: true
193
+ cache-dependency-glob: aiogram-idle/uv.lock
194
+ - run: uv sync --frozen --extra redis --extra nav --python 3.12
195
+ - run: uv run --no-sync pyright --project pyright-nav.json
196
+ - run: uv run --no-sync pytest tests/test_nav*.py tests/test_component*.py tests/test_effect_scope_review.py
197
+ - run: uv run --no-sync python examples/navigation.py --help
198
+
199
+ required:
200
+ if: always()
201
+ needs: [quality, documentation, security, compatibility, redis-compatibility, navigation-integration]
202
+ runs-on: ubuntu-latest
203
+ timeout-minutes: 5
204
+ steps:
205
+ - name: Require every verification job to pass
206
+ env:
207
+ JOB_RESULTS: ${{ toJSON(needs) }}
208
+ run: |
209
+ python - <<'PY'
210
+ import json
211
+ import os
212
+ import sys
213
+ outcomes = json.loads(os.environ['JOB_RESULTS'])
214
+ failed = {name: job['result'] for name, job in outcomes.items() if job['result'] != 'success'}
215
+ if failed:
216
+ print('Required verification did not pass:', failed)
217
+ sys.exit(1)
218
+ print('All required verification passed.')
219
+ PY
@@ -0,0 +1,54 @@
1
+ name: Optional navigation integration
2
+ on:
3
+ workflow_dispatch:
4
+ inputs:
5
+ nav_repository:
6
+ description: Compatible aiogram-nav GitHub repository (owner/name)
7
+ required: true
8
+ type: string
9
+ nav_ref:
10
+ description: Compatible reviewed revision
11
+ required: true
12
+ type: string
13
+ permissions:
14
+ contents: read
15
+ jobs:
16
+ combined:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 30
19
+ defaults:
20
+ run:
21
+ working-directory: aiogram-idle
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ python: ['3.10', '3.11', '3.12', '3.13', '3.14']
26
+ redis: ['redis:7-alpine']
27
+ include:
28
+ - python: '3.12'
29
+ redis: 'redis:8-alpine'
30
+ services:
31
+ redis:
32
+ image: ${{ matrix.redis }}
33
+ ports: ['6379:6379']
34
+ options: --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 3s --health-retries 10
35
+ env:
36
+ AIOGRAM_IDLE_REDIS_URL: redis://localhost:6379/0
37
+ AIOGRAM_IDLE_REQUIRE_REDIS: '1'
38
+ steps:
39
+ - uses: actions/checkout@v4
40
+ with:
41
+ path: aiogram-idle
42
+ - uses: actions/checkout@v4
43
+ with:
44
+ repository: ${{ inputs.nav_repository }}
45
+ ref: ${{ inputs.nav_ref }}
46
+ path: aiogram-nav
47
+ - uses: astral-sh/setup-uv@v6
48
+ - run: uv sync --frozen --extra redis --extra nav --python '${{ matrix.python }}'
49
+ - run: uv run --no-sync ruff check .
50
+ - run: uv run --no-sync ruff format --check .
51
+ - run: uv run --no-sync pyright --project pyright-nav.json
52
+ - run: uv run --no-sync pytest --cov=aiogram_idle --cov-config=coverage-nav.toml
53
+ - name: Check optional example CLI without sending messages
54
+ run: uv run --no-sync python examples/navigation.py --help
@@ -0,0 +1,91 @@
1
+ name: Publish verified release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ manifest_sha256:
7
+ description: SHA256 of the independently verified GitHub release SHA256SUMS
8
+ required: true
9
+ type: string
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ concurrency:
15
+ group: publish-${{ github.ref }}
16
+ cancel-in-progress: false
17
+
18
+ jobs:
19
+ verify:
20
+ if: github.ref_type == 'tag' && startsWith(github.ref_name, 'v')
21
+ runs-on: ubuntu-latest
22
+ timeout-minutes: 10
23
+ steps:
24
+ - uses: actions/checkout@v6
25
+ with:
26
+ persist-credentials: false
27
+ - uses: astral-sh/setup-uv@v7
28
+ with:
29
+ python-version: '3.12'
30
+ - name: Download the exact reviewed release artifacts
31
+ env:
32
+ GH_TOKEN: ${{ github.token }}
33
+ run: gh release download "$GITHUB_REF_NAME" --pattern '*.whl' --pattern '*.tar.gz' --pattern SHA256SUMS --dir dist
34
+ - name: Validate tag, distribution names and independently supplied checksums
35
+ env:
36
+ MANIFEST_SHA256: ${{ inputs.manifest_sha256 }}
37
+ run: |
38
+ python - <<'PYVERIFY'
39
+ import hashlib
40
+ import os
41
+ import re
42
+ import tomllib
43
+ from pathlib import Path
44
+ project = tomllib.loads(Path('pyproject.toml').read_text())['project']
45
+ version = project['version']
46
+ if os.environ['GITHUB_REF_NAME'] != 'v' + version:
47
+ raise SystemExit('Tag does not match project version')
48
+ expected_digest = os.environ['MANIFEST_SHA256']
49
+ if not re.fullmatch(r'[a-f0-9]{64}', expected_digest):
50
+ raise SystemExit('Expected an independently verified SHA256 digest')
51
+ manifest = Path('dist/SHA256SUMS')
52
+ if hashlib.sha256(manifest.read_bytes()).hexdigest() != expected_digest:
53
+ raise SystemExit('Release checksum manifest differs from reviewed input')
54
+ name = project['name'].replace('-', '_')
55
+ expected = {f'{name}-{version}-py3-none-any.whl', f'{name}-{version}.tar.gz'}
56
+ if {p.name for p in Path('dist').iterdir()} != expected | {'SHA256SUMS'}:
57
+ raise SystemExit('Unexpected release files')
58
+ checked = set()
59
+ for line in manifest.read_text().splitlines():
60
+ digest, filename = line.split()
61
+ if filename not in expected or filename in checked:
62
+ raise SystemExit('Unexpected or repeated checksum entry')
63
+ if hashlib.sha256((Path('dist') / filename).read_bytes()).hexdigest() != digest:
64
+ raise SystemExit('Distribution checksum mismatch')
65
+ checked.add(filename)
66
+ if checked != expected:
67
+ raise SystemExit('Missing distribution checksum')
68
+ PYVERIFY
69
+ - run: uvx twine check dist/*.whl dist/*.tar.gz
70
+ - uses: actions/upload-artifact@v6
71
+ with:
72
+ name: verified-distributions
73
+ path: |
74
+ dist/*.whl
75
+ dist/*.tar.gz
76
+ if-no-files-found: error
77
+
78
+ publish:
79
+ needs: verify
80
+ runs-on: ubuntu-latest
81
+ timeout-minutes: 10
82
+ environment: pypi
83
+ permissions:
84
+ id-token: write
85
+ steps:
86
+ - uses: actions/download-artifact@v7
87
+ with:
88
+ name: verified-distributions
89
+ path: dist
90
+ - name: Publish verified distributions using PyPI Trusted Publishing
91
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,20 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ .coverage
7
+ htmlcov/
8
+ dist/
9
+ *.egg-info/
10
+ .env
11
+ .env.*
12
+ !.env.example
13
+ site/
14
+ .mypy_cache/
15
+ .pyright/
16
+ coverage.xml
17
+ bandit-report.json
18
+ pip-audit-report.json
19
+ reports/generated/
20
+ .DS_Store
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+
3
+ <!-- towncrier release notes start -->
4
+
5
+ ## [0.1.0] - 2026-11-10
6
+
7
+ ### Miscellaneous
8
+
9
+ - Align repository automation, typed distribution checks, community
10
+ documentation
11
+ and changelog fragments with the related aiogram libraries. Runtime version
12
+ reporting now reads the installed distribution metadata.
13
+
14
+
15
+ ### Core library
16
+
17
+ - Introduce standalone conversation identity, session/activity guards, policies and typed adapter contracts.
18
+ - Add single-process memory storage and a recoverable inactivity lifecycle.
19
+ - Add reply, inline, command and hybrid prompt controls with aiogram dispatcher integration.
20
+ - Include ordinary-handler and FSM examples, deterministic tests and packaging checks.
21
+ - Add optional Redis 7+ storage, renewable distributed coordination, atomic indexes, retained operation receipts and explicit administrative index recovery.
22
+ - Exercise real-server worker races, process crashes, lease expiry, uncertain commits, corruption and memory/Redis parity.
23
+ - Include optional navigation integration as detailed below.
24
+
25
+ ### Memory and lifecycle audit fixes
26
+
27
+ - Share backend coordination across runtimes and verify FSM borrowing/scope lifetimes.
28
+ - Enforce grace deadlines during answer admission and preserve original delivery grace on recovery.
29
+ - Serialize effect stages, preserve typed receipts and retain confirmed subeffects across retry/recovery.
30
+ - Guard reserved business work from reentrant/public mutations and ordinary handler admission.
31
+ - Protect pending evidence, expire administrative receipts, route namespace/bot claims and tag operation lookup results.
32
+ - Expand automated coverage to 168 tests, including 1,000 abandoned-claim recoveries.
33
+
34
+ ### Redis audit fixes
35
+
36
+ - Fence namespace/configuration history, storage profiles and delegated effect checkpoints atomically.
37
+ - Prevent revoked-scope reentry and enforce shared FSM lock order and lossless Redis FSM keys.
38
+ - Repair missing/orphan queue jobs, isolate corrupt work and bind claims/quarantine to validated snapshots.
39
+ - Preserve unknown business-effect ledgers and validate action receipts before completion.
40
+ - Recheck grace before delivery, order heartbeat retries and preserve external cancellation through timeouts.
41
+ - Document backend scope contracts and explicit recovery in docs/redis-audit.md.
42
+
43
+ ### Optional navigation integration
44
+
45
+ - Add the optional nav extra and aiogram_idle.integrations.nav projection without peer imports in either core.
46
+ - Commit navigation/activity/deadline updates in one memory/Redis transaction with mapped sessions and acceptance counters.
47
+ - Resolve inherited node policies, explicit activity groups and guarded touch/restart semantics.
48
+ - Share one coordinator and combined dispatcher middleware with verified FSM borrowing and prompt-control precedence.
49
+ - Stage Continue/Cancel/restore rendering under existing idle operations and preserve exact worker claims through recovery.
50
+ - Park unknown/schema-incompatible recovery without resending; retain typed receipts across process exit and final-commit failure.
51
+ - Restore temporary reply/hybrid keyboard overlays through durable background work and silence restoration sends.
52
+ - Preserve application cancellation uncertainty in a nested business effect stage.
53
+ - Add a runnable four-style example, standalone artifact checks and a separate optional-integration CI matrix.
@@ -0,0 +1,17 @@
1
+ # Changelog fragments
2
+
3
+ Add a short reStructuredText fragment for a user-visible change. Name it
4
+ `<issue>.<type>.rst`, or `+<description>.<type>.rst` when no issue exists.
5
+ Supported types are `feature`, `bugfix`, `doc`, `removal` and `misc`.
6
+
7
+ Describe the resulting behavior for a library consumer. Keep internal details in
8
+ the pull request unless they explain a compatibility or recovery constraint.
9
+
10
+ Preview release notes without modifying files:
11
+
12
+ ```sh
13
+ uv run --no-sync towncrier build --draft --version 0.1.0
14
+ ```
15
+
16
+ Maintainers assemble the changelog as part of the documented release process;
17
+ adding a fragment does not publish or release the package.
@@ -0,0 +1,14 @@
1
+ # Code of conduct
2
+
3
+ Contributors and maintainers should treat each other respectfully. Discuss ideas
4
+ and code on their merits, welcome questions and differing experience, and give
5
+ specific, constructive feedback.
6
+
7
+ Harassment, threats, discriminatory language, personal attacks and disclosure of
8
+ someone else's private information are not acceptable in project spaces.
9
+
10
+ Maintainers may edit or remove inappropriate contributions and restrict access
11
+ when needed to protect participants. Report conduct concerns privately through
12
+ the contact information on the [maintainer's GitHub profile](https://github.com/ArmanAvanesyan),
13
+ sharing only the information needed to investigate. Maintainers should handle
14
+ reports discreetly and consider context when deciding a response.
@@ -0,0 +1,41 @@
1
+ # Contributing
2
+
3
+ Explain the problem in an issue or pull request and include a minimal reproduction
4
+ for bugs. Keep library behavior independent of a consuming bot's business flows.
5
+ Follow the [code of conduct](CODE_OF_CONDUCT.md) and use the
6
+ [security reporting guidance](SECURITY.md) for sensitive findings.
7
+
8
+ ## Development
9
+
10
+ Use Python 3.10 or newer. From the checkout:
11
+
12
+ ```sh
13
+ uv sync --frozen --extra redis --python 3.12
14
+ uv run --no-sync ruff check .
15
+ uv run --no-sync ruff format --check .
16
+ uv run --no-sync pyright
17
+ uv run --no-sync pytest
18
+ uv run --no-sync mkdocs build --strict
19
+ ```
20
+
21
+ Tests requiring a real Redis server are skipped without its URL. For storage,
22
+ recovery or coordination changes, run the required real-server suite as described
23
+ in [testing](docs/testing.md). Use a dedicated server because tests may flush the
24
+ script cache. Never use production Redis or real Telegram credentials in tests.
25
+
26
+ Optional navigation tests require the adjacent compatible `aiogram-nav` checkout
27
+ and `uv sync --frozen --extra nav --extra redis`. Standalone changes must continue
28
+ working without that peer. The [navigation guide](docs/navigation.md) explains
29
+ the separate type and coverage profiles.
30
+
31
+ ## Change conventions
32
+
33
+ - Keep public interfaces typed and include behavior-focused regression tests.
34
+ - Preserve operation receipts, ownership checks and uncertain-effect evidence.
35
+ - Add a [Towncrier fragment](CHANGES/README.md) for user-visible changes.
36
+ - Document compatibility and recovery changes alongside the public behavior.
37
+ - Keep repository automation in `tools/`; do not commit generated audit reports,
38
+ build output, credentials or local environment files.
39
+
40
+ See [testing](docs/testing.md), [repository tools](tools/README.md) and the
41
+ [maintainer release process](docs/releasing.md) for verification commands.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 aiogram-idle contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.