Skip to content

Add automated pnpm-lock.yaml conflict resolution workflow - #81

Closed
huangyiirene with Copilot wants to merge 4 commits into
mainfrom
copilot/add-automation-for-pnpm-lock
Closed

huangyiirene with Copilot wants to merge 4 commits into
mainfrom
copilot/add-automation-for-pnpm-lock

Conversation

Copilot AI commented Jan 15, 2026 •

Copy link
Copy Markdown
Contributor

Merge conflicts in pnpm-lock.yaml are 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):

    • Triggers on PR events when lockfile or package.json changes
    • Detects merge conflicts via attempted base branch merge
    • If only pnpm-lock.yaml conflicts: regenerates via pnpm install --no-frozen-lockfile, commits, and pushes
    • If multiple files conflict: notifies with manual resolution steps
    • Fork-safe: only runs on same-repo PRs
  • Documentation:

    • Added workflow explanation with flow diagram to .github/WORKFLOWS.md
    • Added troubleshooting section to CONTRIBUTING.md

Behavior

PR with lockfile conflict → Detect conflict → Only pnpm-lock.yaml?
                                                    ↓ yes          ↓ no
                                            Auto-regenerate    Notify user
                                                    ↓
                                            Commit & push
                                                    ↓
                                            Comment on PR

Security: Uses github.event.pull_request.head.repo.full_name == github.repository guard to prevent execution on fork PRs.

Original prompt

创建自动化流程,防止合并分支时报错 pnpm lock 冲突


💡 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.

Copilot AI and others added 3 commits January 15, 2026 11:20
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
Copilot AI requested a review from huangyiirene January 15, 2026 11:28
@github-actions github-actions Bot added documentation Improvements or additions to documentation configuration ci/cd labels Jan 15, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ All checks passed!

  • ✅ Type check passed
  • ✅ Tests passed
  • ✅ Lint check completed

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd configuration documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants