@ultimat3/manifest 19.1.3 → 19.2.0
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.
- package/README.md +15 -2
- package/package.json +6 -6
- package/src/errors.ts +33 -4
- package/src/schema.ts +6 -1
package/README.md
CHANGED
|
@@ -74,15 +74,28 @@ permissions), `diff-rate-limit.ts`, `diff-entities.ts`, `diff-work.ts` (jobs, ta
|
|
|
74
74
|
`diff-change.ts`. `diff.ts` is the orchestrator and nothing else.
|
|
75
75
|
|
|
76
76
|
`verifyContract()` is the gate: a breaking change fails unless the app's **major** version
|
|
77
|
-
moved.
|
|
77
|
+
moved. The version is the app's `package.json` `version`, never `app.config.ts` — `AppConfig`
|
|
78
|
+
has no `version` field. An unparseable version counts as "not bumped" — fail-closed.
|
|
78
79
|
|
|
79
80
|
```
|
|
80
81
|
X_MANIFEST_BREAKING: contract broke without a version bump
|
|
81
82
|
cause: 1 breaking change(s) from 1.4.2 to 1.5.0 with no major version bump:
|
|
82
83
|
actions.publishPost: action removed
|
|
83
|
-
fix: bump the major version in
|
|
84
|
+
fix: bump the major version in package.json - the leading integer, so 1.4.2 becomes
|
|
85
|
+
2.0.0 - or restore the removed contract
|
|
84
86
|
```
|
|
85
87
|
|
|
88
|
+
`from === to` is the shape this fires in first, and it gets its own cause: the drift gate forces
|
|
89
|
+
both sides equal in any green state, so a comparison that "moved" from 0.1.0 to 0.1.0 describes
|
|
90
|
+
nothing. It reads `N breaking change(s) against the committed x.manifest.json, with package.json
|
|
91
|
+
unchanged at 0.1.0` instead.
|
|
92
|
+
|
|
93
|
+
An app still at **0.x** gets its own fix line too. `majorOf` compares leading integers only, so
|
|
94
|
+
`0.1.0 -> 0.2.0` does not satisfy the gate and only `1.0.0` does — which is a strange demand of an
|
|
95
|
+
app `x new` scaffolded at `0.1.0` with no published clients. That branch names the two honest
|
|
96
|
+
actions: re-commit the baseline with `x manifest`, or `bun pm pkg set version=1.0.0` if the app
|
|
97
|
+
really does have clients to keep a promise to.
|
|
98
|
+
|
|
86
99
|
## AGENTS.md: validated, never generated
|
|
87
100
|
|
|
88
101
|
`checkAgentsMd()` / `assertAgentsMd()` verify that a **hand-written** `AGENTS.md` exists and
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ultimat3/manifest",
|
|
3
|
-
"version": "19.
|
|
3
|
+
"version": "19.2.0",
|
|
4
4
|
"description": "x.manifest.json: deterministic generated facts, contract diff, AGENTS.md budget",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
"test": "bun test"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@ultimat3/action": "19.
|
|
35
|
-
"@ultimat3/core": "19.
|
|
36
|
-
"@ultimat3/entity": "19.
|
|
37
|
-
"@ultimat3/jobs": "19.
|
|
38
|
-
"@ultimat3/query": "19.
|
|
34
|
+
"@ultimat3/action": "19.2.0",
|
|
35
|
+
"@ultimat3/core": "19.2.0",
|
|
36
|
+
"@ultimat3/entity": "19.2.0",
|
|
37
|
+
"@ultimat3/jobs": "19.2.0",
|
|
38
|
+
"@ultimat3/query": "19.2.0"
|
|
39
39
|
}
|
|
40
40
|
}
|
package/src/errors.ts
CHANGED
|
@@ -49,15 +49,44 @@ export class ManifestDriftError extends UltimateError {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/**
|
|
52
|
+
/**
|
|
53
|
+
* Whether this app has ever published a major. NOT `verify.ts`'s `majorOf`, which DECIDES the gate
|
|
54
|
+
* and is fail-closed on an unparseable version; this one only picks which sentence the reader gets,
|
|
55
|
+
* and a version it cannot recognise (`"0"`, `"next"`) falls to the `else` branch — the stricter of
|
|
56
|
+
* the two instructions, so a guess is never the permissive one.
|
|
57
|
+
*/
|
|
58
|
+
const neverShippedAMajor = (version: string): boolean => version.trim().startsWith('0.');
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A breaking contract change landed without a version bump.
|
|
62
|
+
*
|
|
63
|
+
* Two causes and two fixes, because the FIRST time this fires it fires in a shape the single
|
|
64
|
+
* message described wrongly, twice over.
|
|
65
|
+
*
|
|
66
|
+
* `from === to` is the guaranteed first-fire shape, not an edge case: the drift gate forces the
|
|
67
|
+
* committed manifest to match the code in any green state, so both sides carry the same
|
|
68
|
+
* `package.json` version and `from 0.1.0 to 0.1.0` reads as a comparison that moved when nothing
|
|
69
|
+
* did. And `x new` scaffolds at `0.1.0`, where the instruction to bump the major is a demand for
|
|
70
|
+
* `1.0.0` from an app with no published clients — `0.2.0` does not satisfy the gate, because
|
|
71
|
+
* `majorOf` compares leading integers only.
|
|
72
|
+
*
|
|
73
|
+
* The file was wrong too: `AppConfig` has no `version` field and `defineConfig` excess-property-
|
|
74
|
+
* checks its literal, so "bump the major version in app.config.ts" fails typecheck when followed
|
|
75
|
+
* literally. The version is read from `package.json` (`app-manifest.ts`).
|
|
76
|
+
*/
|
|
53
77
|
export class ManifestBreakingError extends UltimateError {
|
|
54
78
|
constructor(input: { changes: readonly string[]; from: string; to: string }) {
|
|
55
79
|
super({
|
|
56
80
|
code: 'X_MANIFEST_BREAKING',
|
|
57
81
|
cause:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
82
|
+
input.from === input.to
|
|
83
|
+
? `${input.changes.length} breaking change(s) against the committed x.manifest.json, ` +
|
|
84
|
+
`with package.json unchanged at ${input.from}: ${summarize(input.changes)}`
|
|
85
|
+
: `${input.changes.length} breaking change(s) from ${input.from} to ${input.to} ` +
|
|
86
|
+
`with no major version bump: ${summarize(input.changes)}`,
|
|
87
|
+
fix: neverShippedAMajor(input.from)
|
|
88
|
+
? 'a 0.x app has published no compatibility promise, and only 1.0.0 satisfies this gate — 0.2.0 does not: re-commit the baseline with x manifest, or bun pm pkg set version=1.0.0 in package.json'
|
|
89
|
+
: 'bump the major version in package.json — the leading integer, so 1.4.2 becomes 2.0.0 — or restore the removed contract',
|
|
61
90
|
});
|
|
62
91
|
}
|
|
63
92
|
}
|
package/src/schema.ts
CHANGED
|
@@ -140,7 +140,12 @@ export interface ErrorCodeFact {
|
|
|
140
140
|
export interface Manifest {
|
|
141
141
|
/** Shape version. A reader checks this before anything else. */
|
|
142
142
|
readonly manifestVersion: number;
|
|
143
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* App name and semver from the app's `package.json` (`app-manifest.ts`'s `appIdentity`), never
|
|
145
|
+
* from `app.config.ts` — `AppConfig` has no `version` field and `defineConfig`
|
|
146
|
+
* excess-property-checks its literal, so an instruction to edit one there fails typecheck.
|
|
147
|
+
* Drives the breaking-change gate.
|
|
148
|
+
*/
|
|
144
149
|
readonly app: { readonly name: string; readonly version: string };
|
|
145
150
|
/**
|
|
146
151
|
* Content hash of everything below. Deterministic — NOT a timestamp and not a git sha, so
|