Introduction to Software Engineering · Chapter 07

Lab-07: Agile Software Development Model

Your team runs Sprint 1 of ITC Club Hub with Scrum. You set up a GitHub Projects board and refine the Must stories from Lab-05, plan the sprint with planning poker, implement the first stories in C++ test-first with GoogleTest (RegistrationService::registerStudent and clubhub list-events), log the daily scrums and draw the burndown from the board data, and close the sprint with a review in front of the client and a retrospective. The challenge adds one Extreme Programming practice for the whole sprint and measures its effect.

Scrum Guide 2020 GitHub Projects · gh CLI C++20 · CMake 3.28 · GoogleTest 1.15 Sprint 1 · weeks 9 and 10 ≈ 10 hours per student over the sprint 5 tasks + 1 challenge
How to work through this lab. This lab is Sprint 1, so it spans two weeks: Tasks 1 and 2 in the week-9 lab session (backlog refinement and sprint planning), Tasks 3 and 4 during the sprint (implementation, dailies, board updates), Task 5 in the week-10 lab session (sprint review with the client, retrospective). Read the Goal, follow the Steps, compare with the Expected output, and tick the Acceptance checklist (saved in your browser). Open a hint only when stuck for more than 10 minutes. Each task names the role that leads it; everybody contributes, and every member's work must be visible in the Git history.
0

Setup

20 min
  1. Tools. Git, the GitHub CLI gh 2.40 or later (for Projects commands), CMake 3.28 or later, a C++20 compiler (GCC 13, Clang 17 or MSVC 2022 or later) and your editor. GoogleTest is downloaded by CMake FetchContent; nothing to install. Check the toolchain and start the lab branch from an up-to-date main:
    git --version && gh --version && cmake --version
    gh auth login                       # once per machine
    gh auth refresh -s project          # allow gh to manage GitHub Projects
    cd clubhub                          # your team repository
    git switch main && git pull
    git switch -c lab-07
    cmake -S . -B build && cmake --build build && ctest --test-dir build
    If the last line fails because no test target exists yet, continue: Task 3 adds it.
  2. Case-study brief. The box below contains everything you need to know about the product for this lab.
    Case-study brief: ITC Club Hub
    Purpose
    An application for student clubs at the Institute of Technology of Cambodia. The full system is analysed and modelled as a web and mobile application; the team implements its core in C++20: domain model, business rules and a command-line front end, with CSV or JSON file storage.
    Users
    Club leader registers a club and publishes events · Administrator approves clubs and sees a monthly activity report · Student browses events, registers, cancels and receives a reminder · Organiser checks registered students in at the door and sees attendance.
    Business rules
    Capacity cannot be exceeded (a waiting list is a Should feature) · a student cannot register twice for the same event · cancellation closes 24 hours before the start · events in the past cannot be registered for · only approved clubs can publish events.
    Event data
    Title, date and time, location, capacity, description, owning club. Personal data: student ID, name, email, phone (optional), club membership, attendance records.
    Fallback backlog
    Use your own Lab-05 backlog. Only if it is missing, use these ids: Must US-01 register a club · US-02 publish an event (approved club only) · US-04 list upcoming events · US-05 register for an event · US-06 cancel a registration · US-07 check a student in · US-08 see attendance · US-09 monthly activity report · US-10 approve or reject a club. Should US-03 edit an event · US-11 reminder before the event · waiting list. Could US-12 student profile.
    C++ names
    Namespace clubhub; Club, Event, Student, Registration; ClubStatus (Pending, Approved, Rejected); RegistrationStatus (Registered, Cancelled, CheckedIn, Waitlisted); RegistrationService with registerStudent, cancel, checkIn; interfaces EventRepository and RegistrationRepository with CSV-backed implementations. Layout: CMakeLists.txt, src/, include/clubhub/, tests/, data/.
    Rhythm
    Sprint 1 = weeks 9 and 10 (this lab), Sprint 2 = weeks 11 and 12, project submission and demo in week 14. Sprints are two weeks (10 working days); planning in the week-9 lab session, review and retrospective in the week-10 lab session.
    Team roles
    One Product Owner for the whole project, who liaises with the client (the instructor or teaching assistant); a Scrum Master who rotates every sprint; everyone else, and in practice the SM too, are Developers.
  3. Inputs from earlier labs. This lab reuses the artifacts below. If one is incomplete, use the fallback and note it in lab07/README.md (Task 5); do not stop to repair the earlier lab.
    InputFromWhat you need from itFallback if missing
    Team and rolesLab-01 (lab01/README.md, team charter)Member names and GitHub accounts, who is PO, working agreement (meeting times)PO = the member who led the Lab-05 client interview; Sprint 1 SM = another volunteer; dailies at a fixed time agreed in Task 2.
    Process decisionLab-04 (lab04/)Why Scrum, sprint length, events calendarScrum with two-week sprints, events as in the brief.
    Product backlog and issuesLab-05 (lab05/ backlog and the GitHub issues created there)User stories with ids, MoSCoW priority and Given/When/Then acceptance criteriaThe fallback backlog in the brief; write the acceptance criteria in Task 1.
    Class diagram and headersLab-06 (lab06/ class diagram, include/clubhub/*.hpp)Event, Registration, RegistrationStatus, repository interfacesThe fallback headers in Task 3, step 1.
    BuildEarlier labs (CMakeLists.txt)A library target, an executable, a GoogleTest targetThe CMake snippet in Task 3.
  4. Deliverable folder. Create lab07/; every task fills some of these files. Code goes to src/, include/clubhub/, tests/ and data/ as usual.
    clubhub/
    ├── CMakeLists.txt  src/  include/clubhub/  tests/  data/events.csv
    ├── lab01/ … lab06/                  # earlier labs, read-only here
    └── lab07/
        ├── board.md  +  board-start.png  board-end.png   # Task 1 (+ Task 5)
        ├── definition-of-done.md                         # Task 1
        ├── sprint-planning.md                            # Task 2
        ├── tdd-log.md                                    # Task 3
        ├── daily-scrum-log.md                            # Task 4
        ├── burndown-data.csv  +  burndown.md             # Task 4
        ├── sprint-review.md                              # Task 5
        ├── retrospective.md                              # Task 5
        ├── README.md                                     # Task 5 (record what changed)
        └── xp-experiment.md  +  xp-data.csv              # Challenge
  5. Conventions. Story ids come from Lab-05 (US-05); commit messages start with the story id or the lab task (test(US-05): …, Lab-07 task 2: …); every Markdown file starts with a title, a version and a date. Work on feature branches (feature/US-05-register) and merge to main through pull requests reviewed by another member.
1

Board, backlog refinement and definition of done

Easy Lead: Product Owner 60 min · week 9

Goal

Make the product backlog transparent: a GitHub Projects board with the Scrum workflow columns, every Must story from Lab-05 on it with story points and acceptance criteria, ordered by the PO, and a definition of done the whole team has agreed to.

Steps

  1. Create a GitHub Project (Board layout) named Club Hub board, owned by your team organisation or the repository owner, and link it to the repository. Edit the built-in Status field so its options are exactly Backlog, Sprint backlog, In progress, In review, Done (one board column each).
  2. Add the custom fields Story points (Number), Priority (Single select: Must, Should, Could, Won't) with gh project field-create, and Sprint (Iteration, 2 weeks, first iteration starting on Monday of week 9) in the web interface (the CLI cannot create iteration fields).
  3. Import every Must story: each one must be a GitHub issue created from the user-story issue template (starter below); add all of them to the project with gh project item-add, set Priority and put them in Backlog. Should and Could stories may be added too, below the Musts.
  4. Refinement meeting (30 min, whole team, PO leads): check that every item has at least two Given/When/Then scenarios (one success, one rule violation) and is small enough for one sprint; split anything bigger. Size every item relatively against a reference story (for example US-04 = 3) and fill Story points. Planning poker for the top items follows in Task 2.
  5. The PO orders the Backlog column by value, risk and dependencies (for example US-04 before US-05 before US-06, because you cannot register for an event you cannot list).
  6. Write lab07/definition-of-done.md (template in the chapter, slide 12): at least six checkable items covering build without warnings, GoogleTest tests for every acceptance criterion, review in a pull request, documentation and PO acceptance. Every member approves the pull request that adds it.
  7. Write lab07/board.md (project URL, fields, one-line policy per column: what must be true for a card to enter it) and save a screenshot lab07/board-start.png. Commit as Lab-07 task 1: board, refined backlog, definition of done.

Starter (issue template and gh commands)

<!-- .github/ISSUE_TEMPLATE/user-story.md -->
---
name: User story
about: A product backlog item for ITC Club Hub
labels: user-story
---
**US-__** As a <role>, I want <goal> so that <benefit>.

### Acceptance criteria
```gherkin
Scenario: <success case>
  Given …
  When  …
  Then  …

Scenario: <rule violated>
  Given …
  When  …
  Then  …
```
Priority: Must | Should | Could     Story points: __     Traces to: FR-__
OWNER=itc-clubhub-team3            # your organisation or user
gh project create --owner "$OWNER" --title "Club Hub board"
# note the project number that is printed, for example 1
gh project field-create 1 --owner "$OWNER" --name "Story points" --data-type NUMBER
gh project field-create 1 --owner "$OWNER" --name "Priority" \
  --data-type SINGLE_SELECT --single-select-options "Must,Should,Could,Won't"
# add every issue labelled user-story (Lab-05) to the project
for url in $(gh issue list --label user-story --state open --limit 100 \
               --json url --jq '.[].url'); do
  gh project item-add 1 --owner "$OWNER" --url "$url"
done
gh project item-list 1 --owner "$OWNER" --limit 100

Expected output (excerpt of lab07/board.md)

# Club Hub board · v1.0 · 2026-11-02
Project: https://github.com/orgs/itc-clubhub-team3/projects/1

| Column         | Policy: a card may enter when …                          |
|----------------|----------------------------------------------------------|
| Backlog        | it has an id, a user story sentence and a priority       |
| Sprint backlog | it was selected at sprint planning and has tasks          |
| In progress    | a named developer works on it now                         |
| In review      | a pull request is open and ctest passes on the branch     |
| Done           | every definition-of-done item is ticked and PO accepted   |

| Order | Issue | Story                                   | Pri  | Pts | Scenarios |
|-------|-------|-----------------------------------------|------|-----|-----------|
| 1     | #14   | US-04 List upcoming events              | Must | 3   | 2         |
| 2     | #15   | US-05 Register for an event             | Must | 5   | 4         |
| 3     | #16   | US-06 Cancel a registration             | Must | 5   | 3         |
| 4     | #11   | US-01 Register a club                   | Must | 3   | 2         |
| …     | …     | 9 Must items, 41 points in total        |      |     |           |

Show hints

  • If gh project answers "missing required scopes", run gh auth refresh -s project again and accept in the browser.
  • In the board view, Group by: Status gives you the five columns; the Status options are edited in the project settings, not per view.
  • A story that needs 13 or more points, or that the team cannot explain in one sentence, is not ready: split it along a business rule (register with the capacity rule, then the duplicate rule) or along a data variation.
  • If Lab-05 wrote the stories only in Markdown, create the issues with gh issue create --template user-story.md or paste them in the web form; keep the Lab-05 ids in the titles.

Acceptance checklist

2

Sprint planning with planning poker

Medium Lead: Scrum Master (facilitates), PO (goal and order) 75 min · week 9

Goal

Hold sprint planning for Sprint 1: agree on a Sprint Goal, estimate the top stories with planning poker, select a sprint backlog that fits the team's real capacity, and break every selected story into tasks. The result is recorded in lab07/sprint-planning.md and on the board.

Steps

  1. Capacity. Each member states the hours they can really give over the 10 working days (subtract other exams, deadlines and travel). Multiply by a focus factor (0.7 is a good start for students) and subtract the time of the Scrum events. Record the table.
  2. Sprint Goal. The PO proposes why this sprint matters; the team rewrites it until it is one sentence describing an outcome the client can try (not a list of ids). Sprint 1 must enable at least listing events and registering.
  3. Planning poker for at least the top five backlog items: the PO reads the story and criteria, questions are answered, everyone picks a card from 0, 1, 2, 3, 5, 8, 13, 21, ? in secret, cards are revealed together. If the lowest and highest differ by more than one card, both explain and the team votes again. Record every member's vote per round, the key argument, and the consensus; update the Story points field.
  4. Selection. Pull items from the top of the backlog into Sprint backlog until the next item would exceed the forecast. Sprint 1 must contain US-04 (list events) and US-05 (register, with the capacity and duplicate rules), because Task 3 implements them. Set the Sprint field to Sprint 1.
  5. Task breakdown. Split every selected story into tasks of at most 4 hours (write test, implement rule, CSV storage, CLI command, review) as a task list or sub-issues in the story issue, each with an estimate in hours. The total task hours is the start of your burndown (Task 4) and must not exceed the capacity from step 1.
  6. Write everything into lab07/sprint-planning.md and commit as Lab-07 task 2: sprint 1 planning; the SM commits, the PO reviews.

Starter (lab07/sprint-planning.md)

# Sprint 1 planning · v1.0 · 2026-11-02
PO: __   Scrum Master: __   Sprint: weeks 9-10 (__ to __)

## Capacity
| Member | Hours available | Focus 0.7 | Notes            |
|--------|-----------------|-----------|------------------|
| __     | __              | __        | exam on day __   |
| Scrum events (planning, dailies, review, retro): -__ h
| **Total capacity** | | **__ h** |  |

## Sprint Goal
<one sentence: what the client can do at the end of the sprint>

## Planning poker
| Story | Round | __ | __ | __ | __ | __ | Key argument / outcome |
|-------|-------|----|----|----|----|----|------------------------|
| US-__ | 1     |    |    |    |    |    |                        |
| US-__ | 2     |    |    |    |    |    | consensus: __ points   |

## Sprint backlog (forecast: __ points)
| Order | Story | Points | Tasks (hours) | Total h |
|-------|-------|--------|---------------|---------|

Expected output (excerpt)

Capacity: 5 members, 91 h stated x 0.7 = 64 h, minus 12 h of events = 52 h
Sprint Goal: a student can see the upcoming events, register for one and
             cancel again from the command line.

| Story | Round | Dara | Sokha | Vicheka | Rithy | Malis | Outcome                         |
| US-05 | 1     | 5    | 5     | 3       | 8     | 5     | Vicheka forgot the CSV storage  |
| US-05 | 2     | 5    | 5     | 5       | 5     | 5     | consensus: 5                    |
| US-06 | 1     | 3    | 3     | 5       | 13    | 2     | 24-hour rule needs time input   |
| US-06 | 2     | 5    | 5     | 5       | 8     | 5     | consensus: 5                    |

| 1 | US-04 List upcoming events   | 3 | test upcomingEvents 1, implement 2, CSV 3, CLI 2, review 1 |  9 |
| 2 | US-05 Register for an event  | 5 | 2 tests 2, registerStudent 3, CSV repo 4, CLI 2, review 2 | 13 |
| 3 | US-06 Cancel a registration  | 5 | tests 2, cancel 3, CSV rewrite 3, CLI 2, review 2         | 12 |
| 4 | US-01 Register a club        | 3 | test 1, Club + status 3, CSV 3, CLI 2, review 1           | 10 |
Forecast 16 points · 44 task hours of 52 h capacity (8 h buffer)

Show hints

  • No cards? Use fingers (1, 2, 3, 5), a free online planning poker room, or write the number on paper and flip together. What matters is that nobody sees the others' votes first.
  • The PO answers questions but, if also a developer, votes like everyone else; the SM facilitates and keeps each story under 10 minutes.
  • Sprint 1 has no velocity history, so forecast from capacity: if the task hours exceed about 85 % of capacity, drop the last story instead of hoping.
  • A task like "implement US-05" is too big; a good task names one class or one command and fits in one sitting.

Acceptance checklist

3

Implement the first stories test-first with GoogleTest

Medium Lead: Developers, in pairs 3–4 h per pair · during the sprint

Goal

Deliver US-05 and US-04 as working, tested C++: RegistrationService::registerStudent enforcing the capacity and duplicate rules, and a clubhub list-events command showing upcoming events from data/events.csv. Work test-first: for every rule the Git history shows the red test commit before the green code commit.

Steps

  1. Check that your Lab-06 headers provide Event (with id, start as std::chrono::sys_seconds and capacity), Registration, RegistrationStatus and the RegistrationRepository interface. If not, add the fallback headers below; keep your own names if they differ, and adapt the tests.
  2. Add the test double tests/InMemoryRegistrationRepository.hpp (a RegistrationRepository that stores rows in a std::vector) and the GoogleTest target to CMakeLists.txt (starter). Create the branch feature/US-05-register.
  3. Red: write TEST(RegistrationService, StudentCannotRegisterTwice) in tests/registration_service_test.cpp, plus only the declarations needed to compile (the header below and a registerStudent that saves without checking). Run ctest, see it fail, paste the failure into lab07/tdd-log.md, commit test(US-05): student cannot register twice [red].
  4. Green: add the simplest code in src/RegistrationService.cpp that passes; run ctest; commit feat(US-05): reject duplicate registration [green]. Refactor if the code is unclear (extract isRegistered), tests still green; commit refactor(US-05): ….
  5. Repeat red → green → refactor for RejectsWhenCapacityReached (throws EventFull) and for CancelledSeatCanBeTakenAgain (a Cancelled registration neither blocks the student nor uses a seat). Every acceptance criterion of US-05 has at least one test that asserts something.
  6. US-04 on feature/US-04-list-events, test-first again: upcomingEvents(events, now) hides events that have started and sorts by start time (pass now as a parameter so the test does not depend on the clock); then CsvEventRepository::findAll and the CLI command in src/main.cpp. Add data/events.csv with at least one past and two future events.
  7. Open a pull request per story, reviewed by a member who did not write it; tick the definition of done in the PR description; merge; move the card to Done. Complete lab07/tdd-log.md: one row per rule with the red, green and refactor commit hashes.

Starter (fallback headers, service header, first test, CMake)

// include/clubhub/Event.hpp, Registration.hpp, RegistrationRepository.hpp
// (fallback only: use your Lab-06 headers if you have them)
namespace clubhub {
struct Event {
    std::string id, clubId, title, location;
    std::chrono::sys_seconds start{};
    int capacity{0};
};
enum class RegistrationStatus { Registered, Cancelled, CheckedIn, Waitlisted };
struct Registration {
    std::string eventId, studentId;
    RegistrationStatus status{RegistrationStatus::Registered};
};
class RegistrationRepository {
public:
    virtual ~RegistrationRepository() = default;
    virtual std::vector<Registration> findByEvent(const std::string& eventId) const = 0;
    virtual void save(const Registration& registration) = 0;
};
}  // namespace clubhub
// include/clubhub/RegistrationService.hpp
#pragma once
#include <stdexcept>
#include <string>
#include "clubhub/Event.hpp"
#include "clubhub/RegistrationRepository.hpp"

namespace clubhub {

class RegistrationError : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};
class DuplicateRegistration : public RegistrationError {
public:
    using RegistrationError::RegistrationError;
};
class EventFull : public RegistrationError {
public:
    using RegistrationError::RegistrationError;
};

class RegistrationService {
public:
    explicit RegistrationService(RegistrationRepository& registrations)
        : registrations_{registrations} {}

    // Registers studentId for event.
    // Throws DuplicateRegistration or EventFull (rules of US-05).
    Registration registerStudent(const Event& event, const std::string& studentId);

private:
    RegistrationRepository& registrations_;
};

}  // namespace clubhub
// tests/registration_service_test.cpp
#include <gtest/gtest.h>
#include "InMemoryRegistrationRepository.hpp"
#include "clubhub/RegistrationService.hpp"

using namespace clubhub;
using clubhub::testing::InMemoryRegistrationRepository;

namespace {
Event workshop(int capacity) {
    Event e;
    e.id = "E1";
    e.title = "C++ Workshop";
    e.capacity = capacity;
    return e;
}
}  // namespace

TEST(RegistrationService, StudentCannotRegisterTwice) {
    InMemoryRegistrationRepository repo;
    RegistrationService service{repo};
    const Event event = workshop(30);
    service.registerStudent(event, "S001");
    EXPECT_THROW(service.registerStudent(event, "S001"), DuplicateRegistration);
}

// TODO red: RejectsWhenCapacityReached (capacity 2, third student -> EventFull)
// TODO red: CancelledSeatCanBeTakenAgain
# CMakeLists.txt (add what is missing; keep your earlier targets)
add_library(clubhub_core src/RegistrationService.cpp src/EventQueries.cpp
                         src/CsvEventRepository.cpp)
target_include_directories(clubhub_core PUBLIC include)
if(MSVC)
  target_compile_options(clubhub_core PRIVATE /W4 /WX)
else()
  target_compile_options(clubhub_core PRIVATE -Wall -Wextra -Werror)
endif()
add_executable(clubhub src/main.cpp)
target_link_libraries(clubhub PRIVATE clubhub_core)

include(FetchContent)
FetchContent_Declare(googletest
  URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip)
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)   # needed for MSVC
FetchContent_MakeAvailable(googletest)

enable_testing()
add_executable(clubhub_tests tests/registration_service_test.cpp
                             tests/event_queries_test.cpp)
target_link_libraries(clubhub_tests PRIVATE clubhub_core GTest::gtest_main)
include(GoogleTest)
gtest_discover_tests(clubhub_tests)

Expected output

$ git log --oneline --reverse main -- src tests
3f1c2aa test(US-05): student cannot register twice [red]
8b04d1e feat(US-05): reject duplicate registration [green]
c7e9a10 refactor(US-05): extract isRegistered
d21f5b3 test(US-05): capacity cannot be exceeded [red]
0a9e6c4 feat(US-05): throw EventFull when capacity reached [green]
5d77b2f test(US-05): cancelled registration frees the seat [red]
91ac0e8 feat(US-05): ignore cancelled registrations [green]
e4b3f19 test(US-04): upcomingEvents hides past events, sorts by start [red]
6fd2c01 feat(US-04): upcomingEvents and CsvEventRepository [green]
b8a4d55 feat(US-04): list-events command

$ ctest --test-dir build
1/6 Test #1: RegistrationService.RegistersStudentWhenSeatsLeft ...   Passed
2/6 Test #2: RegistrationService.StudentCannotRegisterTwice ......   Passed
3/6 Test #3: RegistrationService.RejectsWhenCapacityReached ......   Passed
4/6 Test #4: RegistrationService.CancelledSeatCanBeTakenAgain ....   Passed
5/6 Test #5: EventQueries.ParsesAndFormatsDateTime ...............   Passed
6/6 Test #6: EventQueries.UpcomingSkipsPastAndSortsByStart .......   Passed
100% tests passed, 0 tests failed out of 6

$ ./build/clubhub list-events
ID   START             TITLE                       CAP
E01  2026-11-05 18:00  Intro to Git workshop        40
E02  2026-11-07 09:00  Robotics open day           120

Show hints

  • Red commits live on the feature branch only; main receives the branch through a pull request when everything is green, so the red commit is still in the history after the merge (use a merge commit or a rebase merge, not squash).
  • A compile error is not a useful red: add just enough declaration (header plus a registerStudent that saves and returns) so the test compiles and fails on its assertion.
  • Count seats with std::ranges::count_if over findByEvent(event.id), skipping Cancelled; check the duplicate rule before the capacity rule, so a student who is already registered for a full event gets the right error.
  • Parsing 2026-11-05 18:00 portably: read the numbers with a std::istringstream, build a std::chrono::year_month_day, check .ok(), and add hours and minutes to sys_days. The chapter's TDD slides show the style.
  • When pairing, add Co-authored-by: Name <email> as the last line of the commit message so both partners appear in the history.

Acceptance checklist

4

Daily scrums, board updates and the sprint burndown

Medium Lead: Scrum Master 15 min per day + 45 min

Goal

Inspect and adapt every day: hold a 15-minute daily scrum on at least 8 of the 10 sprint days, keep the board true, record the remaining work each day, and draw the sprint burndown (ideal versus actual) from that data with Mermaid.

Steps

  1. Fix the time and channel of the daily (for example 8:00, in person or a 15-minute call). Before it starts, every member moves their cards and updates the remaining hours of their tasks on the board.
  2. Run the daily around the Sprint Goal: each member answers yesterday, today, blockers. The SM notes it in lab07/daily-scrum-log.md with the template below and stops at 15 minutes; discussions happen right after, with only the people involved.
  3. Every blocker gets an owner and a follow-up in the log. A blocker still open at the next daily is escalated by the SM (to the PO for scope questions, to the TA for tooling problems).
  4. After each daily, append one row to lab07/burndown-data.csv: day, date, remaining task hours summed from the board, ideal hours (total from Task 2 × (10 − day) / 10), and a note when tasks were added or removed.
  5. At the end of the sprint, write lab07/burndown.md with a Mermaid xychart-beta drawn from the CSV (first line ideal, second line actual) and three sentences interpreting it: where the team fell behind or caught up, and why.
  6. Commit the log and the CSV at least every two days; different members commit them (the SM of the day, or whoever took the notes), so the history shows the team, not one person.

Starter (log template, CSV, chart skeleton)

## Day 4 · 2026-11-05 · 08:00-08:14 · SM: Sokha
Sprint Goal: students can list, register for and cancel events from the CLI
| Member | Yesterday | Today | Blockers |
|--------|-----------|-------|----------|
| __     | __        | __    | none     |
Follow-ups: <blocker> -> <owner>, <action>, <resolved on day __>
Board: __ h remaining (ideal __ h)
day,date,remaining_h,ideal_h,note
0,2026-11-02,44,44.0,after sprint planning
1,2026-11-03,,39.6,
xychart-beta
  title "Sprint 1 burndown, remaining task hours"
  x-axis [D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10]
  y-axis "Remaining hours" 0 --> 50
  line [44, 39.6, 35.2, 30.8, 26.4, 22, 17.6, 13.2, 8.8, 4.4, 0]
  line [44, __, __, __, __, __, __, __, __, __, __]

Expected output (rendered burndown and interpretation; grey = ideal, blue = actual)

---
config:
  themeVariables:
    xyChart:
      plotColorPalette: "#6c757d, #0d6efd"
---
xychart-beta
  title "Sprint 1 burndown, remaining task hours"
  x-axis [D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10]
  y-axis "Remaining hours" 0 --> 50
  line [44, 39.6, 35.2, 30.8, 26.4, 22, 17.6, 13.2, 8.8, 4.4, 0]
  line [44, 44, 46, 41, 37, 33, 27, 20, 14, 8, 3]
Days 1-2: flat, then +2 h: CSV rewrite
task found for US-06 (logged day 2).
Days 3-6: behind by about 10 h; the
daily on day 5 moved Malis from US-01
to pair on US-05.
Days 7-10: nearly caught up after
US-01 went back to the backlog (day 7,
logged). 3 h left on day 10: the
24-hour rule test of US-06, so US-06
is not done.

Show hints

  • Burn down task hours, not story points: with three or four stories a points burndown is a staircase that tells you nothing until the last day.
  • Never edit past rows to make the curve look better; a line that goes up on the day you discovered work is honest and useful.
  • GitHub Projects has built-in Insights charts; you may add a screenshot, but the Mermaid chart must come from your CSV so the data is in the repository.
  • If the daily keeps running long, the SM asks "does this help us reach the Sprint Goal today?" and moves the topic to after the daily.

Acceptance checklist

5

Sprint review, retrospective and record what changed

Hard Lead: PO (review), Scrum Master (retrospective) 90 min · week 10

Goal

Close Sprint 1: demonstrate the increment to the client, judge honestly what is done against the definition of done, turn the feedback into backlog changes, run a Start/Stop/Continue retrospective with two concrete actions, and record what this lab produced in lab07/README.md.

Steps

  1. Write the demo script in lab07/sprint-review.md: the Sprint Goal, then numbered demo steps with the exact commands and data (git clone, build, clubhub list-events, a registration, a duplicate attempt, a full event), and who presents each step. Demo only from a clean build of main.
  2. Hold the review with the client (instructor or TA), at most 45 minutes: the PO states the goal and what was selected, developers run the script, the client tries it. No slides.
  3. Fill the done / not done table: for each sprint backlog item, every definition-of-done criterion ticked or not, and the verdict. Velocity = points of items that are fully done. Not-done items go back to Backlog with their remaining work written in the issue.
  4. Record the client's feedback; each point becomes a new issue or a change to an existing one (give the issue numbers). The PO reorders the backlog and writes a Sprint 2 forecast range from the velocity.
  5. Retrospective (SM facilitates, 45 minutes, team only): everyone writes Start / Stop / Continue notes silently for 5 minutes, groups them, dot-votes (3 votes each), and the team chooses two actions, each with an owner, a due date and how you will know it worked. Put them in lab07/retrospective.md and as issues labelled improvement in Sprint 2.
  6. Hand over the Scrum Master role for Sprint 2 and save lab07/board-end.png.
  7. Record what changed: create lab07/README.md with a table of every Lab-07 file and a one-line description, a table Inputs reused (the Lab-01, Lab-04, Lab-05 and Lab-06 files or issues you used, with their version or commit hash, or "fallback" if you used the Setup fallback), the code files added or changed in src/, include/clubhub/, tests/, and a change-log row (date, version, what changed). Commit as Lab-07 task 5: sprint review, retrospective, README, push and open the pull request.

Starter (review, retrospective and README skeletons)

# Sprint 1 review · v1.0 · 2026-11-13
Sprint Goal: __        Client: __        Attendees: __
## Demo script
1. (__) git clone … && cmake -S . -B build && cmake --build build
2. (__) ./build/clubhub list-events        -> expect 2 upcoming events
3. (__) register S001 for E01 twice         -> second attempt refused
## Done / not done against the definition of done
| Item  | Pts | Builds, 0 warn | Tests | Reviewed | Docs | PO ok | Verdict |
|-------|-----|----------------|-------|----------|------|-------|---------|
Velocity: __ points (done items only)
## Client feedback -> backlog
| Feedback | Issue | Change |
## Sprint 2 forecast: __ to __ points

# Sprint 1 retrospective · v1.0 · 2026-11-13 · facilitator: __
| Start | Stop | Continue |      (votes in brackets)
## Actions
| # | Action | Owner | Due | How we will know it worked | Issue |
# Lab-07 · Sprint 1 · README
| File | Description |
|------|-------------|
| board.md, board-start.png, board-end.png | … |
## Inputs reused
| Input | Version or commit |
|-------|-------------------|
| lab05 backlog / issues #11-#24 | commit __ |
## Code added or changed
| Path | Change |
## Change log
| Date | Version | Change |
|------|---------|--------|
| 2026-11-13 | 1.0 | Sprint 1 closed: velocity __, SM handed over to __ |

Expected output (excerpt)

| US-04 | 3 | ✓ | ✓ 2 tests | ✓ PR #31 | ✓ | ✓ | Done     |
| US-05 | 5 | ✓ | ✓ 4 tests | ✓ PR #29 | ✓ | ✓ | Done     |
| US-06 | 5 | ✓ | ✗ 24 h rule untested | ✓ PR #35 | ✗ | ✗ | Not done |
Velocity: 8 points. US-06 back to the backlog: "24-hour rule + test, 4 h".
Client feedback: show remaining seats in list-events (#38, new, 2 pts);
                 cancelled students should be able to re-register (already done).
Sprint 2 forecast: 8 to 12 points (one sprint of history, so a wide range).

Retrospective actions
| 1 | WIP limit 2 in "In review"; SM checks at each daily | Vicheka | every daily | no PR waits > 1 day | #40 |
| 2 | "ctest passed" line in the PR template             | Rithy   | Mon wk 11   | 0 red merges        | #41 |

Show hints

  • An item that fails one DoD criterion is not done, even if it "basically works". Saying so openly at the review is exactly what Scrum asks for, and it costs no marks here.
  • Rehearse the demo script once on a fresh clone the day before: missing data/events.csv or a hard-coded path is the most common demo failure.
  • "Communicate better" is not an action. "Post blockers in the team chat before 20:00, SM summarises them at the daily" is.
  • lab07/README.md lists the earlier-lab files you actually used, with a commit hash (git log -1 --format=%h -- lab05/); if you used a Setup fallback, write "fallback" instead of repairing the earlier lab.

Acceptance checklist

Challenge: one XP practice for the whole sprint, measured

Hard 90–120 min spread over the sprint · optional, extra credit

Scenario

Your team suspects that work gets stuck: pull requests wait for days, and knowledge of the CSV code sits in one head. Instead of arguing, run an experiment for the whole of Sprint 1 with one practice, collect simple data, and decide with evidence whether to keep it in Sprint 2.

Requirements

  1. Choose A · pair programming rotation (pairs change every two sprint days, driver and navigator swap every 25 minutes, every commit made in a pair carries a Co-authored-by: trailer) or B · Kanban WIP limit (at most one card per developer in In progress and at most 2 in In review; when a column is full you help finish instead of starting).
  2. Before day 1, write in lab07/xp-experiment.md a hypothesis with a measurable prediction (for example "median cycle time per task drops below 1 day") and the exact rule the team follows.
  3. Collect data in lab07/xp-data.csv during the sprint. For A: per task, pair or solo, cycle time, defects found in review; share of co-authored commits (git log --format=%b | grep -c Co-authored-by). For B: per task, the timestamps when it entered In progress and Done, the daily count of cards in progress, the hours each PR waited for review. Use days 1 to 3 as the baseline if you need a before/after comparison.
  4. Analyse: a results table (median and maximum, baseline versus experiment) and one Mermaid chart (xychart-beta bars or lines) drawn from the CSV.
  5. Conclude in five to eight sentences: was the hypothesis supported, what else could explain the numbers (small sample, exam week, different story sizes), and a recommendation for Sprint 2 that you then add as a retrospective action.

Skeleton

# XP experiment · Sprint 1 · v1.0
Practice: B · Kanban WIP limit     Rule: 1 card per developer in progress, 2 in review
Hypothesis: with the limit, the median cycle time per task falls from about 2 days
            to at most 1 day, and no pull request waits more than 1 day for review.
## Data (xp-data.csv)
task,story,phase,started,done,cycle_days,review_wait_h
T-05,US-05,baseline,2026-11-03,2026-11-05,2,30
## Results
| Measure                  | Baseline (days 1-3) | Experiment (days 4-10) |
|--------------------------|---------------------|------------------------|
| Median cycle time (days) |                     |                        |
| Max review wait (hours)  |                     |                        |
## Conclusion and recommendation for Sprint 2

Expected output (excerpt)

| Median cycle time (days) | 2.0 (n = 6) | 1.0 (n = 14) |
| Max review wait (hours)  | 30          | 9            |
| Cards in progress (avg)  | 7.3         | 4.1          |
Supported, with caveats: n is small, and days 1-3 held the unfamiliar setup work.
Recommendation: keep the review limit of 2 in Sprint 2 (retro action #40); drop
the in-progress limit to 1 per developer only for stories above 5 points.

Show hints

  • Decide the measures before the sprint starts; choosing them afterwards invites picking the numbers that look good.
  • Cycle time is easiest to collect if the person who moves a card also writes the date in the issue (or read the timestamps from the project's item history).
  • Use the median, not the mean: one task blocked for five days would dominate an average of fifteen tasks.
  • A result that does not support the hypothesis is still a full-mark result if the data and the reasoning are honest.

Acceptance checklist

Grading rubric

ComponentPointsFull marks when…
Task 1 · Board, refinement, DoD15Five workflow columns and three fields; every Must story on the board with points and at least two scenarios; ordered backlog; column policies; DoD with six or more checkable items approved by all.
Task 2 · Sprint planning15Per-member capacity; outcome-based Sprint Goal; poker votes per member and round with arguments for five stories; sprint backlog within capacity including US-04 and US-05; tasks of at most 4 h.
Task 3 · First stories with TDD25Duplicate and capacity rules implemented and tested; red-before-green commits for every rule; list-events filters and sorts with a test; zero warnings, ctest green; reviewed pull requests; tdd-log.md complete.
Task 4 · Dailies and burndown15Eight or more daily entries for every member; blockers with owners; CSV consistent with board and log; Mermaid burndown with ideal and actual lines and an interpretation.
Task 5 · Review, retrospective, README20Demo script and review with the client; honest done / not-done table and velocity; feedback linked to issues; two actions with owner, date and measure; complete lab07/README.md.
Teamwork and code quality10Every member has commits and reviews in the sprint; modern C++ (no raw new/delete, const correctness, exceptions for rule violations); clear commit messages with story ids.
★ Challenge (extra credit)+20Hypothesis and rule written before the sprint, data collected during it, table and chart from the CSV, honest conclusion with a Sprint 2 action.
Total100 (+20)
Automatic deductions: −5 per backlog item in the sprint without story points or acceptance criteria · −10 if the history shows no red test commit before the green code commit for registerStudent · −5 per test that asserts nothing · −5 if the sprint backlog exceeds the stated capacity without a written reason · −10 if the burndown does not match the board and the daily log (a curve drawn afterwards) · −5 if a retrospective action has no owner or no date · −10 if cmake build or ctest fails from a clean checkout of lab-07 · −5 per member with no commit in the sprint.

Submission

  1. Repository layout at the end of Sprint 1:
    clubhub/
    ├── CMakeLists.txt
    ├── data/events.csv
    ├── include/clubhub/  Event.hpp  Registration.hpp  RegistrationRepository.hpp
    │                     EventRepository.hpp  EventQueries.hpp  RegistrationService.hpp
    ├── src/              main.cpp  RegistrationService.cpp  EventQueries.cpp
    │                     CsvEventRepository.cpp
    ├── tests/            InMemoryRegistrationRepository.hpp
    │                     registration_service_test.cpp  event_queries_test.cpp
    ├── .github/ISSUE_TEMPLATE/user-story.md
    └── lab07/            board.md  board-start.png  board-end.png  definition-of-done.md
                          sprint-planning.md  tdd-log.md  daily-scrum-log.md
                          burndown-data.csv  burndown.md  sprint-review.md
                          retrospective.md  README.md  (xp-experiment.md  xp-data.csv)
  2. Self-check from a clean checkout, then check the TDD order in the history:
    git clone <your-repo-url> check && cd check && git switch lab-07
    cmake -S . -B build && cmake --build build && ctest --test-dir build
    ./build/clubhub list-events
    git log --oneline --reverse -- src tests | grep -E "\[red\]|\[green\]"
    git shortlog -sn --since="2 weeks ago"      # every member appears
  3. Branch lab-07, pull request titled Lab-07 – <team name>, with the project board URL and the sprint velocity in the description. The instructor reviews the pull request, the board and the review record.