graphrefly 0.18.0__tar.gz → 0.19.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 (352) hide show
  1. {graphrefly-0.18.0 → graphrefly-0.19.0}/CHANGELOG.md +34 -0
  2. graphrefly-0.19.0/CLAUDE.md +48 -0
  3. {graphrefly-0.18.0 → graphrefly-0.19.0}/PKG-INFO +1 -1
  4. {graphrefly-0.18.0 → graphrefly-0.19.0}/pyproject.toml +2 -1
  5. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/__init__.py +0 -6
  6. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/compat/async_utils.py +7 -9
  7. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/compat/asyncio_runner.py +34 -7
  8. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/compat/trio_runner.py +29 -5
  9. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/__init__.py +0 -3
  10. graphrefly-0.19.0/src/graphrefly/core/dynamic_node.py +382 -0
  11. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/meta.py +5 -1
  12. graphrefly-0.19.0/src/graphrefly/core/node.py +540 -0
  13. graphrefly-0.19.0/src/graphrefly/core/node_base.py +739 -0
  14. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/protocol.py +51 -26
  15. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/runner.py +15 -0
  16. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/__init__.py +8 -2
  17. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/adapters.py +16 -8
  18. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/cascading_cache.py +17 -7
  19. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/data_structures.py +1 -3
  20. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/resilience.py +13 -6
  21. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/sources.py +186 -10
  22. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/tier1.py +14 -32
  23. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/tier2.py +22 -5
  24. graphrefly-0.19.0/src/graphrefly/graph/__init__.py +67 -0
  25. graphrefly-0.19.0/src/graphrefly/graph/codec.py +293 -0
  26. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/graph/graph.py +172 -144
  27. graphrefly-0.19.0/src/graphrefly/graph/profile.py +120 -0
  28. graphrefly-0.19.0/src/graphrefly/graph/sizeof.py +115 -0
  29. graphrefly-0.19.0/src/graphrefly/patterns/_internal.py +64 -0
  30. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/ai.py +866 -76
  31. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/cqrs.py +4 -5
  32. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/domain_templates.py +7 -9
  33. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/harness/__init__.py +10 -0
  34. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/harness/bridge.py +44 -1
  35. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/harness/loop.py +153 -69
  36. graphrefly-0.19.0/src/graphrefly/patterns/harness/profile.py +84 -0
  37. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/harness/strategy.py +3 -4
  38. graphrefly-0.19.0/src/graphrefly/patterns/harness/trace.py +239 -0
  39. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/harness/types.py +7 -12
  40. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/messaging.py +3 -8
  41. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/orchestration.py +19 -11
  42. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/reduction.py +108 -4
  43. graphrefly-0.19.0/tests/__init__.py +1 -0
  44. graphrefly-0.19.0/tests/conftest.py +123 -0
  45. graphrefly-0.19.0/tests/helpers/__init__.py +1 -0
  46. graphrefly-0.19.0/tests/helpers/mock_llm.py +122 -0
  47. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_adapters_ingest.py +17 -69
  48. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_adapters_storage.py +8 -16
  49. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_core.py +20 -9
  50. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_domain_templates.py +3 -2
  51. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_dynamic_node.py +3 -3
  52. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_edge_cases.py +19 -34
  53. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_data_structures.py +2 -0
  54. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_resilience.py +23 -39
  55. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_sources.py +5 -2
  56. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_sources_http.py +16 -17
  57. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_tier1.py +57 -88
  58. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_tier2.py +83 -90
  59. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_fastapi.py +2 -2
  60. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_graph.py +36 -21
  61. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_operator_protocol_matrix.py +4 -3
  62. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_ai.py +726 -4
  63. graphrefly-0.19.0/tests/test_patterns_harness.py +698 -0
  64. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_orchestration.py +14 -10
  65. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_reduction.py +9 -9
  66. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_protocol.py +1 -0
  67. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_reduction.py +10 -10
  68. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_sugar.py +3 -2
  69. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_versioning.py +2 -1
  70. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/astro.config.mjs +8 -0
  71. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/scripts/gen_api_docs.py +1 -1
  72. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/Header.astro +5 -2
  73. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/Sidebar.astro +4 -2
  74. graphrefly-0.19.0/website/src/content/docs/api/ReactiveCounterBundle.md +14 -0
  75. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/first_value_from.md +6 -0
  76. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_any.md +1 -1
  77. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/index.md +33 -36
  78. graphrefly-0.19.0/website/src/content/docs/api/is_local_only.md +16 -0
  79. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/is_terminal_message.md +2 -2
  80. graphrefly-0.19.0/website/src/content/docs/api/keepalive.md +21 -0
  81. graphrefly-0.19.0/website/src/content/docs/api/message_tier.md +20 -0
  82. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/partition_for_batch.md +1 -1
  83. graphrefly-0.19.0/website/src/content/docs/api/reactive_counter.md +19 -0
  84. graphrefly-0.19.0/website/src/content/docs/recipes/index.md +8 -0
  85. graphrefly-0.18.0/.claude/skills/dev-dispatch/SKILL.md +0 -119
  86. graphrefly-0.18.0/.claude/skills/parity/SKILL.md +0 -139
  87. graphrefly-0.18.0/.claude/skills/qa/SKILL.md +0 -104
  88. graphrefly-0.18.0/.gemini/skills/dev-dispatch/SKILL.md +0 -171
  89. graphrefly-0.18.0/.gemini/skills/parity/SKILL.md +0 -188
  90. graphrefly-0.18.0/CLAUDE.md +0 -77
  91. graphrefly-0.18.0/TRASH/EmitStrategy.md +0 -10
  92. graphrefly-0.18.0/TRASH/emit_with_batch.md +0 -43
  93. graphrefly-0.18.0/TRASH-FILES.md +0 -2
  94. graphrefly-0.18.0/archive/docs/DESIGN-ARCHIVE-INDEX.md +0 -79
  95. graphrefly-0.18.0/archive/docs/SESSION-access-control-actor-guard.md +0 -210
  96. graphrefly-0.18.0/archive/docs/SESSION-cross-repo-implementation-audit.md +0 -205
  97. graphrefly-0.18.0/archive/docs/SESSION-demo-test-strategy.md +0 -71
  98. graphrefly-0.18.0/archive/docs/SESSION-graphrefly-spec-design.md +0 -111
  99. graphrefly-0.18.0/archive/docs/SESSION-serialization-memory-footprint.md +0 -69
  100. graphrefly-0.18.0/archive/docs/SESSION-tier2-parity-nonlocal-forward-inner.md +0 -54
  101. graphrefly-0.18.0/archive/docs/SESSION-universal-reduction-layer.md +0 -65
  102. graphrefly-0.18.0/archive/docs/design-archive-index.jsonl +0 -14
  103. graphrefly-0.18.0/archive/optimizations/built-in-optimizations.jsonl +0 -8
  104. graphrefly-0.18.0/archive/optimizations/cross-language-notes.jsonl +0 -35
  105. graphrefly-0.18.0/archive/optimizations/parity-fixes.jsonl +0 -6
  106. graphrefly-0.18.0/archive/optimizations/qa-design-decisions.jsonl +0 -11
  107. graphrefly-0.18.0/archive/optimizations/resolved-decisions.jsonl +0 -95
  108. graphrefly-0.18.0/archive/optimizations/summary-table.jsonl +0 -49
  109. graphrefly-0.18.0/archive/roadmap/phase-0-foundation.jsonl +0 -7
  110. graphrefly-0.18.0/archive/roadmap/phase-1-graph-container.jsonl +0 -7
  111. graphrefly-0.18.0/archive/roadmap/phase-2-extra.jsonl +0 -3
  112. graphrefly-0.18.0/archive/roadmap/phase-3-resilience-data.jsonl +0 -4
  113. graphrefly-0.18.0/archive/roadmap/phase-4-domain-layers.jsonl +0 -5
  114. graphrefly-0.18.0/archive/roadmap/phase-5-framework-distribution.jsonl +0 -6
  115. graphrefly-0.18.0/archive/roadmap/phase-6-versioning.jsonl +0 -3
  116. graphrefly-0.18.0/archive/roadmap/phase-7-polish.jsonl +0 -2
  117. graphrefly-0.18.0/archive/roadmap/phase-8-reduction-layer.jsonl +0 -3
  118. graphrefly-0.18.0/archive/roadmap/phase-9-harness-sprint.jsonl +0 -1
  119. graphrefly-0.18.0/docs/docs-guidance.md +0 -247
  120. graphrefly-0.18.0/docs/optimizations.md +0 -80
  121. graphrefly-0.18.0/docs/roadmap.md +0 -161
  122. graphrefly-0.18.0/docs/test-guidance.md +0 -138
  123. graphrefly-0.18.0/src/graphrefly/core/dynamic_node.py +0 -774
  124. graphrefly-0.18.0/src/graphrefly/core/node.py +0 -1046
  125. graphrefly-0.18.0/src/graphrefly/graph/__init__.py +0 -33
  126. graphrefly-0.18.0/tests/conftest.py +0 -46
  127. graphrefly-0.18.0/tests/test_patterns_harness.py +0 -383
  128. graphrefly-0.18.0/website/src/content/docs/api/message_tier.md +0 -19
  129. {graphrefly-0.18.0 → graphrefly-0.19.0}/.github/workflows/pages.yml +0 -0
  130. {graphrefly-0.18.0 → graphrefly-0.19.0}/.github/workflows/release.yml +0 -0
  131. {graphrefly-0.18.0 → graphrefly-0.19.0}/.gitignore +0 -0
  132. {graphrefly-0.18.0 → graphrefly-0.19.0}/.mise.toml +0 -0
  133. {graphrefly-0.18.0 → graphrefly-0.19.0}/CONTRIBUTING.md +0 -0
  134. {graphrefly-0.18.0 → graphrefly-0.19.0}/GEMINI.md +0 -0
  135. {graphrefly-0.18.0 → graphrefly-0.19.0}/LICENSE +0 -0
  136. {graphrefly-0.18.0 → graphrefly-0.19.0}/README.md +0 -0
  137. {graphrefly-0.18.0 → graphrefly-0.19.0}/benchmarks/py-baseline.json +0 -0
  138. {graphrefly-0.18.0 → graphrefly-0.19.0}/docs/ADAPTER-CONTRACT.md +0 -0
  139. {graphrefly-0.18.0 → graphrefly-0.19.0}/docs/benchmark.md +0 -0
  140. {graphrefly-0.18.0 → graphrefly-0.19.0}/examples/README.md +0 -0
  141. {graphrefly-0.18.0 → graphrefly-0.19.0}/examples/basic_counter.py +0 -0
  142. {graphrefly-0.18.0 → graphrefly-0.19.0}/llms.txt +0 -0
  143. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/compat/__init__.py +0 -0
  144. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/bridge.py +0 -0
  145. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/cancellation.py +0 -0
  146. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/clock.py +0 -0
  147. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/guard.py +0 -0
  148. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/subgraph_locks.py +0 -0
  149. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/sugar.py +0 -0
  150. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/timer.py +0 -0
  151. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/core/versioning.py +0 -0
  152. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/backoff.py +0 -0
  153. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/backpressure.py +0 -0
  154. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/checkpoint.py +0 -0
  155. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/composite.py +0 -0
  156. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/extra/cron.py +0 -0
  157. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/integrations/__init__.py +0 -0
  158. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/integrations/django.py +0 -0
  159. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/integrations/fastapi.py +0 -0
  160. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/__init__.py +0 -0
  161. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/graphspec.py +0 -0
  162. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/memory.py +0 -0
  163. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/reactive_layout/__init__.py +0 -0
  164. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/reactive_layout/measurement_adapters.py +0 -0
  165. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/reactive_layout/reactive_block_layout.py +0 -0
  166. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/patterns/reactive_layout/reactive_layout.py +0 -0
  167. {graphrefly-0.18.0 → graphrefly-0.19.0}/src/graphrefly/py.typed +0 -0
  168. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/bench_core.py +0 -0
  169. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_adapter_contract.py +0 -0
  170. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_backpressure.py +0 -0
  171. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_bridge.py +0 -0
  172. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_cascading_cache.py +0 -0
  173. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_concurrency.py +0 -0
  174. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_django.py +0 -0
  175. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_extra_composite.py +0 -0
  176. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_graphspec.py +0 -0
  177. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_guard.py +0 -0
  178. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_measurement_adapters.py +0 -0
  179. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_cqrs.py +0 -0
  180. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_memory.py +0 -0
  181. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_patterns_messaging.py +0 -0
  182. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_perf_smoke.py +0 -0
  183. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_reactive_block_layout.py +0 -0
  184. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_reactive_layout.py +0 -0
  185. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_regressions.py +0 -0
  186. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_runner.py +0 -0
  187. {graphrefly-0.18.0 → graphrefly-0.19.0}/tests/test_smoke.py +0 -0
  188. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/.gitignore +0 -0
  189. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/README.md +0 -0
  190. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/content.config.ts +0 -0
  191. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/package.json +0 -0
  192. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/pnpm-lock.yaml +0 -0
  193. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/public/llms.txt +0 -0
  194. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/py-api-sidebar.mjs +0 -0
  195. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/scripts/sync-docs.mjs +0 -0
  196. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/GraphreflyHero.astro +0 -0
  197. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/MobileMenuFooter.astro +0 -0
  198. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/PyodidePlayground.tsx +0 -0
  199. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/components/SiteTitle.astro +0 -0
  200. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/BackoffPreset.md +0 -0
  201. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/BackoffStrategy.md +0 -0
  202. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/CheckpointAdapter.md +0 -0
  203. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/CircuitBreaker.md +0 -0
  204. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/CircuitOpenError.md +0 -0
  205. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/CompactEntry.md +0 -0
  206. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/DeferWhen.md +0 -0
  207. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/DictCheckpointAdapter.md +0 -0
  208. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/DistillBundle.md +0 -0
  209. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/DownStrategy.md +0 -0
  210. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/Extraction.md +0 -0
  211. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/FileCheckpointAdapter.md +0 -0
  212. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/HttpBundle.md +0 -0
  213. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/JitterMode.md +0 -0
  214. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/MemoryCheckpointAdapter.md +0 -0
  215. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/Message.md +0 -0
  216. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/MessageType.md +0 -0
  217. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/Messages.md +0 -0
  218. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/NodeActions.md +0 -0
  219. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/NodeFn.md +0 -0
  220. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/NodeImpl.md +0 -0
  221. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/NodeStatus.md +0 -0
  222. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/PipeOperator.md +0 -0
  223. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/PubSubHub.md +0 -0
  224. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/ReactiveIndexBundle.md +0 -0
  225. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/ReactiveListBundle.md +0 -0
  226. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/ReactiveLogBundle.md +0 -0
  227. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/ReactiveMapBundle.md +0 -0
  228. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/SqliteCheckpointAdapter.md +0 -0
  229. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/SubscribeHints.md +0 -0
  230. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/TimeoutError.md +0 -0
  231. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/TokenBucket.md +0 -0
  232. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/VerifiableBundle.md +0 -0
  233. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/Versioned.md +0 -0
  234. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/WithBreakerBundle.md +0 -0
  235. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/WithStatusBundle.md +0 -0
  236. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/audit.md +0 -0
  237. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/batch.md +0 -0
  238. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/buffer.md +0 -0
  239. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/buffer_count.md +0 -0
  240. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/buffer_time.md +0 -0
  241. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/cache.md +0 -0
  242. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/cached.md +0 -0
  243. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/checkpoint_node_value.md +0 -0
  244. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/circuit_breaker.md +0 -0
  245. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/combine.md +0 -0
  246. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/concat.md +0 -0
  247. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/concat_map.md +0 -0
  248. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/constant.md +0 -0
  249. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/debounce.md +0 -0
  250. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/decorrelated_jitter.md +0 -0
  251. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/delay.md +0 -0
  252. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/derived.md +0 -0
  253. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/dispatch_messages.md +0 -0
  254. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/distill.md +0 -0
  255. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/distinct_until_changed.md +0 -0
  256. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/down_with_batch.md +0 -0
  257. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/effect.md +0 -0
  258. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/element_at.md +0 -0
  259. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/empty.md +0 -0
  260. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/exhaust_map.md +0 -0
  261. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/exponential.md +0 -0
  262. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/fallback.md +0 -0
  263. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/fibonacci.md +0 -0
  264. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/filter.md +0 -0
  265. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/find.md +0 -0
  266. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/first.md +0 -0
  267. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/flat_map.md +0 -0
  268. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/for_each.md +0 -0
  269. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_async_iter.md +0 -0
  270. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_awaitable.md +0 -0
  271. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_cron.md +0 -0
  272. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_event_emitter.md +0 -0
  273. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_fs_watch.md +0 -0
  274. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_git_hook.md +0 -0
  275. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_http.md +0 -0
  276. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_iter.md +0 -0
  277. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_mcp.md +0 -0
  278. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_timer.md +0 -0
  279. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_webhook.md +0 -0
  280. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/from_websocket.md +0 -0
  281. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/gate.md +0 -0
  282. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/interval.md +0 -0
  283. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/is_batching.md +0 -0
  284. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/is_phase2_message.md +0 -0
  285. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/last.md +0 -0
  286. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/linear.md +0 -0
  287. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/log_slice.md +0 -0
  288. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/map.md +0 -0
  289. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/merge.md +0 -0
  290. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/never.md +0 -0
  291. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/node.md +0 -0
  292. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/of.md +0 -0
  293. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/operator.md +0 -0
  294. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/pairwise.md +0 -0
  295. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/pausable.md +0 -0
  296. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/pipe.md +0 -0
  297. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/producer.md +0 -0
  298. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/propagates_to_meta.md +0 -0
  299. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/pubsub.md +0 -0
  300. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/race.md +0 -0
  301. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/rate_limiter.md +0 -0
  302. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/reactive_index.md +0 -0
  303. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/reactive_list.md +0 -0
  304. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/reactive_log.md +0 -0
  305. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/reactive_map.md +0 -0
  306. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/reduce.md +0 -0
  307. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/repeat.md +0 -0
  308. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/replay.md +0 -0
  309. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/rescue.md +0 -0
  310. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/resolve_backoff_preset.md +0 -0
  311. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/restore_graph_checkpoint.md +0 -0
  312. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/retry.md +0 -0
  313. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/sample.md +0 -0
  314. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/save_graph_checkpoint.md +0 -0
  315. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/scan.md +0 -0
  316. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/share.md +0 -0
  317. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/skip.md +0 -0
  318. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/start_with.md +0 -0
  319. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/state.md +0 -0
  320. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/subscribe.md +0 -0
  321. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/switch_map.md +0 -0
  322. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/take.md +0 -0
  323. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/take_until.md +0 -0
  324. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/take_while.md +0 -0
  325. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/tap.md +0 -0
  326. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/throttle.md +0 -0
  327. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/throw_error.md +0 -0
  328. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/timeout.md +0 -0
  329. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/timeout_node.md +0 -0
  330. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/to_array.md +0 -0
  331. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/to_list.md +0 -0
  332. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/to_sse.md +0 -0
  333. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/to_websocket.md +0 -0
  334. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/token_bucket.md +0 -0
  335. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/token_tracker.md +0 -0
  336. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/valve.md +0 -0
  337. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/verifiable.md +0 -0
  338. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/window.md +0 -0
  339. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/window_count.md +0 -0
  340. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/window_time.md +0 -0
  341. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/with_breaker.md +0 -0
  342. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/with_latest_from.md +0 -0
  343. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/with_max_attempts.md +0 -0
  344. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/with_status.md +0 -0
  345. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/api/zip.md +0 -0
  346. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/index.mdx +0 -0
  347. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content/docs/lab/python.mdx +0 -0
  348. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/content.config.ts +0 -0
  349. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/env.d.ts +0 -0
  350. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/src/styles/custom.css +0 -0
  351. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/theme-prototypes.html +0 -0
  352. {graphrefly-0.18.0 → graphrefly-0.19.0}/website/tsconfig.json +0 -0
@@ -2,6 +2,40 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v0.19.0 (2026-04-10)
6
+
7
+ ### Chores
8
+
9
+ - 9.0 initial test (needs revisit)
10
+ ([`f47a8b4`](https://github.com/graphrefly/graphrefly-py/commit/f47a8b4d32e999d4f867465f678d576184fc111d))
11
+
12
+ ### Features
13
+
14
+ - Add start
15
+ ([`4a008dc`](https://github.com/graphrefly/graphrefly-py/commit/4a008dcda7704e14be12a7111b1d0b9188c736b3))
16
+
17
+ - Address optimization items
18
+ ([`371f9e2`](https://github.com/graphrefly/graphrefly-py/commit/371f9e25e590ded4150fd6aed7e0de3933b8f0f3))
19
+
20
+ - Consolidate inspection tools
21
+ ([`94aa9af`](https://github.com/graphrefly/graphrefly-py/commit/94aa9af3e3d793103496bfcc71a0a4bbb38f5ea3))
22
+
23
+ - Fix
24
+ ([`222e66f`](https://github.com/graphrefly/graphrefly-py/commit/222e66f4d8954aa772534c9fc796eea3ba30a304))
25
+
26
+ - Fix async pytest
27
+ ([`f25ae08`](https://github.com/graphrefly/graphrefly-py/commit/f25ae0885fd824320b498fd2d923f6e4f6ebb0f5))
28
+
29
+ - Fix inspection tool
30
+ ([`09c90f2`](https://github.com/graphrefly/graphrefly-py/commit/09c90f273613fbae1fd7987397d85d4b6fabec8d))
31
+
32
+ - Fix retries and reingestions
33
+ ([`55d1a3d`](https://github.com/graphrefly/graphrefly-py/commit/55d1a3d0beff848a6ecefb054e42d194050d5c37))
34
+
35
+ - Reusable harness patterns
36
+ ([`84bafbb`](https://github.com/graphrefly/graphrefly-py/commit/84bafbb8476c1d00ae373bbc757d4bf813ce16c8))
37
+
38
+
5
39
  ## v0.18.0 (2026-04-08)
6
40
 
7
41
  ### Features
@@ -0,0 +1,48 @@
1
+ # graphrefly-py
2
+
3
+ Python implementation of the GraphReFly reactive graph protocol.
4
+
5
+ **All operational docs (roadmap, optimizations, test guidance, docs guidance, skills, archive) live in `~/src/graphrefly-ts`.** See that repo's `CLAUDE.md` for the full agent context.
6
+
7
+ ## Commands
8
+
9
+ uv workspace managed by mise. `mise trust && mise install` to set up uv. `uv sync` to install dependencies.
10
+
11
+ - Test: `uv run pytest`
12
+ - Lint: `uv run ruff check src/ tests/`
13
+ - Lint fix: `uv run ruff check --fix src/ tests/`
14
+ - Format: `uv run ruff format src/ tests/`
15
+ - Type check: `uv run mypy src/`
16
+
17
+ ## Package naming
18
+
19
+ - Distribution name: `graphrefly-py`
20
+ - Import path: `graphrefly`
21
+
22
+ ## Layout
23
+
24
+ - `src/graphrefly/core/` — message protocol, `node` primitive, batch, sugar constructors (Phase 0)
25
+ - `src/graphrefly/graph/` — `Graph` container, describe/observe, snapshot (Phase 1+)
26
+ - `src/graphrefly/extra/` — operators, sources, data structures, resilience (Phase 2–3)
27
+ - `src/graphrefly/patterns/` — domain-layer APIs: orchestration, messaging, memory, AI, CQRS, reactive layout (Phase 4+)
28
+ - `src/graphrefly/compat/` — async runners: asyncio, trio (Phase 5+)
29
+ - `src/graphrefly/integrations/` — framework integrations: FastAPI (Phase 5+)
30
+
31
+ ## Key references
32
+
33
+ | Doc | Location |
34
+ |-----|----------|
35
+ | Behavior spec | `~/src/graphrefly/GRAPHREFLY-SPEC.md` |
36
+ | Composition guide | `~/src/graphrefly/COMPOSITION-GUIDE.md` |
37
+ | Roadmap, optimizations, test/docs guidance, skills, archive | `~/src/graphrefly-ts/` (single source of truth) |
38
+ | Predecessor (patterns, concurrency) | `~/src/callbag-recharge-py` (reference only, not spec) |
39
+
40
+ ## Design invariants (spec §5.8–5.12)
41
+
42
+ 1. **No polling.** Use reactive timer sources (`from_timer`, `from_cron`).
43
+ 2. **No imperative triggers.** Use reactive `NodeInput` signals.
44
+ 3. **No raw async primitives.** Async boundaries belong in sources and runners, not node fns.
45
+ 4. **Central timer and `message_tier`.** Use `core/clock.py`; never hardcode type checks.
46
+ 5. **Phase 4+ APIs must be developer-friendly.** No protocol internals in primary surface.
47
+ 6. **Thread safety.** Per-subgraph `RLock`, per-node `_cache_lock`. Design for GIL and free-threaded Python.
48
+ 7. **No `async def` in public APIs.** Return `Node[T]`, `Graph`, `None`, or plain synchronous values.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphrefly
3
- Version: 0.18.0
3
+ Version: 0.19.0
4
4
  Summary: Reactive harness layer for agent workflows. Describe automations in plain language, trace every decision, enforce policies, persist checkpoints. Zero dependencies.
5
5
  Project-URL: Homepage, https://py.graphrefly.dev
6
6
  Project-URL: Repository, https://github.com/graphrefly/graphrefly-py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "graphrefly"
3
- version = "0.18.0"
3
+ version = "0.19.0"
4
4
  description = "Reactive harness layer for agent workflows. Describe automations in plain language, trace every decision, enforce policies, persist checkpoints. Zero dependencies."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -90,6 +90,7 @@ quote-style = "double"
90
90
 
91
91
  [tool.pytest.ini_options]
92
92
  testpaths = ["tests"]
93
+ pythonpath = ["tests"]
93
94
  asyncio_mode = "auto"
94
95
  addopts = "-m 'not benchmark'"
95
96
  markers = [
@@ -37,7 +37,6 @@ from graphrefly.core import (
37
37
  defer_down,
38
38
  defer_set,
39
39
  derived,
40
- describe_node,
41
40
  dispatch_messages,
42
41
  down_with_batch,
43
42
  dynamic_node,
@@ -47,7 +46,6 @@ from graphrefly.core import (
47
46
  is_batching,
48
47
  is_phase2_message,
49
48
  is_v1,
50
- meta_snapshot,
51
49
  monotonic_ns,
52
50
  node,
53
51
  normalize_actor,
@@ -74,7 +72,6 @@ from graphrefly.graph import (
74
72
  GraphDiffResult,
75
73
  GraphObserveSource,
76
74
  ObserveResult,
77
- SpyHandle,
78
75
  TraceEntry,
79
76
  reachable,
80
77
  )
@@ -93,7 +90,6 @@ __all__ = [
93
90
  "NodeVersionInfo",
94
91
  "ObserveResult",
95
92
  "PATH_SEP",
96
- "SpyHandle",
97
93
  "TraceEntry",
98
94
  "V0",
99
95
  "V1",
@@ -138,13 +134,11 @@ __all__ = [
138
134
  "compose_guards",
139
135
  "defer_down",
140
136
  "defer_set",
141
- "describe_node",
142
137
  "dispatch_messages",
143
138
  "down_with_batch",
144
139
  "ensure_registered",
145
140
  "is_batching",
146
141
  "is_phase2_message",
147
- "meta_snapshot",
148
142
  "node",
149
143
  "normalize_actor",
150
144
  "partition_for_batch",
@@ -11,6 +11,7 @@ import asyncio
11
11
  import contextlib
12
12
  from typing import TYPE_CHECKING, Any
13
13
 
14
+ from graphrefly.core.node import NO_VALUE
14
15
  from graphrefly.core.protocol import MessageType
15
16
 
16
17
  if TYPE_CHECKING:
@@ -101,13 +102,11 @@ async def first_value_from_async(source: Node[Any]) -> Any:
101
102
  assert value == 42
102
103
  """
103
104
  # Fast path: already settled with a cached value.
104
- # ``source.get()`` returns ``None`` when no value is cached, so
105
- # ``is not None`` doubles as the "has value" sentinel while still
106
- # returning falsy values like ``0``, ``False``, ``""``.
105
+ # Uses NO_VALUE sentinel so ``None`` as a real domain value is not skipped.
107
106
  status = source.status
108
107
  if status in ("settled", "resolved"):
109
- v = source.get()
110
- if v is not None:
108
+ v = getattr(source, "_cached", NO_VALUE)
109
+ if v is not NO_VALUE:
111
110
  return v
112
111
 
113
112
  loop = asyncio.get_running_loop()
@@ -163,12 +162,11 @@ async def settled(source: Node[Any]) -> Any:
163
162
  value = await settled(b)
164
163
  assert value == 20
165
164
  """
166
- # Fast path: already settled (see ``first_value_from_async`` for the
167
- # ``is not None`` rationale).
165
+ # Fast path: already settled uses NO_VALUE sentinel so ``None`` is not skipped.
168
166
  status = source.status
169
167
  if status in ("settled", "resolved"):
170
- v = source.get()
171
- if v is not None:
168
+ v = getattr(source, "_cached", NO_VALUE)
169
+ if v is not NO_VALUE:
172
170
  return v
173
171
 
174
172
  loop = asyncio.get_running_loop()
@@ -3,6 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import asyncio
6
+ import threading
6
7
  from typing import TYPE_CHECKING, Any
7
8
 
8
9
  if TYPE_CHECKING:
@@ -29,10 +30,12 @@ class AsyncioRunner:
29
30
  asyncio.run(main())
30
31
  """
31
32
 
32
- __slots__ = ("_loop",)
33
+ __slots__ = ("_loop", "_scheduled", "_completed")
33
34
 
34
35
  def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
35
36
  self._loop = loop
37
+ self._scheduled = 0
38
+ self._completed = 0
36
39
 
37
40
  @classmethod
38
41
  def from_running(cls) -> AsyncioRunner:
@@ -50,11 +53,12 @@ class AsyncioRunner:
50
53
  on_error: Callable[[BaseException], None],
51
54
  ) -> Callable[[], None]:
52
55
  task: asyncio.Task[Any] | None = None
53
- cancelled = False
56
+ cancelled = threading.Event()
54
57
 
55
58
  def _create_task() -> None:
56
59
  nonlocal task
57
- if cancelled:
60
+ if cancelled.is_set():
61
+ self._completed += 1
58
62
  coro.close()
59
63
  return
60
64
 
@@ -71,19 +75,42 @@ class AsyncioRunner:
71
75
  on_error(err)
72
76
  else:
73
77
  on_result(result)
78
+ finally:
79
+ self._completed += 1
74
80
 
75
81
  task = self._loop.create_task(_wrapper())
76
82
 
77
- # Thread-safe: schedule task creation on the event loop.
78
- self._loop.call_soon_threadsafe(_create_task)
83
+ # Increment eagerly on the calling thread so __repr__ is always consistent.
84
+ self._scheduled += 1
85
+ try:
86
+ self._loop.call_soon_threadsafe(_create_task)
87
+ except RuntimeError:
88
+ # Loop closed — cannot schedule; close the coroutine and balance the counter.
89
+ self._completed += 1
90
+ coro.close()
79
91
 
80
92
  def cancel() -> None:
81
- nonlocal cancelled
82
- cancelled = True
93
+ cancelled.set()
83
94
  if task is not None:
84
95
  task.cancel()
85
96
 
86
97
  return cancel
87
98
 
99
+ def would_block_deadlock(self) -> bool:
100
+ """True if blocking the current thread would starve this runner's loop."""
101
+ try:
102
+ loop = asyncio.get_running_loop()
103
+ except RuntimeError:
104
+ return False
105
+ return loop is self._loop
106
+
107
+ def __repr__(self) -> str:
108
+ pending = self._scheduled - self._completed
109
+ running = self._loop.is_running()
110
+ return (
111
+ f"AsyncioRunner(scheduled={self._scheduled}, completed={self._completed}, "
112
+ f"pending={pending}, loop_running={running})"
113
+ )
114
+
88
115
 
89
116
  __all__ = ["AsyncioRunner"]
@@ -8,6 +8,7 @@ Usage::
8
8
  from graphrefly.compat.trio_runner import TrioRunner
9
9
  from graphrefly.core.runner import set_default_runner
10
10
 
11
+
11
12
  async def main():
12
13
  async with trio.open_nursery() as nursery:
13
14
  runner = TrioRunner(nursery)
@@ -19,6 +20,7 @@ Usage::
19
20
 
20
21
  from __future__ import annotations
21
22
 
23
+ import threading
22
24
  from typing import TYPE_CHECKING, Any
23
25
 
24
26
  if TYPE_CHECKING:
@@ -34,10 +36,12 @@ class TrioRunner:
34
36
  Cancel scopes provide best-effort cancellation.
35
37
  """
36
38
 
37
- __slots__ = ("_nursery",)
39
+ __slots__ = ("_nursery", "_scheduled", "_completed")
38
40
 
39
41
  def __init__(self, nursery: trio.Nursery) -> None:
40
42
  self._nursery = nursery
43
+ self._scheduled = 0
44
+ self._completed = 0
41
45
 
42
46
  def schedule(
43
47
  self,
@@ -48,11 +52,12 @@ class TrioRunner:
48
52
  import trio as _trio
49
53
 
50
54
  cancel_scope = _trio.CancelScope()
51
- cancelled = False
55
+ cancelled = threading.Event()
52
56
 
53
57
  async def _wrapper() -> None:
54
58
  with cancel_scope:
55
- if cancelled:
59
+ if cancelled.is_set():
60
+ self._completed += 1
56
61
  coro.close()
57
62
  return
58
63
  try:
@@ -67,15 +72,34 @@ class TrioRunner:
67
72
  on_error(err)
68
73
  else:
69
74
  on_result(result)
75
+ finally:
76
+ self._completed += 1
70
77
 
78
+ self._scheduled += 1
71
79
  self._nursery.start_soon(_wrapper)
72
80
 
73
81
  def cancel() -> None:
74
- nonlocal cancelled
75
- cancelled = True
82
+ cancelled.set()
76
83
  cancel_scope.cancel()
77
84
 
78
85
  return cancel
79
86
 
87
+ def would_block_deadlock(self) -> bool:
88
+ """True if blocking the current thread would starve the trio nursery."""
89
+ try:
90
+ import trio as _trio
91
+
92
+ _trio.lowlevel.current_trio_token()
93
+ return True
94
+ except RuntimeError:
95
+ return False
96
+
97
+ def __repr__(self) -> str:
98
+ pending = self._scheduled - self._completed
99
+ return (
100
+ f"TrioRunner(scheduled={self._scheduled}, completed={self._completed}, "
101
+ f"pending={pending})"
102
+ )
103
+
80
104
 
81
105
  __all__ = ["TrioRunner"]
@@ -17,7 +17,6 @@ from graphrefly.core.guard import (
17
17
  record_mutation,
18
18
  system_actor,
19
19
  )
20
- from graphrefly.core.meta import describe_node, meta_snapshot
21
20
  from graphrefly.core.node import (
22
21
  NO_VALUE,
23
22
  Node,
@@ -112,7 +111,6 @@ __all__ = [
112
111
  "compose_guards",
113
112
  "defer_down",
114
113
  "defer_set",
115
- "describe_node",
116
114
  "dispatch_messages",
117
115
  "down_with_batch",
118
116
  "ensure_registered",
@@ -121,7 +119,6 @@ __all__ = [
121
119
  "is_terminal_message",
122
120
  "message_tier",
123
121
  "propagates_to_meta",
124
- "meta_snapshot",
125
122
  "node",
126
123
  "normalize_actor",
127
124
  "partition_for_batch",