nighthawk-python 0.15.0__tar.gz → 0.16.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 (308) hide show
  1. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.github/workflows/ci.yml +14 -14
  2. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.github/workflows/docs.yml +26 -8
  3. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.github/workflows/publish.yml +1 -1
  4. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/CHANGELOG.md +19 -1
  5. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/PKG-INFO +1 -1
  6. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/design-drivers.md +19 -0
  7. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/embedded-execution.md +60 -7
  8. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/executors.md +39 -0
  9. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/for-coding-agents.md +5 -5
  10. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/natural-blocks.md +4 -3
  11. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/patterns.md +14 -13
  12. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/roadmap.md +1 -1
  13. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/runtime-configuration.md +161 -2
  14. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/specification.md +101 -59
  15. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/verification.md +14 -9
  16. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/README.md +10 -12
  17. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/inspection_study.py +10 -11
  18. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/pyproject.toml +1 -1
  19. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/composition.py +6 -2
  20. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/configuration.py +5 -4
  21. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/function_call.py +16 -4
  22. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/oversight.py +6 -3
  23. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/environment.py +50 -29
  24. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/expression.py +1 -1
  25. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/model_candidate.py +12 -4
  26. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/preparation.py +1 -4
  27. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/prompt.py +3 -17
  28. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/runner.py +12 -17
  29. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/scoping.py +13 -7
  30. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/step_context.py +2 -5
  31. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/step_executor.py +17 -11
  32. nighthawk_python-0.16.0/src/nighthawk/runtime/step_request.py +99 -0
  33. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/testing.py +25 -23
  34. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_coding_agent_examples.py +1 -1
  35. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_error_examples.py +1 -1
  36. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_readme_example.py +1 -1
  37. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_runtime_examples.py +3 -0
  38. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_natural_composition.py +19 -17
  39. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/lifecycle/test_embedded.py +8 -4
  40. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/lifecycle/test_step_completion.py +1 -1
  41. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/lifecycle/test_step_ledger.py +1 -1
  42. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_runtime_name_hygiene.py +7 -6
  43. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/oversight/test_step_commit.py +9 -12
  44. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_composition.py +2 -2
  45. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_retry.py +1 -1
  46. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_discovery.py +7 -7
  47. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_embedded.py +37 -4
  48. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_environment.py +32 -14
  49. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_executor_contract.py +6 -1
  50. nighthawk_python-0.16.0/tests/runtime/test_explicit_sharing.py +317 -0
  51. nighthawk_python-0.16.0/tests/runtime/test_input_patterns.py +151 -0
  52. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_model_selection.py +2 -2
  53. nighthawk_python-0.16.0/tests/runtime/test_output_selection.py +135 -0
  54. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_preparation.py +1 -1
  55. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_runner.py +10 -5
  56. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_step_executor.py +5 -1
  57. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_workflows.py +5 -5
  58. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/executors.py +4 -3
  59. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_testing.py +28 -26
  60. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/uv.lock +36 -36
  61. nighthawk_python-0.15.0/src/nighthawk/runtime/step_request.py +0 -61
  62. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/docs.md +0 -0
  63. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/evals.md +0 -0
  64. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/promptfoo.md +0 -0
  65. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/python.md +0 -0
  66. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/src.md +0 -0
  67. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/rules/tests.md +0 -0
  68. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/settings.json +0 -0
  69. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.claude/unset_envs.sh +0 -0
  70. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.devcontainer/devcontainer-lock.json +0 -0
  71. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.devcontainer/devcontainer.json +0 -0
  72. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.devcontainer/postCreateCommand.sh +0 -0
  73. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.github/dependabot.yml +0 -0
  74. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.gitignore +0 -0
  75. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/.python-version +0 -0
  76. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/AGENTS.md +0 -0
  77. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/CLAUDE.md +0 -0
  78. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/CONTRIBUTING.md +0 -0
  79. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/LICENSE +0 -0
  80. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/README.md +0 -0
  81. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/AGENTS.md +0 -0
  82. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/api.md +0 -0
  83. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/assets/nighthawk_logo-128x128.png +0 -0
  84. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/coding-agent-backends.md +0 -0
  85. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/index.md +0 -0
  86. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/philosophy.md +0 -0
  87. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/pydantic-ai-providers.md +0 -0
  88. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/docs/quickstart.md +0 -0
  89. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/AGENTS.md +0 -0
  90. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/coding_agents/evidence/20260914-guide-assessment.md +0 -0
  91. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/__init__.py +0 -0
  92. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/cases.py +0 -0
  93. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260908-tool-design-review.md +0 -0
  94. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-assessment.md +0 -0
  95. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-configurations.json +0 -0
  96. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-assessment.md +0 -0
  97. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-configurations.json +0 -0
  98. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-guidance.md +0 -0
  99. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-main.md +0 -0
  100. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-selected-traces.json +0 -0
  101. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-gpt56-trials.csv +0 -0
  102. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-guidance.md +0 -0
  103. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-main.md +0 -0
  104. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-selected-traces.json +0 -0
  105. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260909-trials.csv +0 -0
  106. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260910-natural-composition.md +0 -0
  107. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260910-python-boundaries.md +0 -0
  108. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-ideal-state-audit.md +0 -0
  109. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-inspection-artifact-manifest.json +0 -0
  110. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-inspection-assessment.md +0 -0
  111. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-inspection-failure-traces.jsonl +0 -0
  112. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-inspection-study-protocol.md +0 -0
  113. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/evidence/20260911-inspection-trial-metrics.csv +0 -0
  114. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/prototype.py +0 -0
  115. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/report.py +0 -0
  116. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/model_tools/run.py +0 -0
  117. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/AGENTS.md +0 -0
  118. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/assertions/__init__.py +0 -0
  119. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/assertions/binding_value.py +0 -0
  120. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/assertions/outcome_kind.py +0 -0
  121. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/assertions/raise_message.py +0 -0
  122. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/evidence/2026-03-26-baseline-prompt-ab.md +0 -0
  123. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/evidence/2026-03-26-baseline-regression.md +0 -0
  124. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/evidence/2026-03-26-baseline-suffix-ab.md +0 -0
  125. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/evidence/2026-04-27-runtime-prompt-optimization.md +0 -0
  126. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/promptfooconfig-agents.yaml +0 -0
  127. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/promptfooconfig-luna-sanity.yaml +0 -0
  128. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/promptfooconfig-prompt-ab.yaml +0 -0
  129. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/promptfooconfig-suffix-ab.yaml +0 -0
  130. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/promptfooconfig.yaml +0 -0
  131. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/prompts/eval_coding_agent.txt +0 -0
  132. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/prompts/eval_default.txt +0 -0
  133. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/prompts/eval_legacy_default.txt +0 -0
  134. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/prompts/eval_mutation_aware.txt +0 -0
  135. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/prompts/eval_sequenced.txt +0 -0
  136. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/provider.py +0 -0
  137. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/research-result.md +0 -0
  138. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/binding_operations.yaml +0 -0
  139. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/edge_cases.yaml +0 -0
  140. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/loop_outcomes.yaml +0 -0
  141. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/loop_outcomes_ja.yaml +0 -0
  142. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/multi_step.yaml +0 -0
  143. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/null_handling.yaml +0 -0
  144. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/outcome_kinds.yaml +0 -0
  145. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/evals/promptfoo/test_cases/tool_selection.yaml +0 -0
  146. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/mkdocs.yml +0 -0
  147. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/pyrightconfig.json +0 -0
  148. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/AGENTS.md +0 -0
  149. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/__init__.py +0 -0
  150. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/__init__.py +0 -0
  151. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/_text_fallback.py +0 -0
  152. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/base.py +0 -0
  153. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/claude_code_cli.py +0 -0
  154. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/claude_code_sdk.py +0 -0
  155. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/claude_code_settings.py +0 -0
  156. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/codex.py +0 -0
  157. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/mcp_boundary.py +0 -0
  158. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/mcp_server.py +0 -0
  159. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/process_management.py +0 -0
  160. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/text_projection.py +0 -0
  161. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/tool_bridge.py +0 -0
  162. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/backends/tool_transport.py +0 -0
  163. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/errors.py +0 -0
  164. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/identifier_path.py +0 -0
  165. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/json_renderer.py +0 -0
  166. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/lifecycle.py +0 -0
  167. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/__init__.py +0 -0
  168. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/_names.py +0 -0
  169. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/blocks.py +0 -0
  170. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/decorator.py +0 -0
  171. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/definition.py +0 -0
  172. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/natural/transform.py +0 -0
  173. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/__init__.py +0 -0
  174. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_budget.py +0 -0
  175. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_circuit_breaker.py +0 -0
  176. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_fallback.py +0 -0
  177. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_retry.py +0 -0
  178. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_timeout.py +0 -0
  179. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/resilience/_vote.py +0 -0
  180. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/__init__.py +0 -0
  181. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/_user_content.py +0 -0
  182. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/annotations.py +0 -0
  183. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/assignment.py +0 -0
  184. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/async_bridge.py +0 -0
  185. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/bindings.py +0 -0
  186. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/context.py +0 -0
  187. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/description.py +0 -0
  188. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/discovery.py +0 -0
  189. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/embedded.py +0 -0
  190. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/execution_reference.py +0 -0
  191. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/inspection.py +0 -0
  192. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/interruption.py +0 -0
  193. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/notifications.py +0 -0
  194. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/operation_contract.py +0 -0
  195. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/operations.py +0 -0
  196. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/step_contract.py +0 -0
  197. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/step_definition.py +0 -0
  198. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/step_result.py +0 -0
  199. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/runtime/tool_calls.py +0 -0
  200. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/__init__.py +0 -0
  201. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/_admission.py +0 -0
  202. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/_ordering.py +0 -0
  203. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/_tool_return_content.py +0 -0
  204. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/assignment.py +0 -0
  205. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/contracts.py +0 -0
  206. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/declarations.py +0 -0
  207. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/execution.py +0 -0
  208. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/tools/provided.py +0 -0
  209. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/src/nighthawk/ulid.py +0 -0
  210. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/AGENTS.md +0 -0
  211. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/README.md +0 -0
  212. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/__init__.py +0 -0
  213. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/__init__.py +0 -0
  214. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_base.py +0 -0
  215. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_claude_code_cli.py +0 -0
  216. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_claude_code_sdk.py +0 -0
  217. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_codex.py +0 -0
  218. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_mcp_boundary.py +0 -0
  219. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_process_management.py +0 -0
  220. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_text_fallback.py +0 -0
  221. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_text_projection.py +0 -0
  222. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_tool_bridge.py +0 -0
  223. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/backends/test_tool_transport.py +0 -0
  224. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/conftest.py +0 -0
  225. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/__init__.py +0 -0
  226. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_integrity.py +0 -0
  227. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_links.py +0 -0
  228. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/docs/test_prompt_examples.py +0 -0
  229. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/evals/__init__.py +0 -0
  230. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/evals/model_tools/__init__.py +0 -0
  231. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/evals/model_tools/test_inspection_study.py +0 -0
  232. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/evals/model_tools/test_prototype.py +0 -0
  233. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/__init__.py +0 -0
  234. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/skip_helpers.py +0 -0
  235. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_carry_pattern.py +0 -0
  236. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_claude_code_cli.py +0 -0
  237. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_claude_code_sdk.py +0 -0
  238. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_codex.py +0 -0
  239. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_openai.py +0 -0
  240. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/integration/test_openai_multimodal.py +0 -0
  241. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/lifecycle/__init__.py +0 -0
  242. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/lifecycle/test_notifications.py +0 -0
  243. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/__init__.py +0 -0
  244. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_block_ordering.py +0 -0
  245. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_blocks.py +0 -0
  246. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_decorator_globals.py +0 -0
  247. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_deferred_annotations.py +0 -0
  248. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_function_definition.py +0 -0
  249. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_introspection.py +0 -0
  250. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_lexical_contract.py +0 -0
  251. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_methods.py +0 -0
  252. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_traceback.py +0 -0
  253. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/natural/test_variadic_contracts.py +0 -0
  254. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/oversight/__init__.py +0 -0
  255. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/oversight/test_embedded_commit.py +0 -0
  256. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/oversight/test_return_expression.py +0 -0
  257. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/__init__.py +0 -0
  258. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_budget.py +0 -0
  259. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_circuit_breaker.py +0 -0
  260. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_fallback.py +0 -0
  261. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_timeout.py +0 -0
  262. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/resilience/test_vote.py +0 -0
  263. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/__init__.py +0 -0
  264. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_assignment.py +0 -0
  265. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_async_bridge.py +0 -0
  266. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_bindings.py +0 -0
  267. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_capabilities.py +0 -0
  268. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_context.py +0 -0
  269. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_description.py +0 -0
  270. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_expression.py +0 -0
  271. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_managed_model.py +0 -0
  272. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_model_candidate.py +0 -0
  273. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_model_operation_failures.py +0 -0
  274. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_operations.py +0 -0
  275. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_prompt_globals.py +0 -0
  276. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_prompt_multimodal.py +0 -0
  277. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_prompt_system.py +0 -0
  278. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_prompt_values.py +0 -0
  279. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_request_observation.py +0 -0
  280. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_scope_composition.py +0 -0
  281. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_scoping.py +0 -0
  282. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_step_contract.py +0 -0
  283. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_step_definition.py +0 -0
  284. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_tracing.py +0 -0
  285. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/runtime/test_usage_meter.py +0 -0
  286. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/__init__.py +0 -0
  287. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/codex.py +0 -0
  288. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/contexts.py +0 -0
  289. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/host_controls.py +0 -0
  290. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/prompts.py +0 -0
  291. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/tools.py +0 -0
  292. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/support/values.py +0 -0
  293. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_composition.py +0 -0
  294. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_configuration.py +0 -0
  295. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_function_call.py +0 -0
  296. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_json_renderer.py +0 -0
  297. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/test_public_api.py +0 -0
  298. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/__init__.py +0 -0
  299. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_admission.py +0 -0
  300. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_assignment_async.py +0 -0
  301. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_contracts.py +0 -0
  302. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_coroutine_ownership.py +0 -0
  303. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_declarations.py +0 -0
  304. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_discovery_content.py +0 -0
  305. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_execution.py +0 -0
  306. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_ordering.py +0 -0
  307. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_provided_async.py +0 -0
  308. {nighthawk_python-0.15.0 → nighthawk_python-0.16.0}/tests/tools/test_tool_return_content.py +0 -0
@@ -24,7 +24,7 @@ jobs:
24
24
  persist-credentials: false
25
25
 
26
26
  # setup-uv publishes no floating major tag since v8, so pin an exact release.
27
- - uses: astral-sh/setup-uv@v10.0.1
27
+ - uses: astral-sh/setup-uv@v10.3.0
28
28
  with:
29
29
  python-version: "3.13"
30
30
  # Same dependency set and cache key as "test (3.13)". Only that job
@@ -32,16 +32,16 @@ jobs:
32
32
  save-cache: false
33
33
 
34
34
  - name: Install dependencies
35
- run: uv sync --all-extras --all-groups
35
+ run: uv sync --locked --all-extras --all-groups
36
36
 
37
37
  - name: Format check
38
- run: uv run ruff format --check .
38
+ run: uv run --no-sync ruff format --check .
39
39
 
40
40
  - name: Lint
41
- run: uv run ruff check .
41
+ run: uv run --no-sync ruff check .
42
42
 
43
43
  - name: Type check
44
- run: uv run pyright
44
+ run: uv run --no-sync pyright
45
45
 
46
46
  test:
47
47
  name: Test (Python ${{ matrix.python-version }})
@@ -49,23 +49,22 @@ jobs:
49
49
  strategy:
50
50
  fail-fast: false
51
51
  matrix:
52
- python-version: ["3.13", "3.14"]
53
- continue-on-error: ${{ matrix.python-version != '3.13' }}
52
+ python-version: ["3.13", "3.14", "3.15"]
54
53
  steps:
55
54
  - uses: actions/checkout@v7
56
55
  with:
57
56
  persist-credentials: false
58
57
 
59
58
  # Sole writer of the per-Python-version dependency cache.
60
- - uses: astral-sh/setup-uv@v10.0.1
59
+ - uses: astral-sh/setup-uv@v10.3.0
61
60
  with:
62
61
  python-version: ${{ matrix.python-version }}
63
62
 
64
63
  - name: Install dependencies
65
- run: uv sync --all-extras --all-groups
64
+ run: uv sync --locked --all-extras --all-groups
66
65
 
67
66
  - name: Run tests
68
- run: uv run pytest -q
67
+ run: uv run --no-sync pytest -q
69
68
 
70
69
  build:
71
70
  name: Build distribution
@@ -78,7 +77,7 @@ jobs:
78
77
 
79
78
  # Keep packaging and its fresh installation check independent of the
80
79
  # source test job's dependency cache.
81
- - uses: astral-sh/setup-uv@v10.0.1
80
+ - uses: astral-sh/setup-uv@v10.3.0
82
81
  with:
83
82
  enable-cache: false
84
83
 
@@ -87,14 +86,15 @@ jobs:
87
86
 
88
87
  - name: Verify documented examples against the installed wheel
89
88
  run: |
90
- uv sync --all-groups
89
+ uv sync --locked --all-groups
91
90
  uv venv "$RUNNER_TEMP/nighthawk-distribution"
92
91
  uv pip install --python "$RUNNER_TEMP/nighthawk-distribution/bin/python" dist/*.whl
93
92
  NIGHTHAWK_DISTRIBUTION_PYTHON="$RUNNER_TEMP/nighthawk-distribution/bin/python" \
94
- uv run pytest -q tests/docs/test_runtime_examples.py
93
+ uv run --no-sync pytest -q tests/docs/test_runtime_examples.py
95
94
 
96
95
  - name: Upload distribution artifacts
97
- uses: actions/upload-artifact@v6
96
+ uses: actions/upload-artifact@v7
98
97
  with:
99
98
  name: python-package-distributions
100
99
  path: dist/
100
+ if-no-files-found: error
@@ -1,4 +1,4 @@
1
- name: Deploy docs to GitHub Pages
1
+ name: Build and deploy docs to GitHub Pages
2
2
 
3
3
  on:
4
4
  push:
@@ -8,26 +8,38 @@ on:
8
8
  - "src/nighthawk/**"
9
9
  - "mkdocs.yml"
10
10
  - "pyproject.toml"
11
+ - "uv.lock"
12
+ - ".python-version"
13
+ - ".github/workflows/docs.yml"
14
+ pull_request:
15
+ branches: [main]
16
+ paths:
17
+ - "docs/**"
18
+ - "src/nighthawk/**"
19
+ - "mkdocs.yml"
20
+ - "pyproject.toml"
21
+ - "uv.lock"
22
+ - ".python-version"
11
23
  - ".github/workflows/docs.yml"
12
24
  workflow_dispatch:
13
25
 
14
26
  permissions:
15
27
  contents: read
16
- pages: write
17
- id-token: write
18
28
 
19
29
  concurrency:
20
- group: pages
21
- cancel-in-progress: false
30
+ group: pages-${{ github.event_name == 'pull_request' && github.ref || 'deployment' }}
31
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
22
32
 
23
33
  jobs:
24
34
  build:
25
35
  runs-on: ubuntu-latest
26
36
  steps:
27
37
  - uses: actions/checkout@v7
38
+ with:
39
+ persist-credentials: false
28
40
 
29
41
  # setup-uv publishes no floating major tag since v8, so pin an exact release.
30
- - uses: astral-sh/setup-uv@v10.0.1
42
+ - uses: astral-sh/setup-uv@v10.3.0
31
43
  with:
32
44
  python-version: "3.13"
33
45
  # The docs group is a subset of the cache "test (3.13)" saves under
@@ -35,18 +47,24 @@ jobs:
35
47
  save-cache: false
36
48
 
37
49
  - name: Install dependencies
38
- run: uv sync --group docs
50
+ # The default dev group supplies Ruff for API signature formatting.
51
+ run: uv sync --locked --group docs
39
52
 
40
53
  - name: Build docs
41
- run: uv run mkdocs build
54
+ run: uv run --no-sync mkdocs build
42
55
 
43
56
  - uses: actions/upload-pages-artifact@v5
57
+ if: github.event_name != 'pull_request'
44
58
  with:
45
59
  path: site
46
60
 
47
61
  deploy:
62
+ if: github.event_name != 'pull_request'
48
63
  needs: build
49
64
  runs-on: ubuntu-latest
65
+ permissions:
66
+ pages: write
67
+ id-token: write
50
68
  environment:
51
69
  name: github-pages
52
70
  url: ${{ steps.deployment.outputs.page_url }}
@@ -24,7 +24,7 @@ jobs:
24
24
  id-token: write
25
25
  steps:
26
26
  - name: Download distribution artifacts
27
- uses: actions/download-artifact@v7
27
+ uses: actions/download-artifact@v8
28
28
  with:
29
29
  name: python-package-distributions
30
30
  path: dist/
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.16.0]
11
+
12
+ ### Changed
13
+
14
+ - Breaking: `StepCandidate` and testing responses distinguish omitted output selection (`UNSET`, select initialized declared outputs) from an explicit complete mapping (`{}`, no writes). Added `StepRequest.snapshot_output_bindings()` for explicit Python composition. `StepResponse` and response factories use `binding_name_to_value`; keyword-expanded output arguments are removed.
15
+ - Breaking: `Raise` rejects explicit nonempty output mappings in candidates and rewrites. Standard agent executors retain automatic output selection and final validation.
16
+ - Breaking: optional executor configuration and run identifiers use `UNSET`; invalid `None`, raw configuration dictionaries, and empty run identifiers fail at entry. Environment mappings reject `None`, and `StepExecutorConfiguration.model_settings` defaults to an empty dictionary.
17
+ - `function_call_scope` now supports omission or `UNSET` for inheritance, `None` for clearing, and validated handler replacement.
18
+ - Breaking: Natural functions no longer copy parent working values into their environment. Share values through Python arguments, globals, closures, or explicit `scope(task_references=...)`; ordinary Python helpers can select references from the active environment. Removed the `parent` name source and `parent_name_to_value` from `StepEnvironment` and test-call records.
19
+ - Documented explicit working-state snapshots, scoped reference replacement and clearing, and synchronous/asynchronous host sharing examples. Updated composition examples to declare their dependencies.
20
+
21
+ ### Fixed
22
+
23
+ - Falsey nonempty mappings and configuration objects retain their explicit values; invalid scope arguments fail before model resolution.
24
+ - Nested configuration and sharing scopes preserve the active step identity so child executions retain their parent-step correlation.
25
+
10
26
  ## [0.15.0]
11
27
 
12
28
  ### Added
@@ -43,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
43
59
 
44
60
  ### Fixed
45
61
 
62
+ - Embedded step type annotations resolve explicit and scoped names on Python 3.14, including nested forward references and names that shadow builtins.
46
63
  - Dynamic annotation validation uses explicit `TypeForm[object]` casts at Pydantic `TypeAdapter` boundaries, restoring type-checking compatibility with Pydantic 2.14 without changing runtime validation. Declared `typing-extensions` as a direct dependency.
47
64
  - Error-handling guides distinguish Natural-selected exceptions, recoverable tool errors, and finalization failures. Published handlers are executed against deterministic runtime responses.
48
65
  - Tests follow environment, prompt, executor, and model-selection ownership; scope tests use current composition terminology and avoid duplicate replacement checks or fixed instrumentation names.
@@ -347,7 +364,8 @@ Invalid initial results fail before oversight; use resilience retries to recover
347
364
  - Step executor abstraction and provider integration foundation.
348
365
  - Core documentation and project scaffolding.
349
366
 
350
- [Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.15.0...HEAD
367
+ [Unreleased]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.16.0...HEAD
368
+ [0.16.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.15.0...v0.16.0
351
369
  [0.15.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.14.0...v0.15.0
352
370
  [0.14.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.13.0...v0.14.0
353
371
  [0.13.0]: https://github.com/kurusugawa-computer/nighthawk-python/compare/v0.12.0...v0.13.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: nighthawk-python
3
- Version: 0.15.0
3
+ Version: 0.16.0
4
4
  Summary: A Python library where Python controls flow and LLMs or coding agents reason within constrained Natural blocks.
5
5
  Project-URL: Repository, https://github.com/kurusugawa-computer/nighthawk-python
6
6
  Project-URL: Documentation, https://kurusugawa-computer.github.io/nighthawk-python/
@@ -168,6 +168,25 @@ The expected benefit is less custom host integration for dynamic declarations an
168
168
  Success requires correct per-invocation value contracts and completion records that reflect writeback failures.
169
169
  Compare the effort and complexity of constructing and changing this integration with an ordinary Python implementation providing the same guarantees.
170
170
 
171
+ ## Explicit sharing across nested Natural calls
172
+
173
+ **Status:** The name-resolution contract is covered by deterministic tests in `tests/runtime/test_explicit_sharing.py`, with executable synchronous and asynchronous [sharing examples](runtime-configuration.md#selecting-shared-values-with-python).
174
+ The originating evidence is one embedded conversation host's v0.15.0 reproduction; independent application evidence and model-quality improvements remain unevaluated.
175
+
176
+ The host calls reusable Natural functions from a step containing conversation input and temporary working values.
177
+ Automatically copying those working names into children creates dependencies beyond the child's arguments, Python lexical environment, and deliberately shared references.
178
+ A context builder can omit prompt content but cannot change preparation-time binding resolution or runtime name lookup.
179
+ Requiring host executors to reconstruct Core preparation would move execution complexity into applications.
180
+
181
+ Core therefore constructs each child's own Python environment and supplies only the active scope's explicit task references as additional names.
182
+ Applications select values using ordinary Python helpers and pass dictionaries through `scope(task_references=...)`; no inheritance mode or environment-construction callback is required.
183
+ Scopes preserve execution parentage and existing management contracts while replacing or clearing shared references.
184
+ This simplifies an existing execution semantic; it does not establish a general object-isolation facility.
185
+
186
+ The deterministic evidence covers absent parent bindings, preparation failures, real context construction, expression and discovery access, object identity, nested execution, and scoped asynchronous behavior.
187
+ It does not establish that separating names prevents repeated model calls or improves judgments.
188
+ Assess those hypotheses through application evaluations, including independent reuse and the effort needed to declare shared dependencies.
189
+
171
190
  ## Using Nighthawk to develop Nighthawk
172
191
 
173
192
  **Status:** Conceptual application direction.
@@ -36,7 +36,10 @@ Caller locals, globals, closure cells, and inherited parent working state are no
36
36
  Scoped configuration, execution identity, oversight, capabilities, and lifecycle retain their usual inheritance rules.
37
37
 
38
38
  Called Python functions retain their own closures and globals.
39
- Nested Natural functions use their own Python frames and the usual parent working-state inheritance; the explicit namespace is not installed as their local environment.
39
+ Nested Natural functions use their own Python frames and the active scope's explicit task references.
40
+ The explicit namespace and later parent temporaries do not become implicit inputs to those functions or their descendants.
41
+ Pass values as arguments, or use a Python helper to select references for `nh.scope(task_references=...)` before calling the child.
42
+ See the [synchronous and asynchronous sharing examples](runtime-configuration.md#selecting-shared-values-with-python).
40
43
  This selects an execution environment without isolating Python objects or restricting the authority of called functions.
41
44
 
42
45
  Omitting an output annotation selects the ordinary initial-value inference rule.
@@ -52,10 +55,13 @@ It returns `None` or an awaitable completing that assignment.
52
55
  Callbacks run sequentially in output declaration order; Core records a successful assignment only after its callback returns normally.
53
56
  Both entry points accept synchronous or asynchronous writers; the synchronous entry point uses the ordinary bridge for awaitables.
54
57
 
55
- Normal finalization includes initialized declared outputs, even if the executor does not propose them.
56
- Tracked working values take precedence over initial values, and explicit executor proposals take precedence over both.
57
- Uninitialized outputs without proposals remain absent.
58
- An initial `Raise` discards outputs before value validation while still rejecting undeclared names.
58
+ When `StepCandidate.binding_name_to_value` is omitted or `nh.UNSET`, finalization selects initialized declared outputs.
59
+ Tracked working values take precedence over current Python values; uninitialized outputs and task-only references remain absent.
60
+ A supplied mapping selects exactly those outputs, including when it is empty; omitted names are neither supplemented nor validated for writeback.
61
+ Selected values must satisfy their output contracts before commit inspection.
62
+ Use `request.snapshot_output_bindings()` and ordinary Python dictionary composition to explicitly combine current output values with replacements.
63
+ An initial `Raise` selects no outputs and skips validation of pending working values.
64
+ Pairing `Raise` with an explicitly supplied nonempty output mapping is invalid for both `StepCandidate` and `Rewrite`.
59
65
  A commit `Rewrite` with an explicitly supplied mapping replaces the selected outputs completely; rewriting to `{}` does not restore initial values.
60
66
 
61
67
  These are separate facts:
@@ -71,6 +77,53 @@ An interrupted writer must finish its cancellation handling before control can r
71
77
  If a writer mutates storage and then raises, Core cannot infer whether the assignment completed; that writer owns diagnosis and recovery for its partial effects.
72
78
  This interface does not promise database transactions, rollback, retries, or durable storage.
73
79
 
80
+ This example uses the same executor with synchronous and asynchronous entry points to distinguish automatic, empty, explicit, and composed output selections.
81
+
82
+ <!-- runnable-example:output_selection -->
83
+ ```py
84
+ import asyncio
85
+
86
+ import nighthawk as nh
87
+ from nighthawk.runtime import Pass, StepCandidate, StepDefinition, StepRequest, execute_step, execute_step_async
88
+
89
+
90
+ class Executor:
91
+ def run_step(self, *, request: StepRequest) -> StepCandidate:
92
+ selection = request.processed_natural_program
93
+ if selection == "automatic":
94
+ return StepCandidate(outcome=Pass())
95
+ if selection == "empty":
96
+ return StepCandidate(outcome=Pass(), binding_name_to_value={})
97
+ if selection == "explicit":
98
+ return StepCandidate(outcome=Pass(), binding_name_to_value={"first": 7})
99
+ return StepCandidate(outcome=Pass(), binding_name_to_value={**request.snapshot_output_bindings(), "first": 7})
100
+
101
+
102
+ async def main() -> None:
103
+ selection_to_binding_name_to_value = {
104
+ "automatic": {"first": 1, "second": 2},
105
+ "empty": {},
106
+ "explicit": {"first": 7},
107
+ "composed": {"first": 7, "second": 2},
108
+ }
109
+ with nh.run(Executor()):
110
+ for asynchronous in (False, True):
111
+ for selection, expected_binding_name_to_value in selection_to_binding_name_to_value.items():
112
+ saved_name_to_value: dict[str, object] = {}
113
+ definition = StepDefinition(selection, output_binding_names=("first", "second"))
114
+ initial_name_to_value = {"first": 1, "second": 2}
115
+ if asynchronous:
116
+ await execute_step_async(definition, name_to_value=initial_name_to_value, write_binding=saved_name_to_value.__setitem__)
117
+ else:
118
+ execute_step(definition, name_to_value=initial_name_to_value, write_binding=saved_name_to_value.__setitem__)
119
+ assert saved_name_to_value == expected_binding_name_to_value
120
+
121
+
122
+ asyncio.run(main())
123
+ print("automatic=2; empty=0; explicit=1; composed=2; sync_and_async=True")
124
+ ```
125
+ <!-- /runnable-example:output_selection -->
126
+
74
127
  Terminal delivery happens after writeback or failure, with the usual `StepCompleted`, `StepRaised`, `StepFailed`, or `StepInterrupted` record.
75
128
  Notification failure propagates without replaying execution or notification and without undoing completed writes.
76
129
  The optional `source_location` labels the trusted program for diagnostics; its default is `<embedded>:0`.
@@ -107,7 +160,7 @@ definition = StepDefinition(
107
160
  binding_name_to_type={"summary": str},
108
161
  source_location="trusted_summary:1",
109
162
  )
110
- executor = ScriptedExecutor([pass_response(summary="The trial passed.")])
163
+ executor = ScriptedExecutor([pass_response(binding_name_to_value={"summary": "The trial passed."})])
111
164
  with nh.run(executor), nh.scope(lifecycle=StepLifecycle(finished)):
112
165
  outcome = execute_step(definition, name_to_value=name_to_value, write_binding=name_to_value.__setitem__)
113
166
 
@@ -159,7 +212,7 @@ async def main() -> None:
159
212
  binding_name_to_type={"selected": "Selection"},
160
213
  source_location="trusted_selection:1",
161
214
  )
162
- executor = ScriptedExecutor([pass_response(selected={"label": "alpha"})])
215
+ executor = ScriptedExecutor([pass_response(binding_name_to_value={"selected": {"label": "alpha"}})])
163
216
  with nh.run(executor), nh.scope(lifecycle=StepLifecycle(finished)):
164
217
  outcome = await execute_step_async(definition, name_to_value={"candidates": ["alpha", "beta"], "Selection": Selection}, write_binding=write)
165
218
  assert outcome == Pass()
@@ -30,6 +30,9 @@ step_executor = nh.AgentStepExecutor.from_configuration(configuration=configurat
30
30
 
31
31
  The `model` field accepts a `provider:model` identifier or a borrowed Pydantic AI `Model` instance whose client lifetime remains with the host.
32
32
  The default model is `openai-responses:gpt-5.6-luna`.
33
+ `model_settings` defaults to an empty dictionary; `None` and `UNSET` are invalid field values.
34
+ Optional executor configuration arguments use omission or `nh.UNSET` to create a fresh default configuration.
35
+ An explicit configuration replaces the complete value; raw dictionaries and `None` are rejected before constructing an agent.
33
36
 
34
37
  Use [Runtime configuration](runtime-configuration.md) to establish a run, select child models, or mix executors.
35
38
  Host wrappers can support model selection through the [configuration resolution protocol](specification.md#model-declarations-and-observation).
@@ -49,6 +52,42 @@ executor = nh.AgentStepExecutor.from_agent(agent=agent)
49
52
 
50
53
  For full control, implement `AsyncStepExecutor` directly. See [Specification Section 14.3](specification.md#143-custom-backends) for semantics and [API reference](api.md#runtime-executor-boundary) for the protocol.
51
54
 
55
+ ## Output selection
56
+
57
+ Executors return `StepCandidate(outcome=..., binding_name_to_value=...)`.
58
+ The output mapping selects the complete set of values to validate and consider for writeback.
59
+
60
+ | Selection | Meaning |
61
+ |---|---|
62
+ | Omitted or `nh.UNSET` | Select initialized declared outputs from the working environment at finalization. |
63
+ | `{}` | Select no writes, even when declared outputs already have values. |
64
+ | `{"result": value}` | Select only `result`; do not supplement other initialized outputs. |
65
+ | `None` | Invalid. |
66
+
67
+ The standard agent executor omits the selection, so its tracked assignments and other initialized declared outputs receive final validation.
68
+ An explicit selection validates only its entries; output names must still be declared, and commit inspection still applies.
69
+ Neither an empty selection nor a later rejection undoes earlier calls or in-place object mutations.
70
+ `Raise` permits only omitted or empty output selections.
71
+
72
+ For an explicit combination of current outputs and replacements, use ordinary Python:
73
+
74
+ ```py
75
+ from nighthawk.runtime import Pass, StepCandidate, StepRequest
76
+
77
+
78
+ def select_result(request: StepRequest, result: object) -> StepCandidate:
79
+ return StepCandidate(
80
+ outcome=Pass(),
81
+ binding_name_to_value={**request.snapshot_output_bindings(), "result": result},
82
+ )
83
+ ```
84
+
85
+ `snapshot_output_bindings()` returns a fresh dictionary in declaration order, preferring tracked assignments over current Python values, including live globals and cells.
86
+ Unbound outputs, temporaries, and task-only references are excluded.
87
+ The method preserves value identity and performs no validation or writes.
88
+ A snapshot fixes associations at the time it is taken; omission selects them later, during finalization.
89
+ `Rewrite` uses the same complete-mapping semantics after initial validation, with omission retaining the current commit field.
90
+
52
91
  ## Next steps
53
92
 
54
93
  - **[Pydantic AI providers](pydantic-ai-providers.md)** -- Installation, model identifiers, credentials, and model settings for each Pydantic AI provider.
@@ -89,7 +89,7 @@ Read [Quickstart](https://kurusugawa-computer.github.io/nighthawk-python/quickst
89
89
  - Use `deny` frontmatter to prohibit outcomes that would bypass required Python work. The template denies `return` to preserve the Python return path and denies the explicit `raise` outcome; runtime and helper failures can still raise.
90
90
  - Denying outcomes does not require a fresh assignment. A permitted `pass` can retain an output's initial value. Use a deliberate default or an unbound annotated output, and validate the result before dependent work.
91
91
  - Each block starts a fresh model interaction without implicit message history. Carry essential inputs and results through Python parameters and return values.
92
- - Lexical values, inherited parent working state, and scoped task references can supply context. Prefer explicit arguments for essential dependencies and inheritance for intentionally shared policy. Child name rebinding stays local; mutable objects can remain shared.
92
+ - Python lexical values and scoped task references supply context. Prefer explicit arguments for essential dependencies and `scope(task_references=...)` for intentionally shared policy. Parent working values are not copied into children. Child name rebinding stays local; explicitly shared mutable objects retain identity.
93
93
 
94
94
  The type boundary may sit inside a function: accept text that needs interpretation, then commit a typed result before deterministic work begins.
95
95
  Types constrain the result's shape and range; they do not prove that its meaning is correct.
@@ -189,8 +189,8 @@ def test_quote_batch_processes_each_message_and_uses_host_price():
189
189
  messages = ["A dozen, please.", "Please send three."]
190
190
  executor = ScriptedExecutor(
191
191
  responses=[
192
- pass_response(order={"quantity": 12}),
193
- pass_response(order={"quantity": 3}),
192
+ pass_response(binding_name_to_value={"order": {"quantity": 12}}),
193
+ pass_response(binding_name_to_value={"order": {"quantity": 3}}),
194
194
  ],
195
195
  )
196
196
  with nh.run(executor):
@@ -199,14 +199,14 @@ def test_quote_batch_processes_each_message_and_uses_host_price():
199
199
 
200
200
 
201
201
  def test_quote_batch_stops_when_quantity_is_unclear():
202
- executor = ScriptedExecutor(responses=[pass_response(order={"quantity": None})])
202
+ executor = ScriptedExecutor(responses=[pass_response(binding_name_to_value={"order": {"quantity": None}})])
203
203
  with nh.run(executor), pytest.raises(ValueError, match="Quantity needs clarification"):
204
204
  quote_batch(["A few, please.", "Then three more."], unit_price_cents=250)
205
205
  assert len(executor.calls) == 1
206
206
 
207
207
 
208
208
  def test_quote_batch_rejects_invalid_model_output():
209
- executor = ScriptedExecutor(responses=[pass_response(order={"quantity": 0})])
209
+ executor = ScriptedExecutor(responses=[pass_response(binding_name_to_value={"order": {"quantity": 0}})])
210
210
  with nh.run(executor), pytest.raises(nh.ExecutionError):
211
211
  quote_batch(["One, please."], unit_price_cents=250)
212
212
  ```
@@ -81,7 +81,7 @@ Presentation is a view of accessible state, not its authority or a replacement f
81
81
 
82
82
  Each Natural block performs one task with declared output bindings and one outcome.
83
83
  There is no implicit model message history between blocks.
84
- Python values, inherited parent working state, and scoped task references supply context to each fresh interaction (see [Patterns: cross-block composition](patterns.md#cross-block-composition)).
84
+ Python lexical values and explicitly scoped task references supply context to each fresh interaction (see [Patterns: cross-block composition](patterns.md#cross-block-composition)).
85
85
 
86
86
  ## Providing data to a block
87
87
 
@@ -150,7 +150,8 @@ An explicit output annotation determines its validation contract at block entry.
150
150
  Without one, the runtime infers the initialized value's type, except for `None` and a plain `object()`; otherwise the output is unconstrained.
151
151
  Annotate collections explicitly when element types matter: `findings: list[Finding] = []` retains its element contract, while `findings = []` selects only `list`.
152
152
  An unresolved explicit annotation fails preparation instead of silently falling back to inference.
153
- All bound declared outputs receive final validation even if the model never assigns them; an initial Raise discards pending outputs.
153
+ The standard executor selects all bound declared outputs for final validation even if the model never assigns them; an initial Raise discards pending outputs.
154
+ Custom executors may supply an explicit complete output selection; see [output selection](executors.md#output-selection).
154
155
  Output contracts constrain values, not the factual correctness of a judgment.
155
156
  See [binding contracts](specification.md#7-natural-dsl-bindings) for annotation acquisition and global/nonlocal writeback.
156
157
 
@@ -401,7 +402,7 @@ Function parameters and working locals are candidates for LOCALS, and explicit m
401
402
 
402
403
  Keep fewer incidental locals alive when they do not help the judgment. A callable passed through a parameter retains its live callable metadata even when the parameter annotation is `object`, `Any`, or absent. Signature and documentation acquisition are best-effort and do not execute application properties or annotation expressions.
403
404
 
404
- Use explicit parameters for essential inputs and independent reuse. Module globals and task injection can supply shared capabilities; inherited working state supplies deliberately shared parent context. These layers preserve their provenance and remain available beyond the initial presentation budget.
405
+ Use explicit parameters for essential inputs and independent reuse. Module globals and task references can supply shared capabilities and context. Parent working values are not copied into children; select values in ordinary Python and supply them through arguments or `nh.scope(task_references=...)`. These layers preserve their provenance and remain available beyond the initial presentation budget.
405
406
 
406
407
  **Note:** Nighthawk also accepts native tools through `nh.scope(tools=[...])`, which exposes functions via the model's native tool-calling interface for the duration of the scope. This path is reserved for cases that need native tool calling, such as strict argument schemas or Pydantic AI tool features. Binding functions are preferred for all other uses because they incur no per-definition token overhead beyond a signature line in the prompt context. See [Runtime configuration](runtime-configuration.md#scoped-tools) and [Specification Section 8.3](specification.md#83-tools-available-to-the-llm).
407
408
 
@@ -257,7 +257,7 @@ async def classify_batch(texts: list[str]) -> list[str]:
257
257
  ```
258
258
 
259
259
  Each concurrent Natural block has its own step context and no shared model message history.
260
- Inherited Python objects and host accounting can still be shared; `asyncio.gather` is appropriate when those shared values are safe for concurrent use.
260
+ Explicit Python references and host accounting can still be shared; `asyncio.gather` is appropriate when those shared values are safe for concurrent use.
261
261
  Tasks capture their selected context when created, including model selection and function-call handlers; awaiting a task elsewhere does not replace that context.
262
262
 
263
263
  ### Async and sync interoperability
@@ -274,10 +274,10 @@ You can therefore use async binding functions through tools without changing a s
274
274
  ## Cross-block composition
275
275
 
276
276
  Each Natural block starts a fresh model interaction ([one block, one task](natural-blocks.md#one-block-one-task)).
277
- Use Python arguments and returned values for essential inputs and results, inherited parent working state for intentionally shared task context, and scoped task references for injected capabilities.
278
- Joined children inherit materialized parent associations at entry; shared objects remain live, while child name rebinding does not update the parent.
279
- Children that outlive their parent have no inheritance guarantee.
280
- The [environment contract](specification.md#813-parent-lifetime-and-expression-lifetime) defines the precise boundaries.
277
+ Use Python arguments and returned values for essential inputs and results, and scoped task references for deliberately shared context and capabilities.
278
+ Children do not receive a parent's working values automatically; explicitly shared objects remain live, while child name rebinding does not update the parent.
279
+ Hosts establish explicit inputs and execution scope for independent work that outlives a parent step.
280
+ The [environment contract](specification.md#813-shared-values-and-expression-lifetime) defines the precise boundaries.
281
281
 
282
282
  ### Python iteration with Natural judgment
283
283
 
@@ -317,7 +317,7 @@ async def summarize_and_assess(document: str) -> list[tuple[str, float]]:
317
317
  ### Natural selects follow-up assessments
318
318
 
319
319
  Here the parent chooses which claims need review.
320
- The child receives the document and claim explicitly, and inherits the parent's materialized review policy.
320
+ The child receives the document and claim as arguments, and the review policy through an explicit task-reference scope.
321
321
  Call these ordinary Natural functions inside `nh.run(executor)`:
322
322
 
323
323
  ```python
@@ -342,18 +342,19 @@ async def assess_claim(document: str, claim: str) -> float:
342
342
  async def review_claims(document: str, claims: list[str]) -> list[tuple[str, float]]:
343
343
  review_guidance = "Check quantitative and causal claims against direct evidence."
344
344
  assessments: list[tuple[str, float]] = []
345
- """natural
346
- Use <review_guidance> to choose claims from <claims> that need closer review.
347
- Call <assess_claim> with <document> and each selected claim, awaiting each result.
348
- Store the selected claims and their returned scores in <:assessments>.
349
- """
345
+ with nh.scope(task_references={"review_guidance": review_guidance}):
346
+ """natural
347
+ Use <review_guidance> to choose claims from <claims> that need closer review.
348
+ Call <assess_claim> with <document> and each selected claim, awaiting each result.
349
+ Store the selected claims and their returned scores in <:assessments>.
350
+ """
350
351
  return assessments
351
352
  ```
352
353
 
353
354
  The parent step remains active until its chosen calls finish.
354
- The policy does not need to pass through intermediate helper signatures, but `assess_claim` now has an inherited dependency: calling it independently requires supplying that policy, for example through task injection.
355
+ The policy does not need to pass through intermediate helper signatures, but `assess_claim` has an explicit scoped dependency: calling it independently requires supplying `review_guidance` through task references.
355
356
  Prefer an explicit policy parameter when independent reuse matters.
356
- The [nested execution acceptance example](specification.md#144-nested-execution-acceptance-example) isolates inheritance mechanics separately from this judgment task.
357
+ The [nested execution acceptance example](specification.md#144-nested-execution-acceptance-example) isolates explicit argument passing separately from this judgment task.
357
358
 
358
359
  ### The carry pattern
359
360
 
@@ -82,7 +82,7 @@ Explore explicit serialization of host data and correlation metadata for multi-p
82
82
 
83
83
  ### Async bridge ContextVar propagation
84
84
 
85
- Investigate propagating selected context-variable rebindings back from bridge threads while preserving [parent lifetime and shared-value boundaries](specification.md#813-parent-lifetime-and-expression-lifetime).
85
+ Investigate propagating selected context-variable rebindings back from bridge threads while preserving [shared-value and expression-lifetime boundaries](specification.md#813-shared-values-and-expression-lifetime).
86
86
 
87
87
  ## Implementation hardening
88
88