You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
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
Filed from PR #30409 (card #30326, server half), the dev's acceptance note "not covered" and the seat ACCEPT 6655279987. ⛔ Not a claim. Triage sets the grade.
Business reason. The compatibility check exists so an app written for another platform version does not break a customer's deployment. After PR #30409 the marketplace install door (POST /api/v1/marketplace/install-local) tells the installer when the check was skipped. The package install door POST /api/v1/packages still does not: the administrator who installs a package with no engines.protocol there reads only success, and only the server log says it was not checked.
Reader who acts.domain:server, packages/runtime/src/domains/packages.ts (~L1750, assertProtocolCompat(manifest), its verdict dropped).
What to do
Answer the same optional notice the install-local door answers (protocolCheckSkipped: reason, packageId, protocolVersion, message, plus requiredRange / rangeSource for unparsed-range), read from the verdict assertProtocolCompat now returns (ProtocolCompatAdmitted, PR #30409), never a second reading of the range. Omit it for a checked range. One spelling with the install-local door: share the mapping (protocolCheckSkippedOf) rather than restating it. Pin a no-range install, an unparsed range and a satisfied-range control.
Serial after PR #30409 merges. If the answer is a published packages/spec schema, report it rather than deciding in the PR (#30326's own rule). Dedupe: packages install protocolCheckSkipped, POST /api/v1/packages engines.protocol: none. New.
Claim: PM loop round 1
Session: session_01Utp6CXCS98uhsFQYk64epE (seat) · dev = project card thread session_01Utp6CaqrWFKRoka7Myh79f
Account: os-bill
Branch: claude/project-thread-xmwfp7 (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-30412
Domain: domain:server
Seat: domain:server#6
File surface: packages/runtime/src/domains/packages.ts and the shared protocolCheckSkipped mapping's home from PR #30409, with tests; content/docs/** only for sentences this PR makes false (not releases/**); one changeset. ⛔ packages/spec/**, ui/**, skills/**, docs/adr/**, .claude/**, AGENTS.md (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (opus; dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: yes (widening) — the package install door gains the optional protocolCheckSkipped notice the install-local door already answers (precedent PR #30409); no new key. The seat reviews the declaration at TIER_DEFAULT
Metadata-protocol: none
Responsibility: packages/runtime/src/domains/packages.ts drops the assertProtocolCompat verdict, so a no-range install reads only success | the install-local door already answers the notice (PR #30409); this door does not | every administrator installing through POST /api/v1/packages
Thread-read: 6656374504
Premise: holds (seat read on c5800818: assertProtocolCompat(manifest) at L1750, verdict unused)
Serial constraints cleared: PR #30409 (#30326 server half) merged; seat 5 yielded the card to this seat (coordinator relay 12:25Z)
Order: project file server-seat6/dispatch-30412.md, delivered to the card thread.
Card thread session_01Utp6CaqrWFKRoka7Myh79f · branch claude/project-thread-xmwfp7 (no commits) · Claim 6657995090 · no PR · read on origin/main989ae42
Status: needs_decision. The order's stop line fired: this door's answer is a published packages/spec contract, so the notice cannot be reused here without a spec change. Four readings, all on 989ae42:
The shared mapping cannot be imported from runtime.protocolCheckSkippedOf and ProtocolCheckSkipped are module-private in packages/cloud-connection/src/marketplace-install-local-plugin.ts (L733-783). @objectstack/cloud-connection depends on @objectstack/runtime (its package.json), so runtime cannot call it. One spelling for both doors means moving it down to @objectstack/metadata-coreprotocol-handshake.ts, beside ProtocolCompatAdmitted.
L1750 is the fallback arm only.packages/runtime/src/domains/packages.ts L1750 runs only when no protocol service resolves. The composed door calls protocolSvc.installPackage (packages/metadata-protocol/src/protocol-package-install.ts L274), which runs the handshake itself, drops the verdict and returns the spec type InstallPackageResponse (packages/spec/src/kernel/package-registry.zod.ts L404: package, message, dependencyResolution). Bringing the verdict out without a second reading of the range needs either a key on that spec schema or a non-spec side channel in metadata-protocol.
The answer is bound to a published contract.PackageApiContracts.installPackage (packages/spec/src/api/package-api-assembled.zod.ts L285-290) names output: PackageInstallResponseSchema (packages/spec/src/api/package-api.zod.ts L527: data = package, dependencyResolution, namespaceConflicts, message). The wire answers data = the bare InstalledPackage row instead (pinned in packages/client/src/packages-write-envelope.test.ts L159-176: expect(installed).toEqual(registry.getPackage(MANIFEST.id))). The install-local answer has no spec schema, so triage 6656374504's "adds no new protocol key" holds there and not here.
The door's measured UI caller would see a false alarm. The Console's New package dialog (ui/packages/app-shell/src/views/metadata-admin/PackageFormDialog.tsx L595-610) POSTs /api/v1/packages with { id, name, version, type, … } and no engines.protocol (the create form has no protocol field: grep -n "engines\|protocol" on that file is zero hits). Every package created in Studio is a no-range install, so the notice ("may not work on this platform version") would fire on every create. The Console's Import package file flow goes to /api/v1/marketplace/install-local (PackagesPage.tsx L1559), which already answers the notice.
Governing text: dispatch order "If the shape cannot be reused without a packages/spec change, stop and report needs_decision"; card #30412 "If the answer is a published packages/spec schema, report it rather than deciding in the PR"; AGENTS.md Prime Directive #12 (contract-first).
Options
A. Spec first, then this card. A spec card declares an optional protocolCheckSkipped on the install answer (one shared schema the install-local answer can also name) and settles where it sits, given that the declared data.package and the wire's bare row already disagree. Then this card moves the mapping to metadata-core, has the metadata-protocol primitive return the verdict, and spreads it on both arms in runtime. It also needs a rule that a package created in Studio does not get the warning (reading 4). Cost: two cards, about M (spec) plus M (server, four packages: metadata-core, metadata-protocol, runtime, cloud-connection).
B. Undeclared key on the bare row, no spec change. Put protocolCheckSkipped on data beside the row's keys, as install-local does. Cost: about M across the same four packages. It breaks the order's stop line and Prime Directive #12: the client's InstalledPackage type and the spec contract would both say nothing about a key the wire sends. The client pin above goes red for a no-range manifest and would have to change. The Studio false alarm stays.
C. Do not answer it on this door; record why on #30412 (recommended). The door's real UI caller creates a package on this platform, where "no range" is the normal case, not a risk. Third-party package files reach the install-local door, which already tells the installer. The server warn line stays as it is. Reopen only if someone names a real third-party installer that uses POST /api/v1/packages (the SDK's client.packages.install is the only other caller found in this repo). Cost: zero code.
Four axes
Real business need: the measured UI caller is New package (no range by construction), and imports already get the notice. A warns only if the Studio exemption is also built; B warns falsely on every create. C matches what is measured.
Keeping AI from writing it wrong: B teaches that an undeclared answer key is fine, which is exactly the drift PackageApiContracts exists to stop. A keeps declared equal to served. C leaves nothing to get wrong.
No scope creep at startup stage: A adds a protocol key and two cards for a door whose measured caller does not need it. C is the narrow answer.
Recommendation: C. If the maintainer wants the notice on this door anyway, A, with the Studio exemption ruled in the same answer. B is not recommended.
{
"issue": 30412,
"status": "needs_decision",
"branch": "claude/project-thread-xmwfp7",
"pr": null,
"session": "session_01Utp6CaqrWFKRoka7Myh79f",
"premise_still_valid": false,
"summary": "Stopped before code on the order's spec stop line. The POST /api/v1/packages answer is bound to the published PackageApiContracts.installPackage output PackageInstallResponseSchema, so the notice cannot be reused without a packages/spec change. Also measured: protocolCheckSkippedOf is module-private in cloud-connection, which depends on runtime; L1750 is only the no-protocol fallback, and the composed arm drops the verdict inside metadata-protocol installPackage, which returns spec InstallPackageResponse; the Console New package dialog POSTs this door with no engines.protocol, so the notice would fire on every Studio create. No worktree, no commits, no PR.",
"tests": "none run: needs_decision before code (read-only measurement on origin/main 989ae42d)",
"gates": "none run: no diff",
"dogfood_battery": "n/a: no PR",
"mcp_calls": "3 (all reads): issue_read get #30412, issue_read get_comments #30412 twice; no write tool",
"api_writes": "1: this comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30412/comments)",
"open_questions": [
{
"question": "Should POST /api/v1/packages tell the installer that the protocol check was skipped, given that its answer is a published spec contract and its measured UI caller (Console New package) is a no-range install by construction?",
"options": [
"A: spec card first (declare an optional protocolCheckSkipped on the install answer and settle data.package vs the bare row), then this card across metadata-core, metadata-protocol, runtime and cloud-connection, with a Studio-create exemption",
"B: undeclared key on the bare row, no spec change (breaks the stop line, Prime Directive #12 and the client pin; false alarm on every Studio create)",
"C: do not answer it on this door; record why on #30412; imports already get the notice through install-local"
],
"recommendation": "C, because the door's measured caller creates packages on this platform, imports already carry the notice, and A adds a protocol key and two cards with no measured need; A if the maintainer wants it anyway"
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: b · reach: POST /api/v1/packages answers data = the bare InstalledPackage row (pinned in packages/client/src/packages-write-envelope.test.ts L159-176) while the published PackageApiContracts.installPackage output PackageInstallResponseSchema declares data.package · Seam: spec:PackageApiContracts.installPackage.output → runtime:packages/runtime/src/domains/packages.ts deps.success(pkg) · dedupe words: PackageInstallResponseSchema bare row, installPackage contract data.package"
]
}
Activity
objectstack-fleet commentedon Nov 5, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p3 kept ·
domain:server· 2026-11-05T11:04Z⛔ Not a claim.
POST /api/v1/packagesdrops theassertProtocolCompatverdict, so an install with noengines.protocolreads only success.protocolCheckSkippednotice shape the install-local door already serves (PR feat(cloud-connection,metadata-core): an install the protocol handshake admitted unchecked says so in its answer #30409), so it adds no new protocol key.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE
Claim: PM loop round 1
Session:
session_01Utp6CXCS98uhsFQYk64epE(seat) · dev = project card threadsession_01Utp6CaqrWFKRoka7Myh79fAccount:
os-billBranch:
claude/project-thread-xmwfp7(harness-pinned thread branch; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-30412Domain:
domain:serverSeat:
domain:server#6File surface:
packages/runtime/src/domains/packages.tsand the sharedprotocolCheckSkippedmapping's home from PR #30409, with tests;content/docs/**only for sentences this PR makes false (notreleases/**); one changeset. ⛔packages/spec/**,ui/**,skills/**,docs/adr/**,.claude/**,AGENTS.md(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier (opus; dispatch-gates --tier: no path-derived mandate),effort: highClause-②: yes (widening) — the package install door gains the optional
protocolCheckSkippednotice the install-local door already answers (precedent PR #30409); no new key. The seat reviews the declaration at TIER_DEFAULTMetadata-protocol: none
Responsibility:
packages/runtime/src/domains/packages.ts drops the assertProtocolCompat verdict, so a no-range install reads only success | the install-local door already answers the notice (PR #30409); this door does not | every administrator installing through POST /api/v1/packagesThread-read: 6656374504
Premise: holds (seat read on
c5800818:assertProtocolCompat(manifest)at L1750, verdict unused)Serial constraints cleared:
PR #30409 (#30326 server half) merged; seat 5 yielded the card to this seat (coordinator relay 12:25Z)Order: project file
server-seat6/dispatch-30412.md, delivered to the card thread.objectstack-fleet commentedon Nov 5, 2026
domain:server#6 · os-bill · session_01Utp6CXCS98uhsFQYk64epE
os-dev-report
Card thread
session_01Utp6CaqrWFKRoka7Myh79f· branchclaude/project-thread-xmwfp7(no commits) · Claim 6657995090 · no PR · read onorigin/main989ae42Status: needs_decision. The order's stop line fired: this door's answer is a published
packages/speccontract, so the notice cannot be reused here without a spec change. Four readings, all on 989ae42:protocolCheckSkippedOfandProtocolCheckSkippedare module-private inpackages/cloud-connection/src/marketplace-install-local-plugin.ts(L733-783).@objectstack/cloud-connectiondepends on@objectstack/runtime(its package.json), so runtime cannot call it. One spelling for both doors means moving it down to@objectstack/metadata-coreprotocol-handshake.ts, besideProtocolCompatAdmitted.packages/runtime/src/domains/packages.tsL1750 runs only when noprotocolservice resolves. The composed door callsprotocolSvc.installPackage(packages/metadata-protocol/src/protocol-package-install.tsL274), which runs the handshake itself, drops the verdict and returns the spec typeInstallPackageResponse(packages/spec/src/kernel/package-registry.zod.tsL404:package,message,dependencyResolution). Bringing the verdict out without a second reading of the range needs either a key on that spec schema or a non-spec side channel in metadata-protocol.PackageApiContracts.installPackage(packages/spec/src/api/package-api-assembled.zod.tsL285-290) namesoutput: PackageInstallResponseSchema(packages/spec/src/api/package-api.zod.tsL527:data=package,dependencyResolution,namespaceConflicts,message). The wire answersdata= the bareInstalledPackagerow instead (pinned inpackages/client/src/packages-write-envelope.test.tsL159-176:expect(installed).toEqual(registry.getPackage(MANIFEST.id))). The install-local answer has no spec schema, so triage 6656374504's "adds no new protocol key" holds there and not here.ui/packages/app-shell/src/views/metadata-admin/PackageFormDialog.tsxL595-610) POSTs/api/v1/packageswith{ id, name, version, type, … }and noengines.protocol(the create form has no protocol field:grep -n "engines\|protocol"on that file is zero hits). Every package created in Studio is ano-rangeinstall, so the notice ("may not work on this platform version") would fire on every create. The Console's Import package file flow goes to/api/v1/marketplace/install-local(PackagesPage.tsxL1559), which already answers the notice.Governing text: dispatch order "If the shape cannot be reused without a
packages/specchange, stop and reportneeds_decision"; card #30412 "If the answer is a publishedpackages/specschema, report it rather than deciding in the PR"; AGENTS.md Prime Directive #12 (contract-first).Options
A. Spec first, then this card. A spec card declares an optional
protocolCheckSkippedon the install answer (one shared schema the install-local answer can also name) and settles where it sits, given that the declareddata.packageand the wire's bare row already disagree. Then this card moves the mapping to metadata-core, has the metadata-protocol primitive return the verdict, and spreads it on both arms in runtime. It also needs a rule that a package created in Studio does not get the warning (reading 4). Cost: two cards, about M (spec) plus M (server, four packages: metadata-core, metadata-protocol, runtime, cloud-connection).B. Undeclared key on the bare row, no spec change. Put
protocolCheckSkippedondatabeside the row's keys, as install-local does. Cost: about M across the same four packages. It breaks the order's stop line and Prime Directive #12: the client'sInstalledPackagetype and the spec contract would both say nothing about a key the wire sends. The client pin above goes red for a no-range manifest and would have to change. The Studio false alarm stays.C. Do not answer it on this door; record why on #30412 (recommended). The door's real UI caller creates a package on this platform, where "no range" is the normal case, not a risk. Third-party package files reach the install-local door, which already tells the installer. The server warn line stays as it is. Reopen only if someone names a real third-party installer that uses
POST /api/v1/packages(the SDK'sclient.packages.installis the only other caller found in this repo). Cost: zero code.Four axes
PackageApiContractsexists to stop. A keeps declared equal to served. C leaves nothing to get wrong.Recommendation: C. If the maintainer wants the notice on this door anyway, A, with the Studio exemption ruled in the same answer. B is not recommended.
{ "issue": 30412, "status": "needs_decision", "branch": "claude/project-thread-xmwfp7", "pr": null, "session": "session_01Utp6CaqrWFKRoka7Myh79f", "premise_still_valid": false, "summary": "Stopped before code on the order's spec stop line. The POST /api/v1/packages answer is bound to the published PackageApiContracts.installPackage output PackageInstallResponseSchema, so the notice cannot be reused without a packages/spec change. Also measured: protocolCheckSkippedOf is module-private in cloud-connection, which depends on runtime; L1750 is only the no-protocol fallback, and the composed arm drops the verdict inside metadata-protocol installPackage, which returns spec InstallPackageResponse; the Console New package dialog POSTs this door with no engines.protocol, so the notice would fire on every Studio create. No worktree, no commits, no PR.", "tests": "none run: needs_decision before code (read-only measurement on origin/main 989ae42d)", "gates": "none run: no diff", "dogfood_battery": "n/a: no PR", "mcp_calls": "3 (all reads): issue_read get #30412, issue_read get_comments #30412 twice; no write tool", "api_writes": "1: this comment via post-stamped (POST /repos/objectstack-ai/objectstack/issues/30412/comments)", "open_questions": [ { "question": "Should POST /api/v1/packages tell the installer that the protocol check was skipped, given that its answer is a published spec contract and its measured UI caller (Console New package) is a no-range install by construction?", "options": [ "A: spec card first (declare an optional protocolCheckSkipped on the install answer and settle data.package vs the bare row), then this card across metadata-core, metadata-protocol, runtime and cloud-connection, with a Studio-create exemption", "B: undeclared key on the bare row, no spec change (breaks the stop line, Prime Directive #12 and the client pin; false alarm on every Studio create)", "C: do not answer it on this door; record why on #30412; imports already get the notice through install-local" ], "recommendation": "C, because the door's measured caller creates packages on this platform, imports already carry the notice, and A adds a protocol key and two cards with no measured need; A if the maintainer wants it anyway" } ], "security_findings": "none", "out_of_scope_findings": [ "class: b · reach: POST /api/v1/packages answers data = the bare InstalledPackage row (pinned in packages/client/src/packages-write-envelope.test.ts L159-176) while the published PackageApiContracts.installPackage output PackageInstallResponseSchema declares data.package · Seam: spec:PackageApiContracts.installPackage.output → runtime:packages/runtime/src/domains/packages.ts deps.success(pkg) · dedupe words: PackageInstallResponseSchema bare row, installPackage contract data.package" ] }Report taken 2026-11-05T12:33Z.