Skip to content

plugin-spec.mdx's PLUGIN MANIFEST examples still pin @objectstack/core at ^2.0.0 (kernel-resolved surface, not the npm one #17378 repaired) — with the kernel-resolution leg unmeasured #18188

Description

@claude

Surfaced by #17378's dev as an out_of_scope_findings entry and reported rather than swept into that PR — correctly, because it is a different surface. ⛔ Unlabelled for domain:* and ungraded; routing and grading are triage's. ⛔ The filer did not dedupe; dedupe words at the bottom.

Two surfaces on one page, and only one of them was repaired

content/docs/protocol/kernel/plugin-spec.mdx carries version ranges in two different roles:

surface resolved by status
the npm package.json example (devDependencies) npm ✅ repaired by #17378 / PR #18186 (^2.0.0 → ^17.0.0 on @objectstack/cli and @objectstack/core)
the plugin manifest examples — ManifestSchema.dependencies, a Record<packageId, versionRange> the kernel, ⛔ not npm ⚠️ untouched

The manifest examples still pin '@objectstack/core': '^2.0.0' (two sites), and a third site teaches '2.0.0' as a deliberate exact pin in a pin-vs-caret lesson.

@objectstack/core publishes 2.0.0–2.0.7 and its current version is 17.4.0 — the same fifteen-major gap #17378 measured.

⛔ The load-bearing leg is UNMEASURED, and is named so nobody inherits a guess

Does the kernel actually resolve @objectstack/core as a manifest dependency at plugin load?

  • If it does → copying the example fails at load, and this is class (a).
  • If it does not → it is an inert wrong number, and it belongs in a PR's acceptance notes rather than in a card.

⛔ Neither #17378's dev nor the domain:devx seat measured this. ⛔ Do not grade this card as (a) on the strength of the sibling card — the sibling's surface is npm, which is a different resolver with a different failure mode.

⚠️ The third site is a CONTENT decision, not a mechanical repair

The '2.0.0' exact pin is the worked example of a lesson about pinning versus caret ranges. Changing the number without reading the lesson around it can leave the prose arguing for one thing and demonstrating another. ⛔ Whoever takes this reads that section before touching the number.

Suggested shape (⛔ a proposal, not a prescription)

  1. Establish the kernel-resolution leg first — it decides whether this is a bug or a tidy-up, and therefore what the acceptance bar is.
  2. Then repair the two caret sites to whatever the kernel actually accepts for a 17.x line.
  3. Treat the pin-vs-caret lesson's number separately, with its prose.

Acceptance

  1. The kernel-resolution question is answered with a reading (a call site, or a test that loads a manifest with a dependencies entry), ⛔ not reasoned from the npm side.
  2. Any number changed is consistent with what that reading says the kernel accepts, with a firing control that the probe discriminates.
  3. The pin-vs-caret section still argues and demonstrates the same thing after the edit.

⚠️ Related context, ⛔ not asserted as duplicates: #17378 (the npm surface, repaired) and #16756 (the typescript key on the adjacent line). ⚠️ The #15952 epic (pm:epic) is recorded as holding this page — check whether this belongs inside that subtree before routing it to a lane.

Dedupe words

plugin-spec manifest dependencies · objectstack/core caret 2.0.0 · kernel resolver versionRange · ManifestSchema dependencies · pin vs caret lesson


Generated by Claude Code

Activity

  1. os-try-charles commented on Sep 16, 2026

    @os-try-charles
    Collaborator

    Claim: PM loop round 5
    Session: session_017ef78bLdybu3AffehKkhfk
    Branch: claude/issue-18188-manifest-example-version-ranges
    Worktree: objectstack-issue-18188
    Domain: domain:devx
    File surface: content/docs/protocol/kernel/plugin-spec.mdx (stop on breach; explain in the report) — packages/** is reachable read-only, for the kernel-resolution reading the acceptance asks for
    Container & model: S, mode:subagent, model: opus — this call's --tier on content/docs/protocol/kernel/plugin-spec.mdx printed "no path-derived mandate: the surface hits none of the 3 declared glob(s), derived here, not recalled", so the tier is the PM's judgment call and stays at the default.
    Clause-②: no
    Thread-read: 5690478248
    Serial constraints cleared: none in flight — open-PR listing taken at 2026-09-16T09:19Z (the same reading as the #17472 claim in this round), each PR's file list re-read immediately before this claim; all 13 open PRs had their file lists read and zero touch plugin-spec.mdx; the npm-side predecessor PR #18186 (card #17378) is merged (076bb975de, 2026-09-14T12:55Z). ⚠️ Named, not a constraint: epic #15952 (pm:epic, domain:cli, unassigned, no PR) holds the Plugin Testing section of the same file at :758-765 — a different section and a different subject, so this card is not inside that subtree.

    ⚠️ N = this session's 5th dispatch round; this is its second card. It is independent of #17472, not a fold member — the two file surfaces are disjoint.

    Pre-claim probe — every site the card names is still there, at these lines

    Probed at 2026-09-16T09:22Z in a detached worktree at origin/main f04be62aa (⛔ not the shared checkout). The file is 990 lines.

    site line text
    manifest example #1 60 '@objectstack/core': '^2.0.0',
    manifest example #2 436 '@objectstack/core': '^2.0.0',
    the pin-vs-caret lesson 942 '@objectstack/core': '2.0.0', // Not '^2.0.0'

    Firing control @objectstack/core = 12 hits in this file · dark control = 0, both taken from the probed file itself.
    @objectstack/core's current version read from packages/core/package.json = 17.4.0 — the card's number, confirmed.

    ⚠️ One thing the card does not name. The same two manifest examples also carry '@objectstack/ui': '^2.0.0' at lines 71 and 462 — same shape, same page, same dependencies map. ⛔ I am not grading them: @objectstack/ui is not a package in this repository (no packages/*/package.json declares that name), so whether ^2.0.0 is wrong for it is not answerable from this checkout. The dev reports what it finds and ⛔ changes nothing there without a reading.

    Fences carried into the dispatch

    • ⛔ The load-bearing leg is UNMEASURED and stays that way until someone measures it: does the kernel actually resolve @objectstack/core as a manifest dependency at plugin load? If yes → class (a); if no → an inert wrong number. ⛔ Do not infer it from the npm side — a different resolver with a different failure mode.
    • ⛔ The line-942 exact pin is the worked example of a lesson about pinning versus caret. Read the section before touching the number; the prose and the demonstration must still argue the same thing afterwards.
    • ⛔ The suggested three-step shape in the card is a proposal, not a prescription.

    PM seat domain:devx · round 5, second card · 2026-09-16T09:23Z


    Generated by Claude Code

  2. os-try-charles commented on Sep 16, 2026

    @os-try-charles
    Collaborator

    os-dev-report

    {
      "issue": 18188,
      "status": "done",
      "branch": "claude/issue-18188-manifest-example-version-ranges",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/18415",
      "premise_still_valid": true,
      "summary": "The three sites the card names were all still present at the stated lines and are now repaired: the two PLUGIN MANIFEST `dependencies` carets at :60 and :436 move from '^2.0.0' to '^17.0.0' (matching the npm half of the same page, already at '^17.0.0' since PR #18186), and the pin-vs-caret worked example at :942 moves from '2.0.0' / comment 'Not ^2.0.0' to '17.4.0' / comment 'Not ^17.0.0', which keeps that lesson's argument (exact pin beats caret) form for form. HALF THE CARD'S FRAMING IS FALSIFIED BY THE READING IT ASKED FOR: the manifest `dependencies` surface is kernel-CONSUMED but not kernel-RESOLVED. Both production consumers take Object.keys(...) only, so the version range value is never parsed and a wrong one fails nothing at load -- an inert wrong number, not class (a). Because the page's prose implied an enforcement that does not happen, the PR also adds one Callout under 'Version Constraints' naming the two real consumers and the dead SemanticVersionManager/DependencyResolver pair, and re-anchors the 'Pin Core Dependencies' reason on the installer and on package.json (which npm does resolve) instead of on a kernel check that does not exist. The @objectstack/ui sites at :71 and :462 are deliberately UNCHANGED -- see open_questions.",
      "tests": "KERNEL-RESOLUTION READING (the load-bearing leg), call site first: manifest.dependencies has exactly two production consumers, both Object.keys(...) only -- packages/core/src/artifact-packages.ts:282 (ids -> resolvePluginOrder as optionalDependencies) and packages/metadata-protocol/src/protocol.ts:5346 (ids walked transitively for the write-scope closure). SemanticVersionManager/DependencyResolver (packages/core/src/dependency-resolver.ts) have ZERO production importers. Instrument controls, all from the probed corpus: SUBJECT grep 'dependency-resolver.js' = 2 hits, both non-production (index.ts:126 barrel re-export, dependency-resolver.test.ts:2 its own unit test); FIRING CONTROL 'plugin-order.js' (same dir, same barrel, same export form) = 5 hits incl. 4 production importers; DARK CONTROL 'dependency-resolver-NOSUCH.js' = 0. The instrument discriminates. EXECUTED LEG against built packages/core/dist/index.js calling resolveArtifactPackageOrder :: exit 0 -- S1 '@objectstack/core':'^2.0.0' -> OK [com.acme.a]; S2 '^17.0.0' -> OK [com.acme.a]; C-VALUE firing control 'NOT-A-VERSION-RANGE-@@@' on the same key -> OK [com.acme.a] (nothing parses the value); C-KEY firing control, SAME garbage value but the key names a sibling IN the artifact -> [com.acme.b, com.acme.a], flipped from the declared [a, b] (the keys DO have an observable effect, so the probe discriminates); C-DARK no dependencies -> [com.acme.a, com.acme.b] declared order preserved. EXISTING PIN RUN: pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/artifact-load-path.test.ts :: exit 0, 14/14 passed, incl. 'leaves a dependency on a package OUTSIDE the artifact to the installer' which declares '@steedos/plugin-auth':'^2.0.0'. VERSION READINGS: packages/core/package.json = 17.4.0; npm registry @objectstack/core latest = 17.4.0, 157 versions (firing); @objectstack/ui -> {\"error\":\"Not found\"} (dark leg of the same two-legged query), and no package.json under packages/ or apps/ declares that name (firing control @objectstack/core -> packages/core/package.json; dark control nonsense name -> 0). GATES: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack content/docs/protocol/kernel/plugin-spec.mdx -> 39 families; all 39 run with exit codes recorded; --ran reconciliation prints '39 derived famil(ies) accounted for -- 39 run, 0 NOT-MEASURED (a DERIVED zero)'. 38 of 39 :: exit 0. ONE RED, PROVEN NOT MINE: pnpm check:cross-package-test-inputs :: exit 1, flagging packages/cli/test/init-created-files-summary.e2e.test.ts descending into packages/spec/dist/ -- neither path in this diff. ABLATION: git checkout 7358c1c5b -- the mdx (on-disk proof: my added marker count 0, base marker \"'@objectstack/core': '^2.0.0',\" count back to 2), re-ran the gate :: exit 1 with the identical FAIL line ==> the red survives removal of my diff. RESTORE proven two ways: git diff HEAD empty for that path, and git hash-object = f948028b39a1dd0e1f3959bf1c1c628674f3c8ae = the HEAD blob. CI corroborates: 'Lint & Repo Gates' completed success on 7358c1c5b (this branch's merge base). PREREQUISITE NOT MET, not a verdict: pnpm --filter @objectstack/spec run check:skill-examples first exited 1 refusing on an unbuilt packages/client-react/dist; after pnpm --filter '@objectstack/client-react...' build it :: exit 0 (258 prose examples type-check across 3 surfaces). LOCK: every build/test went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-18188-dev. VERDICT lines verbatim: 'os-verify-lock: VERDICT command-exit 0 - held the lock 256s (4m16s) - waited 0s'; 'os-verify-lock: VERDICT command-exit 0 - held the lock 14s - waited 0s'; 'os-verify-lock: VERDICT command-exit 1 - held the lock 5s - waited 1s' (wrong build order, my error); 'os-verify-lock: VERDICT command-exit 0 - held the lock 466s (7m46s) - waited 0s'. REPO-WIDE LINT, no narrowing: pnpm lint (eslint . --no-inline-config) :: exit 0 at 7cbd43373, whose tree bf6b9c0f5c708647871a55046be254192c1a8b8d is byte-identical to PR head d4f2919c2 (the amend was message-only, verified by comparing both commits' tree oids). CHANGESET READING: 77 package.json scanned, 70 non-private, 0 of them lacking files[], 0 of 70 files[] arrays mention 'content' (SUBJECT), 70 of 70 mention 'dist' (FIRING CONTROL); apps/docs -- the only renderer of content/docs -- is private:true with no files[]. Zero published bytes move ==> skip-changeset, applied to PR 18415 via the additive labels endpoint and read back ['size/s','skip-changeset'], nothing stripped (size/s was added concurrently by the size labeler, not by me). CONTROL-CHAR SCAN: grep -naP over the edited file :: exit 1 (no matches = clean).",
      "mcp_calls": "0 - no MCP GitHub tool was called; every GitHub read and write went through the REST proxy with curl and $GITHUB_TOKEN",
      "api_writes": "3 REST writes, plus 1 git push. POST /repos/objectstack-ai/objectstack/pulls (draft PR 18415); POST /repos/objectstack-ai/objectstack/issues/18415/labels (skip-changeset, additive); POST /repos/objectstack-ai/objectstack/issues/18188/comments (this os-dev-report). git push -u origin claude/issue-18188-manifest-example-version-ranges (the empty-branch routing probe succeeded; the commit push was REFUSED once by the pre-push hook and retried after amending -- see open_questions). No PATCH of any body, no POST /issues.",
      "open_questions": [
        {
          "question": "@objectstack/ui at plugin-spec.mdx:71 and :462 carries '^2.0.0' in a peerDependencies block. I changed nothing there, per the dispatch fence. Two readings: no package.json under packages/ or apps/ declares that name, and the npm registry answers {error: Not found} for it (the same query returns a 157-version packument for @objectstack/core, so the probe discriminates). The page's own callout at :425-429 already says peerDependencies is proposal-only and nothing resolves it. So the range is a version constraint on a package that exists in neither place, inside a block the page says nothing reads.",
          "options": [
            "A - leave both sites as they are: the block is declared proposal-only, so the number is doubly inert and changing it invents a fact",
            "B - file a separate card asking whoever owns the @objectstack/ui name whether the examples should name a package that exists (e.g. @objectstack/client-react) or be dropped with the proposal-only block",
            "C - drop the peerDependencies examples entirely, since the schema declares no such key"
          ],
          "recommendation": "B, because the reading is decisive about what is NOT true (the package is not here and not on npm) and silent about what should replace it -- that is a naming/ownership decision, not a docs repair, and C would delete a documented proposal without a ruling."
        },
        {
          "question": "CONFLICT between the dispatch prompt and the repo's enforced rules, reported rather than silently chosen. The dispatch specified verbatim commit trailers 'Co-Authored-By: Claude Opus 5 (noreply@anthropic.com)' and I put 'Part of #18188' in the commit message. The pre-push hook check:commit-card-trailers REFUSED the push on both counts, citing .claude/agents/os-dev.md: the card relation belongs only in the PR body, and the trailer pair must be model-free.",
          "options": [
            "A - follow the hook: amend to 'Co-authored-by: Claude (noreply@anthropic.com)' plus the Claude-Session trailer, and move 'Part of #18188' to the PR body only",
            "B - use OS_ALLOW_CARD_TRAILER_PUSH=1 to push the dispatch's literal wording"
          ],
          "recommendation": "A, taken. The hook and the agent rules outrank the dispatch wording, and the hook's own text warns the override is for histories that are not yours to reword. The amend was message-only -- both commits share tree bf6b9c0f5c708647871a55046be254192c1a8b8d. Flagging it so the PM can correct the dispatch template."
        }
      ],
      "out_of_scope_findings": [
        "noted, not filed: plugin-spec.mdx:470-471 still introduces the version-constraint grammar through SemanticVersionManager.satisfies(), which this PR's reading shows has no production call site. The new Callout directly above it now states that, so the page no longer misleads, but the sentence still leads with a dead symbol. Successor: whoever next edits this page's Dependency Management section -- a live successor, since this card and #16756 have both landed in it this month. Not filed: it is a phrasing candidate, not an error a reader can be burned by now that the callout is there.",
        "noted, not filed: pnpm check:cross-package-test-inputs :: exit 1 on any tree where packages/spec/dist/ is built (it flags packages/cli/test/init-created-files-summary.e2e.test.ts descending into that dir with no declared glob reaching inside). NOT a defect in the code: 'Lint & Repo Gates' is green on CI at the same commit 7358c1c5b, so this is a local-run-only asymmetry between a built dev tree and CI's. Successor: every developer or agent who builds packages/spec and then runs the derived gate list locally -- i.e. anyone taking a docs card on this surface, which is how I hit it.",
        "noted, not filed: this page's manifest examples also carry '@mycompany/base': '1.0.0 - 2.0.0' at :61 and :437. Left alone deliberately -- @mycompany/base is a fictional illustrative package, so no reading can call its range stale, and the hyphen form is the page's only demonstration of the two-bound syntax. Successor: none; recorded so a future sweep does not read the surviving '2.0.0' substrings on this page as a missed site."
      ]
    }

    Generated by Claude Code

  3. os-try-charles commented on Sep 16, 2026

    @os-try-charles
    Collaborator

    Both open questions discharged — ⛔ no needs-user-decision is owed here

    The patrol's H52 row fires on this card because the newest os-dev-report (comment 5695604851) carries two non-empty open_questions entries while the card carries no needs-user-decision label. Answering both here, in the order the protocol asks for.

    ① @objectstack/ui at plugin-spec.mdx:71 / :462 — ⭐ filed as a NEW card, which is the prescribed remedy

    This is a residual raised while executing this card's ruling, ⛔ not the question this card was dispatched on. Per the protocol that means ⛔ never re-hang the label here — a re-flagged card leaves the inbox unable to say which question is open, and this card's close would take the label and the question's only visibility with it.

    ⇒ Filed as #18417, carrying all three readings with their controls (no package.json under packages/ or apps/ declares that name; the npm registry answers Not found while the same query returns a 157-version packument for @objectstack/core; and this page's own callout at :425-429 declares the peerDependencies block proposal-only), and leaving the three candidate outcomes ungraded — because the reading is decisive about what is not true and silent about what should replace it, which is a naming/ownership decision rather than a docs repair.

    ⭐ The dev's recommendation was B — file rather than choose — and it was right for exactly that reason.

    ② The commit-trailer conflict — ⛔ not a maintainer question

    It is a defect in the PM's own dispatch template, so it was the PM's to answer, and it is answered. scripts/check-commit-card-trailers.mjs:300 declares DECLARED_COAUTHOR = 'Claude <noreply@anthropic.com>', and :876 / :931 assert that the exact string the template carried is the offending trailer the gate quotes back; .claude/agents/os-dev.md:282 states the same rule. The dispatch template now cites that rule rather than transcribing the literal. The dev took the hook over the dispatch wording and ⛔ declined the OS_ALLOW_CARD_TRAILER_PUSH=1 override — both calls were right.

    ⇒ Both questions are answered and ⛔ nothing on this card is waiting on a human. Recorded here because there will be no further os-dev-report on this card whose empty open_questions could stand the row down.

    PM seat domain:devx · round 5 · discharging H52 from the 10:10Z patrol · 2026-09-16T10:19Z


    Generated by Claude Code

  4. os-try-charles commented on Sep 16, 2026

    @os-try-charles
    Collaborator

    落地 —— PR #18415 已合并,两读数确认

    读数一 队列分支   本 PR 的队列分支已消失;队列里现在是
                      gh-readonly-queue/main/pr-18410-0c573f09f9f6acdee64a6075f73de88792b40fc7
                      —— 那个基底 0c573f09f9 正是本 PR 的 squash
    读数二 内容探针   origin/main tip 0c573f09f(重新 fetch 后取)
                      '@objectstack/core': '^17.0.0'   2   (落地前 0)
                      '@objectstack/core': '^2.0.0'    0   (落地前 2)
                      '17.4.0'                         1   (落地前 0)
                      文件 990 → 1009 行
                      暗对照 zzq_nonexistent           0
    squash            0c573f09f9  2026-09-16T10:09Z  父数 1(squash 形状)
    

    ⚠️ 一处发火对照要说清楚,不糊过去:我原本把 @objectstack/core 的全文件计数当作"前后不变"的发火对照,预期 12。落地后读到 13。差额有确切来源 —— 本 PR 新增的 Callout 里有一句 "exported from @objectstack/core"。⇒ 这个对照被 diff 自己移动了,所以它证明了仪器有反应,但 ⛔ 它不是一个"不变量"对照。真正未被触碰的对照是 @objectstack/ui = 2,落地前后一致,而那正是本卡明确不碰的两个站点。

    验收三条,逐条对照卡自己写下的条件

    卡的验收条件 结果
    ① kernel 解析那条腿以读数回答,⛔ 不从 npm 面推 ✅ 答案是不解析。两个非测试消费者都只取 Object.keys(…)(artifact-packages.ts:281-283、protocol.ts:5346-5348,逐字读过);SemanticVersionManager/DependencyResolver 的符号只出现在自己文件与自己单测里 ⇒ 0 个生产调用点。发火对照 plugin-order 13 个文件,暗对照 0。⭐ 这条读数推翻了卡自己的一半前提:不是 class (a),是无害的错数字
    ② 改动的数字与该读数一致,且探针能分辨 ✅ 两处 caret → ^17.0.0(与同页 npm 面 #18186 已修到的版本一致),钉版课 → 17.4.0 / // Not '^17.0.0'
    ③ 钉版 vs caret 那一节改后仍论证同一件事 ✅ 论点(精确钉版优于 caret)形式不变;并且把理由从一个并不存在的 kernel 检查改挂到安装器与 package.json(npm 确实解析它),新增的 Callout 把真实消费者写进了页面

    ⭐ 值得单独记一句:这张卡被派去改三个数字,dev 带回来的却是卡自身前提被证伪,并且去修前提而不是症状。

    关卡,⛔ 无余项

    本 PR 用 Part of,⇒ 卡不自动关闭,由本席判。三条验收全满足,没有留下任何一半 ⇒ 关卡。

    ⚠️ 唯一的邻接问题已另立卡而不是留在这里:@objectstack/ui 在 :71 / :462 的两处 → #18417(三条读数带对照,三种处置不判)。这是协议对残留问题的处方:⛔ 不在本卡重挂 needs-user-decision,因为本卡的关闭会把标签和那个问题的唯一可见性一起带走。

    同笔清半态:pm:dispatched 摘除 · assignee 清空。

    PM seat domain:devx · round 5 · 2026-09-16T10:22Z


    Generated by Claude Code

  5. removed their assignment
    on Sep 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions