~/abhipraya
[S4, W1] PPL: Twelve MRs, One Branch-Naming Standard, Zero Force-Pushes
Output Summary
Sprint 4 Week 1 (May 7 to 13) numbers:
| Metric | Count |
|---|---|
| MRs authored & merged | 12 |
| MRs reviewed (substantive) | 2 |
| Direct main commits | 10 |
| Domains covered | 4 (mr-bot service, infra/CI, security/deps, RBAC) |
| Branches with SIRA ticket prefix | 12 of 12 |
| Force-pushes to main | 0 |
| Merges with conflicts at squash time | 0 |
The week was dominated by sira-mr-bot (eight MRs) but also covered a security response (SIRA-365, pin all deps after the TanStack Snyk incident), a quality-gate addition (SIRA-353, React Doctor), an RBAC expansion (SIRA-364), and ten direct-main commits for infra/dev tooling.
The Twelve MRs
!275 SIRA-354 feat(mr-bot): replace CI-status card with MR-content card
!276 SIRA-355 fix(mr-bot): edge-case hardening
!286 SIRA-356 fix(mr-bot,infra): deploy without sudo and route via sira-api nginx
!288 SIRA-356 fix(ci): make mr-bot:deploy self-sufficient and inject env vars
!292 SIRA-361 feat(mr-bot): put author ping inside the embed Author field
!293 SIRA-362 feat(mr-bot): drop merge follow-up ping + recover from deleted cards
!294 fix(mr-bot): restore floating @ping above the embed
!295 SIRA-353 feat(web): add React Doctor scan in CI quality stage
!296 feat(mr-bot): enforce plain-paragraph summary format
!299 SIRA-365 chore(deps): pin all deps + add 24h install cooldown
!300 SIRA-364 feat(api): RBAC expansion & hardening (BE + docs)
!303 SIRA-366 chore(web): improve React Doctor score
Every branch follows <user>/<type>/<SIRA-XX>-<topic> or, for non-ticket cleanup work, <user>/<topic>. Every merge was squash-merge. The complete list is verifiable at the filtered GitLab view.

Direct Main Commits: Scoped to Infra and Tooling
The project AGENTS.md gives the product owner permission to push directly to main, but only for “non-feature, non-prod-codebase changes.” Ten such commits this week:
5a2bd625 docs: refresh AGENTS.md across root, apps/api, apps/web
cca07ae1 refactor(infra): rename superset-* to wt-* across SIRA
e2b63141 chore(infra): remove conductor + superset GUI configs (wt is canonical)
a4f0c61e fix(ci): pin supabase CLI version to prevent postgres image tag drift
99aab08b feat(scripts): name superset containers after worktree
8d865ef6 feat(scripts): align superset port allocation with wt slot offsets
e6a67589 chore: lower pre-push process priority
458e1324 chore: cap pre-push test workers
66e6d4d5 chore(tooling): drop supabase/sonarqube MCP and allow main pushes
1da5d418 chore(wt): add .wt/config.toml for universal worktree CLI
None touch product code. All are documentation, dev-tooling, infra config, or CI fixes. The CI fix in a4f0c61e (pin supabase CLI to mitigate a postgres image tag drift bug) is the most consequential; it unblocked every subsequent integration-test job. Putting it through an MR would have delayed the fix by a CI cycle for zero review value, so direct-to-main was the right call.
The rule I follow: if a teammate could plausibly object to the change AND it touches code that runs in production, it goes through an MR even if I’m the PO. If it only touches dev-tooling or fixes a CI bug that’s actively blocking the team, direct main is faster and equally safe (the next CI run is the verification).
The Discord Ping Placement Saga: Four Iterations, Discipline Held
The mr-bot’s Discord card has an @author ping. Where does the ping go? This single design question went through four iterations across MRs !275, !292, !293, !294, and !296. The pre-squash commits tell the story:
- !275 original: ping in the message content field, floating above the embed. (Standard Discord pattern; the @ rendering and notification both work.)
- !292 SIRA-361: move ping inside the embed Author field. Rationale: tidier visual layout.
- !293 SIRA-362: realized embedded pings don’t notify the user. The notification is what the team actually needs; visual tidiness is secondary. Revert:
75b187ca revert(mr-bot): put author ping back in content above embed. - !294: floating ping wasn’t quite right either; rendering placement broke when the message was edited. Restore the floating ping with an explicit @-string format that survives edits.
- !296: separately, enforce the Gemini summary as a single plain paragraph; the bot was occasionally returning Markdown lists that broke the embed.
Four iterations on what looks like a small detail. The discipline part: every iteration went through a proper MR with a clear title (feat, fix, or revert), CI passed before merge, and the revert was a real revert commit (not a force-push that erased history). The two reverts (75b187ca, 37ebf290) are still in the pre-squash history if anyone wants to audit how we got to the current ping placement.
The lesson is not “I made a wrong decision and walked it back.” Reverting four times because the constraints became clearer one bug at a time is normal product work. The lesson is every walk-back went through the same merge pipeline as the original; nothing was hidden by a force-push, nothing skipped CI, nothing got merged with [WIP] in the title.
Branch Hygiene
All 12 branches were named with the SIRA ticket prefix where applicable:
abhip/feat/SIRA-364-rbac-expansion-hardeningabhip/feat/SIRA-365-pin-deps-cooldownabhip/react-doctor(no ticket, exploratory work that later got SIRA-353)abhip/mr-notif-cleanup(the mr-bot rebuild, with SIRA-354 in commit messages)
None of the branches outlived their MR. should_remove_source_branch=true was set on every merge, so the branches were auto-deleted on squash. No stale abhip/* branches in the remote at end of week.
CI Discipline
Every one of the 12 MRs went through the full CI pipeline (ci → quality → migrate → build). The quality stage includes SonarQube (with the 85% new-code coverage threshold), security:sast, react-doctor, schema-test, and BDD. Of those:
- Zero MRs merged with red SonarQube (the 85% gate blocked one early attempt; I fixed the coverage gap and re-pushed).
- The mr-bot MRs all passed the
mutation:pythonjob (the mr-bot service has its own pytest config and was wired into the mutation suite from day one). - Two MRs (!288, !286) had to retry their
deployjob because of a containerd ingest race on Nashta. Both retried clean on the second attempt.
No MR was merged with merge_when_pipeline_succeeds=true while the pipeline was actively red. Everything that merged had a green pipeline at the time of the squash.
What I Learned
Two patterns from the week worth keeping:
Direct main is a privilege scoped to infrastructure, not a workflow shortcut. Ten direct commits felt like a lot until I went back and checked what each touched. None of them are product behavior; all are dev tooling or CI fixes. The discipline isn’t “never push to main”; it’s “every push to main has to pass the test ‘would a teammate object?’ applied honestly.”
Walk-backs are normal, but they have to be transparent. The Discord ping went through four iterations because the constraints (Discord’s notification semantics, embed render behavior, edit-survivability) only became clear as users hit them. The work isn’t about getting it right the first time; it’s about every iteration being visible in the git history. Two real revert(mr-bot): commits are better than one rewritten history that pretends I knew the answer all along.
Evidence
- 12 authored MRs: !275, !276, !286, !288, !292, !293, !294, !295, !296, !299, !300, !303
- Direct main commits:
5a2bd625,cca07ae1,e2b63141,a4f0c61e,99aab08b,8d865ef6,e6a67589,458e1324,66e6d4d5,1da5d418 - Revert commits visible in pre-squash history:
75b187ca(ping back to content above embed),37ebf290(ping back to content above embed, second occurrence in !293) - Filtered MR list: GitLab merge requests deployed 2026-05-07 to 2026-05-14