Skip to content

Commit c0934cc

Browse files
committed
fix: harden options and publication contracts
1 parent 66c8a80 commit c0934cc

22 files changed

Lines changed: 1035 additions & 171 deletions

‎.github/ISSUE_TEMPLATE/bug_report.yml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ body:
1212
id: version
1313
attributes:
1414
label: CometAPI SDK version
15-
placeholder: 0.1.0-alpha.1
15+
description: Run `npm list cometapi` and report the installed package version.
16+
placeholder: Paste the installed package version
1617
validations:
1718
required: true
1819
- type: input

‎AGENTS.md‎

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,15 @@ repository.
5151
merely to complete lifecycle cleanup. Fail closed and report the exact state
5252
whenever a required cleanliness, fetch, or fast-forward condition is not met.
5353

54-
## Current Milestone: Stable 0.1.1 and Repository Foundation Complete
54+
## Current Milestone: Stable 0.1.x Maintenance
5555

56-
Private Remote Validation, Public Preview, Registry Alpha, stable `0.1.0`, and
57-
the `0.1.1` maintenance patch are complete. The canonical repository is public,
58-
`0.1.1` is available from npm's `latest` channel, and `0.1.0-alpha.3` remains
59-
available from `next`; the published lines have verified provenance and
60-
public-install evidence. No later milestone is active. Do not begin the 0.2
61-
provider adapters without an explicit maintainer request.
56+
Private Remote Validation, Public Preview, Registry Alpha, and Repository
57+
foundation are complete. The canonical repository is public and remains in
58+
stable 0.1.x maintenance: stable packages use npm's `latest` channel and
59+
Registry Alpha artifacts use `next`. Do not pin an exact current package or
60+
Release version in durable repository guidance. Query npm and GitHub when exact
61+
state matters. No later milestone is active; do not begin the 0.2 provider
62+
adapters without an explicit maintainer request.
6263

6364
The accepted identity is:
6465

@@ -78,21 +79,23 @@ The unscoped `cometapi` package is the primary Node SDK. `@cometapi` is the
7879
standard scope for future official scoped packages; do not introduce new
7980
official packages under `@cometapi-dev`.
8081

81-
Stable `0.1.1` corrected the public options boundary without expanding the 0.1
82-
resource surface. Release Please created the reviewed patch PR, immutable tag,
83-
and GitHub Release. Publication required a disclosed one-time main-context
84-
recovery because the immutable tag predated the repaired tag handoff. The
85-
recovery published only the exact previously verified artifact through npm
86-
OIDC, then the repository restored its variables and tag-only Environment
87-
policy. The current workflow contains no publication-recovery input, fixed
88-
recovery run or artifact ID, prior-package-artifact or live-evidence reuse, or
89-
branch-context publication path.
82+
Stable `0.1.1` established the runtime options boundary and repaired the release
83+
path without expanding the 0.1 resource surface. Release Please created the
84+
reviewed patch PR, immutable tag, and GitHub Release. Publication required a
85+
disclosed one-time main-context recovery because the immutable tag predated the
86+
repaired tag handoff. The recovery published only the exact previously verified
87+
artifact through npm OIDC, then the repository restored its variables and
88+
tag-only Environment policy. The current workflow contains no
89+
publication-recovery input, fixed recovery run or artifact ID,
90+
prior-package-artifact or live-evidence reuse, or branch-context publication
91+
path.
9092

9193
Release Please remains disabled between explicitly authorized release
9294
operations. Permanent stable patches follow only the tag-bound path in
93-
`RELEASING.md`. The `0.1.1` recovery provenance is historical evidence, not
94-
proof that the current permanent tag path has completed a registry publication;
95-
the next explicitly authorized stable patch is its first end-to-end execution.
95+
`RELEASING.md`. The recovery provenance for stable `0.1.1` is historical
96+
evidence and does not prove an execution of the permanent path. The next
97+
explicitly authorized stable patch is that path's first end-to-end registry
98+
execution.
9699

97100
## Product Contract
98101

@@ -125,6 +128,11 @@ message translation are not 0.1 features.
125128
Do not hand-write replacements for those layers.
126129
- Use only documented public OpenAI constructor and client options. Do not
127130
depend on private upstream attributes or methods.
131+
- Declare CometAPI-owned `provider`, `workloadIdentity`, and
132+
`dangerouslyAllowBrowser` fields as optional `never` properties on
133+
`CometAPIOptions`. The constructor and `withOptions` must reject every
134+
non-`undefined` value at runtime as well as through TypeScript variables,
135+
spreads, and constrained generics.
128136
- Preserve official OpenAI request, response, stream, and exception types for
129137
the supported 0.1 operations.
130138
- Keep CometAPI-specific resources in `src/resources/` and their types in
@@ -243,6 +251,10 @@ repository root.
243251
- Inspect `npm pack` output, install the exact tarball in clean ESM, CommonJS,
244252
and compatible-OpenAI host fixtures, and verify version agreement before
245253
publication.
254+
- Treat `package.json` as the sole candidate-version authority. A normal stable
255+
Release Please PR changes exactly `.release-please-manifest.json`,
256+
`CHANGELOG.md`, `package-lock.json`, and `package.json`; all four version
257+
records must agree, while durable documentation remains publication-neutral.
246258
- Keep development checks compatible with unresolved maintainer input, but
247259
make the publish workflow fail closed until maintainers have supplied the
248260
copyright holder, canonical security and support contacts, repository

‎ARCHITECTURE.md‎

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ only for CometAPI defaults and public branding:
2929
3. The default base URL is `https://api.cometapi.com/v1`.
3030
4. Other documented and supported OpenAI client options pass through unchanged.
3131

32-
The public `CometAPIOptions` type excludes the upstream `provider`,
33-
`workloadIdentity`, and `dangerouslyAllowBrowser` fields in addition to the
34-
CometAPI-owned `apiKey` and `baseURL` fields. Provider and workload-identity
35-
routing conflict with the API key and base URL that this client injects.
36-
Browser-side long-lived key use is outside the 0.1 security boundary. These
37-
fields never represented valid CometAPI behavior, so their removal from the
38-
public type is a 0.1.1 contract correction rather than a supported feature
39-
removal.
32+
The public `CometAPIOptions` type omits the upstream definitions of `provider`,
33+
`workloadIdentity`, and `dangerouslyAllowBrowser`, then redeclares those names as
34+
`provider?: never`, `workloadIdentity?: never`, and
35+
`dangerouslyAllowBrowser?: never`. Provider and workload-identity routing
36+
conflict with the API key and base URL that this client injects. Browser-side
37+
long-lived key use is outside the 0.1 security boundary. The optional-`never`
38+
contract makes variables, spreads, and constrained generics structurally
39+
incompatible when they carry a non-`undefined` reserved value. These fields
40+
never represented valid CometAPI behavior, so tightening the declaration within
41+
stable 0.1.x is not a supported feature removal.
4042

4143
The inherited `withOptions` path is constrained to the same
4244
`CometAPIOptions` contract. Both the constructor and `withOptions` validate
@@ -99,15 +101,22 @@ The package manifest declares only intended runtime files. Generated build
99101
artifacts and dependency directories are not committed. A successful source-tree
100102
import is not package evidence; verification must use the packed artifact.
101103

102-
`package.json` is the source of the candidate version. Local and release checks
103-
derive the version from it and require agreement with the package-lock root,
104-
the Release Please manifest or the documented one-time bootstrap, the single
105-
candidate changelog heading, and packed metadata. Remote publication adds exact
106-
tag and GitHub release agreement.
104+
`package.json` is the sole source of the candidate version. Local and release
105+
checks derive the version from it and require agreement with the package-lock
106+
root, the Release Please manifest or the documented one-time bootstrap, the
107+
single candidate changelog heading, and packed metadata. A normal stable
108+
Release Please PR changes exactly `.release-please-manifest.json`,
109+
`CHANGELOG.md`, `package-lock.json`, and `package.json`; version-specific status
110+
does not belong in its durable documentation. Remote publication adds exact tag
111+
and GitHub Release agreement.
107112

108113
The publish workflow is the sole source of npm dist-tag selection: prereleases
109114
use `next`, stable versions use `latest`. The package manifest must not carry a
110115
static dist-tag because that would make stable and prerelease policy diverge.
116+
Exact registry and Release state must be queried from npm and GitHub rather than
117+
inferred from repository prose. The unversioned package page is
118+
<https://www.npmjs.com/package/cometapi>, and GitHub release state is available
119+
from <https://github.com/cometapi-dev/cometapi-node/releases>.
111120
Trusted Publishing is the only executable authentication path. The protected-
112121
environment token bootstrap used for `0.1.0-alpha.1` is historical evidence;
113122
current workflows contain no token publication path and reject registry-token

‎COMPATIBILITY.md‎

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
Compatibility document version: 0.1
44
Package line: `0.1.x`
55

6-
Stable release: `0.1.1`; the immutable Release, bounded live smoke, npm OIDC
7-
publication, and separate public-registry verification completed on 2026-07-30.
8-
Registry Alpha `0.1.0-alpha.3` remains available from npm's `next` channel.
6+
Maintenance status: stable `0.1.x`. Stable packages use npm's `latest` channel,
7+
and Registry Alpha artifacts use `next`. Exact package, dist-tag, and GitHub
8+
Release state is intentionally not pinned here; query
9+
<https://www.npmjs.com/package/cometapi> and
10+
<https://github.com/cometapi-dev/cometapi-node/releases>. Dated evidence for
11+
each completed release remains below.
912

1013
This matrix defines the contract-tested 0.1 compatibility surface. Inheritance
1114
from the official OpenAI client does not by itself establish CometAPI support.
@@ -42,24 +45,27 @@ error contract.
4245

4346
The 0.1 client keeps supported OpenAI transport and observability options, while
4447
reserving CometAPI routing, authentication, and the browser security boundary.
45-
The 0.1.0 declarations mistakenly admitted the three reserved fields even
46-
though they could not produce valid, supported CometAPI behavior; 0.1.1 corrects
47-
that contract:
48+
Earlier stable declarations omitted the three reserved fields, which rejected
49+
fresh object literals but still admitted structurally typed variables. Those
50+
fields never produced valid, supported CometAPI behavior. Stable maintenance
51+
therefore makes the prohibition structural:
4852

4953
| Option group | Contract |
5054
| -------------------------------------------------------------------------------------------- | -------------------------------------------- |
5155
| `timeout`, `maxRetries`, `fetch`, `fetchOptions`, `defaultHeaders`, `defaultQuery`, `logger` | Supported constructor pass-through |
5256
| `organization`, `project`, `webhookSecret`, `adminAPIKey` | Supported constructor pass-through |
5357
| Per-request options | Supported for the contract-tested operations |
54-
| `provider`, `workloadIdentity`, `dangerouslyAllowBrowser` | Rejected by declarations and at runtime |
58+
| `provider?: never`, `workloadIdentity?: never`, `dangerouslyAllowBrowser?: never` | Rejected by declarations and at runtime |
5559

5660
`provider` and `workloadIdentity` would conflict with the CometAPI API key and
5761
base URL injected by the SDK. `dangerouslyAllowBrowser` would cross the 0.1
58-
long-lived-key boundary. The constructor and `withOptions` enforce the same
59-
rule. Runtime rejections use the official OpenAI `OpenAIError`, identify only
60-
the forbidden field, and do not include its value. Compile-time negative tests
61-
are executed by TypeScript against source and packed ESM/CommonJS declarations;
62-
runtime tests cover plain JavaScript and type-cast bypasses.
62+
long-lived-key boundary. Redeclaring all three fields as optional `never` makes
63+
non-`undefined` values incompatible through object literals, inferred
64+
variables, spreads, and constrained generics. The constructor and `withOptions`
65+
enforce the same rule at runtime. Runtime rejections use the official OpenAI
66+
`OpenAIError`, identify only the forbidden field, and do not include its value.
67+
Compile-time negative tests run against source and packed ESM/CommonJS
68+
declarations; runtime tests cover plain JavaScript and type-cast bypasses.
6369

6470
## Inherited but unsupported in 0.1
6571

‎README.md‎

Lines changed: 37 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ The official CometAPI entry point for the OpenAI-compatible API. The SDK keeps
44
the official OpenAI JavaScript request, response, stream, and error types while
55
defaulting the client to CometAPI.
66

7-
> **Stable 0.1 release:** `0.1.1` is published on npm's default `latest`
8-
> dist-tag. Its immutable GitHub Release, bounded live smoke, npm OIDC
9-
> publication, provenance, signature, and separate public-registry installation
10-
> verification are complete. The supported API remains limited to the
11-
> contract-tested 0.1 surface documented here and in
7+
> **Stable 0.1.x maintenance:** Stable packages install from npm's default
8+
> `latest` dist-tag, while prerelease artifacts use `next`. Exact package,
9+
> dist-tag, and GitHub Release state is intentionally not pinned in this README;
10+
> query the registries when that state matters. The supported API remains
11+
> limited to the contract-tested 0.1 surface documented here and in
1212
> [COMPATIBILITY.md](./COMPATIBILITY.md).
1313
1414
## Supported 0.1 surface
@@ -46,6 +46,17 @@ Install the stable package from npm's default `latest` dist-tag:
4646
npm install cometapi
4747
```
4848

49+
The unversioned registry page is
50+
<https://www.npmjs.com/package/cometapi>. Query npm and GitHub instead of using
51+
an exact version copied from repository prose:
52+
53+
```bash
54+
npm view cometapi version
55+
npm view cometapi dist-tags --json
56+
gh release view --repo cometapi-dev/cometapi-node \
57+
--json tagName,isDraft,isPrerelease,publishedAt,url
58+
```
59+
4960
The release workflow is the sole source of the npm dist-tag: prerelease
5061
versions publish to `next`, while stable versions publish to `latest`. The
5162
package manifest does not declare a static dist-tag.
@@ -164,12 +175,13 @@ const response = await client.chat.completions.create(
164175
);
165176
```
166177
167-
Starting with 0.1.1, the public type matches the runtime boundary that 0.1.0
168-
intended. The SDK owns CometAPI routing, authentication, and the Node-only
169-
secret boundary. Consequently, `provider`, `workloadIdentity`, and
170-
`dangerouslyAllowBrowser` are not `CometAPIOptions`. They are rejected both by
171-
the TypeScript declarations and at runtime when plain JavaScript or a type cast
172-
bypasses those declarations. The same restriction applies to inherited
178+
The 0.1.x public type matches the enforced runtime boundary. The SDK owns
179+
CometAPI routing, authentication, and the Node-only secret boundary.
180+
`CometAPIOptions` therefore declares `provider?: never`,
181+
`workloadIdentity?: never`, and `dangerouslyAllowBrowser?: never`. Non-`undefined`
182+
values are rejected by TypeScript, including through inferred variables,
183+
spreads, and constrained generics, and runtime validation protects plain
184+
JavaScript and type-cast bypasses. The same restriction applies to inherited
173185
`withOptions` calls. A rejection is an official OpenAI `OpenAIError` and names
174186
only the forbidden field; it never includes the supplied value.
175187
@@ -229,24 +241,20 @@ parent.
229241
230242
## Project status
231243
232-
The repository has completed Public Preview, Registry Alpha, stable `0.1.0`,
233-
the `0.1.1` maintenance patch, and Repository foundation. Blocking CI,
234-
protected repository rules, security reporting, protected environments, and
235-
the authorized bounded live smoke have passed. Stable `0.1.1` is available from
236-
`latest`; Registry Alpha `0.1.0-alpha.3` remains available from `next`. A
237-
separate public-registry check passed ESM, CommonJS, declarations, supported
238-
mocked calls, the compatible-OpenAI host fixture with one effective OpenAI
239-
installation, official error identity, integrity, signature, and provenance.
240-
241-
The immutable `0.1.0-alpha.2` GitHub release remains as an unpublished failure
242-
record because its guard stopped before invoking npm. Mocked responses, packed
243-
artifacts, GitHub Actions, trusted live tests, and npm publication remain
244-
separate evidence layers and must not be represented as another. Published npm
245-
artifacts are immutable, so the `0.1.1` tarball retains its candidate-era
246-
README; this post-release status first ships in a later package version. The
247-
one-time `0.1.1` publication recovery is documented as historical evidence in
248-
[RELEASING.md](./RELEASING.md); the current permanent release workflow is
249-
immutable-tag-bound. No 0.2 provider adapter work is included.
244+
The repository is in stable 0.1.x maintenance, and no 0.2 provider-adapter
245+
milestone is active. Repository foundation, Public Preview, and Registry Alpha
246+
are complete. Stable packages use `latest`; Registry Alpha artifacts use
247+
`next`. Use the npm and GitHub queries in [Installation](#installation) for
248+
exact current state. Release-specific CI, live-smoke, registry, integrity,
249+
signature, provenance, and public-install evidence is retained in
250+
[RELEASING.md](./RELEASING.md), not restated as mutable version status here.
251+
252+
Mocked responses, packed artifacts, GitHub Actions, trusted live tests, and npm
253+
publication remain separate evidence layers and must not be represented as one
254+
another. Exact failed-release, immutable-artifact, and one-time recovery history
255+
is retained in [RELEASING.md](./RELEASING.md) rather than reproduced in this
256+
consumer README. The permanent release workflow is immutable-tag-bound and
257+
publishes through npm OIDC.
250258
251259
See:
252260

0 commit comments

Comments
 (0)