stogger 2026.5.12__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 (213) hide show
  1. stogger-2026.5.12/.agents/drafts/pytest-stogger-new-checks.md +284 -0
  2. stogger-2026.5.12/.agents/impl_specs/logging-decorators-docs.md +91 -0
  3. stogger-2026.5.12/.agents/impl_specs/logging-decorators.md +322 -0
  4. stogger-2026.5.12/.agents/impl_specs/postgres-target.md +255 -0
  5. stogger-2026.5.12/.agents/impl_specs/pytest-stogger-new-checks.md +187 -0
  6. stogger-2026.5.12/.agents/impl_specs/raw-output.md +110 -0
  7. stogger-2026.5.12/.agents/reports/quality-audit.md +371 -0
  8. stogger-2026.5.12/.envrc +2 -0
  9. stogger-2026.5.12/.gitignore +34 -0
  10. stogger-2026.5.12/.pre-commit-config.yaml +26 -0
  11. stogger-2026.5.12/.python-version +1 -0
  12. stogger-2026.5.12/.vulture_whitelist.py +168 -0
  13. stogger-2026.5.12/AGENTS.md +20 -0
  14. stogger-2026.5.12/CONVENTIONS.md +428 -0
  15. stogger-2026.5.12/LICENSE +235 -0
  16. stogger-2026.5.12/PKG-INFO +12 -0
  17. stogger-2026.5.12/README.md +66 -0
  18. stogger-2026.5.12/conftest.py +25 -0
  19. stogger-2026.5.12/coverage.json +1 -0
  20. stogger-2026.5.12/docs/.gitignore +15 -0
  21. stogger-2026.5.12/docs/Makefile +28 -0
  22. stogger-2026.5.12/docs/_build/html/.buildinfo +4 -0
  23. stogger-2026.5.12/docs/_build/html/.doctrees/__intersphinx_cache__/python_objects.inv +0 -0
  24. stogger-2026.5.12/docs/_build/html/.doctrees/__intersphinx_cache__/structlog_objects.inv +0 -0
  25. stogger-2026.5.12/docs/_build/html/.doctrees/api/index.doctree +0 -0
  26. stogger-2026.5.12/docs/_build/html/.doctrees/api/stogger/config/index.doctree +0 -0
  27. stogger-2026.5.12/docs/_build/html/.doctrees/api/stogger/core/index.doctree +0 -0
  28. stogger-2026.5.12/docs/_build/html/.doctrees/api/stogger/factory/index.doctree +0 -0
  29. stogger-2026.5.12/docs/_build/html/.doctrees/api/stogger/index.doctree +0 -0
  30. stogger-2026.5.12/docs/_build/html/.doctrees/api/stogger/processors/index.doctree +0 -0
  31. stogger-2026.5.12/docs/_build/html/.doctrees/dev/adr/format-config-extension.doctree +0 -0
  32. stogger-2026.5.12/docs/_build/html/.doctrees/dev/adr/index.doctree +0 -0
  33. stogger-2026.5.12/docs/_build/html/.doctrees/dev/adr/postgres-target.doctree +0 -0
  34. stogger-2026.5.12/docs/_build/html/.doctrees/dev/adr/stogger-self-logging.doctree +0 -0
  35. stogger-2026.5.12/docs/_build/html/.doctrees/dev/adr/stogger-systemd.doctree +0 -0
  36. stogger-2026.5.12/docs/_build/html/.doctrees/dev/index.doctree +0 -0
  37. stogger-2026.5.12/docs/_build/html/.doctrees/dev/testing_guide.doctree +0 -0
  38. stogger-2026.5.12/docs/_build/html/.doctrees/dev/type_checking_guide.doctree +0 -0
  39. stogger-2026.5.12/docs/_build/html/.doctrees/environment.pickle +0 -0
  40. stogger-2026.5.12/docs/_build/html/.doctrees/index.doctree +0 -0
  41. stogger-2026.5.12/docs/_build/html/.doctrees/user/cheatsheet.doctree +0 -0
  42. stogger-2026.5.12/docs/_build/html/.doctrees/user/getting_started.doctree +0 -0
  43. stogger-2026.5.12/docs/_build/html/.doctrees/user/index.doctree +0 -0
  44. stogger-2026.5.12/docs/_build/html/.doctrees/user/logging_patterns.doctree +0 -0
  45. stogger-2026.5.12/docs/_build/html/.doctrees/user/nix_integration.doctree +0 -0
  46. stogger-2026.5.12/docs/_build/html/.doctrees/user/postgres.doctree +0 -0
  47. stogger-2026.5.12/docs/_build/html/.doctrees/user/systemd.doctree +0 -0
  48. stogger-2026.5.12/docs/_build/html/.doctrees/user/testing.doctree +0 -0
  49. stogger-2026.5.12/docs/_build/html/404.html +324 -0
  50. stogger-2026.5.12/docs/_build/html/_images/stogger_logo_ascii.txt +14 -0
  51. stogger-2026.5.12/docs/_build/html/_modules/index.html +327 -0
  52. stogger-2026.5.12/docs/_build/html/_modules/stogger/config.html +1001 -0
  53. stogger-2026.5.12/docs/_build/html/_modules/stogger/core.html +1442 -0
  54. stogger-2026.5.12/docs/_build/html/_modules/stogger/factory.html +566 -0
  55. stogger-2026.5.12/docs/_build/html/_modules/stogger/processors.html +355 -0
  56. stogger-2026.5.12/docs/_build/html/_sources/api/index.rst.txt +7 -0
  57. stogger-2026.5.12/docs/_build/html/_sources/api/stogger/config/index.rst.txt +320 -0
  58. stogger-2026.5.12/docs/_build/html/_sources/api/stogger/core/index.rst.txt +414 -0
  59. stogger-2026.5.12/docs/_build/html/_sources/api/stogger/factory/index.rst.txt +49 -0
  60. stogger-2026.5.12/docs/_build/html/_sources/api/stogger/index.rst.txt +27 -0
  61. stogger-2026.5.12/docs/_build/html/_sources/api/stogger/processors/index.rst.txt +37 -0
  62. stogger-2026.5.12/docs/_build/html/_sources/dev/adr/format-config-extension.md.txt +159 -0
  63. stogger-2026.5.12/docs/_build/html/_sources/dev/adr/index.md.txt +10 -0
  64. stogger-2026.5.12/docs/_build/html/_sources/dev/adr/postgres-target.md.txt +208 -0
  65. stogger-2026.5.12/docs/_build/html/_sources/dev/adr/stogger-self-logging.md.txt +125 -0
  66. stogger-2026.5.12/docs/_build/html/_sources/dev/adr/stogger-systemd.md.txt +203 -0
  67. stogger-2026.5.12/docs/_build/html/_sources/dev/index.md.txt +8 -0
  68. stogger-2026.5.12/docs/_build/html/_sources/dev/testing_guide.md.txt +174 -0
  69. stogger-2026.5.12/docs/_build/html/_sources/dev/type_checking_guide.md.txt +147 -0
  70. stogger-2026.5.12/docs/_build/html/_sources/index.md.txt +71 -0
  71. stogger-2026.5.12/docs/_build/html/_sources/user/cheatsheet.md.txt +115 -0
  72. stogger-2026.5.12/docs/_build/html/_sources/user/getting_started.md.txt +93 -0
  73. stogger-2026.5.12/docs/_build/html/_sources/user/index.md.txt +13 -0
  74. stogger-2026.5.12/docs/_build/html/_sources/user/logging_patterns.md.txt +429 -0
  75. stogger-2026.5.12/docs/_build/html/_sources/user/nix_integration.md.txt +79 -0
  76. stogger-2026.5.12/docs/_build/html/_sources/user/postgres.md.txt +187 -0
  77. stogger-2026.5.12/docs/_build/html/_sources/user/systemd.md.txt +180 -0
  78. stogger-2026.5.12/docs/_build/html/_sources/user/testing.md.txt +156 -0
  79. stogger-2026.5.12/docs/_build/html/_sphinx_design_static/design-tabs.js +101 -0
  80. stogger-2026.5.12/docs/_build/html/_sphinx_design_static/sphinx-design.min.css +1 -0
  81. stogger-2026.5.12/docs/_build/html/_static/base-stemmer.js +476 -0
  82. stogger-2026.5.12/docs/_build/html/_static/basic.css +906 -0
  83. stogger-2026.5.12/docs/_build/html/_static/check-solid.svg +4 -0
  84. stogger-2026.5.12/docs/_build/html/_static/clipboard.min.js +7 -0
  85. stogger-2026.5.12/docs/_build/html/_static/copy-button.svg +5 -0
  86. stogger-2026.5.12/docs/_build/html/_static/copybutton.css +94 -0
  87. stogger-2026.5.12/docs/_build/html/_static/copybutton.js +248 -0
  88. stogger-2026.5.12/docs/_build/html/_static/copybutton_funcs.js +73 -0
  89. stogger-2026.5.12/docs/_build/html/_static/debug.css +69 -0
  90. stogger-2026.5.12/docs/_build/html/_static/design-tabs.js +101 -0
  91. stogger-2026.5.12/docs/_build/html/_static/doctools.js +150 -0
  92. stogger-2026.5.12/docs/_build/html/_static/documentation_options.js +13 -0
  93. stogger-2026.5.12/docs/_build/html/_static/english-stemmer.js +1066 -0
  94. stogger-2026.5.12/docs/_build/html/_static/file.png +0 -0
  95. stogger-2026.5.12/docs/_build/html/_static/graphviz.css +12 -0
  96. stogger-2026.5.12/docs/_build/html/_static/language_data.js +13 -0
  97. stogger-2026.5.12/docs/_build/html/_static/minus.png +0 -0
  98. stogger-2026.5.12/docs/_build/html/_static/plus.png +0 -0
  99. stogger-2026.5.12/docs/_build/html/_static/pygments.css +250 -0
  100. stogger-2026.5.12/docs/_build/html/_static/scripts/furo-extensions.js +0 -0
  101. stogger-2026.5.12/docs/_build/html/_static/scripts/furo.js +3 -0
  102. stogger-2026.5.12/docs/_build/html/_static/scripts/furo.js.LICENSE.txt +7 -0
  103. stogger-2026.5.12/docs/_build/html/_static/scripts/furo.js.map +1 -0
  104. stogger-2026.5.12/docs/_build/html/_static/searchtools.js +693 -0
  105. stogger-2026.5.12/docs/_build/html/_static/skeleton.css +296 -0
  106. stogger-2026.5.12/docs/_build/html/_static/sphinx-design.min.css +1 -0
  107. stogger-2026.5.12/docs/_build/html/_static/sphinx_highlight.js +159 -0
  108. stogger-2026.5.12/docs/_build/html/_static/styles/furo-extensions.css +2 -0
  109. stogger-2026.5.12/docs/_build/html/_static/styles/furo-extensions.css.map +1 -0
  110. stogger-2026.5.12/docs/_build/html/_static/styles/furo.css +2 -0
  111. stogger-2026.5.12/docs/_build/html/_static/styles/furo.css.map +1 -0
  112. stogger-2026.5.12/docs/_build/html/_static/togglebutton.css +166 -0
  113. stogger-2026.5.12/docs/_build/html/_static/togglebutton.js +257 -0
  114. stogger-2026.5.12/docs/_build/html/api/index.html +368 -0
  115. stogger-2026.5.12/docs/_build/html/api/stogger/config/index.html +770 -0
  116. stogger-2026.5.12/docs/_build/html/api/stogger/core/index.html +1022 -0
  117. stogger-2026.5.12/docs/_build/html/api/stogger/factory/index.html +471 -0
  118. stogger-2026.5.12/docs/_build/html/api/stogger/index.html +394 -0
  119. stogger-2026.5.12/docs/_build/html/api/stogger/processors/index.html +421 -0
  120. stogger-2026.5.12/docs/_build/html/dev/adr/format-config-extension.html +640 -0
  121. stogger-2026.5.12/docs/_build/html/dev/adr/index.html +368 -0
  122. stogger-2026.5.12/docs/_build/html/dev/adr/postgres-target.html +691 -0
  123. stogger-2026.5.12/docs/_build/html/dev/adr/stogger-self-logging.html +548 -0
  124. stogger-2026.5.12/docs/_build/html/dev/adr/stogger-systemd.html +666 -0
  125. stogger-2026.5.12/docs/_build/html/dev/index.html +367 -0
  126. stogger-2026.5.12/docs/_build/html/dev/testing_guide.html +583 -0
  127. stogger-2026.5.12/docs/_build/html/dev/type_checking_guide.html +531 -0
  128. stogger-2026.5.12/docs/_build/html/genindex.html +746 -0
  129. stogger-2026.5.12/docs/_build/html/index.html +456 -0
  130. stogger-2026.5.12/docs/_build/html/llms-full.txt +3088 -0
  131. stogger-2026.5.12/docs/_build/html/llms.txt +29 -0
  132. stogger-2026.5.12/docs/_build/html/objects.inv +0 -0
  133. stogger-2026.5.12/docs/_build/html/py-modindex.html +365 -0
  134. stogger-2026.5.12/docs/_build/html/search.html +337 -0
  135. stogger-2026.5.12/docs/_build/html/searchindex.js +1 -0
  136. stogger-2026.5.12/docs/_build/html/user/cheatsheet.html +533 -0
  137. stogger-2026.5.12/docs/_build/html/user/getting_started.html +479 -0
  138. stogger-2026.5.12/docs/_build/html/user/index.html +371 -0
  139. stogger-2026.5.12/docs/_build/html/user/logging_patterns.html +893 -0
  140. stogger-2026.5.12/docs/_build/html/user/nix_integration.html +473 -0
  141. stogger-2026.5.12/docs/_build/html/user/postgres.html +627 -0
  142. stogger-2026.5.12/docs/_build/html/user/systemd.html +610 -0
  143. stogger-2026.5.12/docs/_build/html/user/testing.html +542 -0
  144. stogger-2026.5.12/docs/api/index.rst +7 -0
  145. stogger-2026.5.12/docs/api/stogger/config/index.rst +320 -0
  146. stogger-2026.5.12/docs/api/stogger/core/index.rst +414 -0
  147. stogger-2026.5.12/docs/api/stogger/factory/index.rst +49 -0
  148. stogger-2026.5.12/docs/api/stogger/index.rst +27 -0
  149. stogger-2026.5.12/docs/api/stogger/processors/index.rst +37 -0
  150. stogger-2026.5.12/docs/assets/stogger_logo_ascii.txt +14 -0
  151. stogger-2026.5.12/docs/conf.py +176 -0
  152. stogger-2026.5.12/docs/dev/adr/format-config-extension.md +159 -0
  153. stogger-2026.5.12/docs/dev/adr/index.md +10 -0
  154. stogger-2026.5.12/docs/dev/adr/postgres-target.md +208 -0
  155. stogger-2026.5.12/docs/dev/adr/stogger-self-logging.md +125 -0
  156. stogger-2026.5.12/docs/dev/adr/stogger-systemd.md +203 -0
  157. stogger-2026.5.12/docs/dev/index.md +8 -0
  158. stogger-2026.5.12/docs/dev/testing_guide.md +174 -0
  159. stogger-2026.5.12/docs/dev/type_checking_guide.md +147 -0
  160. stogger-2026.5.12/docs/index.md +71 -0
  161. stogger-2026.5.12/docs/user/cheatsheet.md +115 -0
  162. stogger-2026.5.12/docs/user/getting_started.md +93 -0
  163. stogger-2026.5.12/docs/user/index.md +13 -0
  164. stogger-2026.5.12/docs/user/logging_patterns.md +429 -0
  165. stogger-2026.5.12/docs/user/nix_integration.md +79 -0
  166. stogger-2026.5.12/docs/user/postgres.md +187 -0
  167. stogger-2026.5.12/docs/user/systemd.md +180 -0
  168. stogger-2026.5.12/docs/user/testing.md +156 -0
  169. stogger-2026.5.12/examples/demo/pyproject.toml +35 -0
  170. stogger-2026.5.12/examples/demo/src/demo/__init__.py +3 -0
  171. stogger-2026.5.12/examples/demo/src/demo/__main__.py +11 -0
  172. stogger-2026.5.12/examples/demo/src/demo/cli/__init__.py +0 -0
  173. stogger-2026.5.12/examples/demo/src/demo/cli/commands.py +79 -0
  174. stogger-2026.5.12/examples/demo/src/demo/service/__init__.py +0 -0
  175. stogger-2026.5.12/examples/demo/src/demo/service/orders.py +91 -0
  176. stogger-2026.5.12/examples/demo/tests/test_conventions.py +90 -0
  177. stogger-2026.5.12/examples/demo/tests/test_coverage.py +57 -0
  178. stogger-2026.5.12/examples/demo/uv.lock +361 -0
  179. stogger-2026.5.12/flake.nix +366 -0
  180. stogger-2026.5.12/packages/stogger-postgres/pyproject.toml +24 -0
  181. stogger-2026.5.12/packages/stogger-postgres/src/stogger_postgres/__init__.py +114 -0
  182. stogger-2026.5.12/pyproject.toml +196 -0
  183. stogger-2026.5.12/scripts/extract_logs.py +57 -0
  184. stogger-2026.5.12/src/stogger/__init__.py +72 -0
  185. stogger-2026.5.12/src/stogger/_colors.py +23 -0
  186. stogger-2026.5.12/src/stogger/_decorators.py +478 -0
  187. stogger-2026.5.12/src/stogger/_regexes.py +20 -0
  188. stogger-2026.5.12/src/stogger/_types.py +17 -0
  189. stogger-2026.5.12/src/stogger/config.py +660 -0
  190. stogger-2026.5.12/src/stogger/core.py +1035 -0
  191. stogger-2026.5.12/src/stogger/factory.py +234 -0
  192. stogger-2026.5.12/src/stogger/processors.py +29 -0
  193. stogger-2026.5.12/stubs/stogger_systemd/__init__.pyi +20 -0
  194. stogger-2026.5.12/tests/__init__.py +1 -0
  195. stogger-2026.5.12/tests/conftest.py +15 -0
  196. stogger-2026.5.12/tests/impl_spec/__init__.py +0 -0
  197. stogger-2026.5.12/tests/impl_spec/test_format_config_extension.py +373 -0
  198. stogger-2026.5.12/tests/impl_spec/test_logging_decorators.py +487 -0
  199. stogger-2026.5.12/tests/impl_spec/test_postgres_target.py +327 -0
  200. stogger-2026.5.12/tests/impl_spec/test_stogger_self_logging.py +337 -0
  201. stogger-2026.5.12/tests/test_architecture.py +57 -0
  202. stogger-2026.5.12/tests/test_config.py +454 -0
  203. stogger-2026.5.12/tests/test_core.py +869 -0
  204. stogger-2026.5.12/tests/test_decorators.py +234 -0
  205. stogger-2026.5.12/tests/test_e2e_single_module_app.py +167 -0
  206. stogger-2026.5.12/tests/test_exception_logging.py +23 -0
  207. stogger-2026.5.12/tests/test_factory.py +360 -0
  208. stogger-2026.5.12/tests/test_integration.py +172 -0
  209. stogger-2026.5.12/tests/test_postgres_integration.py +187 -0
  210. stogger-2026.5.12/tests/test_postgres_integration_real.py +38 -0
  211. stogger-2026.5.12/tests/test_systemd_integration.py +153 -0
  212. stogger-2026.5.12/tests/test_systemd_integration_real.py +35 -0
  213. stogger-2026.5.12/uv.lock +1340 -0
@@ -0,0 +1,284 @@
1
+ ---
2
+ lifecycle:
3
+ requirements:
4
+ completed_at: "2026-05-03T18:00:00Z"
5
+ git_rev: c4f0f2b
6
+ ---
7
+
8
+ ## Problem
9
+
10
+ pytest-stogger erzwingt 12 AST-basierte Logging-Konventionen. Basierend auf einem Sample von ~280 Log-Statements aus 3 Projekten (batou-type, code-rag, docdisco) wurden 6 Lücken identifiziert, die zu unnötigem Log-Noise, fehlendem Context und ungenutztem Structlog-Potential führen.
11
+
12
+ ## Binding Decisions
13
+
14
+ ### scope-batch
15
+
16
+ #### Context
17
+
18
+ Es gibt 6 vorgeschlagene Checks. Zu viele auf einmal risking Qualität, zu wenige liefern nicht den erwarteten Mehrwert.
19
+
20
+ #### Decision
21
+
22
+ Alle 6 Checks in einem Durchgang umsetzen:
23
+ 1. `log-consolidate-repeated` — 3+ Log-Calls in direkter Folge mit shared Context → zusammenfassen
24
+ 2. `log-debug-context-range` — max 5 key-value pairs bei DEBUG
25
+ 3. `log-bind-threshold` — wiederholter key-value 3+ Mal → log.bind() nutzen
26
+ 4. `log-exception-not-in-except` — log.exception() außerhalb except-Block
27
+ 5. `log-error-in-except` — log.error() in except-Block statt log.exception()
28
+ 6. `log-warning-for-not-found` — WARNING bei "not found" Event-IDs
29
+
30
+ #### Alternatives
31
+
32
+ a. Nur Top 3 — schneller, aber Lücken bleiben
33
+ b. Nur 1 MVP — zu wenig Impact
34
+
35
+ #### Consequences
36
+
37
+ Größerer Durchgang, aber alle Checks folgen demselben Registry-Pattern und teilen Helper-Funktionen.
38
+
39
+ ### consolidate-severity
40
+
41
+ #### Context
42
+
43
+ Die Consolidation-Heuristik hat False Positives bei legitimen Multi-Step-Logging.
44
+
45
+ #### Decision
46
+
47
+ Config-gesteuert: Default WARNING, kann per Config auf ERROR gestellt werden via `consolidate_as_error = true`.
48
+
49
+ #### Alternatives
50
+
51
+ a. Immer WARNING — zu schwach für CI
52
+ b. Immer ERROR — zu viele False Positives
53
+
54
+ #### Consequences
55
+
56
+ Neue Config-Option `consolidate_as_error` in `[tool.pytest-stogger]`.
57
+
58
+ ### debug-range-config
59
+
60
+ #### Context
61
+
62
+ Konvention ist "2-3 key-values normal, max 5". Braucht das einen konfigurierbaren Schwellwert?
63
+
64
+ #### Decision
65
+
66
+ Fester Wert 5 — hardcoded wie die meisten Rules. Kein Config-Overhead.
67
+
68
+ #### Alternatives
69
+
70
+ a. Per Config (debug_max_context) — flexibel aber unnötig
71
+ b. Nur Warning bei >7 — zu großzügig
72
+
73
+ #### Consequences
74
+
75
+ Hardgrenze bei 5 key-value pairs für DEBUG. Darüber → Violation.
76
+
77
+ ### exception-placement
78
+
79
+ #### Context
80
+
81
+ log.exception() erzeugt einen Stacktrace — ohne except-Block ist das sinnlos oder verwirrend.
82
+
83
+ #### Decision
84
+
85
+ Eigenständiger Check: `log-exception-not-in-except`. log.exception() nur erlaubt innerhalb von except-Blöcken.
86
+
87
+ #### Alternatives
88
+
89
+ a. Mit Inline-Ignore — nicht nötig, klarer Fix
90
+ b. Nicht umsetzen — zu noisy
91
+
92
+ #### Consequences
93
+
94
+ Klare Rule mit klarer Migration: exception() → error() wenn außerhalb von except.
95
+
96
+ ### consolidate-message-ux
97
+
98
+ #### Context
99
+
100
+ Fehlermeldungen müssen dem User helfen, nicht nur informieren.
101
+
102
+ #### Decision
103
+
104
+ Zeige Merge-Vorschlag: betroffene Zeilen + konkreter Vorschlag wie die zusammengefasste Statement aussehen könnte.
105
+
106
+ #### Alternatives
107
+
108
+ a. Nur Zeilen + Count — nicht hilfreich genug
109
+ b. Diff-Style — zu komplex für ersten Wurf
110
+
111
+ #### Consequences
112
+
113
+ Die Violation-Message enthält ein konkretes Code-Beispiel.
114
+
115
+ ## Scope Boundaries
116
+
117
+ - INCLUDE: 6 neue File-Rules im bestehenden Registry-Pattern
118
+ - INCLUDE: Neue Config-Option `consolidate_as_error`
119
+ - EXCLUDE: Changes an bestehenden Rules
120
+ - EXCLUDE: Changes am logging-coverage Check
121
+ - EXCLUDE: Autofix-Funktionalität (nur Detection)
122
+
123
+ ## Open Questions
124
+
125
+ - Severity der restlichen 5 Checks (ERROR wie bestehende Rules?)
126
+ - Default-Severity für bind-threshold und error-in-except
127
+ - Interface: wie werden die neuen Rules in --help und Status-Output sichtbar?
128
+
129
+ ### severity-strategy
130
+
131
+ #### Context
132
+
133
+ 6 neue Checks mit unterschiedlicher Heuristik-Qualität. Klare AST-basierte Rules können ERROR sein, heuristische sollten WARNING sein.
134
+
135
+ #### Decision
136
+
137
+ Gemischt:
138
+ - ERROR: `log-exception-not-in-except`, `log-error-in-except`, `log-debug-context-range`, `log-bind-threshold`
139
+ - WARNING (config-steuerbar): `log-consolidate-repeated`, `log-warning-for-not-found`
140
+
141
+ #### Alternatives
142
+
143
+ a. Alle ERROR — zu streng für heuristische Checks
144
+ b. Alle WARNING — zu schwach für klare Rules
145
+
146
+ #### Consequences
147
+
148
+ Zwei Severity-Level in der Rule-Architektur. Needs flag `needs_warning_severity` auf _RuleSpec oder Config-basiert.
149
+
150
+ ### error-in-except-severity
151
+
152
+ #### Context
153
+
154
+ log.error() in except-Block verliert den Stacktrace — suboptimal aber nicht falsch.
155
+
156
+ #### Decision
157
+
158
+ ERROR — strenger als ursprünglich empfohlen. log.exception() ist in except-Blöcken immer die bessere Wahl.
159
+
160
+ #### Alternatives
161
+
162
+ a. WARNING — weniger Breakage aber schwächer
163
+ b. Nicht umsetzen — bestehende no-log-info-in-except reicht
164
+
165
+ #### Consequences
166
+
167
+ Migration: alle log.error() in except-Blöcken → log.exception(). Inline-Ignore möglich.
168
+
169
+ ### warning-not-found-fp
170
+
171
+ #### Context
172
+
173
+ Pattern-Matching auf Event-IDs (*-not-found, *-missing, *-absent) hat False Positives.
174
+
175
+ #### Decision
176
+
177
+ Inline-Ignore: # stogger: ignore log-warning-for-not-found für legitime Fälle.
178
+
179
+ #### Alternatives
180
+
181
+ a. Exempt-List in Config — flexibel aber Config-Bloat
182
+ b. Nicht umsetzen — zu heuristisch
183
+
184
+ #### Consequences
185
+
186
+ Neue Rule mit needs_inline_ignores=True Flag.
187
+
188
+ ### bind-threshold-value
189
+
190
+ #### Context
191
+
192
+ Wiederholter key-value in Scope → log.bind() nutzen.
193
+
194
+ #### Decision
195
+
196
+ Schwellwert 3 — konsistent mit bestehender check_bind_for_repeating die auch bei 3 Wiederholungen triggert.
197
+
198
+ #### Alternatives
199
+
200
+ a. 2 Mal — strenger
201
+ b. Config-gesteuert — unnötig, 3 ist bewährt
202
+
203
+ #### Consequences
204
+
205
+ Konsistente Schwelle im Codebase. Kein neuer Config-Wert nötig.
206
+
207
+ ## Scope Boundaries (Updated)
208
+
209
+ - INCLUDE: 6 neue File-Rules im bestehenden Registry-Pattern
210
+ - INCLUDE: Neue Config-Option `consolidate_as_error`
211
+ - INCLUDE: Severity-Level ERROR vs WARNING für neue Rules
212
+ - EXCLUDE: Changes an bestehenden Rules
213
+ - EXCLUDE: Changes am logging-coverage Check
214
+ - EXCLUDE: Autofix-Funktionalität (nur Detection)
215
+
216
+ ### warning-pytest-output
217
+
218
+ #### Context
219
+
220
+ WARNING-Level Rules sollen den Test nicht failen lassen, aber sichtbar sein.
221
+
222
+ #### Decision
223
+
224
+ Normale `pytest.warning` — Test besteht, Warning wird angezeigt. Konsistent mit Python-Warnings.
225
+
226
+ #### Alternatives
227
+
228
+ a. Eigener Item-Typ — zu komplex
229
+ b. Nur in Summary — nicht prominent genug
230
+
231
+ #### Consequences
232
+
233
+ Plugin nutzt `warnings.warn()` statt `StoggerViolationError` für WARNING-Level Rules.
234
+
235
+ ### warning-flag-architecture
236
+
237
+ #### Context
238
+
239
+ Rule-Architektur braucht ein Konzept für Severity-Level.
240
+
241
+ #### Decision
242
+
243
+ Neues Flag `is_warning: bool = False` auf `_RuleSpec`. Plugin entscheidet basierend auf Flag ob ERROR oder WARNING.
244
+
245
+ #### Alternatives
246
+
247
+ a. Config pro Rule — flexibel aber Config-Bloat
248
+ b. Separate Rule-Liste — dupliziert Architektur
249
+
250
+ #### Consequences
251
+
252
+ Neues Feld auf _RuleSpec. Plugin.py muss zwei Pfade haben: ERROR-Path (bestehend) + WARNING-Path (neu, via warnings.warn).
253
+
254
+ ### discoverability
255
+
256
+ #### Context
257
+
258
+ Neue Rules sollen für Consumer-Projekte sofort nützlich sein.
259
+
260
+ #### Decision
261
+
262
+ Automatisch sichtbar — Zero-Config. Neue Rules laufen wie bestehende, werden im Test-Output sichtbar.
263
+
264
+ #### Alternatives
265
+
266
+ a. Disabled per Default — sicher aber weniger nützlich
267
+
268
+ #### Consequences
269
+
270
+ Consumer-Projekte sehen neue Rules sofort. WARNING-Level Rules brechen nicht, ERROR-Level Rules können per disable_rules deaktiviert werden.
271
+
272
+ ## Scope Boundaries (Final)
273
+
274
+ - INCLUDE: 6 neue File-Rules im bestehenden Registry-Pattern
275
+ - INCLUDE: Neues `is_warning` Flag auf `_RuleSpec`
276
+ - INCLUDE: WARNING-Path via `warnings.warn()` in plugin.py
277
+ - INCLUDE: Neue Config-Option `consolidate_as_error`
278
+ - EXCLUDE: Changes an bestehenden Rules
279
+ - EXCLUDE: Changes am logging-coverage Check
280
+ - EXCLUDE: Autofix-Funktionalität (nur Detection)
281
+
282
+ - Interface: wie werden die neuen Rules in --help und Status-Output sichtbar?
283
+ - Brauchen wir ein neues `needs_warning_severity` Flag auf `_RuleSpec`?
284
+ - Wie wird WARNING im pytest-Output dargestellt? ( eigenes Item-Type oder nur in Summary?)
@@ -0,0 +1,91 @@
1
+ ---
2
+ lifecycle:
3
+ requirements:
4
+ completed_at: "2026-05-04T14:00:00Z"
5
+ git_rev: "be50a11"
6
+ ---
7
+
8
+ # logging-decorators-docs
9
+
10
+ ## Context
11
+
12
+ The logging decorators (`log_call`, `log_result`, `log_operation`, `log_scope`) are implemented and functional (commit be50a11) but documentation-invisible. Docstrings lack structured parameter docs. Autoapi skips `_decorators.py` (underscore prefix). No user-facing prose exists. Users cannot discover or learn the decorators through docs.
13
+
14
+ ## Decisions
15
+
16
+ ### docstring-quality
17
+
18
+ #### Context
19
+
20
+ Existing docstrings describe behavior in 1-2 sentences but omit structured parameter documentation, return types, raised exceptions, and usage examples. Other stogger public APIs (e.g., `init_logging`) have full Args/Returns/Raises docstrings.
21
+
22
+ #### Decision
23
+
24
+ Enrich all 5 public docstrings (`log_call`, `log_result`, `log_operation`, `log_scope`, `LogScope`) with Google-style Args, Returns, Raises, and Examples sections. Match the quality of `init_logging` in `core.py`.
25
+
26
+ #### Alternatives
27
+
28
+ a. Numpy-style docstrings — inconsistent with existing codebase convention
29
+ b. Minimal docstrings + separate docs — forces users to look in two places
30
+
31
+ #### Consequences
32
+
33
+ `help(log_call)` and generated API docs both show complete usage information. Single source of truth per function.
34
+
35
+ ### api-docs-visibility
36
+
37
+ #### Context
38
+
39
+ Autoapi skips `_decorators.py` because the `autoapi_skip_member` hook in `conf.py` rejects names starting with `_`. The re-exports in `core.py` are bare imports (`# noqa: F401`) so autoapi doesn't document them either. Generated `docs/api/stogger/core/index.rst` has zero decorator entries.
40
+
41
+ #### Decision
42
+
43
+ Add manual Sphinx directives to `docs/api/stogger/core/index.rst` for the 5 re-exported names. Use `.. py:function::` for decorators and `.. py:class::` for `LogScope`, with `:canonical:` pointing to `stogger._decorators` source. This keeps the private module hidden while surfacing the public API.
44
+
45
+ #### Alternatives
46
+
47
+ a. Modify `autoapi_skip_member` to allow `_decorators` — exposes private module internals
48
+ b. Move decorators to public `decorators.py` — violates architecture decision (Layer 2 placement)
49
+
50
+ #### Consequences
51
+
52
+ Decorators appear in generated HTML docs under `stogger.core`. Source links go to `_decorators.py` which is acceptable since users navigate via public API, not module internals.
53
+
54
+ ### user-guide-integration
55
+
56
+ #### Context
57
+
58
+ `docs/user/logging_patterns.md` has manual "Function Tracing" and "Timing Operations" patterns that are exactly what the decorators automate. Users reading that page have no indication that decorators exist.
59
+
60
+ #### Decision
61
+
62
+ Add a new "Decorators" section to `logging_patterns.md` after the "Common Patterns" section. Cover all 4 features (`@log_call`, `@log_result`, `@log_operation`, `log_scope()`) with practical examples. Cross-reference from the existing "Function Tracing" and "Timing Operations" subsections.
63
+
64
+ #### Alternatives
65
+
66
+ a. New standalone page `docs/user/decorators.md` — fragments the logging patterns narrative
67
+ b. No user guide, rely on API docs only — poor discoverability for new users
68
+
69
+ #### Consequences
70
+
71
+ Users reading logging patterns naturally discover decorators. Single coherent page covers manual and automated approaches.
72
+
73
+ ## Requirements
74
+
75
+ ### Files to Modify
76
+
77
+ - **Modify**: `src/stogger/_decorators.py` — enriched docstrings for all 5 public names
78
+ - **Modify**: `docs/api/stogger/core/index.rst` — add decorator entries to summary lists and module contents
79
+ - **Modify**: `docs/user/logging_patterns.md` — add "Decorators" section with examples
80
+
81
+ ### Docstring Requirements
82
+
83
+ Each decorator must document: Args (func, include_args, exclude_args with types and semantics), event format (fields emitted), exception behavior. `LogScope` must document constructor args, `add_fields`, enter/exit lifecycle, async support. `log_scope` must document name and **fields parameters. All must include a 2-3 line usage example.
84
+
85
+ ### User Guide Requirements
86
+
87
+ New section must show: basic usage of all 4 features, arg filtering example, exception handling example, async usage. Each example must be self-contained and runnable.
88
+
89
+ ## References
90
+
91
+ - `.agents/impl_specs/logging-decorators.md` — original implementation spec with event schemas and interface contracts
@@ -0,0 +1,322 @@
1
+ ---
2
+ lifecycle:
3
+ requirements:
4
+ completed_at: "2026-05-03T12:00:00Z"
5
+ git_rev: "c4f0f2b"
6
+ design:
7
+ completed_at: "2026-05-03T12:30:00Z"
8
+ git_rev: "c4f0f2b"
9
+ implement:
10
+ completed_at: "2026-05-03T13:00:00Z"
11
+ git_rev: "1682052"
12
+ ---
13
+
14
+ # logging-decorators
15
+
16
+ ## Context
17
+
18
+ Stogger has no decorators or context managers for structured logging. Users must manually write `log.info("called", func=..., args={...})`. Three named decorators and one context manager will provide structured call/result logging that integrates with the existing structlog pipeline.
19
+
20
+ ## Decisions
21
+
22
+ ### module-placement
23
+
24
+ #### Context
25
+
26
+ New code must fit the existing layered architecture enforced by pytest-archon. core.py is already 951 lines and should not grow further.
27
+
28
+ #### Decision
29
+
30
+ New private module `src/stogger/_decorators.py` at Layer 2. Imports `_types` and `structlog`. Re-exported through `core.py` → `__init__.py`. Registered in `test_architecture.py` with Layer 2 rules (may import `_types`, `config`; may not import `factory` or `__init__`).
31
+
32
+ #### Alternatives
33
+
34
+ a. Add to core.py — would push it past 1100 lines, no separation of concerns
35
+ b. Public `decorators.py` at Layer 1 — cannot import `_types`, would need duplicate EventDict
36
+
37
+ #### Consequences
38
+
39
+ Clean module boundary. Architecture enforcement covers the new code from day one.
40
+
41
+ ### decorator-variants
42
+
43
+ #### Context
44
+
45
+ Users need different granularity levels for function-call logging. Three named decorators are more discoverable than one configurable decorator.
46
+
47
+ #### Decision
48
+
49
+ Three decorators with distinct semantics:
50
+
51
+ 1. `@log_call` — logs at entry. Event: `event="called"`, `func="module.qualname"`, `args={...}`. No result, no duration.
52
+ 2. `@log_result` — logs at exit. Event: `event="returned"`, `func="module.qualname"`, `result=...`, `duration_ms=...`. No args.
53
+ 3. `@log_operation` — logs at exit. Event: `event="operation"`, `func="module.qualname"`, `args={...}`, `result=...`, `duration_ms=...`. Everything in one event.
54
+
55
+ All three share: sync+async support, `include_args`/`exclude_args` filtering, auto-logger via `structlog.get_logger()`, exception logging with re-raise, automatic `self`/`cls` filtering.
56
+
57
+ #### Alternatives
58
+
59
+ a. Single decorator with mode parameter — less discoverable, obscures intent
60
+ b. Eliot-style start/end event pairs — doubles output, adds complexity
61
+
62
+ #### Consequences
63
+
64
+ Three explicit import paths. Users choose by intent: invocation tracking (`log_call`), result tracking (`log_result`), full audit (`log_operation`).
65
+
66
+ ### scope-object-design
67
+
68
+ #### Context
69
+
70
+ The `log_scope()` context manager needs state (start time, bound fields, accumulated fields) and explicit enter/exit behavior including exception handling.
71
+
72
+ #### Decision
73
+
74
+ `LogScope` class with `__enter__`/`__exit__`. On enter: binds fields via structlog context. On exit: logs `scope_end` event with duration and accumulated fields. On exception: logs `scope_failed` event with `exc_type`/`exc_msg`, then re-raises. `add_fields(**kwargs)` method for mid-scope enrichment. Factory function `log_scope(name, **fields)` returns a `LogScope` instance.
75
+
76
+ Async support via `__aenter__`/`__aexit__` on the same class.
77
+
78
+ #### Alternatives
79
+
80
+ a. Generator-based `@contextmanager` — requires separate `@asynccontextmanager` for async
81
+ b. Two separate classes for sync/async — doubles code
82
+
83
+ #### Consequences
84
+
85
+ Single class handles both sync and async. Stateful object enables `add_fields()` accumulation.
86
+
87
+ ### async-support
88
+
89
+ #### Context
90
+
91
+ Python ≥3.14. All decorators and context manager must work with both sync and async functions.
92
+
93
+ #### Decision
94
+
95
+ Each decorator uses `inspect.iscoroutinefunction(wrapped_function)` at decoration time. Returns either a sync wrapper or an async wrapper accordingly. No runtime check overhead — the check happens once at import/decoration time.
96
+
97
+ For `LogScope`: implements both `__enter__`/`__exit__` and `__aenter__`/`__aexit__`. Python automatically calls the correct protocol based on `with` vs `async with`.
98
+
99
+ #### Alternatives
100
+
101
+ a. Single sync wrapper — breaks async functions
102
+ b. Runtime isinstance(result, Coroutine) check — overhead on every call
103
+
104
+ #### Consequences
105
+
106
+ Zero runtime overhead for the sync/async dispatch. Two code paths per decorator, but they share arg-extraction and logging logic.
107
+
108
+ ### arg-extraction
109
+
110
+ #### Context
111
+
112
+ Need `args={'x': 1, 'y': 2}` in events. `inspect.getcallargs` is removed in Python 3.14.
113
+
114
+ #### Decision
115
+
116
+ `inspect.signature(wrapped_function)` + `sig.bind(*args, **kwargs)` + `bound.apply_defaults()`. This resolves positional args, keyword args, and defaults into a plain dict. Then apply `include_args`/`exclude_args` filtering and strip `self`/`cls`.
117
+
118
+ #### Alternatives
119
+
120
+ a. Manual dict construction — loses parameter names and defaults
121
+ b. `locals()` capture — unreliable with decorators
122
+
123
+ #### Consequences
124
+
125
+ Correct arg resolution including defaults. Standard pattern that works with Python 3.14+.
126
+
127
+ ### duration-measurement
128
+
129
+ #### Context
130
+
131
+ `@log_result`, `@log_operation`, and `log_scope()` all need `duration_ms`.
132
+
133
+ #### Decision
134
+
135
+ `time.perf_counter()` — capture `t0` at entry, compute `(perf_counter() - t0) * 1000` at exit. Highest resolution, monotonic, no NTP drift.
136
+
137
+ #### Alternatives
138
+
139
+ a. `time.monotonic` — practically equivalent on Linux, lower resolution on some platforms
140
+ b. Event timestamp subtraction — impossible for single-event decorators like `@log_call`
141
+
142
+ #### Consequences
143
+
144
+ Consistent duration measurement across all features. Sub-millisecond precision.
145
+
146
+ ### exception-handling
147
+
148
+ #### Context
149
+
150
+ Exceptions in decorated functions must be logged without changing program behavior.
151
+
152
+ #### Decision
153
+
154
+ Own `exc_type` and `exc_msg` fields in the event dict. `exc_type` = exception class name (e.g., `"ValueError"`). `exc_msg` = `str(exception)`. Exception is then re-raised unchanged. Does NOT use `exc_info=True` — the existing `process_exc_info`/`format_exc_info` pipeline is not invoked for decorator exceptions.
155
+
156
+ Event semantics per decorator on exception:
157
+ - `@log_call` — no exception handling (logs at entry, before execution)
158
+ - `@log_result` — `event="failed"`, `exc_type`, `exc_msg`, `duration_ms`
159
+ - `@log_operation` — `event="failed"`, `exc_type`, `exc_msg`, `duration_ms`, `args`
160
+ - `log_scope()` — `event="scope_failed"`, `exc_type`, `exc_msg`, `duration_ms`
161
+
162
+ #### Alternatives
163
+
164
+ a. `exc_info=True` via existing pipeline — produces full tracebacks, too verbose for every decorated call
165
+ b. Both own fields AND exc_info — redundant output
166
+
167
+ #### Consequences
168
+
169
+ Compact exception logging. Users get exception type and message without traceback noise. Full tracebacks available via explicit `log.exception()` outside decorators.
170
+
171
+ ### func-name
172
+
173
+ #### Context
174
+
175
+ Every event needs a `func` field identifying the decorated function.
176
+
177
+ #### Decision
178
+
179
+ `f"{wrapped_function.__module__}.{wrapped_function.__qualname__}"` at decoration time. Stored once, no runtime inspection needed. Works with `@functools.wraps` which preserves `__module__` and `__qualname__`.
180
+
181
+ #### Alternatives
182
+
183
+ a. `f.__name__` only — not unique across modules
184
+ b. Frame inspection — expensive, unreliable with decorators
185
+
186
+ #### Consequences
187
+
188
+ Unique, searchable function identifiers. Zero runtime cost (computed once at decoration).
189
+
190
+ ### test-strategy
191
+
192
+ #### Context
193
+
194
+ No shared test fixtures exist. Each test file has its own `_reset_structlog` autouse fixture.
195
+
196
+ #### Decision
197
+
198
+ 1. New `tests/conftest.py` with shared `_reset_structlog` autouse fixture (call `structlog.reset_defaults()`).
199
+ 2. New `tests/test_decorators.py` with tests for all three decorators and `log_scope()`.
200
+ 3. Update `tests/test_architecture.py` to register `_decorators` as Layer 2 module.
201
+ 4. TDD approach: write tests first, then implementation.
202
+
203
+ Test locations:
204
+ - Permanent decision tests: `tests/test_decorators.py`
205
+ - Architecture enforcement: `tests/test_architecture.py`
206
+
207
+ #### Alternatives
208
+
209
+ a. No shared conftest, each file has its own reset — inconsistent with the improvement opportunity
210
+ b. No new tests — unacceptable for new public API
211
+
212
+ #### Consequences
213
+
214
+ Solid test foundation. Architecture rules cover the new module from the start.
215
+
216
+ ## Requirements
217
+
218
+ ### Interface Contracts
219
+
220
+ **Decorator usage:**
221
+ ```python
222
+ from stogger import log_call, log_result, log_operation
223
+
224
+ @log_call
225
+ def fetch_user(user_id: int): ...
226
+
227
+ @log_result
228
+ def compute_hash(data: bytes) -> str: ...
229
+
230
+ @log_operation(include_args=["query"], exclude_args=["password"])
231
+ def authenticate(query: str, password: str) -> bool: ...
232
+ ```
233
+
234
+ **Context manager usage:**
235
+ ```python
236
+ from stogger import log_scope
237
+
238
+ with log_scope("db_transaction", table="users") as scope:
239
+ insert(user)
240
+ scope.add_fields(rows_inserted=1)
241
+ ```
242
+
243
+ **Event examples:**
244
+ ```
245
+ # @log_call
246
+ {"event": "called", "func": "mymodule.fetch_user", "args": {"user_id": 42}}
247
+
248
+ # @log_result
249
+ {"event": "returned", "func": "mymodule.compute_hash", "result": "abc123", "duration_ms": 2.4}
250
+
251
+ # @log_operation
252
+ {"event": "operation", "func": "mymodule.authenticate", "args": {"query": "admin"}, "result": true, "duration_ms": 15.3}
253
+
254
+ # log_scope success
255
+ {"event": "scope_end", "scope": "db_transaction", "table": "users", "rows_inserted": 1, "duration_ms": 45.2}
256
+
257
+ # @log_result exception
258
+ {"event": "failed", "func": "mymodule.compute_hash", "exc_type": "ValueError", "exc_msg": "empty input", "duration_ms": 0.1}
259
+
260
+ # log_scope exception
261
+ {"event": "scope_failed", "scope": "db_transaction", "exc_type": "ConnectionError", "exc_msg": "timeout", "duration_ms": 30001.0}
262
+ ```
263
+
264
+ ### Scope Boundary
265
+
266
+ Not part of this work: task_uuid, task_level, parent-child tracking, preserve_context, distributed tracing, serialization.
267
+
268
+ ### Files to Create/Modify
269
+
270
+ - **Create**: `src/stogger/_decorators.py`
271
+ - **Modify**: `src/stogger/core.py` — add re-exports for decorators and log_scope
272
+ - **Modify**: `src/stogger/__init__.py` — add to `__all__` and import from core
273
+ - **Create**: `tests/conftest.py` — shared _reset_structlog fixture
274
+ - **Create**: `tests/test_decorators.py`
275
+ - **Modify**: `tests/test_architecture.py` — register _decorators as Layer 2
276
+
277
+ ## Appendix
278
+
279
+ ### Implementation Plan
280
+
281
+ ```yaml
282
+ id: logging-decorators
283
+ description: "Three logging decorators (log_call, log_result, log_operation) and one context manager (log_scope) as new _decorators.py module at Layer 2. Sync+async support, arg filtering, duration measurement, exception logging."
284
+ specs:
285
+ - .agents/impl_specs/logging-decorators.md
286
+ target_tests:
287
+ - file: tests/impl_spec/test_logging_decorators.py
288
+ tests:
289
+ - test_import_log_call_from_decorators
290
+ - test_import_log_result_from_decorators
291
+ - test_import_log_operation_from_decorators
292
+ - test_import_log_scope_from_decorators
293
+ - test_import_log_call_from_stogger_top_level
294
+ - test_import_log_scope_from_stogger_top_level
295
+ - test_log_call_produces_called_event
296
+ - test_log_result_produces_returned_event
297
+ - test_log_operation_produces_operation_event
298
+ - test_log_scope_returns_log_scope_instance
299
+ - test_log_scope_has_add_fields_method
300
+ - test_log_scope_success_produces_scope_end_event
301
+ - test_log_scope_exception_produces_scope_failed_event
302
+ - test_log_call_works_with_async
303
+ - test_log_result_works_with_async
304
+ - test_log_operation_works_with_async
305
+ - test_log_scope_works_with_async_with
306
+ - test_args_include_default_values
307
+ - test_args_strip_self
308
+ - test_args_strip_cls
309
+ - test_include_args_whitelist_filtering
310
+ - test_exclude_args_blacklist_filtering
311
+ - test_log_result_has_duration_ms
312
+ - test_log_operation_has_duration_ms
313
+ - test_log_scope_has_duration_ms
314
+ - test_log_result_logs_exception_and_reraises
315
+ - test_log_operation_logs_exception_with_args
316
+ - test_log_call_does_not_catch_exceptions
317
+ - test_log_scope_exception_reraises
318
+ - test_func_field_is_module_qualname
319
+ - test_func_field_for_method
320
+ created_at: "2026-05-03T13:00:00Z"
321
+ git_rev: "1682052"
322
+ ```