You will implement the harness and run the participant watcher loop three times, observing all three exit states the loop is capable of producing.
The instructor runs a separate mutator loop that updates three fake Artificial Intelligence (AI) provider pricing pages on a public URL every 3 minutes. Your watcher reads those pages, diffs them against your local catalogue, and halts for your approval before writing any update.
-
Node.js 18 or later. Verify on the command prompt of your local Windows machine:
node --versionOn macOS or Linux, run the same command in a terminal.
-
Git installed and configured:
git --version
nightbuild3-exercise/
├── providers.json ← your local pricing catalogue (starts intentionally stale)
├── watcher/
│ └── watcher.js ← the participant loop implementation
├── HARNESS.md ← harness spec — read before running anything
├── LOOP.md ← loop spec — read before running anything
├── DIFF.md ← written by the watcher when changes are detected
├── RUN_LOG.md ← append-only run history
└── APPROVAL.md.template ← copy this to create APPROVAL.md
On the command prompt of your local Windows machine:
git clone https://github.com/mugdhav/nightbuild3-exercise.git
cd nightbuild3-exercise
On macOS or Linux, run the same commands in a terminal.
Open HARNESS.md and LOOP.md before running anything.
HARNESS.md defines which files the agent reads and writes in each phase,
the schema-projection contract (the 7 fields extracted per provider page),
the three verification gates, and the two human gates where the loop halts.
LOOP.md defines the five exit states, the full iteration structure from
fetch through report through update, and the retry policy per failure type.
The watcher in watcher/watcher.js is a direct implementation of those
specs. Trace each action in the terminal output back to the relevant
section of the spec as you run the steps below.
Wait for the instructor's signal that State 0 (baseline) is live. Then verify on the command prompt of your local Windows machine:
curl https://www.vmugdha.in/nightbuild/prices/synthai.json
On macOS or Linux:
curl https://www.vmugdha.in/nightbuild/prices/synthai.json
Expected output: a JSON object containing "provider": "SynthAI" and
"_state": 0. If the request fails or _state is not 0, notify the
instructor before continuing.
Wait for the instructor's signal that State 1 has been pushed. Then start the watcher on a 3-minute schedule.
On the command prompt of your local Windows machine:
node watcher/watcher.js --schedule
On macOS or Linux:
node watcher/watcher.js --schedule
Leave this terminal open. The watcher runs immediately, then every 3 minutes.
The watcher fetches all three provider pages, projects the schema fields,
and diffs the result against providers.json.
Expected terminal output:
Phase 1: Fetching provider pages...
Phase 2: Diffing against catalogue...
Phase 3: Writing DIFF.md (2 change(s), 1 warning(s))...
[DIFF.md written] 2 change(s), 1 warning(s)
[ACTION REQUIRED] Write APPROVAL.md, then re-run the watcher.
Open DIFF.md. Before proceeding, verify all three of the following:
SynthAI / Developer / price_amountis classified asPRICE_CHANGE. The catalogue holds20.00; the page now returns25.00.OrbitalAI / Pro / feature_flagsis classified asBENEFIT_CHANGE.fine_tuningwas removed andvisionwas added.VectronAI / Base / price_amountappears under Extraction warnings, not under Changes. The page returnednullfor this field. The harness treats a field going null as a potential scrape failure, not a confirmed pricing change, so it logs the warning and does not block on approval.
The loop has halted at the first human gate defined in HARNESS.md.
Copy APPROVAL.md.template to APPROVAL.md.
On the command prompt of your local Windows machine:
copy APPROVAL.md.template APPROVAL.md
On macOS or Linux:
cp APPROVAL.md.template APPROVAL.md
Open APPROVAL.md in any text editor and fill in:
RUN_ID: copy the value exactly from the top ofDIFF.md. Format:YYYY-MM-DD-HH:MM.REVIEWED_BY: your name or any identifier.REVIEWED_AT: current date and time in ISO 8601 format. Example:2025-07-04T09:30:00Z.
Set STATUS: APPROVED and save the file. The completed file:
RUN_ID: 2025-07-04-09:25
STATUS: APPROVED
REASON: Verified SynthAI price increase and OrbitalAI feature swap
REVIEWED_BY: your-name
REVIEWED_AT: 2025-07-04T09:30:00Z
The watcher validates this file strictly. A missing RUN_ID or STATUS
exits with ERROR rather than proceeding.
On its next 3-minute tick, the watcher detects PENDING_APPROVAL in
RUN_LOG.md, reads APPROVAL.md, and runs Gate 3 from HARNESS.md:
APPROVAL.mdexists and containsSTATUS: APPROVED.- The
RUN_IDinAPPROVAL.mdmatches the pending run. - The approved diff has not already been applied.
Expected terminal output:
[STATE] Prior run <id> is PENDING_APPROVAL.
[APPROVAL] Approved. Loading last diff for update...
[providers.json updated]
[APPROVAL.md deleted — consumed]
Open providers.json and verify:
SynthAI / Developer / price_amountis25.00.OrbitalAI / Pro / feature_flagscontainsvision, notfine_tuning.VectronAI / Base / price_amountis still12.00. The extraction warning was not applied as a diff.
APPROVAL.md has been deleted. A consumed approval cannot be replayed.
On the next tick, one of two things happens depending on whether the instructor has pushed State 2.
State 2 not yet live: the watcher finds no classified diffs against
the now-updated providers.json and exits NO_DIFF.
State 2 live: the watcher finds a second set of changes and exits
PENDING_APPROVAL. DIFF.md is overwritten with the new report.
Repeat Steps 5 and 6 to approve and apply.
Read RUN_LOG.md after Run 3. A complete three-run session shows:
... | PENDING_APPROVAL | providers_checked=3 | diffs=2 | warnings=1
... | UPDATED | applied_from_approval=true
... | NO_DIFF | providers_checked=3 | diffs=0 | warnings=1
Press Ctrl+C in the terminal running --schedule.
Read the Honest limitations section in HARNESS.md and the What
this loop does not handle section in LOOP.md. These are intentional
exclusions. For each one, identify what additional component it would
require and where in the iteration structure it would be inserted.
Trigger ERROR. Set one pricing_url in providers.json to an
invalid URL and run a single tick:
node watcher/watcher.js
Read the error in RUN_LOG.md, then restore the correct URL.
Trigger ID_MISMATCH. Write APPROVAL.md with a RUN_ID that does
not match the pending run. Observe Gate 3 reject it. Find the Gate 3
check in watcher/watcher.js.
Trigger REJECTED. Write APPROVAL.md with STATUS: REJECTED and a
REASON. Run the watcher and read the log entry. Note that a rejection
discards the diff and starts a fresh fetch on the next tick.