Run Change C through your track

Day 3: Choose your adventure · Exercise 2 of 3 · 55 min

By the end you will have driven one brief through your framework's own artifacts, commands and implementation, and graded the result with an acceptance suite it never saw.

This continues Exercise 1's day3-work. Starting here? Run the setup block, then your track's install-and-init steps there.

Setup

Quit Claude Code and paste one block from the course root (cd .. first if you are in the copy). It keeps an existing day3-work, adds the brief and the cycle fixture, and leaves you inside it, where every later command runs.

Swift lane
mkdir -p work
{ [ -d day3-work ] || cp -R sandbox/swift day3-work; } && cd day3-work
cp ../day-3-choose-your-adventure/starter/change-c-brief.md .
cp ../day-3-choose-your-adventure/starter/fixtures/cycle-config.tsv Tests/LedgerKitTests/Fixtures/
{ [ -f ../work/map.md ] || cp ../day-3-choose-your-adventure/starter/map-template.md ../work/map.md; }
ls change-c-brief.md Tests/LedgerKitTests/Fixtures/

The fixtures folder lists cycle-config.tsv.

Kotlin lane
mkdir -p work
{ [ -d day3-work ] || cp -R sandbox/kotlin day3-work; } && cd day3-work
cp ../day-3-choose-your-adventure/starter/change-c-brief.md .
cp ../day-3-choose-your-adventure/starter/fixtures/cycle-config.tsv src/test/resources/
{ [ -f ../work/map.md ] || cp ../day-3-choose-your-adventure/starter/map-template.md ../work/map.md; }
ls change-c-brief.md src/test/resources/

src/test/resources/ lists cycle-config.tsv.

Start claude there, with a second terminal tab for shell commands. In default mode Claude Code asks before each edit and command; approving is not steering.

The brief pins the type names and entry point, so a test against them compiles, and nothing else: no acceptance criteria, two unmarked ambiguities.

Note the time: 25 minutes to the checkpoint in step 6, reading the brief included; then implementing takes about 10 on OpenSpec, 17 on LID and 20 on BMAD, whose build reviews its diff with three subagents; then 8 to grade. That is 43, 50 or 53 of the 55; the rest is reading this page and its reveals.

Steps

  1. Read the brief before typing anything. In ../work/ambiguities.md, list every place two reasonable engineers would build different things.

  2. Confirm the suite is green, as in Exercise 1.

    Swift lane
    swift test
    Test Suite 'All tests' passed at ….
    	 Executed 34 tests, with 1 test skipped and 0 failures (0 unexpected) in … (…) seconds
    Kotlin lane
    ./gradlew test
    BUILD SUCCESSFUL in …

    Gradle prints no count; read it from the report:

    cat build/test-results/test/TEST-*.xml | grep -c '<testcase '
    grep -o 'skipped="[0-9]*"' build/test-results/test/TEST-ledgerkit.KnownIssueTest.xml

    It prints 85, then skipped="1".

  3. Start planning with your tab's prompt, pasted whole: whether the framework reads the file is part of the test.

  4. When the planning output appears (some commands, /opsx:propose among them, write several files at once), mark each item on your list: asked, recorded as an open question, or silently chosen; the third is what matters. Then send:

    Do not change any code yet. List every behaviour in the brief that you had to decide without the brief telling you, one line each, with the decision you made and the file where that decision is now written down. If a decision is only in this conversation and not in a file, say so explicitly for that line.
  5. Resolve each ambiguity in the framework's own artifact (your tab names it), not in chat: /clear empties the conversation, and a decision kept there goes with it. Then send:

    I have written my decisions into <the file your tab names>. Re-read it from disk, treat those open questions as closed, and continue to your next step without changing them. Do not write any code yet.
  6. Checkpoint at 25 minutes. If planning is unfinished, quit Claude Code, copy in your track's reference planning artifacts (made by its workflow on the build machine) with your tab's lines, restart claude, and continue at step 7. Taking it is not failing.

  7. Run your tab's implementation prompt. Do not hand-edit source while it runs.

  8. Run your lane's suite. If anything is red, send your tab's repair prompt with the failing output in place of <paste>, and re-run until green. The count now includes your framework's own tests: it is grading itself.

    Swift lane
    swift test
    Kotlin lane
    ./gradlew test
  9. Copy in the acceptance suite, outside day3-work until now and the same for every track, then run the self-check.

    Swift lane
    cp ../day-3-choose-your-adventure/starter/acceptance/ChangeCAcceptanceTests.swift Tests/LedgerKitTests/
    ls Tests/LedgerKitTests/
    Kotlin lane
    cp ../day-3-choose-your-adventure/starter/acceptance/ChangeCAcceptanceTest.kt src/test/kotlin/
    ls src/test/kotlin/
  10. Check the bounds: the known-issue run, then a diff against the shipped lane. Below, the reference implementation stands in.

    Swift lane
    LEDGER_RUN_KNOWN_ISSUES=1 swift test
    diff -rq -x .build -x build -x .gradle -x .kotlin ../sandbox/swift .

    Known-issue run:

    …/Tests/LedgerKitTests/KnownIssueTests.swift:35: error: -[LedgerKitTests.KnownIssueTests testLEDGER7_JPYRendersWithTwoDecimalPlaces] : XCTAssertEqual failed: ("-¥1,280.00") is not equal to ("-¥128,000") - LEDGER-7: LK-014 (JPY) rendered the wrong amount.
      expected: -¥128,000
      actual:   -¥1,280.00
    …
    	 Executed … tests, with 1 failure (0 unexpected) in … (…) seconds

    Diff:

    Only in ./Sources/LedgerKit: StatementPeriods.swift
    Only in ./Tests/LedgerKitTests: ChangeCAcceptanceTests.swift
    Only in ./Tests/LedgerKitTests/Fixtures: cycle-config.tsv
    Only in .: change-c-brief.md
    Kotlin lane
    LEDGER_RUN_KNOWN_ISSUES=1 ./gradlew test
    diff -rq -x .build -x build -x .gradle -x .kotlin ../sandbox/kotlin .

    Known-issue run:

    KnownIssueTest > LEDGER-7 the JPY row renders with decimal places it should not have() FAILED
        org.opentest4j.AssertionFailedError: … ==> expected: <-¥128,000> but was: <-¥1,280.00>
    …
    … tests completed, 1 failed
    …
    BUILD FAILED in …

    Diff:

    Only in .: change-c-brief.md
    Only in ./src/main/kotlin/ledgerkit: StatementPeriods.kt
    Only in ./src/test/kotlin: ChangeCAcceptanceTest.kt
    Only in ./src/test/resources: cycle-config.tsv

    One failure, the JPY case. Read the diff as in Exercise 1: every line must be in your source or test folders, the brief, or your map's list, and no differ line may name Money or LedgerFilter. Your diff will be longer than the four lines above: your track adds its own folders (on OpenSpec, openspec/ and .claude/) and its own test file; those are in your map's list.

  11. Under ## Change C notes in ../work/map.md, write three lines: which ambiguity your framework caught, which one it chose without asking, and which file the resolution ended up in.

Your track

OpenSpec: plan (step 3)

/opsx:propose Statement periods for LedgerKit. The full brief is in change-c-brief.md in this project folder — read that file, do not work from this sentence. Produce the proposal and the delta specs for this change, plus whatever design note and task list your workflow normally produces. Do not write implementation code in this step. Where the brief leaves a behaviour genuinely undetermined, do not ask me before creating the change or choose for me: record it under a heading "Open questions", still write the design note and task list, mark each task that depends on an open question blocked, and stop. Keep every code change inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane, or src/main/kotlin/ and src/test/kotlin/ on the Kotlin lane.

/opsx:propose writes every artifact under openspec/changes/ and stops on the open questions.

Where a decision lives (step 5)

In the delta spec: a ### Requirement: under ## ADDED Requirements, pinned by a #### Scenario:. The build run also recorded each decision in proposal.md, but the delta spec is the copy /opsx:apply implements. Validate by the name openspec list shows:

openspec list
openspec validate <name>

On the build machine (1.13.1, 2026-09-22): Change 'add-statement-periods' is valid.

Checkpoint (step 6)

Move any change of your own out first:

mv openspec/changes/<your-change> ../work/
cp -R ../day-3-choose-your-adventure/starter/checkpoints/openspec/changes/. openspec/changes/
Kotlin lane

Its tasks and design assume Swift; paste this under # Tasks in openspec/changes/add-statement-periods/tasks.md:

Kotlin lane: this checkout is the Kotlin lane, and this line overrides every Swift path and command in these tasks and in design.md. Code goes in src/main/kotlin/ledgerkit/, tests in src/test/kotlin/, fixtures in src/test/resources/, and ./gradlew test replaces swift build and swift test.

Implement (step 7)

Send /opsx:apply with the change name openspec list shows (after the checkpoint, add-statement-periods) and your bounds:

/opsx:apply <name> Work this change's task list. Implement only what the delta specs describe. Stay inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane, or src/main/kotlin/ and src/test/kotlin/ on the Kotlin lane, and stop when the task list is complete. Do not use git in this folder: where a task runs git, run diff -rq -x .build -x build -x .gradle -x .kotlin ../sandbox/swift . (on the Kotlin lane, ../sandbox/kotlin) instead.

Repair (step 8)

/opsx:apply again, then:

The test suite is red. Here is the failing output, verbatim: <paste>. Fix it by working the task list and the delta specs — if the delta spec is what is wrong, change the delta spec first and then the code. Do not edit the tests to make them pass.
What OpenSpec produced on the build run: the proposal and the delta spec

OpenSpec 1.13.1, 2026-09-22, in a fresh copy of the Swift lane, handed the planning prompt above. The full folder is ../day-3-choose-your-adventure/starter/checkpoints/openspec/.

openspec/changes/add-statement-periods/proposal.md
openspec/changes/add-statement-periods/design.md
openspec/changes/add-statement-periods/tasks.md
openspec/changes/add-statement-periods/.openspec.yaml
openspec/changes/add-statement-periods/specs/statement-cycle/spec.md
openspec/changes/add-statement-periods/specs/statement-periods/spec.md

It stopped on four open questions with the dependent tasks blocked. After the answers were folded back in, the proposal's last section reads, headings only:

## Decisions on what the brief left open
### OQ-1. Placement date: the posted date
### OQ-2. Short months: clamp the start day to the month's last day
### OQ-3. Rule combination: single rule only
### OQ-4. Malformed table rows: skip the row

The first requirement of specs/statement-periods/spec.md, with its first scenario:

### Requirement: A transaction is placed by its posted date
The date that decides which period a transaction belongs to SHALL be the UTC
calendar date of its `postedAt`, the same date the existing day grouping uses.
The authorized date SHALL never decide membership. This applies to every
status: a pending or declined transaction is placed by its `postedAt` like any
other.

#### Scenario: Fixture row LK-015 is placed by its posted date
- **WHEN** the twenty transactions of `transactions.tsv` are grouped with the
  `standard` cycle from the shipped cycle table
- **THEN** `LK-015` (authorized `2026-03-04`, posted `2026-03-05`) is in the
  period starting `2026-03-05` and ending `2026-04-04`, not in the period
  ending `2026-03-04`

LID: plan (step 3)

Describe the change: the ## LID block Exercise 1 added to CLAUDE.md sends it down the arrow through the linked-intent-dev skill (/linked-intent-dev:update-lid is for drift and mode changes). Paste as an ordinary message:

Statement periods for LedgerKit. The full brief is in change-c-brief.md in this project folder — read that file, do not work from this message. This module already has a design tree from Exercise 1, so extend it rather than proposing a new architecture. Give the new EARS requirements the prefix LK-PERIOD. Stop for my review at the end of each phase. Where the brief leaves a behaviour genuinely undetermined, raise it rather than choosing for me.

The skill stops for approval after each phase: high-level design, low-level design, EARS requirements, edge audit, tests. Read each, then send:

Approved. Continue to the next phase.

Where a decision lives (step 5)

Before requirements exist, in the leaf's design doc under Decisions & Alternatives; after, in the LK-PERIOD requirement it cascades to (docs/intent/<segment>/<segment>-specs.md), one EARS sentence per decision.

Checkpoint (step 6)

Move any leaf of your own out first, and delete any LK-PERIOD segment it added to docs/arrows/index.yaml:

mv docs/intent/<your-leaf> ../work/
cp -R ../day-3-choose-your-adventure/starter/checkpoints/lid/docs/intent/statement-period docs/intent/

Then copy in the arrow doc and make by hand the three edits ../day-3-choose-your-adventure/starter/checkpoints/lid/CHECKPOINT.md lists, in docs/arrows/index.yaml, docs/high-level-design.md and CLAUDE.md, which a copy would overwrite. The overlay snippet comes in both shapes an index.yaml can have; match yours.

Implement (step 7)

At the stop before tests (after the checkpoint, as your first message), send:

Continue down the arrow: write the tests for the LK-PERIOD requirements first, then the code, and annotate each with // @spec and its requirement ID on the topmost function that owns the behaviour. Keep code and tests inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane; on the Kotlin lane, in src/main/kotlin/ledgerkit/ and src/test/kotlin/, in place of any Swift file the design names. Do not change any requirement to match code you have already written — if the code cannot satisfy a requirement, stop and tell me which one.

Each annotation is // @spec and comma-separated IDs, each a design-tree path plus a number. List them:

Swift lane
grep -rn '@spec LK-PERIOD' Sources Tests
Kotlin lane
grep -rn '@spec LK-PERIOD' src

Repair (step 8)

The test suite is red. Here is the failing output, verbatim: <paste>. Decide first whether the failure means the code is wrong or the requirement is wrong. If the requirement is wrong, fix the low-level design and cascade downstream; if the code is wrong, fix the code and leave the requirement alone. Tell me which of the two you concluded and which artifact you changed. Do not edit the tests to make them pass.
What LID produced on the build run: the design addition and the LK-PERIOD block

LID at commit 831c1959, 2026-09-22, in a fresh copy of the Swift lane with the design tree already mapped. That run could not stop for a person at its phase boundaries, so it was handed the planning prompt plus the answers to the two ambiguities up front. It was started as /linked-intent-dev:update-lid with the prompt as its argument; the plain-message start this tab uses was not run on the build machine, so your run is the first observation of it. This is what it produced, not a fixed file list; the files are in ../day-3-choose-your-adventure/starter/checkpoints/lid/.

docs/high-level-design.md                                  the new leaf added to the high-level design
docs/intent/statement-period/statement-period-design.md   the low-level design addition
docs/intent/statement-period/statement-period-specs.md    22 EARS requirements, LK-PERIOD-001..022
docs/arrows/index.yaml                                     a new LK-PERIOD segment
CLAUDE.md                                                  PERIOD added to the leaf list

The design doc's sections run Purpose, Scope, Design, Interfaces, Decisions & Alternatives, Open Questions & Future Decisions, and Verification. Two of the requirements:

**LK-PERIOD-008** When a calendar month has fewer days than the cycle's
start day, the statement-period grouping shall open that month's period on
the last day of that month, and shall leave every other month's opening
day unchanged (a start day of 31 opens the February 2026 period on
2026-02-28 and the March 2026 period on 2026-03-31).
Verified by: (no test yet).

**LK-PERIOD-013** The statement-period grouping shall place each
transaction in the period whose `start` and `end` days, both inclusive,
contain the transaction's `postedDay` (the UTC calendar day of
`postedAt`), and shall never use `authorizedDay` to decide membership
(fixture row `LK-015`, authorized 2026-03-04 and posted 2026-03-05,
belongs on a start-day-5 cycle to the period that opens on 2026-03-05).
Verified by: (no test yet).

Every requirement reads (no test yet): the arrow had reached requirements and not tests. The run also reported three sibling documents from the mapping as stale rather than editing them, because a sibling is not downstream on the arrow.

BMAD: plan (step 3)

/bmad-build Statement periods for LedgerKit. The full brief is in change-c-brief.md in this project folder — read that file, do not work from this sentence. Ask your clarifying questions before you plan, and show me the plan for approval before you implement anything. Where the brief leaves a behaviour genuinely undetermined, ask rather than choosing for me. Keep every code change inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane, or src/main/kotlin/ and src/test/kotlin/ on the Kotlin lane.

/bmad-build opens with a uv run command naming _bmad/scripts/render_skill.py: approve it. Without uv, or with that command refused, it halts.

Where a decision lives (step 5)

In the spec /bmad-build writes under _bmad-output/implementation-artifacts/: by its step-01 text one spec-<slug>.md; on the build machine, statement-periods/SPEC.md. Answer its Open Questions there, as decisions inside its <frozen-after-approval> block.

Checkpoint (step 6)

Move any spec of your own out first. cp -R into a missing folder renames the copy, so mkdir comes first:

mv _bmad-output/implementation-artifacts/<your spec file or folder> ../work/
mkdir -p _bmad-output/implementation-artifacts
cp -R ../day-3-choose-your-adventure/starter/checkpoints/bmad/statement-periods _bmad-output/implementation-artifacts/
Kotlin lane

The implementing subagent reads only the spec, so in the frozen block of statement-periods/SPEC.md cut or a Kotlin lane and its parenthesis from Never: and add under Always:

- This repository is the Kotlin lane, and this line overrides every Swift name, path and command in this spec: use the brief's Kotlin block, code in src/main/kotlin/ledgerkit/, tests in src/test/kotlin/, fixtures in src/test/resources/, and run ./gradlew test.

Implement (step 7)

After reviewing its plan:

Approved — build the plan you just showed me. Implement only what the spec describes, keep every change inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane, or src/main/kotlin/ and src/test/kotlin/ on the Kotlin lane, and stop when the spec's status reaches done. Do not use git in this folder: wherever your workflow needs a diff, use the output of diff -ruN -x .build -x build -x .gradle -x .kotlin -x _bmad -x _bmad-output -x .claude ../sandbox/swift . (on the Kotlin lane, ../sandbox/kotlin) as the provided diff, and do not commit.

After the checkpoint, hand /bmad-build the spec; at ready-for-dev it goes straight to implementation:

/bmad-build _bmad-output/implementation-artifacts/statement-periods/SPEC.md Implement this spec. Implement only what the spec describes, keep every change inside Sources/LedgerKit/ and Tests/LedgerKitTests/ on the Swift lane, or src/main/kotlin/ and src/test/kotlin/ on the Kotlin lane, and stop when the spec's status reaches done. Do not use git in this folder: wherever your workflow needs a diff, use the output of diff -ruN -x .build -x build -x .gradle -x .kotlin -x _bmad -x _bmad-output -x .claude ../sandbox/swift . (on the Kotlin lane, ../sandbox/kotlin) as the provided diff, and do not commit.

No git: in a clone of the course, git reports on the whole course.

Repair (step 8)

BMAD's phase-4 chain runs bmad-sprint-planning, bmad-build, bmad-code-review; your repair prompt re-enters it at the review.

The test suite is red. Here is the failing output, verbatim: <paste>. Re-enter at bmad-code-review for the spec or story that owns this behaviour, then bmad-build to apply the fix. Do not edit the tests to make them pass, and tell me which one you reopened. Do not use git in this folder: wherever your workflow needs a diff, use the output of diff -ruN -x .build -x build -x .gradle -x .kotlin -x _bmad -x _bmad-output -x .claude ../sandbox/swift . (on the Kotlin lane, ../sandbox/kotlin) as the provided diff, and do not commit.
What BMAD produced on the build run: SPEC.md and stories.yaml

BMAD 6.12.0, 2026-09-22, in a fresh copy of the Swift lane, handed the planning prompt above and told to halt after planning. That run could not answer in conversation, so it wrote its five clarifying questions into the spec; the answers were then folded in by a second pass. This is what it produced, not a fixed file list; the folder is ../day-3-choose-your-adventure/starter/checkpoints/bmad/.

_bmad-output/implementation-artifacts/statement-periods/SPEC.md
_bmad-output/implementation-artifacts/statement-periods/stories.yaml
_bmad-output/implementation-artifacts/statement-periods/stories/1-parse-cycle-configuration.md
_bmad-output/implementation-artifacts/statement-periods/stories/2-group-into-statement-periods.md

The frontmatter of SPEC.md, which goes on to a frozen decision block, a 25-row edge-case matrix, tasks and acceptance criteria:

---
title: 'Statement periods'
type: 'feature'
created: '2026-09-22'
status: 'ready-for-dev'
route: 'dispatch'
review_loop_iteration: 0
context:
  - '{project-root}/change-c-brief.md'
---

stories.yaml, whole:

# Story set for SPEC.md (statement periods). Execution order is list order.
# The five planning questions were answered on 2026-09-22; the decisions live
# under "Decided" in the SPEC.md frozen block. Both stories are unblocked.
- id: "1"
  title: Parse a cycle configuration from TSV
  description: >-
    Add CycleRule and StatementCycle with parse(tsv:named:) as fixed in
    change-c-brief.md, covering every "parse" row of the SPEC.md matrix. A
    malformed row is skipped; nil only when no usable row carries the name.
  spec_checkpoint: true
  invoke_dev_with: >-
    Read the Decided list in the SPEC.md frozen block first; the frozen block
    is locked and settles every parse row. Hand-rolled parsing only.
- id: "2"
  title: Group transactions into statement periods
  description: >-
    Add StatementPeriod and StatementPeriods.periods(for:cycle:), placing by
    posted day, newest period first, contiguous, empty middle periods
    included, short months clamped, one governing rule per list, covering
    every grouping row of the SPEC.md matrix. Depends on story 1.
  spec_checkpoint: true
  invoke_dev_with: >-
    Read the Decided list in the SPEC.md frozen block first; membership is by
    posted day, a missing start day clamps to the month's last day, and one
    rule governs the whole list. Reuse UTCDay and ISO8601.daysSinceEpoch from
    Transaction.swift for all date arithmetic.

If you see something else instead

Likely wrong turns

Self-check

The acceptance suite decides it

Run it after step 9 and any repair.

Swift lane
swift test 2>&1 | grep -A1 -e "Test Suite 'ChangeCAcceptanceTests' [pf]" -e "Test Suite 'All tests' [pf]"

With the reference implementation in place it printed:

Test Suite 'ChangeCAcceptanceTests' passed at ….
	 Executed 6 tests, with 0 failures (0 unexpected) in … (…) seconds
--
Test Suite 'All tests' passed at ….
	 Executed … tests, with 1 test skipped and 0 failures (0 unexpected) in … (…) seconds

Pass is both suites passed. failed on either is a red test; no output means no compile.

Kotlin lane
./gradlew test
grep -o 'tests="[0-9]*" skipped="[0-9]*" failures="[0-9]*" errors="[0-9]*"' build/test-results/test/TEST-ledgerkit.ChangeCAcceptanceTest.xml

With the reference implementation in place the grep printed:

tests="6" skipped="0" failures="0" errors="0"

Pass is BUILD SUCCESSFUL in … from the first command and exactly that line from the second. After BUILD FAILED with e: lines, the report is left over from an earlier run.

Done when: the six acceptance tests pass in a green suite, the known-issue run fails on JPY alone, the diff shows nothing out of bounds, decisions live in artifacts, and your three lines sit under ## Change C notes in ../work/map.md.

Reference answers

The two deliberate ambiguities, and which track surfaced them on the build run

First: whether a transaction belongs to a period by its authorized date or its posted date. The brief says the two are often different days and never says which one counts. Fixture row LK-015, authorized 2026-03-04 and posted 2026-03-05, lands in different periods under the standard cycle depending on the answer. testAuthorizedVsPostedMembership holds one reading.

Second: what a cycle that starts on day 31 does in February. The brief allows any start day from the 1st to the 31st, and the cycle table your setup copied in carries a month-end configuration on the 31st. testFebruaryCycleStart holds one reading.

On the build machine on 2026-09-22, one run per track: OpenSpec found both unprompted, recorded them as blocking open questions without recommending an answer, named LK-015 and the month-end configuration as its evidence, and refused to implement. BMAD found both among five clarifying questions, each with options and a recommendation. LID was handed both answers in its prompt because that run could not stop for a person, so it turned them into requirements rather than questions, and its finding of them is the least independently shown of the three. None of the three chose silently. That is one observation on one machine on one date, not a property of the frameworks: your run is the evidence for your card in Exercise 3.

Reset

Quit Claude Code, then from inside day3-work run your lane's line. It replaces the copy with a fresh one and leaves you inside it; sandbox/ and ../work/ are untouched.

Swift lane
cd .. && rm -rf day3-work && cp -R sandbox/swift day3-work && cd day3-work
Kotlin lane
cd .. && rm -rf day3-work && cp -R sandbox/kotlin day3-work && cd day3-work

Then paste this page's setup lines after cd day3-work and redo your track's install-and-init steps from Exercise 1. OpenSpec on your PATH and the LID plugins at user scope survive; BMAD lives in the project, so rerun its installer. Do not reset at the end: Exercise 3 continues in this day3-work.

Sources