Skip to content

feat(runtime): a package export names each connector map it withheld; install-local names each as incomplete - #29746

Merged
objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-vrj8cl
Nov 3, 2026
Merged

objectstack-fleet[bot] merged 9 commits into
mainfrom
claude/project-thread-vrj8cl

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Warren · project thread
Fixes #29342

Clause-②: yes (widening)
Metadata-protocol: none

One narrowing arm, named here in prose as the seat directed (amendment 6592752231): POST /marketplace/install-local now refuses a withheldMaps value that the export's own declaration refuses, answering PLUGIN_MANIFEST_INVALID before any write in either mode. Before this change the door ignored the key whatever its value. No producer wrote the key before this PR, so only a hand-written list can be refused.

维护者速读

  • 改了什么:包导出(GET /packages/:id/export)现在写出 withheldMaps(整库导出 GET /packages/export 的每个条目同样带上,因其逐包复用同一导出),逐条列出被整张扣下的连接器 header/env 表;install-local 的托管与非托管两种安装都在应答里逐条点名这些不完整的表,并打一条 warn。
  • 为什么改:导出读的是脱敏后的条目,这四张表被整张拿掉后,导入方分不清"被扣下"和"本来就没有"([Decision] connector credential follow-ups after #28596: header-value advisory, legacy auth keys at rest, whole-map withholding #28640 裁决 ③A,席位裁决 A 6578196369)。
  • 风险与回滚:导出对每个连接器多一次按名执行读;拿不到执行读就失败而不是省略键。安装门对格式错误的 withheldMaps 新增 400 拒绝。回滚即还原本 PR。
  • 先看:packages/runtime/src/domains/packages.ts 的 withheldConnectorMaps;packages/cloud-connection/src/marketplace-install-local-plugin.ts 的 judgeWithheldMaps 及两处应答;packages/spec/src/api/package-lifecycle.zod.ts 的描述改动。
  • 两分钟验证:pnpm --filter @objectstack/runtime exec vitest run src/domains/packages-export-withheld-maps.test.ts,预期 6 条全绿,第一条列出四个位置。
  • 需要你做的:无。契约复核 PASS(6594653702),两轮增量复核 PASS(6595333171、6596808111),席位落地。

What changes

Tests

  • packages/runtime/src/domains/packages-export-withheld-maps.test.ts (6 tests). It uses the real dispatcher, with a protocol double whose served list runs the real connector redactor. It checks: all four positions in order; the exported items as served, with no header name or value in the manifest; a connector with no map, or with a cleared map, is not listed; a package with no connectors asks the face nothing; a protocol without the face, and a missing body, each fail the export.
  • packages/cloud-connection/src/marketplace-install-local-withheld-maps.test.ts (7 tests), at the plugin's real route. Managed and unmanaged answers each name the list, with one warn line. A body without the list gets no key and no warn. Three malformed lists are refused PLUGIN_MANIFEST_INVALID, 400, in both modes, with nothing registered, ledgered or imported.
  • packages/qa/dogfood/test/export-withheld-connector-maps.dogfood.test.ts (4 tests) runs on the real showcase composition. It installs a package with three connectors, two carrying header maps, then exports it. The export lists the three maps and carries no header name or value. A managed re-install of the export names them. On a second boot that never held the package, an unmanaged install of the export also names them.
Red first, by reverse verification on the base source (744211f)

git restore --source=744211fc of the two runtime and cloud-connection source files, with on-disk marker counts 0 0 and runtime and cloud-connection rebuilt. Then ablation-dist-preflight confirmed that withheldConnectorMaps is absent from packages/runtime/dist.

  • runtime unit: 3 failed, 3 passed. The "lists every withheld position" test and both no-guess tests were red.
  • cloud-connection unit: 5 failed, 2 passed. Both naming tests and the 3 refusals were red.
  • dogfood: 3 failed, 1 passed. The export listing, the managed answer and the unmanaged answer were red.

Restored with git restore --source=HEAD --staged --worktree, git status --porcelain empty, rebuilt, preflight found the marker present again, and the dogfood ran 4/4 green.

Ablation of the narrowing arm (seat ask)

node scripts/ablation-replace.mjs turned if (!declared.success) into if (!declared.success && false) in judgeWithheldMaps: anchor 1 → 0, blob f2cf4131 → 84f0fc0a. Result: 3 failed | 4 passed, and the failures were exactly the three PLUGIN_MANIFEST_INVALID cases. Restored: the blob equals HEAD, and git diff HEAD is empty.

Acceptance notes

Verification

Unit suites, typecheck, gates and lint below were measured at 583fce44, before the merge, and re-run at head c5a34147, after merging origin/main (33ee9aa). Post-merge figures are given where they differ.

  • pnpm --filter @objectstack/runtime test: 530 files, 8518 passed, 19 skipped; after the merge, 532 files, 8529 passed, 19 skipped. pnpm --filter @objectstack/cloud-connection test: 68 files, 820 passed, the same after the merge. Spec package-lifecycle.test.ts and unmanaged-install.test.ts: 63 passed; after the merge, 67 passed. Dogfood file: 4/4 after the merge. pnpm --filter @objectstack/runtime --filter @objectstack/cloud-connection typecheck: exit 0.
  • pnpm --filter @objectstack/spec check:generated: check:docs was stale and was fixed with --fix (one artifact). The other 13 were up to date.
  • node scripts/pm/dispatch-gates.mjs --commands: 105 families. All 105 exit 0, three of them after their prerequisites were met: the clone was unshallowed for check-plugin-teardown-shape --self-test, and the client and plugin packages were built for check:skill-examples and check:dual-build-cjs-loads. --ran reconciliation: 105 derived, 105 run, 0 NOT-MEASURED, 0 UNRUN.
  • pnpm lint: exit 0.
  • Full dogfood battery: not run. The title has no ! and Clause-② has no (narrowing) arm.

Re-run at head 85d56fc4 (after merging origin/main b3d1415): typecheck for spec, runtime and cloud-connection exit 0; spec package-lifecycle and unmanaged-install 67 passed; runtime 535 files, 8560 passed, 19 skipped; cloud-connection 68 files, 820 passed; dogfood file 4/4; dispatch-gates --commands 105 derived, 105 exit 0, --ran 105/105, 0 NOT-MEASURED.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7


Generated by Claude Code

…nstall-local names each as incomplete

Claude-Session: https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7
Co-authored-by: Claude <noreply@anthropic.com>
…es name them; changeset

Claude-Session: https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7
Co-authored-by: Claude <noreply@anthropic.com>
… withheldMaps describe

Claude-Session: https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7
Co-authored-by: Claude <noreply@anthropic.com>
…-vrj8cl

# Conflicts:
#	packages/runtime/src/domains/packages.ts
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Nov 3, 2026
@github-actions

github-actions Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/cloud-connection, @objectstack/runtime, @objectstack/spec, touching 14 documentable anchor(s).

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/deployment/cli.mdx (via MarketplaceInstallLocalPlugin (symbol, a top-level class))
  • content/docs/deployment/publish-and-preview.mdx (via PLUGIN_MANIFEST_INVALID (literal, a string literal in judgeWithheldMaps))
What this run could not see
  • the SDK route bridge reached 61 of 219 client-bound route-ledger rows — the other 158 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 158: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 103 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 176 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json be6b15c7cb309cf89358332e5927b4763e9c82a2 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 99b84e01cdcdb13d00eb8c468626b5d489bd4d8e — the merge of head 85d56fc4e07d81342f9b269d77ec4772605e5868 into base be6b15c7cb309cf89358332e5927b4763e9c82a2, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 99b84e01cdcdb13d00eb8c468626b5d489bd4d8e && git checkout 99b84e01cdcdb13d00eb8c468626b5d489bd4d8e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin be6b15c7cb309cf89358332e5927b4763e9c82a2 85d56fc4e07d81342f9b269d77ec4772605e5868 && git checkout -B drift-repro be6b15c7cb309cf89358332e5927b4763e9c82a2 && git merge --no-ff 85d56fc4e07d81342f9b269d77ec4772605e5868

node scripts/docs-audit/affected-docs.mjs --json be6b15c7cb309cf89358332e5927b4763e9c82a2

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs be6b15c7cb309cf89358332e5927b4763e9c82a2 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

Contract-review-claim: session_01JQwxbZUR3xvHyDPCjNL5P4 · head c5a3414 · 2026-11-03T03:16Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c5a341477a90422cdf74532ca4cc0de3c85b03bd
Local-runs: none
Scope: packages/spec/src/api/package-lifecycle.zod.ts, packages/spec/src/kernel/unmanaged-install.ts + packages/spec/src/api/package-lifecycle.test.ts, packages/runtime/src/domains/packages.ts, packages/cloud-connection/src/marketplace-install-local-plugin.ts, packages/spec/src/integration/connector-credential-redaction.ts, packages/spec/src/kernel/metadata-type-redaction.ts, packages/metadata-protocol/src/protocol-meta-item-reads.ts, packages/metadata-protocol/src/protocol-meta-list-reads.ts, packages/metadata-protocol/src/package-unmanaged-install.ts, packages/runtime/src/route-ledger.ts

Inputs read: card #29342 (body + all 11 comments, rulings 6578196369 / 6592752231 included), PR #29746 body, file list and net diff origin/main...c5a34147 (10 files, +699/−37, merge base 33ee9aa), and the head's check-runs. Read-only: the diff was read with git show/git diff on a fetched ref; nothing was checked out, built or run.

① Derived judgments

  • Export response widens by one declared optional key. GET /packages/:id/export (route-ledger row responseSchema: 'PackageExportManifestSchema', packages/runtime/src/route-ledger.ts:567) now writes withheldMaps when at least one connector map was withheld, omitted otherwise. The key, its closed element shape and its four-value path enum were already declared on main by feat(spec): the package export manifest declares withheldMaps, classified door for the unmanaged import #29521; the PR adds no key, value or type to the schema. Right — the runtime test parses the export through PackageExportManifestSchema and the list is preserved.
  • Spec change is describe/docblock only. In package-lifecycle.zod.ts the [PLANNED — not yet served] prefix leaves withheldMaps.describe, the member docblock and the module docblock say served, and no z.* call changes; content/docs/references/api/package-lifecycle.mdx is the regenerated artifact of exactly that. In kernel/unmanaged-install.ts only the comment on the withheldMaps: 'door' row changes; the row, the disposition union and the refusing set are untouched, and unmanaged-install.test.ts is not in the diff (its toBe('door') pin still holds). Right — the hits files publish no accept-set or type change.
  • install-local answers gain one optional key in both modes (withheldMaps, omitted when the body carries none, so the key set of an answer without it is unchanged). No spec schema declares that answer: the runtime route ledger has no marketplace/install-local row and packages/spec/src/api has no install-local response schema, so this is an undeclared-surface widening with no transcription owed. Right.
  • install-local accept set narrows for a malformed withheldMaps (judgeWithheldMaps: PackageExportManifestSchema.shape.withheldMaps.safeParse, refused PLUGIN_MANIFEST_INVALID 400 inline / 502 cloud, before any write, both modes). PLUGIN_MANIFEST_INVALID is already in the error-code ledger (error-code-ledger.zod.ts:1304), and the status pair is the one judgeInstallMode already uses. Right, see ② for the Clause-② reading.
  • The unmanaged copy never carries the key. The planner (package-unmanaged-install.ts:426, case 'door': break) skips withheldMaps because of the row already on main; the PR's door reads it before importUnmanagedPackage runs. Right — the door row's comment now describes a reader that exists.
  • Runtime-internal: PackagesDomainProtocol gains an optional getMetaItemForExecution member typed off the producer's own signature; the protocol's request type has packageId?: string, so the call { type: 'connector', name, packageId } is in-contract. Right.

② Semver level

  • Changeset .changeset/29342-export-withheld-connector-maps.md: patch for @objectstack/runtime, @objectstack/cloud-connection, @objectstack/spec, carrying Clause-②: yes (widening) and Metadata-protocol: none, and naming the narrowing arm in prose. PR body carries the same two lines. Per AGENTS.md Post-Task §3, Metadata-protocol: none takes patch, and a non-protocol widening ships patch — matches what the diff publishes (no authorable key changes anywhere; withheldMaps is not authorable on any item, the connector bodies stay byte-identical as served).
  • Clause-②: yes (widening) holds for the export (one declared optional key starts being written) and for the two install answers. The narrowing arm (a malformed withheldMaps refused as PLUGIN_MANIFEST_INVALID) is, as the seat's amendment 6592752231 put it, the spec's own refusal made real: the closed element shape and the four-value enum were published with the key on main before any producer wrote it, so no consumer ever held a capability the door now takes away — only a hand-written value the declaration already refused is refused. AGENTS.md allows at most one arm on the line, (narrowing) is BREAKING, and this PR carries no BREAKING banner, no ADR-0087 disposition and no ! in its title. I accept the line as written on that reading; the arm is named in prose in both the PR body and the changeset, which is the record the seat directed.
  • The spec patch is right for a describe-only change (no .d.ts surface moves).

③ Boundary flags

  • Dev report 6594523288 lists open_questions: []; the three questions of the first dev report (6578135265) were all answered by seat ruling 6578196369 (option A; import accepts and names; the connector's four maps only, webhook headers out). The tree follows all three.
  • Out-of-scope findings in the dev report, each answered here: (a) the per-package export carries no type/installModes, so the bare export refuses an unmanaged import — pre-existing export-manifest-key family, carrier packages: a tenant exports its whole ontology — every installed package, its .custom pair and environment customizations — as installable packages for the open runtime (os package export + the read it calls) #28914; not this PR's (the dogfood adds the two keys and says so in its header). (b) installUnmanaged logs a 4xx reason only when status ≥ 500 — pre-existing; the dev reported it to the seat for filing (class a); not this PR's. (c) webhook headers dropped the same way — ruling 3A keeps it out of scope; right to leave.
  • Read-only observation, not escalated: the runtime's own managed door POST /api/v1/packages parses the manifest through PackageInstallManifestSchema (= ManifestSchema, a strictObject), which refuses an export carrying withheldMaps — but it already refuses the export's label on main, and ruling A names install-local (the door the Studio import button posts to, PackagesPage.tsx:1544) as the reader. No regression attributable to this PR; belongs with the packages: a tenant exports its whole ontology — every installed package, its .custom pair and environment customizations — as installable packages for the open runtime (os package export + the read it calls) #28914 export-manifest-key family if anyone wants that door to accept exports.
  • Check-runs on c5a34147 at read time: 62 runs — 26 success, 8 skipped, 28 in_progress (Test Core 1–8, Test UI 1–16, Type Check UI, Type Check · workspace, Build Core, Live E2E UI), 0 failures. The gate verdicts are therefore not all in yet; the queue guard reads them itself before landing. The dev's own run (105/105 dispatch-gate families exit 0, runtime/cloud-connection suites, lint) is the PR body's account and was not relied on.

④ Design judgment

packages/spec/src/api/package-lifecycle.zod.ts — judged against seat ruling 6578196369 (option A), the director's ③A, and its first consumers (assemblePackageManifest, judgeWithheldMaps).

  • The member docblock's new claim ("assemblePackageManifest writes the list, judging each exported connector's stored body with the same redactor the served read ran, and both install modes of POST /marketplace/install-local read it, accept the package and name each incomplete map") is true of the tree: withheldConnectorMaps (runtime packages.ts) calls getMetadataTypeRedactor('connector') — the built-in redactConnectorItem, the same function decorateMetadataItem → redactMetadataItem runs on the served face — on the body from getMetaItemForExecution, and keeps only the positions the declaration's own enum lists (PackageExportManifestSchema.shape.withheldMaps.unwrap().element.shape.path.options), so the two vocabularies cannot drift; judgeWithheldMaps parses the key by reference to the same declaration and both answers carry it.
  • The by-name execution read is a legitimate reader: its docblock (protocol.ts:4620–4627) allows a gate inside a door to read a DECISION off it with no byte of the body reaching the response, and the hunk emits positions only; the runtime test pins that no header name or value leaves. Attempted breaks: (i) the two reads disagreeing — getMetaItemsPerPackage and readMetaItem hide a disabled package's items by the same predicate (isItemOfDisabledPackage), both read active state when none is passed, and connector is neither overridable nor bundled, so I found no scenario where the per-package list serves a connector the by-name read answers no body for; when it would, the export fails 500 rather than writing a false "nothing withheld", which the describe's "from an exporter that writes it, absence means nothing was withheld" requires. (ii) A cleared map ({}) is not in redactedKeys (isClearedForm), is served as written, and is correctly not listed. (iii) A map the redactor withholds under items 7/8 (undeclared keys) at one of the four paths is still listed, since only redactedKeys membership is read. Holds.
  • The pin flip in package-lifecycle.test.ts asserts no PLANNED and ^Every map the export withheld WHOLE, which the new describe satisfies; #\d{3,} still refused. The module docblock's "One member … the nav arm" is correct at the member level; it never counted PackageExportBundleSchema (packages: a tenant exports its whole ontology — every installed package, its .custom pair and environment customizations — as installable packages for the open runtime (os package export + the read it calls) #28914, a whole schema still marked PLANNED), and that omission pre-exists on main ("Two members" there also omits it) — noted, not a finding of this PR.
  • No must-fix. No should-fix.

packages/spec/src/kernel/unmanaged-install.ts — judged against the planner that reads the table and the door the comment names.

  • Comment-only change on the withheldMaps: 'door' row; the new wording ("the install-local door reads it to name each incomplete map in its answer, and this row keeps the import from refusing an export that carries the key") is true of the tree: installUnmanaged receives the parsed list from handleInstall step 1d', the planner's case 'door' leaves the key out of the copy, and the answer and one warn line name each map. Table totality is unchanged (no key added or removed), so the unmanaged-install.test.ts battery is unaffected.
  • No must-fix. No should-fix.

Cited code read, not reviewed (the lane seat's ACCEPT at TIER_DEFAULT covers it): withheldConnectorMaps iterates manifest.connectors after the ownDocumentsOf filter and after clean(), so a connector's name is the served name; the hunk sits after the dependencies line and apart from #29687's filter as the PR says. The managed path's new withheldMaps spread and warn sit after every refusal and after the ledger write, so a refused install still writes nothing new.

Implemented-by: claude/project-thread-vrj8cl
Reviewed-by: session_01JQwxbZUR3xvHyDPCjNL5P4

VERDICT: PASS

…ent export as declared ahead

The nav arm is served by #28722's server slice (#29742); the paragraph now
names PackageExportBundleSchema (#28914) alone. Reference doc regenerated.

Claude-Session: https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 18ad0f5b91e2225b6036f652086de6a7b3056d9c
Local-runs: none
Scope: packages/spec/src/api/package-lifecycle.zod.ts, packages/spec/src/kernel/unmanaged-install.ts + content/docs/references/api/package-lifecycle.mdx, PR #29742's packages/spec/src/api/package-lifecycle.zod.ts hunk (read through the REST file list, head be28754)

Delta record: one commit on top of c5a34147 (reviewed PASS, record 6594653702), git diff c5a34147 18ad0f5b = 2 files, +6/−6: the header paragraph of package-lifecycle.zod.ts (lines 41–46) and its regenerated transcription in package-lifecycle.mdx (lines 46–50). kernel/unmanaged-install.ts is unchanged in the delta; every ① – ④ judgment of the earlier record stands for the rest of the tree and is not restated. Read-only: nothing checked out, built or run.

① Derived judgments

  • No accept-set or public-surface change. The delta touches a module-level docblock comment and the generated reference page only; no z.* call, type, key, row or export moves. Right — nothing publishes beyond prose.
  • What the header now says: "One member is not a transcription but DECLARED AHEAD OF ITS PRODUCER … PackageExportBundleSchema, the whole-deployment export (packages: a tenant exports its whole ontology — every installed package, its .custom pair and environment customizations — as installable packages for the open runtime (os package export + the read it calls) #28914)." Against the tree at 18ad0f5b that is incomplete: the same file still carries the nav arm's declared-ahead markers — the GetPackageCustomizationsResponseSchema docblock (line 527–531, "the nav arm's describe opens [PLANNED — not yet served]"), the arm's leading comment (line 600) and its describe (line 619, [PLANNED — not yet served] …), plus the member-level and schema-level "not yet served" wording — none of which this PR drops. So at this head the header names one declared-ahead declaration while the file holds two (nav and the bundle). The previous head named nav and omitted the bundle (that omission pre-exists on main); this head names the bundle and omits nav. Nothing pins the header text (no test or script reads it; git grep on the head tree finds no pin), and the member-level pins in package-lifecycle.test.ts are the contract's truth and are untouched.

② Semver level

  • Unchanged: the changeset (patch ×3, Clause-②: yes (widening), Metadata-protocol: none) still matches what the diff publishes; the delta adds nothing publishable. Matches.

③ Boundary flags

④ Design judgment

packages/spec/src/api/package-lifecycle.zod.ts — the delta is the header paragraph alone; judged against the file's own markers and against #29742's hunk.

  • The paragraph is non-normative prose; the ADR-0049 convention's enforcement is the per-member [PLANNED — not yet served] prefix and the pin test, both of which this PR leaves correct for nav and flips correctly for withheldMaps (unchanged from the PASS head). The header's new sentence is the right end state after both PRs land and is wrong-by-omission on main only in the window described in ③.
  • Tried to break it: no test, script or doc-audit rule reads the header; check:docs regeneration is satisfied (the mdx hunk is the exact transcription); no tracker-id rule applies to a module docblock (the #\d{3,} refusal is on describes, and the header already carried issue numbers on main).
  • Should-fix (ordering, not text): land after feat(runtime): the customizations read serves the nav contributions other packages add to a base's apps #29742, or, if landing first, state both remaining declared-ahead declarations in the paragraph so main is true at every point. No must-fix.

packages/spec/src/kernel/unmanaged-install.ts — not in the delta; the earlier record's judgment stands unchanged.

Implemented-by: claude/project-thread-vrj8cl
Reviewed-by: session_01JQwxbZUR3xvHyDPCjNL5P4

VERDICT: PASS

…-vrj8cl

# Conflicts:
#	packages/spec/src/api/package-lifecycle.zod.ts
…he reference after merging main

With #29742 (nav arm), #29755 (whole-deployment export) and this change
(withheldMaps) all served, no member of package-lifecycle.zod.ts is
declared ahead of its producer.

Claude-Session: https://claude.ai/code/session_01JQwxbYXRMR5S5B7JSmKkV7
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 85d56fc4e07d81342f9b269d77ec4772605e5868
Local-runs: none
Scope: packages/spec/src/api/package-lifecycle.zod.ts, packages/spec/src/kernel/unmanaged-install.ts + content/docs/references/api/package-lifecycle.mdx, packages/runtime/src/domains/packages.ts (assemblePackageExportBundle, #29755), packages/runtime/src/route-ledger.ts, packages/cli/src/commands/package/export.ts, packages/cli/src/commands/package/install.ts, packages/runtime/src/domains/packages-export-bundle.test.ts, packages/qa/dogfood/test/package-export-bundle-round-trip.dogfood.test.ts, .changeset/28914-package-export-whole-deployment.md

Delta record: two commits on top of 18ad0f5b (reviewed PASS, record 6595333171) — c5f0877d merges origin/main at b3d14150 (brings in #29742, nav served, and #29755, GET /packages/export served with its PLANNED marker dropped), and 85d56fc4 removes the header's declared-ahead paragraph and regenerates the mdx. Merge base is now b3d14150; the net diff b3d14150…85d56fc4 is the same 10 files (+691/−41). Read-only: fetched refs, git diff/git show only; nothing checked out, built or run.

① Derived judgments

② Semver level

  • Changeset unchanged (patch ×3, Clause-②: yes (widening), Metadata-protocol: none): still matches. The bundle entries gaining the key is the same declared optional key written by the same one producer, already covered by the yes (widening) line and already declared on the bundle through composition — no new arm and no level change owed. Should-fix (prose only): the changeset and PR body name GET /api/v1/packages/:id/export as the producer; since feat(runtime,client,cli): export a deployment's whole ontology as installable packages in one read (GET /packages/export, os package export) #29755 landed under this PR, GET /packages/export (os package export) carries the key per entry too, and one clause saying so would spare a reader the inference. Not a must-fix: the declaration, the level and the arm are all correct as written.

③ Boundary flags

④ Design judgment

packages/spec/src/api/package-lifecycle.zod.ts — the delta is the header paragraph's removal; judged against the file's own markers on the merged tree and against its consumers.

packages/spec/src/kernel/unmanaged-install.ts — not in the delta (net diff identical to the reviewed one); the first record's judgment stands.

Cited code read, not reviewed: assemblePackageExportBundle is #29755's and is unchanged by this PR; the auto-merge placed withheldConnectorMaps between assemblePackageManifest and it, and the export hunk still sits at the end of assemblePackageManifest, after dependencies.

Implemented-by: claude/project-thread-vrj8cl
Reviewed-by: session_01JQwxbZUR3xvHyDPCjNL5P4

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4

席位核对

ACCEPT · domain:server#5 · head 85d56fc4 · 2026-11-03T06:42Z · The contract review at CONTRACT_REVIEW_TIER passed: 6594653702 on c5a34147, delta 6595333171 on 18ad0f5b and delta 6596808111 on this head (spec hits). The rest is the seat review of record at TIER_DEFAULT. Not governed: check-governed-merges --pr 29746 reads NOT governed, 732 lines. Clause-②: yes (widening), with one narrowing arm named in prose.

  1. Shape: draft, base main (b3d1415), body Fixes #29342. 10 files, +691/-41:

    • the export's withheldConnectorMaps at the end of assemblePackageManifest;
    • judgeWithheldMaps and both install-local answers in cloud-connection;
    • the spec withheldMaps describe/docblock and unmanaged-install.ts comments, with the regenerated mdx;
    • three tests, a dogfood case and a changeset.

    The seat amended the body after the merge: new head, the bundle clause, filed cloud-connection: an unmanaged install-local refused 4xx tells the operator "the reason is in the server log", but nothing is logged below 500 #29822, and the post-merge readings.

  2. Premise measured: it holds. Ruling A (6578196369) is served as written. Red first by reverse verification on 744211f: runtime 3 red, cloud-connection 5 red, dogfood 3 red. The narrowing ablation reds exactly the three PLUGIN_MANIFEST_INVALID cases. After feat(runtime): the customizations read serves the nav contributions other packages add to a base's apps #29742 and feat(runtime,client,cli): export a deployment's whole ontology as installable packages in one read (GET /packages/export, os package export) #29755 landed, no member of package-lifecycle.zod.ts is declared ahead, so the header paragraph is removed (85d56fc). This was checked in the tree by delta 2.

  3. Gates on this head: check-runs pinned to 85d56fc4 after the body patch: 69 total, 59 success, 10 skipped, 0 failed. The dev ran these locally on 85d56fc4:

    • typecheck for spec, runtime and cloud-connection: exit 0;
    • runtime: 8560 passed, 19 skipped;
    • cloud-connection: 820 passed;
    • spec: 67 passed;
    • dogfood: 4/4;
    • dispatch-gates --ran: 105 derived, 105 run, 0 NOT MEASURED.
  4. Accepted deviations:

  5. Out of scope:

  6. Landing: not governed and under 3000 lines, so the seat lands it (pr_ready + automerge_enable). At MERGED: a landing record on packages: a package export marks each withheld connector header/env map, so an import knows it is incomplete (#28640 ruling 3A) #29342 (closed by Fixes) and pm:dispatched removed. runtime: a package export silently drops a whole metadata type when its per-package read throws, so the export (and the whole-deployment bundle) can be thinner with no error #29760 (PR fix(runtime)!: a package export refuses when the read of a type the runtime serves fails, naming the package and the type #29824) then merges main.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 3, 2026 06:43
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 3, 2026 06:43
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit e756782 Nov 3, 2026
70 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-vrj8cl branch November 3, 2026 07:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

packages: a package export marks each withheld connector header/env map, so an import knows it is incomplete (#28640 ruling 3A)

1 participant