Skip to content

Software Development Lifecycle

Sprint cycles and release cycles operate independently

Section titled “Sprint cycles and release cycles operate independently”

Work is planned and executed in sprints that are staggered with releases (i.e. sprints don’t end with releases). By decoupling releases from sprint boundaries, we give ourselves space to build out test coverage without the pressure of “but we need to ship Thursday,” develop confidence in our QA process, and learn our actual cycle times without the noise of artificial deadlines.

Our current model is building the runway for CI/CD:

  1. Stabilize releases (where we are now): Establish a predictable release rhythm that doesn’t create panic. Use the breathing room to build comprehensive automated test coverage, make deployments low-risk and reversible, and develop QA processes that can keep pace with development.
  2. Shrink the gap: As test coverage grows and deployment confidence increases, the time needed between “code complete” and “released” naturally compresses. Releases start happening more frequently, not because we’re pushing harder, but because the safety nets are in place.
  3. Releases become non-events: Eventually, shipping is just something that happens—multiple times a day if needed—because automated tests catch regressions, rollbacks are trivial, and feature flags let us decouple deployment from exposure.

The question we should ask periodically: “What would need to be true for us to release more frequently without the panic?” The answer becomes our infrastructure and process roadmap.

  • Calendar-bound iterations of fixed duration
  • Goal of a sprint cadence is to complete a defined chunk of work sized to fit within the sprint (i.e. the work is the variable)
  • Each sprint concludes with a retrospective and sprint planning meeting
  • Sprint boundaries are fixed regardless of work completion status
  • Development targets releases one cycle ahead, allowing for better quality assurance and release preparation
  • For the timing of the recurring sprint cycle, see the _Production Google calendar.
  • Goal of the release cadence is to ensure sufficient time for QA
  • Milestone-based releases triggered by feature/goal completion
  • Regular cadence but tied to milestone achievement rather than sprint end dates
  • Releases may occur mid-sprint or span multiple sprints depending on milestone completion
Branch Environment Purpose
main momentum-main.fly.dev Source of truth for all code
staging momentum-staging.fly.dev Pre-release QA
prod production Live application

All PRs merge to main. The staging and prod branches are deployment targets that are fast-forwarded to main (or to a release tag). They never receive independent commits directly. This means all three branches share the same commit history, eliminating divergence and making it always clear exactly what code is in each environment.

Every release is tagged on main (e.g., v2.13.0). Because branches are fast-forwarded, the tag points to the same commit on all three branches. Tags serve as:

  • The marker for what is currently in production
  • The base for hotfix branches
  • The boundary for “what’s queued for next release” (git log v2.13.0..main)

As a developer begins work on a ticket, they create a new git branch. They commit changes to their branch until the requirements in the ticket are met. Once complete, the developer creates a pull request against main.

Tasks are managed as issues in Github.

Type Created by Owned by Closes ticket Tagged to Milestone Can belong to Has PRs
Feature Product Product Product No No
User Story Product, QA QA QA Yes Feature No
Task Developers, QA Developers Developers Yes Feature, User Story, or another Task Yes
Bug (P0-P3) QA, Product, Developers QA QA Yes Yes

Feature: A body of work, often spanning sprints. Features are containers for planning, not work items. Product closes them when the feature is complete, which may span multiple releases.

User Story: User-focused functionality that belongs to a Feature, or standalone for smaller user-facing changes. QA owns verification and closes these tickets.

Task: Technical work owned by developers. Tasks may be standalone or belong to a Feature, User Story, or another Task. A Task under another Task is a sub-task by relationship, not by type.

Bug (P0-P3): Unexpected problem or behavior. Priority is indicated by the type: P0 (Critical/Urgent), P1 (High), P2 (Medium), P3 (Low). QA verifies fixes and closes these tickets.

Every PR must be associated with a Task or Bug. This is a SOC2 requirement.

Must Ship: Indicates the ticket must be included in the ticket’s Milestone.

Tickets progress through the following states:

Triage

  • Bike Rack / No status: Issue identified but not reviewed or scheduled.
  • New: Newly filed ticket. Should be triaged.

Planning

  • Sprint Backlog: Ticket can optionally be worked on during the current sprint. Not yet in progress.

Development

  • In Progress: Someone is assigned and actively working on the task.
  • Waiting for Code Review: A PR against main is ready for review.

Testing

  • Ready to Test: Code has been merged to main, deployed to momentum-main.fly.dev, and tested by the ticket owner. Ready for QA handoff.
  • In QA/Test: QA is actively testing on momentum-staging.fly.dev

Completion

  • QA Verified: QA has verified that all specifications have been met. Any additional issues or edge cases are documented or added to the backlog.
  • Done: Task has been completed.
  • Done - PR Awaiting Post-Merge Review: Code was pushed without human review and the developer has requested post-merge review.

The QA team ensures that User Stories meet their requirements and that Bug fixes resolve the reported issues. If a ticket does not meet the quality threshold, QA keeps it in the testing state and writes sub-tickets for specific faults to be fixed.

Tasks with no intended behavioral change are covered by regression tests and automated testing rather than explicit QA review, and are moved directly to Done after merging.

Pull requests require different levels of review based on risk assessment. Developers evaluate risk considering technical changes, business context, potential impact, and AI-reviewer based complexity and risk assessments. Review requirements range from AI-only for low-risk changes to mandatory human review for high-risk modifications affecting authentication, payments, or core data models.

Medium-risk changes may use either human review or AI review if the developer believes this is justifiable. Special markers like [FF] for feature flags or [PARALLEL] for backward-compatible changes can reduce risk levels.

For detailed guidelines and examples, see the Risk-Based PR Review Policy.

Once review requirements are met and objections resolved, the developer merges their work into main and moves the ticket to “Ready to Test”.

When the criteria for a release have been met, the release conductor runs the Promote to Staging workflow, which:

  1. Tags the release on main (e.g., v2.13.0)
  2. Creates a draft GitHub release with auto-generated notes
  3. Fast-forwards staging to the release tag, triggering a deploy to staging
  4. QA performs end-to-end testing on the staging environment

Once QA has verified the release on staging, the release conductor runs the Promote to Production workflow, which:

  1. Fast-forwards prod to the same release tag, triggering a deploy to production
  2. Verifies the production site responds successfully
  3. Publishes the draft GitHub release

Because all three branches share the same commits, there is no back-merge step. The release tag permanently marks exactly what was deployed.

Bugs discovered in staging during pre-release testing are fixed on main and staging is re-promoted. This keeps main as the single source of truth.

  1. QA writes sub-tickets (Tasks) under the original User Story or Bug ticket for specific faults to be fixed.
  2. Developer branches from main and opens a PR targeting main
  3. Once merged, bump the patch version (e.g., v2.14.0v2.14.1) and re-run the Promote to Staging workflow
  4. This re-tags and fast-forwards staging with the fix included
  5. QA re-tests on staging — repeat as needed for additional fixes

Hotfixes follow the same principle: fix on main first, then package and promote through the normal workflow. Never commit directly to staging or prod.

  1. QA or Product writes a Bug ticket (P0)
  2. Developer fixes the bug on main (normal PR process)
  3. Create a new patch version (e.g., v2.14.1 if the release was v2.14.0)
  4. Run Promote to Staging with the patch version — this tags and fast-forwards staging
  5. QA does a targeted test on staging (can be abbreviated for critical fixes)
  6. Run Promote to Production with the patch version
  7. Post in #tech_change-control that a hotfix was deployed

Non-critical (P1-P3) bugs found in production

Section titled “Non-critical (P1-P3) bugs found in production”
  1. QA or Product writes a Bug ticket (P1-P3)
  2. P1 bugs get the Must Ship label and are placed in the next Milestone
  3. P2-P3 bugs are created in the New state for triage by Product
  4. These are fixed on main as normal development work and deployed in the next release

Github actions are set up to support the release cadence.

Merging a pull request to main triggers an automatic deploy to momentum-main.fly.dev. This is expected to be triggered multiple times a day.

Fast-forwarding staging to a release tag triggers an automatic deploy to momentum-staging.fly.dev for pre-release QA.

Fast-forwarding prod to a release tag triggers an automatic deploy to production. Calculation service deployments are done via a manual trigger of a github action. Production releases are expected once per sprint.

Automatic deploys trigger any database migrations that are necessary to bring the environment’s associated database to the current revision.

Tests are automatically run when pull requests are opened. Pull requests cannot be merged if there are failing tests.

Likewise, static code analyzers are run on the codebase when pull requests are opened. Failing static code analysis will block a pull request from being merged.

After each deployment, automated monitoring tools are used to track system performance, error rates, and user behavior. This helps quickly identify any issues that may have been introduced by the new changes.

Any exceptions triggered in production results in an alert to the development team for immediate investigation.

The QA team is responsible for maintaining the quality of the product. A range of tooling and processes are involved.

At the end of the release cycle, a regression test is performed to check that no features have been inadvertently degraded. These regression tests are formally tracked in test management software.

Automated tests are created by developers, and (as above) are run automatically when pull requests are submitted.

Security testing is regularly performed using an analysis tool named Zed Attack Proxy, which tests server, application and network configuration for weaknesses. The QA team also tests for OWASP related vulnerabilities such a SQL injection. On a regular cadence, a dedicated penetration tester is contracted to conduct a formal test and report.

Load testing is regularly performed to uncover weaknesses in the scaling architecture of the application.

User acceptance testing is continually performed, whereby the QA team and business users of the product will provide feedback if the implementation of features is confusing or cumbersome.

The team uses AI pair programming tools such as Claude Code and leverages automated code review tools such as CodeRabbit and ZeroPath. AI reviewers provide checks for code quality, security vulnerabilities, and best practices.

AI Context Management: The Momentum-Docs MCP (Model Context Protocol) provides Claude Code with accurate, up-to-date documentation about our codebase. Developers should document stable patterns and domain knowledge in momentum-docs to improve AI assistance accuracy and reduce repetitive searches.

AI Review Comment Policy: All comments from AI reviewers must be addressed by either implementing the suggestion or providing justification for not implementing. This ensures valuable automated insights are not overlooked while maintaining developer discretion. While all comments must be resolved (e.g. via the “Resolve Conversation” button), trivial or repetitive comments may be addressed collectively without individual responses.

The risk-based review policy ensures appropriate human oversight based on the criticality of changes. For detailed AI development practices, see the AI Code Generation Practices.

When AI agents are assigned to complete coding tasks independently (i.e., not pair programming with a developer), the following controls apply:

Task Assignment: AI agents may be assigned well-scoped, straightforward tasks where requirements are clear and the solution approach is understood. Complex tasks requiring architectural decisions, ambiguous requirements, or significant judgment should be assigned to human developers.

Agent Identity: The AI agent must create the pull request under its own identity (e.g., a bot account), not the human user who assigned the task. This ensures the audit trail accurately reflects code authorship.

Mandatory Human Review: All pull requests authored by AI agents MUST receive human review before merging. The human reviewer may use AI-assisted tools to support their review, but a human must approve the change.

Rationale: These controls ensure human accountability for all code changes and maintain an accurate audit trail of authorship. AI-generated code may contain subtle errors, security vulnerabilities, or misunderstandings of business requirements that require human judgment to catch.

The step-by-step procedures for releases, hotfixes, rollbacks, and CI/CD configuration live in the momentum wiki and the momentum GitHub Actions workflows:

  • This policy will be reviewed annually and updated as necessary to reflect changes in our systems, processes, or regulatory requirements.

Internal & Confidential: This page is only available in the internal handbook and contains confidential information.