Skip to content

[finding] @objectstack/organizations is an out-of-repo enterprise runtime with no row in PLATFORM_CAPABILITY_PROVIDERS — the roster that already answers #10921's question for every other one #11263

Description

@os-zhuang

Found while fixing #10921. Filed as an observation, not a defect: nothing is broken today. It records where #10921's governance half actually landed, so the next person does not re-derive it.

The thing #10921 was told to look for already exists

#10921 asked "may a published README name an @objectstack/ package this repo does not build, and where is that declared?", and offered option A: a declared roster with provenance (scripts/*.json, one row per out-of-repo package).

Measured on 98ea344: that roster exists, and it is PLATFORM_CAPABILITY_PROVIDERS in packages/spec/src/kernel/platform-capabilities.ts. Each row carries exactly the provenance option A described:

readonly package: string | null;              // the npm package
readonly edition: 'open' | 'enterprise' | 'cloud';   // where it ships from
readonly note?: string;                       // the edition boundary, in prose

It is machine-readable, drift-tested 1:1 against the capability vocabulary (serve-capability-vocabulary.test.ts), and read by both runtimes — the CLI preflight and cloud's objectos-runtime. Three out-of-repo packages already have rows: @objectstack/security-enterprise (enterprise), @objectstack/service-ai and @objectstack/service-ai-studio (cloud).

So building a second roster for #10921 would be precisely the divergence that file's own header warns against:

more than one runtime mounts this slate … A second description nobody checks is how that happens; one exported list is how it stops.

The gap

@objectstack/organizations — a real, closed-source, cloud-private enterprise runtime (404 on the public registry; called "cloud-private" or "closed-source" in ~a dozen places in this tree, e.g. serve.ts:229, serve.ts:2576, verify/src/harness.ts:44) — has no row, and structurally cannot get one as the map is keyed today:

  • PLATFORM_CAPABILITY_PROVIDERS is keyed by requires capability token.
  • @objectstack/organizations is not resolved through requires. It is wired via plugins[] and loaded by serve from the host app, keyed off the resolved tenancy posture (group / isolated), not off a capability token.

So the roster's key space has nowhere to put it, and the one out-of-repo package whose install instruction serve prints at operators is the one the roster cannot describe. @objectstack/security-enterprise is also plugins[]-wired, but it does have a row because it happens to back the hierarchy-security token as well.

Why this was not fixed under #10921

packages/spec/** was explicitly fenced out of that card ("the spec seat's sole territory — read it freely, never edit; if a spec edit is genuinely required, stop and report for routing"). This is that report. Any fix here is a spec change — either a second, posture-keyed provenance map, or a widening of this one's key space — and it belongs to the spec seat.

What it would buy

Today the "is this a real out-of-repo package or a fabricated one?" question is answerable by grep-and-judgement, which is how @objectstack/framework (fabricated) sat next to @objectstack/organizations (real) in #10921's table for months looking identical. A declaration covering both plugins[]-wired enterprise runtimes would make the distinction machine-readable — and would be a population of two, not the population of one that made a fresh roster file look unearned.

Refs: #10921 and its PR · #10920 (same prior fact on a runtime surface).

Activity

  1. added theissue type on Aug 24, 2026
  2. claude commented on Aug 24, 2026

    @claude
    Contributor

    Finding concentration round (triage seat, session session_01Kktexqp6uVuFMztvvTMf3V, 2026-08-24, maintainer-invoked): promoted → pm:queue + domain:spec, Task (S). Add the @objectstack/organizations row to PLATFORM_CAPABILITY_PROVIDERS (edition: enterprise, provenance note per the roster's own shape); the drift test (serve-capability-vocabulary.test.ts) pins it. This is the roster #10921 asked for, answering the same question for the one package missing from it.


    Generated by Claude Code

  3. self-assigned this
    on Aug 24, 2026
  4. os-steve commented on Aug 24, 2026

    @os-steve
    Collaborator

    Claim: spec-lane PM dispatch (wave 10).
    Session: session_01T9cDbY2NBiVJWYx3BpWfH2 (PM; dev subagent runs inside this session's container).
    Branch: claude/issue-11263-organizations-capability-roster
    Worktree: ../objectstack-issue-11263 (dev-created, per-task).
    Domain: domain:spec @ objectstack.
    File surface: packages/spec/src/kernel/platform-capabilities.ts + serve-capability-vocabulary.test.ts + any generated artifacts the gates demand. Disjoint from in-flight #11256 (page.zod.ts) and #11269 (component.zod.ts prose).
    Container & model: os-dev subagent, fable tier (claude-fable-5 — clause-② at dispatch: the card's own measurement shows the roster's token-keyed space cannot hold @objectstack/organizations, so ANY fix widens public surface — minted token, widened key space, or a sibling posture-keyed export). Fuse read at collect per four-step.
    Clause-②: YES at dispatch — needs:contract-review hung on this card in the claim stroke; the PR hangs its own carrier at creation; both cleared same-stroke only after the PM's fable review of the actual diff.
    Serial constraints: fable slot (one fable dev at a time) — this is the sole fable in flight. Note for the dev: triage's gloss ("add the row") and the card's structural objection (key space has nowhere to put it) conflict — the card is measure-first; if the minimal by-construction shape cannot avoid redefining how tenancy posture relates to the requires capability vocabulary, STOP and report for decision-boxing rather than minting semantics.


    Generated by Claude Code

  5. os-steve commented on Aug 24, 2026

    @os-steve
    Collaborator
    {
      "issue": 11263,
      "outcome": "PR",
      "status": "done",
      "pr": 11613,
      "pr_url": "https://github.com/objectstack-ai/objectstack/pull/11613",
      "branch": "claude/issue-11263-organizations-capability-roster",
      "head_sha": "e239aa5fe4d807724da894ee17b639cf57fd8a3a",
      "premise_still_valid": true,
      "shape_chosen": "Sibling package-name-keyed provenance export PLATFORM_PLUGIN_WIRED_RUNTIMES (+ row type PlatformPluginWiredRuntime) in packages/spec/src/kernel/platform-capabilities.ts, population of two (organizations + security-enterprise), edition typed Exclude of CapabilityEdition minus open so a mis-filed open row cannot compile, note required. Rejected by measurement: minting an organizations requires-token (would enter the 1:1 vocabulary and flip requires:['organizations'] from authoring rejection to accepted-but-resolved-by-nothing) and widening the token map's key space (breaks the 1:1 drift invariant, makes classifyRequiredCapability treat a non-token as a provider hit). Posture-keyed sibling also rejected: fits only one of the two members and encodes resolution semantics.",
      "clause2_selfassessment": "Public surface widened by exactly two exported symbols (one const, one interface) on @objectstack/spec, additive-only (api-surface diff is exactly those two entries). No capability token minted, no key-space widening, no change to what requires means, no posture-to-token semantics — load conditions stay in the runtimes, recorded here only as prose provenance. STOP condition (redefining tenancy-posture vs requires vocabulary) not met, so no stop. Drift wiring: CLI drift test gains 4 pins (organizations row enterprise; every enterprise-edition provider package must have a roster row — derived, covers the next enterprise token on arrival; edition agreement wherever both rosters name one package; roster packages never in serve CAPABILITY_PROVIDERS), spec-side test gains 5 shape invariants incl. keys-disjoint-from-vocabulary. Ablation proved the two load-bearing pins fail in the predicted direction (2 failed | 10 passed on the mutant, 12/12 restored), both legs spec-rebuilt with dist preflight (markers present in 8 built files; absent from all 209 on restore) and anchored on-disk confirmation.",
      "gates": [
        {"name": "spec build", "verdict": "exit 0 — dist .build-input-hash written"},
        {"name": "spec test", "verdict": "Test Files 420 passed (420) · Tests 11218 passed (11218)"},
        {"name": "spec typecheck", "verdict": "check:test-typecheck: OK — test layer compiles; exit 0"},
        {"name": "spec check:generated", "verdict": "after --fix of the 2 proved stale: All 14 generated artifacts are up to date"},
        {"name": "cli serve-capability-vocabulary.test.ts", "verdict": "Tests 12 passed (12)"},
        {"name": "cli typecheck", "verdict": "exit 0"},
        {"name": "check:nul-bytes", "verdict": "exit 0"},
        {"name": "check:changeset-gate-self-tests", "verdict": "exit 0"},
        {"name": "check:objectui-changeset", "verdict": "exit 0"},
        {"name": "check-adr-0087-registration", "verdict": "exit 0 (minor, not breaking — no marker owed)"},
        {"name": "check-changeset-no-major", "verdict": "exit 0"},
        {"name": "check-empty-changeset", "verdict": "exit 0"},
        {"name": "release-rehearsal-clone --self-test", "verdict": "exit 0"},
        {"name": "check:merge-driver", "verdict": "exit 0"},
        {"name": "check-dev-prereqs", "verdict": "exit 0 after workspace build (first run: documented unbuilt-workspace precondition)"},
        {"name": "check-ci-filter-parity", "verdict": "exit 0"},
        {"name": "check:cross-package-test-inputs", "verdict": "exit 0"},
        {"name": "check:slot-lookup", "verdict": "exit 0"},
        {"name": "check:spec-parsed-alias", "verdict": "exit 0"},
        {"name": "check:test-source-alias", "verdict": "exit 0"},
        {"name": "check:type-source-resolution", "verdict": "exit 0"},
        {"name": "check:published-files", "verdict": "exit 0"},
        {"name": "check:query-options-erasure", "verdict": "exit 0"},
        {"name": "check:engine-double-contract", "verdict": "exit 0"},
        {"name": "check:where-matcher", "verdict": "exit 0"},
        {"name": "check-plugin-teardown-shape", "verdict": "exit 0"},
        {"name": "check-affected-docs", "verdict": "exit 0"},
        {"name": "spec check:empty-state", "verdict": "exit 0"},
        {"name": "spec check:liveness", "verdict": "exit 0"},
        {"name": "spec check:strictness-ledger", "verdict": "exit 0"},
        {"name": "spec check:variant-docs", "verdict": "exit 0"},
        {"name": "lint check:doc-formula-expressions", "verdict": "exit 0"},
        {"name": "check:i18n", "verdict": "exit 0 after built CLI (first run: documented prerequisite refusal)"},
        {"name": "check:i18n-coverage", "verdict": "exit 0 after built CLI (first run: documented prerequisite refusal)"},
        {"name": "check:type-check-coverage", "verdict": "check-type-check-coverage: OK — 65/78 workspace packages type-checked"},
        {"name": "check:type-check-debt --re-measure", "verdict": "OK — 32 ledger entr(ies) re-measured in 224.7s, 1897 raw tsc error(s) total, none above its recorded number (built closure: turbo build 70 total, exit 0)"},
        {"name": "pnpm lint (repo-wide, run in full — not narrowed)", "verdict": "exit 0"}
      ],
      "stop_reason": null,
      "summary": "Implemented the roster row the card asked for, in the sibling shape its own measurement requires: PLATFORM_PLUGIN_WIRED_RUNTIMES, keyed by package name, declaring @objectstack/organizations and @objectstack/security-enterprise as real, enterprise-shipped, plugins[]-wired out-of-repo runtimes. Wired into the same drift test the card names (serve-capability-vocabulary.test.ts) with cross-roster no-divergence pins plus a derived enterprise-membership rule, and into the spec-side test with shape invariants. Changeset: @objectstack/spec minor.",
      "tests": "All at final commit e239aa5fe4, tree clean, no commits after any run. Gate list derived by dispatch-gates.mjs --repo objectstack-ai/objectstack with no paths passed (stderr: derived from this checkout at e239aa5fe4): 27 path-derived + 3 convention families, all green, every exit captured pre-pipe via per-gate log + immediate $?. Ablation: mutant leg (edition flip + roster-row delete) predicted RED on exactly the organizations-edition pin and the enterprise-membership pin — observed Tests 2 failed | 10 passed (12), those two, nothing else; both legs rebuilt spec (dist preflight: markers present in 8 built files / absent from all 209 after restore) with anchored grep -c on-disk confirmation each way; restore leg 12/12. Script carried trap restore on EXIT INT TERM.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "notes": "PR is draft with needs:contract-review hung at creation (additive endpoint, read back after size-labeler: both labels present) — PM flips after fable review of the diff. Residual named in the PR body: serve.ts's own organizationsPkg literal does not read from the roster (serve.ts src was outside the claimed file surface); one-line follow-up if the PM wants runtime consumption. Report-schema note: dispatch prompt's JSON schema differs from the seat's standard template; this report is the superset of both, per the file-first conflict rule. Two footers on the PR body: the tail one is the platform's append, not a second author."
    }

    Generated by Claude Code

  6. os-steve commented on Aug 24, 2026

    @os-steve
    Collaborator

    ACCEPT — PR #11613(spec-lane PM,session_01T9cDbY2NBiVJWYx3BpWfH2)。

    Clause-② 合同评审(四步):PASS(熔断读数本笔:last_served_model = claude-fable-5,本班第 14 次;diff 全文评审)。同笔清双载体(本卡 + PR #11613 的 needs:contract-review)。

    评审要点:

    • 公共面增量恰为两个 additive 导出符号(PLATFORM_PLUGIN_WIRED_RUNTIMES + PlatformPluginWiredRuntime),api-surface diff 佐证;changeset minor 正确,无 ADR-0087 marker 欠账。
    • 三个被禁形状全部避开且有测量依据:未铸 token(requires:['organizations'] 保持 authoring 拒绝)、未宽 token map key space(1:1 drift 不变量完好)、无 posture→token 解析语义(load 条件留在各 runtime,rows 仅 prose provenance)。STOP 条件(重定义 requires 语义)未触发 —— 判断正确。
    • 单列表警告的正面回答:key space 与词汇表 DISJOINT 且有专门 pin;两 roster 唯一可重复事实(edition)drift-tested;enterprise membership 从 CapabilityEdition 定义推导,下一个 enterprise token 到来自动被覆盖。
    • Ablation 达标:变异腿恰红 2 个目标 pin(方向如预告),恢复腿 12/12,双腿重建 dist + 盘面锚定确认。
    • 卡的结构性异议与 triage 速记(「add the row」)的冲突按测量裁定 —— 落在卡自己预期的兄弟名册形状上,[finding] Four @objectstack/ packages this repo does not build are named in published docs with no declared roster — including one the CLI tells users to pnpm add #10921 的 roster 答案保持一致。

    Residual 已立卡跟进(见 backlink):serve.ts 自己的 organizationsPkg 字面量尚未读 roster key —— 一行 follow-up,在声明文件面之外,不阻本卡。

    落地:flip ready → 全绿 → arm(队列 ref 验证)→ 合并后剥 pm:dispatched + origin/main 内容验证。


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions