engineering-process 0.1.0__tar.gz → 0.1.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 (91) hide show
  1. {engineering_process-0.1.0 → engineering_process-0.1.1}/PKG-INFO +2 -2
  2. {engineering_process-0.1.0 → engineering_process-0.1.1}/README.md +1 -1
  3. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/__init__.py +1 -1
  4. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/tooling.py +18 -1
  5. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/PKG-INFO +2 -2
  6. {engineering_process-0.1.0 → engineering_process-0.1.1}/pyproject.toml +1 -1
  7. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_tooling.py +68 -0
  8. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/assess-design/SKILL.md +0 -0
  9. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/build-frontend/SKILL.md +0 -0
  10. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/build-frontend-foundation/SKILL.md +0 -0
  11. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/change-api/SKILL.md +0 -0
  12. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/cross-repo-change/SKILL.md +0 -0
  13. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/define-change-contract/SKILL.md +0 -0
  14. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/design-module/SKILL.md +0 -0
  15. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/evolve-process/SKILL.md +0 -0
  16. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/finish-change/SKILL.md +0 -0
  17. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/govern-ui/SKILL.md +0 -0
  18. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/implement-change/SKILL.md +0 -0
  19. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/implement-module/SKILL.md +0 -0
  20. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/implement-use-case/SKILL.md +0 -0
  21. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/integrate-mcp/SKILL.md +0 -0
  22. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/maintain-docs/SKILL.md +0 -0
  23. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/plan-change/SKILL.md +0 -0
  24. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/publish-change/SKILL.md +0 -0
  25. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/review-change/SKILL.md +0 -0
  26. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/run-change/SKILL.md +0 -0
  27. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/run-change/references/execution.md +0 -0
  28. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/run-project-command/SKILL.md +0 -0
  29. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/specify-use-case/SKILL.md +0 -0
  30. {engineering_process-0.1.0 → engineering_process-0.1.1}/.agents/skills/verify-change/SKILL.md +0 -0
  31. {engineering_process-0.1.0 → engineering_process-0.1.1}/LICENSE +0 -0
  32. {engineering_process-0.1.0 → engineering_process-0.1.1}/bundles.json +0 -0
  33. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/_download_worker.py +0 -0
  34. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/_supervisor_posix.py +0 -0
  35. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/_supervisor_windows.py +0 -0
  36. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/_windows_job.py +0 -0
  37. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/bootstrap.py +0 -0
  38. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/bundles.py +0 -0
  39. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/cli.py +0 -0
  40. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/contracts.py +0 -0
  41. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/distribution.py +0 -0
  42. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/environment.py +0 -0
  43. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/helper_launch.py +0 -0
  44. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/lifecycle.py +0 -0
  45. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/managed.py +0 -0
  46. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/markdown.py +0 -0
  47. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/publication.py +0 -0
  48. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/requirements-build.txt +0 -0
  49. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/requirements-dev.txt +0 -0
  50. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/requirements-runtime.txt +0 -0
  51. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/runner.py +0 -0
  52. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/runtime.py +0 -0
  53. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/skills.py +0 -0
  54. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/supervision.py +0 -0
  55. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process/syncing.py +0 -0
  56. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/SOURCES.txt +0 -0
  57. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/dependency_links.txt +0 -0
  58. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/entry_points.txt +0 -0
  59. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/requires.txt +0 -0
  60. {engineering_process-0.1.0 → engineering_process-0.1.1}/engineering_process.egg-info/top_level.txt +0 -0
  61. {engineering_process-0.1.0 → engineering_process-0.1.1}/examples/change.json +0 -0
  62. {engineering_process-0.1.0 → engineering_process-0.1.1}/examples/plan.json +0 -0
  63. {engineering_process-0.1.0 → engineering_process-0.1.1}/examples/project.json +0 -0
  64. {engineering_process-0.1.0 → engineering_process-0.1.1}/examples/review.json +0 -0
  65. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/change.schema.json +0 -0
  66. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/lifecycle.schema.json +0 -0
  67. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/plan.schema.json +0 -0
  68. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/process-lock.schema.json +0 -0
  69. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/project.schema.json +0 -0
  70. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/review.schema.json +0 -0
  71. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/reviewer-attestation.schema.json +0 -0
  72. {engineering_process-0.1.0 → engineering_process-0.1.1}/schemas/verification.schema.json +0 -0
  73. {engineering_process-0.1.0 → engineering_process-0.1.1}/setup.cfg +0 -0
  74. {engineering_process-0.1.0 → engineering_process-0.1.1}/templates/AGENTS.process.md +0 -0
  75. {engineering_process-0.1.0 → engineering_process-0.1.1}/templates/PULL_REQUEST_TEMPLATE.md +0 -0
  76. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_bootstrap.py +0 -0
  77. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_bundles.py +0 -0
  78. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_cli.py +0 -0
  79. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_contracts.py +0 -0
  80. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_distribution.py +0 -0
  81. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_environment.py +0 -0
  82. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_evals.py +0 -0
  83. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_lifecycle.py +0 -0
  84. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_publication.py +0 -0
  85. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_runner.py +0 -0
  86. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_runtime.py +0 -0
  87. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_schemas.py +0 -0
  88. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_skills.py +0 -0
  89. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_supervision.py +0 -0
  90. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_syncing.py +0 -0
  91. {engineering_process-0.1.0 → engineering_process-0.1.1}/tests/test_windows_job.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-process
3
- Version: 0.1.0
3
+ Version: 0.1.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
@@ -105,7 +105,7 @@ Install `processctl` from a tagged release and create a candidate manifest from
105
105
  standard in one command:
106
106
 
107
107
  ~~~text
108
- python -m pip install "engineering-process==0.1.0"
108
+ python -m pip install "engineering-process==0.1.1"
109
109
  processctl project init --project-root . --manifest project.json \
110
110
  --bundle core --bundle delivery --bundle product
111
111
  processctl doctor --project-root .
@@ -70,7 +70,7 @@ Install `processctl` from a tagged release and create a candidate manifest from
70
70
  standard in one command:
71
71
 
72
72
  ~~~text
73
- python -m pip install "engineering-process==0.1.0"
73
+ python -m pip install "engineering-process==0.1.1"
74
74
  processctl project init --project-root . --manifest project.json \
75
75
  --bundle core --bundle delivery --bundle product
76
76
  processctl doctor --project-root .
@@ -1,3 +1,3 @@
1
1
  """Agent-neutral engineering process."""
2
2
 
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
@@ -19,13 +19,14 @@ import urllib.request
19
19
  from urllib.parse import urljoin, urlsplit
20
20
  import zipfile
21
21
 
22
+ from . import VERSION
22
23
  from .contracts import ContractError, ManagedTool, ManagedToolArtifact
23
24
  from .helper_launch import isolated_helper_command
24
25
 
25
26
 
26
27
  DOWNLOAD_READ_TIMEOUT_SECONDS = 30
27
28
  MARKER_NAME = ".engineering-process-tool.json"
28
- USER_AGENT = "engineering-process/0.1.0"
29
+ USER_AGENT = f"engineering-process/{VERSION}"
29
30
 
30
31
 
31
32
  @dataclass(frozen=True)
@@ -340,6 +341,15 @@ def _set_response_read_timeout(response: object, timeout: float) -> None:
340
341
  raise ContractError(f"cannot update the managed download timeout: {error}") from error
341
342
 
342
343
 
344
+ def _response_is_closed(response: object) -> bool:
345
+ """Report a consumed HTTP response without depending on its private socket."""
346
+
347
+ is_closed = getattr(response, "isclosed", None)
348
+ if callable(is_closed):
349
+ return bool(is_closed())
350
+ return bool(getattr(response, "closed", False))
351
+
352
+
343
353
  def _download_artifact_direct(
344
354
  artifact: ManagedToolArtifact,
345
355
  destination: Path,
@@ -353,11 +363,14 @@ def _download_artifact_direct(
353
363
  ) as response:
354
364
  _validated_https_target(artifact.url, response.geturl())
355
365
  content_length = response.headers.get("Content-Length")
366
+ declared_size = None
356
367
  if content_length is not None:
357
368
  try:
358
369
  declared_size = int(content_length)
359
370
  except ValueError as error:
360
371
  raise ContractError("tool response has an invalid Content-Length") from error
372
+ if declared_size < 0:
373
+ raise ContractError("tool response has an invalid Content-Length")
361
374
  if declared_size > artifact.max_download_bytes:
362
375
  raise ContractError(
363
376
  f"tool artifact exceeds maxDownloadBytes: {declared_size} > "
@@ -367,6 +380,10 @@ def _download_artifact_direct(
367
380
  total = 0
368
381
  with destination.open("xb") as output:
369
382
  while True:
383
+ if declared_size is not None and total == declared_size:
384
+ break
385
+ if _response_is_closed(response):
386
+ break
370
387
  _set_response_read_timeout(
371
388
  response,
372
389
  min(DOWNLOAD_READ_TIMEOUT_SECONDS, _remaining(deadline)),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: engineering-process
3
- Version: 0.1.0
3
+ Version: 0.1.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
@@ -105,7 +105,7 @@ Install `processctl` from a tagged release and create a candidate manifest from
105
105
  standard in one command:
106
106
 
107
107
  ~~~text
108
- python -m pip install "engineering-process==0.1.0"
108
+ python -m pip install "engineering-process==0.1.1"
109
109
  processctl project init --project-root . --manifest project.json \
110
110
  --bundle core --bundle delivery --bundle product
111
111
  processctl doctor --project-root .
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "engineering-process"
7
- version = "0.1.0"
7
+ version = "0.1.1"
8
8
  description = "Agent-neutral end-to-end engineering lifecycle and deterministic process CLI"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -162,6 +162,74 @@ class ManagedToolTests(unittest.TestCase):
162
162
  self.assertEqual(b"payload", destination.read_bytes())
163
163
  self.assertEqual([0.25, 0.1], response.socket.timeouts)
164
164
 
165
+ def test_download_does_not_touch_socket_after_content_length_closes_response(self):
166
+ class Socket:
167
+ def __init__(self):
168
+ self.timeouts = []
169
+
170
+ def settimeout(self, value):
171
+ self.timeouts.append(value)
172
+
173
+ class Raw:
174
+ def __init__(self, active_socket):
175
+ self._sock = active_socket
176
+
177
+ class Stream:
178
+ def __init__(self, active_socket):
179
+ self.raw = Raw(active_socket)
180
+
181
+ class Response:
182
+ def __init__(self):
183
+ self.socket = Socket()
184
+ self.fp = Stream(self.socket)
185
+ self.headers = {"Content-Length": "7"}
186
+
187
+ def __enter__(self):
188
+ return self
189
+
190
+ def __exit__(self, *unused):
191
+ return False
192
+
193
+ def geturl(self):
194
+ return "https://downloads.example.test/sample"
195
+
196
+ def isclosed(self):
197
+ return self.fp is None
198
+
199
+ def read(self, size):
200
+ del size
201
+ self.fp = None
202
+ return b"payload"
203
+
204
+ artifact = ManagedToolArtifact(
205
+ platform="linux-glibc-x64",
206
+ url="https://downloads.example.test/sample",
207
+ checksum=f"sha256:{'0' * 64}",
208
+ archive_format="file",
209
+ strip_components=0,
210
+ max_download_bytes=100,
211
+ max_extracted_bytes=100,
212
+ max_files=1,
213
+ commands={"sample": ManagedCommand("sample", None)},
214
+ )
215
+ response = Response()
216
+ with tempfile.TemporaryDirectory() as directory:
217
+ destination = Path(directory) / "artifact"
218
+ with (
219
+ patch(
220
+ "engineering_process.tooling._HTTPS_OPENER.open",
221
+ return_value=response,
222
+ ),
223
+ patch(
224
+ "engineering_process.tooling._remaining",
225
+ side_effect=[10.0, 0.25],
226
+ ),
227
+ ):
228
+ _download_artifact_direct(artifact, destination, deadline=123.0)
229
+
230
+ self.assertEqual(b"payload", destination.read_bytes())
231
+ self.assertEqual([0.25], response.socket.timeouts)
232
+
165
233
  def test_download_worker_is_force_terminated_at_the_wall_clock_deadline(self):
166
234
  artifact = ManagedToolArtifact(
167
235
  platform="linux-glibc-x64",