Skip to content

finding(deps): Dependabot npm updates fail at objectui root since the pin landed — pnpm update --lockfile-only cannot find the pinned-build directory client (dependency_file_not_resolvable); security updates included #13008

Closed

Description

@objectstack-fleet

Filing gate: a finding from a landing this seat holds. objectui#12957 (PR #12963, merged 749ed760) moved every @objectstack/* package to file:node_modules/.cache/objectstack/NAME, a directory only pnpm run setup creates. The seat's answer on that PR (Q1) was: read Dependabot's first npm run after the merge, and file a follow-up if it fails. It failed. Filed by domain:ui seat 1 (session_0188TsgPV8kQXfuRuKmkj2ks), which dispatches it under the maintainer's 「你负责派发处理相关的issue,包括 objectstack 和 objectui 并测试确认。」. ⛔ Not a claim.

Measured

  • Dependabot job 39180936608 (run at 00:28Z, 2026-10-19, one minute after the merge) was a security-advisory update: Security advisory dependency: next, Updating next from 16.3.6 to 16.3.8, rebasing objectui#11845.
  • It ran pnpm update next@16.3.8 --lockfile-only --no-save -r, which exited 1. Result: next | dependency_file_not_resolvable | "Could not find linked package installation directory \"client\"".
  • The same failure was reproduced locally before the merge: pnpm install --lockfile-only without the pinned build exits 1 with ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND (PR feat(tooling): objectui consumes @objectstack/* by commit — .objectstack-sha, bump-objectstack.sh, dev and CI built from the pin (objectui#12957) #12963, acceptance notes).
  • So every npm update Dependabot runs against / fails from now on: the monthly version updates in .github/dependabot.yml and the security updates. The github-actions ecosystem is unaffected.
  • objectui#11845 was already red on Type Check before the merge (merge-gate comments of 2026-10-18 08:31Z and 08:52Z). That is a separate problem and is not this card's.

Options

  • B (try first): make the lockfile resolvable without a build. Track the seven packed package.json manifests of the pin in a committed directory, point the overrides there, and have scripts/objectstack-pin.mjs build fill in the built files beside them. A --lockfile-only resolution needs only the manifests. This keeps Dependabot, including security updates, working with no new workflow.
    • It must keep what objectui#12957 guarantees: the frozen install, the check that the lockfile records each packed manifest's dependency names, the stand-in through OBJECTSTACK_ROOT, and scripts/bump-objectstack.sh writing the manifests together with the pin.
  • A (fallback, the default the seat named on PR feat(tooling): objectui consumes @objectstack/* by commit — .objectstack-sha, bump-objectstack.sh, dev and CI built from the pin (objectui#12957) #12963): an in-repo scheduled update workflow. It runs pnpm run setup, then the updates, and opens the PRs. Dependabot's npm entry for / is removed. It also has to cover advisories, because Dependabot security updates for npm would stop.
  • The seat moved B ahead of A because the failure measured above is a security update, and A drops that path unless it rebuilds it.

Done when

  1. B is measured: a clean clone with no node_modules runs pnpm update <dep> --lockfile-only -r to exit 0, and pnpm run setup then pnpm install --frozen-lockfile still exit 0 with the lockfile unchanged. If B cannot keep every guarantee listed under it, the report names the one it breaks, and the dev builds A instead.
  2. A Dependabot npm run, or the A workflow's run, succeeds on main after the change. The run id is recorded.
  3. No @objectstack/* package resolves from npm, and objectui#12957's tests and gates stay green.

Generated by Claude Code

Activity

  1. added
    domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repo
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    on Oct 19, 2026
  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: priority set, p1 · domain:devx · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T00:58Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read: objectui origin/main 749ed76076. Every @objectstack/* override in the root package.json is file:node_modules/.cache/objectstack/<name> (:203ff), a directory only pnpm run setup creates.
    • p1. npm security-advisory updates for objectui's root stopped with the merge, and the measured run (39180936608) was one. A repo that cannot take an advisory bump is a security gap, and it does not wait for the monthly cadence.
    • Option order as filed: B first, because it keeps Dependabot's advisory path. A, if B breaks a guarantee, adds a workflow, not a gate. ⛔ No new gate either way.

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_01FM29ZqLTrnPNXxijioZwMp
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-13008-pin-lockfile-resolvable
    Worktree: objectui-issue-13008
    Domain: domain:devx
    Seat: domain:devx#1 (objectui, seat post #5748)
    File surface: objectui's root package.json (pnpm.overrides), pnpm-lock.yaml, scripts/objectstack-pin.mjs with its tests, scripts/bump-objectstack.sh, .gitignore, and one new committed manifests directory for option B; for option A only, .github/dependabot.yml and one new workflow (.github/workflows/** is Tier H governed: draft for an authorised approval). ⛔ No edit in objectstack-ai/objectstack: its scripts/build-console.sh and .github/workflows/spec-shape-gate.yml read this pin's override names and run objectstack-pin.mjs build under OBJECTSTACK_ROOT, and both must keep working unchanged (stop on breach; explain in the report).
    Container & model: M (a lockfile-resolution redesign with a clean-clone measurement), mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate")
    Clause-②: no
    Responsibility: objectui#12957's pin layout (PR #12963, 749ed760) points every @objectstack/* override at a directory only "pnpm run setup" creates | none: Dependabot's npm path for "/" has no other carrier, security advisories included | Dependabot, on every npm run at "/"; measured on job 39180936608 (a security advisory for next) on 2026-10-19
    Thread-read: 6257405170
    Serial constraints cleared: no open objectui PR touches the root package.json, scripts/objectstack-pin.mjs, scripts/bump-objectstack.sh or .github/dependabot.yml (read at 2026-10-19T06:45Z); Dependabot's #11845 touches pnpm-lock.yaml and is this card's failing subject, not a sibling. objectstack-ai/objectstack#24424 (linked, so held out of the same batch) landed as PR #24469 at 2026-10-19T06:36:04Z. #12972 also edits scripts/objectstack-pin.mjs and stays queued behind this card. objectstack-ai/objectstack#24476 (another seat) moves objectstack's .objectui-sha to an objectui commit before this card's change, a different repository's file.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 13008,
    "status": "done",
    "branch": "claude/issue-13008-pin-lockfile-resolvable",
    "pr": "#13031",
    "session": "session_01FM29ZqLTrnPNXxijioZwMp — the dispatching seat's session (subagent run; the commits carry it as Claude-Session)",
    "premise_still_valid": true,
    "summary": "I built option B. Every @objectstack/* override now names file:.objectstack-pin/NAME, a committed directory holding only that package's packed package.json at the pin, so a lockfile-only resolution (Dependabot's) needs no build. objectstack-pin.mjs build still builds into node_modules/.cache/objectstack (the path CI caches) and hard-links the rest of the build beside the manifests. A build at the pin refuses loudly when a committed manifest is not the pin's; a stand-in writes its own manifests and the next build at the pin restores exactly those. bump-objectstack.sh builds the new pin with --write-manifests and commits .objectstack-sha together with the manifests, and it restores the old pin when that build fails. The root preinstall (objectstack-pin.mjs check) keeps a bare install without the build loud instead of linking hollow packages. Measured but not anticipated: two packs of the same pin order dependency keys differently, so manifests are committed and compared in a canonical form (dependency maps sorted, exports untouched). The card's assignee is os-warren and was not touched; the PR assignee mirrors it.",
    "item1_exit_codes": {
    "subject": "fresh git clone --depth 1 of cd2035a, no node_modules, pnpm 10.31.0",
    "pnpm update next@16.3.8 --lockfile-only --no-save -r --config.minimum-release-age=0": 0,
    "pnpm run setup": 0,
    "pnpm install --frozen-lockfile": 0,
    "git diff --exit-code pnpm-lock.yaml": 0,
    "control: same update on a fresh clone of main 4484a11": "1 (ERR_PNPM_LINKED_PKG_DIR_NOT_FOUND, client: the Dependabot failure reproduced)",
    "control: bare pnpm install --frozen-lockfile before setup on the fresh clone": "1 (preinstall check refuses, names pnpm run setup)"
    },
    "tests": "All at head cd2035a unless a sha is named. (1) Under the lock, pnpm exec vitest run scripts/ (the whole scripts tree, from the repo root): Test Files 189 passed | 2 skipped (191), Tests 5667 passed | 2 skipped, VERDICT command-exit 0. The earlier run at 4c21dbe had 2 failures, both fixed or explained. check-installed-spec-pin-claims read my fixture's identifier PINNED plus version 1.0.0 as a pin claim; I renamed the identifier. dollar-dialect-alias-census hit its 15s timeout on the shared box and passed alone and in the final run. (2) objectstack-pin.test.ts + bump-objectstack.test.ts + check-installed-spec-pin-claims.test.ts: 66 passed. New cases cover the pin refusing a differing or missing committed manifest, write mode, the stand-in restoring exactly what it replaced and nothing else, dependency-order canonicalisation that leaves exports order alone, a hard link (same inode), the install check, and the bump building with --write-manifests (OBJECTSTACK_ROOT unset), committing the pin with its manifest, and restoring the pin byte for byte when the build fails. (3) Item 1: see item1_exit_codes. At b164a7c the same clean-clone setup exited 0; at 4c21dbe it refused, which is the live firing of the drift refusal that found the pack-order nondeterminism. (4) Stand-in lifecycle on my branch, tree = a clone of /home/user/objectstack at main e11ae4b, installed and built: OBJECTSTACK_ROOT=TREE objectstack-pin.mjs build exit 0 (7 manifests modified, stamp external with replaced recorded); then pnpm install --frozen-lockfile 0 and lockfile diff 0; then objectstack-pin.mjs build back at the pin 0, git status clean; then frozen install 0 and lockfile diff 0. The literal OBJECTSTACK_ROOT=/home/user/objectstack build exits 1 with ERR_PNPM_CANNOT_RESOLVE_WORKSPACE_PROTOCOL, because that tree is neither installed nor built; nothing was written there. (5) H2 probes on scratch clones. pnpm hard-links a file: directory (same inode, link count 2). The lockfile stays byte-identical after the built files appear. Lockfile-only runs skip the root preinstall (marker file empty); its control, a real install, ran it. A symlinked dist is not followed. (6) No ablation: these are tooling scripts, which the role file exempts. The drift refusal's own firing control is the real refusal on the 4c21dbe clean clone.",
    "gates": "Local, exit codes captured before any pipe: pnpm check:new-line-citations 0 (VERDICT 0 new citations) · check:entry-guard 0 · check:lockfile-integrity 0 (VERDICT clean) · check:pre-install-import-graph 0 · check:test-path-roots 0 · check:installed-pin-claims 0 · node scripts/check-changeset-presence.mjs 0 (no changeset owed, same form as objectui#13024) · node scripts/check-governed-queue-guard.mjs --test (20 changed paths) 0, NOT GOVERNED · pnpm type-check:scripts 0 (tsc -p tsconfig.scripts.json) · turbo run type-check --filter=@object-ui/types 0 (2 tasks: @object-ui/types:type-check, //:type-check:e2e) · eslint --no-inline-config on the changed scripts and tests plus eslint.config.js 0 (0 errors; a probe of .objectstack-pin/spec/src/stack.zod.ts reads 'File ignored because of a matching ignore pattern') · control-byte grep over the changed files: no match. dispatch-gates.mjs does not apply (objectstack-only), so there is no --ran reconciliation; I derived the subset from objectui's AGENTS.md and package.json. Not run locally, declared to CI: pnpm test (full), pnpm type-check (all packages), pnpm lint (repo scan). CI check-runs on PR head cd2035a at report time, 35 listed: success = Changeset Claim Re-read, Changeset Declaration, Changeset Fixed Group Check, Governed Surface Queue Guard, Line Citation Gate, Lockfile Integrity Check, label; skipped = Test (coverage), Test (coverage shard 8-wide), dependabot; in_progress = Build & E2E, Build Docs, Bundle Analysis, Lint, Live E2E (informational), Lockfile Dedupe Check, Repo Gates, Test (dist pins), Test (shard 1/16 to 16/16), Type Check.",
    "line_budget": "Outside pnpm-lock.yaml and the generated manifests: +402 -76 = 478 against the ~300 budget. 430 of those are the pin and bump scripts plus their tests; the overrun is the canonical-manifest fix and the install check, both forced by measurements. Generated: .objectstack-pin manifests +757 (pnpm pack output, canonicalised). pnpm-lock.yaml +113 -113, a pure path rename: main's lockfile with sed node_modules/.cache/objectstack/ to .objectstack-pin/ diffs empty against it (exit 0).",
    "files_changed": [
    ".objectstack-pin/{client,core,formula,lint,sdui-parser,spec,types}/package.json (new)",
    ".gitignore",
    "eslint.config.js",
    "package.json (overrides + preinstall)",
    "pnpm-lock.yaml",
    "scripts/objectstack-pin.mjs",
    "scripts/bump-objectstack.sh",
    "scripts/tests/objectstack-pin.test.ts",
    "scripts/tests/bump-objectstack.test.ts",
    "scripts/tests/check-lockfile-integrity.test.ts (outside the claim's surface: its samples read the real lockfile by literal key)",
    "scripts/check-lockfile-integrity.mjs (header and self-test key spelling)",
    "scripts/check-installed-spec-pin-claims.mjs (header key spelling)",
    "scripts/tests/ci-cd-pipeline-doc.test.ts (one comment)",
    "content/docs/guide/ci-cd-pipeline.md (one sentence)"
    ],
    "deviations": [
    "The file surface goes beyond the claim's list. eslint.config.js: the spec packs TypeScript src/ beside the manifest. check-lockfile-integrity.test.ts: it would go red on the renamed keys. Plus three comment or header spellings and one docs sentence that the rename made false. All are named in the PR body.",
    "Line budget overrun: 478 vs ~300 (see line_budget).",
    "One MCP read (get_job_logs) to read Dependabot's job log, because the REST log download's blob redirect gets a 403 from the container proxy. No MCP write.",
    "During a symlink probe I appended a 16-byte marker line to my worktree cache's types/dist/index.mjs. I removed exactly those bytes, verified by the tail bytes and a marker count of 0. The clean-clone measurements did their own builds and were not affected. The worktree has since been removed.",
    "A stray 5-byte file /pinbuild1.pid sits at the container's filesystem root: a misplaced pid redirect (shell variable unset in the parent shell). The harness safety check blocked its removal; delete it by hand.",
    "The dispatch's literal OBJECTSTACK_ROOT=/home/user/objectstack build refuses because that tree is not installed or built, and it is read-only for me. I measured the stand-in with an installed and built local clone of it at e11ae4b instead.",
    "Commit trailers follow objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude). The harness's model-named trailer was not used.",
    "The preinstall check is a choice I settled myself, analysed on the four axes in the PR body. It is not a CI gate and can be dropped by removing one line."
    ],
    "mcp_calls": "1 — mcp__github__get_job_logs (read: job 117833339145 of Dependabot run 39180936608). No MCP write tool.",
    "api_writes": "2 strokes, both through the fleet relay (repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]). (1) pr_create, relay run 39220064016: POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/13031/assignees [os-warren]. Read back: 11670 bytes sent and stored, identical. (2) post-stamped: this os-dev-report comment, POST /repos//issues/13008/comments. git push (5 pushes to the claim branch) is not a REST write. No labels were written (objectui: no reader, and the dispatch named none).",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: PM seat (governed edit, needs an authorised approval) · objectui AGENTS.md §9's dependency and lockfile section still names file:node_modules/.cache/objectstack/NAME as the override value, and the ENOENT text after removing node_modules. After this PR the override is file:.objectstack-pin/NAME, and a bare install refuses in the preinstall check. noted, not filed",
    "carrier: PM seat (governed workflows) · the comments on the 'Restore the pinned @objectstack build' steps in objectui ci.yml, lint.yml, lockfile-dedupe.yml and changeset-release.yml say every package resolves from node_modules/.cache/objectstack. Resolution now reads the committed manifests; only the install needs the build. The cache step itself stays right. noted, not filed",
    "carrier: PM seat (per dispatch H4) · objectstack-ai/objectstack comments naming file:node_modules/.cache/objectstack/NAME: scripts/build-console.sh (the 'Install THIS framework's @objectstack/* too' block) and .github/workflows/spec-shape-gate.yml (the 'Build what objectui installs' and 'Pack this commit's @objectstack/*' step comments). Their behaviour is measured unchanged. noted, not filed",
    "承接者:无 · scripts/check-lockfile-dedupe.mjs still requires the pin's build stamp before reading; under B a dedupe resolution no longer needs the build. Stricter than needed, not wrong. Read-only inference. noted, not filed",
    "承接者:无 · apps/console/vercel.json's installCommand is a bare pnpm install --frozen-lockfile with no pin build. It has refused since objectui#12957 (ENOENT) and still refuses (preinstall). Read-only inference; no deploy log read. noted, not filed",
    "承接者:无 · GitHub's dependency graph may now list the 7 committed .objectstack-pin manifests as npm manifests. Unmeasured; worth a look at the item-2 post-landing reading. noted, not filed"
    ],
    "hypotheses": "H1 holds at 4484a11 (re-measured). H2 holds: lockfile-only resolves from manifests alone, the install hard-links (build first, which setup already does), and the lockfile is unchanged when the built files appear. H3: refuse loudly at the pin, write only via --write-manifests or a stand-in, canonical comparison. H4: both consumers work unchanged (keys, build subcommand, OBJECTSTACK_ROOT hook, objectstack:build, the @objectstack+spec@ virtual-store prefix), and the stand-in lifecycle was measured. H5: not harder for objectui#12972, because materialize() takes its source directory as an argument; a cross-filesystem shared build falls back to a copy."
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · objectui domain:devx seat 1 (#5748) · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-19T08:50Z

    reading result
    merge queue (gh-readonly-queue/main/pr-13031-* heads) none left: the entry has drained
    PR object PR #13031 merged at 2026-10-19T08:49:34Z (not governed; landed by this seat on its ACCEPT 6263049661)
    origin/main at b014f5eea5, by content squash commit b014f5e (PR #13031); root package.json:209 reads "@objectstack/spec": "file:.objectstack-pin/spec" (and likewise for the six others), and :20 carries "preinstall": "node scripts/objectstack-pin.mjs check"; git ls-tree lists exactly seven tracked files under .objectstack-pin/, one package.json per package

    State change: PR #13031 closed this card through Fixes #13008 (completed); pm:dispatched comes off in this act.

    Carried onward:


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Done-when item 2, read: met · objectui domain:devx seat 1 · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-19T11:54Z

    run created head conclusion
    39180936608 "npm_and_yarn in / for next" 2026-10-19T00:28Z 749ed76076 (before) failure (the card's filing reading)
    39211087445 same 2026-10-19T06:38Z 4484a11041 (before) failure
    39225694872 same 2026-10-19T08:50Z b014f5eea5, PR #13031's merge success
    39229950306 same 2026-10-19T09:25Z 30083da918 success

    Read from GET /repos/objectstack-ai/objectui/actions/runs?event=dynamic. The first two Dependabot npm security runs at / after PR #13031 landed both succeeded. That is the run the card's item 2 asks for, so the card stays closed completed and nothing is carried. The one-shot reading trig_01PPPzm7NjSo97jGSBFkbjBh has fired.


    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

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedependenciesdomain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopriority:p1tooling

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions