Skip to content

Latest commit

 

History

History
145 lines (120 loc) · 6.54 KB

File metadata and controls

145 lines (120 loc) · 6.54 KB

SPEC.md — Alarm Clock CLI

Status: Approved for implementation Version: 1.0 This spec is the source of truth. Every requirement below has an ID. Every ID must be traceable to an implementation location and a test — see TRACEABILITY.md. If code exists that isn't traceable to an ID here, that's scope creep and should be cut or the spec should be updated first.

1. Problem statement

Build a CLI alarm clock. No web UI, no database. Time-boxed exercise, no detailed spec was provided by the requester — so this document is the spec, written first, before implementation, to remove ambiguity and give a fixed target to build and test against.

2. Actors

  • User: a person operating the tool from a terminal.

3. Functional requirements

Each requirement has a unique ID, a description, and acceptance criteria in Given/When/Then form. Acceptance criteria are what the tests in tests/test_alarmclock.py are written against — not vibes.

FR-1: Create an alarm

The user can create an alarm with a time, an optional label, and a repeat mode.

  • FR-1.1 — Given a time in 24-hour HH:MM format, when the user adds an alarm, then it is persisted with that time, zero-padded (e.g. 7:507:05).
  • FR-1.2 — Given a time outside valid ranges (hour > 23, minute > 59) or a non-time string, when the user attempts to add it, then the system rejects it with a clear error and does not persist it.
  • FR-1.3 — Given no --repeat flag, when an alarm is created, then it defaults to once.
  • FR-1.4 — Given --repeat is provided, it must be either once or daily; any other value is rejected.
  • FR-1.5 — Given a label is omitted, the alarm is stored with an empty label (not an error).
  • FR-1.6 — Given a once alarm whose time has already passed today, when it is created, then the system accepts it (it will fire at that time tomorrow) and prints an informational note — this is not an error condition.

FR-2: List alarms

The user can view all alarms currently stored.

  • FR-2.1 — Given zero alarms exist, when the user lists them, then a "no alarms" message is shown (not an empty table, not an error).
  • FR-2.2 — Given one or more alarms exist, when listed, then each row shows: id, time, repeat mode, enabled/disabled status, and label.
  • FR-2.3 — Alarms are listed sorted by time, ascending.

FR-3: Remove an alarm

The user can delete an alarm by its id.

  • FR-3.1 — Given a valid existing id, when removed, then it no longer appears in subsequent list calls.
  • FR-3.2 — Given an id that does not exist, when removal is attempted, then the system reports an error and exits non-zero, without modifying the store.

FR-4: Run the clock (watch loop)

The user can start a foreground process that watches for due alarms and rings them.

  • FR-4.1 — Given the current time matches an enabled alarm's time (same HH:MM), when the watch loop polls, then that alarm fires.
  • FR-4.2 — Given an alarm has already fired once on the current calendar date, when the loop polls again within that same date, then it must not fire again (prevents re-firing every poll cycle within the same matching minute).
  • FR-4.3 — Given an alarm's repeat is daily, when it fires and is dismissed, then it remains enabled and will fire again on the next matching date.
  • FR-4.4 — Given an alarm's repeat is once, when it fires and is dismissed, then it is disabled (will not fire again).
  • FR-4.5 — Given a disabled alarm, when the loop polls, then it is never considered due, regardless of time match.
  • FR-4.6 — When the loop is interrupted with Ctrl+C, the process exits cleanly with a message, not a stack trace.

FR-5: Ring interaction (snooze / dismiss)

When an alarm fires, the user must be able to dismiss or snooze it.

  • FR-5.1 — On firing, the system plays an audible/visual alert (bell + banner) and prompts for input.
  • FR-5.2 — Given the user presses Enter (or types d/dismiss), the alarm is dismissed: FR-4.3/FR-4.4 apply.
  • FR-5.3 — Given the user types s/snooze, the alarm is rescheduled to fire again in 5 minutes, remains enabled, and is treated as a fresh one-shot fire (not double-counted against the original schedule).
  • FR-5.4 — Given unrecognized input, the system reprompts rather than crashing or silently dismissing.
  • FR-5.5 — Given stdin is closed/unavailable mid-prompt (EOF), the system treats this as a safe auto-dismiss rather than crashing the process.

4. Non-functional requirements

  • NFR-1 (No external runtime dependencies) — the tool must run using only the Python standard library. Rationale: this is a timed exercise and a portable deliverable; audio/scheduling libraries add platform-specific install failure modes that aren't worth the risk.
  • NFR-2 (No database) — explicitly excluded by the assignment. Persistence is a flat JSON file.
  • NFR-3 (Crash safety of persisted state) — a corrupted or half-written store file must not crash the CLI; it should be treated as empty rather than raising an unhandled exception.
  • NFR-4 (Atomic writes) — writes to the store must not leave a partially-written file if interrupted mid-write.
  • NFR-5 (Testability) — every FR above must have at least one corresponding automated test. See TRACEABILITY.md.

5. Explicitly out of scope

Documented here rather than silently dropped, so scope decisions are visible and defensible:

  • OS-1: Timezone handling — local system time only.
  • OS-2: Weekday-specific repeat patterns (e.g. weekdays-only). Only once and daily per FR-1.4.
  • OS-3: Custom/audio-file sounds — terminal bell only, per NFR-1.
  • OS-4: Background/daemon mode (systemd, nohup, etc.) — run is a foreground blocking process by design; backgrounding it is an OS-level concern outside this tool.
  • OS-5: Simultaneous ringing of multiple due alarms — they ring sequentially in the order encountered, not concurrently.

6. Definition of done

A requirement is "done" when:

  1. Implementation exists that satisfies its acceptance criteria.
  2. An automated test exists exercising that acceptance criteria and passes.
  3. It is listed in TRACEABILITY.md with links to both.

This spec is deliberately written before PLAN.md and before any implementation code, and is not edited retroactively to match whatever got built — if implementation reveals the spec was wrong, the spec is updated explicitly and that update is called out, not silently absorbed.