Repository navigation
Commit 514001a
Fixes #21002
Clause-②: yes (widening)
The published-snapshot read of a flow name a managed package ships now
answers the package's flow when a stored row of that name is at rest.
This holds on the REST route and on its runtime-dispatcher twin. This is
the second half of #21002, as triage ruled in `5924438659`: option A,
scoped by the decision, not by type. The first half, the layered read,
landed in PR #21043.
⚠️ This body follows the #20761 family's disclosure discipline. It talks
about doors, roles, codes and statuses only. It has no request body,
header or field spelling, and no seeding steps.
## What changed
**`packages/rest/src/rest-server.ts`**, the `GET
/meta/:type/:name/published` handler:
- It still reads the layered answer first. When that answer has a stored
layer, the door now asks the protocol's `isShippedFlowName` about the
answer's own type and name.
- When the predicate holds, the layered read has put the loader's body
over the stored row. The door then serves the effective layer, which is
the loader's body.
- In every other case it serves the stored layer, exactly as before. A
protocol that brings no such predicate also keeps today's answer.
**`packages/runtime/src/domains/meta.ts`**, the dispatcher twin of that
route:
- The same change, in the same place.
- `MetaDomainProtocol` gains the predicate as an optional member. It is
`Pick`ed from `ObjectStackProtocolImplementation`, not restated, so a
rename at the producer is a compile error here. This is the same move
`domains/automation.ts` makes for `packagedBaseRefusal`.
**`packages/metadata-protocol/src/protocol.ts`**, the declared
cross-lane surface the claim allows:
- `isShippedFlowName` changes from `private` to public. Its body is
unchanged.
- A docblock paragraph names the doors that ask it.
- `getMetaItemLayered`'s effective-layer decision (PR #21043) is not
touched.
**`.changeset/21002-published-door-shipped-flow.md`**:
`@objectstack/metadata-protocol` `minor`, `@objectstack/rest` `patch`,
`@objectstack/runtime` `patch`.
## How the doors learn the decision
There is one decision point, the predicate PR #21043 already calls.
- No per-type list, no new response key, no fourth precedence path, and
no second copy of the rule.
- Each door asks the protocol's own predicate about the type and name
the layered answer reports. The layered answer's type is the canonical
singular, so the predicate gets exactly the arguments
`getMetaItemLayered` used.
- `object` is never named. Its effective layer differs from its stored
layer by folding and governance, not by this decision, so it is served
byte-identically.
The predicate was private to the protocol class. A door in another
package could not reach it except by copying the rule (the flow-only
scoping plus `packagedArtifactOwner`), which the ruling forbids. So
making it public is the minimal reachability change.
## Clause ② reads `yes (widening)`, not the claim's `no`
The claim's own reading said the dev re-reads the line against the real
diff. The real diff adds one public member to a class
`@objectstack/metadata-protocol` exports, so its published declaration
grows.
- The rule `check-changeset-no-major.mjs` quotes says a purely additive
widening of a published package's public surface takes at least `minor`.
- The two in-family precedents read it the same way. PR #20817 made
`packagedBaseRefusal` public, and PR #20853 made
`tenantAuthoredWriteRefusal` public. Both were declared `Clause-②: yes
(widening)` with `@objectstack/metadata-protocol` at `minor`.
- No wire shape moves. No request key, response key or accept set
changes. `rest` and `runtime` stay `patch`: `MetaDomainProtocol` is not
exported from the runtime package entry.
If the seat rules this `no`, the revert is two lines: this body's second
line, and the changeset's `minor` back to `patch` with its own Clause
line.
## Reproduction
Showcase composition on a database file, cold boot, signed-in admin. The
stored rows were written on a first boot and read on the second. The
base is `63d1a7c378`.
| case | door | before | after |
|:---|:---|:---|:---|
| shipped flow name, stored row | REST | `200`, the stored body | `200`,
the loader's body |
| shipped flow name, stored row | dispatcher twin | `200`, the stored
body | `200`, the loader's body |
| flow name no package ships, stored row | REST and twin | `200`, the
stored body | unchanged, same bytes |
| `object`, published stored layer | REST and twin | `200`, the stored
layer | unchanged, same bytes |
"Same bytes" means the SHA-256 of the served document is equal before
and after, on both doors. The dispatcher figures come from a throwaway
probe that drove `HttpDispatcher` in-process over the booted kernel. The
probe was deleted.
## Pins
- **REST unit**, `packages/rest/src/meta-published-overlay.test.ts`: 5
new cases. They use the real protocol and the file's own engine double,
with a registry that ships one flow from a package.
- A shipped name with a stored row answers the loader's body, equal to
the layered effective layer.
- The plural type spelling reaches the same decision.
- Controls: a flow name no package ships keeps its stored row. An
`object`'s published stored row is served as stored, and its effective
layer is shown to differ. A protocol without the predicate keeps the
stored row.
- **Runtime unit**,
`packages/runtime/src/domains/meta-published-runtime-publish.test.ts`:
the same 5 cases, through the real `HttpDispatcher`.
- **Dogfood**, the new file
`packages/qa/dogfood/test/flow-shipped-name-published-door.dogfood.test.ts`:
5 cases, showcase, cold boot.
- A store check, plus the layered read putting the loader's body over
the stored row.
- The REST door answers the loader's body.
- The REST door's body equals the layered effective layer.
- Controls: a flow name no package ships keeps its stored body. An
`object`'s published stored layer is served unchanged, and its effective
layer is shown to differ.
- No existing `flow-shipped-name-*.dogfood.test.ts` file is edited.
Neither unit file gains an engine double, so
`scripts/engine-double-contract.pinned.json` is untouched.
**Why the dispatcher twin is not in the dogfood file.** The verify
harness mounts no dispatcher `/meta` catch-all. That route is reached
only on hosts that mount `@objectstack/hono`'s catch-all, so in this
composition the twin is not served at all. Driving `HttpDispatcher`
in-process from the dogfood package means importing runtime source.
`check:test-source-alias` then refuses four new dist-resolved imports
for the dogfood package (`metadata-protocol`, `observability`, `rest`,
`service-datasource`). Its remedy is to alias them to source in the
dogfood vitest config, which is outside this claim's file surface and
would change every isolated dogfood test's resolution. So the twin is
pinned at the unit level, with the real protocol and the real
dispatcher.
## Ablation
The fix was committed first. Both mutations went through
`scripts/ablation-replace.mjs`, replacing the predicate clause with a
constant false. Each leg is shown below.
- **REST door** (`rest-server.ts`), at head `292cc60f45`:
- The anchor went from 1 to 0 hits, and the blob from `a97cfde7c227` to
`418bc95a799c`.
- Unit (source-resolved): 2 failed (shipped name, plural spelling), 12
passed.
- Rebuild of `@objectstack/rest`. Then `ablation-dist-preflight
--absent` found the predicate call absent from all 6 built files.
- Dogfood (dist-resolved): 2 failed (the REST door, and its equality
with the effective layer), 3 passed (the store check and both controls).
- Restore: blob equals HEAD `a97cfde7c227` and `git diff HEAD` is empty.
After the rebuild, the preflight found the call present in 2 built
files, and the tree was clean.
- **Dispatcher twin** (`meta.ts`), at head `292cc60f45`:
- The anchor went from 1 to 0 hits, and the blob from `0c4ddceecbb8` to
`1e10bb639fc9`.
- Unit (source-resolved): 2 failed (shipped name, plural spelling), 8
passed.
- Restore: blob equals HEAD and `git diff HEAD` is empty.
## Verification
All at head `292cc60f45` unless a line names another.
- **Unit pins:** `meta-published-overlay.test.ts` 14 passed (9 existing,
5 new). `meta-published-runtime-publish.test.ts` 10 passed (5 existing,
5 new). Both at `92f242cee4`, and neither file has changed since.
- **Whole packages:**
- `@objectstack/rest`: 259 files, 5035 passed, 143 skipped, at
`b973faeca2`.
- `@objectstack/runtime` (`--project local`): 297 files, 4254 passed, 5
skipped, at `b973faeca2`.
- The only later change in either package is the reworded docblock and
one dropped fixture key in its unit file. Both files were re-run green
after it.
- `@objectstack/metadata-protocol`: 196 files passed and 3 skipped; 2930
tests passed and 19 skipped, at `92f242cee4`.
- **Dogfood:** the new file, 5 passed.
- **Typecheck:** `metadata-protocol`, `rest`, `runtime` (including
`check:test-typecheck`) and `dogfood` all exit 0. `tsc --listFiles`
counts each new or edited test file once in its own program.
- **Gates:** `dispatch-gates --repo objectstack-ai/objectstack
--commands` derived 68 families. All 68 were run, each exit code
recorded before any pipe, and every one is 0. `--ran` reports 68
derived, 68 run, 0 NOT-MEASURED, 0 UNRUN.
- The first pass, at `92f242cee4`, had two non-zero exits.
- `check:dual-build-cjs-loads` exited 3, PREREQUISITE NOT MET: 8
packages outside the diff had no dist. They were built (41 of 41 turbo
cache hits).
- `check:test-source-alias` exited 1 on the dogfood dispatcher leg,
which was then removed. The reason is under Pins.
- **Lint**, a proven narrowing:
- Population, from eslint's own config: 6 of the 7 touched paths are
linted. The changeset is ignored, with no matching configuration.
- Count, from `--format json` with the `pnpm lint` flags: 6 results, 0
errors, 0 warnings.
- Invariance: there is no type-aware linting. Every `parserOptions`
block is `ecmaVersion` and `sourceType` only. The config reads only two
baseline JSON files, and this diff touches neither. So no untouched
file's verdict can move.
- **Not measured locally, declared to CI:** the Test Core shards, the
full Dogfood Regression Gate, Temporal Conformance, Build Core, the
type-check lanes, and the runtime `repo` test project.
## Acceptance notes
- **Unchanged background fact**, per the review `5924388874`: in the
showcase composition, a shipped flow with no stored row answers `501`
`NOT_IMPLEMENTED` on the published door. That kernel has no code/package
store. This PR does not change that path.
- **Not merged with `origin/main`:** 9 commits landed since the base.
None of them touches the 7 files here. PR CI tests the merge ref.
- **Read, not edited:** `getMetaItemLayered` and the predicate's body.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VvcEokUG1tvVxkceYfR5XB)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent ba03198 commit 514001a
7 files changed
Lines changed: 598 additions & 3 deletions
File tree
- .changeset
- packages
- metadata-protocol/src
- qa/dogfood/test
- rest/src
- runtime/src/domains
| 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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14630 | 14630 | | |
14631 | 14631 | | |
14632 | 14632 | | |
| 14633 | + | |
| 14634 | + | |
| 14635 | + | |
| 14636 | + | |
| 14637 | + | |
| 14638 | + | |
| 14639 | + | |
| 14640 | + | |
| 14641 | + | |
14633 | 14642 | | |
14634 | | - | |
| 14643 | + | |
14635 | 14644 | | |
14636 | 14645 | | |
14637 | 14646 | | |
| |||
Lines changed: 273 additions & 0 deletions
| 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 | + | |
0 commit comments