engineering-process 1.2.1__tar.gz → 1.2.3__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.
- {engineering_process-1.2.1/engineering_process.egg-info → engineering_process-1.2.3}/PKG-INFO +5 -1
- {engineering_process-1.2.1 → engineering_process-1.2.3}/README.md +4 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/__init__.py +1 -1
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/publication_compat.py +6 -1
- {engineering_process-1.2.1 → engineering_process-1.2.3/engineering_process.egg-info}/PKG-INFO +5 -1
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/SOURCES.txt +1 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/finish-change/SKILL.md +6 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/pyproject.toml +1 -1
- {engineering_process-1.2.1 → engineering_process-1.2.3}/templates/PULL_REQUEST_TEMPLATE.md +2 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_automation.py +29 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_publication_compat.py +36 -0
- engineering_process-1.2.3/tests/test_pypi_cache_horizon.py +81 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_skills.py +2 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/LICENSE +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/MANIFEST.in +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/__main__.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_contract.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_posix.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_windows.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_windows_job.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/adoption.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/cli.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/commands.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/contracts.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/distribution.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/helper_launch.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/lifecycle.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/production_engineering.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/project.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/release.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/repository.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/requirements-dev.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/requirements-runtime.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/skills.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/supervision.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/dependency_links.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/entry_points.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/requires.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/top_level.txt +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process-graph.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/implement-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/improve-process/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/plan-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/production-engineering/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/production-engineering/invariants.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/review-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/run-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/start-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/verify-change/SKILL.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/change.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/plan.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/process-graph.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/process-lock.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/production-engineering.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/project-legacy.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/project.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/receipt.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/release-change.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/release.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/review.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/run.schema.json +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/setup.cfg +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/templates/AGENTS.process.md +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/templates/adopt-process-windows-job.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/templates/adopt-process.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_adoption.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_architecture.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_cli.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_commands.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_contracts.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_distribution.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_lifecycle.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_production_engineering.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_release.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_repository.py +0 -0
- {engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_supervisor_posix.py +0 -0
{engineering_process-1.2.1/engineering_process.egg-info → engineering_process-1.2.3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: engineering-process
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: A small agent-neutral engineering lifecycle with managed adoption
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/phuongnse/engineering-process
|
|
@@ -422,6 +422,10 @@ review identities.
|
|
|
422
422
|
It rejects missing, repeated, misplaced, hidden, unordered, or unsupported visible
|
|
423
423
|
structure. Completion checkboxes belong only to the Completion gate section. Ready
|
|
424
424
|
pull requests must have every checkbox checked; drafts may retain unchecked work.
|
|
425
|
+
One trailing `Refs ISSUE.` line remains optional. A ready, contract-identified final
|
|
426
|
+
consumer adoption may instead use `Closes ISSUE, closes OWNER/REPOSITORY#NUMBER.` with
|
|
427
|
+
the complete keyword/reference syntax repeated for every issue; drafts cannot close
|
|
428
|
+
issues. Producer and intermediate pull requests do not close release-source issues.
|
|
425
429
|
The managed template never solicits execution identity,
|
|
426
430
|
and authors plus independent review keep it out of free-form values. The validator is
|
|
427
431
|
a positive grammar for public fields; it deliberately does not guess identities from
|
|
@@ -398,6 +398,10 @@ review identities.
|
|
|
398
398
|
It rejects missing, repeated, misplaced, hidden, unordered, or unsupported visible
|
|
399
399
|
structure. Completion checkboxes belong only to the Completion gate section. Ready
|
|
400
400
|
pull requests must have every checkbox checked; drafts may retain unchecked work.
|
|
401
|
+
One trailing `Refs ISSUE.` line remains optional. A ready, contract-identified final
|
|
402
|
+
consumer adoption may instead use `Closes ISSUE, closes OWNER/REPOSITORY#NUMBER.` with
|
|
403
|
+
the complete keyword/reference syntax repeated for every issue; drafts cannot close
|
|
404
|
+
issues. Producer and intermediate pull requests do not close release-source issues.
|
|
401
405
|
The managed template never solicits execution identity,
|
|
402
406
|
and authors plus independent review keep it out of free-form values. The validator is
|
|
403
407
|
a positive grammar for public fields; it deliberately does not guess identities from
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/publication_compat.py
RENAMED
|
@@ -53,8 +53,9 @@ PR_CHECKS = (
|
|
|
53
53
|
)
|
|
54
54
|
FENCE = re.compile(r"^ {0,3}(`{3,}|~{3,})(.*)$")
|
|
55
55
|
NON_MARKDOWN_LINE_SEPARATOR = re.compile("[\v\f\x85\u2028\u2029]")
|
|
56
|
+
ISSUE_TARGET = r"(?:[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+)?#[1-9][0-9]*"
|
|
56
57
|
ISSUE_REFERENCE = re.compile(
|
|
57
|
-
|
|
58
|
+
rf"^(?:Refs {ISSUE_TARGET}|Closes {ISSUE_TARGET}(?:, closes {ISSUE_TARGET})*)\.$"
|
|
58
59
|
)
|
|
59
60
|
|
|
60
61
|
|
|
@@ -232,6 +233,10 @@ def _pull_request_body_issues(body: str, state: str) -> list[str]:
|
|
|
232
233
|
and reference_positions[0] <= checklist_positions[-1]
|
|
233
234
|
):
|
|
234
235
|
issues.append("pull request body issue reference must follow the checklist")
|
|
236
|
+
if state == "draft" and any(
|
|
237
|
+
lines[position].startswith("Closes ") for position in reference_positions
|
|
238
|
+
):
|
|
239
|
+
issues.append("draft pull request cannot close issues")
|
|
235
240
|
field_patterns = tuple(
|
|
236
241
|
re.compile(rf"^- {re.escape(field)}:\s*.*$")
|
|
237
242
|
for fields in PR_FIELDS.values()
|
{engineering_process-1.2.1 → engineering_process-1.2.3/engineering_process.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: engineering-process
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: A small agent-neutral engineering lifecycle with managed adoption
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/phuongnse/engineering-process
|
|
@@ -422,6 +422,10 @@ review identities.
|
|
|
422
422
|
It rejects missing, repeated, misplaced, hidden, unordered, or unsupported visible
|
|
423
423
|
structure. Completion checkboxes belong only to the Completion gate section. Ready
|
|
424
424
|
pull requests must have every checkbox checked; drafts may retain unchecked work.
|
|
425
|
+
One trailing `Refs ISSUE.` line remains optional. A ready, contract-identified final
|
|
426
|
+
consumer adoption may instead use `Closes ISSUE, closes OWNER/REPOSITORY#NUMBER.` with
|
|
427
|
+
the complete keyword/reference syntax repeated for every issue; drafts cannot close
|
|
428
|
+
issues. Producer and intermediate pull requests do not close release-source issues.
|
|
425
429
|
The managed template never solicits execution identity,
|
|
426
430
|
and authors plus independent review keep it out of free-form values. The validator is
|
|
427
431
|
a positive grammar for public fields; it deliberately does not guess identities from
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/finish-change/SKILL.md
RENAMED
|
@@ -15,6 +15,12 @@ The command writes one bounded completion receipt and marks the run completed.
|
|
|
15
15
|
Completion does not itself grant merge, deployment, or release authority; those
|
|
16
16
|
remain project-owned operations. Never report completion from prose alone.
|
|
17
17
|
|
|
18
|
+
Use a normal trailing `Refs ISSUE.` line for producer and intermediate pull requests.
|
|
19
|
+
Only a contract-identified final consumer adoption that has verified the released
|
|
20
|
+
behavior may use `Closes ISSUE, closes ISSUE.` after the completed public checklist.
|
|
21
|
+
Repeat the full keyword and local or `OWNER/REPOSITORY#NUMBER` reference for every
|
|
22
|
+
issue; never close source issues merely because the producer release merged.
|
|
23
|
+
|
|
18
24
|
Report the readiness capabilities protected or advanced and the remaining planned
|
|
19
25
|
gaps after completion. Carry the owner and stable record URL for every accepted-risk
|
|
20
26
|
or tracked-follow-up disposition into the durable handoff. Finish never edits
|
|
@@ -34,4 +34,6 @@ tracked-follow-up entries need an owner and durable HTTPS record. -->
|
|
|
34
34
|
- [ ] Required profiles pass on the reviewed snapshot.
|
|
35
35
|
- [ ] Independent review approved with no blocking finding.
|
|
36
36
|
- [ ] Every non-blocking finding has a recorded disposition.
|
|
37
|
+
<!-- Producer/intermediate PR: Refs ISSUE. Final verified consumer adoption only:
|
|
38
|
+
Closes ISSUE, closes OWNER/REPOSITORY#NUMBER. Repeat the keyword for every issue. -->
|
|
37
39
|
<!-- engineering-process:pr-description:end -->
|
|
@@ -55,6 +55,8 @@ class AutomationTests(unittest.TestCase):
|
|
|
55
55
|
template.index("## Completion gate"),
|
|
56
56
|
)
|
|
57
57
|
self.assertIn("Every non-blocking finding has a recorded disposition.", template)
|
|
58
|
+
self.assertIn("Final verified consumer adoption only", template)
|
|
59
|
+
self.assertIn("Closes ISSUE, closes OWNER/REPOSITORY#NUMBER", template)
|
|
58
60
|
|
|
59
61
|
def test_renovate_process_rule_materializes_the_complete_adoption(self) -> None:
|
|
60
62
|
config = json.loads((ROOT / ".github" / "renovate.json").read_text(encoding="utf-8"))
|
|
@@ -103,6 +105,31 @@ class AutomationTests(unittest.TestCase):
|
|
|
103
105
|
" dispatch-adoption:\n name: Dispatch consumer adoption\n", workflow
|
|
104
106
|
)
|
|
105
107
|
self.assertIn("needs: [metadata, publish]", workflow)
|
|
108
|
+
dispatch_job = workflow.split("\n dispatch-adoption:\n", maxsplit=1)[1]
|
|
109
|
+
self.assertIn(" timeout-minutes: 20\n", dispatch_job)
|
|
110
|
+
cache_wait = dispatch_job.split(
|
|
111
|
+
" - name: Wait for consumer Simple caches to expire\n", maxsplit=1
|
|
112
|
+
)[1].split(
|
|
113
|
+
" - name: Create short-lived Renovate event token\n", maxsplit=1
|
|
114
|
+
)[0]
|
|
115
|
+
self.assertIn(
|
|
116
|
+
"python verification/wait_for_pypi_cache_horizon.py",
|
|
117
|
+
cache_wait,
|
|
118
|
+
)
|
|
119
|
+
self.assertIn("${{ steps.release.outputs.published_at }}", cache_wait)
|
|
120
|
+
self.assertIn(
|
|
121
|
+
"ref: ${{ github.sha }}",
|
|
122
|
+
dispatch_job,
|
|
123
|
+
)
|
|
124
|
+
self.assertNotIn("ref: ${{ needs.metadata.outputs.source_sha }}", dispatch_job)
|
|
125
|
+
self.assertIn(
|
|
126
|
+
'published_at=$(gh release view "$RELEASE_TAG"',
|
|
127
|
+
dispatch_job,
|
|
128
|
+
)
|
|
129
|
+
self.assertLess(
|
|
130
|
+
dispatch_job.index(" - name: Bind the published distribution\n"),
|
|
131
|
+
dispatch_job.index(" - name: Wait for consumer Simple caches to expire\n"),
|
|
132
|
+
)
|
|
106
133
|
self.assertIn("Verify PyPI exposes the exact built hashes", workflow)
|
|
107
134
|
visibility = workflow.split(
|
|
108
135
|
" - name: Verify PyPI exposes the exact built hashes\n", maxsplit=1
|
|
@@ -140,6 +167,8 @@ class AutomationTests(unittest.TestCase):
|
|
|
140
167
|
publish_job = workflow.split(" publish:\n", maxsplit=1)[1].split(
|
|
141
168
|
"\n dispatch-adoption:\n", maxsplit=1
|
|
142
169
|
)[0]
|
|
170
|
+
self.assertIn("ref: ${{ needs.metadata.outputs.source_sha }}", publish_job)
|
|
171
|
+
self.assertNotIn("ref: ${{ github.sha }}", publish_job)
|
|
143
172
|
self.assertIn("id: release-token", publish_job)
|
|
144
173
|
self.assertIn("repositories: engineering-process", publish_job)
|
|
145
174
|
self.assertIn("permission-contents: write", publish_job)
|
|
@@ -290,6 +290,42 @@ class PublicationCompatibilityTests(unittest.TestCase):
|
|
|
290
290
|
self.validate_body(repeated),
|
|
291
291
|
)
|
|
292
292
|
|
|
293
|
+
def test_final_adoption_can_close_multiple_issues_only_when_ready(self) -> None:
|
|
294
|
+
closing = (
|
|
295
|
+
f"{CANONICAL_BODY}\n"
|
|
296
|
+
"Closes example/process#123, closes #456, closes other/repository#789.\n"
|
|
297
|
+
)
|
|
298
|
+
self.assertEqual([], self.validate_body(closing))
|
|
299
|
+
self.assertIn(
|
|
300
|
+
"draft pull request cannot close issues",
|
|
301
|
+
self.validate_body(closing, state="draft"),
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
unchecked = closing.replace(
|
|
305
|
+
"- [x] Required profiles", "- [ ] Required profiles", 1
|
|
306
|
+
)
|
|
307
|
+
self.assertIn(
|
|
308
|
+
"ready pull request has unchecked item: Required profiles pass on the reviewed snapshot.",
|
|
309
|
+
self.validate_body(unchecked),
|
|
310
|
+
)
|
|
311
|
+
|
|
312
|
+
for malformed in (
|
|
313
|
+
"Closes example/process#123, #456.",
|
|
314
|
+
"Closes example/process#123, Closes #456.",
|
|
315
|
+
"Fixes example/process#123.",
|
|
316
|
+
"Closes example/process#0.",
|
|
317
|
+
):
|
|
318
|
+
with self.subTest(malformed=malformed):
|
|
319
|
+
issues = self.validate_body(f"{CANONICAL_BODY}\n{malformed}\n")
|
|
320
|
+
self.assertTrue(
|
|
321
|
+
any(
|
|
322
|
+
issue.startswith(
|
|
323
|
+
"pull request body has unsupported visible content at line "
|
|
324
|
+
)
|
|
325
|
+
for issue in issues
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
|
|
293
329
|
def test_pull_request_ignores_template_comments(self) -> None:
|
|
294
330
|
body = CANONICAL_BODY.replace(
|
|
295
331
|
"- Outcome: Preserve the requested behavior.",
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from datetime import datetime, timezone
|
|
2
|
+
from email.message import Message
|
|
3
|
+
import unittest
|
|
4
|
+
from unittest.mock import patch
|
|
5
|
+
|
|
6
|
+
from verification.wait_for_pypi_cache_horizon import (
|
|
7
|
+
MAX_SIMPLE_CACHE_SECONDS,
|
|
8
|
+
read_simple_max_age,
|
|
9
|
+
parse_max_age,
|
|
10
|
+
remaining_seconds,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class _Response:
|
|
15
|
+
def __init__(self, headers: Message) -> None:
|
|
16
|
+
self.headers = headers
|
|
17
|
+
|
|
18
|
+
def __enter__(self) -> "_Response":
|
|
19
|
+
return self
|
|
20
|
+
|
|
21
|
+
def __exit__(self, *args: object) -> None:
|
|
22
|
+
return None
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PyPICacheHorizonTests(unittest.TestCase):
|
|
26
|
+
NOW = datetime(2026, 9, 4, 13, 30, tzinfo=timezone.utc)
|
|
27
|
+
|
|
28
|
+
def test_parses_current_bounded_header(self) -> None:
|
|
29
|
+
self.assertEqual(600, parse_max_age(["max-age=600, public"]))
|
|
30
|
+
self.assertEqual(
|
|
31
|
+
MAX_SIMPLE_CACHE_SECONDS,
|
|
32
|
+
parse_max_age([f"public, max-age={MAX_SIMPLE_CACHE_SECONDS}"]),
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def test_rejects_missing_duplicate_malformed_and_excessive_max_age(self) -> None:
|
|
36
|
+
invalid = [
|
|
37
|
+
None,
|
|
38
|
+
["public"],
|
|
39
|
+
["max-age=600", "max-age=300"],
|
|
40
|
+
["max-age=-1"],
|
|
41
|
+
["max-age=invalid"],
|
|
42
|
+
[f"max-age={MAX_SIMPLE_CACHE_SECONDS + 1}"],
|
|
43
|
+
]
|
|
44
|
+
for values in invalid:
|
|
45
|
+
with self.subTest(values=values), self.assertRaises(RuntimeError):
|
|
46
|
+
parse_max_age(values)
|
|
47
|
+
|
|
48
|
+
def test_reads_every_cache_control_field(self) -> None:
|
|
49
|
+
headers = Message()
|
|
50
|
+
headers["Content-Type"] = "application/vnd.pypi.simple.v1+json"
|
|
51
|
+
headers["Cache-Control"] = "public, max-age=600"
|
|
52
|
+
headers["Cache-Control"] = "max-age=300"
|
|
53
|
+
with patch(
|
|
54
|
+
"verification.wait_for_pypi_cache_horizon.urlopen",
|
|
55
|
+
return_value=_Response(headers),
|
|
56
|
+
), self.assertRaises(RuntimeError):
|
|
57
|
+
read_simple_max_age()
|
|
58
|
+
|
|
59
|
+
def test_current_horizon_and_elapsed_resume(self) -> None:
|
|
60
|
+
self.assertEqual(
|
|
61
|
+
305,
|
|
62
|
+
remaining_seconds("2026-09-04T13:20:00Z", 900, now=self.NOW),
|
|
63
|
+
)
|
|
64
|
+
self.assertEqual(
|
|
65
|
+
0,
|
|
66
|
+
remaining_seconds("2026-09-04T13:00:00Z", 600, now=self.NOW),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def test_rejects_malformed_naive_and_future_timestamps(self) -> None:
|
|
70
|
+
invalid = [
|
|
71
|
+
"invalid",
|
|
72
|
+
"2026-09-04T13:20:00",
|
|
73
|
+
"2026-09-04T13:31:01Z",
|
|
74
|
+
]
|
|
75
|
+
for published_at in invalid:
|
|
76
|
+
with self.subTest(published_at=published_at), self.assertRaises(RuntimeError):
|
|
77
|
+
remaining_seconds(published_at, 600, now=self.NOW)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
unittest.main()
|
|
@@ -78,6 +78,8 @@ class SkillTests(unittest.TestCase):
|
|
|
78
78
|
"Finish never edits\nreadiness",
|
|
79
79
|
"remaining planned\ngaps",
|
|
80
80
|
"owner and stable record URL",
|
|
81
|
+
"contract-identified final consumer adoption",
|
|
82
|
+
"Closes ISSUE, closes ISSUE",
|
|
81
83
|
),
|
|
82
84
|
"improve-process": (
|
|
83
85
|
"new immutable pack version",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_contract.py
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_posix.py
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/_supervisor_windows.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/helper_launch.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/requirements-dev.txt
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process/requirements-runtime.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/requires.txt
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/engineering_process.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/plan-change/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/review-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/run-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/start-change/SKILL.md
RENAMED
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/process_assets/skills/verify-change/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/schemas/production-engineering.schema.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/templates/adopt-process-windows-job.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{engineering_process-1.2.1 → engineering_process-1.2.3}/tests/test_production_engineering.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|