engineering-process 0.5.0__tar.gz → 0.5.1__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 (171) hide show
  1. {engineering_process-0.5.0/engineering_process.egg-info → engineering_process-0.5.1}/PKG-INFO +5 -4
  2. {engineering_process-0.5.0 → engineering_process-0.5.1}/README.md +4 -3
  3. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/__init__.py +1 -1
  4. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/_windows_job.py +1 -1
  5. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/supervision.py +1 -0
  6. {engineering_process-0.5.0 → engineering_process-0.5.1/engineering_process.egg-info}/PKG-INFO +5 -4
  7. {engineering_process-0.5.0 → engineering_process-0.5.1}/improvement-catalog.json +2 -2
  8. {engineering_process-0.5.0 → engineering_process-0.5.1}/pyproject.toml +1 -1
  9. engineering_process-0.5.1/release.json +46 -0
  10. {engineering_process-0.5.0 → engineering_process-0.5.1}/templates/adopt-process-windows-job.py +1 -1
  11. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_candidate.py +22 -12
  12. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_self_hosting.py +17 -3
  13. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_windows_job.py +50 -5
  14. engineering_process-0.5.0/release.json +0 -138
  15. {engineering_process-0.5.0 → engineering_process-0.5.1}/LICENSE +0 -0
  16. {engineering_process-0.5.0 → engineering_process-0.5.1}/MANIFEST.in +0 -0
  17. {engineering_process-0.5.0 → engineering_process-0.5.1}/PROCESS_IMPROVEMENT.md +0 -0
  18. {engineering_process-0.5.0 → engineering_process-0.5.1}/PRODUCTION_STANDARD.md +0 -0
  19. {engineering_process-0.5.0 → engineering_process-0.5.1}/VERSIONING.md +0 -0
  20. {engineering_process-0.5.0 → engineering_process-0.5.1}/bundles.json +0 -0
  21. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/__main__.py +0 -0
  22. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/_download_worker.py +0 -0
  23. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/_supervisor_posix.py +0 -0
  24. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/_supervisor_windows.py +0 -0
  25. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/adoption.py +0 -0
  26. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/artifact_attestation.py +0 -0
  27. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/bootstrap.py +0 -0
  28. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/bounded_process.py +0 -0
  29. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/bundles.py +0 -0
  30. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/cli.py +0 -0
  31. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/command_catalog.py +0 -0
  32. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/contracts.py +0 -0
  33. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/diagnostics.py +0 -0
  34. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/distribution.py +0 -0
  35. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/distribution_verify.py +0 -0
  36. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/environment.py +0 -0
  37. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/evidence.py +0 -0
  38. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/evidence_transport.py +0 -0
  39. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/git.py +0 -0
  40. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/git_attributes.py +0 -0
  41. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/helper_launch.py +0 -0
  42. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/impact.py +0 -0
  43. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/improvement.py +0 -0
  44. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/lifecycle.py +0 -0
  45. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/lifecycle_routes.py +0 -0
  46. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/managed.py +0 -0
  47. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/markdown.py +0 -0
  48. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/process_graph.py +0 -0
  49. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/publication.py +0 -0
  50. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/release.py +0 -0
  51. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/release_candidate.py +0 -0
  52. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/requirements-build.txt +0 -0
  53. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/requirements-dev.txt +0 -0
  54. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/requirements-release.txt +0 -0
  55. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/requirements-runtime.txt +0 -0
  56. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/runner.py +0 -0
  57. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/runtime.py +0 -0
  58. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/skills.py +0 -0
  59. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/supplemental.py +0 -0
  60. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/syncing.py +0 -0
  61. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process/tooling.py +0 -0
  62. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process.egg-info/SOURCES.txt +0 -0
  63. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process.egg-info/dependency_links.txt +0 -0
  64. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process.egg-info/entry_points.txt +0 -0
  65. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process.egg-info/requires.txt +0 -0
  66. {engineering_process-0.5.0 → engineering_process-0.5.1}/engineering_process.egg-info/top_level.txt +0 -0
  67. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/adoption-migration.json +0 -0
  68. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/automation-policy.json +0 -0
  69. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/automation-proposal-policy.json +0 -0
  70. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/automation-proposal.json +0 -0
  71. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/change.json +0 -0
  72. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/improvement-catalog.json +0 -0
  73. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/improvement-disposition.json +0 -0
  74. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/improvement-reproduction.json +0 -0
  75. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/improvement-resolution.json +0 -0
  76. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/improvement-signal.json +0 -0
  77. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/plan.json +0 -0
  78. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/project.json +0 -0
  79. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/release-change.json +0 -0
  80. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/release.json +0 -0
  81. {engineering_process-0.5.0 → engineering_process-0.5.1}/examples/review.json +0 -0
  82. {engineering_process-0.5.0 → engineering_process-0.5.1}/process-graph.json +0 -0
  83. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/assess-design/SKILL.md +0 -0
  84. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/build-frontend/SKILL.md +0 -0
  85. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/build-frontend-foundation/SKILL.md +0 -0
  86. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/change-api/SKILL.md +0 -0
  87. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/cross-repo-change/SKILL.md +0 -0
  88. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/define-change-contract/SKILL.md +0 -0
  89. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/design-module/SKILL.md +0 -0
  90. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/evolve-process/SKILL.md +0 -0
  91. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/finish-change/SKILL.md +0 -0
  92. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/govern-ui/SKILL.md +0 -0
  93. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/implement-change/SKILL.md +0 -0
  94. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/implement-module/SKILL.md +0 -0
  95. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/implement-use-case/SKILL.md +0 -0
  96. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/integrate-mcp/SKILL.md +0 -0
  97. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/maintain-docs/SKILL.md +0 -0
  98. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/plan-change/SKILL.md +0 -0
  99. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/publish-change/SKILL.md +0 -0
  100. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/review-change/SKILL.md +0 -0
  101. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/run-change/SKILL.md +0 -0
  102. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/run-change/references/execution.md +0 -0
  103. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/run-project-command/SKILL.md +0 -0
  104. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/specify-use-case/SKILL.md +0 -0
  105. {engineering_process-0.5.0 → engineering_process-0.5.1}/process_assets/skills/verify-change/SKILL.md +0 -0
  106. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/adoption-migration.schema.json +0 -0
  107. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/automation-policy.schema.json +0 -0
  108. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/automation-proposal-policy.schema.json +0 -0
  109. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/automation-proposal.schema.json +0 -0
  110. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/change.schema.json +0 -0
  111. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/evidence-receipt.schema.json +0 -0
  112. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/improvement-catalog.schema.json +0 -0
  113. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/improvement-disposition.schema.json +0 -0
  114. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/improvement-reproduction.schema.json +0 -0
  115. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/improvement-resolution.schema.json +0 -0
  116. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/improvement-signal.schema.json +0 -0
  117. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/lifecycle.schema.json +0 -0
  118. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/plan.schema.json +0 -0
  119. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/process-graph.schema.json +0 -0
  120. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/process-lock.schema.json +0 -0
  121. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/project.schema.json +0 -0
  122. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/release-change.schema.json +0 -0
  123. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/release.schema.json +0 -0
  124. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/review.schema.json +0 -0
  125. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/reviewer-attestation.schema.json +0 -0
  126. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/supplemental-verification.schema.json +0 -0
  127. {engineering_process-0.5.0 → engineering_process-0.5.1}/schemas/verification.schema.json +0 -0
  128. {engineering_process-0.5.0 → engineering_process-0.5.1}/setup.cfg +0 -0
  129. {engineering_process-0.5.0 → engineering_process-0.5.1}/templates/AGENTS.process.md +0 -0
  130. {engineering_process-0.5.0 → engineering_process-0.5.1}/templates/PULL_REQUEST_TEMPLATE.md +0 -0
  131. {engineering_process-0.5.0 → engineering_process-0.5.1}/templates/adopt-process.py +0 -0
  132. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_adoption.py +0 -0
  133. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_adoption_runner.py +0 -0
  134. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_artifact_attestation.py +0 -0
  135. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_bootstrap.py +0 -0
  136. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_bounded_process.py +0 -0
  137. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_bundles.py +0 -0
  138. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_cli.py +0 -0
  139. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_completed_release_dispatch.py +0 -0
  140. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_completion_evidence_transport.py +0 -0
  141. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_contracts.py +0 -0
  142. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_diagnostics.py +0 -0
  143. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_distribution.py +0 -0
  144. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_distribution_verify.py +0 -0
  145. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_environment.py +0 -0
  146. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_evals.py +0 -0
  147. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_impact.py +0 -0
  148. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_improvement.py +0 -0
  149. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_lifecycle.py +0 -0
  150. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_process_graph.py +0 -0
  151. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_process_install.py +0 -0
  152. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_publication.py +0 -0
  153. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_publish_event.py +0 -0
  154. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_pypi_publication.py +0 -0
  155. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release.py +0 -0
  156. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_candidate_boundary.py +0 -0
  157. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_completion_identity.py +0 -0
  158. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_evidence_restore.py +0 -0
  159. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_evidence_selection.py +0 -0
  160. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_preparation.py +0 -0
  161. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_release_qualification.py +0 -0
  162. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_runner.py +0 -0
  163. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_runtime.py +0 -0
  164. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_schemas.py +0 -0
  165. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_skills.py +0 -0
  166. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_source_checkout.py +0 -0
  167. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_supervision.py +0 -0
  168. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_supplemental.py +0 -0
  169. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_syncing.py +0 -0
  170. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_test_suite.py +0 -0
  171. {engineering_process-0.5.0 → engineering_process-0.5.1}/tests/test_tooling.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-process
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Agent-neutral end-to-end engineering lifecycle and deterministic process CLI
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/phuongnse/engineering-process
@@ -92,9 +92,10 @@ distribution: the POSIX backend owns a new process session/group and the Windows
92
92
  backend owns a kill-on-close Job Object. Consumer manifests, evidence, and exit codes
93
93
  do not branch by operating system. If an outer Windows Job applies incompatible
94
94
  nesting or UI limits, target creation fails closed instead of running uncontained.
95
- After a command root exits, both backends allow at most 250 milliseconds for child
96
- accounting to drain naturally. A process still present after that bound is terminated
97
- and makes the command fail; commands with no remaining child return immediately.
95
+ After a command root exits, the POSIX backend allows at most 250 milliseconds and the
96
+ Windows Job Object backend allows at most 5 seconds for child accounting to drain
97
+ naturally. A process still present after its platform bound is terminated and makes
98
+ the command fail; commands with no remaining child return immediately.
98
99
 
99
100
  This task boundary intentionally separates finite commands from services and
100
101
  interactive protocols. `processctl exec`, requirement probes, setup command actions,
@@ -57,9 +57,10 @@ distribution: the POSIX backend owns a new process session/group and the Windows
57
57
  backend owns a kill-on-close Job Object. Consumer manifests, evidence, and exit codes
58
58
  do not branch by operating system. If an outer Windows Job applies incompatible
59
59
  nesting or UI limits, target creation fails closed instead of running uncontained.
60
- After a command root exits, both backends allow at most 250 milliseconds for child
61
- accounting to drain naturally. A process still present after that bound is terminated
62
- and makes the command fail; commands with no remaining child return immediately.
60
+ After a command root exits, the POSIX backend allows at most 250 milliseconds and the
61
+ Windows Job Object backend allows at most 5 seconds for child accounting to drain
62
+ naturally. A process still present after its platform bound is terminated and makes
63
+ the command fail; commands with no remaining child return immediately.
63
64
 
64
65
  This task boundary intentionally separates finite commands from services and
65
66
  interactive protocols. `processctl exec`, requirement probes, setup command actions,
@@ -1,3 +1,3 @@
1
1
  """Agent-neutral engineering process."""
2
2
 
3
- VERSION = "0.5.0"
3
+ VERSION = "0.5.1"
@@ -36,7 +36,7 @@ WAIT_FAILED = 0xFFFFFFFF
36
36
  WAIT_OBJECT_0 = 0x00000000
37
37
  WAIT_TIMEOUT = 0x00000102
38
38
  CLEANUP_GRACE_MILLISECONDS = 5_000
39
- NATURAL_DRAIN_GRACE_MILLISECONDS = 250
39
+ NATURAL_DRAIN_GRACE_MILLISECONDS = 5_000
40
40
  MAX_STATUS_BYTES = 4096
41
41
  MAX_STATUS_ERROR_CHARACTERS = 1024
42
42
 
@@ -15,6 +15,7 @@ from typing import Mapping, Protocol
15
15
 
16
16
 
17
17
  NATURAL_DRAIN_GRACE_MILLISECONDS = 250
18
+ WINDOWS_NATURAL_DRAIN_GRACE_MILLISECONDS = 5_000
18
19
 
19
20
 
20
21
  @dataclass(frozen=True)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-process
3
- Version: 0.5.0
3
+ Version: 0.5.1
4
4
  Summary: Agent-neutral end-to-end engineering lifecycle and deterministic process CLI
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/phuongnse/engineering-process
@@ -92,9 +92,10 @@ distribution: the POSIX backend owns a new process session/group and the Windows
92
92
  backend owns a kill-on-close Job Object. Consumer manifests, evidence, and exit codes
93
93
  do not branch by operating system. If an outer Windows Job applies incompatible
94
94
  nesting or UI limits, target creation fails closed instead of running uncontained.
95
- After a command root exits, both backends allow at most 250 milliseconds for child
96
- accounting to drain naturally. A process still present after that bound is terminated
97
- and makes the command fail; commands with no remaining child return immediately.
95
+ After a command root exits, the POSIX backend allows at most 250 milliseconds and the
96
+ Windows Job Object backend allows at most 5 seconds for child accounting to drain
97
+ naturally. A process still present after its platform bound is terminated and makes
98
+ the command fail; commands with no remaining child return immediately.
98
99
 
99
100
  This task boundary intentionally separates finite commands from services and
100
101
  interactive protocols. `processctl exec`, requirement probes, setup command actions,
@@ -4,8 +4,8 @@
4
4
  "activeChangeId": null,
5
5
  "id": "deterministic-cross-platform-test-environment",
6
6
  "lastResolution": {
7
- "changeId": "fix-windows-verification-boundary",
8
- "version": "0.5.0"
7
+ "changeId": "extend-windows-natural-drain",
8
+ "version": "0.5.1"
9
9
  },
10
10
  "publicSurfaces": [
11
11
  "cross-platform-tests",
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "engineering-process"
7
- version = "0.5.0"
7
+ version = "0.5.1"
8
8
  description = "Agent-neutral end-to-end engineering lifecycle and deterministic process CLI"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -0,0 +1,46 @@
1
+ {
2
+ "schemaVersion": 3,
3
+ "previousVersion": "0.5.0",
4
+ "version": "0.5.1",
5
+ "classification": "patch",
6
+ "compatibility": "backward-compatible",
7
+ "schemaImpact": "unchanged",
8
+ "migration": null,
9
+ "identity": {
10
+ "package": "engineering-process",
11
+ "distribution": "engineering_process",
12
+ "tag": "v0.5.1",
13
+ "releaseName": "v0.5.1",
14
+ "runtimeVersion": {
15
+ "path": "engineering_process/__init__.py",
16
+ "variable": "VERSION"
17
+ },
18
+ "artifacts": [
19
+ "engineering_process-0.5.1-py3-none-any.whl",
20
+ "engineering_process-0.5.1.tar.gz"
21
+ ],
22
+ "receiptAsset": "engineering-process-v0.5.1-evidence.json",
23
+ "authorizationAsset": null
24
+ },
25
+ "provenance": {
26
+ "mode": "governed",
27
+ "statement": "The public N-1 lifecycle receipt and reviewed Release PR authorize this release.",
28
+ "lifecycleReceipt": {
29
+ "asset": "engineering-process-v0.5.1-evidence.json",
30
+ "project": "engineering-process",
31
+ "changeId": "release-0-5-1",
32
+ "cycle": 1
33
+ }
34
+ },
35
+ "changes": [
36
+ {
37
+ "id": "extend-windows-natural-drain",
38
+ "type": "fix",
39
+ "surfaces": [
40
+ "command-execution",
41
+ "windows-supervision"
42
+ ],
43
+ "rationale": "Extend the Windows Job Object natural-drain bound from 250 milliseconds to 5 seconds so successful finite Cargo and Tauri commands can finish child accounting while commands that retain descendants beyond the bound remain terminated and fail closed."
44
+ }
45
+ ]
46
+ }
@@ -36,7 +36,7 @@ WAIT_FAILED = 0xFFFFFFFF
36
36
  WAIT_OBJECT_0 = 0x00000000
37
37
  WAIT_TIMEOUT = 0x00000102
38
38
  CLEANUP_GRACE_MILLISECONDS = 5_000
39
- NATURAL_DRAIN_GRACE_MILLISECONDS = 250
39
+ NATURAL_DRAIN_GRACE_MILLISECONDS = 5_000
40
40
  MAX_STATUS_BYTES = 4096
41
41
  MAX_STATUS_ERROR_CHARACTERS = 1024
42
42
 
@@ -20,6 +20,22 @@ from engineering_process.release_candidate import (
20
20
  render_release_pull_request,
21
21
  )
22
22
  class ReleaseCandidateTests(unittest.TestCase):
23
+ def assert_federated_migration_contract(
24
+ self, aggregate: str, federated_migration: str | None
25
+ ) -> None:
26
+ self.assertLessEqual(len(aggregate), 1_000)
27
+ if federated_migration is None:
28
+ return
29
+ for required in (
30
+ "Must adopt cross-repo-change",
31
+ "classify governed failures/findings",
32
+ "consumers await disposition",
33
+ "immutable release",
34
+ "exact reproduction",
35
+ "Released lifecycle/evidence readers retain historical meaning",
36
+ ):
37
+ self.assertIn(required, federated_migration)
38
+
23
39
  def test_source_release_migration_aggregate_fits_public_contract(self):
24
40
  changes_dir = Path(__file__).resolve().parent.parent / "release-changes"
25
41
  if not changes_dir.is_dir():
@@ -45,20 +61,14 @@ class ReleaseCandidateTests(unittest.TestCase):
45
61
  )
46
62
  )
47
63
  aggregate = release.migration or ""
48
- self.assertIn("federated-process-improvement:", aggregate)
49
- federated_migration = aggregate
64
+ if "federated-process-improvement:" in aggregate:
65
+ federated_migration = aggregate
50
66
  else:
51
67
  aggregate = "; ".join(migrations)
52
- self.assertLessEqual(len(aggregate), 1_000)
53
- for required in (
54
- "Must adopt cross-repo-change",
55
- "classify governed failures/findings",
56
- "consumers await disposition",
57
- "immutable release",
58
- "exact reproduction",
59
- "Released lifecycle/evidence readers retain historical meaning",
60
- ):
61
- self.assertIn(required, federated_migration)
68
+ self.assert_federated_migration_contract(aggregate, federated_migration)
69
+
70
+ def test_migration_free_patch_has_no_legacy_guidance_requirement(self):
71
+ self.assert_federated_migration_contract("", None)
62
72
 
63
73
  def test_generated_release_closes_only_catalog_entries_in_its_change_set(self):
64
74
  with tempfile.TemporaryDirectory() as directory:
@@ -35,6 +35,16 @@ class SelfHostingTests(unittest.TestCase):
35
35
  self.assertIn("process-action-smoke/Scripts/python.exe", ci)
36
36
  self.assertIn("process-action-smoke/bin/python", ci)
37
37
  self.assertIn("Verify shared install action authority", ci)
38
+ windows_job = ci.index("Verify real Windows Job Object boundary")
39
+ install_wheel = ci.index("Install built wheel")
40
+ windows_job_block = ci[windows_job:install_wheel]
41
+ self.assertIn("if: runner.os == 'Windows'", windows_job_block)
42
+ self.assertIn(
43
+ "run: python -m unittest tests.test_windows_job",
44
+ windows_job_block,
45
+ )
46
+ self.assertLess(ci.index("Build distributions"), windows_job)
47
+ self.assertLess(windows_job, install_wheel)
38
48
  create = ci.index("Create exact public N-1 release qualification environment")
39
49
  install = ci.index("Install exact public N-1 release qualification authority")
40
50
  dependencies = ci.index("Install release qualification dependencies")
@@ -208,12 +218,12 @@ class SelfHostingTests(unittest.TestCase):
208
218
  self.assertIn("lifecycle comparison base", readme)
209
219
  self.assertNotIn("No workflow invokes merge", readme)
210
220
 
211
- def test_renovate_cannot_publish_before_a_completed_lifecycle(self):
221
+ def test_renovate_consumer_intent_keeps_authority_adoption_disabled(self):
212
222
  renovate = json.loads(
213
223
  (PROCESS_ROOT / ".github" / "renovate.json").read_text(encoding="utf-8")
214
224
  )
215
225
 
216
- self.assertFalse(renovate["enabled"])
226
+ self.assertTrue(renovate["enabled"])
217
227
  self.assertFalse(renovate["automerge"])
218
228
  self.assertFalse(renovate["dependencyDashboard"])
219
229
  self.assertNotIn("draftPR", renovate)
@@ -578,11 +588,15 @@ class SelfHostingTests(unittest.TestCase):
578
588
  marker = "# Managed by engineering-process; do not edit.\n"
579
589
  self.assertTrue(template.read_text(encoding="utf-8").startswith(marker))
580
590
  self.assertTrue(managed.read_text(encoding="utf-8").startswith(marker))
581
- self.assertNotIn('"--status-handle"', managed.read_text(encoding="utf-8"))
591
+ self.assertEqual(managed.read_bytes(), template.read_bytes())
582
592
  self.assertIn('"--status-handle"', template.read_text(encoding="utf-8"))
583
593
  self.assertTrue(
584
594
  managed_windows_helper.read_text(encoding="utf-8").startswith(marker)
585
595
  )
596
+ self.assertIn(
597
+ "JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE",
598
+ managed_windows_helper.read_text(encoding="utf-8"),
599
+ )
586
600
  self.assertEqual(
587
601
  windows_helper.read_bytes(), template_windows_helper.read_bytes()
588
602
  )
@@ -12,7 +12,9 @@ import unittest
12
12
  from unittest.mock import patch
13
13
 
14
14
  from engineering_process import _windows_job
15
- from engineering_process.supervision import NATURAL_DRAIN_GRACE_MILLISECONDS
15
+ from engineering_process.supervision import (
16
+ WINDOWS_NATURAL_DRAIN_GRACE_MILLISECONDS,
17
+ )
16
18
 
17
19
 
18
20
  class NativeCall:
@@ -240,9 +242,9 @@ class WindowsJobTests(unittest.TestCase):
240
242
  self.assertEqual(7, exit_code)
241
243
  self.assertTrue(json.loads(status)["descendantsFound"])
242
244
 
243
- def test_natural_drain_uses_the_portable_supervision_bound(self):
245
+ def test_natural_drain_uses_the_windows_supervision_bound(self):
244
246
  self.assertEqual(
245
- NATURAL_DRAIN_GRACE_MILLISECONDS,
247
+ WINDOWS_NATURAL_DRAIN_GRACE_MILLISECONDS,
246
248
  _windows_job.NATURAL_DRAIN_GRACE_MILLISECONDS,
247
249
  )
248
250
 
@@ -350,6 +352,49 @@ class WindowsJobTests(unittest.TestCase):
350
352
 
351
353
  self.assertEqual([202, 201, 101], kernel32.closed_handles)
352
354
 
355
+ @unittest.skipUnless(os.name == "nt", "Windows Job Object integration")
356
+ def test_real_job_allows_a_short_lived_descendant_to_drain(self):
357
+ with tempfile.TemporaryDirectory() as directory:
358
+ root = Path(directory)
359
+ started = root / "started"
360
+ completed = root / "completed"
361
+ child = (
362
+ "from pathlib import Path; import sys, time; "
363
+ "Path(sys.argv[1]).write_text('started'); "
364
+ "time.sleep(1); Path(sys.argv[2]).write_text('completed')"
365
+ )
366
+ parent = (
367
+ "from pathlib import Path; import subprocess, sys, time; "
368
+ "subprocess.Popen([sys.executable, '-c', sys.argv[1], "
369
+ "sys.argv[2], sys.argv[3]]); "
370
+ "deadline=time.monotonic()+5; marker=Path(sys.argv[2]); "
371
+ "\nwhile not marker.exists() and time.monotonic() < deadline: "
372
+ "time.sleep(0.01)\n"
373
+ "raise SystemExit(0 if marker.exists() else 2)"
374
+ )
375
+
376
+ started_at = time.monotonic()
377
+ exit_code = _windows_job._run(
378
+ sys.executable,
379
+ [
380
+ sys.executable,
381
+ "-c",
382
+ parent,
383
+ child,
384
+ str(started),
385
+ str(completed),
386
+ ],
387
+ )
388
+ elapsed = time.monotonic() - started_at
389
+
390
+ self.assertEqual(0, exit_code)
391
+ self.assertTrue(completed.exists())
392
+ self.assertGreaterEqual(elapsed, 0.75)
393
+ self.assertLess(
394
+ elapsed,
395
+ WINDOWS_NATURAL_DRAIN_GRACE_MILLISECONDS / 1000 + 5,
396
+ )
397
+
353
398
  @unittest.skipUnless(os.name == "nt", "Windows Job Object integration")
354
399
  def test_real_job_terminates_a_descendant_left_by_the_target(self):
355
400
  with tempfile.TemporaryDirectory() as directory:
@@ -359,7 +404,7 @@ class WindowsJobTests(unittest.TestCase):
359
404
  child = (
360
405
  "from pathlib import Path; import sys, time; "
361
406
  "Path(sys.argv[1]).write_text('started'); "
362
- "time.sleep(1); Path(sys.argv[2]).write_text('survived')"
407
+ "time.sleep(30); Path(sys.argv[2]).write_text('survived')"
363
408
  )
364
409
  parent = (
365
410
  "from pathlib import Path; import subprocess, sys, time; "
@@ -387,7 +432,7 @@ class WindowsJobTests(unittest.TestCase):
387
432
  ]
388
433
  )
389
434
 
390
- time.sleep(1.25)
435
+ time.sleep(0.25)
391
436
  self.assertFalse(survived.exists())
392
437
 
393
438
 
@@ -1,138 +0,0 @@
1
- {
2
- "schemaVersion": 3,
3
- "previousVersion": "0.4.0",
4
- "version": "0.5.0",
5
- "classification": "minor",
6
- "compatibility": "incompatible",
7
- "schemaImpact": "breaking",
8
- "migration": "fail-on-verification-diagnostics: Fix canonical-command warnings/errors. Emit verification schema 3 and supplemental schema 2; retain verification 1/2 and supplemental 1 only as history. Never suppress or down-convert.; federated-process-improvement: Must adopt cross-repo-change; classify governed failures/findings; consumers await disposition, immutable release, exact reproduction. Released lifecycle/evidence readers retain historical meaning.; restore-pre-pr-review-invariant: Adopt publish-change and process-graph validation. Require host semantic review before completion, validated evidence before PR publication, and old-authority introduction before trust-root cutover.; standing-gated-automation: Install .process/automation.json. Keep provider automerge off before completion; emit proposal policy/evidence schema 2 for standing merge. Schema 1 remains human-only. Enable auto-merge/exact checks; escalate unavailable capability.",
9
- "identity": {
10
- "package": "engineering-process",
11
- "distribution": "engineering_process",
12
- "tag": "v0.5.0",
13
- "releaseName": "v0.5.0",
14
- "runtimeVersion": {
15
- "path": "engineering_process/__init__.py",
16
- "variable": "VERSION"
17
- },
18
- "artifacts": [
19
- "engineering_process-0.5.0-py3-none-any.whl",
20
- "engineering_process-0.5.0.tar.gz"
21
- ],
22
- "receiptAsset": "engineering-process-v0.5.0-evidence.json",
23
- "authorizationAsset": null
24
- },
25
- "provenance": {
26
- "mode": "governed",
27
- "statement": "The public N-1 lifecycle receipt and reviewed Release PR authorize this release.",
28
- "lifecycleReceipt": {
29
- "asset": "engineering-process-v0.5.0-evidence.json",
30
- "project": "engineering-process",
31
- "changeId": "release-0-5-0",
32
- "cycle": 1
33
- }
34
- },
35
- "changes": [
36
- {
37
- "id": "configure-release-push-credentials",
38
- "type": "fix",
39
- "surfaces": [
40
- "publication",
41
- "workflow"
42
- ],
43
- "rationale": "Configure GitHub CLI as Git's credential helper only in the final publication step so the short-lived App token can push the exact reviewed candidate without persistent checkout credentials or token-bearing URLs, headers, arguments, or config values."
44
- },
45
- {
46
- "id": "controlled-automation-proposals",
47
- "type": "capability",
48
- "surfaces": [
49
- "cli",
50
- "publication",
51
- "schema",
52
- "skills"
53
- ],
54
- "rationale": "Add an explicit strict-default policy contract for untrusted dependency proposals and an exact-head lifecycle-completion merge gate without granting proposal creation semantic or merge authority. Before enabling it, consumers must adopt the immutable capability release in a completed lifecycle, add the protected-base opt-in policy in a separate completed change, pin an immutable verifier, and require the canonical completion check."
55
- },
56
- {
57
- "id": "fail-on-verification-diagnostics",
58
- "type": "breaking",
59
- "surfaces": [
60
- "command-execution",
61
- "supplemental-verification",
62
- "verification-evidence"
63
- ],
64
- "rationale": "Process-owned commands now fail on classified warning or error diagnostics even when the child exits zero, and current verification and supplemental evidence require redacted diagnostic summaries."
65
- },
66
- {
67
- "id": "federated-process-improvement",
68
- "type": "breaking",
69
- "surfaces": [
70
- "cli",
71
- "governance",
72
- "lifecycle",
73
- "schema",
74
- "skills"
75
- ],
76
- "rationale": "Make evolve-process the mandatory owner of improvement-required, route shared consumer cases through improvement-pending, add a transport-neutral signal/disposition/resolution/reproduction chain and producer recurrence catalog, and block verification, completion, and publication until the applicable local or federated proof is explicit."
77
- },
78
- {
79
- "id": "fix-windows-verification-boundary",
80
- "type": "fix",
81
- "surfaces": [
82
- "command-execution",
83
- "verification"
84
- ],
85
- "rationale": "Propagate typed Windows descendant-cleanup results through a private bounded helper channel, route the public-action installer and N+1 standalone adoption runner through the current protocol, and make every managed producer test fixture independent of inherited Git line-ending conversion policy."
86
- },
87
- {
88
- "id": "preserve-release-generator-outputs",
89
- "type": "fix",
90
- "surfaces": [
91
- "publication",
92
- "workflow"
93
- ],
94
- "rationale": "Commit every deterministic prepare-release output, declare the complete generated path set in the release lifecycle plan, and fail before bundling when tracked, staged, or untracked candidate residue remains."
95
- },
96
- {
97
- "id": "recover-published-release-evidence",
98
- "type": "fix",
99
- "surfaces": [
100
- "publication",
101
- "workflow"
102
- ],
103
- "rationale": "Keep the exact pre-publication completion artifact as the primary release evidence source, but let recovery of an already published immutable release restore the same declared evidence asset when that ephemeral artifact is absent; draft, mutable, incomplete, or invalid releases still fail closed."
104
- },
105
- {
106
- "id": "restore-pre-pr-review-invariant",
107
- "type": "breaking",
108
- "surfaces": [
109
- "cli",
110
- "distribution",
111
- "skills",
112
- "workflow"
113
- ],
114
- "rationale": "Restore semantic checkpoint review before PR publication, prevent static checks from fabricating approval, make publication a mandatory core skill, add a runtime-bound process graph, and define safe self-hosted authority rotation."
115
- },
116
- {
117
- "id": "separate-release-comparison-bases",
118
- "type": "fix",
119
- "surfaces": [
120
- "publication",
121
- "workflow"
122
- ],
123
- "rationale": "Validate the candidate's immediate protected-main parent against source publication while independently validating completion evidence against the previous-release comparison base owned by the generated lifecycle contract."
124
- },
125
- {
126
- "id": "standing-gated-automation",
127
- "type": "breaking",
128
- "surfaces": [
129
- "governance",
130
- "publication",
131
- "schema",
132
- "skills",
133
- "workflow"
134
- ],
135
- "rationale": "Replace the hard-coded human-only merge terminal with project-owned standing authorization for every routine post-gate operation, including exact-head merge, release, deployment, adoption, and ephemeral cleanup; escalation is limited to unavailable capability, exhausted bounded recovery, or a missing material decision."
136
- }
137
- ]
138
- }