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
runtime: export the disable door's dependent-validation-rule verdict for host doors, so a host that removes a package another way answers the same 409 #31067
readDisableDependentRules (packages/runtime/src/domains/packages.ts) is module-private. The sentence disableDependentRulesMessage("Package '<id>' cannot be disabled", dependents) is composed inline at the door.
Consumer: cloud packages/service-cloud/src/routes/environment-crud/packages.ts. Its disable arm (PATCH …/cloud/environments/:id/packages/:pkgId/disable) and the soft-disable uninstall drop the package from the environment's artifact with no scan. On the cloud#31001 rig this left every write on the object refused 400 VALIDATION_FAILED.
Expected
A public, pure verdict over a registry, or a kernel service read, that returns the dependent rules plus the message builder. The door itself consumes it, so there is still one spelling of the scan and the sentence.
On the maintainer's ruling 「平台开放检查,cloud 接上(推荐)」. readDisableDependentRules and the door's sentence are module-private, so cloud's own disable and uninstall routes skip the check and leave an object's writes refused. Export a pure verdict plus the message builder, and have the door consume it, so the scan and the sentence keep one spelling.
{
"issue": 31067,
"status": "done",
"branch": "claude/issue-31067-export-disable-verdict",
"pr": "https://github.com/objectstack-ai/objectstack/pull/31157",
"head": "72296d6c61dd32ff7b45236b4f39c4f51c322a21",
"premise_still_valid": true,
"files_changed": [
".changeset/31067-runtime-export-disable-dependents.md",
"packages/runtime/src/domains/packages-disable-module-extension-fields.test.ts",
"packages/runtime/src/domains/packages.ts",
"packages/runtime/src/index.ts"
],
"line_budget": "140 changed lines (+138 / -2, 4 files) vs the 3000 human-merge threshold: under. Inside the claim's file surface; packages/core untouched.",
"gates": {
"derived_on_72296d6c": "62/62 :: exit 0 (check:type-check-debt under os-verify-lock); dispatch-gates --ran: 62 derived, 62 run, 0 NOT-MEASURED (derived zero, every entry exit-coded)",
"first_sweep_on_aae146a8": "59 :: exit 0 first pass; 3 exit 3 rerun to exit 0: check-plugin-teardown-shape --self-test (control commit 621a4876 fetched into refs/os-dev-31067/teardown-control, shallow clone), check:dual-build-cjs-loads (after full pnpm build, 119/119), check:type-check-debt (lock queue-timeout, rerun under the lock)",
"runtime_test_aae146a8": "pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 :: exit 0 · Test Files 554/554 · Tests 8918 passed, 19 skipped",
"runtime_typecheck": "pnpm --filter @objectstack/runtime typecheck :: exit 0 on aae146a8 and on 72296d6c (test layer 27 files / 186 errors / 66 pinned, unchanged)",
"post_merge_scoped_72296d6c": "pnpm build (119/119) && runtime typecheck && vitest run of the 3 disable-door files :: exit 0 · Test Files 3/3 · Tests 82/82",
"lint": "eslint packages/runtime --no-inline-config :: exit 0",
"harness_wall": "packages-disable-module-extension-fields.test.ts base 17.02s (29 tests) vs head 17.90s (33 tests), back to back under the lock",
"ci": "in_progress at report time (21 check-runs on 72296d6c: 18 in_progress, 3 skipped)",
"ablation": "not run: no tested behaviour changes; the identity pin (entry export toBe the door's function) is the one that can fail"
},
"deviations": [
"origin/main was merged twice: the first merge, at 5f003744, was a no-op. main then moved to cadd6aa2 before the PR opened, so it was merged again as 72296d6c. The merge did not touch runtime/objectql, and the delta against main is still these 4 files. The scoped checks and all 62 gates were rerun on the merge head.",
"The export is a re-export alias on the entry (readDisableDependentRules as readPackageDisableDependents, disableDependentRulesMessage as formatPackageDisableDependents), not a rename of the declarations. A rename would leave the old name stale in the reason text of packages/core/src/security/second-object-read-exposure.pin.test.ts, which is outside the claimed file surface."
],
"open_questions": [
{
"question": "Should the entry also export the wire pair { code: PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE, status: 409 } for host doors?",
"options": ["A: no. The code is already ledgered in @objectstack/spec (ApiError['code']), so the host spells it type-checked and hard-codes 409", "B: export the runtime constant too, which widens the surface further"],
"recommendation": "A, because a second public spelling of a ledgered code adds surface without adding a check"
},
{
"question": "Should the exported registry parameter stay typed any?",
"options": ["A: keep any, as the door passes it. The verdict probes getObjectContributors/getAllObjects and answers [] otherwise", "B: narrow it to a structural registry type (contract change; touches the door's typing)"],
"recommendation": "A for this card; B is a contract-review call"
}
],
"out_of_scope_findings": [],
"mcp_calls": "0",
"api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> run 42384040880 -> POST /pulls + POST /issues/31157/assignees), and this comment via post-stamped.mjs (POST /issues/31067/comments). git push is not a REST write.",
"security_findings": "none"
}
Activity
objectstack-fleet commentedon Nov 7, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: audit · p2 kept ·
domain:server· 2026-11-07T00:52Z⛔ Not a claim.
readDisableDependentRulesand the door's sentence are module-private, so cloud's own disable and uninstall routes skip the check and leave an object's writes refused. Export a pure verdict plus the message builder, and have the door consume it, so the scan and the sentence keep one spelling.domain:server,pm:queuekept. The door's behaviour is unchanged. It sits beside runtime: uninstalling a package (DELETE /packages/:id) withdraws its extension fields with no scan, so another package's active validation rule that reads one breaks every write (#30379 follow-up) #30999 (the uninstall refusal), which consumes the same verdict, so whichever lands second re-reads the first.Generated by Claude Code
objectstack-fleet commentedon Nov 7, 2026
domain:server#4 · marchtian · session_017ihL2dLQEXWGsE2SZ3Qn5F
Claim: PM loop round 1
Session:
session_017ihL2dLQEXWGsE2SZ3Qn5FAccount:
marchtianBranch:
claude/issue-31067-export-disable-verdictWorktree:
objectstack-issue-31067Domain:
domain:serverSeat:
domain:server#4File surface:
packages/runtime/src/domains/packages.ts,packages/runtime/src/index.ts(entry export), runtime tests,.changeset/(stop on breach; explain in the report)Container & model:
S/M,mode:subagent(in-seat background subagent, the project's standing dev form),model: default(dispatch-gates --tier: no path-derived mandate; PM judgment, default tier),effort: mediumClause-②: yes
Metadata-protocol: none
Responsibility: n/a — not a defect card
Thread-read: 6699918326
Premise: holds
Serial constraints cleared: #30999 and #31023 share packages.ts and queue behind this card (seat 4 serial); no in-flight claim on packages.ts found among open
pm:dispatchedserver cardsobjectstack-fleet commentedon Nov 7, 2026
domain:server#4 · marchtian · session_017ihL2dLQEXWGsE2SZ3Qn5F
os-dev-report
{ "issue": 31067, "status": "done", "branch": "claude/issue-31067-export-disable-verdict", "pr": "https://github.com/objectstack-ai/objectstack/pull/31157", "head": "72296d6c61dd32ff7b45236b4f39c4f51c322a21", "premise_still_valid": true, "files_changed": [ ".changeset/31067-runtime-export-disable-dependents.md", "packages/runtime/src/domains/packages-disable-module-extension-fields.test.ts", "packages/runtime/src/domains/packages.ts", "packages/runtime/src/index.ts" ], "line_budget": "140 changed lines (+138 / -2, 4 files) vs the 3000 human-merge threshold: under. Inside the claim's file surface; packages/core untouched.", "gates": { "derived_on_72296d6c": "62/62 :: exit 0 (check:type-check-debt under os-verify-lock); dispatch-gates --ran: 62 derived, 62 run, 0 NOT-MEASURED (derived zero, every entry exit-coded)", "first_sweep_on_aae146a8": "59 :: exit 0 first pass; 3 exit 3 rerun to exit 0: check-plugin-teardown-shape --self-test (control commit 621a4876 fetched into refs/os-dev-31067/teardown-control, shallow clone), check:dual-build-cjs-loads (after full pnpm build, 119/119), check:type-check-debt (lock queue-timeout, rerun under the lock)", "runtime_test_aae146a8": "pnpm --filter @objectstack/runtime exec vitest run --project local --maxWorkers=2 :: exit 0 · Test Files 554/554 · Tests 8918 passed, 19 skipped", "runtime_typecheck": "pnpm --filter @objectstack/runtime typecheck :: exit 0 on aae146a8 and on 72296d6c (test layer 27 files / 186 errors / 66 pinned, unchanged)", "post_merge_scoped_72296d6c": "pnpm build (119/119) && runtime typecheck && vitest run of the 3 disable-door files :: exit 0 · Test Files 3/3 · Tests 82/82", "lint": "eslint packages/runtime --no-inline-config :: exit 0", "harness_wall": "packages-disable-module-extension-fields.test.ts base 17.02s (29 tests) vs head 17.90s (33 tests), back to back under the lock", "ci": "in_progress at report time (21 check-runs on 72296d6c: 18 in_progress, 3 skipped)", "ablation": "not run: no tested behaviour changes; the identity pin (entry export toBe the door's function) is the one that can fail" }, "deviations": [ "origin/main was merged twice: the first merge, at 5f003744, was a no-op. main then moved to cadd6aa2 before the PR opened, so it was merged again as 72296d6c. The merge did not touch runtime/objectql, and the delta against main is still these 4 files. The scoped checks and all 62 gates were rerun on the merge head.", "The export is a re-export alias on the entry (readDisableDependentRules as readPackageDisableDependents, disableDependentRulesMessage as formatPackageDisableDependents), not a rename of the declarations. A rename would leave the old name stale in the reason text of packages/core/src/security/second-object-read-exposure.pin.test.ts, which is outside the claimed file surface." ], "open_questions": [ { "question": "Should the entry also export the wire pair { code: PACKAGE_DISABLE_RESTRICTED_BY_VALIDATION_RULE, status: 409 } for host doors?", "options": ["A: no. The code is already ledgered in @objectstack/spec (ApiError['code']), so the host spells it type-checked and hard-codes 409", "B: export the runtime constant too, which widens the surface further"], "recommendation": "A, because a second public spelling of a ledgered code adds surface without adding a check" }, { "question": "Should the exported registry parameter stay typed any?", "options": ["A: keep any, as the door passes it. The verdict probes getObjectContributors/getAllObjects and answers [] otherwise", "B: narrow it to a structural registry type (contract change; touches the door's typing)"], "recommendation": "A for this card; B is a contract-review call" } ], "out_of_scope_findings": [], "mcp_calls": "0", "api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> run 42384040880 -> POST /pulls + POST /issues/31157/assignees), and this comment via post-stamped.mjs (POST /issues/31067/comments). git push is not a REST write.", "security_findings": "none" }objectstack-fleet commentedon Nov 7, 2026
domain:server#4 · marchtian · session_017ihL2dLQEXWGsE2SZ3Qn5F
Landed · PR #31157 merged by the merge queue as
4bf30da14d709ed902ea1ab6b3ebfe31ab177362.merged_atfrom the pulls APIcompletedbyFixes #31067origin/maincontentreadPackageDisableDependentsexported frompackages/runtime/src/index.tspm:dispatchedremoved with this record. Host adoption is the consumers'; #31023 in this lane asks the same verdict on the uninstall door.