Repository navigation
Commit d9d41dd
fix(spec): a truncated-history build judges a commit by the anchor it records, never by origin/main (#24436)
Fixes #24359
Clause-②: no
## What changed
`packages/spec/scripts/build-schemas.ts` computes ONE baseline for its
three git-reading ratchets: the schema removal check, the authorable-key
deletion check and the default-change check. Where `merge-base HEAD
origin/main` answers, nothing changes: that is the path this
repository's own PR and merge-queue gate runs (`Type Check · source
gates` checks out with `fetch-depth: 0`).
Where history is truncated, which is every `--depth=1` rebuild of a
pinned commit, the old resolver picked its anchor in this order:
1. the tree's own `authorable-surface.base.json` `baseRev`, but only if
origin/main vouched for it;
2. otherwise the rev **origin/main's** anchor names;
3. otherwise **origin/main's tip**.
Arms 2 and 3 make the verdict about commit X a function of where main
points when the build runs.
Now a truncated history always anchors on the rev **the tree under test
records**. Its keys, manifest and defaults are still read out of git at
that rev (never out of the file), and the file is still checked against
them. With no anchor the tree can read, the run refuses: either the file
is missing, or its `baseRev` cannot be fetched. It never falls back to
the tip. `--update-base` is the one mode that still reads the tip in a
truncated history, unchanged; moving an existing anchor still refuses
there (the forward-only rule).
Per ratchet in the file (measured, not assumed):
- the manifest removal check, the authorable-key deletion check and the
default-change check all read the single `resolveSurfaceBase()`
resolution, so all three share the defect and all three get this change
at once;
- the never-published ratchet (`lib/unemitted-schemas`) and the
dropped-refinement ratchet read only in-tree baselines (no git reads),
so neither shares the defect and neither changes.
## Measured: the release commit, rebuilt the way objectui rebuilds it
The commit `@objectstack/spec@18.0.0-next.3` was released from,
`2c9bf9430a`, rebuilt with `pnpm gen:schema` in an objectui-shaped
clone: `git init`, a remote, a depth-1 fetch of the pin. Its
`build-schemas.ts` is byte-identical to main's, so "after" means that
commit with this script copied in. Every leg's anchor rev is
`85c6d76ec42a` unless stated otherwise.
| remote the clone fetches `main` from | before (script `a266dcd7e296`)
| after (script `48aab23a9e72`) |
|---|---|---|
| real GitHub main (`71fa166e96` before, `e22defb13c` after) | exit 0,
anchored on `85c6d76ec42a` (main still names the same anchor) | exit 0,
anchored on `85c6d76ec42a` |
| a main whose anchor commit cannot be fetched (models the objectui CI
jobs; see notes) | **exit 1**: anchors on the TIP; `3 schema(s) left the
published set with no registered removal`: `api/PackageInstallManifest`,
`security/DefaultRowScope`, `ui/PageRecordBinding`, all added on main
after the release | exit 1, an accurate refusal: the anchor commit was
not served, so the run refuses rather than judge the tree against main
or skip the checks |
| a main that re-anchored past the release (synthetic commit
`07857fe78f` on the tip, as `--update-base` writes it) | **exit 1**:
anchors on main's anchor rev `71fa166e965a`; the same 3 schemas | exit
0, anchored on `85c6d76ec42a` |
| no remote (objectui's workaround) | exit 0, offline in-tree anchor |
exit 0, offline in-tree anchor |
So for every origin/main (the real tip, a re-anchored main, none) the
release commit gets the same verdict on the same anchor. The only red
after the change is a remote that will not serve the commit's own
anchor, and that red says exactly that.
objectui's real failure (PR objectui#12963, the `Type Check` job's
annotation) matches the before/fetch-failure leg message for message.
First "no upstream anchor was usable either … anchors on the origin/main
TIP `51ad8e4fba87`", then `❌ 2 schema(s) left the published set …`. At
that tip main's own anchor also named `85c6d76ec42a`, so the old
resolver's arm 1 was lost only because the anchor fetch failed in that
job.
## Ruling ③: the ratchet does not weaken where it guards
The ratchet's own refusal pins (the `a deleted manifest key must prove
itself` block): the bypass repro is **red** on a removal, a declared
removal is **green**, and the negative control is green.
- before, at BASE `71fa166e96`: `Tests 3 passed`
- after, at HEAD `a99d2041d4`: the whole block, `9 passed`, inside a
28/28 run
Those cases run on walkable history, the PR gate's path, which this
change does not touch.
New in the shallow block, a commit that is already on main, rebuilt in a
truncated clone:
- **same verdict:** under a main that only moved on and under a main
that re-anchored past it, both runs are green on the commit's own
anchor, and the removal comparison really ran;
- **teeth:** a schema the commit's anchor recorded and the build
dropped, unregistered, is **red under either main**, naming that schema.
Under the re-anchored main the old resolver missed this removal and
named one of main's additions instead.
## The trade, stated
A truncated history cannot prove `baseRev` is upstream, so a branch that
points `baseRev` at its own commit is no longer overridden with main's
anchor in a shallow job. That forged rev is refused where history is
walkable: `NOT an ancestor of origin/main`, the existing authenticity
check, which runs on this repository's PR and merge-queue gate. Both
halves are pinned in one case: the shallow run uses the tree's rev, and
the walkable run refuses it.
## Tests (all at HEAD `a99d2041d4`)
- `build-schemas-check-mode.test.ts` (vitest `repo` project; the file is
about 20 minutes long, so it ran in four `-t` slices): **92 of 92
passed** (13 + 28 + 29 + 22).
- `def-key-collisions.test.ts`,
`published-projection-choke-point.test.ts` and
`schema-tree-freshness.test.ts` (they spawn, read or digest this
script): 35/35 passed.
- `@objectstack/spec` local project: 696 files, 21251 tests passed.
- `pnpm --filter @objectstack/spec typecheck`: exit 0. `tsc -p
tsconfig.scripts.json --listFiles` includes both changed files.
- **Ablation**, one-shot. BASE's `build-schemas.ts` was put on disk
(hash `a266dcd7e296…` matched BASE's blob), the shallow block ran, then
the file was restored (hash `48aab23a9e72…` matched HEAD's blob, `git
diff HEAD` empty). Result: **7 failed, 2 passed**. The 2 are the
unchanged cases (a real deletion stays red; keys come from git, not the
file). The two new cases failed on the old resolver exactly as described
above, with `1 schema(s) left the published set …
ui/ZzzPublishedOnMainAfterTheCommit`. No `dist/` leg: the test copies
`scripts/` and runs it with tsx.
- One fixture in the drift-notice block was re-based without changing
its subject. Its shallow state now keeps `merge-base` answerable,
because a shallow run with no merge base now anchors on exactly the
committed anchor and has no drift left to describe.
## Gates (local, derived with `dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `a99d2041d4`)
`--ran` reconciliation: **65 derived, 60 run, 5 NOT-MEASURED, 0 UNRUN**
(exit 0).
- 60 ran, every one exit 0. This includes the five spec gates
(`check:authorable-surface`, `check:empty-state`, `check:liveness`,
`check:strictness-ledger`, `check:variant-docs`), `check:nul-bytes`,
`check:published-files`, `check:changeset-gate-self-tests`,
`check:adr-0087-registration --base origin/main`, and
`check:pm-dispatch-gates`. That battery ran detached; its verdict line
was `1913 cases pass` (fast tier).
- NOT MEASURED, `check:dts-closure`, `check:dual-build-cjs-loads`,
`check:lean-entry-closure`, `check:sourcemap-no-sources-content`: exit
3, prerequisite not met (no workspace `dist/` in this worktree).
- NOT MEASURED, `check:type-check-debt`: it re-measures `tsc` for every
package under a closure build and exceeded a 420 s bound (exit 124).
CI runs all five NOT MEASURED families.
## Changeset: `skip-changeset`
`packages/spec/scripts/**` is outside `files[]`. `npm pack --dry-run`
lists 0 `scripts/` entries.
Measured: none of this diff's symbols or strings appears in any
`files[]` path, nor in `dist/` (each 0 files). Positive controls do hit:
`x-unprojectable-branches`, which this script writes into
`json-schema/`, is in 6 files; `PageRecordBinding` is in 22 `dist/`
files.
The one shipped byte sequence that moves is
`json-schema/.build-input-hash-schema`, a freshness digest whose inputs
include `scripts/**`, as they do for any test-only spec change. The
precedent is `0d43004100`, which changed only this script and carried no
changeset.
## Acceptance notes
- **Applies to commits that carry it.** A rebuild runs the script of the
commit being built. The 18.0.0-next.3 commit keeps its own resolver
forever, so objectui's remote-drop workaround stays needed until its pin
moves to a commit carrying this change. Retiring the workaround is
objectui's.
- **Boundary, unchanged:** a full clone whose origin/main is OLDER than
the commit's own `baseRev` still refuses with `NOT an ancestor of
origin/main`. Stale origin/main and a forged anchor are
indistinguishable without history, and that refusal is the guard. Noted,
not filed; the carrier is none.
- **Inferred, not measured:** why the anchor fetch failed in 13 of
objectui's 25 jobs. The annotations show the fetch failed in the
re-anchor call and succeeded moments later in the authenticity check.
The job logs are on a blob host this container cannot reach (403).
- The origin/main the tree was compared against moved 2 commits after
BASE, neither touching `packages/spec/`; the branch was not merged with
main.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WnW7HvfnfHbLg1fpkHX3Mu)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 9112bcd commit d9d41dd
2 files changed
Lines changed: 362 additions & 175 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2777 | 2777 | | |
2778 | 2778 | | |
2779 | 2779 | | |
2780 | | - | |
2781 | | - | |
2782 | | - | |
2783 | | - | |
2784 | | - | |
2785 | | - | |
2786 | | - | |
2787 | | - | |
| 2780 | + | |
| 2781 | + | |
| 2782 | + | |
| 2783 | + | |
| 2784 | + | |
| 2785 | + | |
| 2786 | + | |
| 2787 | + | |
| 2788 | + | |
| 2789 | + | |
2788 | 2790 | | |
2789 | 2791 | | |
2790 | 2792 | | |
2791 | 2793 | | |
2792 | | - | |
| 2794 | + | |
| 2795 | + | |
| 2796 | + | |
| 2797 | + | |
| 2798 | + | |
2793 | 2799 | | |
2794 | 2800 | | |
2795 | 2801 | | |
2796 | 2802 | | |
2797 | | - | |
| 2803 | + | |
2798 | 2804 | | |
| 2805 | + | |
2799 | 2806 | | |
2800 | 2807 | | |
2801 | 2808 | | |
| |||
2903 | 2910 | | |
2904 | 2911 | | |
2905 | 2912 | | |
2906 | | - | |
2907 | | - | |
2908 | | - | |
2909 | | - | |
2910 | | - | |
2911 | | - | |
2912 | | - | |
2913 | | - | |
| 2913 | + | |
| 2914 | + | |
| 2915 | + | |
| 2916 | + | |
| 2917 | + | |
| 2918 | + | |
| 2919 | + | |
| 2920 | + | |
| 2921 | + | |
| 2922 | + | |
| 2923 | + | |
| 2924 | + | |
| 2925 | + | |
| 2926 | + | |
| 2927 | + | |
| 2928 | + | |
2914 | 2929 | | |
2915 | 2930 | | |
2916 | 2931 | | |
2917 | 2932 | | |
2918 | 2933 | | |
2919 | 2934 | | |
2920 | 2935 | | |
| 2936 | + | |
| 2937 | + | |
| 2938 | + | |
| 2939 | + | |
| 2940 | + | |
2921 | 2941 | | |
2922 | 2942 | | |
2923 | 2943 | | |
| |||
2932 | 2952 | | |
2933 | 2953 | | |
2934 | 2954 | | |
| 2955 | + | |
| 2956 | + | |
| 2957 | + | |
| 2958 | + | |
| 2959 | + | |
2935 | 2960 | | |
2936 | 2961 | | |
2937 | 2962 | | |
| |||
3004 | 3029 | | |
3005 | 3030 | | |
3006 | 3031 | | |
3007 | | - | |
| 3032 | + | |
3008 | 3033 | | |
3009 | 3034 | | |
3010 | 3035 | | |
| |||
3055 | 3080 | | |
3056 | 3081 | | |
3057 | 3082 | | |
3058 | | - | |
3059 | | - | |
| 3083 | + | |
| 3084 | + | |
3060 | 3085 | | |
3061 | | - | |
| 3086 | + | |
3062 | 3087 | | |
3063 | 3088 | | |
3064 | 3089 | | |
3065 | | - | |
3066 | | - | |
3067 | | - | |
| 3090 | + | |
3068 | 3091 | | |
3069 | 3092 | | |
3070 | 3093 | | |
3071 | 3094 | | |
3072 | 3095 | | |
3073 | 3096 | | |
3074 | 3097 | | |
| 3098 | + | |
| 3099 | + | |
| 3100 | + | |
| 3101 | + | |
| 3102 | + | |
3075 | 3103 | | |
3076 | 3104 | | |
3077 | | - | |
3078 | | - | |
3079 | | - | |
3080 | | - | |
3081 | | - | |
3082 | | - | |
3083 | | - | |
3084 | | - | |
3085 | | - | |
| 3105 | + | |
| 3106 | + | |
| 3107 | + | |
| 3108 | + | |
| 3109 | + | |
| 3110 | + | |
| 3111 | + | |
| 3112 | + | |
| 3113 | + | |
| 3114 | + | |
| 3115 | + | |
| 3116 | + | |
| 3117 | + | |
| 3118 | + | |
| 3119 | + | |
3086 | 3120 | | |
3087 | 3121 | | |
3088 | 3122 | | |
3089 | 3123 | | |
3090 | | - | |
| 3124 | + | |
3091 | 3125 | | |
3092 | 3126 | | |
3093 | | - | |
3094 | | - | |
3095 | | - | |
3096 | | - | |
| 3127 | + | |
| 3128 | + | |
| 3129 | + | |
| 3130 | + | |
3097 | 3131 | | |
3098 | 3132 | | |
3099 | 3133 | | |
| |||
3106 | 3140 | | |
3107 | 3141 | | |
3108 | 3142 | | |
3109 | | - | |
3110 | | - | |
| 3143 | + | |
| 3144 | + | |
| 3145 | + | |
| 3146 | + | |
| 3147 | + | |
| 3148 | + | |
| 3149 | + | |
| 3150 | + | |
| 3151 | + | |
| 3152 | + | |
| 3153 | + | |
| 3154 | + | |
| 3155 | + | |
| 3156 | + | |
| 3157 | + | |
| 3158 | + | |
| 3159 | + | |
| 3160 | + | |
| 3161 | + | |
| 3162 | + | |
| 3163 | + | |
| 3164 | + | |
| 3165 | + | |
| 3166 | + | |
| 3167 | + | |
| 3168 | + | |
| 3169 | + | |
3111 | 3170 | | |
| 3171 | + | |
| 3172 | + | |
| 3173 | + | |
| 3174 | + | |
| 3175 | + | |
| 3176 | + | |
| 3177 | + | |
| 3178 | + | |
| 3179 | + | |
| 3180 | + | |
| 3181 | + | |
| 3182 | + | |
| 3183 | + | |
| 3184 | + | |
| 3185 | + | |
| 3186 | + | |
| 3187 | + | |
| 3188 | + | |
| 3189 | + | |
| 3190 | + | |
| 3191 | + | |
| 3192 | + | |
| 3193 | + | |
| 3194 | + | |
| 3195 | + | |
3112 | 3196 | | |
3113 | | - | |
3114 | | - | |
| 3197 | + | |
| 3198 | + | |
| 3199 | + | |
| 3200 | + | |
| 3201 | + | |
| 3202 | + | |
| 3203 | + | |
| 3204 | + | |
| 3205 | + | |
| 3206 | + | |
| 3207 | + | |
| 3208 | + | |
| 3209 | + | |
| 3210 | + | |
| 3211 | + | |
| 3212 | + | |
| 3213 | + | |
| 3214 | + | |
| 3215 | + | |
| 3216 | + | |
| 3217 | + | |
| 3218 | + | |
| 3219 | + | |
| 3220 | + | |
| 3221 | + | |
| 3222 | + | |
| 3223 | + | |
| 3224 | + | |
| 3225 | + | |
| 3226 | + | |
| 3227 | + | |
| 3228 | + | |
| 3229 | + | |
| 3230 | + | |
| 3231 | + | |
| 3232 | + | |
| 3233 | + | |
| 3234 | + | |
| 3235 | + | |
| 3236 | + | |
| 3237 | + | |
| 3238 | + | |
| 3239 | + | |
| 3240 | + | |
| 3241 | + | |
| 3242 | + | |
| 3243 | + | |
| 3244 | + | |
| 3245 | + | |
| 3246 | + | |
| 3247 | + | |
| 3248 | + | |
| 3249 | + | |
| 3250 | + | |
| 3251 | + | |
| 3252 | + | |
| 3253 | + | |
| 3254 | + | |
| 3255 | + | |
| 3256 | + | |
| 3257 | + | |
| 3258 | + | |
| 3259 | + | |
| 3260 | + | |
| 3261 | + | |
| 3262 | + | |
| 3263 | + | |
| 3264 | + | |
| 3265 | + | |
| 3266 | + | |
| 3267 | + | |
| 3268 | + | |
| 3269 | + | |
| 3270 | + | |
| 3271 | + | |
| 3272 | + | |
| 3273 | + | |
| 3274 | + | |
| 3275 | + | |
| 3276 | + | |
| 3277 | + | |
| 3278 | + | |
| 3279 | + | |
| 3280 | + | |
| 3281 | + | |
| 3282 | + | |
| 3283 | + | |
| 3284 | + | |
| 3285 | + | |
| 3286 | + | |
| 3287 | + | |
| 3288 | + | |
| 3289 | + | |
| 3290 | + | |
| 3291 | + | |
| 3292 | + | |
| 3293 | + | |
| 3294 | + | |
| 3295 | + | |
| 3296 | + | |
| 3297 | + | |
| 3298 | + | |
| 3299 | + | |
| 3300 | + | |
| 3301 | + | |
| 3302 | + | |
| 3303 | + | |
| 3304 | + | |
| 3305 | + | |
| 3306 | + | |
| 3307 | + | |
| 3308 | + | |
| 3309 | + | |
| 3310 | + | |
| 3311 | + | |
3115 | 3312 | | |
3116 | 3313 | | |
3117 | 3314 | | |
| |||
0 commit comments