Skip to content

Commit a088290

Browse files
author
CometAPI
committed
fix: make release gates deterministic
1 parent 7857adb commit a088290

26 files changed

Lines changed: 3087 additions & 885 deletions

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ body:
3838
attributes:
3939
label: Versions
4040
description: Provide Python, cometapi, and openai versions.
41-
placeholder: "Python 3.13; cometapi 0.1.0a1; openai 2.45.0"
41+
placeholder: "Python 3.13; cometapi <installed version>; openai 2.45.0"
4242
validations:
4343
required: true
4444
- type: input

.github/workflows/ci.yml

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ jobs:
4444
run: uv run pyright
4545
- name: Run offline unit and contract tests
4646
run: uv run pytest -m "not live"
47+
- name: Select latest OpenAI within the supported major
48+
run: uv pip install --python .venv/bin/python --upgrade "openai>=2.45.0,<3.0.0"
49+
- name: Run latest-within-major tests without resyncing the lock
50+
run: uv run --no-sync pytest -m "not live"
4751
- name: Check version agreement and durable public content
4852
run: uv run python scripts/check_version.py --require-changelog --require-public-preview-docs
4953
- name: Scan for credentials and scope mistakes
@@ -95,27 +99,6 @@ jobs:
9599
- name: Run offline tests without resyncing the lock
96100
run: uv run --no-sync pytest -m "not live"
97101

98-
latest-openai:
99-
name: Latest OpenAI within major canary
100-
if: github.event_name == 'schedule' || github.actor == 'dependabot[bot]'
101-
runs-on: ubuntu-latest
102-
timeout-minutes: 20
103-
steps:
104-
- name: Check out the candidate
105-
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
106-
- name: Set up Python
107-
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
108-
with:
109-
python-version: "3.14"
110-
- name: Install the pinned uv frontend
111-
run: python -m pip install --disable-pip-version-check "uv==$UV_VERSION"
112-
- name: Create the development environment
113-
run: uv sync --locked
114-
- name: Select latest OpenAI within the supported major
115-
run: uv pip install --python .venv/bin/python --upgrade "openai>=2.45.0,<3.0.0"
116-
- name: Run canary tests without resyncing the lock
117-
run: uv run --no-sync pytest -m "not live"
118-
119102
package:
120103
name: Build, inspect, and clean-install exact artifacts
121104
needs: [quality, locked-runtime, minimum-openai]

.github/workflows/live-smoke.yml

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ on:
44
schedule:
55
- cron: "17 3 * * *"
66
workflow_dispatch:
7+
inputs:
8+
max_output_tokens:
9+
description: Maximum output tokens for each bounded live request
10+
required: true
11+
default: "64"
12+
type: choice
13+
options:
14+
- "64"
15+
- "128"
16+
- "256"
717

818
permissions:
919
contents: read
@@ -15,8 +25,8 @@ concurrency:
1525
env:
1626
UV_VERSION: 0.11.8
1727
COMETAPI_LIVE_MAX_REQUESTS: "4"
18-
COMETAPI_LIVE_MAX_OUTPUT_TOKENS: "16"
19-
COMETAPI_LIVE_MODEL: gpt-5.4
28+
COMETAPI_LIVE_MAX_OUTPUT_TOKENS: ${{ inputs.max_output_tokens || '64' }}
29+
COMETAPI_LIVE_MODEL: gpt-5.6-sol
2030
COMETAPI_LIVE_REQUEST_TIMEOUT_SECONDS: "30"
2131
COMETAPI_LIVE_CONCURRENCY: "1"
2232
COMETAPI_LIVE_RUN: "1"

.github/workflows/publish.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -314,14 +314,14 @@ jobs:
314314
timeout-minutes: 10
315315
permissions:
316316
contents: read
317-
# Required repository configuration: protect this environment without required reviewers,
318-
# and configure COMETAPI_KEY plus the approved COMETAPI_LIVE_MODEL variable.
317+
# Required repository configuration: protect this environment without required reviewers
318+
# and configure only the scoped COMETAPI_KEY credential.
319319
environment: live-smoke
320320
env:
321321
COMETAPI_LIVE_CONCURRENCY: "1"
322-
COMETAPI_LIVE_MAX_OUTPUT_TOKENS: "16"
322+
COMETAPI_LIVE_MAX_OUTPUT_TOKENS: "64"
323323
COMETAPI_LIVE_MAX_REQUESTS: "4"
324-
COMETAPI_LIVE_MODEL: ${{ vars.COMETAPI_LIVE_MODEL || 'gpt-5.4' }}
324+
COMETAPI_LIVE_MODEL: gpt-5.6-sol
325325
COMETAPI_LIVE_REQUEST_TIMEOUT_SECONDS: "30"
326326
COMETAPI_LIVE_RUN: "1"
327327
COMETAPI_LIVE_STOP_ON_FAILURE: "1"
@@ -381,7 +381,7 @@ jobs:
381381
working-directory: release-bundle
382382
run: sha256sum --check artifact-sha256.txt
383383
- name: Publish through the configured PyPI Trusted Publisher
384-
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
384+
uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1, node24
385385
with:
386386
packages-dir: release-bundle/dist/
387387
print-hash: true

AGENTS.md

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -64,44 +64,8 @@ Registry Alpha, and the first stable release are completed historical steps and
6464
must not be repeated. The canonical repository is public with protected branch
6565
and version-tag rules, Private Vulnerability Reporting, immutable releases,
6666
protected environments, public default-branch CI, and protected release and
67-
registry evidence.
68-
69-
The accepted `0.1.1` maintenance release evidence is:
70-
71-
| Field | Value |
72-
| --- | --- |
73-
| Release commit and tag target | `576e7503a0a8c1103faca5143e4b8d576f8e8b44` |
74-
| Release tag | `v0.1.1` |
75-
| GitHub release | `https://github.com/cometapi-dev/cometapi-python/releases/tag/v0.1.1` |
76-
| Release workflow | `https://github.com/cometapi-dev/cometapi-python/actions/runs/30429821548` |
77-
| PyPI release | `https://pypi.org/project/cometapi/0.1.1/` |
78-
| Wheel SHA256 | `27e7904542f82fbbcd60e0de23a4a62c042420b6d004d00286d1f37d2ec4c5e5` |
79-
| Source SHA256 | `64c7cb87745032703b3374cc562ea00b979416c54908862dbcebd116b2dc44c8` |
80-
81-
The accepted `0.1.0` stable release evidence is:
82-
83-
| Field | Value |
84-
| --- | --- |
85-
| Release commit and tag target | `6f42981edcc6c252f8db997606671c3da84d1dd8` |
86-
| Release tag | `v0.1.0` |
87-
| GitHub release | `https://github.com/cometapi-dev/cometapi-python/releases/tag/v0.1.0` |
88-
| Release workflow | `https://github.com/cometapi-dev/cometapi-python/actions/runs/30359383715` |
89-
| PyPI release | `https://pypi.org/project/cometapi/0.1.0/` |
90-
| Wheel SHA256 | `8eae758688bb6c98274e48d8d81f882eeae760f69cfd2f5e125004881d60e90f` |
91-
| Source SHA256 | `e9308b44f6091200b5121e24d1a0e1b9ea3e6bcccc109d6de87554b1ab2a8bca` |
92-
93-
The accepted Registry Alpha evidence is:
94-
95-
| Field | Value |
96-
| --- | --- |
97-
| Release commit | `31b68904141489ca04932edbf305ccf88af09372` |
98-
| Recovery tag | `v0.1.0-alpha.1+recovery.1` |
99-
| Tag object | `fdc4a6cce31f4534f83903f3f95e7757a4d4049f` |
100-
| GitHub release | `https://github.com/cometapi-dev/cometapi-python/releases/tag/v0.1.0-alpha.1%2Brecovery.1` |
101-
| Release workflow | `https://github.com/cometapi-dev/cometapi-python/actions/runs/30261746138` |
102-
| PyPI release | `https://pypi.org/project/cometapi/0.1.0a1/` |
103-
| Wheel SHA256 | `a6820347317943ca22f7632acbe354dd992f31a122a6172dfe45b57960e3a093` |
104-
| Source SHA256 | `98d86829ef14771e8b7ec180d452c6638289f49c14a39b7207be5c47cb64cde7` |
67+
registry evidence. Exact historical identities and digests belong only in the
68+
validated evidence blocks in `ROADMAP.md` and `RELEASING.md`.
10569

10670
The accepted identity is:
10771

@@ -155,7 +119,7 @@ Post-stable invariants:
155119
direct dependency's `result` to equal `success`. A skipped, cancelled,
156120
failed, or missing dependency must never make build, live smoke,
157121
publication, or registry verification eligible.
158-
9. Keep Release Please pinned to the reviewed `v5.0.0` commit
122+
9. Keep Release Please v5.0.0 pinned to the reviewed commit
159123
`45996ed1f6d02564a971a2fa1b5860e934307cf7`, whose immutable action metadata
160124
uses `node24`. The workflow semantic checker must reject any different pin.
161125
Invoke that action release-only first with `skip-github-pull-request: true`;
@@ -170,6 +134,10 @@ Post-stable invariants:
170134
state read-only, and stop. Do not use another main push or recovery path
171135
until the exact external state is known and recovery is separately
172136
authorized.
137+
Keep the PyPI publisher v1.14.1 pinned to the reviewed commit whose
138+
composite action uses the Node 24 `setup-python` fallback. The workflow
139+
checker must reject any other publisher SHA without changing the top-level
140+
workflow, job, environment, or Trusted Publisher identity.
173141
10. `README.md` is the distribution long description and must remain accurate
174142
before and after publication. Use `python -m pip install cometapi`,
175143
unversioned project links, and publication-neutral maintenance language.
@@ -181,8 +149,11 @@ Post-stable invariants:
181149
persistent guidance or current-state documentation. Query public PyPI when
182150
current registry state is required. Keep candidate version truth in
183151
`pyproject.toml` and `.release-please-manifest.json`, and keep exact released
184-
versions only in immutable historical evidence. The document/version
185-
checker must fail before merge or release when this boundary is violated.
152+
versions only in `CHANGELOG.md` or validated immutable evidence blocks in
153+
`ROADMAP.md` and `RELEASING.md`. All other persistent/current-state public
154+
documents must contain no exact CometAPI patch or recovery identity. The
155+
document/version checker must fail before merge or release when this
156+
boundary is violated.
186157

187158
## Repository independence
188159

@@ -265,9 +236,9 @@ that exact version. Runtime dependencies belong in the manifest only when
265236
CometAPI source directly imports and owns their use.
266237

267238
Compatibility checks cover the minimum supported OpenAI version, the locked
268-
development version, and a scheduled or dependency-PR latest-within-major
269-
canary. Python 3.10 through 3.14 is the initial blocking runtime range while
270-
Python 3.10 remains upstream-supported.
239+
development version, and a blocking latest-within-major lane on every pull
240+
request and default-branch push. Python 3.10 through 3.14 is the initial
241+
blocking runtime range while Python 3.10 remains upstream-supported.
271242

272243
## Development and verification
273244

@@ -312,7 +283,7 @@ committed.
312283

313284
## Release and documentation rules
314285

315-
- The first public artifact must be functional `0.1.0a1`, never a placeholder.
286+
- The first public artifact was functional Registry Alpha, never a placeholder.
316287
- Publication uses a reviewed immutable tag, a protected `pypi` environment,
317288
and PyPI OIDC Trusted Publishing.
318289
- The release commit must equal the tag target and belong to the protected
@@ -339,11 +310,10 @@ committed.
339310
- Every distribution `Project-URL` must use HTTPS. The canonical Support URL
340311
is `https://github.com/cometapi-dev/cometapi-python/blob/main/SUPPORT.md`;
341312
`support@cometapi.com` remains the support and conduct contact.
342-
- GitHub permanently reserved `v0.1.0-alpha.1` after its immutable release
343-
reached OIDC publication but failed before any PyPI distribution was
344-
accepted. The sole approved recovery tag is
345-
`v0.1.0-alpha.1+recovery.1`, which maps to package version `0.1.0a1`.
346-
Later releases must use their ordinary canonical tag spelling.
313+
- The initial Registry Alpha recovery exception is immutable historical
314+
evidence recorded in `ROADMAP.md` and `RELEASING.md`. Later releases must use
315+
their ordinary canonical tag spelling; do not reuse or increment that
316+
exception.
347317
- Keep Release Please disabled outside an explicitly authorized release
348318
sequence. The stable-readiness configuration used a reviewed and tested
349319
`last-release-sha` bridge because the recovery tag's build metadata could not
@@ -362,7 +332,9 @@ committed.
362332
- Keep README, roadmap, compatibility matrix, examples, and changelog aligned
363333
with shipped behavior. README installation and availability guidance must be
364334
publication-neutral because it is embedded in immutable distribution
365-
metadata. Use currently supported model IDs.
335+
metadata. Keep the active example/live model in the checker's canonical
336+
model constant; executable README examples and both live workflows must fail
337+
validation when they drift from it.
366338
- All repository documentation is written in English.
367339

368340
The Public Preview readiness record requires

ARCHITECTURE.md

Lines changed: 17 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ Compatibility evidence has three lanes:
101101

102102
- minimum OpenAI on the oldest supported Python runtime;
103103
- locked OpenAI across the blocking Python runtime matrix; and
104-
- latest OpenAI below 3.0 as a scheduled and dependency-update canary.
104+
- latest OpenAI below 3.0 as a blocking pull-request and default-branch lane.
105105

106106
## Verification boundaries
107107

@@ -135,11 +135,19 @@ and after a release. Source-document and artifact checks reject approval,
135135
unpublished, exact-version installation, and versioned release-link text; each
136136
artifact long description must also exactly match the source README.
137137

138-
Release Please is pinned to the immutable `v5.0.0` commit whose action metadata
138+
Release Please v5.0.0 is pinned to the immutable commit whose action metadata
139139
uses `node24`. The workflow semantic contract fixes that SHA and runtime
140140
disposition so GitHub does not need to force a deprecated Node 20 action onto a
141141
newer runtime.
142142

143+
The version gate accepts Release Please's native linked, dated changelog heading
144+
as well as the existing legacy dated form. It validates repository, previous
145+
tag, candidate tag, and calendar date rather than rewriting generated history.
146+
147+
The PyPI publisher remains directly in `publish.yml` and is pinned to its
148+
reviewed Node 24 maintenance release. Pinning its exact SHA prevents a syntactic
149+
full-SHA substitution from silently changing the OIDC publication supply chain.
150+
143151
Release Please execution is split at the mutability boundary. The first pinned
144152
action invocation is release-only (`skip-github-pull-request: true`) and is
145153
neither continued on error nor retried. Only when that invocation succeeds
@@ -150,39 +158,10 @@ failure ends the job. Updating a branch or pull request is mutable and
150158
idempotent, while retrying immutable tag or GitHub Release creation could leave
151159
ambiguous external state and is forbidden.
152160

153-
[Release Please run 30509764960](https://github.com/cometapi-dev/cometapi-python/actions/runs/30509764960)
154-
isolated the motivating failure to the action's Undici/global `fetch`: the PR
155-
workflow reached its write boundary and then failed with `other side closed`
156-
before any branch, pull-request, tag, GitHub Release, live, or registry write.
157-
The existing release branch and repository pull-request permission were not the
158-
cause. This is negative transport evidence, not evidence of a stale branch or
159-
authorization drift.
160-
161-
This complete trust chain executed successfully in
162-
[release workflow run 30261746138](https://github.com/cometapi-dev/cometapi-python/actions/runs/30261746138)
163-
for release commit `31b68904141489ca04932edbf305ccf88af09372`, recovery tag
164-
`v0.1.0-alpha.1+recovery.1`, and PyPI version `0.1.0a1`. The public wheel and
165-
source distribution matched the retained pre-publication digests, Trusted
166-
Publisher provenance was verified, and the clean registry install/import/mocked
167-
smoke passed.
168-
169-
The same trust chain executed successfully for stable `0.1.0` in
170-
[release workflow run 30359383715](https://github.com/cometapi-dev/cometapi-python/actions/runs/30359383715).
171-
The immutable `v0.1.0` tag resolves to release commit
172-
`6f42981edcc6c252f8db997606671c3da84d1dd8`; the protected live suite, direct
173-
top-level OIDC publication, public digest and provenance comparison, and clean
174-
registry install all passed. The selector-descendant conditions were therefore
175-
verified in GitHub's hosted scheduler, not only by local static checks.
176-
177-
The same trust chain completed for maintenance release `0.1.1` in
178-
[release workflow run 30429821548](https://github.com/cometapi-dev/cometapi-python/actions/runs/30429821548).
179-
The immutable `v0.1.1` tag resolves to release commit
180-
`576e7503a0a8c1103faca5143e4b8d576f8e8b44`; exact-release live smoke, direct
181-
top-level OIDC publication, public digest and provenance comparison, and clean
182-
registry installation all passed. The public wheel SHA256 is
183-
`27e7904542f82fbbcd60e0de23a4a62c042420b6d004d00286d1f37d2ec4c5e5`, and the
184-
source-distribution SHA256 is
185-
`64c7cb87745032703b3374cc562ea00b979416c54908862dbcebd116b2dc44c8`.
161+
Immutable run, tag, commit, registry, and digest records live only in the
162+
validated release-evidence blocks in `ROADMAP.md` and `RELEASING.md`.
163+
Architecture documents mechanisms and boundaries, not a second historical
164+
ledger.
186165

187166
The scheduled/manual default-branch smoke is an operational canary only; it
188167
does not prove the release commit. `COMETAPI_KEY` is exposed only to the
@@ -218,11 +197,9 @@ reject every rerun, and require every direct dependency's result to equal
218197
`success`. This crosses only the unused branch's skipped ancestry; cancellation,
219198
failure, a skipped direct dependency, or a missing result remains fail-closed.
220199

221-
The initial alpha has one release-identity exception. GitHub's immutable
222-
release tombstone permanently reserves `v0.1.0-alpha.1`, so the reviewed
223-
recovery release uses SemVer build metadata in
224-
`v0.1.0-alpha.1+recovery.1`. The build suffix does not change the package
225-
artifact identity: the PyPI version remains `0.1.0a1`.
200+
The initial Registry Alpha has one immutable release-identity exception. Its
201+
exact recovery tag and package mapping are historical evidence in
202+
`RELEASING.md`; later releases use the ordinary canonical tag spelling.
226203

227204
Release Please remains disabled outside an explicitly authorized release
228205
sequence. The stable-readiness configuration used a tested `last-release-sha`

COMPATIBILITY.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ openai>=2.45.0,<3.0.0
4848
| --- | --- | --- |
4949
| Minimum `2.45.0` | Prove the declared lower bound | Oldest supported Python runtime |
5050
| Locked development version | Reproducible contributor and blocking CI environment | Every blocking Python runtime |
51-
| Latest available below `3.0.0` | Detect upstream drift | Scheduled and dependency-update canary |
51+
| Latest available below `3.0.0` | Detect upstream drift | Every pull request and default-branch push |
5252

5353
The lock file is development evidence only. It does not narrow the dependency
5454
range installed for library users.

CONTRIBUTING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ uv run python scripts/check_repository_independence.py
3838
uv run python scripts/run_actionlint.py
3939
```
4040

41-
`scripts/run_actionlint.py` downloads and checksum-verifies `actionlint`
42-
1.7.12 when it is not cached. A passing static workflow check does not mean the
41+
`scripts/run_actionlint.py` downloads and checksum-verifies actionlint 1.7.12
42+
when it is not cached. A passing static workflow check does not mean the
4343
workflow has run successfully on GitHub.
4444

4545
If a check is unavailable, say so in the pull request rather than describing

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ from cometapi import CometAPI
7474

7575
with CometAPI() as client:
7676
response = client.chat.completions.create(
77-
model="gpt-5.4",
77+
model="gpt-5.6-sol",
7878
messages=[{"role": "user", "content": "Hello!"}],
7979
)
8080
print(response.choices[0].message.content)
@@ -88,7 +88,7 @@ from cometapi import CometAPI
8888

8989
with CometAPI() as client:
9090
stream = client.chat.completions.create(
91-
model="gpt-5.4",
91+
model="gpt-5.6-sol",
9292
messages=[{"role": "user", "content": "Write one sentence."}],
9393
stream=True,
9494
)
@@ -104,7 +104,7 @@ from cometapi import CometAPI
104104

105105
with CometAPI() as client:
106106
response = client.responses.create(
107-
model="gpt-5.4",
107+
model="gpt-5.6-sol",
108108
input="Explain API compatibility in one sentence.",
109109
)
110110
models = client.models.list()
@@ -125,7 +125,7 @@ from cometapi import AsyncCometAPI
125125
async def main() -> None:
126126
async with AsyncCometAPI() as client:
127127
response = await client.responses.create(
128-
model="gpt-5.4",
128+
model="gpt-5.6-sol",
129129
input="Say hello.",
130130
)
131131
print(response.output_text)

0 commit comments

Comments
 (0)