Skip to content

[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

Description

@os-zhuang

Found while closing the member-existence blind spot in check:published-readme-exports (#10893). Filed unassigned, no pm:queue — triage's call. This is #10893's second shape, which that card said was not decidable offline and deliberately left open.

The observation

The #10893 sweep measured every @objectstack/ token in the 60 published documents against the workspace member map. After the repairs, four names remain that this repo does not build, and all four are legitimate as written — they are prose, not runnable imports:

name named in what the tree says it is
@objectstack/security-enterprise packages/plugins/plugin-audit/README.md:365 the enterprise hierarchy resolver. packages/cli prints pnpm add @objectstack/security-enterprise as a capability hint, and packages/cli/test/capability-preflight.test.ts:74 pins that message
@objectstack/service-tenant (removed from READMEs by #10893, still in source) the cloud control-plane runtime — packages/spec/src/system/constants/platform-object-names.ts:132-134: "Objects contributed by the CLOUD runtime (@objectstack/service-tenant, defined in the separate cloud repository)"
@objectstack/framework packages/console/README.md:3, 13, 25 the umbrella install name — pnpm add @objectstack/framework, also in packages/console/package.json's description and packages/cli/src/utils/console.ts:17
@objectstack/organizations packages/plugins/plugin-security/README.md (added by #10893) the enterprise multi-org runtime — packages/cli/src/commands/serve.ts:2423 tells the operator to add it to their app

Two more are historical names, correct because the sentence is about the past: @objectstack/service-external-datasource and @objectstack/service-datasource-admin, which packages/services/service-datasource/README.md:11-12 names as the packages it used to be.

Why it is worth a card

Nothing declares any of this. A reader cannot tell an out-of-repo package from a fabricated one, and neither can a gate — which is exactly why #10893's new assertion is fenced to import statements only: measured on 409077e93c, zero published documents import an out-of-repo @objectstack/ package from a fence, so the fence costs nothing today and an allowlist would have been a population of zero. That fence holds only while the count stays zero.

The sharper half is @objectstack/framework. It is not a passing mention — it is an install command in a published README, and it names a package that is in no workspace directory of this repo. Either it is published from somewhere this repo does not record, or the canonical install instruction for the framework is wrong. Nothing here can tell which, and that is the finding.

The question that has to be answered before anything is built

May a published README name an @objectstack/ package this repo does not build, and if so, where is that declared? Three shapes, and picking one is a ruling rather than a scan:

⛔ Not a rider on #10893: that card's PR closes the offline-decidable half and says in its body that this half wants its own card.

Refs: #10893 / its PR (the offline half, and the measured fence) · #10920 (knowledge-turso, the same question on a runtime surface) · #9532 · #10368

Activity

  1. huangyiirene commented on Aug 21, 2026

    @huangyiirene
    Collaborator

    First-touch grading (triage seat, session session_013ELWDeai2Y6Wqrh7DmkUV6): promoted out of finding into the decision inbox. domain:devx kept — the roster/gate half lands in scripts/. This card is made the parent for the shared prior question; #10920 (the runtime-surface instance) is being marked pm:blocked against it rather than entering the inbox separately, per the same-family meta-criterion.

    Why it is not queueable as filed: the body's three shapes each widen what a gate accepts (a roster admits fenced examples the current fence forbids; a probe decides admission from the network). That is the mechanical boundary test for the manual floor — accepted-set expansion — so no seat rules on it.

    [facets-block] 四棱分析(业务视角)

    一句话问题:我们公开的文档和产品运行时提示里,可以出现「这个仓库不构建的 @objectstack/ 包」吗?可以的话,它从哪发布这件事记在哪?

    客户可感知的代价:今天 packages/console/README.md 的第一条安装指令是 pnpm add @objectstack/framework,而这个包不在本仓任何目录里。它要么真的在别处发布(那我们只是没记录),要么我们的头号安装指令是坏的。读者分不出来,gate 也分不出来。同类还有三个:CLI 会打印 pnpm add @objectstack/security-enterprise(且有测试 pin 住这句话)、serve.ts 让运维加 @objectstack/organizations、spec 常量注释指向 cloud 仓的 @objectstack/service-tenant。

    选项 客户端效果 我们付的代价
    A 建声明式名册(一行一个仓外包 + 它从哪发布) gate 能放行真实仓外包的可运行示例,读者能查到出处 多一个必须保持真实的文件
    B 只允许散文提及、机械强制(#10893 后的现状) 永远不能为一个真实在别处发布的包写可运行示例 零成本,但把一条合法用例永久关死
    C 联网查 registry 判定 自动、永远准 把这族刻意离线的 gate 拉上网(限流、离线 CI 失效)

    行业类比:像文档里写「请安装我们的企业版插件」,但公司内部没有任何一张表说明企业版插件由哪个团队发布、发布到哪 —— 客服和文档作者只能互相打听。

    ① 实际业务需求:这四个名字里至少一个(@objectstack/framework)是安装指令,不是顺带提及,而且被 CLI 的一条测试 pin 住。⚠️ 但这一半严格说不是决策题,是没人查过的事实题 —— 见下面的推荐。
    ② 项目长远合理性:A 把「仓外包」从口头知识变成声明,与 contract-first 同向;B 永久禁止一类合法用例;C 破坏这族 gate 一致的离线设计,为一个问题引入一整类新故障。
    ③ 防 AI 写错:今天读者和 gate 都区分不了「仓外包」与「凭空捏造的包」—— AI 会照抄 README 里的 pnpm add,这正是批量犯错被掩盖的温床。A 的「声明即强制」最对症;B 至少保住 gate 的响亮拒绝;C 把判断权交给网络。
    ④ 创业阶段不扩散:B 零成本;A 一个文件加一份保持真实的义务;C 最贵。

    推荐:先答事实,再选形状。 四个包到底发布没发布、发布在哪,这个读数一旦有了,选项就塌缩了 —— 如果它们真在别处发布,A 几乎是唯一诚实的选择;如果一个都没有,那这些根本不是治理问题,是四处文档/运行时错误,按 B 修文本即可,连 ruling 都不需要。⛔ 不推荐 C。

    本分析看不见什么:① 本席无法从仓内查 npm registry,四个包的发布状态是零读数,而它决定 A 与 B 谁对;② cloud 仓不在本会话的 GitHub 授权面,@objectstack/service-tenant 的归属无法自查;③ @objectstack/framework 是否是伞包(umbrella)发布名,本仓无任何记录。

    裁决格式(低摩擦):你如果知道这四个包发布在哪,回一句话就够了 —— 我据此直接路由(有出处 ⇒ A 建名册;没有 ⇒ B 修四处文本)。你如果也不确定,回「查」,我路由一张 S 级测量卡(查这四个名字的发布状态与出处)进 domain:devx 队列,本卡挂 Blocked-by: 等它。也可以直接回 A / B / C 覆盖以上。

    裁后执行段:本卡裁定落地时,同笔解除 #10920 的 pm:blocked(它等的是同一个前置事实,不会自己解锁 —— 本卡即使转成工作态仍是 open,解锁扫描看不见)。


    Generated by Claude Code

  2. huangyiirene commented on Aug 22, 2026

    @huangyiirene
    Collaborator

    Maintainer ruling recorded (2026-08-22, decision-inbox digest with the skills seat, session_01ApyDuQY2fkunMCqXiqvBhR)

    The full decision inbox (46 cards) was presented with per-card four-axis recommendations; the maintainer accepted the batch, verbatim: 「接受所有」.

    Ruled: Measure first — the triage recommendation ("先答事实,再选形状") is adopted as-is. This card's first step is the measurement described in the recommendation: establish the publication status and provenance of the four out-of-repo names (@objectstack/framework, @objectstack/security-enterprise, @objectstack/organizations, @objectstack/service-tenant). The A/B fork is decided by the measured result, not now: packages that really are published elsewhere collapse the choice toward A (a declared roster with provenance); if none are published, this is four documentation/runtime text errors to be fixed under B's shape, with no governance ruling needed. Option C (a registry probe at gate time) is not taken. The post-ruling execution note stands: when this card's fork resolves, the same change unblocks #10920, which waits on the same prior fact.

    State: needs-user-decision removed → pm:queue (ready for dispatch).


    Generated by Claude Code

  3. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    The ruled measurement is taken — and the fork collapses mixed, 3 fabricated / 1 real

    The maintainer's ruling of 2026-08-22 (5377356971, from the 46-card digest accepted 「接受所有」) made this card's first step a measurement: "establish the publication status and provenance of the four out-of-repo names", with the A/B fork decided by the result and option C not taken.

    The triage analysis said it could not take that reading — "本席无法从仓内查 npm registry,四个包的发布状态是零读数,而它决定 A 与 B 谁对". This seat can. Taken 2026-08-23T06:2xZ, unauthenticated GET https://registry.npmjs.org/@objectstack%2F<name>:

    name registry verdict
    @objectstack/framework 404 not publicly resolvable
    @objectstack/security-enterprise 404 not publicly resolvable
    @objectstack/organizations 404 not publicly resolvable
    @objectstack/service-tenant 200, dist-tags.latest = 4.1.0 real, published

    Positive control, because a bare 404 proves nothing on its own: @objectstack/spec → 200. So the endpoint works, the @objectstack scope is publicly readable, and service-tenant returning a real version from that same scope proves an out-of-repo package does publish there. The three 404s are therefore a reading about those names, not about my access.

    ⚠️ The one caveat, stated rather than glossed: npm answers 404 for a private package as well as a nonexistent one, and this probe is unauthenticated. So the strict claim is "not publicly resolvable", not "does not exist". For three of these that distinction does not rescue the text, because the operative fact is identical: a public reader who runs the command we print cannot install it.

    What this makes of the four cases

    Three are broken instructions we ship to users — and these are not passing mentions, they are commands:

    • packages/console/README.md:3,13,25 — pnpm add @objectstack/framework is the first install instruction of a published README.
    • packages/cli prints pnpm add @objectstack/security-enterprise as a capability hint, and packages/cli/test/capability-preflight.test.ts:74 pins that string — so the test currently guarantees we keep telling users to install a package they cannot install.
    • packages/cli/src/commands/serve.ts:2423 tells the operator to add @objectstack/organizations.

    One is real — @objectstack/service-tenant@4.1.0, exactly as packages/spec/src/system/constants/platform-object-names.ts:132-134 describes it (contributed by the cloud runtime, defined in the separate cloud repo). Its prose is correct and must not be "fixed".

    How that lands against the ruling

    The ruling: "packages that really are published elsewhere collapse the choice toward A (a declared roster with provenance); if none are published, this is four documentation/runtime text errors to be fixed under B's shape." The measured world is neither pure branch — it is one of each — so the honest reading of the ruling is that both of its arms fire, each on its own rows: B for the three fabricated names (fix the text, and the test that pins it), and, for service-tenant, the provenance question A exists to answer. Because that is a population of one, whether it earns a roster file is a live judgement rather than a foregone A; a card dispatched off this comment should say which it chose and why, and is free to conclude that one row does not need a registry.

    ⭐ Worth stating plainly, because it reprices this card: it was filed as a governance question about where a roster lives. The measurement says the sharp half is not governance at all — three customer-facing install commands name packages the customer cannot install, one of them defended by a passing test. That is the finding.

    ⛔ Not acted on here beyond the reading. Dispatch follows from this seat in the same round; #10920 waits on this same prior fact and is unblocked by whatever lands, per the ruling's standing execution note.

    Seat devx@objectstack, session session_01SPBxLsqQGCVL5z5UXvgipH.


    Generated by Claude Code

  4. self-assigned this
    on Aug 23, 2026
  5. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01SPBxLsqQGCVL5z5UXvgipH
    Branch: claude/issue-10921-out-of-repo-package-names
    Worktree: objectstack-issue-10921
    Domain: domain:devx
    File surface: packages/console/README.md, packages/cli/src/utils/console.ts, packages/cli/src/commands/serve.ts, packages/cli/test/capability-preflight.test.ts, packages/plugins/plugin-audit/README.md, packages/plugins/plugin-security/README.md (README only in that package), plus a .changeset/ entry (stop on breach; explain in the report)
    ⛔ Fenced OUT of the surface: packages/spec/** is the spec seat's sole territory — read it, never edit it; if the fix needs a spec edit, stop and report for routing. scripts/** and root package.json are owned this round by #10738 — do not add a gate or a check: alias here.
    Container & model: M, mode:subagent, model: opus — node scripts/pm/dispatch-gates.mjs --tier <surface> printed "no path-derived mandate: the surface hits none of the 3 declared glob(s)", so the floor is not raised by path; opus is this seat's judgement call, because the card requires deciding A-vs-B per row against a maintainer ruling and editing a test that pins a user-facing string.
    Clause-②: no — the change corrects install/runtime text that names unresolvable packages and updates the test pinning it. It neither changes contract accept/reject behaviour nor widens the public surface; if anything it narrows what we tell users to install. No packages/spec/src/** path is in the surface.
    Serial constraints cleared: no open PR touches any file in this surface. The 6 open PRs are #11246 (engine/services runtime), #11244 (packages/spec — fenced out here), #11241 (service-datasource), #11211 and #11183 (packages/plugins/plugin-security/src/** — ⚠️ same package as one of my files, different file: they touch src/, I touch README.md only; declared rather than assumed), #10183 (Version Packages, maintainer-only, untouched). Cross-lane note: packages/cli/** is domain:cli territory by the anchoring rule — the domain:cli seat post reports 在飞 0 and no open PR touches packages/cli, so there is no live collision; the routing question is raised for triage in the round report rather than re-labelled here.

    Measurement backing this dispatch is on 5384607091: three of the four names are not publicly resolvable (framework, security-enterprise, organizations → 404, against a @objectstack/spec → 200 positive control), and @objectstack/service-tenant is real at 4.1.0.


    Generated by Claude Code

  6. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    ⚠️ PM correction — my reading on 5384607091 was wrong on two of the three, and the caveat that catches it is one I wrote myself

    The dev re-took the measurement and reached a different split. It is right and I am recording that here rather than only in the PR, because my comment stands on this card as a confident finding another seat could act on.

    My numbers reproduce exactly. framework, security-enterprise, organizations → 404; service-tenant → 200 at 4.1.0; positive controls @objectstack/spec and @objectstack/cli → 200. Nothing about the registry reading changed.

    What was wrong is the inference. I treated three 404s as three fabricated names. I even wrote the caveat that refutes that — "npm answers 404 for a private package as well as a nonexistent one, and this probe is unauthenticated" — and then reasoned in the very next paragraph as if it did not apply. It applies to two of the three.

    name my reading measured against the tree
    @objectstack/framework fabricated fabricated ✅
    @objectstack/security-enterprise fabricated ❌ real, deliberately private — declared with provenance in PLATFORM_CAPABILITY_PROVIDERS as edition: 'enterprise'
    @objectstack/organizations fabricated ❌ real, deliberately private — "closed-source" (serve.ts:2576), "cloud-private" (serve.ts:228,253,2618, verify/src/harness.ts:44,153,466,487), one citing cloud#1013

    Verified independently from this seat on origin/main before accepting the correction — I did not take it on the dev's word:

    • packages/spec/src/kernel/platform-capabilities.ts:121 really does export PLATFORM_CAPABILITY_PROVIDERS with package / edition (open|cloud|enterprise) / note, and :60 records that hierarchy-security ships in @objectstack/security-enterprise.
    • git grep returns eight sites calling @objectstack/organizations closed-source or cloud-private across two packages.
    • @objectstack/framework: no workspace package of that name exists, and packages/console/README.md:25 presents it as the default public install — "Default install for @objectstack/framework consumers". Nothing anywhere calls it private or enterprise. So that one is genuinely a public install command for a package no reader can install.

    So "three broken install commands" is wrong; it is one. The other two are real packages whose hints already carry their edition boundary, and "fixing" them would have been precisely the vacuity this card warned about.

    ⭐ And option A is already built — which is a better answer than the one I proposed

    I suggested a population of one might not earn a roster file. The dev found the roster already exists: PLATFORM_CAPABILITY_PROVIDERS is exactly "one row per out-of-repo package with where it ships" — package + edition + a prose note, drift-tested against the capability vocabulary and read by both the CLI preflight and cloud's runtime. Three out-of-repo packages already have rows.

    So the right move was to add no roster, no gate and no check: alias — a second one would be the failure that file's own header names: "A second description nobody checks is how that happens; one exported list is how it stops." That resolves the ruling's A/B fork better than either arm as written: A's artifact was already there.

    The one genuine gap — @objectstack/organizations has no row, because the map is keyed by requires token and that package is plugins[]-wired off the tenancy posture — needs a packages/spec/** edit, which I fenced out of this card. Correctly routed to #11263 for the spec seat instead of being done here.

    This is the second time this round a dev re-derived instead of building on what I handed it, and the second time that is the only reason a wrong reading did not become a wrong change. The dispatch asked to be falsified; it was.

    Seat devx@objectstack, session session_01SPBxLsqQGCVL5z5UXvgipH. ACCEPT for PR #11266 follows once its CI converges — currently green-so-far and still running.


    Generated by Claude Code

  7. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    os-dev-report

    {
      "issue": 10921,
      "status": "done",
      "branch": "claude/issue-10921-out-of-repo-package-names",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/11266",
      "premise_still_valid": false,
      "summary": "The four sites are real and the card was actionable, but two of its load-bearing premises are falsified by the tree, so this is reported as premise_still_valid:false with a PR covering only what survived. (1) The card says 'Nothing declares any of this' and offers option A, 'a declared roster with provenance'. That roster ALREADY EXISTS: PLATFORM_CAPABILITY_PROVIDERS in packages/spec/src/kernel/platform-capabilities.ts carries package + edition ('open'|'enterprise'|'cloud') + a prose note, is drift-tested 1:1 against the capability vocabulary, and is read by both the CLI preflight and cloud's objectos-runtime. Three out-of-repo packages already have rows. So no roster was added — a second one is the exact divergence that file's own header warns against. (2) The PM's ZONE 2 assumption of '3 fabricated / 1 real' is inverted: it is 1 fabricated / 3 real. The registry numbers reproduce exactly (framework/security-enterprise/organizations 404; service-tenant 200@4.1.0; controls spec 200@17.1.0 and cli 200@17.1.0), but the READING was wrong. This tree calls organizations and security-enterprise 'closed-source' and 'cloud-private' in ~a dozen places (serve.ts:229, serve.ts:2576, verify/src/harness.ts:44, one citing cloud#1013), and security-enterprise is declared edition:'enterprise' in the roster above — so their 404 is exactly the private-package caveat the PM flagged, not fabrication. Only @objectstack/framework is genuinely fabricated: nothing in the tree calls it enterprise/cloud/private, it is presented as the DEFAULT PUBLIC install, and the real onboarding path (npx create-objectstack, blank template) never names it. Fixed: console README and cli/src/utils/console.ts now name the real mechanism (@objectstack/cli declares @objectstack/console, both in the Changesets fixed group), corrected rather than deleted so the reader keeps a runnable command; serve.ts's multi-org remedy now states that @objectstack/organizations is closed-source and not on the public registry, which is the un-followable 'add it to your dependencies' that framework#3366 exists to make legible. NOT changed, deliberately: security-enterprise's hint (already edition-legible), plugin-audit/README.md:365 and plugin-security/README.md:42,48 (re-read, already correct prose — which also keeps this PR clear of #11211/#11183 in that package).",
      "tests": "All verification on final commit ce44f6057 (tree clean, 0 dirty paths). Targeted: `pnpm --filter @objectstack/cli exec vitest run test/capability-preflight.test.ts --maxWorkers=2` -> 'Test Files 1 passed (1) / Tests 15 passed (15)'; `pnpm --filter @objectstack/cli typecheck` -> clean. Dependency closure built first (`pnpm --filter '@objectstack/cli^...' build`, then the full lint.yml-shaped `turbo run build --filter=./packages/* --filter=./packages/*/*` -> 'Tasks: 70 successful, 70 total'), so check:type-check-debt is a measurement not a refusal. ABLATION on the strengthened assertion: subject is imported RELATIVELY ('../src/utils/capability-preflight.js') and packages/cli/vitest.config.ts aliases only @objectstack/service-cache and create-objectstack, so no exports/dist resolution is involved and NO REBUILD is needed for the mutation to take effect (@objectstack/spec/kernel, where the note is read from, DOES resolve through dist and was built). Mutation confirmed on disk by counting BOTH the removed anchor (1 -> 0) and the injected marker (0 -> 1), never by an editor exit code. Mutant leg: 'Tests 1 failed | 14 passed (15)', failing exactly and only the new assertion with 'AssertionError: expected ... to contain ADR-0057 hierarchy scopes ship in the...'. Restore leg confirmed on disk (anchor back to 1, marker to 0) and re-run: 'Tests 15 passed (15)'. Script carried trap ... EXIT INT TERM. Predicted direction was RED-on-that-assertion-alone; observed exactly that. Every heavy command ran through scripts/pm/os-verify-lock.sh; all verdicts read from its VERDICT line, and every gate exit code captured before any pipe (redirect-then-capture), never from a bare $? after a tail.",
      "gates": {
        "check:nul-bytes": "PASS (plus a manual grep -naP control-byte scan of all 5 changed files: no matches)",
        "check:changeset-gate-self-tests": "PASS",
        "check:objectui-changeset": "PASS ('objectui-range --self-test: all checks passed')",
        "check:published-files": "PASS ('69 publishable package(s) of 78 workspace member(s) declare a files whitelist...')",
        "check:route-envelope": "PASS",
        "check:slot-lookup": "PASS ('slot-lookup ratchet holds: 107 unswept site(s) in 25 file(s), none new')",
        "check:test-source-alias": "PASS",
        "check:type-check-coverage": "PASS",
        "check:type-source-resolution": "PASS",
        "check:cross-package-test-inputs": "PASS ('14 package(s) read outside themselves, all declared')",
        "check:query-options-erasure": "PASS ('ratchet holds: 67 unswept non-test site(s) in 17 file(s), none new')",
        "check:engine-double-contract": "PASS",
        "check:where-matcher": "PASS ('282 matcher(s) discovered, 282 answer the combinator battery correctly or refuse it loudly')",
        "check:type-check-debt": "PASS ('check-type-check-coverage --re-measure: OK - 33 ledger entr(ies) re-measured in 225.2s, 1897 raw tsc error(s) total, none above its recorded number')",
        "check-adr-0087-registration.mjs": "PASS ('this PR adds no declared-breaking changeset')",
        "check-changeset-no-major.mjs": "PASS ('This diff introduces no major bump')",
        "check-empty-changeset.mjs": "PASS ('No empty-frontmatter changeset introduced by this diff')",
        "check-ci-filter-parity.mjs": "PASS ('all 88 declared cross-package glob(s) (76 unique) are covered')",
        "check-plugin-teardown-shape.mjs": "PASS ('63 Plugin implementation(s) across 4508 source(s)')",
        "check-affected-docs.mjs": "PASS ('affected-docs self-test: 339 cases pass')",
        "check-published-readme-exports.mjs": "PASS ('60 published document(s) across 78 workspace package(s); 212 import statement(s), 197/197 @objectstack/ specifier(s) naming a workspace member') - run because it is the gate this card descends from, though not path-derived",
        "pnpm lint (repo-wide)": "NARROWED, declared. Targeted ESLint over all 5 changed paths: 0 errors, 0 real warnings. Three evidences: (1) population read from ESLint's own resolution - it reported 3 files linted and 2 (.md) as 'File ignored because no matching configuration was supplied', not my guess at what counts; (2) counts read from --format json (5 results); (3) invariance for untouched files - eslint.config.mjs states with its own recorded positive control that this repo 'never enables type-aware linting (no parserOptions.project, no typed @typescript-eslint rules) for ANY file', so nothing in this diff can move a verdict on a file it does not touch. CI runs the full farm regardless."
      },
      "files_changed": [
        "packages/console/README.md",
        "packages/cli/src/utils/console.ts",
        "packages/cli/src/commands/serve.ts",
        "packages/cli/test/capability-preflight.test.ts",
        ".changeset/out-of-repo-package-names.md"
      ],
      "deviations": [
        "premise_still_valid:false rather than a clean 'done' - the card's 'nothing declares any of this' is falsified (PLATFORM_CAPABILITY_PROVIDERS is that declaration) and ZONE 2's 3-fabricated/1-real is inverted to 1/3. The PR covers only the half that survived. PM asked to be falsified if wrong; this is that.",
        "No roster file and no gate added, answering ZONE 3's 'say which you chose and why': neither. Option A's artifact already exists in packages/spec/src/kernel/platform-capabilities.ts with package+edition+note, drift-tested and consumed by two runtimes. A second roster is the divergence that file's header explicitly warns about. This also honours the ZONE 1 fences on scripts/** and root package.json.",
        "Surface NOT breached: all 4 edited files plus the changeset are inside the declared surface. Two surface files (plugin-audit/README.md, plugin-security/README.md) were re-read and deliberately left untouched because they are already correct - which additionally keeps this PR clear of the declared #11211/#11183 overlap.",
        "Gate list re-derived rather than trusted: `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` with NO paths passed (it reads its own change set from the merge base). It added four families the dispatch lead did not name, all via the convention-triggered bucket for editing a test file: check:query-options-erasure, check:engine-double-contract, check:where-matcher, check:cross-package-test-inputs. All four run and green.",
        "A spec edit is genuinely required for the remaining gap and was NOT made - routed to #11263 per the ZONE 1 instruction to stop and report rather than touch packages/spec/**.",
        "SANITIZER SELF-CHECK, as requested - and my first answer was WRONG, so this is the corrected one. Read through the MCP issue tools, two fragments looked truncated: comment 5384607091 showed 'GET https://registry.npmjs.org/@objectstack%2F' and claim comment 5384609407 showed 'dispatch-gates.mjs --tier ', each missing an angle-bracket placeholder, and I first reported that as sanitizer truncation. I then fetched the bodies RAW from the REST API to check, and GitHub's stored text is INTACT: 5384609407 really does hold '--tier ' followed by an angle-bracket 'surface' placeholder, and 5384607091 really does hold '@objectstack%2F' followed by an angle-bracket 'name' placeholder. Nothing was eaten on write. What drops angle-bracket fragments is the MCP issue/PR READ path, not GitHub. VERDICT: the issue body and all four comments are COMPLETE - no truncation - and nothing I acted on was affected. Consequence worth carrying: an MCP read of any body containing such a placeholder under-reports it, and the REST API is how to confirm. This comment's own marker is the same story - the HTML-comment marker survived in storage; the literal 'os-dev-report' first line was added as belt-and-braces after an MCP read appeared to show it missing.",
        "The e2e suite packages/cli/test/serve-organizations-*.e2e.test.ts (300s-timeout real-server boots) was NOT run - it is outside the declared surface and would exceed the foreground cap. Its two assertions on the text I edited are toMatch(/to THIS APP/) and toMatch(/NODE_PATH/); both literals are preserved verbatim in the edit and were grep-confirmed on disk. Declared rather than silently skipped."
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #11261: packages/console/package.json's npm `description` still names the fabricated @objectstack/framework - outside the declared surface, and the most npm-visible remaining site; one-line fix",
        "filed as #11262: packages/console/README.md:27-31 describes an @object-ui/console fallback resolveConsolePath() no longer performs, directly contradicting console.ts:26-31 - which side is stale depends on cloud's real Docker overlay target, unreadable from this repo, so it was not guessed at",
        "filed as #11263 (label `finding`): @objectstack/organizations has no row in PLATFORM_CAPABILITY_PROVIDERS because that map is keyed by `requires` token while the package is plugins[]-wired off the tenancy posture - needs a packages/spec/** edit, routed to the spec seat"
      ]
    }

    Note for triage: per the ruling's standing execution note, #10920 waits on this same prior fact and is unblocked by whatever lands here.


    Generated by Claude Code


    Generated by Claude Code

  8. os-zhuang commented on Aug 23, 2026

    @os-zhuang
    ContributorAuthor

    ACCEPT — PM review of record, PR #11266. Verified against GitHub and the tree.

    My correction of the analysis is on 5384792385 and is not repeated here; this is the delivery verdict.

    premise_still_valid: false is the right call, and it still ships a PR

    Two load-bearing premises were falsified — the card's "Nothing declares any of this" (the roster exists) and my ZONE-2 split (1 fabricated, not 3). The dev shipped only the half that survived and said so in the field designed for it. That is the contract working: a falsified premise is a re-triage input, never a failed dispatch.

    Checked

    PR form. Draft · base main · Fixes #10921 first line · 5 files, all inside the declared surface · Check Changeset success.

    Path surface from get_files-equivalent review: packages/console/README.md, packages/cli/src/utils/console.ts, packages/cli/src/commands/serve.ts, packages/cli/test/capability-preflight.test.ts, .changeset/. No governed path ⇒ ordinary landing. packages/spec/** untouched, as fenced — the one edit that would have needed it was routed out to #11263 rather than taken. Clause ② correctly no.

    CI: fully green. All 37 check runs success or legitimately skipped (Build Docs / Console Pin Gate skipped — no docs or console-dist paths). Named gate-bearing jobs green: Lint & Repo Gates, Test Core + all six shards, Build Core, Type Check · workspace / source gates / consumer gates / debt ledger, Dogfood Regression Gate (all 3 shards) + Dogfood Verify CLI, Temporal Conformance.

    The test pin was strengthened, not loosened — the outcome I asked for. It now asserts the message carries the roster's note read from PLATFORM_CAPABILITY_PROVIDERS rather than copied as a literal, so a drift between spec and CLI cannot leave both green. The ablation is properly done: mutation confirmed on disk by counting both the removed anchor and the injected marker, mutant fails exactly and only the new assertion (1 failed | 14 passed), restore confirmed on disk and re-run green, trap … EXIT INT TERM throughout. Predicted direction stated before running, observed exactly.

    Two surface files deliberately left untouched after being re-read — plugin-audit/README.md and plugin-security/README.md are already correct prose. That also keeps the PR clear of the #11211 / #11183 overlap I declared in the claim. Not editing a file you were authorised to edit, and saying why, is the right shape.

    Docs blast radius — bounded, and it is small

    The docs-drift-check advisory flagged 16 hand-written docs. I checked the one thing that would actually matter: zero occurrences of @objectstack/framework under content/, against a positive control proving content/ is searchable for that spelling (@objectstack/cli, 11 hits in one file). So the fabricated install command never reached the published docs site — its whole blast radius is package-local README / docblock / package.json. The remaining site is filed as #11261. No further action on the advisory.

    Findings filed — all three verified present, unassigned, back-linked

    #11261 (console package.json npm description still names the fabricated package — the most npm-visible remaining site) · #11262 (README describes an @object-ui/console fallback resolveConsolePath() no longer performs; correctly not guessed at — which side is stale depends on cloud's Docker overlay target, unreadable from here) · #11263 (the PLATFORM_CAPABILITY_PROVIDERS gap — spec-seat territory).

    ⛔ Note for triage: #10920 waits on this same prior fact and is unblocked by what lands here, per the ruling's standing execution note.

    The e2e suite, declared rather than silently skipped

    serve-organizations-*.e2e.test.ts (300s real-server boots) was not run — outside the surface and past the foreground cap. Its two assertions on the edited text (/to THIS APP/, /NODE_PATH/) are preserved verbatim and grep-confirmed on disk. Declaring a skip with the reason and a compensating check beats running it badly.

    ⛔ Landing HELD

    Same as #11259 and #11265: #11253 blocks 17.2.0 and is still open (PR #11257 ready and clean, not merged). This PR stays draft until that lands. Unlike the other two it shares no file with #11257, so it carries no merge hazard of its own — the hold here is purely the queue-position yield.

    Seat devx@objectstack, session session_01SPBxLsqQGCVL5z5UXvgipH.


    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