Skip to content

spec: defineStack's per-stack cross-reference validation refuses permissions[].objects and data[].object that name an object owned by ANOTHER PACKAGE OF THE SAME ARTIFACT — so ADR-0130's co-owned artifact and the "permission sets stay whole in the app package" addendum cannot both hold once the app package owns objects #18202

Description

@os-elon-musk

Finding (class b — a declared contract that cannot be satisfied)

ADR-0130 D4 lets one artifact carry N packages sharing a namespace, with dependencies between them; its 2026-09-02 addendum (objectstack#14487) rules that permission sets stay whole in the type: app package. On @objectstack/spec 17.4.0 those two records cannot both hold as soon as the app package owns objects of its own: defineStack validates cross-references per stack, and a permission set in the app stack that grants on an object owned by a module stack is refused.

Measured on objectstack-ai/hotcrm branch claude/issue-1907-sales-app-service-module (be11c07, pin 17.4.0), where sales is the type: app package (15 objects) and service is a type: module (3 objects, dependencies: { 'app.objectstack.hotcrm': '^3.1.0' }), composed with composeStacks([service, app], { manifest: 'preserve' }):

$ pnpm validate
defineStack cross-reference validation failed (18 issues)
  … permission set grants on crm_case / crm_knowledge_article / crm_article_feedback — "not defined in objects" (18 grants across 7 sets)

data[].object is refused the same way (Seed data references object crm_case which is not defined in objects), so the service package had to carry its own seed rows.

Why the addendum's own measurement did not see this: hotcrm#1449 measured a shape where the app package declared no objects at all, which is exactly the case the check early-returns on — stack.zod.ts validateCrossReferences: if (objectNames.size === 0) return errors;. The moment the app package owns one object, the check runs and refuses every grant on a dependency's object. The composed pass (composeStacksos build's union) accepts the identical grants, and the runtime registers both packages, resolves ownership (GET /api/v1/packages: 15 + 3 objects), and serves the app correctly — measured on a dev boot with an identical browser walk against main.

The only local escapes are strict: false on the app stack (disables every schema check for the whole package) or splitting the sets per package (contradicts the addendum, and per-package grant composition is objectstack#14488 — filed, not decided). hotcrm's charter forbids routing around a platform defect, so the packaging card waits on this.

Ask

Make the per-stack check dependency-aware: an object owned by a package named in manifest.dependencies (or, more simply, any object present in the composed artifact) counts as defined for permissions[].objects, data[].object and the other reference classes the check covers — or defer those classes to the composed pass, which already has the union. Either way the addendum's shape becomes authorable. If the intended answer is instead "a package's grants must be on its own objects", then the addendum needs re-ruling and #14488 needs deciding — say which.

The refusal must MOVE, not disappear. Whatever mechanism is chosen, a reference to an object that no package in the artifact defines must still be refused, loudly, at some named pass. A fixture proving that is an acceptance criterion, not a nicety — deleting the check is the one outcome worse than today's false refusal.

Dedupe words: permission set, cross-package, defineStack, cross-reference validation, ADR-0130 dependencies, objectNames.size === 0, co-owned artifact.

Related: objectstack-ai/hotcrm#1904 (epic), objectstack-ai/hotcrm#1907 (the blocked card), #14487 (the addendum), #14488 (per-package grant composition), #18170 / #18171 / #18203 / #18204 (sibling gaps from the same split).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:specpriority:p1High: required for production / M2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions