Blogs Engineering

Making Read-Only Mean Read-Only in BrightBean Studio's Composer

A published post's composer still offered Publish. The PR hid it, and the maintainer extended it with server-side guards and 19 regression tests.

Pythonbrightbeanxyz/brightbean-studioDjangoUI stateauthorization

A UI bug that turned out to be a server-side data integrity bug, finished by the maintainer.

Short answer

After a post was published, BrightBean Studio's composer showed a "read-only" banner but still offered an enabled Publish button. The original PR hid Publish for read-only posts. A maintainer then picked up the PR, which had nearly been closed as stale, and widened the fix. They gated the whole action bar, added server-side guards against rewriting published posts, and added 19 regression tests. It was merged as PR #157 and closed issue #116.

The problem

Issue #116 showed the banner "This post is Publishing and read-only. Use Clone to repost an editable copy." with the Publish button still visible and enabled.

What the PR proposed

The first commit changed two files (+12 / -6). It added a read-only check in apps/composer/views.py and hid the Publish split-button in the composer template.

What the maintainer found and added

In September a project member posted that the PR was being closed as stale. Two days later a maintainer picked it back up instead, explaining that "the checks had simply never run, because a fork PR from a first-time contributor sits at action_required until a maintainer approves the workflow." On top of the original commit they:

  1. Restored whitespace the original patch had collapsed in the template.
  2. Gated Save Draft and Submit for Approval too, since only Publish had been hidden.
  3. Added a server-side guard. Before it, action=publish_now on a published post re-stamped post.scheduled_at, and the 30-second autosave rewrote a published post's title, caption and tags. In their words: "So 'read-only' was false even with nobody at the keyboard."
  4. Added "the regression tests the description claimed", noting that no test file had been included. "There are 19 now."

They also documented two deliberate choices. Delete and Clone stay visible on read-only posts, because the composer is the only place a published post can be deleted. And the server guard works per channel, so the failed channel of a partially published post can still be retried.

By the numbers

  • Repository: brightbeanxyz/brightbean-studio, 2,612 stars (Nov 3, 2026), Python, AGPL-3.0
  • Files changed: 6
  • Lines: +547 / -14 (the original commit was +12 / -6)
  • Commits: 7 (1 from the PR author, 6 from a maintainer, including 2 merges of main)
  • Opened: Aug 21, 2026. Merged: Sep 17, 2026. Time to merge: 27 days, 2 hours
  • Review: extended and merged by a maintainer

Takeaways

  • The reported symptom was a button. The real bug was that the server accepted writes to published posts.
  • A PR that claims tests it doesn't contain costs reviewer trust. Here the maintainer wrote them.

FAQ

Can published posts still be deleted or cloned?

Yes. Both stay available by design, as documented in the PR.

Where can I read more?

See the pull request and the original issue.

The goal

A good first patch fixes the symptom. A good review asks what the symptom was protecting. This merge is mostly the maintainer's answer to that question.

Run the loop

Turn production signals into reviewed fixes.

Start a free trial and see how Prilog maps real incidents to code-level pull requests.