Skip to content

fix(cloud-connection)!: install-local judges a ledger entry in the CLI's lifted shape through the install door's flatten, at boot and on the sample-data doors - #28683

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-uy0k8q
Nov 1, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/project-thread-uy0k8q

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread

Fixes #28604

Clause-②: no (narrowing) — at kernel:ready the install-local rehydrate no longer loads, and POST /api/v1/marketplace/install-local/:manifestId/reseed-sample-data and /purge-sample-data answer 422 OS_PROTOCOL_INCOMPATIBLE for, a ledger entry an install wrote before #28535 in the body os package install FILE sends (id and version lifted beside a nested manifest) whose nested engines.protocol excludes this runtime. That entry loaded, and those doors acted on it, before. A flat entry with the same range was already refused the same way. Nothing is widened.
Metadata-protocol: none
Skills-docs: none — the pages already state the behaviour this restores: skills/objectstack-platform/SKILL.md ("The runtime checks it before it loads anything and refuses an out-of-range app at the boundary"). No page described a ledgered CLI install as an exception.

BREAKING boot-load and accept-set narrowing for already-ledgered install-local entries (@objectstack/cloud-connection): the kernel:ready rehydrate and the two sample-data doors, reached by a deployment where os package install ./dist/objectstack.json ran before PR #28603.

维护者速读

What changes

The one flatten, read at three more places (packages/cloud-connection/src/marketplace-install-local-plugin.ts). An install before PR #28603 ledgered the CLI's body as it arrived: { id, version, manifest: { …, engines, dependencies }, objects, data, … }. Every reader that decides by a manifest key read it at the top, so the nested keys were invisible. Each now reads the entry through flattenPackageBody, the function the install door already uses (no second flatten, no second handshake):

  • the kernel:ready rehydrate's checkProtocolCompat(flattenPackageBody(entry.manifest)), so an excluded nested range is not loaded, is recorded in refusedAtRehydrate (the listing's notLoaded marker) and gets the one error line, exactly as a flat entry;
  • refuseProtocolIncompatibleEntry, the reseed/purge doors' handshake, so both answer the install route's 422 for it before any side effect;
  • inDependencyOrder, so a lifted entry is ordered by the dependencies its nested manifest declares (ADR-0141 D5). At boot, a flat entry's dependencies are used for this ordering only (the rehydrate runs no dependency check: checkDeclaredDependencies is called only at the install door), so ordering is the parity a lifted entry is owed.

flattenPackageBody gains a !isPlainObject(body) guard so it is total over a ledger value, which LocalManifestSource does not shape-check. Measured: a null, a string and a number manifest produce byte-identical rehydrate logs, registrations and door answers on base and head (probe in the evidence folder below).

What stays as today. A compatible lifted entry registers, converts, binds and seeds the body exactly as ledgered: only the judging and the ordering read the flattened view. The install door and its #28603 flatten are untouched.

Why

ADR-0087 D1 puts the handshake "before loading a package's metadata", and a rehydrate is a load (#21762). The triage (6557784727) graded the reach p3: one closed population, the entries a CLI install wrote before PR #28603 (7449e479), since new installs are refused at the door.

Tests

  • marketplace-install-local-protocol-handshake.test.ts, new group [#28604] kernel:ready rehydrate of an entry ledgered in the CLI's lifted shape: the lifted ^17 entry is not registered, nothing is synced, and its error lines equal a flat ^17 entry's on a fresh ledger, byte for byte; the GET listing marks it notLoaded { code: OS_PROTOCOL_INCOMPATIBLE, requiredRange: ^17 }; lit control: a lifted ^18 entry rehydrates with no error and registers the body deep-equal to the ledgered one.
  • marketplace-install-local-sample-data-not-loaded.test.ts, new group: precondition (lifted refused not loaded, lifted loadable loaded); reseed and purge on the lifted refused entry answer 422, leave i18n, seed-datasets, the engine and the ledger unchanged, and their payloads equal the flat entry's byte for byte; lit control: both doors answer 200 on the lifted loadable entry.
  • marketplace-install-local-rehydrate-order.test.ts: a lifted module entry listed ahead of its parent registers after it.

Red on base (plugin source swapped to origin/main 0b6a52e8; on disk: flatten-at-judge count 0, base judge count 2; restored with git checkout HEAD --, git diff HEAD empty, blob hash equal to HEAD): 5 failed / 32 passed of 37, exactly the five lifted-shape cases above that judge or order; both lit controls pass on both trees. Green on head: 37/37.

Ablation, one leg per site, through scripts/ablation-replace.mjs (anchor 1 → 0 on disk, restored to the HEAD blob, git diff HEAD empty after each). The tests import the plugin by relative path (source), so there is no dist leg.

Leg Mutation Red
1 rehydrate judges entry.manifest 3: the two boot cases + the sample-data precondition
2 door judges entry.manifest 1: reseed/purge byte parity
3 order reads entry.manifest 1: the lifted dependency order

Acceptance notes

  • Pre-existing, not changed: a ledger file whose manifest is null throws Cannot read properties of null (reading 'engines') from checkProtocolCompat, at the rehydrate (logged as "rehydrate failed") and out of the reseed/purge handlers. Identical on base and head. No door or producer writes such an entry, so it is noted here and not filed.
  • Overlap: re-read the 17 open PRs before pr_create; none touches the plugin file or the three test files.

Verification

All on head 365d3ac3 (the only commit; the base is origin/main 0b6a52e8).

  • pnpm --filter @objectstack/cloud-connection test: 65 files / 796 tests passed. pnpm --filter @objectstack/cloud-connection typecheck: exit 0 (under the verify lock, VERDICT command-exit 0).
  • The three touched files alone: 37/37.
  • Full dogfood battery (owed by the (narrowing) arm), closure built then pnpm --filter @objectstack/dogfood test under the lock: VERDICT command-exit 0 (held 2009s) · Test Files 369 passed, 3 skipped (372) · Tests 2981 passed, 28 skipped (3009) · no failures.
  • Derived gates: dispatch-gates --commands --repo objectstack-ai/objectstack derived 60 families; all 60 exit 0, exit codes captured before any pipe. --ran: "60 derived famil(ies) accounted for — 60 run, 0 NOT-MEASURED (a DERIVED zero — all 60 recorded an exit code and none of them is 3)". Two first runs were not measurements and were re-run to exit 0: check-plugin-teardown-shape --self-test exited 3 on the shallow clone until its pinned fixture commit was fetched, and check:dual-build-cjs-loads exited 3 until a full packages/** build. Record: project file pm-orders/server/evidence/28604/gates-ran-365d3ac3.txt.
  • CI families (lint, Test Core shards and the rest) are read from this PR's check-runs, not re-run locally.
  • Non-object ledger probe (base vs head byte-identical): pm-orders/server/evidence/28604/non-object-ledger-probe.txt.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes (CI).
  • 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: n/a.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the 维护者速读 section is the lane's required maintainer summary).
  • The Before Submitting list in CONTRIBUTING.md is done.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FEkQ5piHvtwq5wxJ2RJYfj


Generated by Claude Code

…ugh the install door's flatten at boot and on purge/reseed

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEkQ5piHvtwq5wxJ2RJYfj
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/cloud-connection, touching 4 documentable anchor(s).

1 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))
What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 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; 100 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 — 5 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 da46b2afe3e6829dcf70051f10578c61d611ec72 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 3fe06cd3f7f2a5bb8e4234ecc9843559eef3d2fd — the merge of head 365d3ac3cab55c47125879dc62e258396d9216d2 into base da46b2afe3e6829dcf70051f10578c61d611ec72, 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 3fe06cd3f7f2a5bb8e4234ecc9843559eef3d2fd && git checkout 3fe06cd3f7f2a5bb8e4234ecc9843559eef3d2fd
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin da46b2afe3e6829dcf70051f10578c61d611ec72 365d3ac3cab55c47125879dc62e258396d9216d2 && git checkout -B drift-repro da46b2afe3e6829dcf70051f10578c61d611ec72 && git merge --no-ff 365d3ac3cab55c47125879dc62e258396d9216d2

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

⚠️ 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 da46b2afe3e6829dcf70051f10578c61d611ec72 → 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#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 365d3ac3cab55c47125879dc62e258396d9216d2
Local-runs: probe — node scripts/check-changeset-no-major.mjs --base 0b6a52e8 --head 365d3ac3 --event with the PR payload, because the payload-less run reports the level axis NOT APPLICABLE and the two declaration lines are read by that gate's own reader (scripts/pm/clause2-line.mjs); nothing was built, tested or re-run
Scope: packages/cloud-connection/src/marketplace-install-local-plugin.ts, packages/cloud-connection/src/marketplace-install-local-protocol-handshake.test.ts, packages/cloud-connection/src/marketplace-install-local-rehydrate-order.test.ts, packages/cloud-connection/src/marketplace-install-local-sample-data-not-loaded.test.ts + packages/metadata-core/src/protocol-handshake.ts (checkProtocolCompat, resolveDeclaredRange), packages/core/src/hydration-order.ts and packages/core/src/artifact-packages.ts (orderHydrationBatch, artifactPackageId, declaredDependencyIds), packages/cloud-connection/src/local-manifest-source.ts (read/readAll shape-free), packages/cli/src/commands/package/install.ts (the lifted body, :172–174)

Face: narrowing (record-recognisers --paths on the five committed paths decides no schema or governed face; the changeset's Clause-②: no (narrowing) line decides, so --face narrowing, CONTRACT_REVIEW_TIER). Scope floor on this face = every diff path outside the prose faces; the changeset .changeset/28604-install-local-rehydrate-lifted-entry.md is the seat's ACCEPT, read here only for ②. Reviewed at 2026-11-01T13:36Z against merge-base 0b6a52e8a0d9982ede44a74912e917b353154582 (= origin/main). PR author objectstack-fleet[bot]; PR is draft. Card #28604 (p3, triage 6557784727, claim 6557844083), order pm-orders/server/order-28604.md, os-dev-report 6558578887, source card #28535 / PR #28603 (7449e479) all read.

① Derived judgments

  1. One flatten, one handshake — holds. Both judged reads call the existing flattenPackageBody (:622) and the existing checkProtocolCompat imported from @objectstack/metadata-core (:197): rehydrate :1109 checkProtocolCompat(flattenPackageBody(entry.manifest)), doors :3863 the same inside refuseProtocolIncompatibleEntry. No new flatten function, no inline { ...manifest, ...sections }, no second compat predicate. Base held exactly two checkProtocolCompat(entry.manifest) reads; head rewrites those two and adds none. The door-side judge being separate from the boot-side judge is the pre-existing [finding] install-local: reseed-sample-data on a package the rehydrate refused (protocol-incompatible) loads its translations and merges its 5 seed datasets before failing, and purge-sample-data flips its withSampleData; neither runs the handshake #21834 design (an entry another runtime ledgered after this boot), not a second handshake introduced here.
  2. Outcome parity for a lifted entry with an excluded range — holds. The flattened view { ...meta, ...sections } carries engines from the nested manifest and id/version from the lifted top (the CLI sets them from artifact.manifest.id ?? artifact.id, install.ts:172, so they equal the nested ones). resolveDeclaredRange then reads engines.protocol exactly as for a flat entry; the diagnostic's packageId is the same id; reportProtocolIncompatibleEntry prints from entry.manifestId/entry.version and the diagnostic; refusedAtRehydrate is keyed by manifestId+installedAt; the doors answer the shared protocolIncompatibleAnswer. Nothing in the refusal path reads the body's shape after the judge. The tests pin this as byte equality against a flat entry on a fresh ledger (error line; reseed and purge payloads) and assert the notLoaded { code, requiredRange } marker. Red on base (5/37) and three ablation legs reported in the PR; both lit controls pass on both trees.
  3. Compatible lifted entries unchanged — holds. The load path is untouched: convertPackageBodyForward(ctx, entry.manifest) (:1131) still converts and registers the ledgered body unflattened, as base did; only the judge (:1109), the order (:1186) and the doors' judge (:3863) read the flattened view. Lit control asserts the registered manifest deep-equals the ledgered lifted body, no error line, one sync. Ordering of a compatible lifted entry without nested dependencies is unchanged: declaredIds is empty on both trees and artifactPackageId reads the same lifted id (sections win in the flatten), so no edge is added and orderHydrationBatch keeps source order where no edge decides.
  4. !isPlainObject(body) guard — no existing caller moves. Three pre-existing callers: normalizeBundle (:1577) already guards with isPlainObject(m) before calling, so the new branch is unreachable from the install door; :3274 flattenPackageBody(converted) and :3452 flattenPackageBody(manifest) sit past the id gate and the handshake on the install body, which is a non-null object there (an array body read [].manifest as undefined on base and is returned as-is on both trees). The guard only changes null/primitive inputs, which base threw a TypeError on and which no existing caller can pass. Signature unchanged (a plain-object record in and out). For the new ledger callers the dev measured null/string/number manifest values byte-identical on base and head, consistent with the code: null still throws inside checkProtocolCompat (pre-existing, per-entry caught as "rehydrate failed"); a string/number reads no range and loads as before.
  5. The dependency-order leg — justified, in scope, not a new behaviour. inDependencyOrder (:1182) now reads flattenPackageBody(entry.manifest) so a lifted entry's nested dependencies (and a lifted multi-package artifact's packages[], which sits at the top in both shapes) feed ADR-0141 D5's ordering. No dependency CHECK runs at boot — checkDeclaredDependencies is called once, in handleInstall :1798, and AGENTS.md Startup registry reads forbids a boot-time verdict — so "ordering" is the whole of what a flat entry's dependencies do at boot, and the card's reach names "or whose dependencies it does not satisfy". It is the third decision at the rehydrate that reads a manifest key, judged through the same one flatten, with its own red case and ablation leg (lifted module listed ahead of its parent now registers after it). It does not touch the accept set and is not part of the declared narrowing; it is correctly left out of the Clause-② line.
  6. Narrowing arm — right, and the carriers are consistent. An entry that loaded at boot no longer loads, and two served doors move 200 → 422 for it: not a widening, breaking → no (narrowing) ([finding] An accept-set narrowing owes a **BREAKING** banner in core but not in platform-objects — and the ADR-0087 classifier reads the banner #16421), the same reading fix(cloud-connection)!: install-local reads the manifest of a compiled artifact as os package install sends it, so the protocol handshake runs on it #28603 declared for the install door. clause2-line.mjs reads both the PR body and the changeset as declared / no / narrowing and Metadata-protocol: none; no authorable key is added, narrowed or re-meant, so none and patch follow ruling A (AGENTS.md step 3: "a non-protocol change, widening or breaking, ships patch and keeps its BREAKING banner and ADR-0087 disposition"). The probe run of check-changeset-no-major.mjs with the PR payload: ✓ no major, ✓ level axis (patch · none · narrowing), ✓ lockstep. Title fix(cloud-connection)!: on the PR and on the changeset summary (carrier 3), **BREAKING** banner in both bodies (carrier 2), exactly one adr-0087: not-required (no-migration-prescription) marker in the changeset; the body carries no FROM → TO or consumer-rewrite instruction (the named remedies are the existing refusal's own text), so the category is honest under the gate's statement-against-statement check. check-adr-0087-registration.mjs could not run here (no tsx without pnpm install); it is read from the head's check-runs (Lint · docs & code guards, in progress at review time) — fix(cloud-connection)!: install-local reads the manifest of a compiled artifact as os package install sends it, so the protocol handshake runs on it #28603 carried the identical disposition and landed green. Skills-docs: none — REASON is present in the PR body, as the arm owes (SKILL.md:313), and the cited skills/objectstack-platform/SKILL.md sentence does describe this refusal.
  7. Overlap with objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565 — none. objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565 is an open card with no PR yet (search: the only open PRs naming the plugin file are this one, fix(service-automation)!: a connector stored in the environment never reads the host's files #28671 whose file list does not include it, and chore: version packages #26517 version packages). Its target check lands in handleInstall beside the dependency check (≈:1790–1810, "at both install doors"). This diff's four hunks are :609–626 (flattenPackageBody docblock + guard), :1102–1109 (rehydrate judge), :1181–1189 (inDependencyOrder), :3849–3863 (refuseProtocolIncompatibleEntry): none inside handleInstall, none in its early checks, and flattenPackageBody's signature is unchanged, so a later caller there is unaffected. No textual or semantic conflict foreseen.
  8. Upgrade / availability — no new boot-stop. The refusal is continue inside the per-entry try (:1110–1120), identical to the flat path [finding] marketplace install-local installs a manifest whose engines.protocol this runtime cannot satisfy (^16 on 17): 200 success, while POST /api/v1/packages refuses it 422 OS_PROTOCOL_INCOMPATIBLE #21762 established: the entry is skipped, the boot proceeds, the ledger is kept, DELETE and a compatible reinstall act on it. No new throw: the flatten is total, checkProtocolCompat is pure over objects, and the only throwing input (manifest: null) threw on base too and is per-entry caught. A lifted entry whose nested manifest is null or whose range is unparsable still loads (no-range / unparsed-range admit on both trees). What an operator sees after upgrading: a pre-fix CLI install built for another protocol is absent, named once in the error log with the remedy, and marked notLoaded in the listing — the declared narrowing, not an outage.

② Semver level

@objectstack/cloud-connection: patch with Clause-②: no (narrowing) + Metadata-protocol: none, ! title and **BREAKING** banner in PR body and changeset, one ADR-0087 marker. Consistent with ruling A and with the gate's own reading (probe above). Correct.

③ Boundary flags

  • open_questions: []. Two out_of_scope_findings, both carrier: none · noted, not filed: (a) a ledger file with manifest: null throws from checkProtocolCompat at the rehydrate (caught, "rehydrate failed") and out of the reseed/purge handlers — verified pre-existing and byte-identical on base; no producer writes it; not filing is acceptable, the seat may file at its discretion; (b) the objectql: an object extension's display patch is carried and applied by mergeObjectDefinitions; a patch naming a missing field or option is refused at install and validate #28565 overlap note — answered in ①.7.
  • Author is objectstack-fleet[bot]: no login note owed.
  • CI at review time: 13 check-runs success (Check Changeset, Governed Surface Queue Guard, PR-body guards, Lint · ESLint, Lint · PM dispatch-gates, Dogfood Regression Gate, Test UI, Build-plan and labels), 19 in_progress (Build Core, Test Core 1–8, Type Check ×4, Lint ×4, Live E2E UI), 0 failed. The landing pre-check ② (all green) is the seat's at landing; nothing here waives it.
  • Non-blocking note: the flatten gives top-level sections precedence over nested meta, so a lifted entry that also carried a top-level engines would be judged by the top-level one. No producer (install.ts lifts only id/version) writes that, and it is the install door's own precedence, so parity holds. Not a must-fix.

④ Design judgment

On the narrowing face, against the published contract on main: ADR-0087 D1 puts the handshake "before loading a package's metadata" at the loader and the installer, with "in range → load, major-incompatible → fail fast with a structured diagnostic"; skills/objectstack-platform/SKILL.md teaches that the runtime "refuses an out-of-range app at the boundary". No page or schema declares a ledgered CLI install as an exception. The narrowing therefore makes the spec's own refusal real at the one boundary where it was silently skipped, and takes no declared capability away from a consumer; the remedy the refusal names (a build for this protocol, or DELETE) is the existing diagnostic's. Per hits file: the plugin change holds against the cited checkProtocolCompat/resolveDeclaredRange (engines read off the flattened view), orderHydrationBatch/artifactPackageId/declaredDependencyIds (ids and dependencies read off the same view), the shape-free LocalManifestSource (which is why the total guard is needed) and the CLI body builder (the lifted shape the tests reproduce is the real one). The three test files pin the accepted scenario — byte parity with the flat entry, listing marker, lit controls, dependency order — on the harnesses the flat cases already use. The design holds.

Implemented-by: claude/project-thread-uy0k8q
Reviewed-by: session_0186vfjHHMsRXC9EUT9hTFMo

VERDICT: PASS

Must-fixes: none.


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo

席位核对

ACCEPT · domain:server seat 2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-11-01T13:37Z · head 365d3ac3 · #28604

The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.

  1. Shape:
    • A draft against main with Fixes #28604.
    • It carries a patch changeset for @objectstack/cloud-connection with the BREAKING banner and the ADR-0087 not-required marker, and a ! title.
    • check-governed-merges --pr 28683 reads NOT governed, +167 / -10. Landing tier S.
    • The claim (6557844083) names this PR's branch, claude/project-thread-uy0k8q.
  2. Against the order:
  3. Contract review: PASS on this head, 6558689509 (CONTRACT_REVIEW_TIER, the narrowing face; Clause-②: no (narrowing), Metadata-protocol: none).
  4. Gates:
    • The dev reports 60 of 60 derived gates exit 0, package 796/796, and a green full dogfood battery.
    • CI on this head was in progress with 0 red at review, and auto-merge waits for it.
  5. Overlap: git merge-tree against main is clean, and no open PR touches the file.
  6. Landing: pr_ready + automerge_enable through the relay.

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 1, 2026 13:38
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 1, 2026 13:38
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 1, 2026
Merged via the queue into main with commit a06feb7 Nov 1, 2026
49 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-uy0k8q branch November 1, 2026 13:59
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/m tests tooling

Projects

None yet

1 participant