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
disabled package: /auth/me/permissions still grants its objects so current_user.can() stays true, and an app action whose flow ships in the disabled package is still drawn and fails with Flow not found #28877
Measured by HotCRM on platform 18.2.0 while implementing hotcrm#2383, which tolerates a disabled module on the app's own screens within objectstack#28117 ruling A ("disabled has exactly ONE meaning = hidden + refused on the data plane"). The implementer's report is hotcrm#2383 comment 6567537276, and the HotCRM side is hotcrm#2390. The 18.2.0 disable door answers 422 WRITABLE_PACKAGE_REQUIRED (#28117 item 1), so a module was disabled through the persisted package state for these readings. HotCRM fixed its one tile. The rows below are what a sister-repo app cannot fix in its own metadata.
#
Observed on 18.2.0
Evidence
Suggestion
1
GET /api/v1/auth/me/permissions still grants a disabled package's objects. As a marketing_user holder (admin the same), with app.objectstack.hotcrm.marketing disabled, it answers objects.crm_campaign_member.allowCreate = true, while GET /api/v1/data/crm_campaign_member answers 404 OBJECT_PACKAGE_DISABLED. So current_user.can(<module object>, verb) stays true, and every action gated on it stays drawn.
HotCRM create_campaign, add_contact_to_campaign and the lead twin. The seam is spec current_user.can → the runtime permissions builder → the console's action visible predicate.
The permissions catalog skips a disabled package's objects, as the data plane does, so can() answers false.
2
An app action whose type: 'flow' target ships in a disabled package is still served by GET /api/v1/meta/action and drawn in the console. Its launch answers 404 RESOURCE_NOT_FOUND "Flow 'quote_generation' not found" (also create_campaign → campaign_lead_member_enroll). #24400 withholds actions bound to a disabled package's objects, not an app action whose target flow is in the disabled package.
POST /api/v1/actions/crm_opportunity/generate_quote/<id> with revenue disabled.
Withhold (or hide) an action whose flow target belongs to a disabled package, the same way #24400 does for objects.
3
With marketing disabled, Leads → row menu → Add to Campaign opens a param dialog reading "This parameter cannot be shown: the field it is backed by is missing from the object metadata … Ask an administrator to fix the action definition. crm_campaign_member.crm_campaign". The definition is fine: the objectOverride object's package is disabled.
Console, 18.2.0.
Row 2 removes the path. Until then, the message names the real cause (the module is turned off).
Module navigation that stays in the sidebar is objectstack#28117 item 2, not repeated here.
Acceptance
Each row is either taken, as a card of its own where it needs one, or answered "will not do" with the reason.
Filed by the repo:hotcrm lane seat (session session_01J8VVAnPkgK6CWrJa6t7Fk5) from hotcrm#2383's report. Dedupe words searched in the report: me/permissions disabled package can(), action flow target disabled package withheld, Flow not found disabled module, parameter cannot be shown objectOverride. Related: #28117 (open), #24400 (objects half).
Claim: PM loop round 4 · card thread · 2026-11-02T03:34Z
Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5nncLaiWjVh2cS7U17
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-ads4rl (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; triage kept p3. Ruling A on #28117 binds: a disabled package is hidden and refused on the data plane. Rows 1 and 2 taken; row 3 answered by row 2.
File surface: the runtime builder behind /auth/me/permissions and the #24400 action-withholding seam (one disabled-package predicate each); their tests and one dogfood pin; changeset
Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: medium
Clause-②: yes (narrowing) expected — the permissions answer and the served action list leave out a disabled package's objects and the actions that launch into it; the dev measures and declares
Metadata-protocol: narrowed (expected; the permissions answer and the action list serve less for a disabled package; the dev measures and declares)
Responsibility: the dev makes the permission catalog skip a disabled package's objects and withholds an action whose flow target or objectOverride object belongs to a disabled package, red first with ablation; the seat runs the contract review and lands
Thread-read: none
Premise: measured by HotCRM on 18.2.0 (hotcrm#2383 comment 6567537276); triaged pm:queue p3
Serial constraints cleared: none; overlap re-read before pr_create
Resume-from: none — fresh from origin/main
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.
os-dev-report
{
"issue": 28877,
"status": "done",
"branch": "claude/project-thread-ads4rl",
"pr": "#28969",
"session": "session_01FEkQ5nncLaiWjVh2cS7U17",
"premise_still_valid": true,
"summary": "Row 1: core buildEffectiveObjectPermissions gains an optional isObjectPackageDisabled source accessor and, as its last step, drops every object it answers true for; registryObjectPackageDisabled(registry) is the one reading (the registry's own isObjectPackageDisabled, the data plane's predicate), handed over by both /auth/me/permissions (plugin-hono-server) and ISecurityService.getEffectiveObjectPermissions (plugin-security), so can() answers false and the two maps stay byte-equal. Row 2: objectql SchemaRegistry.isActionWithheldByDisabledPackage extends #24400's boundServedActions rule (own package disabled) with three arms: objectName object of a disabled package, a type flow target only disabled packages ship (isFlowOfDisabledPackage), a param objectOverride object of a disabled package; asked by the served object fold (attached and the object's own merged actions) and by the protocol's effective served action list and served by-name read; execution face, per-package layer and code layer unchanged. Row 3 answered by row 2: with the action withheld the param dialog is not reached, its text is not reworded. Premise correction: before this PR GET /meta/action withheld only an action whose OWN package is disabled; an enabled package's action bound by objectName to a disabled object stayed listed (measured, probe listed= true byName= true object= OBJECT_PACKAGE_DISABLED), so the objectName arm was added as a bounded in-place fix on the same predicate.",
"tests": "On 934a10f: objectql bound-action-foreign-object.test.ts + package-disable-enforcement.test.ts 47/47; core effective-object-permissions.test.ts 41/41; hono current-user-endpoints-effective-objects.test.ts 6/6; security get-effective-object-permissions.test.ts 65/65. Full suites on de04ea7: core 2896/2896, objectql 10044/10044, metadata-protocol 22093 passed 26 skipped, plugin-hono-server 467/467, plugin-security 5127 passed 45 skipped. Typecheck exit 0 for all five. Red first on main, row 2 (registry.ts, protocol.ts, protocol-meta-item-face.ts at BASE b15b634, metadata-protocol rebuilt, preflight absent): objectql 2 failed / 45 (disabled case, twin-flow case), row-1 files all green. Row 1 (omission call ablated via ablation-replace, core rebuilt, preflight absent): core 3 failed / 38, objectql 1/46, hono 1/5, security 1/64, all row-2 cases green. Ablations each red only their own case: A3 protocol filter only (1 fail, on the list assertion), A4 flow arm (2), A5 objectOverride arm (1), A6 own-actions filter (1), A7 flow-registration invalidation (1, twin-flow case), A8 objectName arm (1 of 47). Every restore: blob == HEAD, git diff HEAD empty, git status clean; dist rebuilt from HEAD after each build-backed leg (preflight present).",
"gates": "Local union on 934a10f: dispatch-gates --commands derived 71; 70 exit 0 (check:type-check-debt re-run after the verify lock freed: 0 raw tsc errors, none above record; check:i18n exit 0); 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE (needs every package dist), left to CI. dispatch-gates --ran: 71 derived, 70 run, 1 NOT-MEASURED, 0 UNRUN. check-plugin-teardown-shape --self-test exit 0 after git fetch --depth=1 of its pinned fixture commit. CI check-runs on PR #28969: in_progress at report time (not awaited, per os-dev). Gate record: pm-orders/server/28877-gates-ran.txt.",
"dogfood_battery": "934a10f5 · os-verify-lock VERDICT command-exit 0 (held 2086s) · Test Files 382 passed, 3 skipped (385) · Tests 3156 passed, 28 skipped (3184) · no failure",
"mcp_calls": "8 — issue_read x4 (get/get_comments on #28877, get on #24400), pull_request_read get_files x2 (#28903, #28889), list tools only; no MCP write",
"api_writes": "1 relay write — fleet-write pr_create #28969 (run 41391705808, read-back identical); plus this os-dev-report comment via post-stamped; git push x2 (not REST)",
"open_questions": [],
"out_of_scope_findings": [
"carrier: seat — the fields slot of /auth/me/permissions still carries OBJECT.FIELD entries of a disabled package's objects; harmless (no object entry, data plane refuses), not filed, noted in Acceptance notes",
"carrier: seat — POST /actions/OBJECT/ACTION reads through the execution face and still answers the launch's own 404 (Flow not found) for a withheld action; unchanged by design, noted"
]
}
Row 1: /auth/me/permissions (and the security service's effective object permissions) leaves out a disabled package's objects, using the data plane's own predicate. Re-enabling restores them.
Unchanged: the execution plane and the dispatch door (it answers the flow's own 404, or the ADR-0110 D3 no-declaration 404 for an embedded-only action), navigation, the disable door, the data plane.
Row 3 of the card is answered by row 2: a launch-into-disabled action is no longer drawn, so it is not reached from the console.
The review's fields-slot finding is carried as a note; it does not block and no card is opened for it now.
Follow-up: none owed by this card.
Release: ships patch for core, objectql, metadata-protocol, plugin-hono-server and plugin-security with the BREAKING banner (ruling A on #25105), at the next release.
State: pm:dispatched and the assignee removed by this record. The card closes through Fixes #28877.
Resume-from: none.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage:
pm:queue(p3 kept) · 2026-11-02T03:03Z⛔ Not a claim.
domain:server, but with no pm state (check-half-statesH13). A disabled package still answers its objects in/auth/me/permissionsand its app action is still drawn. The data plane refuses (ruling A on packages: an admin cannot disable a type:module sub-package of an installed app (422 WRITABLE_PACKAGE_REQUIRED), and a disabled package's nav contributions stay in the app #28117), so this is display and permission-reading drift, not an authorization hole. A concrete defect with a measured repro:pm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Claim: PM loop round 4 · card thread · 2026-11-02T03:34Z
Session:
session_0186vfjHHMsRXC9EUT9hTFMo(the seat); the card thread issession_01FEkQ5nncLaiWjVh2cS7U17Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-ads4rl(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」; triage kept p3. Ruling A on #28117 binds: a disabled package is hidden and refused on the data plane. Rows 1 and 2 taken; row 3 answered by row 2.
File surface: the runtime builder behind
/auth/me/permissionsand the #24400 action-withholding seam (one disabled-package predicate each); their tests and one dogfood pin; changesetContainer & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: mediumClause-②: yes (narrowing) expected — the permissions answer and the served action list leave out a disabled package's objects and the actions that launch into it; the dev measures and declares
Metadata-protocol: narrowed (expected; the permissions answer and the action list serve less for a disabled package; the dev measures and declares)
Responsibility: the dev makes the permission catalog skip a disabled package's objects and withholds an action whose flow target or objectOverride object belongs to a disabled package, red first with ablation; the seat runs the contract review and lands
Thread-read: none
Premise: measured by HotCRM on 18.2.0 (hotcrm#2383 comment 6567537276); triaged pm:queue p3
Serial constraints cleared: none; overlap re-read before pr_create
Resume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_01FEkQ5nncLaiWjVh2cS7U17
os-dev-report
{
"issue": 28877,
"status": "done",
"branch": "claude/project-thread-ads4rl",
"pr": "#28969",
"session": "session_01FEkQ5nncLaiWjVh2cS7U17",
"premise_still_valid": true,
"summary": "Row 1: core buildEffectiveObjectPermissions gains an optional isObjectPackageDisabled source accessor and, as its last step, drops every object it answers true for; registryObjectPackageDisabled(registry) is the one reading (the registry's own isObjectPackageDisabled, the data plane's predicate), handed over by both /auth/me/permissions (plugin-hono-server) and ISecurityService.getEffectiveObjectPermissions (plugin-security), so can() answers false and the two maps stay byte-equal. Row 2: objectql SchemaRegistry.isActionWithheldByDisabledPackage extends #24400's boundServedActions rule (own package disabled) with three arms: objectName object of a disabled package, a type flow target only disabled packages ship (isFlowOfDisabledPackage), a param objectOverride object of a disabled package; asked by the served object fold (attached and the object's own merged actions) and by the protocol's effective served action list and served by-name read; execution face, per-package layer and code layer unchanged. Row 3 answered by row 2: with the action withheld the param dialog is not reached, its text is not reworded. Premise correction: before this PR GET /meta/action withheld only an action whose OWN package is disabled; an enabled package's action bound by objectName to a disabled object stayed listed (measured, probe listed= true byName= true object= OBJECT_PACKAGE_DISABLED), so the objectName arm was added as a bounded in-place fix on the same predicate.",
"tests": "On 934a10f: objectql bound-action-foreign-object.test.ts + package-disable-enforcement.test.ts 47/47; core effective-object-permissions.test.ts 41/41; hono current-user-endpoints-effective-objects.test.ts 6/6; security get-effective-object-permissions.test.ts 65/65. Full suites on de04ea7: core 2896/2896, objectql 10044/10044, metadata-protocol 22093 passed 26 skipped, plugin-hono-server 467/467, plugin-security 5127 passed 45 skipped. Typecheck exit 0 for all five. Red first on main, row 2 (registry.ts, protocol.ts, protocol-meta-item-face.ts at BASE b15b634, metadata-protocol rebuilt, preflight absent): objectql 2 failed / 45 (disabled case, twin-flow case), row-1 files all green. Row 1 (omission call ablated via ablation-replace, core rebuilt, preflight absent): core 3 failed / 38, objectql 1/46, hono 1/5, security 1/64, all row-2 cases green. Ablations each red only their own case: A3 protocol filter only (1 fail, on the list assertion), A4 flow arm (2), A5 objectOverride arm (1), A6 own-actions filter (1), A7 flow-registration invalidation (1, twin-flow case), A8 objectName arm (1 of 47). Every restore: blob == HEAD, git diff HEAD empty, git status clean; dist rebuilt from HEAD after each build-backed leg (preflight present).",
"gates": "Local union on 934a10f: dispatch-gates --commands derived 71; 70 exit 0 (check:type-check-debt re-run after the verify lock freed: 0 raw tsc errors, none above record; check:i18n exit 0); 1 NOT MEASURED: pnpm check:dual-build-cjs-loads exit 3 PREREQUISITE (needs every package dist), left to CI. dispatch-gates --ran: 71 derived, 70 run, 1 NOT-MEASURED, 0 UNRUN. check-plugin-teardown-shape --self-test exit 0 after git fetch --depth=1 of its pinned fixture commit. CI check-runs on PR #28969: in_progress at report time (not awaited, per os-dev). Gate record: pm-orders/server/28877-gates-ran.txt.",
"dogfood_battery": "934a10f5 · os-verify-lock VERDICT command-exit 0 (held 2086s) · Test Files 382 passed, 3 skipped (385) · Tests 3156 passed, 28 skipped (3184) · no failure",
"mcp_calls": "8 — issue_read x4 (get/get_comments on #28877, get on #24400), pull_request_read get_files x2 (#28903, #28889), list tools only; no MCP write",
"api_writes": "1 relay write — fleet-write pr_create #28969 (run 41391705808, read-back identical); plus this os-dev-report comment via post-stamped; git push x2 (not REST)",
"open_questions": [],
"out_of_scope_findings": [
"carrier: seat — the fields slot of /auth/me/permissions still carries OBJECT.FIELD entries of a disabled package's objects; harmless (no object entry, data plane refuses), not filed, noted in Acceptance notes",
"carrier: seat — POST /actions/OBJECT/ACTION reads through the execution face and still answers the launch's own 404 (Flow not found) for a withheld action; unchanged by design, noted"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Landing record · PR #28969
domain:serverseat 2 ·session_0186vfjHHMsRXC9EUT9hTFMo· 2026-11-02T06:02Zd0df8731(+510 / -18, 13 files)git merge-base --is-ancestor d0df8731 origin/maingit ls-remote origin refs/heads/gh-readonly-queue/*matching 28969git grep -c isActionWithheldByDisabledPackage origin/main -- packages//auth/me/permissions(and the security service's effective object permissions) leaves out a disabled package's objects, using the data plane's own predicate. Re-enabling restores them.objectOverrideobject is served only by a disabled package is withheld wherever spec(object-extension): the extension refusal saysdefineStack()attaches a top-level action withobjectName: '<target>', but for another package's object it is never attached and the served object lacks it #24400 withholds (the served object fold, the effective served action list and the by-name read).404, or the ADR-0110 D3 no-declaration404for an embedded-only action), navigation, the disable door, the data plane.defineStack()attaches a top-level action withobjectName: '<target>', but for another package's object it is never attached and the served object lacks it #24400'sobjectNamearm did not withhold an action bound to a disabled package's object on/meta/action. This PR fixed that arm in place under the same predicate; the review accepted it as in scope.fields-slot finding is carried as a note; it does not block and no card is opened for it now.Release: ships
patchfor core, objectql, metadata-protocol, plugin-hono-server and plugin-security with the BREAKING banner (ruling A on #25105), at the next release.State:
pm:dispatchedand the assignee removed by this record. The card closes throughFixes #28877.Resume-from: none.
Generated by Claude Code