Introduction to Software Engineering · Chapter 03

Lab-03: Privacy, licence, accessibility and ethics review for ITC Club Hub

Your team reviews ITC Club Hub before much code exists, which is when changes are cheapest. You build a data inventory and decide what not to collect, write the privacy notice and consent step students will see, and implement a C++ Student class that stores only what the inventory allows and logs only a redacted form. You then choose and apply a licence for the team repository, review the planned interfaces against WCAG 2.2 and write rules for accessible CLI output, and analyse two ethics scenarios with the seven-step framework. The challenge asks for a go/no-go recommendation on an AI event recommender.

SE Code 5.2 · ACM Code 2018 · GDPR principles · WCAG 2.2 C++20 · CMake · GoogleTest · GitHub · Mermaid ≈ 5 hours 5 tasks + 1 challenge
How to work through this lab. Do the tasks in order; each builds on the previous. 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. This is team work: every task names a lead role, and each member's contribution must be visible in the Git history (own commits, or review comments on the pull request).
0

Setup

20 min
  1. Tools. Git, CMake 3.28 or later, a C++20 compiler (GCC 13, Clang 17 or MSVC in Visual Studio 2022, or newer), an editor with Markdown preview and Mermaid support (VS Code with Markdown Preview Mermaid Support, or mermaid.live), and a contrast checker for Task 4 (for example the WebAIM Contrast Checker in the browser). GoogleTest is fetched by CMake; nothing to install.
    git --version
    cmake --version          # 3.28 or later
    g++ --version            # GCC 13+, or clang++ --version, or MSVC 2022
    cd itc-club-hub          # your team repository from Lab-01
    git switch main && git pull
    git switch -c lab-03
  2. Inputs from earlier labs. This lab reuses your Lab-01 charter and your Lab-02 application-type decision. If one of them is incomplete, use the fallback and carry on; do not stop to repair the earlier lab.
    InputWhere (typical file)What you need from itFallback if missing
    Team charterlab01/ charter fileTeam name (for the copyright line), members and roles (Product Owner, Scrum Master, Developers), working agreementsTeam name "Team <table number>"; the Product Owner is the member whose name comes first alphabetically; the Scrum Master is the second.
    Repository skeletonroot of the repository (Lab-01)README.md, CMakeLists.txt, include/clubhub/, src/, tests/Create the folders and use the minimal CMakeLists.txt in step 5 below.
    Application type and quality attributeslab02/ application-type documentWhich front ends exist or are planned (CLI, web, mobile), the top quality attributes, where data is storedC++ core with a command-line front end and CSV files (built this semester); a responsive web app and a mobile app for students and organisers (planned, modelled only). Top attributes: usability, reliability, privacy and security.
    Product factsCase-study brief (next step)Features, roles, business rules and the personal data involvedAlways available; it is the product definition for this course.
  3. Case-study brief. The box below is everything you need to know about the product for this lab. Wherever a step says "the brief", it means this box.
    Case-study brief: ITC Club Hub
    Purpose
    An application for the student clubs of the Institute of Technology of Cambodia. Teams of 4 to 5 students analyse and model it as a web and mobile application and implement its core in C++20: domain model, business rules and a command-line front end with CSV or JSON file storage.
    Roles
    Student: browses events, registers, cancels, receives a reminder. Club leader: registers a club and manages it. Organiser: publishes events, checks students in at the door, sees attendance. Administrator (clubs office): approves clubs, sees a monthly activity report across clubs. Club leaders and organisers are students too.
    Features
    Club registration and approval · events with title, date and time, location, capacity and description · student registration and cancellation · reminders · check-in and attendance · monthly activity report.
    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 · past events cannot be registered for · only approved clubs can publish events.
    Personal data
    Student ID, name, email, phone (optional), club membership, attendance records. Nothing else is required by any feature.
    Ethics context
    The clubs office is responsible for the data (it plays the "data controller"). Some clubs have sponsors (phone shops, banks, cafés). Cambodian data-protection rules are evolving (the Law on Electronic Commerce, 2019, contains provisions on personal data held electronically); the course uses GDPR principles as the design reference. The planned interfaces target WCAG 2.2 level AA.
    Code conventions
    Namespace clubhub; classes Club, Event, Student, Registration; enums ClubStatus (Pending, Approved, Rejected) and RegistrationStatus (Registered, Cancelled, CheckedIn, Waitlisted); headers in include/clubhub/, sources in src/, GoogleTest tests in tests/.
    Project rhythm
    15-week semester · Sprint 1 in weeks 9 and 10, Sprint 2 in weeks 11 and 12 · submission and demo in week 14 · the instructor or a teaching assistant plays the client and talks to your Product Owner.
  4. Deliverable files. Create lab03/ and the files below (empty for now); every task fills some of them.
    itc-club-hub/
    ├── LICENSE                            # Task 3
    ├── THIRD_PARTY_NOTICES.md             # Task 3
    ├── licenses/googletest-LICENSE.txt    # Task 3
    ├── CMakeLists.txt                     # Tasks 2 and 4 add files
    ├── include/clubhub/Student.h          # Task 2
    ├── include/clubhub/ConsoleOutput.h    # Task 4
    ├── src/Student.cpp                    # Task 2
    ├── src/ConsoleOutput.cpp              # Task 4
    ├── tests/StudentPrivacyTest.cpp       # Task 2
    ├── tests/ConsoleOutputTest.cpp        # Task 4
    └── lab03/
        ├── data-inventory.md              # Task 1
        ├── privacy-notice.md              # Task 2
        ├── consent-flow.mmd               # Task 2
        ├── retention-rules.md             # Task 2
        ├── licence-decision.md            # Task 3
        ├── accessibility-checklist.md     # Task 4
        ├── cli-output-rules.md            # Task 4
        ├── ethics-cases.md                # Task 5
        ├── README.md                      # Task 5 (record what changed)
        └── ai-feature-proposal.md         # Challenge
  5. Build file. If your repository has no working CMakeLists.txt yet, start from this one. If it has one, only add the new source and test files to it.
    cmake_minimum_required(VERSION 3.28)
    project(ClubHub LANGUAGES CXX)
    
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    add_library(clubhub_core
      src/Student.cpp
      src/ConsoleOutput.cpp)
    target_include_directories(clubhub_core PUBLIC include)
    
    include(FetchContent)
    FetchContent_Declare(googletest
      URL https://github.com/google/googletest/archive/refs/tags/v1.15.2.zip)
    # Windows/MSVC: use the same runtime library as the project
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
    FetchContent_MakeAvailable(googletest)
    
    enable_testing()
    add_executable(clubhub_tests
      tests/StudentPrivacyTest.cpp
      tests/ConsoleOutputTest.cpp)
    target_link_libraries(clubhub_tests PRIVATE clubhub_core GTest::gtest_main)
    include(GoogleTest)
    gtest_discover_tests(clubhub_tests)
  6. Conventions. Every Markdown file starts with a title, a version, a date and its authors. Use invented people only (IDs such as e2099xxxx, emails at example.edu): no real student's data goes into the repository, not even your own. Commit after each task with a message Lab-03 task N: ...; the person who did the work makes the commit.
1

Data inventory with minimisation decisions

Easy 45 min · Product Owner leads

Goal

List every piece of personal data Club Hub could store, give each one a purpose, a legal basis, a retention limit and a reader list, and decide what to keep, mask, aggregate or drop. The inventory becomes the rule book for the code in Task 2.

Steps

  1. Create lab03/data-inventory.md from the starter. Add one row for each of the six personal data items in the brief (studentId, name, email, phone, clubMemberships, attendance), then at least three candidate fields that someone in your team or a club might ask for (for example date of birth, photo, faculty and year, gender, Telegram handle).
  2. Fill every column: Purpose (the screen, report or rule that uses the field), Legal basis / consent (necessary for the service, consent, or legitimate interest with a one-sentence justification), Retention (tied to an event, for example "until consent is withdrawn"), Who can see it (by role: student, organiser, club leader, administrator) and Stored in (file name, for example data/students.csv).
  3. Fill the Decision column with Keep, Keep optional, Mask, Aggregate or Drop, plus a one-sentence reason. At least three fields must end as Mask, Aggregate or Drop.
  4. Complete the Copies of personal data section: one rule each for log files, CSV exports, test fixtures, backups and screenshots in documentation.
  5. Draw the lifecycle of the phone field (collect, store, use, share, delete) as a Mermaid flowchart LR in the same file, with the obligation of each step in the node text.
  6. The Product Owner walks the teaching assistant (acting client) through the Drop decisions in five minutes and records any objection under Client feedback. Commit: git commit -m "Lab-03 task 1: data inventory".

Starter

# Data inventory · ITC Club Hub
Version 0.1 · 2026-MM-DD · Authors: <names>

| Field | Subject | Purpose | Legal basis / consent | Retention | Who can see it | Stored in | Decision |
|-------|---------|---------|-----------------------|-----------|----------------|-----------|----------|
| studentId | student | identify; block double registration | necessary for the service | TODO | TODO | data/students.csv | Mask for organisers: TODO reason |
| name | student | TODO | TODO | TODO | TODO | TODO | TODO |
| phone | student | TODO | consent (opt-in) | TODO | TODO | TODO | TODO |
| attendance | student | TODO | legitimate interest: TODO why | TODO | TODO | data/registrations.csv | TODO |
| dateOfBirth | student | TODO: is there any? | TODO | TODO | TODO | TODO | TODO |

## Copies of personal data
| Copy | Rule |
|------|------|
| log files | only `redacted()` output, never name, email or phone |
| CSV exports | TODO |
| test fixtures | TODO |
| backups | TODO |
| screenshots in docs | TODO |

## Lifecycle of the phone field
```mermaid
flowchart LR
  C["Collect
TODO"] --> S["Store
TODO"] ``` ## Client feedback - TODO

Expected output

Two rows of a good inventory (yours has at least nine) and the rendered lifecycle of the phone field:

FieldPurposeLegal basis / consentRetentionWho can see itDecision
phoneSMS reminder 24 h before an event, only if chosenConsent, opt-in, withdrawable in My profileDeleted at once on withdrawal, otherwise 6 months after graduationNobody on screen; read only by the reminder senderKeep optional: SMS reaches students without mobile data
dateOfBirthNone: no feature, rule or report uses itNoneNot collectedNobodyDrop: "might be useful" is not a purpose
flowchart LR
  C["Collect
only after SMS opt-in"] --> S["Store
phone column, students.csv"] S --> U["Use
reminder sender only"] U --> SH["Share
SMS gateway, nobody else"] SH --> D["Delete
on withdrawal or
6 months after graduation"]

Show hints

  • A purpose names a user-visible function. If you cannot point to the screen, rule or report that reads the field, the decision is Drop.
  • "Legitimate interest" needs a reason and a limit: why does the institute need identified attendance, and when does it become counts only?
  • Organisers are students too: do they need the full student ID at the door, or is the name plus a masked ID enough?
  • Retention tied to an event ("6 months after graduation") is easier to implement and explain than a bare number of days.
  • Mermaid node text with commas or parentheses must be in double quotes: C["Collect, then store"].

Acceptance checklist

2

Privacy notice, consent, retention and a privacy-aware Student

Medium 75 min · Developers lead (one writes, one codes)

Goal

Turn the inventory into what a student sees at registration (a plain-language notice and a fair consent step), into written retention rules, and into a C++ Student class that can only hold what the inventory allows and can only be logged in redacted form.

Steps

  1. Write lab03/privacy-notice.md (at most 300 words) with the sections Who we are, What we collect and why, Who sees it, How long, Your choices and Contact. Every Keep field of the inventory appears; no dropped field does. Short sentences, "we" and "you", no legal jargon.
  2. Design the consent step in lab03/consent-flow.mmd (Mermaid flowchart LR) for the CLI command clubhub register and the planned web form: the one-line notice with a link, one separate question per optional purpose, all optional answers defaulting to "no", account creation that works when everything optional is declined, and the path to withdraw consent later.
  3. Write lab03/retention-rules.md: one row per kept field with trigger, action (delete, aggregate or anonymise), who or what runs it (for example a future admin command clubhub purge, monthly) and how to verify it happened.
  4. Implement include/clubhub/Student.h and src/Student.cpp from the starter: only inventory fields; phone is a std::optional<std::string> set only by giveSmsConsent() and erased by withdrawSmsConsent(); email reminders are off by default; the constructor throws std::invalid_argument for an empty ID or name and for an email without @.
  5. Implement redacted() (masked ID only, for example Student{id=e2******7}) and the free function maskId(). Replace any place in src/ that prints a student with redacted(); review every hit of git grep -nE "name\(\)|email\(\)|phone\(\)" -- src/: none may be a log or print line.
  6. Complete tests/StudentPrivacyTest.cpp with at least six tests: redaction hides name, email and phone; optional consents start off; withdrawal erases the phone; bad email throws; a phone with letters is rejected; short IDs are fully masked.
  7. Build and test, then commit (the author of each file commits it): cmake -S . -B build && cmake --build build && ctest --test-dir build.

Starter code

// include/clubhub/Student.h
// SPDX-License-Identifier: TODO (Task 3)
#pragma once

#include <optional>
#include <string>
#include <string_view>

namespace clubhub {

// Stores only the fields allowed by lab03/data-inventory.md.
class Student {
public:
    // Throws std::invalid_argument for an empty id or name,
    // or an email without '@'.
    Student(std::string id, std::string name, std::string email);

    const std::string& id() const noexcept { return id_; }
    const std::string& name() const noexcept { return name_; }
    const std::string& email() const noexcept { return email_; }
    const std::optional<std::string>& phone() const noexcept {
        return phone_;
    }
    bool remindersByEmail() const noexcept { return remindByEmail_; }

    // Consent is explicit, separate and can be withdrawn.
    void giveSmsConsent(std::string phone);   // TODO: digits, '+', ' '
    void withdrawSmsConsent() noexcept;       // TODO: erase the number
    void setEmailReminders(bool on) noexcept { remindByEmail_ = on; }

    // Safe for logs: "Student{id=e2******7}", nothing else.
    std::string redacted() const;             // TODO

private:
    std::string id_;
    std::string name_;
    std::string email_;
    std::optional<std::string> phone_;        // only with SMS consent
    bool remindByEmail_ = false;              // opt-in: off by default
    // TODO: add a member ONLY if it has a Keep row in the inventory
};

// "e20990417" -> "e2******7"; 3 characters or fewer -> all '*'
std::string maskId(std::string_view id);      // TODO

}  // namespace clubhub
// tests/StudentPrivacyTest.cpp
#include "clubhub/Student.h"

#include <gtest/gtest.h>

#include <stdexcept>

using clubhub::Student;

// Invented test data only: never real students.
TEST(StudentPrivacy, RedactedHidesPersonalData) {
    Student s{"e20990417", "Test Student", "test@example.edu"};
    s.giveSmsConsent("012 345 678");
    const std::string r = s.redacted();
    EXPECT_EQ(r, "Student{id=e2******7}");
    EXPECT_EQ(r.find("Test"), std::string::npos);
    EXPECT_EQ(r.find("example.edu"), std::string::npos);
    EXPECT_EQ(r.find("345"), std::string::npos);
}

TEST(StudentPrivacy, OptionalConsentsStartOff) { /* TODO */ }
TEST(StudentPrivacy, WithdrawingSmsConsentErasesPhone) { /* TODO */ }

TEST(StudentPrivacy, RejectsEmailWithoutAt) {
    EXPECT_THROW((Student{"e20990417", "A", "no-at-sign"}),
                 std::invalid_argument);
}

TEST(StudentPrivacy, RejectsPhoneWithLetters) { /* TODO */ }
TEST(StudentPrivacy, MaskIdHidesShortIdsCompletely) { /* TODO */ }

Expected output

$ ctest --test-dir build
    Start 1: StudentPrivacy.RedactedHidesPersonalData
1/6 Test #1: StudentPrivacy.RedactedHidesPersonalData ..........   Passed    0.01 sec
    Start 2: StudentPrivacy.OptionalConsentsStartOff
2/6 Test #2: StudentPrivacy.OptionalConsentsStartOff ...........   Passed    0.01 sec
...
6/6 Test #6: StudentPrivacy.MaskIdHidesShortIdsCompletely ......   Passed    0.01 sec

100% tests passed, 0 tests failed out of 6

The first part of a good consent flow (consent-flow.mmd, rendered). Yours continues with the web form and the withdrawal path:

flowchart LR
  A["clubhub register"] --> B["Enter student ID, name, email
one-line notice + link to full notice"] B --> C{"Email reminders?
default: no"} C -- yes --> D["setEmailReminders(true)"] C -- no --> E D --> E{"SMS reminders?
default: no"} E -- yes --> F["Ask phone number
giveSmsConsent()"] E -- no --> G["Account created"] F --> G

Show hints

  • std::optional::reset() erases the stored value; after it, phone().has_value() is false.
  • Validate the phone before assigning it, so that a rejected number leaves the old state untouched (use std::all_of with a lambda over unsigned char).
  • maskId: copy the string, then overwrite positions 2 to size() - 2 with '*'; handle the short case first.
  • Write the notice for a first-year student reading on a phone: if a sentence needs a second reading, split it. A Khmer version is welcome as privacy-notice.km.md.
  • Retention "verify" examples: a test that the purge removes a row, or a monthly admin checklist item with a date and a signature.

Acceptance checklist

3

Choose and apply a licence for the team repository

Medium 45 min · Scrum Master leads, whole team decides

Goal

Decide between MIT, Apache 2.0 and GPL-3.0 with written reasons, apply the licence correctly (LICENSE file, SPDX headers) and give credit for every third-party component, starting with GoogleTest.

Steps

  1. Fill the justification table in lab03/licence-decision.md: six criteria (who may reuse our code, whether improvements must be shared back, patent protection, compatibility with our dependencies, simplicity for future student teams, any requirement of the instructor or institute) against the three licences. Check first with the teaching assistant whether the course requires a particular licence.
  2. Record the decision, a one-paragraph rationale and every member's agreement (name and date). Each member owns the copyright of their own contributions, so a licence needs everyone's consent.
  3. Add LICENSE at the repository root with the full, unmodified licence text (from choosealicense.com or the SPDX list); for MIT fill in the year and <team name>, ITC Club Hub contributors.
  4. Add the two-line SPDX header to every file in include/, src/ and tests/, then run the check below; it must print nothing.
  5. Create THIRD_PARTY_NOTICES.md listing GoogleTest (the exact version in your CMakeLists.txt, licence BSD-3-Clause, source URL, used for tests only, not shipped) and any other copied code or asset, or the line "No other third-party code". Copy GoogleTest's licence text to licenses/googletest-LICENSE.txt.
  6. Add a Licence section to the root README.md, push, and check that GitHub shows the licence in the repository sidebar. Commit: Lab-03 task 3: licence and notices.

Starter

# Licence decision · ITC Club Hub
Version 1.0 · 2026-MM-DD · Lead: <Scrum Master>

| Criterion                               | MIT  | Apache-2.0 | GPL-3.0 |
|-----------------------------------------|------|------------|---------|
| Anyone (incl. companies) may reuse      | TODO | TODO       | TODO    |
| Improvements must be shared back        | TODO | TODO       | TODO    |
| Explicit patent grant                   | TODO | TODO       | TODO    |
| Compatible with GoogleTest (BSD-3)      | TODO | TODO       | TODO    |
| Simple for future student teams         | TODO | TODO       | TODO    |
| Instructor / institute requirement      | TODO | TODO       | TODO    |

**Decision:** TODO
**Rationale:** TODO (one paragraph)

| Member | Agrees | Date |
|--------|--------|------|
| TODO   | yes    | TODO |
# every tracked source file must carry an SPDX header: prints nothing when OK
git ls-files 'include/*' 'src/*' 'tests/*' | xargs grep -L "SPDX-License-Identifier"

Expected output

// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Team Mekong, ITC Club Hub contributors
#include "clubhub/Student.h"
| Component  | Version | Licence      | Source                               | Used for | Shipped? |
|------------|---------|--------------|--------------------------------------|----------|----------|
| GoogleTest | 1.15.2  | BSD-3-Clause | https://github.com/google/googletest | tests    | no       |

The SPDX check prints nothing, and the GitHub sidebar shows the licence you chose (for example "MIT license").

Show hints

  • Using a BSD-3-Clause library does not force your licence; it only requires you to keep its copyright notice and licence text.
  • Do not edit the licence text itself: only the copyright line of MIT (or the appendix of Apache 2.0) is filled in.
  • Apache 2.0 needs a NOTICE file only if you have notices to pass on; GPL-3.0 needs the full text, which is long: that is normal.
  • If one member disagrees, discuss the criterion they care about and record the outcome; do not outvote silently.

Acceptance checklist

4

Accessibility review: WCAG 2.2 checklist and CLI output rules

Medium 60 min · one Developer with the Product Owner

Goal

Make accessibility a design input rather than a late fix: a WCAG 2.2 level AA checklist for the planned web and mobile interface, concrete rules for the command-line output you are building now, and a small C++ helper that shows status in words, with colour only as a repeat.

Steps

  1. In lab03/accessibility-checklist.md, list at least 12 WCAG 2.2 success criteria covering all four POUR principles. Include these six added in 2.2: 2.4.11 Focus Not Obscured (Minimum), 2.5.7 Dragging Movements, 2.5.8 Target Size (Minimum), 3.2.6 Consistent Help, 3.3.7 Redundant Entry, 3.3.8 Accessible Authentication (Minimum). Columns: number and name, level, Club Hub screen, how we meet it, how we test it.
  2. Pick two planned screens from your Lab-02 decision (for example event list and registration form). For each, write three design decisions and measure the contrast of your intended text and button colours with a contrast checker; record the ratios (text needs 4.5:1, large text and UI components 3:1).
  3. Write lab03/cli-output-rules.md with at least six rules, each with a bad and a good example: no colour-only meaning; honour NO_COLOR and a --no-color flag; errors say what failed, why, and the next step; non-zero exit code on error; prompts state the expected format; unambiguous dates (2026-10-14 17:30).
  4. Implement include/clubhub/ConsoleOutput.h and src/ConsoleOutput.cpp from the starter (statusLabel, colourEnabled, formatStatus, formatError). If RegistrationStatus already exists in your code, include that header instead of declaring the enum again.
  5. Add tests/ConsoleOutputTest.cpp with at least three tests: the status is readable without colour, the coloured version still contains the word, and an error message contains "Next step:". If your CLI already lists registrations, use formatStatus there; otherwise open a backlog issue for it.
  6. Build and test, then commit: Lab-03 task 4: accessibility review.

Starter code

// include/clubhub/ConsoleOutput.h
// SPDX-License-Identifier: <your licence>
#pragma once

#include <string>
#include <string_view>

namespace clubhub {

// Declare here only if your repository does not define it yet.
enum class RegistrationStatus { Registered, Cancelled, CheckedIn, Waitlisted };

// Upper-case word for a status: "REGISTERED", "CHECKED IN", ...
std::string_view statusLabel(RegistrationStatus s);

// false when the --no-color flag is set or NO_COLOR exists (no-color.org)
bool colourEnabled(bool noColorFlag);

// "[CANCELLED]", wrapped in ANSI colour codes only if colour is true
std::string formatStatus(RegistrationStatus s, bool colour);

// "Error: <what>: <why>.\nNext step: <next>"
std::string formatError(std::string_view what, std::string_view why,
                        std::string_view next);

}  // namespace clubhub
# Accessibility checklist · ITC Club Hub (planned web and mobile UI)
Target: WCAG 2.2 level AA · Version 0.1 · 2026-MM-DD

| SC | Name | Level | Screen | How we meet it | How we test it |
|----|------|-------|--------|----------------|----------------|
| 1.4.1 | Use of Color | A | event list | status badge has text "Full" | view in greyscale |
| 2.5.8 | Target Size (Minimum) | AA | registration form | TODO | TODO |
| TODO | | | | | |

Expected output

rule 1: never colour alone
  bad : E-017  Git Workshop      (shown in red)
  good: E-017  Git Workshop      [CANCELLED]

rule 3: say what failed, why, and the next step
  bad : ERR_CAP
  good: Error: cannot register for E-017: the event is full (40 of 40 seats).
        Next step: clubhub waitlist E-017

$ ctest --test-dir build -R ConsoleOutput
1/3 Test #7: ConsoleOutput.StatusIsReadableWithoutColour .......   Passed    0.01 sec
2/3 Test #8: ConsoleOutput.ColourOnlyRepeatsTheWord ............   Passed    0.01 sec
3/3 Test #9: ConsoleOutput.ErrorSaysWhatWhyAndNextStep .........   Passed    0.01 sec

Show hints

  • The official "How to Meet WCAG (Quick Reference)" page at w3.org lets you filter by level AA and by the 2.2 additions.
  • "How we test it" should be something a teammate can repeat: tab through the page without a mouse, view in greyscale, zoom to 200 %, run a screen reader (NVDA on Windows, TalkBack on Android).
  • std::getenv returns nullptr when the variable does not exist. MSVC warns (C4996) about it; that warning is safe to ignore here.
  • ANSI codes: "\x1b[31m" red, "\x1b[32m" green, "\x1b[0m" reset. The word must be inside the brackets either way.

Acceptance checklist

5

Ethics case analysis and "Record what changed"

Hard 60 min · whole team, one lead per scenario

Goal

Apply the seven-step decision framework from the chapter to two realistic Club Hub situations, turn each conclusion into a preventive engineering change, and record what this lab produced.

Scenario A · "Just a small report"

The Robotics Club leader asks your team to add a report, visible only to club leaders, showing which students attended other clubs' events, "so we can recruit the active ones". The leader is friends with the clubs office and says the administrator "won't mind".

Scenario B · "Don't mention it in the demo"

Two days before the Sprint 1 review, a developer finds that cancellations inside the 24-hour window are accepted, and that the monthly report counts cancelled registrations as attendance. The Scrum Master says: "Don't mention it in the demo, we'll fix it in Sprint 2. The client will never notice."

Steps

  1. Assign one lead per scenario (not the Scrum Master for Scenario B); the others review through pull request comments. Write both analyses in lab03/ethics-cases.md using the template.
  2. For each scenario complete the seven steps: facts (and what you would need to find out), stakeholders and possible harms, at least two cited principles or clauses (SE Code principle number or ACM Code item, plus a GDPR principle where data is involved), at least three options, the tests (harm, rights, fairness, publicity) for each option, the decision and action, and a reflection.
  3. Write the message (at most 120 words) the team would actually send: to the club leader for A, to the Scrum Master and Product Owner for B.
  4. For each scenario define one preventive engineering change (for example a role restriction on reports, a regression test for the 24-hour rule, a "known issues" section in the review template) and open it as a GitHub issue with the label ethics; link the issue numbers in the file.
  5. Record what changed. Create lab03/README.md: a table of every file this lab created or changed (including root files such as LICENSE), the earlier-lab inputs reused with their commit hash (git log -1 --format=%h -- lab01), a change-log row, and open questions for the client.
  6. Push the branch and open the pull request Lab-03 – <team name>; check that every member appears in git shortlog -sn main..lab-03.

Starter

# Ethics case analyses · ITC Club Hub
Version 1.0 · 2026-MM-DD · Leads: A = <name>, B = <name>

## Scenario A: "Just a small report"
| Step | Analysis |
|------|----------|
| 1 Facts | TODO (and what we still need to find out) |
| 2 Stakeholders and harms | TODO |
| 3 Codes, law, policy | SE Code principle TODO; ACM TODO; GDPR TODO |
| 4 Options | (a) TODO (b) TODO (c) TODO |
| 5 Tests | harm / rights / fairness / publicity for each option |
| 6 Decision and action | TODO |
| 7 Reflection | TODO |

**Message sent:** TODO (max. 120 words)
**Preventive change:** TODO, issue #TODO

## Scenario B: "Don't mention it in the demo"
(same table)
# Lab-03 · Record of what changed

| File | Task | Status |
|------|------|--------|
| lab03/data-inventory.md | 1 | new |
| include/clubhub/Student.h | 2 | new |
| LICENSE | 3 | new |
| TODO | | |

## Inputs reused
| Input | File | Version / commit |
|-------|------|------------------|
| Team charter | lab01/TODO | TODO (git log -1 --format=%h -- lab01) |
| Application type | lab02/TODO | TODO |

## Change log
| Date | Change | Author |
|------|--------|--------|
| 2026-MM-DD | Lab-03: inventory, notice, Student, licence, a11y, ethics | team |

## Open questions for the client
- TODO

Expected output

An excerpt of a good Scenario B analysis (steps 4 to 6 only):

StepAnalysis
4 Options(a) stay silent as asked · (b) postpone the whole demo · (c) demo as planned and state the defect and its fix date under "known issues" · (d) fix the rule in the two days and drop another item from the demo
5 Tests(a) fails honesty (SE Code 3 Product, ACM 1.3) and the publicity test: the client would feel deceived when reports turn out wrong. (b) protects nothing extra and wastes the review. (c) and (d) pass; (d) only if the fix and its test fit in the time.
6 Decision(c), and (d) if the regression test is green by Thursday. The developer raises it with the Scrum Master first (SE Code 6.12), then the Product Owner puts it on the review agenda.

Show hints

  • Scenario A: which purpose did students accept when their attendance was recorded? Compare with the purpose-limitation principle and with your own privacy notice from Task 2.
  • Look for the third option: in A, could the club advertise to all students through the normal event list instead of targeting individuals?
  • Scenario B is about honesty toward the client more than about the bug itself. The Scrum Master is a colleague (principle 7): disagree respectfully and in writing.
  • A good preventive change can be tested or checked: "only administrators may run cross-club reports" can become a unit test on the role check.

Acceptance checklist

Challenge: AI feature proposal, recommended events

Hard 90–120 min · optional, extra credit

Scenario

The clubs office asks for a new feature: "Recommended for you", a list of five upcoming events chosen for each student from their attendance history. Before anyone writes code, your team must deliver a proposal that the client can accept or reject: what data it needs, how it could be unfair or opaque, how students can say no, and whether it should be built at all.

Requirements

  1. In lab03/ai-feature-proposal.md, describe the user problem and a non-personalised baseline (for example "popular this week" plus "events of my clubs") that solves part of it without personal data.
  2. List the data needed in a table (field, source, already in the inventory?, new purpose or consent needed?, minimisation applied) and state which Task 1 decisions would change.
  3. Identify at least four bias risks (for example: new students without history, the popularity feedback loop, attendance as a proxy for money, distance or disability, large clubs crowding out small ones), each with a mitigation and a measurable fairness check (for example "share of recommendations going to clubs with fewer than 20 members, compared with their share of events").
  4. Design transparency: the "Why am I seeing this?" text for one example event, and a short description of the ranking inputs that the clubs office could publish.
  5. Design the opt-out (or opt-in, with a justification of the default): where the switch lives, what happens to derived data when a student switches it off, and a Mermaid flowchart of that path.
  6. End with a go / no-go / go-with-conditions recommendation, the conditions, and who would own the fairness check after release.

Skeleton

# AI feature proposal: "Recommended for you"
Version 0.1 · 2026-MM-DD · Authors: <names>

## 1 Problem and non-personalised baseline
## 2 Data needed
| Field | Source | In inventory? | New purpose / consent? | Minimisation |
|-------|--------|---------------|------------------------|--------------|
## 3 Bias risks
| Risk | Who is harmed | Mitigation | Fairness check (metric, threshold) |
|------|---------------|------------|------------------------------------|
## 4 Transparency
"Why am I seeing this?" example: TODO
## 5 Opt-out design
```mermaid
flowchart TD
  A["My profile: Recommendations switch"] --> B{"Switched off?"}
```
## 6 Recommendation
Decision: GO / NO-GO / GO WITH CONDITIONS
Conditions: TODO · Owner of the fairness check: TODO

Expected output

## 6 Recommendation
Decision: GO WITH CONDITIONS, not before Sprint 2, and only after the baseline
has been live for one month.
Conditions:
 1. Opt-in, off by default; switching off deletes the student's derived profile
    within 24 hours.
 2. Uses only attendance of the last 12 months and club memberships; no phone,
    no email, no free-text data.
 3. At least 2 of the 5 slots show events from clubs the student has never
    attended (exploration against the feedback loop).
 4. Monthly exposure check: clubs with fewer than 20 members receive at least
    80 % of their fair share of recommendations; owner: clubs office.

Show hints

  • A simple, explainable rule ("events from clubs whose events you attended twice or more") is also a recommender; you do not need machine learning to have bias.
  • GDPR Art. 22 restricts decisions based solely on automated processing that have legal or similarly significant effects. Event suggestions are usually not that significant, but the transparency principle still applies.
  • "Fair share" can be defined as a club's share of upcoming events; compare it with its share of recommendation slots.
  • A no-go with good reasons and a better alternative is a valid, full-credit answer.

Acceptance checklist

Grading rubric

ComponentPointsFull marks when…
Task 1 · Data inventory15Nine or more fields with every column filled; justified minimisation decisions; copies covered; lifecycle diagram renders.
Task 2 · Notice, consent, retention, Student25Readable notice consistent with the inventory; fair consent flow; retention rule per field; Student stores only inventory fields; six or more meaningful tests pass.
Task 3 · Licence15Justified, unanimous decision; unmodified LICENSE; SPDX headers everywhere; complete third-party notice.
Task 4 · Accessibility review1512+ criteria across POUR with test methods; measured contrast; six CLI rules with examples; ConsoleOutput tested.
Task 5 · Ethics cases and record20Both analyses complete and specific to Club Hub; honest, sendable messages; preventive issues opened; lab03/README.md complete.
Quality and team process10Clean builds without warnings from your own code (MSVC C4996 excepted); dated, versioned documents; every member's work visible in commits or reviews.
★ Challenge (extra credit)+20Baseline, data table, four bias risks with metrics, transparency text, opt-out flow and a reasoned recommendation.
Total100 (+20)
Automatic deductions:
  • −10 if real personal data of any person (not invented) appears anywhere in the repository: fixtures, CSV files, screenshots or logs.
  • −5 per member variable of Student that has no row in the data inventory (consent flags included).
  • −5 if any code or CLI output prints a student's name, email or phone where redacted() should be used.
  • −10 if LICENSE is missing or modified, or the SPDX headers name a different licence.
  • −5 if a status in the CLI rules or the UI checklist is shown by colour alone.
  • −5 per case analysis with fewer than three options.

Submission

  1. Repository layout after this lab (earlier folders unchanged):
    itc-club-hub/
    ├── LICENSE
    ├── THIRD_PARTY_NOTICES.md
    ├── README.md                 # with a Licence section
    ├── CMakeLists.txt
    ├── licenses/googletest-LICENSE.txt
    ├── include/clubhub/Student.h, ConsoleOutput.h
    ├── src/Student.cpp, ConsoleOutput.cpp
    ├── tests/StudentPrivacyTest.cpp, ConsoleOutputTest.cpp
    ├── lab01/  lab02/
    └── lab03/
        ├── README.md
        ├── data-inventory.md
        ├── privacy-notice.md  consent-flow.mmd  retention-rules.md
        ├── licence-decision.md
        ├── accessibility-checklist.md  cli-output-rules.md
        ├── ethics-cases.md
        └── ai-feature-proposal.md    # challenge, optional
  2. Self-check from a clean checkout: the build and all tests must pass, and the other three outputs must match the comments:
    cmake -S . -B build && cmake --build build && ctest --test-dir build
    git ls-files 'include/*' 'src/*' 'tests/*' | xargs grep -L "SPDX-License-Identifier"   # nothing
    git grep -nE "(name|email|phone)\(\)" -- src/ ':!src/Student.cpp'                        # review: no hit logs or prints
    git shortlog -sn main..lab-03                                                           # every member
  3. Work on the branch lab-03 and open a pull request titled Lab-03 – <team name>. At least one member other than the author approves it; the teaching assistant reviews the pull request, not a zip file.