Repository navigation
fix(spec): PackageInstallResponseSchema declares the bare installed row the install door serves - #30593
fix(spec): PackageInstallResponseSchema declares the bare installed row the install door serves#30593objectstack-fleet[bot] wants to merge 5 commits into
Conversation
…ow the install door serves
POST /api/v1/packages answers success(pkg): the InstalledPackage row as
data. The published contract declared data: { package, dependencyResolution?,
namespaceConflicts?, message? }, a wrapper no surface sends. The contract now
follows the wire; a contract-vs-wire pin in the client harness drives the real
dispatcher and parses its answer with PackageApiContracts.installPackage.output.
Claude-Session: https://claude.ai/code/session_01WGufzgC3iduZ3nT4eSzSkT
Co-authored-by: Claude <noreply@anthropic.com>
…, add the changeset Claude-Session: https://claude.ai/code/session_01WGufzgC3iduZ3nT4eSzSkT Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P Co-authored-by: Claude <noreply@anthropic.com>
…ocol narrowing at patch
The schema now refuses the { package } wrapper it accepted and the
PackageInstallResponse type loses four members, so the Clause-2 line
carries the narrowing arm. An API answer shape is nothing a metadata
author writes, so the kind is none and the level patch. The ADR-0087
disposition is not-required (no-migration-prescription), with D8 named.
Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 14 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 170 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 74d921b447c3630b7115cbeb7b912fb16be3bdb0 && git checkout 74d921b447c3630b7115cbeb7b912fb16be3bdb0
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin bdbaf80cdb01ececd5af069757fb1f35c653bb8a 89a687971f528d1578b45dd35c9ae3f669bc46ca && git checkout -B drift-repro bdbaf80cdb01ececd5af069757fb1f35c653bb8a && git merge --no-ff 89a687971f528d1578b45dd35c9ae3f669bc46ca
node scripts/docs-audit/affected-docs.mjs --json bdbaf80cdb01ececd5af069757fb1f35c653bb8a
|
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Contract reviewServed-tier: Reviewed read-only against card #30464 (body and every comment, 6658640900 through 6664176068), PR #30593's body and file list, the net diff ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Implemented-by: VERDICT: PASS Generated by Claude Code |
…rowing A non-protocol breaking change ships patch and keeps its banner; the line follows the spelling the other narrowing changesets use. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P
|
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P Regen-provenance: 6664812981 · 维护者速读
席位核对ACCEPT · head
Generated by Claude Code |
Requested by Sales · project thread
domain:spec#2 · os-sales · session_01L6bhgVugtCCwBs98FeR27P
Fixes #30464
Clause-②: yes (narrowing) —
PackageInstallResponseSchemanow accepts the bare installed row the door serves, which it refused, and refuses the{ package }wrapper it accepted;PackageInstallResponse['data']losespackage,dependencyResolution,namespaceConflictsandmessage. No export is added, removed or renamed.Metadata-protocol: none — the shape of an API answer, not anything a metadata author writes.
Skills-docs: none —
git grep -nE 'PackageInstallResponse|data\.package\b' -- skills/ content/docs/ ':!content/docs/references'has 0 hits; thedata.packagereads inpackages/andui/source are other answers (override declarations, the permission-set clone, the marketplace detail), none the install answer.维护者速读
POST /api/v1/packages)的应答形状改成服务器实际返回的样子:data就是安装后的包记录本身,不再声明一个从未发送过的{ package, … }外层包装。服务器和官方客户端的行为都不变。data.package,实际拿到undefined;官方客户端早已按真实返回改过(client.packagesdeclares envelopes two mounted surfaces do not emit:getdiverges between them, andinstall/enable/disabledeclare{ package }where the only serving surface sends the bare row #12034),只剩已发布契约是错的。依赖它的 Package install: POST /api/v1/packages installs a package with no protocol range unchecked and says so only in the server log (the install-local door now answers it) #30412 要在这个形状上决定安装门是否加提示。data.package等四个成员的 TypeScript 代码升级后会编译报错(这些代码运行时本来就读到 undefined),changeset 写明了改法。回滚即撤本 PR。packages/spec/src/api/package-api.zod.ts的PackageInstallResponseSchema(data那一行);packages/client/src/packages-write-envelope.test.ts的#30464块(真实安装门的应答原样交给契约解析);.changeset/30464-install-response-bare-row.md。pnpm --filter @objectstack/client exec vitest run src/packages-write-envelope.test.ts,预期 6 条全绿;把data换回 main 上的包装(连同dropped-refinements.baseline.json里那三行)并重建 spec 后,#30464块的 2 条转红。What changes
The published contract follows the wire; the door is not changed. Triage audit 6658640900: "The published contract is wrong, not the door … The change corrects the published schema to match the wire".
packages/spec/src/api/package-api.zod.ts:PackageInstallResponseSchema.dataisInstalledPackageSchema, reused rather than restated: theInstalledPackagerowSchemaRegistry.installPackagerecorded, which the door answers assuccess(pkg)with status201on both install arms. The docblock says why, names the authoring stage of the row (this door computes nowritable/disableable), and names the pin. The type namesPackageInstallResponse/PackageInstallResponseParsedand thePackageApiContracts.installPackagebinding are unchanged.packages/spec/src/api/package-api.test.ts: the two cases that pinned the wrapper are replaced by three: the bare row parses; the{ package }wrapper is refused atdata.manifestanddata.source;PackageApiContracts.installPackage.outputis this schema.packages/client/src/packages-write-envelope.test.ts: a contract-vs-wire block. A realSchemaRegistryand the realHttpDispatcher.handlePackages('', 'POST', …)produce the 201 body, which goes untouched toPackageApiContracts.installPackage.output.safeParse: it parses green,dataequals the registry's row and the parse strips no key the door sent; the wrapper built from the door's own row is refused. Nothing in the block writes the expected body by hand.packages/spec/dropped-refinements.baseline.json: the threeapi/PackageInstallResponsesites move fromdata.package.manifest.…todata.manifest.…: the same three refinements, their path moved with the shape (the spec build gates this ledger).content/docs/references/api/package-api.mdx;docs/audits/2026-07-unknown-key-strictness-ledger.counts/api.md(api/501 → 499 sites: the wrapper object and the conflict-entry object are gone).@objectstack/spec:patch) with both declaration lines, the FROM → TO mapping, the consumer fix and the ADR-0087 dispositionnot-required (no-migration-prescription).Tests
Head
3789cc39e(this branch merged withorigin/mainatc23eafa88).Package suites, typecheck, eslint
pnpm --filter @objectstack/spec test: Test Files 815 passed (815), Tests 25644 passed, 1 todo.pnpm --filter @objectstack/client test: Test Files 54 passed (54), Tests 699 passed. The pin file alone: 6 passed (6).pnpm --filter @objectstack/runtime test: Test Files 543 passed (543), Tests 8655 passed, 19 skipped. The suites that drive the install door (handlePackages('', 'POST', …)): the eightpackages/runtime/src/domains/packages-install-*.test.ts,packages-ensure-customization.test.ts,http-dispatcher.test.ts.pnpm --filter @objectstack/spec run typecheck: exit 0 (test layer: 52 files / 240 errors / 131 signatures held in the existing debt ledger, unchanged).pnpm --filter @objectstack/client run typecheck: exit 0 (test layer 0 / 0 / 0).--no-inline-config) over the three changed TypeScript files: exit 0, no findings.Dogfood battery (owed by the narrowing arm)
pnpm --filter @objectstack/dogfood testunder the verify lock, after a full workspace build (turbo run build, 119/119 tasks):VERDICT command-exit 0; Test Files 420 passed, 3 skipped (423); Tests 3496 passed, 36 skipped (3532); no failure.Ablation: main's wrapper put back on `data`
scripts/ablation-replace.mjsreplaced thedata:line with main's{ package, dependencyResolution?, namespaceConflicts?, message? }object (anchor 1 → 0, markerABLATION_30464) and moved the three ledger sites back todata.package.manifest.…(anchor 3 → 0): a two-file mutation, because the spec build gatesdropped-refinements.baseline.json. Spec rebuilt;ablation-dist-preflightread the marker in 2 built files.#30464cases; spec pin 2 failed, 96 passed (98), the bare-row and wrapper-refusal cases.git diff HEADempty; spec rebuilt; preflight--absent(marker absent from all 592 built files, tree clean). Client pin 6 passed (6); spec pin 98 passed (98).dist/, and its client reading was discarded.Acceptance notes
domain:server#6) has the install door answer an optionalprotocolCheckSkippednotice, as the install-local door does. With this PR the declareddatais the bareInstalledPackagerow, so where that notice sits (on the envelope besidedata, or elsewhere) is decided on that card against this shape; there is no wrapper left to add a member to.packages/runtime/**is untouched in this PR.Clause-②: yesandMetadata-protocol: semantic. Measured and read against the rules, this PR declaresyes (narrowing)andnone, atpatch:semanticis "the meaning or default of an authorable key", and this schema is an API answer; the narrowing half (the wrapper refused, four type members gone) is real on the published@objectstack/spec/apisurface. Both pairs passcheck-changeset-no-majorandcheck:adr-0087-registration, which do not judge the act;nonewithminorexits 1 (none-minor). The seat updates the claim lines.type-surface-onlyis closed to a narrowing whose schema lives inpackages/spec(predicate 2, no-spec-diff), andruntime-interface-onlyto a*.zod.ts, so a spec API-answer narrowing whose affected party is a TypeScript consumer has no exact category. It carriesno-migration-prescription, which the gate admits because its detector reads no arrow or framed table in the consumer line; the marker says so and cites D8.InstallPackageResult(packages/spec/src/contracts/package-service.ts) still declares{ package, dependencyResolution?, namespaceConflicts?, message? }. It is the in-processIPackageServiceresult, not the HTTP answer, and this PR does not touch it.Verification
Head
3789cc39e.Derived gate families: 102 run, reconciled
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 102 commands for 7 paths vs merge basec23eafa88. Each was run with its exit code captured before any pipe;--rananswers "102 derived, 102 run, 0 NOT-MEASURED, 0 UNRUN" (a derived zero: all 102 carry an exit code).check-plugin-teardown-shape --self-testneeded a positive-control commit this shallow clone lacked: fetched at depth 1, rerun exit 0 (48 cases).check:dual-build-cjs-loadsneeded 32 more packages'dist/: full build, rerun exit 0 (116 entries across 71 packages load).check:skill-examples: the first run exits 3, PREREQUISITE NOT MET, becausepackages/client-react/distheld no.d.ts. Afterpnpm --filter @objectstack/client-react build: exit 0, "283 prose examples type-check across 3 surface(s)".pnpm --filter @objectstack/spec check:generated: all 14 generated artifacts up to date.check:dev-prereqsexit 0 after the full build (107 artifacts present);check:skill-frame-freshnessexit 0.Declaration gates
check-changeset-no-major.mjs --base origin/main --eventwith apull_requestpayload carrying this body's lines: exit 0, "LEVEL AXIS: … a non-protocol change atpatch".check-adr-0087-registration.mjs --base origin/main: exit 0, "1 declared-breaking changeset(s), each carrying an ADR-0087 disposition … [clause-②-narrowing] not-required (no-migration-prescription)".yes/semantic/minor) also exits 0 on both gates, andnonebeside the oldminorexits 1 (none-minor). The gates check the declarations against the levels; which pair is true is read from the diff (Acceptance notes).Outside the derived total
$RUNNER_TEMP, the shard matrix) and have no local invocation:check-issue-citations.mjs --census,check-shard-attestation.mjs(dogfood, dogfood-verify) andcheck-test-completeness.mjs. NOT MEASURED locally; read on this PR's check-runs.origin/mainmoved 15 commits past the merge base (to48b3ae6eb) after the merge. None touches this diff's files or the install answer: the two inside its packages are the seed-apply catch inpackages/runtime/src/domains/packages.tsand the seedlandeddescribe inpackages/spec/src/api/protocol.zod.ts.🤖 Generated with Claude Code
https://claude.ai/code/session_01L6bhgVugtCCwBs98FeR27P