openfactory 0.2.0__tar.gz → 0.3.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 (988) hide show
  1. openfactory-0.3.0/PKG-INFO +41 -0
  2. openfactory-0.3.0/README.md +232 -0
  3. openfactory-0.3.0/openfactory/__init__.py +7 -0
  4. openfactory-0.3.0/openfactory/actions/__init__.py +369 -0
  5. openfactory-0.3.0/openfactory/actions/base.py +336 -0
  6. openfactory-0.3.0/openfactory/actions/catalog.py +5665 -0
  7. openfactory-0.3.0/openfactory/adapters/agent/base.py +686 -0
  8. openfactory-0.3.0/openfactory/adapters/agent/claude_code.py +1088 -0
  9. openfactory-0.3.0/openfactory/adapters/agent/codex.py +386 -0
  10. openfactory-0.3.0/openfactory/adapters/agent/kimi.py +315 -0
  11. openfactory-0.3.0/openfactory/adapters/agent/opencode.py +455 -0
  12. openfactory-0.3.0/openfactory/adapters/agent/roles.py +267 -0
  13. openfactory-0.3.0/openfactory/adapters/agent/techlead.py +108 -0
  14. openfactory-0.3.0/openfactory/adapters/board/azure_devops.py +763 -0
  15. openfactory-0.3.0/openfactory/adapters/board/base.py +305 -0
  16. openfactory-0.3.0/openfactory/adapters/board/columns.py +162 -0
  17. openfactory-0.3.0/openfactory/adapters/board/factory.py +230 -0
  18. openfactory-0.3.0/openfactory/adapters/board/jira.py +274 -0
  19. openfactory-0.3.0/openfactory/adapters/board/local.py +221 -0
  20. openfactory-0.3.0/openfactory/adapters/board_db.py +329 -0
  21. openfactory-0.3.0/openfactory/adapters/board_setup/local.py +72 -0
  22. openfactory-0.3.0/openfactory/adapters/credential/registry.py +190 -0
  23. openfactory-0.3.0/openfactory/adapters/environment/registry.py +186 -0
  24. openfactory-0.3.0/openfactory/adapters/forge/azure_devops.py +1746 -0
  25. openfactory-0.3.0/openfactory/adapters/forge/base.py +594 -0
  26. openfactory-0.3.0/openfactory/adapters/forge/github.py +1035 -0
  27. openfactory-0.3.0/openfactory/adapters/forge/local.py +823 -0
  28. openfactory-0.3.0/openfactory/adapters/reviewer/claude_code.py +140 -0
  29. openfactory-0.3.0/openfactory/adapters/reviewer/harness.py +154 -0
  30. openfactory-0.3.0/openfactory/adapters/sandbox/base.py +421 -0
  31. openfactory-0.3.0/openfactory/adapters/sandbox/worktree.py +438 -0
  32. openfactory-0.3.0/openfactory/adapters/tracker/azure_devops.py +942 -0
  33. openfactory-0.3.0/openfactory/adapters/tracker/base.py +630 -0
  34. openfactory-0.3.0/openfactory/adapters/tracker/github.py +611 -0
  35. openfactory-0.3.0/openfactory/adapters/tracker/github_project.py +748 -0
  36. openfactory-0.3.0/openfactory/adapters/tracker/jira.py +827 -0
  37. openfactory-0.3.0/openfactory/adapters/tracker/local.py +411 -0
  38. openfactory-0.3.0/openfactory/adapters/tracker/parse.py +535 -0
  39. openfactory-0.3.0/openfactory/adapters/tracker/registry.py +220 -0
  40. openfactory-0.3.0/openfactory/after_merge.py +81 -0
  41. openfactory-0.3.0/openfactory/agent_answer.py +199 -0
  42. openfactory-0.3.0/openfactory/api/app.py +3091 -0
  43. openfactory-0.3.0/openfactory/api/metrics_view.py +357 -0
  44. openfactory-0.3.0/openfactory/api/panel.html +4105 -0
  45. openfactory-0.3.0/openfactory/approvals.py +341 -0
  46. openfactory-0.3.0/openfactory/box_prove.py +1793 -0
  47. openfactory-0.3.0/openfactory/cli.py +3802 -0
  48. openfactory-0.3.0/openfactory/conformance/adapters.py +638 -0
  49. openfactory-0.3.0/openfactory/contracts/checks.py +254 -0
  50. openfactory-0.3.0/openfactory/contracts/item_space.py +86 -0
  51. openfactory-0.3.0/openfactory/contracts/refs.py +174 -0
  52. openfactory-0.3.0/openfactory/contracts/run.py +341 -0
  53. openfactory-0.3.0/openfactory/contracts/ticket.py +123 -0
  54. openfactory-0.3.0/openfactory/doctor.py +1782 -0
  55. openfactory-0.3.0/openfactory/factory.py +527 -0
  56. openfactory-0.3.0/openfactory/floor/ladder.py +661 -0
  57. openfactory-0.3.0/openfactory/floor/reading.py +660 -0
  58. openfactory-0.3.0/openfactory/identity/base.py +108 -0
  59. openfactory-0.3.0/openfactory/identity/local.py +252 -0
  60. openfactory-0.3.0/openfactory/identity/people.py +392 -0
  61. openfactory-0.3.0/openfactory/listeners.py +245 -0
  62. openfactory-0.3.0/openfactory/memory/messages.py +406 -0
  63. openfactory-0.3.0/openfactory/memory/transcript.py +267 -0
  64. openfactory-0.3.0/openfactory/observability/job_record.py +96 -0
  65. openfactory-0.3.0/openfactory/observability/query.py +89 -0
  66. openfactory-0.3.0/openfactory/observability/registry.py +260 -0
  67. openfactory-0.3.0/openfactory/observability/sqlite_metrics.py +246 -0
  68. openfactory-0.3.0/openfactory/onboarding/deployment.py +819 -0
  69. openfactory-0.3.0/openfactory/onboarding/spend.py +76 -0
  70. openfactory-0.3.0/openfactory/ops/impediment.py +295 -0
  71. openfactory-0.3.0/openfactory/orchestrator/machine.py +2941 -0
  72. openfactory-0.3.0/openfactory/org_defaults/engineering.md +92 -0
  73. openfactory-0.3.0/openfactory/plugins.py +226 -0
  74. openfactory-0.3.0/openfactory/preflight.py +575 -0
  75. openfactory-0.3.0/openfactory/product/authoring.py +1845 -0
  76. openfactory-0.3.0/openfactory/product/brownfield.py +240 -0
  77. openfactory-0.3.0/openfactory/product/case.py +409 -0
  78. openfactory-0.3.0/openfactory/product/channel.py +1463 -0
  79. openfactory-0.3.0/openfactory/product/confirm.py +841 -0
  80. openfactory-0.3.0/openfactory/product/corpus.py +533 -0
  81. openfactory-0.3.0/openfactory/product/intents.py +667 -0
  82. openfactory-0.3.0/openfactory/product/module.py +3305 -0
  83. openfactory-0.3.0/openfactory/product/queue.py +265 -0
  84. openfactory-0.3.0/openfactory/product/release.py +253 -0
  85. openfactory-0.3.0/openfactory/product/role.py +1356 -0
  86. openfactory-0.3.0/openfactory/product/staging.py +480 -0
  87. openfactory-0.3.0/openfactory/product/triage.py +310 -0
  88. openfactory-0.3.0/openfactory/product/voice.py +2392 -0
  89. openfactory-0.3.0/openfactory/registry.py +541 -0
  90. openfactory-0.3.0/openfactory/runtime/boxed_job.py +406 -0
  91. openfactory-0.3.0/openfactory/runtime/host.py +389 -0
  92. openfactory-0.3.0/openfactory/runtime/repairable.py +73 -0
  93. openfactory-0.3.0/openfactory/runtime/temporal/activities.py +5212 -0
  94. openfactory-0.3.0/openfactory/runtime/temporal/connection.py +246 -0
  95. openfactory-0.3.0/openfactory/runtime/temporal/io.py +645 -0
  96. openfactory-0.3.0/openfactory/runtime/temporal/schedule.py +498 -0
  97. openfactory-0.3.0/openfactory/runtime/temporal/standing.py +134 -0
  98. openfactory-0.3.0/openfactory/runtime/temporal/view.py +1267 -0
  99. openfactory-0.3.0/openfactory/runtime/temporal/vocabulary.py +64 -0
  100. openfactory-0.3.0/openfactory/runtime/temporal/worker.py +363 -0
  101. openfactory-0.3.0/openfactory/runtime/temporal/workflow.py +2632 -0
  102. openfactory-0.3.0/openfactory/techlead/__init__.py +40 -0
  103. openfactory-0.3.0/openfactory/techlead/classify.py +479 -0
  104. openfactory-0.3.0/openfactory/techlead/conversation.py +1402 -0
  105. openfactory-0.3.0/openfactory/techlead/voice.py +718 -0
  106. openfactory-0.3.0/openfactory/techlead/watch.py +647 -0
  107. openfactory-0.3.0/openfactory/testing/local_flow.py +272 -0
  108. openfactory-0.3.0/openfactory.egg-info/PKG-INFO +41 -0
  109. openfactory-0.3.0/openfactory.egg-info/SOURCES.txt +814 -0
  110. openfactory-0.3.0/pyproject.toml +229 -0
  111. openfactory-0.3.0/tests/test_a_card_is_named_in_the_forge_only_where_the_forge_owns_it.py +303 -0
  112. openfactory-0.3.0/tests/test_a_card_that_was_split_is_not_delivered_until_its_children_are.py +320 -0
  113. openfactory-0.3.0/tests/test_a_credential_is_asked_of_its_own_axis.py +466 -0
  114. openfactory-0.3.0/tests/test_a_credential_is_scoped.py +330 -0
  115. openfactory-0.3.0/tests/test_a_declined_read_is_said_where_it_is_read.py +260 -0
  116. openfactory-0.3.0/tests/test_a_delivered_card_is_closed_by_its_tracker.py +210 -0
  117. openfactory-0.3.0/tests/test_a_deployments_addresses_have_one_owner.py +592 -0
  118. openfactory-0.3.0/tests/test_a_disabled_project_does_not_look_armed.py +224 -0
  119. openfactory-0.3.0/tests/test_a_failing_check_is_read_for_what_it_is.py +780 -0
  120. openfactory-0.3.0/tests/test_a_finished_card_is_closed_as_delivered.py +466 -0
  121. openfactory-0.3.0/tests/test_a_forge_that_brings_its_own_credential_is_not_reported_as_having_none.py +262 -0
  122. openfactory-0.3.0/tests/test_a_frame_does_not_erase_what_it_omits.py +408 -0
  123. openfactory-0.3.0/tests/test_a_free_deployment_can_read_its_logs.py +337 -0
  124. openfactory-0.3.0/tests/test_a_fresh_install_reads_an_empty_store.py +93 -0
  125. openfactory-0.3.0/tests/test_a_job_branches_from_the_base_the_forge_holds.py +341 -0
  126. openfactory-0.3.0/tests/test_a_machine_made_hold_says_its_own_cause.py +379 -0
  127. openfactory-0.3.0/tests/test_a_manifest_can_be_proven_before_it_is_merged.py +369 -0
  128. openfactory-0.3.0/tests/test_a_manifest_that_loads_is_not_a_manifest_that_is_right.py +433 -0
  129. openfactory-0.3.0/tests/test_a_name_nobody_registered_is_not_removed.py +145 -0
  130. openfactory-0.3.0/tests/test_a_person_is_invited_not_signed_up.py +506 -0
  131. openfactory-0.3.0/tests/test_a_poller_that_is_on_is_not_a_poller_that_ticks.py +226 -0
  132. openfactory-0.3.0/tests/test_a_process_that_approves_keeps_one_engine_client.py +341 -0
  133. openfactory-0.3.0/tests/test_a_project_nobody_registered_is_never_a_500.py +184 -0
  134. openfactory-0.3.0/tests/test_a_promotion_the_box_cannot_run_is_refused_before_the_first_card.py +168 -0
  135. openfactory-0.3.0/tests/test_a_proposal_can_carry_what_to_change.py +270 -0
  136. openfactory-0.3.0/tests/test_a_proposal_whose_base_moved_still_lands_on_the_local_forge.py +303 -0
  137. openfactory-0.3.0/tests/test_a_provider_is_named_by_its_own_row.py +223 -0
  138. openfactory-0.3.0/tests/test_a_pull_request_is_read_and_merged_in_its_own_repository.py +374 -0
  139. openfactory-0.3.0/tests/test_a_refusal_is_not_an_answer.py +673 -0
  140. openfactory-0.3.0/tests/test_a_resume_re_enters_the_merge.py +311 -0
  141. openfactory-0.3.0/tests/test_a_scenario_is_one_criterion.py +296 -0
  142. openfactory-0.3.0/tests/test_a_staged_decision_survives_a_refresh.py +567 -0
  143. openfactory-0.3.0/tests/test_a_store_that_cannot_be_read_authorizes_nobody_and_says_so.py +529 -0
  144. openfactory-0.3.0/tests/test_a_stream_ends_when_its_credential_does.py +913 -0
  145. openfactory-0.3.0/tests/test_a_ticket_written_in_portuguese.py +181 -0
  146. openfactory-0.3.0/tests/test_a_trust_file_nobody_reads_is_a_green_proof.py +192 -0
  147. openfactory-0.3.0/tests/test_a_verdict_nobody_answers_is_said_so_inside_the_deadline.py +381 -0
  148. openfactory-0.3.0/tests/test_a_wait_can_say_until_when.py +176 -0
  149. openfactory-0.3.0/tests/test_a_withdrawn_card_is_not_delivered_on_jira.py +473 -0
  150. openfactory-0.3.0/tests/test_a_withdrawn_card_lands_in_the_sites_own_status_on_jira.py +478 -0
  151. openfactory-0.3.0/tests/test_acceptance_loop.py +462 -0
  152. openfactory-0.3.0/tests/test_accepting_starts_the_work.py +294 -0
  153. openfactory-0.3.0/tests/test_accepting_what_the_code_already_does_files_nothing.py +709 -0
  154. openfactory-0.3.0/tests/test_acknowledgement.py +217 -0
  155. openfactory-0.3.0/tests/test_an_activity_uses_the_client_its_worker_holds.py +383 -0
  156. openfactory-0.3.0/tests/test_an_unreadable_store_is_not_an_empty_one.py +258 -0
  157. openfactory-0.3.0/tests/test_api.py +116 -0
  158. openfactory-0.3.0/tests/test_auto_merge_is_judged_from_the_gates_that_were_read.py +257 -0
  159. openfactory-0.3.0/tests/test_board_is_vendor_neutral.py +133 -0
  160. openfactory-0.3.0/tests/test_box_prove.py +600 -0
  161. openfactory-0.3.0/tests/test_brownfield_wired.py +208 -0
  162. openfactory-0.3.0/tests/test_card_maintenance.py +1673 -0
  163. openfactory-0.3.0/tests/test_card_maintenance_channel.py +1823 -0
  164. openfactory-0.3.0/tests/test_confirmation_by_click.py +648 -0
  165. openfactory-0.3.0/tests/test_decision_loop.py +454 -0
  166. openfactory-0.3.0/tests/test_deploy_watch_workflow.py +171 -0
  167. openfactory-0.3.0/tests/test_doctor.py +419 -0
  168. openfactory-0.3.0/tests/test_doctor_checks_the_product_link.py +191 -0
  169. openfactory-0.3.0/tests/test_init_generates_the_deployment.py +405 -0
  170. openfactory-0.3.0/tests/test_memory_recall_eval.py +239 -0
  171. openfactory-0.3.0/tests/test_no_front_end_pays_for_the_engines_client_by_accident.py +584 -0
  172. openfactory-0.3.0/tests/test_no_gesture_exists_in_one_language_only.py +286 -0
  173. openfactory-0.3.0/tests/test_no_unbounded_growth.py +384 -0
  174. openfactory-0.3.0/tests/test_nothing_speaks_before_it_asks_the_language.py +293 -0
  175. openfactory-0.3.0/tests/test_one_author_writes_the_close_of_a_repair_brief.py +382 -0
  176. openfactory-0.3.0/tests/test_one_author_writes_the_order_of_a_recovery_and_a_resume.py +415 -0
  177. openfactory-0.3.0/tests/test_orphaned_cards_are_repointed.py +656 -0
  178. openfactory-0.3.0/tests/test_product_brownfield.py +347 -0
  179. openfactory-0.3.0/tests/test_product_init_writes_a_file_its_own_check_accepts.py +219 -0
  180. openfactory-0.3.0/tests/test_product_simulation.py +570 -0
  181. openfactory-0.3.0/tests/test_product_triage.py +229 -0
  182. openfactory-0.3.0/tests/test_provenance_in_the_brief.py +381 -0
  183. openfactory-0.3.0/tests/test_something_finally_asks_the_agent.py +530 -0
  184. openfactory-0.3.0/tests/test_sweep_client_surface.py +732 -0
  185. openfactory-0.3.0/tests/test_sweep_records_only_what_posted.py +518 -0
  186. openfactory-0.3.0/tests/test_temporal_view.py +289 -0
  187. openfactory-0.3.0/tests/test_temporal_workflow.py +1774 -0
  188. openfactory-0.3.0/tests/test_the_action_layer.py +1608 -0
  189. openfactory-0.3.0/tests/test_the_approver_verbs_ask_which_store_is_in_force.py +334 -0
  190. openfactory-0.3.0/tests/test_the_attended_driver_records_what_it_spent.py +124 -0
  191. openfactory-0.3.0/tests/test_the_board_is_a_page_on_the_panel.py +897 -0
  192. openfactory-0.3.0/tests/test_the_board_keeps_your_place.py +228 -0
  193. openfactory-0.3.0/tests/test_the_board_lives_in_one_file.py +515 -0
  194. openfactory-0.3.0/tests/test_the_board_row_says_which_stage_its_column_is.py +541 -0
  195. openfactory-0.3.0/tests/test_the_box_image_resolves_in_one_place.py +314 -0
  196. openfactory-0.3.0/tests/test_the_budget_read_leaves_the_panels_loop.py +309 -0
  197. openfactory-0.3.0/tests/test_the_button_without_a_gate.py +118 -0
  198. openfactory-0.3.0/tests/test_the_chat_has_its_own_fences.py +259 -0
  199. openfactory-0.3.0/tests/test_the_ci_is_read_more_than_once.py +361 -0
  200. openfactory-0.3.0/tests/test_the_cli_runs_in_the_deployments_box.py +173 -0
  201. openfactory-0.3.0/tests/test_the_cloud_is_a_directory_delete.py +1457 -0
  202. openfactory-0.3.0/tests/test_the_docs_do_not_drift.py +815 -0
  203. openfactory-0.3.0/tests/test_the_doctor_names_the_gates_only_a_person_settles.py +341 -0
  204. openfactory-0.3.0/tests/test_the_doctor_never_says_no_gate_about_a_branch_it_could_not_read.py +410 -0
  205. openfactory-0.3.0/tests/test_the_doctor_survives_its_own_probes.py +352 -0
  206. openfactory-0.3.0/tests/test_the_engine_answers_or_says_so.py +211 -0
  207. openfactory-0.3.0/tests/test_the_engine_starts_only_beside_the_library_its_worker_runs_on.py +189 -0
  208. openfactory-0.3.0/tests/test_the_extra_ca_file_is_always_a_valid_pem.py +182 -0
  209. openfactory-0.3.0/tests/test_the_first_yes_writes_and_the_second_yes_is_on_the_ticket.py +266 -0
  210. openfactory-0.3.0/tests/test_the_floor_is_a_platform_capability.py +724 -0
  211. openfactory-0.3.0/tests/test_the_floor_is_not_re_read_on_every_frame.py +518 -0
  212. openfactory-0.3.0/tests/test_the_gate_holds_when_the_store_cannot_be_read.py +527 -0
  213. openfactory-0.3.0/tests/test_the_installer_builds_the_commands_it_says_it_does.py +748 -0
  214. openfactory-0.3.0/tests/test_the_intake_memo_is_read_once_and_handed_out_as_a_copy.py +365 -0
  215. openfactory-0.3.0/tests/test_the_merge_gate_is_heard_on_every_path.py +428 -0
  216. openfactory-0.3.0/tests/test_the_merge_is_the_end_of_the_road.py +254 -0
  217. openfactory-0.3.0/tests/test_the_panel_holds_one_engine_client.py +499 -0
  218. openfactory-0.3.0/tests/test_the_panel_is_a_channel.py +652 -0
  219. openfactory-0.3.0/tests/test_the_panel_reads_as_a_control_room.py +295 -0
  220. openfactory-0.3.0/tests/test_the_panel_says_whether_work_is_picked_up.py +301 -0
  221. openfactory-0.3.0/tests/test_the_panel_serves_without_the_engines_client.py +440 -0
  222. openfactory-0.3.0/tests/test_the_poller_has_a_lever.py +219 -0
  223. openfactory-0.3.0/tests/test_the_product_conversation_is_core.py +970 -0
  224. openfactory-0.3.0/tests/test_the_product_role_lives_outside_slack.py +2255 -0
  225. openfactory-0.3.0/tests/test_the_proof_on_the_host.py +471 -0
  226. openfactory-0.3.0/tests/test_the_pull_request_lives_in_the_file.py +401 -0
  227. openfactory-0.3.0/tests/test_the_queue_proposes_in_batches.py +342 -0
  228. openfactory-0.3.0/tests/test_the_refusal_reads_the_file_it_would_write.py +126 -0
  229. openfactory-0.3.0/tests/test_the_repair_brief_states_the_failure_it_was_given.py +272 -0
  230. openfactory-0.3.0/tests/test_the_second_deployment_is_not_the_first.py +264 -0
  231. openfactory-0.3.0/tests/test_the_set_ends_together.py +282 -0
  232. openfactory-0.3.0/tests/test_the_shell_we_ship_runs_on_both_seds.py +76 -0
  233. openfactory-0.3.0/tests/test_the_suite_cannot_reach_a_live_engine.py +218 -0
  234. openfactory-0.3.0/tests/test_the_suite_runs_where_a_maintainer_sits.py +204 -0
  235. openfactory-0.3.0/tests/test_the_techlead_asks_the_engine_on_a_loop_that_outlives_the_question.py +233 -0
  236. openfactory-0.3.0/tests/test_the_techlead_sees_a_jira_floor.py +194 -0
  237. openfactory-0.3.0/tests/test_the_trajectory_reaches_the_record.py +230 -0
  238. openfactory-0.3.0/tests/test_the_worker_waits_for_the_engine_to_listen.py +247 -0
  239. openfactory-0.3.0/tests/test_three_commands_one_verdict.py +1081 -0
  240. openfactory-0.3.0/tests/test_transcript_memory.py +407 -0
  241. openfactory-0.3.0/tests/test_what_the_card_shows_inside_a_bullet_is_what_is_read.py +202 -0
  242. openfactory-0.2.0/PKG-INFO +0 -41
  243. openfactory-0.2.0/README.md +0 -232
  244. openfactory-0.2.0/openfactory/__init__.py +0 -7
  245. openfactory-0.2.0/openfactory/actions/__init__.py +0 -344
  246. openfactory-0.2.0/openfactory/actions/base.py +0 -334
  247. openfactory-0.2.0/openfactory/actions/catalog.py +0 -4872
  248. openfactory-0.2.0/openfactory/adapters/agent/base.py +0 -358
  249. openfactory-0.2.0/openfactory/adapters/agent/claude_code.py +0 -1023
  250. openfactory-0.2.0/openfactory/adapters/agent/codex.py +0 -350
  251. openfactory-0.2.0/openfactory/adapters/agent/kimi.py +0 -291
  252. openfactory-0.2.0/openfactory/adapters/agent/opencode.py +0 -432
  253. openfactory-0.2.0/openfactory/adapters/agent/roles.py +0 -263
  254. openfactory-0.2.0/openfactory/adapters/agent/techlead.py +0 -108
  255. openfactory-0.2.0/openfactory/adapters/board/azure_devops.py +0 -748
  256. openfactory-0.2.0/openfactory/adapters/board/base.py +0 -193
  257. openfactory-0.2.0/openfactory/adapters/board/columns.py +0 -68
  258. openfactory-0.2.0/openfactory/adapters/board/factory.py +0 -218
  259. openfactory-0.2.0/openfactory/adapters/board/jira.py +0 -252
  260. openfactory-0.2.0/openfactory/adapters/board/local.py +0 -187
  261. openfactory-0.2.0/openfactory/adapters/board_db.py +0 -276
  262. openfactory-0.2.0/openfactory/adapters/board_setup/local.py +0 -63
  263. openfactory-0.2.0/openfactory/adapters/credential/registry.py +0 -164
  264. openfactory-0.2.0/openfactory/adapters/environment/registry.py +0 -160
  265. openfactory-0.2.0/openfactory/adapters/forge/azure_devops.py +0 -1528
  266. openfactory-0.2.0/openfactory/adapters/forge/base.py +0 -515
  267. openfactory-0.2.0/openfactory/adapters/forge/github.py +0 -779
  268. openfactory-0.2.0/openfactory/adapters/forge/local.py +0 -660
  269. openfactory-0.2.0/openfactory/adapters/reviewer/claude_code.py +0 -140
  270. openfactory-0.2.0/openfactory/adapters/reviewer/harness.py +0 -154
  271. openfactory-0.2.0/openfactory/adapters/sandbox/base.py +0 -410
  272. openfactory-0.2.0/openfactory/adapters/sandbox/worktree.py +0 -381
  273. openfactory-0.2.0/openfactory/adapters/tracker/azure_devops.py +0 -904
  274. openfactory-0.2.0/openfactory/adapters/tracker/base.py +0 -549
  275. openfactory-0.2.0/openfactory/adapters/tracker/github.py +0 -529
  276. openfactory-0.2.0/openfactory/adapters/tracker/github_project.py +0 -733
  277. openfactory-0.2.0/openfactory/adapters/tracker/jira.py +0 -575
  278. openfactory-0.2.0/openfactory/adapters/tracker/local.py +0 -379
  279. openfactory-0.2.0/openfactory/adapters/tracker/parse.py +0 -231
  280. openfactory-0.2.0/openfactory/adapters/tracker/registry.py +0 -200
  281. openfactory-0.2.0/openfactory/after_merge.py +0 -51
  282. openfactory-0.2.0/openfactory/api/app.py +0 -2627
  283. openfactory-0.2.0/openfactory/api/metrics_view.py +0 -337
  284. openfactory-0.2.0/openfactory/api/panel.html +0 -3419
  285. openfactory-0.2.0/openfactory/approvals.py +0 -86
  286. openfactory-0.2.0/openfactory/box_prove.py +0 -1458
  287. openfactory-0.2.0/openfactory/cli.py +0 -3298
  288. openfactory-0.2.0/openfactory/conformance/adapters.py +0 -622
  289. openfactory-0.2.0/openfactory/contracts/refs.py +0 -155
  290. openfactory-0.2.0/openfactory/contracts/run.py +0 -326
  291. openfactory-0.2.0/openfactory/contracts/ticket.py +0 -113
  292. openfactory-0.2.0/openfactory/doctor.py +0 -1577
  293. openfactory-0.2.0/openfactory/factory.py +0 -460
  294. openfactory-0.2.0/openfactory/floor/ladder.py +0 -655
  295. openfactory-0.2.0/openfactory/floor/reading.py +0 -302
  296. openfactory-0.2.0/openfactory/identity/base.py +0 -95
  297. openfactory-0.2.0/openfactory/identity/local.py +0 -186
  298. openfactory-0.2.0/openfactory/identity/people.py +0 -352
  299. openfactory-0.2.0/openfactory/memory/messages.py +0 -406
  300. openfactory-0.2.0/openfactory/memory/transcript.py +0 -267
  301. openfactory-0.2.0/openfactory/observability/query.py +0 -80
  302. openfactory-0.2.0/openfactory/observability/registry.py +0 -253
  303. openfactory-0.2.0/openfactory/observability/sqlite_metrics.py +0 -203
  304. openfactory-0.2.0/openfactory/onboarding/deployment.py +0 -807
  305. openfactory-0.2.0/openfactory/onboarding/spend.py +0 -82
  306. openfactory-0.2.0/openfactory/ops/impediment.py +0 -288
  307. openfactory-0.2.0/openfactory/orchestrator/machine.py +0 -2617
  308. openfactory-0.2.0/openfactory/org_defaults/engineering.md +0 -75
  309. openfactory-0.2.0/openfactory/plugins.py +0 -208
  310. openfactory-0.2.0/openfactory/preflight.py +0 -577
  311. openfactory-0.2.0/openfactory/product/authoring.py +0 -1791
  312. openfactory-0.2.0/openfactory/product/brownfield.py +0 -210
  313. openfactory-0.2.0/openfactory/product/case.py +0 -409
  314. openfactory-0.2.0/openfactory/product/channel.py +0 -1437
  315. openfactory-0.2.0/openfactory/product/confirm.py +0 -801
  316. openfactory-0.2.0/openfactory/product/corpus.py +0 -462
  317. openfactory-0.2.0/openfactory/product/intents.py +0 -641
  318. openfactory-0.2.0/openfactory/product/module.py +0 -3100
  319. openfactory-0.2.0/openfactory/product/queue.py +0 -273
  320. openfactory-0.2.0/openfactory/product/release.py +0 -153
  321. openfactory-0.2.0/openfactory/product/role.py +0 -1356
  322. openfactory-0.2.0/openfactory/product/staging.py +0 -477
  323. openfactory-0.2.0/openfactory/product/triage.py +0 -277
  324. openfactory-0.2.0/openfactory/product/voice.py +0 -2080
  325. openfactory-0.2.0/openfactory/registry.py +0 -526
  326. openfactory-0.2.0/openfactory/runtime/boxed_job.py +0 -399
  327. openfactory-0.2.0/openfactory/runtime/host.py +0 -91
  328. openfactory-0.2.0/openfactory/runtime/temporal/activities.py +0 -5081
  329. openfactory-0.2.0/openfactory/runtime/temporal/connection.py +0 -89
  330. openfactory-0.2.0/openfactory/runtime/temporal/io.py +0 -639
  331. openfactory-0.2.0/openfactory/runtime/temporal/schedule.py +0 -465
  332. openfactory-0.2.0/openfactory/runtime/temporal/view.py +0 -884
  333. openfactory-0.2.0/openfactory/runtime/temporal/worker.py +0 -325
  334. openfactory-0.2.0/openfactory/runtime/temporal/workflow.py +0 -2459
  335. openfactory-0.2.0/openfactory/techlead/__init__.py +0 -38
  336. openfactory-0.2.0/openfactory/techlead/classify.py +0 -427
  337. openfactory-0.2.0/openfactory/techlead/conversation.py +0 -1401
  338. openfactory-0.2.0/openfactory/techlead/voice.py +0 -679
  339. openfactory-0.2.0/openfactory/techlead/watch.py +0 -638
  340. openfactory-0.2.0/openfactory/testing/local_flow.py +0 -272
  341. openfactory-0.2.0/openfactory.egg-info/PKG-INFO +0 -41
  342. openfactory-0.2.0/openfactory.egg-info/SOURCES.txt +0 -745
  343. openfactory-0.2.0/pyproject.toml +0 -229
  344. openfactory-0.2.0/tests/test_a_credential_is_asked_of_its_own_axis.py +0 -464
  345. openfactory-0.2.0/tests/test_a_credential_is_scoped.py +0 -329
  346. openfactory-0.2.0/tests/test_a_disabled_project_does_not_look_armed.py +0 -218
  347. openfactory-0.2.0/tests/test_a_frame_does_not_erase_what_it_omits.py +0 -243
  348. openfactory-0.2.0/tests/test_a_free_deployment_can_read_its_logs.py +0 -335
  349. openfactory-0.2.0/tests/test_a_manifest_that_loads_is_not_a_manifest_that_is_right.py +0 -434
  350. openfactory-0.2.0/tests/test_a_person_is_invited_not_signed_up.py +0 -501
  351. openfactory-0.2.0/tests/test_a_poller_that_is_on_is_not_a_poller_that_ticks.py +0 -215
  352. openfactory-0.2.0/tests/test_a_proposal_can_carry_what_to_change.py +0 -268
  353. openfactory-0.2.0/tests/test_a_resume_re_enters_the_merge.py +0 -309
  354. openfactory-0.2.0/tests/test_a_staged_decision_survives_a_refresh.py +0 -566
  355. openfactory-0.2.0/tests/test_a_ticket_written_in_portuguese.py +0 -180
  356. openfactory-0.2.0/tests/test_a_wait_can_say_until_when.py +0 -168
  357. openfactory-0.2.0/tests/test_acceptance_loop.py +0 -462
  358. openfactory-0.2.0/tests/test_accepting_starts_the_work.py +0 -294
  359. openfactory-0.2.0/tests/test_acknowledgement.py +0 -217
  360. openfactory-0.2.0/tests/test_an_unreadable_store_is_not_an_empty_one.py +0 -257
  361. openfactory-0.2.0/tests/test_api.py +0 -111
  362. openfactory-0.2.0/tests/test_board_is_vendor_neutral.py +0 -124
  363. openfactory-0.2.0/tests/test_box_prove.py +0 -500
  364. openfactory-0.2.0/tests/test_brownfield_wired.py +0 -207
  365. openfactory-0.2.0/tests/test_card_maintenance.py +0 -1465
  366. openfactory-0.2.0/tests/test_card_maintenance_channel.py +0 -1753
  367. openfactory-0.2.0/tests/test_confirmation_by_click.py +0 -648
  368. openfactory-0.2.0/tests/test_decision_loop.py +0 -454
  369. openfactory-0.2.0/tests/test_deploy_watch_workflow.py +0 -169
  370. openfactory-0.2.0/tests/test_doctor.py +0 -408
  371. openfactory-0.2.0/tests/test_doctor_checks_the_product_link.py +0 -192
  372. openfactory-0.2.0/tests/test_init_generates_the_deployment.py +0 -358
  373. openfactory-0.2.0/tests/test_memory_recall_eval.py +0 -239
  374. openfactory-0.2.0/tests/test_no_gesture_exists_in_one_language_only.py +0 -278
  375. openfactory-0.2.0/tests/test_no_unbounded_growth.py +0 -342
  376. openfactory-0.2.0/tests/test_nothing_speaks_before_it_asks_the_language.py +0 -172
  377. openfactory-0.2.0/tests/test_orphaned_cards_are_repointed.py +0 -651
  378. openfactory-0.2.0/tests/test_product_brownfield.py +0 -309
  379. openfactory-0.2.0/tests/test_product_simulation.py +0 -570
  380. openfactory-0.2.0/tests/test_product_triage.py +0 -198
  381. openfactory-0.2.0/tests/test_sweep_client_surface.py +0 -732
  382. openfactory-0.2.0/tests/test_sweep_records_only_what_posted.py +0 -513
  383. openfactory-0.2.0/tests/test_temporal_view.py +0 -280
  384. openfactory-0.2.0/tests/test_temporal_workflow.py +0 -1768
  385. openfactory-0.2.0/tests/test_the_action_layer.py +0 -1592
  386. openfactory-0.2.0/tests/test_the_board_is_a_page_on_the_panel.py +0 -293
  387. openfactory-0.2.0/tests/test_the_board_lives_in_one_file.py +0 -513
  388. openfactory-0.2.0/tests/test_the_box_image_resolves_in_one_place.py +0 -317
  389. openfactory-0.2.0/tests/test_the_button_without_a_gate.py +0 -114
  390. openfactory-0.2.0/tests/test_the_chat_has_its_own_fences.py +0 -261
  391. openfactory-0.2.0/tests/test_the_ci_is_read_more_than_once.py +0 -361
  392. openfactory-0.2.0/tests/test_the_cli_runs_in_the_deployments_box.py +0 -150
  393. openfactory-0.2.0/tests/test_the_cloud_is_a_directory_delete.py +0 -1443
  394. openfactory-0.2.0/tests/test_the_docs_do_not_drift.py +0 -727
  395. openfactory-0.2.0/tests/test_the_doctor_survives_its_own_probes.py +0 -349
  396. openfactory-0.2.0/tests/test_the_first_yes_writes_and_the_second_yes_is_on_the_ticket.py +0 -266
  397. openfactory-0.2.0/tests/test_the_floor_is_a_platform_capability.py +0 -722
  398. openfactory-0.2.0/tests/test_the_installer_builds_the_commands_it_says_it_does.py +0 -494
  399. openfactory-0.2.0/tests/test_the_merge_is_the_end_of_the_road.py +0 -252
  400. openfactory-0.2.0/tests/test_the_panel_is_a_channel.py +0 -651
  401. openfactory-0.2.0/tests/test_the_panel_reads_as_a_control_room.py +0 -293
  402. openfactory-0.2.0/tests/test_the_panel_says_whether_work_is_picked_up.py +0 -290
  403. openfactory-0.2.0/tests/test_the_product_conversation_is_core.py +0 -969
  404. openfactory-0.2.0/tests/test_the_product_role_lives_outside_slack.py +0 -2149
  405. openfactory-0.2.0/tests/test_the_proof_on_the_host.py +0 -223
  406. openfactory-0.2.0/tests/test_the_pull_request_lives_in_the_file.py +0 -401
  407. openfactory-0.2.0/tests/test_the_queue_proposes_in_batches.py +0 -342
  408. openfactory-0.2.0/tests/test_the_second_deployment_is_not_the_first.py +0 -259
  409. openfactory-0.2.0/tests/test_the_suite_cannot_reach_a_live_engine.py +0 -217
  410. openfactory-0.2.0/tests/test_the_techlead_sees_a_jira_floor.py +0 -201
  411. openfactory-0.2.0/tests/test_the_trajectory_reaches_the_record.py +0 -224
  412. openfactory-0.2.0/tests/test_three_commands_one_verdict.py +0 -1080
  413. openfactory-0.2.0/tests/test_transcript_memory.py +0 -407
  414. {openfactory-0.2.0 → openfactory-0.3.0}/LICENSE +0 -0
  415. {openfactory-0.2.0 → openfactory-0.3.0}/NOTICE +0 -0
  416. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/actions/floor_intents.py +0 -0
  417. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/__init__.py +0 -0
  418. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/__init__.py +0 -0
  419. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/registry.py +0 -0
  420. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/routes.py +0 -0
  421. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/session_store.py +0 -0
  422. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/stream.py +0 -0
  423. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/agent/token_pool.py +0 -0
  424. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/azure_devops.py +0 -0
  425. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/board/__init__.py +0 -0
  426. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/board_setup/__init__.py +0 -0
  427. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/board_setup/base.py +0 -0
  428. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/board_setup/registry.py +0 -0
  429. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/channel/__init__.py +0 -0
  430. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/channel/base.py +0 -0
  431. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/channel/panel.py +0 -0
  432. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/channel/registry.py +0 -0
  433. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/credential/__init__.py +0 -0
  434. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/environment/__init__.py +0 -0
  435. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/environment/azure_pipelines.py +0 -0
  436. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/environment/base.py +0 -0
  437. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/environment/github_actions.py +0 -0
  438. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/environment/none.py +0 -0
  439. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/forge/__init__.py +0 -0
  440. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/forge/registry.py +0 -0
  441. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/github_app.py +0 -0
  442. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/notify/__init__.py +0 -0
  443. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/notify/base.py +0 -0
  444. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/notify/panel.py +0 -0
  445. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/notify/registry.py +0 -0
  446. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/reviewer/__init__.py +0 -0
  447. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/reviewer/base.py +0 -0
  448. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/sandbox/__init__.py +0 -0
  449. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/sandbox/container.py +0 -0
  450. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/sandbox/registry.py +0 -0
  451. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/sandbox/timeouts.py +0 -0
  452. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/tracker/__init__.py +0 -0
  453. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/adapters/tracker/github_board_setup.py +0 -0
  454. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/api/__init__.py +0 -0
  455. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/cli_refusals.py +0 -0
  456. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/conformance/__init__.py +0 -0
  457. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/__init__.py +0 -0
  458. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/bot.py +0 -0
  459. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/commands.py +0 -0
  460. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/decision.py +0 -0
  461. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/manifest.py +0 -0
  462. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/product.py +0 -0
  463. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/profile.py +0 -0
  464. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/project.py +0 -0
  465. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/review.py +0 -0
  466. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/contracts/state.py +0 -0
  467. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/credentials.py +0 -0
  468. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/doors.py +0 -0
  469. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/environ.py +0 -0
  470. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/floor/__init__.py +0 -0
  471. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/identity/__init__.py +0 -0
  472. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/identity/oidc.py +0 -0
  473. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/identity/registry.py +0 -0
  474. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/__init__.py +0 -0
  475. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/bundle.py +0 -0
  476. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/check.py +0 -0
  477. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/contracts.py +0 -0
  478. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/experiment.py +0 -0
  479. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/gaps.py +0 -0
  480. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/gate.py +0 -0
  481. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/gather.py +0 -0
  482. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/generator.py +0 -0
  483. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/inventory.py +0 -0
  484. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/okf.py +0 -0
  485. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/pipeline.py +0 -0
  486. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/render.py +0 -0
  487. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/service.py +0 -0
  488. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/knowledge/staleness.py +0 -0
  489. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/language/__init__.py +0 -0
  490. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/language/assent.py +0 -0
  491. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/loader.py +0 -0
  492. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/memory/__init__.py +0 -0
  493. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/memory/ledger.py +0 -0
  494. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/memory/recall.py +0 -0
  495. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/memory/store.py +0 -0
  496. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/namespace.py +0 -0
  497. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/observability/__init__.py +0 -0
  498. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/observability/events.py +0 -0
  499. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/observability/metrics.py +0 -0
  500. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/observability/trajectory.py +0 -0
  501. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/__init__.py +0 -0
  502. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/concepts.py +0 -0
  503. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/context.py +0 -0
  504. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/cover.py +0 -0
  505. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/firstrun.py +0 -0
  506. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/history.py +0 -0
  507. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/infer.py +0 -0
  508. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/live_ci.py +0 -0
  509. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/onboard.py +0 -0
  510. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/propose_manifest.py +0 -0
  511. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/questions.py +0 -0
  512. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/readiness.py +0 -0
  513. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/onboarding/renew.py +0 -0
  514. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/ops/__init__.py +0 -0
  515. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/__init__.py +0 -0
  516. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/context.py +0 -0
  517. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/errors.py +0 -0
  518. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/merge_policy.py +0 -0
  519. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/promotion.py +0 -0
  520. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/risk.py +0 -0
  521. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/orchestrator/validation.py +0 -0
  522. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/floor.yaml +0 -0
  523. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/profiles/prototype.yaml +0 -0
  524. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/profiles/regulated.yaml +0 -0
  525. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/requirements/0000-template.md +0 -0
  526. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/coordinator.md +0 -0
  527. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/executor.md +0 -0
  528. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/planner.md +0 -0
  529. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/product.md +0 -0
  530. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/recovery.md +0 -0
  531. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/sizer.md +0 -0
  532. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/roles/techlead.md +0 -0
  533. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/org_defaults/tdd.md +0 -0
  534. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/own_work.py +0 -0
  535. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/paths.py +0 -0
  536. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/__init__.py +0 -0
  537. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/authz.py +0 -0
  538. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/census.py +0 -0
  539. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/conformance.py +0 -0
  540. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/floor.py +0 -0
  541. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/presets.py +0 -0
  542. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/profiles.py +0 -0
  543. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/protected.py +0 -0
  544. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/policy/test_work.py +0 -0
  545. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/presets/node.yaml +0 -0
  546. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/presets/python.yaml +0 -0
  547. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/presets/security-oss.yaml +0 -0
  548. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/presets/terraform.yaml +0 -0
  549. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/__init__.py +0 -0
  550. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/asked.py +0 -0
  551. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/board.py +0 -0
  552. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/config.py +0 -0
  553. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/conversation.py +0 -0
  554. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/domain.py +0 -0
  555. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/facts.py +0 -0
  556. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/followup.py +0 -0
  557. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/loader.py +0 -0
  558. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/needs_action.py +0 -0
  559. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/onboard.py +0 -0
  560. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/reading.py +0 -0
  561. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/requester.py +0 -0
  562. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/product/workspace.py +0 -0
  563. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/review/__init__.py +0 -0
  564. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/review/verdict.py +0 -0
  565. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/__init__.py +0 -0
  566. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/card_repo.py +0 -0
  567. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/repo_cache.py +0 -0
  568. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/temporal/__init__.py +0 -0
  569. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/temporal/poller.py +0 -0
  570. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/temporal/starter.py +0 -0
  571. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/runtime/toolbox.py +0 -0
  572. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/scheduler.py +0 -0
  573. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/semver.py +0 -0
  574. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/techlead/diagnosis.py +0 -0
  575. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/techlead/memory.py +0 -0
  576. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/techlead/pack.py +0 -0
  577. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/testing/__init__.py +0 -0
  578. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/util/__init__.py +0 -0
  579. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/util/bounded.py +0 -0
  580. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/util/causes.py +0 -0
  581. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory/util/scratch.py +0 -0
  582. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory.egg-info/dependency_links.txt +0 -0
  583. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory.egg-info/entry_points.txt +0 -0
  584. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory.egg-info/requires.txt +0 -0
  585. {openfactory-0.2.0 → openfactory-0.3.0}/openfactory.egg-info/top_level.txt +0 -0
  586. {openfactory-0.2.0 → openfactory-0.3.0}/setup.cfg +0 -0
  587. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_banner_line_does_not_kill_the_review.py +0 -0
  588. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_budget_nothing_spends_is_not_a_defect.py +0 -0
  589. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_card_says_who_asked_for_it.py +0 -0
  590. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_case_does_not_outlive_its_test.py +0 -0
  591. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_concept_is_earned_not_declared.py +0 -0
  592. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_context_repository_is_creatable_on_azure_too.py +0 -0
  593. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_count_is_a_number_not_a_sentence.py +0 -0
  594. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_credential_only_goes_to_its_own_host.py +0 -0
  595. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_decision_is_written_down.py +0 -0
  596. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_declared_environment_is_observed_or_named.py +0 -0
  597. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_delivered_ticket_is_not_rerun.py +0 -0
  598. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_double_without_intake_answers_every_turn.py +0 -0
  599. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_failed_board_read_is_not_a_wrong_root.py +0 -0
  600. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_failing_setup_is_not_silent.py +0 -0
  601. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_file_nothing_describes_is_the_least_safe_to_change.py +0 -0
  602. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_fingerprint_gains_a_reader.py +0 -0
  603. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_free_deployment_resumes_its_own_sessions.py +0 -0
  604. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_fresh_install_registers_no_projects.py +0 -0
  605. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_gate_is_not_a_stall.py +0 -0
  606. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_gate_that_could_not_run.py +0 -0
  607. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_gate_that_holds_says_so_where_the_person_decides.py +0 -0
  608. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_green_deploy_asks_somebody_to_look.py +0 -0
  609. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_green_environment_is_green_for_THIS_change.py +0 -0
  610. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_hostile_value_stays_data.py +0 -0
  611. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_human_gate_is_not_a_review.py +0 -0
  612. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_jira_project_is_a_board.py +0 -0
  613. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_killed_mutation_run_cannot_hide.py +0 -0
  614. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_local_deployment_names_no_vendor.py +0 -0
  615. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_message_never_claims_an_action_nobody_takes.py +0 -0
  616. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_message_only_teaches_a_verb_the_channel_parses.py +0 -0
  617. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_model_nobody_can_run_is_not_a_setting.py +0 -0
  618. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_named_check_is_not_dropped.py +0 -0
  619. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_negation_the_bridge_carries_is_refused.py +0 -0
  620. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_pass_in_flight_is_not_a_gate.py +0 -0
  621. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_pass_that_changed_nothing.py +0 -0
  622. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_path_nothing_declares_is_not_the_freest.py +0 -0
  623. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_path_registers_itself.py +0 -0
  624. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_paused_factory_says_so.py +0 -0
  625. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_personal_accounts_board_is_readable.py +0 -0
  626. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_personal_boards_columns_can_be_read.py +0 -0
  627. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_preexisting_context_repo_is_declarable.py +0 -0
  628. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_probe_set_is_pinned_whole.py +0 -0
  629. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_project_can_change_the_language_it_speaks_first.py +0 -0
  630. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_project_declares_what_it_is.py +0 -0
  631. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_project_is_not_registered_as_the_wrong_vendor.py +0 -0
  632. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_proof_that_was_not_recorded_says_so.py +0 -0
  633. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_proposed_command_can_run_where_the_box_runs_it.py +0 -0
  634. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_pull_that_changes_nothing_is_impossible_to_miss.py +0 -0
  635. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_question_reaches_the_person_who_asked.py +0 -0
  636. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_range_is_a_citation.py +0 -0
  637. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_rebuild_is_not_a_change.py +0 -0
  638. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_ref_that_is_not_a_number.py +0 -0
  639. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_rejected_review_can_be_asked_again.py +0 -0
  640. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_remedy_names_a_document_that_exists.py +0 -0
  641. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_repaired_card_is_announced_on_any_tracker.py +0 -0
  642. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_repository_on_the_former_name_is_refused_at_every_door.py +0 -0
  643. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_retired_pipeline_is_not_a_gate.py +0 -0
  644. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_review_belongs_to_the_code_it_read.py +0 -0
  645. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_scratch_directory_is_the_only_thing_we_delete.py +0 -0
  646. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_skip_is_something_that_happened.py +0 -0
  647. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_stranger_can_add_a_role.py +0 -0
  648. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_stranger_can_add_an_adapter.py +0 -0
  649. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_suite_that_stopped_collecting_is_not_a_green_suite.py +0 -0
  650. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_ticket_ref_is_never_typed_as_a_number.py +0 -0
  651. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_typed_instruction_reaches_the_same_row_as_the_button.py +0 -0
  652. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_vendor_error_code_is_not_a_status.py +0 -0
  653. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_verb_says_what_to_put_in_it.py +0 -0
  654. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_wedged_job_has_an_exit.py +0 -0
  655. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_wedged_job_is_seen.py +0 -0
  656. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_write_that_did_not_land_is_not_counted.py +0 -0
  657. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_a_yes_is_an_answer.py +0 -0
  658. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_accept_flows_end_to_end.py +0 -0
  659. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_adapter_conformance_suite.py +0 -0
  660. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_advisory_findings_survive_save.py +0 -0
  661. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_agent_harness.py +0 -0
  662. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_agent_resume_c2.py +0 -0
  663. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_agent_roles.py +0 -0
  664. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_agent_stream.py +0 -0
  665. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_agent_token_pool.py +0 -0
  666. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_already_asked_is_answered_from_the_board_not_the_transcript.py +0 -0
  667. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_advisory_gate_cannot_hold_a_pickup.py +0 -0
  668. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_advisory_gate_reports_and_never_blocks.py +0 -0
  669. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_environment_written_before_this_change_still_resolves_the_old_path.py +0 -0
  670. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_intake_is_a_typed_case.py +0 -0
  671. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_open_question_can_be_retired.py +0 -0
  672. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_open_question_is_an_offer_not_a_toll.py +0 -0
  673. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_an_unread_review_is_not_a_rejection.py +0 -0
  674. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_board_read_cost.py +0 -0
  675. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_bot_push.py +0 -0
  676. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_box_carries_the_provider_kind.py +0 -0
  677. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_breakdown_reuses_what_exists.py +0 -0
  678. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_c18_has_an_azure_expression.py +0 -0
  679. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_c18_reaches_every_entry_point.py +0 -0
  680. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_causes.py +0 -0
  681. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_ci_runs_what_we_run.py +0 -0
  682. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_client_board_is_not_a_test_bench.py +0 -0
  683. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_commit_workflow_strip.py +0 -0
  684. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_compose_forwards_the_whole_env_file.py +0 -0
  685. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_confirmation_is_understood.py +0 -0
  686. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_context.py +0 -0
  687. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_conversation_worlds.py +0 -0
  688. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_corpus_health_and_board_placement.py +0 -0
  689. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_create_repository_survives_an_app_token.py +0 -0
  690. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_decision.py +0 -0
  691. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_diff_hygiene.py +0 -0
  692. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_env_apply_answers_in_the_readers_language.py +0 -0
  693. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_env_apply_takes_a_path_like_env_read.py +0 -0
  694. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_env_proposes_before_it_verifies.py +0 -0
  695. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_event_sinks.py +0 -0
  696. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_every_FROM_the_release_builds_resolves_without_the_local_daemon.py +0 -0
  697. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_every_image_the_compose_file_names_is_one_the_release_builds.py +0 -0
  698. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_every_mutation_plan_can_run.py +0 -0
  699. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_factory_asks_for_help.py +0 -0
  700. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_filed_work_is_reachable.py +0 -0
  701. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_first_real_conversation.py +0 -0
  702. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_forge_ci.py +0 -0
  703. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_forge_deploy.py +0 -0
  704. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_forge_idempotency.py +0 -0
  705. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_foundation.py +0 -0
  706. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_gh_is_authenticated.py +0 -0
  707. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_handoff.py +0 -0
  708. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_init_asks_for_one_machine.py +0 -0
  709. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_init_speaks_to_the_operator_not_to_us.py +0 -0
  710. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_init_that_acts.py +0 -0
  711. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_internal_imports_resolve.py +0 -0
  712. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_judge_verdict_parsing.py +0 -0
  713. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_kernel_names_no_vendor.py +0 -0
  714. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_knowledge.py +0 -0
  715. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_knowledge_build_reaches_a_factory_cloned_project.py +0 -0
  716. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_knowledge_derived_not_cached.py +0 -0
  717. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_knowledge_experiment.py +0 -0
  718. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_knowledge_pipeline.py +0 -0
  719. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_local_flow.py +0 -0
  720. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_loops_are_reachable.py +0 -0
  721. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_manifest_version.py +0 -0
  722. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_memory_ledger.py +0 -0
  723. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_memory_store.py +0 -0
  724. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_merge_policy.py +0 -0
  725. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_metrics.py +0 -0
  726. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_no_card_id_reaches_a_stranger.py +0 -0
  727. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_no_checkout_assumes_a_branch_name.py +0 -0
  728. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_no_module_is_ever_called_like_a_function.py +0 -0
  729. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_no_plumbing_reaches_the_client.py +0 -0
  730. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_no_silent_failures.py +0 -0
  731. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_non_numeric_refs_reach_the_api.py +0 -0
  732. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_observability_registries.py +0 -0
  733. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboard_builds_the_context_too.py +0 -0
  734. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboard_proposes_a_measured_setup.py +0 -0
  735. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboarding_a_context_that_already_exists.py +0 -0
  736. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboarding_backfills_the_context.py +0 -0
  737. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboarding_creates_the_context_repository.py +0 -0
  738. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_onboarding_firstrun.py +0 -0
  739. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_one_process_one_installation.py +0 -0
  740. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_one_question_decides_where_the_factory_runs.py +0 -0
  741. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_opencode_harness.py +0 -0
  742. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_panel_approval_store.py +0 -0
  743. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_panel_reads_events_without_aws.py +0 -0
  744. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_park_alert.py +0 -0
  745. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_paths_are_traversal_safe.py +0 -0
  746. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_permission_is_an_order_in_every_language.py +0 -0
  747. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_ports_are_serialisable.py +0 -0
  748. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_preflight.py +0 -0
  749. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_preflight_json_is_the_document_the_agent_lane_reads.py +0 -0
  750. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_preflight_names_a_remedy_for_every_thing_it_refuses.py +0 -0
  751. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_preflight_says_which_machine_it_measured.py +0 -0
  752. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_authoring.py +0 -0
  753. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_board_reads.py +0 -0
  754. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_channel.py +0 -0
  755. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_config.py +0 -0
  756. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_corpus.py +0 -0
  757. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_followup.py +0 -0
  758. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_followup_e2e.py +0 -0
  759. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_intents.py +0 -0
  760. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_loader.py +0 -0
  761. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_module.py +0 -0
  762. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_needs_action.py +0 -0
  763. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_role.py +0 -0
  764. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_sees_the_code.py +0 -0
  765. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_sweep.py +0 -0
  766. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_view_is_stable.py +0 -0
  767. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_voice.py +0 -0
  768. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_product_workspace.py +0 -0
  769. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_project_add_exposes_language.py +0 -0
  770. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_project_add_speaks_azure_devops.py +0 -0
  771. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_promotion.py +0 -0
  772. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_provider_seams.py +0 -0
  773. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_public_core_names_no_forge.py +0 -0
  774. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_recent_runs_outlives_the_engine.py +0 -0
  775. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_registry_is_runtime_state.py +0 -0
  776. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_repo_cache_credentials.py +0 -0
  777. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_repo_cache_lifecycle.py +0 -0
  778. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_requirement_can_be_dropped.py +0 -0
  779. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_requirement_lifecycle.py +0 -0
  780. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_sandbox_registry.py +0 -0
  781. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_scheduler.py +0 -0
  782. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_schedules_are_reachable.py +0 -0
  783. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_somebody_is_asked_to_look_at_what_shipped.py +0 -0
  784. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_sqlite_metrics.py +0 -0
  785. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_sso_is_a_row_the_core_ships.py +0 -0
  786. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_techlead_classify.py +0 -0
  787. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_techlead_memory.py +0 -0
  788. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_techlead_self_heal.py +0 -0
  789. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_techlead_watch.py +0 -0
  790. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_telemetry_reads_from_the_configured_sink.py +0 -0
  791. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_temporal_call_arity.py +0 -0
  792. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_acceptance_map_reaches_a_person.py +0 -0
  793. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_add_on_packages_install.py +0 -0
  794. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_board.py +0 -0
  795. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_coordinates_have_one_home.py +0 -0
  796. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_credential_outlives_one_token.py +0 -0
  797. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_forge.py +0 -0
  798. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_pipelines.py +0 -0
  799. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ado_tracker.py +0 -0
  800. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_alert_names_its_ticket_on_any_tracker.py +0 -0
  801. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_announcement_carries_the_verdict.py +0 -0
  802. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_app_key_reaches_every_entry_point.py +0 -0
  803. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_app_permission_table_has_one_home.py +0 -0
  804. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_areas_that_change_are_the_ones_that_matter.py +0 -0
  805. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_backfill_is_metered.py +0 -0
  806. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_backfill_names_the_real_reason.py +0 -0
  807. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_backfill_reads_every_source.py +0 -0
  808. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_backfills_questions_can_be_finished.py +0 -0
  809. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_base_branch_is_asked_not_assumed.py +0 -0
  810. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_bench_is_not_the_case.py +0 -0
  811. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_board_names_its_own_pickup_column.py +0 -0
  812. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_board_port_takes_any_providers_ref.py +0 -0
  813. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_board_says_where_it_lives.py +0 -0
  814. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_can_obtain_the_repository.py +0 -0
  815. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_can_reach_the_pr_branch.py +0 -0
  816. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_claims_only_what_it_does.py +0 -0
  817. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_clones_from_the_forge_it_was_told.py +0 -0
  818. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_does_not_run_the_clients_shell_profile.py +0 -0
  819. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_env_is_a_named_seam.py +0 -0
  820. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_image_the_worker_spawns_is_one_the_install_pulls.py +0 -0
  821. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_program_can_be_launched.py +0 -0
  822. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_proof_is_watchable.py +0 -0
  823. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_says_where_the_harness_is.py +0 -0
  824. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_box_transmits_while_it_runs.py +0 -0
  825. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_boxed_job_entrypoint.py +0 -0
  826. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_branch_carries_the_products_name.py +0 -0
  827. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_card_carries_ONE_acceptance_section.py +0 -0
  828. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_card_moves_even_when_the_link_cannot_be_built.py +0 -0
  829. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_card_says_what_the_floor_says.py +0 -0
  830. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_chat_is_a_directory_delete.py +0 -0
  831. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_chat_thread_survives_a_refresh.py +0 -0
  832. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_cli_refuses_in_sentences.py +0 -0
  833. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_client_never_reads_an_emoji.py +0 -0
  834. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_client_releases_production.py +0 -0
  835. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_columns_and_the_identity_are_the_platforms.py +0 -0
  836. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_compose_file_can_be_installed_and_built_from_one_file.py +0 -0
  837. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_confirmation_executor.py +0 -0
  838. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_context_proposal_is_reachable.py +0 -0
  839. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_context_repository_can_be_created.py +0 -0
  840. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_context_repository_exists_on_this_runtime.py +0 -0
  841. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_core_addon_ledger.py +0 -0
  842. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_core_boundary.py +0 -0
  843. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_core_does_not_need_a_cloud.py +0 -0
  844. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_core_is_a_core.py +0 -0
  845. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_credential_scan_reads_a_delimiter.py +0 -0
  846. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_default_language_is_the_products.py +0 -0
  847. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_deployment_asks_the_rows_for_their_variables.py +0 -0
  848. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_diff_decides_scope_and_what_validates.py +0 -0
  849. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_distribution_ships_what_it_tells_you_to_copy.py +0 -0
  850. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_docs_name_no_vendor_as_the_core.py +0 -0
  851. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_docs_say_which_promise.py +0 -0
  852. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_doctor_says_where_project_less_speech_goes.py +0 -0
  853. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_doctor_tells_the_truth_about_this_machine.py +0 -0
  854. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_documentation_has_one_front_door.py +0 -0
  855. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_documented_default_is_the_real_one.py +0 -0
  856. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_documents_describe_the_product_this_tree_is.py +0 -0
  857. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_documents_name_the_repository_and_keep_their_accents.py +0 -0
  858. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_doors_derive_from_the_registries.py +0 -0
  859. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_end_to_end_install_is_a_script_the_suite_can_run.py +0 -0
  860. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_engine_dying_under_a_job_is_not_a_mystery.py +0 -0
  861. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_environment_carries_the_products_name.py +0 -0
  862. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_environment_round_is_a_terminal_verb.py +0 -0
  863. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_event_axis_is_reached.py +0 -0
  864. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_examples_a_reader_copies_load_on_the_core.py +0 -0
  865. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_extensibility_doc_names_the_real_group.py +0 -0
  866. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_factory_asks_before_it_starts.py +0 -0
  867. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_factory_authors_what_it_does_not_know_before_it_changes_it.py +0 -0
  868. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_factory_runs_on_one_machine.py +0 -0
  869. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_factory_runs_without_a_cloud.py +0 -0
  870. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_facts_are_files_the_techlead_can_open.py +0 -0
  871. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_facts_stay_files_for_every_harness.py +0 -0
  872. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_first_hour_fails_by_name.py +0 -0
  873. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_first_round_is_reachable.py +0 -0
  874. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_floor_and_the_inbox_agree.py +0 -0
  875. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_floor_is_a_deployment_default_not_a_transcription.py +0 -0
  876. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_floor_is_enforced_where_the_money_is.py +0 -0
  877. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_forge_can_read_a_foreign_repository.py +0 -0
  878. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_forge_credential_is_per_project.py +0 -0
  879. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_forge_opens_a_pr_in_another_repository.py +0 -0
  880. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_form_asks_what_the_address_needs.py +0 -0
  881. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_gate_checks_the_shell_script_a_stranger_runs_first.py +0 -0
  882. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_gate_shows_what_the_review_found.py +0 -0
  883. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_generated_environment_names_a_work_directory_that_needs_no_root.py +0 -0
  884. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_harness_endpoint_is_the_clients.py +0 -0
  885. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_harness_is_watched_while_it_runs.py +0 -0
  886. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_harness_pulse.py +0 -0
  887. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_history_says_where_the_work_is.py +0 -0
  888. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_install_line_the_readme_prints_is_the_url_the_release_publishes_to.py +0 -0
  889. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_installer_knows_exactly_two_facts_the_package_does_not.py +0 -0
  890. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_installer_never_calls_sudo.py +0 -0
  891. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_installer_pins_a_version_and_never_installs_a_floating_tag.py +0 -0
  892. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_inventory_counts_what_it_could_not_place.py +0 -0
  893. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_journal_is_where_the_deployment_says.py +0 -0
  894. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_journal_records_how_a_job_ENDED.py +0 -0
  895. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_judging_roles_can_reach_their_model.py +0 -0
  896. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_language_reaches_every_unprompted_surface.py +0 -0
  897. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_lifecycle_names_no_provider.py +0 -0
  898. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_loop_tells_the_truth.py +0 -0
  899. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_manifest_can_be_proposed_server_side.py +0 -0
  900. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_manifest_reference_is_complete.py +0 -0
  901. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_map_does_not_wait_for_a_merge.py +0 -0
  902. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_map_is_published_beside_the_concepts.py +0 -0
  903. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_map_says_what_it_does_not_cover.py +0 -0
  904. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_merge_re_authors_what_it_invalidated.py +0 -0
  905. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_model_is_a_per_project_choice.py +0 -0
  906. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_model_is_set_from_the_cli.py +0 -0
  907. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_mutation_runner_is_not_decoration.py +0 -0
  908. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_namespace_is_the_products_name.py +0 -0
  909. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_net_that_protects_the_client.py +0 -0
  910. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_number_told_is_the_number_written.py +0 -0
  911. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_one_machine_deployment_runs_unattended.py +0 -0
  912. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_open_distribution_has_a_voice.py +0 -0
  913. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_operator_hears_the_projects_language.py +0 -0
  914. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_operator_path_names_what_the_code_mints.py +0 -0
  915. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_oss_distribution.py +0 -0
  916. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_is_pushed_to.py +0 -0
  917. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_names_no_vendor.py +0 -0
  918. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_says_a_pass_is_running.py +0 -0
  919. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_says_where_to_change_things.py +0 -0
  920. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_says_which_harness.py +0 -0
  921. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_speaks_one_language.py +0 -0
  922. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_panel_touches_no_cloud_locally.py +0 -0
  923. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_platform_reads_a_repository_and_proposes.py +0 -0
  924. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_carries_no_ones_past.py +0 -0
  925. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_carries_no_owners_name.py +0 -0
  926. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_owner_opens_a_card_as_described.py +0 -0
  927. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_owner_orders_the_backlog_from_chat.py +0 -0
  928. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_owner_reads_an_intake_and_teaches.py +0 -0
  929. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_owner_writes_the_backlog_order.py +0 -0
  930. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_owners_facts_are_files.py +0 -0
  931. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_path_is_not_github_by_construction.py +0 -0
  932. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_product_role_speaks_the_clients_language.py +0 -0
  933. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_project_remembers_what_everyone_said.py +0 -0
  934. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_promotion_tail_speaks.py +0 -0
  935. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_proof_gates_each_repository.py +0 -0
  936. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_proof_gates_pickup.py +0 -0
  937. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_proposal_covers_the_floor.py +0 -0
  938. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_public_cut_is_written_down.py +0 -0
  939. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_public_documents_serve_a_stranger.py +0 -0
  940. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_pull_request_says_what_the_card_says.py +0 -0
  941. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_reading_is_bound_against_the_bundle_that_exists.py +0 -0
  942. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_release_assembles_what_the_installer_downloads.py +0 -0
  943. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_remedy_a_refusal_hands_you_can_be_followed.py +0 -0
  944. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_renewal_keeps_the_inventory_current.py +0 -0
  945. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_repository_moves_to_the_ticket.py +0 -0
  946. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_review_findings_stay_fixed.py +0 -0
  947. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_reviewer_can_actually_run.py +0 -0
  948. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_role_does_not_claim_blindness.py +0 -0
  949. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_roles_can_reach_the_bundle.py +0 -0
  950. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_roles_run_on_the_local_rows.py +0 -0
  951. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_second_yes_is_the_requesters.py +0 -0
  952. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_security_policy_promises_what_the_scrub_does.py +0 -0
  953. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_sizer_names_the_area_it_expects_to_touch.py +0 -0
  954. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_socket_is_real_and_scoped.py +0 -0
  955. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_split_says_which_card_to_drag.py +0 -0
  956. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_starter_template_passes_its_own_floor.py +0 -0
  957. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_station_strip_resets_on_a_re_run.py +0 -0
  958. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_stock_box_runs_what_the_proposer_proposes.py +0 -0
  959. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_structural_documents_speak_the_projects_portuguese.py +0 -0
  960. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_suite_cannot_reach_production.py +0 -0
  961. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_answers_without_a_channel.py +0 -0
  962. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_can_see_the_change_it_judges.py +0 -0
  963. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_can_see_what_it_reasons_about.py +0 -0
  964. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_does_not_cry_wolf.py +0 -0
  965. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_reads_through_the_ports.py +0 -0
  966. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_techlead_remembers_the_conversation.py +0 -0
  967. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_ticket_url_is_the_trackers_own.py +0 -0
  968. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_toolbox.py +0 -0
  969. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_tracker_has_a_read_side.py +0 -0
  970. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_tracker_reads_what_a_person_wrote.py +0 -0
  971. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_trajectory_is_a_measurement.py +0 -0
  972. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_two_halves_agree_on_which_code_they_run.py +0 -0
  973. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_vendors_credential_is_found_by_default.py +0 -0
  974. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_verifier_is_not_editable_by_what_it_verifies.py +0 -0
  975. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_walk_respects_what_the_repository_ignores.py +0 -0
  976. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_web_conversation_is_directed_at_the_person_in_it.py +0 -0
  977. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_web_offers_the_room_and_the_private_chat.py +0 -0
  978. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_wheel_is_published_under_the_name_the_docs_tell_you_to_install.py +0 -0
  979. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_wheel_ships_what_the_platform_needs.py +0 -0
  980. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_the_word_list_is_a_shortcut_not_a_gate.py +0 -0
  981. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_token_provider.py +0 -0
  982. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_tracker_board_writes.py +0 -0
  983. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_tracker_is_vendor_neutral.py +0 -0
  984. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_two_projects_do_not_share_a_box.py +0 -0
  985. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_voice_vocabulary.py +0 -0
  986. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_walking_skeleton.py +0 -0
  987. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_what_git_refuses_the_person_reads.py +0 -0
  988. {openfactory-0.2.0 → openfactory-0.3.0}/tests/test_who_is_asking.py +0 -0
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: openfactory
3
+ Version: 0.3.0
4
+ Summary: A framework to run software tickets autonomously with coding agents — policies authorize actions, humans evaluate results.
5
+ Author: The OpenFactory Authors
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://openfactory.digital
8
+ Project-URL: Repository, https://github.com/Open-Factory-Digital/openfactory-core
9
+ Project-URL: Issues, https://github.com/Open-Factory-Digital/openfactory-core/issues
10
+ Keywords: sdlc,agents,automation,devops,ai
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Build Tools
16
+ Classifier: Topic :: Software Development :: Quality Assurance
17
+ Requires-Python: >=3.12
18
+ License-File: LICENSE
19
+ License-File: NOTICE
20
+ Requires-Dist: pydantic>=2.7
21
+ Requires-Dist: pyyaml>=6.0
22
+ Requires-Dist: typer>=0.12
23
+ Requires-Dist: httpx>=0.27
24
+ Requires-Dist: pyjwt[crypto]>=2.8
25
+ Requires-Dist: python-dotenv>=1.0
26
+ Requires-Dist: fastapi>=0.111
27
+ Requires-Dist: uvicorn>=0.30
28
+ Requires-Dist: websockets>=12
29
+ Provides-Extra: runtime
30
+ Requires-Dist: temporalio>=1.7; extra == "runtime"
31
+ Provides-Extra: dev
32
+ Requires-Dist: ruff>=0.5; extra == "dev"
33
+ Requires-Dist: mypy>=1.10; extra == "dev"
34
+ Requires-Dist: bandit>=1.7; extra == "dev"
35
+ Requires-Dist: pytest>=8.2; extra == "dev"
36
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
37
+ Requires-Dist: types-pyyaml; extra == "dev"
38
+ Requires-Dist: temporalio>=1.7; extra == "dev"
39
+ Requires-Dist: pytest-randomly>=3.15; extra == "dev"
40
+ Requires-Dist: pytest-xdist>=3.6; extra == "dev"
41
+ Dynamic: license-file
@@ -0,0 +1,232 @@
1
+ # OpenFactory
2
+
3
+ **An autonomous software factory.** It takes tickets from your board and returns reviewed pull
4
+ requests — planned, implemented, validated by *your* test suite, independently reviewed, and
5
+ merged under the policy you chose. Humans stop authorising every step and start evaluating
6
+ results; production stays behind a human gate, always.
7
+
8
+ [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)
9
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12%2B-blue.svg)](pyproject.toml)
10
+
11
+ It is **not a coding agent** — it orchestrates the ones you already use (Claude Code, Codex,
12
+ Kimi, OpenCode) behind one adapter contract. It is **not a SaaS** — it runs on your machines,
13
+ against your board, with your credentials, and no cloud account is required.
14
+
15
+ ## Why this one
16
+
17
+ - **Policies authorise, humans evaluate.** The manifest declares the merge policy, the quality
18
+ floor and the promotion chain; the factory refuses vacuous green — a project with no declared
19
+ test command is *held*, not "passed".
20
+ - **The box is proven before money is spent.** `box prove` runs your own `setup:` and
21
+ `validate:` inside the real sandbox before any ticket is picked up. A misconfigured
22
+ environment is a named finding, not a burned agent pass.
23
+ - **Every stall speaks.** A blocked job parks with executable options for a human; a silent
24
+ forever-wait is treated as the platform's own defect class.
25
+ - **Provider axes, not provider lock-in.** Tracker, board, forge, CI observer, notifier, coding
26
+ agent and sandbox are independent adapters — GitHub Issues + Projects, Jira, Azure DevOps
27
+ (work items → Azure Repos PRs, end to end), chosen per project in a registry.
28
+ - **An independent review, structurally.** The reviewer can run on a *different* engine from the
29
+ executor, so "you did not write this code" is true by construction.
30
+ - **Honest docs.** What does not work is written down (`docs/STATUS.md`)
31
+ before you decide anything.
32
+
33
+ ## Quickstart — one machine
34
+
35
+ The shortest path is your own repository and the coding agent you already pay for: **one
36
+ credential, no Docker, no account anywhere**. The factory branches from your repository, opens a
37
+ pull request in it, reviews the change and fast-forwards your base.
38
+
39
+ Prerequisites: git, Python 3.12+, and a coding agent on your PATH already signed in (`claude`,
40
+ `codex`, `kimi` or `opencode`).
41
+
42
+ ```bash
43
+ git clone https://github.com/Open-Factory-Digital/openfactory-core.git && cd openfactory-core
44
+ python3 -m venv .venv && source .venv/bin/activate # 3.12+; see docs/ONBOARDING.md §0
45
+ pip install -e '.[runtime]' # the durable engine's worker runs on the extra
46
+
47
+ openfactory init # press Enter twice: your code and your tickets live HERE
48
+ openfactory project init myapp ~/code/myapp # a path registers as itself — no owner, no board
49
+ openfactory doctor myapp # on this door, green IS the prerequisite list
50
+
51
+ openfactory act card_create -p myapp -P title="Add a health endpoint" -P body="## Objective
52
+ Serve 200 at /health
53
+
54
+ ## Acceptance criteria
55
+ - GET /health returns 200"
56
+ openfactory act card_move -p myapp -i 1 -P column=TO-DO
57
+ openfactory poll myapp # one card, all the way to Done
58
+ ```
59
+
60
+ `openfactory serve` serves the same thing in a browser at http://localhost:8787 — the Board, the
61
+ job, the pull request. The whole door is **[docs/setup/one-machine.md](docs/setup/one-machine.md)**,
62
+ including what happens to your working tree when a merge lands.
63
+
64
+ ## Quickstart — with Docker, on a hosted forge
65
+
66
+ The other door: the compose stack, a real forge and a real board, several people watching the same
67
+ panel. **Two credentials are irreducible here** — the coding agent's
68
+ (`CLAUDE_CODE_OAUTH_TOKEN` from `claude setup-token`, or `ANTHROPIC_API_KEY`) and a forge
69
+ credential (a PAT to try things out, a GitHub App for real use). Docker is asked for at this hour,
70
+ not before.
71
+
72
+ **Docker. Only Docker.** No Python on the host, no `sudo`, one line:
73
+
74
+ ```bash
75
+ curl -fsSL https://openfactory.digital/install.sh | sh
76
+ ```
77
+
78
+ | | |
79
+ |---|---|
80
+ | **read it first** | `curl -fsSL https://openfactory.digital/install.sh -o install.sh && less install.sh && sh install.sh` |
81
+ | **no script at all** | the four commands below |
82
+
83
+ > The worker mounts the host's Docker socket — that is how `sandbox: container` starts a box, and
84
+ > it is root-equivalent on the host. It is the same trade `docker compose up` has always made here.
85
+
86
+ > The installer sends nothing anywhere. There is no telemetry in this project.
87
+
88
+ Re-running the installer is the upgrade path: it resolves the newest release, pulls it, and
89
+ restarts the stack. Your answers and your data survive it.
90
+
91
+ <a id="the-un-piped-equivalent"></a>
92
+ Prefer to do it by hand? These are the same four steps, and nothing else:
93
+
94
+ ```bash
95
+ REPO=https://github.com/Open-Factory-Digital/openfactory-core
96
+ VERSION=$(curl -fsSLI -o /dev/null -w '%{url_effective}' $REPO/releases/latest); VERSION=${VERSION##*/tag/}
97
+ curl -fsSL $REPO/releases/download/$VERSION/docker-compose.yml -o docker-compose.yml
98
+ curl -fsSL $REPO/releases/download/$VERSION/SHA256SUMS | sha256sum -c --ignore-missing
99
+ docker run --rm -it -v "$PWD:/out" -u "$(id -u):$(id -g)" \
100
+ ghcr.io/open-factory-digital/openfactory-cli:$VERSION init --out /out/.env.compose
101
+ echo "OPENFACTORY_VERSION=$VERSION" >> .env.compose
102
+ docker pull ghcr.io/open-factory-digital/openfactory-sandbox:$VERSION
103
+ docker compose --env-file .env.compose up -d
104
+ ```
105
+
106
+ Three of those lines look optional and are not. The **version is resolved once** and written into
107
+ `.env.compose`, because `docker-compose.yml` defaults to `main` — right for a contributor working
108
+ on the branch, wrong for anybody running a factory. The **box image is pulled by hand** because
109
+ `docker compose up` does not fetch it: the worker launches it as a sibling container on your own
110
+ daemon. And the **checksums are verified**, which is why the files come from the release rather
111
+ than from the website — a static host can serve a file and cannot checksum one.
112
+
113
+ Then open http://localhost:8787 in a browser — the panel (8080 is the engine's own UI).
114
+
115
+ **Two credentials are irreducible for a real ticket** — the coding agent's
116
+ (`CLAUDE_CODE_OAUTH_TOKEN` from `claude setup-token`, or `ANTHROPIC_API_KEY`) and a forge
117
+ credential (a PAT to try things out, a GitHub App for real use). `openfactory init` asks for
118
+ neither and names both; only the agent's cannot be postponed past the first hour.
119
+
120
+ `openfactory preflight` says what is still missing on this machine, one line each with a remedy.
121
+
122
+ Register a project **inside the worker** (the compose stack has its own registry; a
123
+ laptop-registered project is invisible to it). One command registers it and creates the board
124
+ with the platform's columns:
125
+
126
+ ```bash
127
+ docker compose --env-file .env.compose exec worker \
128
+ openfactory project init myapp https://github.com/<owner>/myapp.git # your org or username
129
+ docker compose --env-file .env.compose exec worker openfactory doctor myapp
130
+ ```
131
+
132
+ (`project add` is the variant for a board you already have, or for none at all. On Azure
133
+ DevOps, register with your `dev.azure.com` clone URL — it carries the
134
+ organisation/project/repository, and Azure Boards ships with the project, so there is no board
135
+ to create: **[docs/setup/azure-devops.md](docs/setup/azure-devops.md)**.)
136
+
137
+ `doctor` runs nine checks always and up to four more when they apply, naming every missing
138
+ prerequisite with its remedy — including the
139
+ agent credential and the forge credential. From there, the guided first hour is
140
+ **[docs/ONBOARDING.md](docs/ONBOARDING.md)**: the environment session that reads your repository
141
+ and proposes its own manifest, the box proof, a costed rehearsal on a synthetic ticket, and the
142
+ first real card.
143
+
144
+ ## Your first ticket
145
+
146
+ An ordinary issue, in English or Portuguese:
147
+
148
+ ```markdown
149
+ ## Objective
150
+ Users can export their report as CSV.
151
+
152
+ ## Acceptance criteria
153
+ - a `GET /reports/{id}/export` endpoint returns text/csv
154
+ - the export respects the report's current filters
155
+ ```
156
+
157
+ Drag it to **TO-DO**. The factory sizes it, proves the box, plans, implements, runs *your*
158
+ gates, opens the PR, has it independently reviewed — and with `merge_policy: human` (the
159
+ recommended start) waits for your merge. The panel at `:8787` shows every step live.
160
+
161
+ ## The shape
162
+
163
+ ```
164
+ openfactory/
165
+ ├── contracts/ Pydantic models — the framework↔project↔agent↔board interface
166
+ ├── registry.py the set of projects one deployment drives (add one = data, not code)
167
+ ├── policy/ the quality floor: stack presets + org defaults + conformance
168
+ ├── adapters/ the provider axes — a project mixes them freely; the core ships GitHub,
169
+ │ │ Azure DevOps and Jira on every axis below that has a vendor, and an
170
+ │ │ add-on package adds a kind through the `openfactory.adapters` entry points
171
+ │ ├── tracker/ GitHub Issues, Jira, Azure DevOps work items
172
+ │ ├── board/ GitHub Projects, Jira status, Azure DevOps boards
173
+ │ ├── forge/ GitHub, Azure Repos — branches, PRs, merges, tags
174
+ │ ├── environment/ CI / deploy / health, read-only — GitHub Actions, Azure Pipelines
175
+ │ ├── agent/ CodingAgentAdapter — Claude Code, Codex, Kimi, OpenCode
176
+ │ ├── reviewer/ the independent review
177
+ │ ├── channel/ the panel — the reference surface; a chat channel is an add-on package (openfactory-slack)
178
+ │ └── sandbox/ container = real; worktree = local/test; a cloud box is an add-on package (openfactory-aws)
179
+ ├── orchestrator/ the deterministic state machine (the spine)
180
+ ├── runtime/ the durable engine (Temporal): poller, jobs, promotion tail
181
+ └── cli.py `openfactory` — project-first commands
182
+ ```
183
+
184
+ ## The roles you can switch on
185
+
186
+ | role | what it is | where it lives |
187
+ |---|---|---|
188
+ | **engineering loop** | ticket → reviewed PR → merge | on by default; this README |
189
+ | **post-merge** | watch your deploy, walk your stages, gate production | opt-in per project — [ONBOARDING §13](docs/ONBOARDING.md) says what silence means |
190
+ | **tech-lead** | diagnoses parked jobs, proposes the fix, acts on your yes | the panel; a chat channel such as Slack is an add-on package (openfactory-slack), never a prerequisite |
191
+ | **product owner** | requirements as reviewed docs in a context repo; accept/queue/release | `/product/<name>` on the panel — [docs/reference/product-role.md](docs/reference/product-role.md) |
192
+ | **release gate** | production is approved by a named human with a password, always | [docs/reference/product-role.md §3](docs/reference/product-role.md) |
193
+
194
+ ## Documentation
195
+
196
+ **One path, three references.** The map is [docs/README.md](docs/README.md); this is the short
197
+ form:
198
+
199
+ | read this | when |
200
+ |---|---|
201
+ | [docs/ONBOARDING.md](docs/ONBOARDING.md) | **start here** — the whole guided session on your own codebase, and the only onboarding there is |
202
+ | [docs/setup/one-machine.md](docs/setup/one-machine.md) | one repository, one terminal, one credential — the door that needs no account anywhere |
203
+ | [docs/setup/github.md](docs/setup/github.md) | the path sends you here for GitHub: the App screen by screen, a personal account's board token, a board by hand |
204
+ | [docs/setup/azure-devops.md](docs/setup/azure-devops.md) | …or here for the all-Microsoft side: PAT scopes, board states, registration by clone URL |
205
+ | [docs/STATUS.md](docs/STATUS.md) | the honest read before deciding anything |
206
+ | [docs/reference/configuration.md](docs/reference/configuration.md) | manifest / registry / environment — who owns which setting, promotion chains |
207
+ | [docs/reference/cli.md](docs/reference/cli.md) | every command (the `env`/`box`/`product` surfaces are walked in ONBOARDING) |
208
+ | [docs/reference/product-role.md](docs/reference/product-role.md) | switching on the product owner |
209
+ | [docs/writing-an-addon.md](docs/writing-an-addon.md) | your deployment needs a provider the core does not ship — a row, end to end, editing nothing here |
210
+ | [docs/adr/](docs/adr/) | why it is built this way (49 decision records) |
211
+
212
+ ## Status
213
+
214
+ Working, and honest about where. The whole loop — sizing → box proof → agent → your gates → PR
215
+ → independent review → merge — has run end to end on four stacks (Python,
216
+ serverless TypeScript, .NET, multi-repo) against real GitHub, real Jira and real Azure DevOps.
217
+ The suite runs in both orders on every change and new guards are proven by mutation before they
218
+ count — the current size, the commit it was measured at, and everything that is NOT settled are
219
+ in [`docs/STATUS.md`](docs/STATUS.md), which is the one place any of those numbers live.
220
+
221
+ ## Taking part
222
+
223
+ Issues and pull requests are welcome, and the bar is written down rather than implied:
224
+ [CONTRIBUTING.md](CONTRIBUTING.md) explains the house rules (a guard for every behaviour, a
225
+ mutation for every guard) and how to add a provider to an axis without touching the core.
226
+ **There is no CLA** — Apache-2.0 §5 already covers what you submit, and you keep the copyright
227
+ on what you write. Everyone taking part is held to the [Code of Conduct](CODE_OF_CONDUCT.md).
228
+
229
+ ## License
230
+
231
+ [Apache-2.0](LICENSE). The [NOTICE](NOTICE) file separates the free code from the defended
232
+ brand. Security reports: see [SECURITY.md](SECURITY.md). Contributions: [CONTRIBUTING.md](CONTRIBUTING.md).
@@ -0,0 +1,7 @@
1
+ """openfactory-platform — a framework to run software tickets autonomously.
2
+
3
+ Policies authorize actions; humans evaluate results. See
4
+ docs/adr/0001-foundational-conceptual-model.md for the conceptual model.
5
+ """
6
+
7
+ __version__ = "0.3.0"
@@ -0,0 +1,369 @@
1
+ """The action layer — everything a human can ask the factory to DO, written once (C-23).
2
+
3
+ WHAT WAS ACTUALLY WRONG. The Slack bot never calls the HTTP API: zero httpx, zero requests, zero
4
+ aiohttp. The two front ends were written independently against the same domain, and by the time
5
+ this card was opened they had drifted in ways nobody chose:
6
+
7
+ resume the panel passes the DecisionRequest option key; Slack hard-codes ""
8
+ → a job parked with a real question can be answered from the panel and only
9
+ resumed blindly from Slack, in a channel where the question was posted
10
+ ack exists in Slack, does not exist in the panel at all
11
+ enable / scan exist in the panel, do not exist in Slack
12
+ approve_prod two implementations — a durable signal and an in-process PromotionRunner —
13
+ reachable from one front end each, under names that suggest they are the same
14
+ validation the panel checks the ref shape; Slack checks nothing
15
+
16
+ None of that is a bug anybody wrote. It is what happens when a capability has no home, and it is
17
+ the manifesto's empty SDK box: there was no layer for a third front end to be written against, so
18
+ a third front end would have made it three.
19
+
20
+ WHAT THIS LAYER IS. A table of actions. Each takes values and `by: Actor`, returns an `Outcome`,
21
+ and speaks no transport: no HTTP status, no mrkdwn, no Slack block, no exception escaping. The
22
+ front ends become mappings — a route or a verb picks a name and renders the result.
23
+
24
+ WHAT IT IS NOT. It is not authorization (C-26 / #55): `Actor.admin` is still decided by whoever
25
+ carried the request, and this layer only carries and records it. It is not the conversational
26
+ tech-lead (C-24 / #52): `ask` and `diagnose` are catalogued here and their brains still live in
27
+ the Slack package until that card moves them. Both are deliberate — putting either in this card
28
+ would mean designing identity or the agent's memory model inside a refactor, and that is how a
29
+ refactor becomes a rewrite.
30
+
31
+ REACHING IT. Two universal transports dispatch the whole catalog by name:
32
+
33
+ POST /api/act/{name} the panel and anything holding its token
34
+ openfactory act <name> … a shell on the host
35
+
36
+ and the named front-end paths (`/api/temporal/act`, the Slack verbs, `/api/projects/{n}/enabled`)
37
+ are mappings onto the same rows. That is the property the guards in
38
+ `tests/test_the_action_layer.py` hold: **every action is reachable from at least two transports and
39
+ implemented by none of them.**
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+ import logging
45
+ import re
46
+
47
+ from openfactory.actions.base import (
48
+ CODES,
49
+ CONFLICT,
50
+ DENIED,
51
+ FAILED,
52
+ FLOOR,
53
+ INVALID,
54
+ NOT_FOUND,
55
+ OK,
56
+ PRODUCT,
57
+ SCOPES,
58
+ SYSTEM,
59
+ UNAVAILABLE,
60
+ UNIMPLEMENTED,
61
+ ActionSpec,
62
+ Actor,
63
+ Outcome,
64
+ done,
65
+ not_moved_yet,
66
+ refused,
67
+ )
68
+
69
+ log = logging.getLogger("openfactory.actions")
70
+
71
+ __all__ = [
72
+ "CATALOG", "CODES", "CONFLICT", "DENIED", "FAILED", "FLOOR", "INVALID", "NOT_FOUND", "OK",
73
+ "PRODUCT", "SCOPES", "SYSTEM", "UNAVAILABLE", "UNIMPLEMENTED", "ActionSpec", "Actor",
74
+ "Outcome", "done", "names", "not_moved_yet", "perform", "proposable", "refused",
75
+ "run_staged", "spec",
76
+ ]
77
+
78
+
79
+ async def run_staged(*, project: str, by: Actor, token: str = "") -> Outcome:
80
+ """Perform what the tech-lead staged for `project` — see `catalog.run_staged`.
81
+
82
+ Re-exported lazily for the same reason `_Catalog` is: importing the implementations costs
83
+ `temporalio`, and the panel is built to serve without the runtime extra."""
84
+ from openfactory.actions.catalog import run_staged as _run
85
+
86
+ return await _run(project=project, by=by, token=token)
87
+
88
+
89
+ def _catalog() -> dict[str, ActionSpec]:
90
+ from openfactory.actions.catalog import CATALOG as rows
91
+
92
+ return rows
93
+
94
+
95
+ class _Catalog:
96
+ """A lazy mapping over `catalog.py`, so importing `openfactory.actions` costs nothing.
97
+
98
+ The catalog's implementations reach Temporal, the forge and the approver store. Importing them
99
+ eagerly would put `temporalio` on the import path of every front end — including the panel,
100
+ which is explicitly built to serve without the `runtime` extra installed. The bodies already
101
+ import lazily; this keeps the module itself lazy too, so the guard tests can walk the table on
102
+ a machine that has none of it.
103
+
104
+ THAT PROMISE IS HELD BY A GUARD SINCE #178, because for a while it was only written down: the
105
+ page's own words came from `view.py` and `workflow.py`, so `/` and `/api/floor` answered 500
106
+ on exactly the install this paragraph describes. It asks every GET route in an interpreter
107
+ where `temporalio` cannot be found:
108
+ `tests/test_the_panel_serves_without_the_engines_client.py`."""
109
+
110
+ def __getitem__(self, name: str) -> ActionSpec:
111
+ return _catalog()[name]
112
+
113
+ def __contains__(self, name: object) -> bool:
114
+ return name in _catalog()
115
+
116
+ def __iter__(self):
117
+ return iter(_catalog())
118
+
119
+ def __len__(self) -> int:
120
+ return len(_catalog())
121
+
122
+ def values(self):
123
+ return _catalog().values()
124
+
125
+ def items(self):
126
+ return _catalog().items()
127
+
128
+ def get(self, name: str, default=None):
129
+ return _catalog().get(name, default)
130
+
131
+
132
+ #: The one table. Iterating it is how a front end lists what it can offer, and how the guards
133
+ #: check that every row is reachable.
134
+ CATALOG = _Catalog()
135
+
136
+
137
+ def names() -> tuple[str, ...]:
138
+ """Every action, in catalog order — which is grouped by what an operator is doing, not
139
+ alphabetical, because this is what `openfactory act --list` prints."""
140
+ return tuple(_catalog())
141
+
142
+
143
+ def spec(name: str) -> ActionSpec | None:
144
+ return _catalog().get((name or "").strip().lower())
145
+
146
+
147
+ #: What a proposal may CARRY. It was `{project, issue}` — a ticket and nothing else — because the
148
+ #: channel back was `[[SUGGEST verb #NN]]`, with nowhere to put a sentence. That dropped `adjust`,
149
+ #: and the consequence was the shape of the whole role: the tech-lead could propose that you throw
150
+ #: work away (`discard`) or rerun it blind (`resume`), and could not propose the one thing a senior
151
+ #: engineer actually says, which is WHAT TO CHANGE (#170).
152
+ #:
153
+ #: A SECRET IS STILL NOT ADDRESSABLE, and that is the line this set now draws. `_SECRET` below
154
+ #: names what may never travel through a proposal; a parameter outside it is prose a human reads on
155
+ #: the button before pressing it.
156
+ _ADDRESSABLE = frozenset({"project", "issue", "instruction"})
157
+
158
+
159
+ def proposable(by: Actor) -> tuple[str, ...]:
160
+ """The actions this actor may perform AND the tech-lead may propose, in catalog order (#121).
161
+
162
+ THREE FILTERS, ALL DERIVED, because the alternative is the sentence this replaces: the
163
+ tech-lead's guidance said *"never suggest prod/merge actions"* — a rule written when the
164
+ catalogue had no merge row. #120 added one, gated, reachable from the chat, and the guidance
165
+ went on forbidding it. A hand-written list of verbs in a prompt is a second copy of the
166
+ catalogue that nobody updates.
167
+
168
+ 1. **The asker's own credential**, by the SAME two checks `perform` applies and in the same
169
+ order — scope, then admin. A credential that cannot press the button must not be told to
170
+ ask for it; being handed an action and then refused is worse than not being offered it.
171
+ 2. **What a human could have typed.** A suggestion is a proposal somebody approves with one
172
+ word, so it must be something they could have said themselves: the operator grammar
173
+ (`contracts/commands.py`, which is `resume`/`skip` and deliberately excludes prod) and the
174
+ floor matcher (`actions/floor_intents.py`, which is merge/discard/adjust). Rows like
175
+ `start`, `diagnose` and `product_release` are addressable by a ticket and are NOT things
176
+ the floor's own grammar accepts — which is exactly the line the old rule was reaching for.
177
+ 3. **What a proposal can carry** — see `_ADDRESSABLE`. This used to drop `adjust`, because
178
+ the channel was one verb and one ticket wide. It carries an instruction now (#170), and the
179
+ blast radius is closed by (2): `typeable` is `{adjust, discard, merge, resume, skip, stop}`,
180
+ so relaxing this admits EXACTLY `adjust`. `approve_prod` and `promote` stay out where they
181
+ already were — not in the floor grammar — rather than by this filter's accident.
182
+
183
+ `ack` is deliberately absent from (2). It is a person saying they have seen something, and
184
+ nobody can propose that on somebody else's behalf.
185
+ """
186
+ from openfactory.actions.floor_intents import FLOOR_ROWS
187
+ from openfactory.contracts.commands import ACTION_OF
188
+
189
+ typeable = set(ACTION_OF.values()) | set(FLOOR_ROWS.values())
190
+ out: list[str] = []
191
+ for name, found in _catalog().items():
192
+ if name not in typeable:
193
+ continue
194
+ if not by.may_enter(found.scope):
195
+ continue
196
+ if found.needs_admin and not by.admin:
197
+ continue
198
+ if set(found.required) - _ADDRESSABLE or "issue" not in found.required:
199
+ continue
200
+ out.append(name)
201
+ return tuple(out)
202
+
203
+
204
+ async def perform(name: str, *, by: Actor, **params: object) -> Outcome:
205
+ """Run one action. Never raises. Always returns an `Outcome`.
206
+
207
+ THE FIVE THINGS THAT HAPPEN HERE RATHER THAN IN THREE FRONT ENDS:
208
+
209
+ 1. **The name is resolved**, and an unknown one is refused with the list of what exists —
210
+ the registry rule this codebase already holds everywhere else (`adapters/*/registry.py`).
211
+ 2. **Parameters are checked** against the spec, in both directions. A missing one is named; so
212
+ is an unexpected one, because a front end that renames a field and keeps working silently
213
+ is how `image=` came to be omitted at all four job-launch sites (see
214
+ `a-negative-guard-needs-a-positive-twin`).
215
+ 3. **A ticket ref is normalised once.** `#189` and `189` are the same ticket, and until now the
216
+ panel knew that and Slack did not.
217
+ 4. **`needs_admin` is enforced.** Slack had this gate, the panel had a token, the CLI had
218
+ nothing; now the three answers meet in `Actor.admin` and the decision is made in one place.
219
+ 5. **Everything is logged with the actor**, whatever the result. This is the audit line — the
220
+ first time this platform can say who asked for a thing, which is the question an enterprise
221
+ security review opens with.
222
+
223
+ NEVER RAISING IS NOT POLITENESS. Both front ends already have a hard must-always-reply rule,
224
+ and both implemented it by wrapping every call in `except Exception`. Doing it here means an
225
+ action author cannot forget, and means the exception's real message survives — `first_message`
226
+ walks the chain, because an error crossing a Temporal activity boundary otherwise arrives as
227
+ the fixed string "Activity task failed" (#66).
228
+ """
229
+ key = (name or "").strip().lower()
230
+ found = _catalog().get(key)
231
+ if found is None:
232
+ return refused(
233
+ NOT_FOUND,
234
+ f"there is no action called {name!r} — this deployment does: " + ", ".join(names()),
235
+ )
236
+
237
+ problem = _check_params(found, params)
238
+ if problem:
239
+ return refused(INVALID, problem)
240
+
241
+ if "issue" in params:
242
+ ref, bad = _clean_ref(str(params["issue"]))
243
+ if bad:
244
+ return refused(INVALID, bad)
245
+ params["issue"] = ref
246
+
247
+ # SCOPE BEFORE ADMIN, because they answer different questions and the order is the point: a
248
+ # business analyst holding a product credential IS an admin of the product area — accepting a
249
+ # requirement is the most consequential act there — and must still be refused `merge` outright.
250
+ # Asking `admin` first would let that credential through on every row it happens to satisfy.
251
+ if not by.may_enter(found.scope):
252
+ log.warning("DENIED_SCOPE %s (%s) by %s (%s)", key, found.scope, by, _loggable(params))
253
+ return refused(
254
+ DENIED,
255
+ f"this credential is scoped to {', '.join(sorted(by.scopes or ())) or 'nothing'} and "
256
+ f"{key} belongs to the {found.scope}. Nothing was done — ask somebody whose "
257
+ f"credential covers the {found.scope}.",
258
+ )
259
+
260
+ if found.needs_admin and not by.admin:
261
+ log.warning("DENIED %s by %s (%s)", key, by, _loggable(params))
262
+ return refused(
263
+ DENIED,
264
+ f"{by} is not allowed to {key} — ask somebody listed as an admin for this project.",
265
+ )
266
+
267
+ try:
268
+ outcome = await found.run(by=by, **params)
269
+ except Exception as exc: # noqa: BLE001 — an action must never take its caller down
270
+ log.exception("action %s raised for %s", key, by)
271
+ return refused(FAILED, f"could not {key}: {_why(exc)}")
272
+ if not isinstance(outcome, Outcome): # an action that returns None is a silent success (F5)
273
+ log.error("action %s returned %r, not an Outcome", key, type(outcome).__name__)
274
+ return refused(
275
+ FAILED,
276
+ f"'{key}' did not report what it did — treat this as a failure and check the logs "
277
+ f"before assuming it happened.",
278
+ )
279
+ log.info("action=%s by=%s ok=%s code=%s params=%s", key, by, outcome.ok,
280
+ outcome.code or "-", _loggable(params))
281
+ return outcome
282
+
283
+
284
+ #: Parameters whose VALUE must never reach a log line. `approve_prod` and `promote` take the
285
+ #: approver's password, and this module writes an audit line on every call including the refusals —
286
+ #: which is precisely the path a wrong password takes.
287
+ _SECRET = frozenset({"password", "token", "secret", "key"})
288
+
289
+
290
+ def _why(exc: Exception) -> str:
291
+ """What the refusal says an action died of — the install, when the install is what is missing.
292
+
293
+ THE ROWS THAT ARE THE ENGINE'S IMPORT ITS MODULES INSIDE THEIR BODIES, by design: that is what
294
+ keeps `temporalio` off every front end's import path (see `_Catalog`). So on an install made
295
+ without the `runtime` extra, `start`, `stop`, `approve` and the rest raise here, and the person
296
+ read `could not start: No module named 'temporalio'` — a cause with no remedy. The catch-all
297
+ above is the one guard all of them share, so it is the one place that names the install:
298
+ `host.CLIENT_MISSING`, the sentence every other surface gives for that condition (#178)."""
299
+ from openfactory.runtime.host import CLIENT_MISSING, the_client_is_what_is_missing
300
+ from openfactory.util.causes import first_message
301
+
302
+ # The chain, not only its head: a row that wraps its own failures still died of the import.
303
+ link: BaseException | None = exc
304
+ for _ in range(8): # bounded: a chain is short, and a hand-built cyclic one must not spin
305
+ if link is None:
306
+ break
307
+ if the_client_is_what_is_missing(link):
308
+ return CLIENT_MISSING
309
+ link = link.__cause__ or link.__context__
310
+ return first_message(exc)
311
+
312
+
313
+ def _loggable(params: dict[str, object]) -> dict[str, object]:
314
+ return {k: ("***" if k in _SECRET else v) for k, v in params.items()}
315
+
316
+
317
+ def _check_params(found: ActionSpec, params: dict[str, object]) -> str:
318
+ missing = [p for p in found.required if p not in params or params[p] in (None, "")]
319
+ if missing:
320
+ return (f"'{found.name}' needs {', '.join(missing)} — it takes "
321
+ + ", ".join(found.parameters) + ".")
322
+ unexpected = [p for p in params if p not in found.parameters]
323
+ if unexpected:
324
+ return (f"'{found.name}' does not take {', '.join(sorted(unexpected))} — it takes "
325
+ + (", ".join(found.parameters) or "no parameters") + ".")
326
+ return ""
327
+
328
+
329
+ #: What a tracker actually calls a ticket: `189` (GitHub, optionally `#`-prefixed), `CONT-412`
330
+ #: (Jira), `1234` (Azure DevOps). Letters, digits, one kind of separator, nothing else.
331
+ #:
332
+ #: Lifted verbatim from `api/app.py::_valid_issue`, which is the point: the panel held this and
333
+ #: Slack held nothing, so a ref typed in a channel went straight into a Temporal workflow id. The
334
+ #: bound matters for the same reason it did there — a ref becomes part of a workflow id and, via
335
+ #: `paths.journal_stem`, part of a filename.
336
+ _ISSUE_RE = re.compile(r"^[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$")
337
+ #: …and the same ref carrying the repository it lives in (C-18): `owner/name#189`. One product can
338
+ #: own several repositories, so on a multi-repo board a bare number names no single ticket. Kept as
339
+ #: a SECOND, fully-anchored pattern rather than by loosening the first: `/` and `#` reach a
340
+ #: workflow id and a filename, and the way to allow exactly two segments and one hash is to spell
341
+ #: that out, not to add characters to a class and hope.
342
+ _QUALIFIED_RE = re.compile(
343
+ r"^[A-Za-z0-9][A-Za-z0-9._-]*/[A-Za-z0-9][A-Za-z0-9._-]*#[A-Za-z0-9]+(?:[-_][A-Za-z0-9]+)*$")
344
+ _ISSUE_MAX = 64
345
+ #: The qualified form needs room for `owner/name#` on top of the ref itself. A SEPARATE bound, so
346
+ #: widening it here cannot quietly widen what a bare ref may be — the bound is what keeps a ref
347
+ #: from becoming an unreasonable workflow id or filename, and each shape deserves its own.
348
+ _QUALIFIED_MAX = 160
349
+
350
+
351
+ def _clean_ref(issue: str) -> tuple[str, str]:
352
+ """`(ref, problem)` — the provider's own ref without the decoration a human types.
353
+
354
+ `#189` and `189` must not be two tickets. The panel already knew that in `_valid_issue`; Slack
355
+ passed whatever was typed straight into a Temporal workflow id, so `skip #250` and `skip 250`
356
+ addressed different workflows and only one of them existed.
357
+
358
+ REJECTING IS STILL WORTH DOING even though `paths.py` neutralises a hostile ref on its own
359
+ (C-06a). This is where there is somebody to tell: a sentence naming the problem beats a job
360
+ launched against a ref no provider will ever recognise, which surfaces minutes later as an
361
+ unexplained 404."""
362
+ ref = (issue or "").strip().lstrip("#").strip()
363
+ bare = bool(ref) and len(ref) <= _ISSUE_MAX and bool(_ISSUE_RE.match(ref))
364
+ qualified = bool(ref) and len(ref) <= _QUALIFIED_MAX and bool(_QUALIFIED_RE.match(ref))
365
+ if not (bare or qualified):
366
+ return "", ("that is not a ticket reference — letters, digits, '-' or '_', optionally "
367
+ "with the repository it lives in "
368
+ f"(e.g. 189, #189, CONT-412, owner/name#189), got {issue!r}")
369
+ return ref, ""