Repository navigation
Commit 94990a2
Part of #21002
Clause-②: no
## What
For a flow name the loader ships from a managed package, the layered
read (`GET /api/v1/meta/flow/NAME/layers`, and the deprecated layers
flag on the by-name door, which uses the same helper) now reports the
loader's body as the effective layer. That is the body the by-name read
(`GET /api/v1/meta/flow/NAME`) and the flow list (`GET
/api/v1/meta/flow`) have answered for that name since #20946 and #20913.
A stored row of that name is still reported, as a separate shadowed
layer of its own scope, and is never the effective layer under the
package's lock and provenance flags.
`getMetaItemLayered` in `packages/metadata-protocol/src/protocol.ts` now
decides its effective layer with the stored-row predicate PR #20942
introduced and PR #20994 reuses, `isShippedFlowName`, judged by name. It
adds no precedence rule of its own.
- **The predicate is called, not edited.** Only `getMetaItemLayered`
moves in `protocol.ts`: the effective-layer binding and its docblock
(+29 / -2 there).
- **The response shape is unchanged.** No key is added or removed. The
stored row stays where the layered answer already reports a stored row,
beside the effective layer, with its own scope.
- **The registry half needs no call here.** The code layer reads the
loader's set (`lookupArtifactItem`, blind to tenant-authored rows)
before the registry's bare slot, and a shipped name is one that set
holds by definition. So `isStoredFlowEntryOfShippedName` would add an
unreachable branch.
- **The lock and provenance flags are unchanged.** They already resolved
from the code layer first.
## Why
- Triage direction `5923270373`: "In `getMetaItemLayered`, the effective
layer for a shipped flow name is the loader's body, decided by the
predicate PR #20942 / #20994 put on the list and the by-name read. ⛔ No
fourth precedence path." And: "The stored row appears **as a shadowed
layer**, with its own provenance, never as the effective layer under the
package's lock flags."
- ADR-0126 §2 (`flow` is Regime C): "⛔ Never silent override, never an
overlay read path". ADR-0131 D6: managed definitions are sealed.
- #20761's ruling `5904938166`, rule 1: a body's package-provenance
stamps are display only.
- The method's own docblock, and the spec's description of the layered
response, say the effective layer is what the ordinary by-name read
returns. For a shipped flow name that is now true.
What becomes of the stored rows themselves (keep, refuse, migrate)
belongs to #15206. This PR does not decide it.
## Why this PR is `Part of`: the published-snapshot door does not follow
The triage expected the published-snapshot read to follow the effective
layer automatically. Measured, it does not.
- `GET /api/v1/meta/flow/NAME/published`
(`packages/rest/src/rest-server.ts`, about `:8413`–`:8425`) reads the
layered answer, but it picks a layer itself: when a stored layer is
present it serves that layer, and it never reads the effective one.
- Its dispatcher twin in `packages/runtime/src/domains/meta.ts` (about
`:1121`–`:1137`) has the same shape, by source reading. It was not
measured: the dogfood stack routes through the REST transport.
- So, with the stored row kept as a shadowed layer as the triage
requires, that door still answers `200` with the stored body, both
before and after this change.
The dispatch said to stop there and report, and not to edit that door in
this card. The measurement and the options are in the report on #21002.
#21002 remains open for that half.
## Repro, before and after
Showcase composition on a database file, cold boot. A stored row is at
rest under a shipped flow name, with a body that can be told apart from
the loader's. There is also an organization-scoped row under a second
shipped name, and an environment-wide row under a name no package ships.
| Door or reading | `origin/main` `2f2fa11d75` | this branch |
|---|---|---|
| `/meta/flow/NAME/layers`, shipped name with a stored row: the
effective layer | 200, the stored body, under the package's provenance
and package id | 200, the loader's body, same flags |
| the same answer: the stored row | reported as a separate layer,
environment scope | unchanged: reported, shadowed |
| the deprecated layers flag on the by-name door | 200, effective layer
is the stored body | 200, effective layer is the loader's body |
| `GET /meta/flow/NAME` | 200, the loader's body | unchanged |
| `GET /meta/flow`, the entry for NAME | the loader's body | unchanged |
| `GET /meta/flow/NAME/published` | 200, the stored body | **unchanged:
200, the stored body** (see above) |
| control: a shipped name with no stored row, layers | effective layer
is the loader's body, no stored layer | unchanged |
| control: the same name, published | `501 NOT_IMPLEMENTED` (this kernel
has no code/package store) | unchanged |
| control: a shipped name with an organization-scoped row only, layers |
effective layer is the loader's body, no stored layer | unchanged |
| control: an unshipped name with a stored row, layers | effective layer
is the stored body | unchanged |
| control: the same name, published | 200, the stored body | unchanged |
## Pins
- **Unit:**
`packages/metadata-protocol/src/protocol.flow-layered-shipped-name.test.ts`,
9 cases. It reuses the registry double of PR #20994's unit pin: the real
`SchemaRegistry` key shapes, its `getItem` precedence (the bare slot
first) and its artifact lookup.
- A shipped name with a stored row: the effective and code layers are
the loader's body, the stored row is reported with its own scope, and
the package's flags stand. This holds before and after the row is
hydrated.
- The layered read, the by-name read and the list answer one and the
same body.
- The package-scoped read and the plural type spelling answer the same.
- A row bound to the shipping package, or one whose body claims the
package's stamps, is judged by name alone.
- Controls: an unshipped name keeps its stored row as the effective
layer; a shipped name with no row is unchanged; an organization-scoped
row is out of reach; an overlay-regime type keeps overlay-wins.
- **Dogfood cold boot:**
`packages/qa/dogfood/test/flow-shipped-name-layered-read.dogfood.test.ts`,
8 cases, a new file.
- The layered door reports the loader's body as the effective layer,
under the package's flags.
- The stored row is still reported, as a shadowed layer of its own
scope.
- The layered door, the by-name read and the list answer one and the
same body.
- The deprecated layers flag answers the same.
- Three controls: a shipped name with no stored row, an
organization-scoped row, and an unshipped name.
- `flow-shipped-name-by-name-read.dogfood.test.ts` and
`flow-provenance-server-held.dogfood.test.ts` are not touched.
- The published-snapshot door is **not** pinned. The file's header says
why.
## Verification, at head `39ed9ac48a`
`protocol.ts` and both pins are byte-identical between `5cdb27e44d` and
`39ed9ac48a`. The last commit adds only the changeset and the ledger
row.
- `pnpm --filter @objectstack/metadata-protocol exec vitest run
--maxWorkers=2` (the whole package), at `39ed9ac48a`: 196 files passed,
3 skipped; 2905 tests passed, 19 skipped.
- `pnpm --filter @objectstack/metadata-protocol run typecheck`: exit 0.
`tsc --listFiles` includes the new unit pin.
- Dogfood, `vitest run` over four files: the new pin, PR #20994's
`flow-shipped-name-by-name-read`, PR #20942's
`flow-shipped-name-stored-row-boot` and `flow-provenance-server-held`. 4
files, 36 tests passed. The metadata-protocol `dist` carries the fix:
the guard's text is in 2 built files.
- `pnpm --filter @objectstack/dogfood run typecheck`: exit 0.
`--listFiles` includes the new pin.
- **Red before:** on the `origin/main` build of metadata-protocol, the
layered door's effective layer for the subject was the stored body. The
table above shows this.
**Ablation.** The fix was committed first (`d690943261`). Each leg ran
through `scripts/ablation-replace.mjs` and deleted the predicate clause
from the effective-layer binding. The anchor hit once, and the blob
changed from `6056394ec7a6` to `ed01c7ddc863`.
| Leg | Resolution | Result |
|---|---|---|
| A1, the unit pin | `./protocol.js` from source, no rebuild | 5 failed,
4 passed. The 5 are every shipped-name case; the 4 controls pass. |
| A2, the dogfood pin | the metadata-protocol `dist`, rebuilt after the
mutation | 3 failed, 5 passed. Failed: the effective layer, the
three-way agreement and the deprecated flag. Passed: the store check,
the shadowed-row report and the three controls. |
- **A2 dist proof:** `scripts/ablation-dist-preflight.mjs` found the
guard absent from all 24 built files after the mutated build.
- **Restores:** each restore was proven: the blob equals HEAD, and `git
diff HEAD` is empty. After the restored build, the guard is present in 2
built files and the working tree is clean against HEAD.
- **A first A1 attempt was a no-op.** The replacement text was a
substring of the anchor, so the tool refused it before any test ran and
restored the file. It produced no measurement.
**Derived gates.** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --commands` printed 74 commands for this tree
at `39ed9ac48a`. All 74 were run, each exit code captured before any
pipe. `--ran` reconciliation: 74 derived, 74 run, 0 NOT-MEASURED, 0
unrun.
- **First pass:** `check:dual-build-cjs-loads` exited 3, `PREREQUISITE
NOT MET`. Eight packages outside this diff had no `dist/` in this fresh
worktree. After building those eight (all turbo cache hits), it exited
0.
- **Roster gates:** the ten roster gates whose roster sits beside a path
of this diff were also run, all exit 0. They are
`check-changeset-fixed`, `check-published-list-mirrors` (plain and
`--self-test`), `check:authz-resolver`, `check:console-injection`,
`check:engine-double-contract`, `check:error-code-casing`,
`check:i18n-stale-fill`, `check:published-readme-exports` and
`check-dts-references --self-test`.
- **Base:** `origin/main` has not moved since the branch point
`2f2fa11d75`.
**Lint, a proven narrowing of `pnpm lint` (the repo-wide run is CI's),
at `39ed9ac48a`:**
1. **Population, from eslint's own config:** of the 5 touched paths, the
config matches the 3 `.ts` files. The `.md` and `.json` files answer
"File ignored because no matching configuration was supplied."
2. **Count, from `--format json`:** 5 results. The 3 linted files have 0
errors and 0 warnings.
3. **Invariance:** `eslint.config.mjs` never enables type-aware linting.
All seven `parserOptions` blocks are `ecmaVersion` and `sourceType`
only, with no `project`. The only other files the config reads are
`scripts/slot-lookup-baseline.json` and
`scripts/query-options-erasure-baseline.json`, and this diff touches
neither. So the diff cannot move the verdict on any untouched file.
**NOT MEASURED locally, declared to CI:**
- Test Core shards, Temporal Conformance, the full Dogfood Regression
Gate and Dogfood Verify CLI.
- Build Core and the workspace type-check lanes.
- The runtime dispatcher's published twin (source reading only).
## Deviations
1. **`Part of #21002`, not a closing line.** The dispatch named a
closing line. The published-snapshot door half of the card is measured
unresolved and is now a decision for the seat, so this PR does not close
the card. The seat can rewrite the first line if it rules that half out
of the card.
2. **`scripts/engine-double-contract.pinned.json`, one generated row.**
The new unit pin's engine double has a `findOne`, so
`check:engine-double-contract` requires the coverage ledger to learn the
file, through `--write`. The diff is exactly that one row. PR #20994 has
the same precedent.
3. **No published-snapshot pin.** The dispatch said to stop and report
if that door picks a layer by itself. It does, so the door is measured
and reported here, not pinned.
## Acceptance notes
- **Unchanged, and named:**
- every other metadata type (the predicate gates on `flow` first);
- flow names no managed package ships;
- organization-scoped flow rows, which this read never reaches because
`flow` declares no org override;
- the lock, provenance and affordance flags, which already resolved from
the code layer.
- **For an unshipped name with a stored row,** the layered door's code
layer is the stored body (measured on both trees). The code-layer
fallback reaches the registry's bare slot, which holds the hydrated row.
The spec describes that layer as null when no artifact ships the item.
This is reported separately and is not touched here.
- **In the showcase composition,** the published-snapshot door answers
`501 NOT_IMPLEMENTED` for a shipped flow with no stored row. That kernel
has no code/package store for it to fall back to. This bears on what
that door could answer for a shipped name, so it is part of the report.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2821e9f commit 94990a2
5 files changed
Lines changed: 658 additions & 2 deletions
File tree
- .changeset
- packages
- metadata-protocol/src
- qa/dogfood/test
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9035 | 9035 | | |
9036 | 9036 | | |
9037 | 9037 | | |
9038 | | - | |
| 9038 | + | |
| 9039 | + | |
| 9040 | + | |
| 9041 | + | |
9039 | 9042 | | |
9040 | 9043 | | |
9041 | 9044 | | |
| |||
9369 | 9372 | | |
9370 | 9373 | | |
9371 | 9374 | | |
9372 | | - | |
| 9375 | + | |
| 9376 | + | |
| 9377 | + | |
| 9378 | + | |
| 9379 | + | |
| 9380 | + | |
| 9381 | + | |
| 9382 | + | |
| 9383 | + | |
| 9384 | + | |
| 9385 | + | |
| 9386 | + | |
| 9387 | + | |
| 9388 | + | |
| 9389 | + | |
| 9390 | + | |
| 9391 | + | |
| 9392 | + | |
| 9393 | + | |
| 9394 | + | |
| 9395 | + | |
| 9396 | + | |
| 9397 | + | |
| 9398 | + | |
| 9399 | + | |
9373 | 9400 | | |
9374 | 9401 | | |
9375 | 9402 | | |
| |||
0 commit comments