Skip to content

A hand-picked changeset filename can silently overwrite another PR's changeset — 371 accumulated files, and git status shows M, not ?? #6336

Description

@os-support-ai

Filed unassigned by the domain:ui @ objectui execution seat, PM session session_011SfZeFWrhGLHmfq61xbz4q (os-support-ai). ⛔ Not claiming. Recording a near-miss that actually happened today so it does not live only in one PR thread.

What happened

A dev run on #6165 wrote its changeset to a hand-picked changesets-style name, olive-donkeys-smile.md. That file already existed on main, carrying an unrelated declaration:

---
"@object-ui/plugin-charts": minor
---

The heredoc overwrote it. Caught and fully reverted before any commit; I verified independently that the file on that branch is byte-identical to main and the plugin-charts: minor declaration is intact. ⇒ No damage occurred. This card is about the hazard, not the incident.

Why it is a hazard rather than one agent's slip

The failure is silent, and the two signals that should catch it both fail:

  1. git status shows M (modified), not ?? (untracked). An agent scanning for "did my new file appear" sees a modification and reads it as its own write landing. Nothing says "you replaced someone else's file."
  2. The loss is a deleted release declaration. A minor bump silently vanishing is not something any gate downstream flags — the packages simply do not get bumped at release time. There is no red anywhere.

⚠️ And the base rate is not small: the repo currently holds 371 accumulated changeset files. The changesets name space is adjective-animal-verb, so hand-picking one has a real collision probability, and it rises with every unreleased changeset.

What actually caught it was neither a gate nor a test: check-changeset-presence reported "0 changeset(s) added", and the dev read the gate's own detection logic instead of assuming the gate was wrong. That is a thin thread to hang this on.

Why "just tell agents not to do it" is not sufficient on its own

It is the right habit — the repo's own <issue>-<slug> convention makes collisions impossible in practice, and that is what the PR ended up using. But:

  • a convention is not enforced, and an agent under time pressure reaching for a plausible-looking random name is exactly the observed failure;
  • the person who pays is not the agent that made the mistake — it is whichever earlier PR's release declaration disappears, discovered (if at all) when a package fails to bump.

Possible directions — ⛔ not prescribing, this wants triage

  1. A gate: fail when a PR's diff modifies or deletes a pre-existing .changeset/*.md that it does not otherwise own. A changeset is append-only by nature — a PR touching someone else's is almost always a mistake, and this is mechanically checkable from the diff alone.
  2. Make the convention the documented one in AGENTS.md / the changeset docs (<issue>-<slug>), so "pick a random name" stops being the default mental model. Cheapest, weakest.
  3. Both — (2) reduces the rate, (1) catches the remainder. (1) is the only one that survives an agent that does not read the docs.

⚠️ Whatever is chosen, note the property that makes this worth a gate rather than a guideline: the cost lands on a third party and is invisible at the time it happens.

Provenance

Metadata

Metadata

Assignees

Labels

domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopm:dispatched

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions