Repository navigation
Add automated pnpm-lock.yaml conflict resolution workflow - #81
Closed
huangyiirene with Copilot wants to merge 4 commits into
Closed
huangyiirene with Copilot wants to merge 4 commits into
huangyiirene with Copilot wants to merge 4 commits into
Conversation
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Add automation to prevent pnpm lock conflicts during merge
Add automated pnpm-lock.yaml conflict resolution workflow
Jan 15, 2026
Contributor
|
✅ All checks passed!
|
jinyitao123
referenced
this pull request
in jinyitao123/objectui
Sep 16, 2026
… action designer (#9567) Fixes #7234 Ruling B from decision batch #81 (2026-09-08), landed: a declared action whose `requiredPermissions` the viewer lacks stays invisible to end users, and the reason becomes visible where the person who configures the app looks. ## The card's premise was already falsified, and stays falsified The card says the relay drops `objectDef.actions`. It does not — PR #8123 measured the relay carrying it, the button drawn, and ADR-0066 D4's capability gate doing the hiding (differential F vs G: identical payload, identical code path, only the held capability set differs). Nothing here re-investigates that, and nothing here changes the gate. ## Which existing channel, and why this one The ruling leaves the channel to the implementer, requiring only that it already exist and add no end-user surface. Measured on `origin/main` this fire: | candidate | what it actually shows | who actually looks | verdict | |:--|:--|:--|:--| | `preview/capabilityLint.ts` | that a referenced capability string is registered **nowhere** — a typo, over PENDING DRAFTS | whoever clicks **Publish**, once, as a transient toast (`usePublishAllDrafts` passes the warnings to `toast`) | ⛔ wrong question, wrong audience. The reporting admin installed a published package: no pending drafts, no Publish click, no toast. And a toast cannot be where someone *looks* for a standing reason | | `metadata-admin/inspectors/ObjectDefaultInspector.tsx` | the **object's** `access.default` posture and the object's own `requiredPermissions` | object designers | ⛔ right family, wrong subject — this card is `action.requiredPermissions` | | **the action designer** — `inspectors/ActionDefaultInspector.tsx` + `previews/ActionPreview.tsx` | the action's Placement and *Where it appears* | exactly the person the console docs send to the Studio Data tab's **Actions** panel to configure `actions[]` | ✅ chosen | Two things settled it. The inspector's **Placement** section already carries the sibling notice for the *other* way a declared action never surfaces (empty `locations`, from #3142) — so "here is why your button will not appear" is an established job of this panel, not a new one. And `ActionPreview`'s *Where it appears* frames drew the button in every declared location unconditionally; its own `PlacementPreview` note rules against exactly that shape, naming the ADR-0078 "declares, 'renders', reports success, and does nothing" harm as the reason the retired `global_nav` frame was removed. A capability-gated action was the surviving instance of it. ## What changed - **Inspector, Placement section.** Names the gating capabilities and says the action is *hidden*, not disabled or errored. When the signed-in session is itself missing one of them it says so in the first person — which is what answers the reported complaint, "I configured the buttons and I see none of them." The held set comes from `MePermissionsProvider` through `usePermissions`, the same signal `useCanAuthorMetadata` consumes; this is not a second client-side permission derivation. An unreported held set is *unknown*, and that clause stays silent rather than guessing — mirroring the gate's own fail-open doctrine. - **Action preview.** The capability line in the metadata strip and above the *Where it appears* frames. Declaration-side only: it renders a draft, not a session (pinned by case H). - **`content/docs/guide/console.md`.** States the hide and where the reason is shown. ## Ruling part (a) is pinned, not promised No end-user surface is added, and option C (drawing the action greyed out with the missing capability named) is not implemented. Case **J**, added to #8123's existing nine-case pin, asserts the gated end-user list surface still explains nothing: no capability name, no notice standing in for the button, paired with a positive that the list itself rendered. An implementer who lands this reason on a running app's list surface turns it red. ## Where ruling part (c) landed, and where it did not `action.requiredPermissions`'s authoritative prose lives in `@objectstack/spec` — a different repository and the `domain:spec` seat's lane, fenced out of this one. It was **read, not edited**, and it owes nothing: - **"State the hide" is already there.** The `requiredPermissions` member of the spec's action schema describes itself as "Enforced with 403 on the platform action route (script/flow/modal + MCP) and **mirrored as a UI hide**". - **"Where the reason is shown" cannot go there.** The channel is an objectui surface. The spec is renderer-agnostic and objectui is one consumer of it; a spec description naming this repo's action designer would couple the protocol to one renderer. ⇒ part (c) is an objectui obligation, and `content/docs/guide/console.md` discharges it. ⛔ No upstream card is owed. ⛔ Neither `packages/types/src/objectql.ts` nor its Zod twin was touched — the sibling card #7804 holds both. ## Clause-② — the declaration was conservative, and the route came in under it `needs:contract-review` is hung on this PR as required. Evidence for a re-grade at review, ⛔ not a request to strip it: this route adds **no new exported symbol and no new diagnostic code**. `git diff` adds no `export` to either changed source file; the only new import is `usePermissions`, already a published export of `@object-ui/permissions` and already a declared dependency of `@object-ui/app-shell`. The change is copy inside two panels that already exist, plus tests and docs. ## Gates — each exit code captured to a file before reading | gate | exit | |:--|:--| | `pnpm exec vitest run packages/app-shell/` (707 files, 6948 passed, 1 skipped, 0 failed) | 0 | | `packages/app-shell` `type-check` (`tsc --noEmit` and `tsc -p tsconfig.test.json`) | 0 | | `eslint .` over the whole `packages/app-shell` package: 0 errors, pre-existing warnings only | 0 | | `check:changeset-claims` · `check-changeset-presence` · `check-changeset-no-major` | 0 | | `check:control-bytes` · `check:phantom-deps` · `check:test-path-roots` | 0 | | `check:i18n-keys` · `check:i18n-drift` · `check:i18n-designer-parity` · `check:designer-field-key-parity` | 0 | | `check:vi-mock-inherit` · `check:vi-mock-override-shape` · `check:vi-mock-specifiers` | 0 | | `check:new-line-citations` · `check:doc-fences` | 0 | | `check-governed-queue-guard --test` over all six changed paths | 0 — NOT GOVERNED | The lint reading is a **declared narrowing**: the repo-wide `pnpm lint` is `turbo run lint` across every package and belongs to CI. Run here instead: `packages/app-shell`'s own `eslint .`, whose population is the file list eslint enumerated from its own config rather than a guess of mine, with the count read from `--format json`. The narrowing is sound because type-aware linting is not enabled anywhere in the flat config — no `projectService`, no `parserOptions.project`, no `project:` — so this diff cannot move a verdict on a file it does not touch. ## Reverse verification — direction predicted before each run, three legs Every leg mutated from the committed state, proved the mutation reached disk by blob hash before running anything, restored with `git checkout HEAD -- PATH`, and verified `git diff HEAD` empty afterwards. No build or `dist` step is involved: both mutations and both pins live inside `packages/app-shell` and the tests import them by relative path, so nothing resolves through a package's `exports`. | leg | predicted | measured | |:--|:--|:--| | inspector notice deleted | A, C, D, E red; B (control) and the three preview cases green | 4 failed (A, C, D, E) / 4 passed | | both preview notices deleted | F and H red only | 2 failed (F, H) / 6 passed | | an end-user permission notice injected into `ObjectView`'s list toolbar | J red only | 1 failed (J) / 9 passed | The second leg is the one worth reading twice: before this branch hardened case H it compared two reads of the notice, and with the notice deleted both are `undefined`, so it passed for a deleted renderer. Case J had the same shape and now asserts a positive over the same render. Both hardenings are in their own commit. The third leg is the pin that matters to the ruling: it is the only leg that fires on the failure this card must not produce, and the only one whose mutation is an addition rather than a deletion. ## Out of scope, reported rather than fixed - **`DeclaredActionsBar` applies no capability gate.** It renders `objectDef.actions[]` for a record at a location, filtering on `locations` and the `visible` CEL only — no `useCapabilityGate`, unlike `action:bar`, `page:header`, the grid row menu and the selection bar. The same divergence on `BulkActionBar` was treated as a defect when it was found. Not touched here: out of this card's surface, and it needs its own measurement of whether that bar is reachable with gated actions. - **The client gate may be stricter than the server for a platform admin** (`useCapabilityGate` reads only `user.systemPermissions` and ignores the `isPlatformAdmin` that `useConsoleActionRuntime` passes alongside it). Explicitly ⛔ not this card; unmeasurable from this repository. Session: `session_01KSd9P5u2Mf4p8g4n4SD4Fx`. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01KSd9P5u2Mf4p8g4n4SD4Fx --- _Generated by [Claude Code](https://claude.ai/code/session_01KSd9P5u2Mf4p8g4n4SD4Fx)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merge conflicts in
pnpm-lock.yamlare a recurring friction point in monorepo workflows. This PR adds automation to detect and resolve lockfile-only conflicts automatically.Implementation
New workflow (
.github/workflows/pnpm-lock-autofix.yml):pnpm-lock.yamlconflicts: regenerates viapnpm install --no-frozen-lockfile, commits, and pushesDocumentation:
.github/WORKFLOWS.mdCONTRIBUTING.mdBehavior
Security: Uses
github.event.pull_request.head.repo.full_name == github.repositoryguard to prevent execution on fork PRs.Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.