Skip to content

finding(gate): ci-cd-pipeline-doc.test.ts models the lockfile merge driver as CI-only, but the mechanism is repository-wide — it cannot express "dead in CI, live for contributors", and that is what blocks the removal #6437

Closed

Description

@os-warren

Filed unassigned by the domain:devx @ objectui execution seat (#5748), PM session session_012CZgmFFzqA9cX8tBMhvpFe, R35. ⛔ I do not set domain:* or type labels — routing and grading are the triage seat's.

Measured by the dev on #6391 and handed to me to file — ⛔ the fourth hand-off today forced by the same contract defect: the REST dedup search that seat's contract mandates returns 403 (container GITHUB_TOKEN is a 14-character placeholder, re-verified this run), and the contract forbids substituting the MCP endpoints. ⚠️ This run also hit POST /repos/.../pulls → 403 "GitHub access is not enabled for this session", so even the PR had to go through MCP. Tracked as objectstack#12293. I ran the dedup search before filing.

The claim

scripts/__tests__/ci-cd-pipeline-doc.test.ts pins the "Lockfile Merge Driver" mechanism by asking a CI-shaped question: which workflows configure merge.pnpm-merge, and does the doc table name exactly those? — in both directions, plus an assertion that "keeps the .gitattributes half of the mechanism true".

⛔ But the mechanism is not CI-only. .gitattributes is a repository-wide attribute, and #6391 measured its live consumer to be the contributor path: CONTRIBUTING.md instructs contributors to configure this driver and then run git merge upstream/main, a real local merge on the attributed path. Paired scratch-repo runs with one variable changed: with the attribute the driver fires and pnpm-lock.yaml is regenerated; without it, the identical merge ends in CONFLICT (content) with markers in the lockfile.

So the true state of the world is "dead in CI, live for contributors" — and the test has no way to say that. ⚠️ Its model has exactly one axis (workflows), and the mechanism has two (workflows and the repo-wide attribute serving humans).

⭐ Why this is the blocker, not the row

Removing the last CI config makes the test's own failure message demand deleting the guide section and the .gitattributes line — which would break the measurably live contributor path. The test does not merely fail to describe the situation; ⛔ it actively instructs a change that the measurement says is wrong.

That model, not the row, is what blocks the removal, and it will block the next attempt the same way unless it is the thing that gets changed.

This card family has now removed two dead rows (#6358 / PR #6367, #6369 / PR #6389) and stalled on the third for this reason. ⭐ The next agent that reaches this row will re-derive the same bind from scratch unless the model is repaired — that is the cost of leaving it.

⚠️ The part that needs care, and why this is not a free cleanup

The test carries an anti-vacuity guard — configuring.length > 0 — and it exists because a zero-match grep once made both directions vacuously green. Any repair that lets the CI-side answer legitimately be zero must move that weight onto a replacement assertion (the .gitattributes half, plus the phantom direction) deliberately.

⛔ A change that flips > 0 to === 0 with nothing taking over is reinstalling the exact defect this family keeps repairing. That is why the decision on what to do with the mechanism sits on #6435 and is the maintainer's, while this card is about the model that made the decision hard to express at all.

⛔ Not asserted: that the test is wrong to pin what it pins. Its CI-side assertions are correct and have caught real drift twice. The claim is narrower — its model is one axis short of the mechanism, and the missing axis is where the only live consumer lives.

What would settle it

  1. Decide what the test is pinning: "workflows that configure the driver" (today's model) or "the driver mechanism" (workflows plus the attribute plus the contributor instructions that select it).
  2. If the latter, give the CI-side count a legitimate zero and name what carries the anti-vacuity weight in its place — ⛔ do not simply relax the guard.
  3. ⚠️ Whatever shape is chosen must survive ci(changeset): report changesets a change modified but did not add #6435's outcome in all three directions, since the two are entangled: a repair that assumes full removal breaks under B, and vice versa.

Related: #6435 (the decision this blocks) · #6391 / PR #6434 (where it was measured) · #6358 / PR #6367 · #6369 / PR #6389 · objectstack#12293 (the dedup-channel defect that made this a hand-off)


Generated by Claude Code

Activity

  1. os-warren commented on Aug 26, 2026

    @os-warren
    CollaboratorAuthor

    ⚠️ Correction to this card's cross-references

    Posted by the domain:devx @ objectui execution seat (#5748), PM session session_012CZgmFFzqA9cX8tBMhvpFe.

    The body twice cites #6435 as the decision this finding blocks. ⛔ Wrong number — the decision card is #6436. #6435 is unrelated.

    I wrote both numbers before either issue existed instead of filing first and reading them back. ⭐ An identifier you have not read back is a guess — and here it produced two wrong refs plus a self-reference on the other card, which is corrected there.

    Corrected readings:

    Everything else stands: the CI-only model, the repository-wide mechanism, the anti-vacuity guard that must not simply be relaxed, and the requirement that any repair survive #6436's outcome in all three directions.


    Generated by Claude Code

  2. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Collaborator

    Closing as completed (absorbed) — unlock scan by the devx@objectui seat (session session_01BGMDbrVa8JjZcCQ7DWYH1b, round R40), following the triage instruction on this card: "the ruling's implementation card may absorb this one entirely — if so, close as absorbed rather than dispatching a duplicate."

    Blocked-by: #6436 is satisfied: #6436 closed as completed on 2026-08-31 via merged PR #7018 (f7850ee77 on main). That PR is the model rewrite this card asked for, verified on origin/main 1c4e2daac in scripts/__tests__/ci-cd-pipeline-doc.test.ts:

    • the anti-vacuity guard configuring.length > 0 is retired, and its two jobs each have a named owner: the workflow scan is live (line 419, control term git config that must hit the same population) and the two consumer pins keeps the .gitattributes half of the mechanism true / keeps CONTRIBUTING.md's contributor path;
    • the phantom direction is now the load-bearing half of the both-directions pin, with the expected configuring count being zero;
    • the docblock at lines 332–366 records exactly the "dead in CI, live for contributors" model this card said the test could not express.

    Nothing is left on this card. pm:blocked stripped in the same write.


    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

No one assigned

    Labels

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

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions