Skip to content

Commit 218da4b

Browse files
authored
Merge pull request #130 from escendit/docs/epm-t144-gh129-someone-else-reproduces-coldframe
docs(reproduce): reproduction checklist, result record and stuck-point form
2 parents cd033ba + f0004b9 commit 218da4b

10 files changed

Lines changed: 581 additions & 1 deletion

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Reproduction stuck point
2+
description: >-
3+
A place where the docs alone did not get you through the reproduction checklist
4+
(docs/reproduce/README.md).
5+
title: "[reproduce] "
6+
labels:
7+
- bug
8+
body:
9+
- type: markdown
10+
attributes:
11+
value: >-
12+
Thank you for running the reproduction checklist. File one issue per stuck point.
13+
**Do not paste any secret**: no setup code, key, token, password, KEK, Secret value or
14+
account credential. Write your domain as `<domain>`.
15+
- type: dropdown
16+
id: part
17+
attributes:
18+
label: Checklist part
19+
options:
20+
- A. Start clean
21+
- B. The release
22+
- C. Build the Node and the Hub
23+
- D. Flash the Hub and the Node
24+
- E. Deploy the Server at home
25+
- F. Build your own apps
26+
- G. Add the Hub and the Node, calibrate
27+
- H. A Threshold Alert inside the Notification Window
28+
validations:
29+
required: true
30+
- type: input
31+
id: guide
32+
attributes:
33+
label: Guide page and section
34+
description: The page and heading you were following.
35+
placeholder: docs/build/flash.md#first-boot-and-the-setup-code
36+
validations:
37+
required: true
38+
- type: textarea
39+
id: did
40+
attributes:
41+
label: What you did
42+
description: The steps, commands and values you used (secrets removed).
43+
validations:
44+
required: true
45+
- type: textarea
46+
id: expected
47+
attributes:
48+
label: What you expected
49+
description: What the guide or the checklist said should happen.
50+
validations:
51+
required: true
52+
- type: textarea
53+
id: happened
54+
attributes:
55+
label: What happened
56+
description: The output, error or screen you got instead, and any workaround you found.
57+
render: text
58+
validations:
59+
required: true
60+
- type: input
61+
id: release
62+
attributes:
63+
label: Release tag
64+
description: Write none if you have no tag yet.
65+
placeholder: v0.2.0
66+
validations:
67+
required: false
68+
- type: textarea
69+
id: environment
70+
attributes:
71+
label: Environment
72+
description: >-
73+
Machine OS, home server arch and OS, boards and BOM substitutes, phone model and OS.
74+
validations:
75+
required: false
76+
- type: checkboxes
77+
id: no-secrets
78+
attributes:
79+
label: No secrets
80+
options:
81+
- label: This issue contains no setup code, key, token, password or other credential.
82+
required: true

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and deployment all live in this repository.
1313
- [Build guide](docs/build/README.md): build, flash and add your own Node and Hub.
1414
- [Deploy guide](docs/deploy/README.md): run Coldframe on your home server, then
1515
[build your own apps](docs/build/apps.md).
16+
- [Reproduce Coldframe](docs/reproduce/README.md): the end-to-end checklist for a second person
17+
rebuilding Coldframe from these docs, and how to report where they got stuck.
1618
- [Firmware reference](docs/firmware/README.md): learn ESP-NOW, BLE provisioning, eFuse keys and
1719
deep sleep from the Node and Hub firmware.
1820
- [Hardware design](hardware/README.md): schematics, BOM, wiring, enclosure and probe sealing.

‎_bmad-output/implementation-artifacts/deferred-work.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,3 +946,11 @@ source_spec: `spec-10-1-releases-with-one-version-and-firmware-binaries.md`
946946
severity: medium
947947
reason: dry_run is true for every non-push event, so these steps are skipped on PRs; only a real v* tag exercises them. Owed as an operator action (cut the first release and check it).
948948
status: open
949+
950+
### DW-122: Hub comments still claim the eFuse adapter holds the Hub's only unsafe code, but board/rtc.rs has an unsafe block for the mbedTLS clock hooks.
951+
origin: spec-deferred d5a00e9af471
952+
location: apps/rs/hub/src/board/efuse.rs:7
953+
source_spec: `spec-10-4-firmware-learning-reference.md`
954+
severity: low
955+
reason: apps/rs/hub/src/board/efuse.rs module doc line 7 and apps/rs/hub/Cargo.toml:60 say only efuse.rs may use unsafe; apps/rs/hub/src/board/rtc.rs:40-41 has #[allow(unsafe_code)] unsafe { ... }. Pre-existing, not caused by story 10-4; docs/firmware/identity.md already states the code's truth.
956+
status: open

‎_bmad-output/implementation-artifacts/spec-10-5-someone-else-reproduces-coldframe.md‎

Lines changed: 175 additions & 0 deletions
Large diffs are not rendered by default.

‎_bmad-output/implementation-artifacts/sprint-status.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,6 @@ development_status:
115115
10-1-releases-with-one-version-and-firmware-binaries: awaiting-operator
116116
10-2-build-a-node-and-a-hub-from-the-docs: awaiting-operator
117117
10-3-deploy-coldframe-at-home-and-build-my-own-apps: awaiting-operator
118-
10-4-firmware-learning-reference: backlog
118+
10-4-firmware-learning-reference: done
119119
10-5-someone-else-reproduces-coldframe: backlog
120120
epic-10-retrospective: optional

‎docs/build/README.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ first: the [deploy guide](../deploy/README.md) sets it up on your home server (t
4949
3. Calibrate the soil probe once it has settled in the soil for 2–3 days
5050
([why](power.md#soil-moisture)).
5151

52+
Reproducing Coldframe as someone other than its author? Follow the
53+
[reproduction checklist](../reproduce/README.md), which walks this guide and the deploy guide end
54+
to end.
55+
5256
## Checking this guide
5357

5458
CI checks these pages on every change (`.github/workflows/docs.yml`):

‎docs/deploy/README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,5 @@ restart durability and a backup in S3.
233233
- **Verification**: tick the checklist again after every upgrade.
234234
- **Restore**: when the database is lost or damaged, restore it from the S3 backups with the
235235
same `coldframe-device-kek` ([`restore.md`](../operations/restore.md)).
236+
- **Reproducing Coldframe** as a second person: the [reproduction checklist](../reproduce/README.md)
237+
walks this guide and the build guide end to end.

‎docs/reproduce/README.md‎

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
# Reproduction checklist: someone else builds Coldframe (Story 10.5)
2+
3+
This checklist is the test of Coldframe's promise that it can be reproduced from the public
4+
repository alone (success criterion SM-5). It walks the [build guide](../build/README.md) and the
5+
[deploy guide](../deploy/README.md) end to end, from the parts to a Threshold Alert on your phone.
6+
It does not repeat their commands: **the guides are what is under test**. Each part names the guide
7+
section that does the work and lists what you must observe when it is done.
8+
9+
Who may run it:
10+
11+
- **A person other than the author**, using only this public repository and its docs; or
12+
- **the author on a clean machine with fresh hardware and no prior state**: no cached toolchain, no
13+
existing cluster, no Keycloak realm, no enrolled boards, no app build or account left over from
14+
earlier work. Part A records that attestation; a run without it does not count.
15+
16+
Nobody helps you beyond what is written in the repository. When a guide is unclear, wrong or
17+
incomplete, that is a **stuck point**: do not ask the author, file it
18+
([When you get stuck](#when-you-get-stuck)) and work around it only if the guide's own text lets
19+
you. Every stuck point is fixed in the docs before the story closes.
20+
21+
At the end you write a result record from [`results/TEMPLATE.md`](results/TEMPLATE.md) and commit
22+
it under [`results/`](results/README.md).
23+
24+
## What you need
25+
26+
- **A release tag** `vX.Y.Z` of this repository with its GitHub Release (firmware binaries and
27+
`SHA256SUMS`): [`docs/operations/release.md`](../operations/release.md). Use the same tag for
28+
everything below.
29+
- **The parts for one Node and one Hub** from the [bill of materials](../../hardware/bom.md), plus
30+
USB cables, the soil the probe goes into, and the tools to assemble the Node.
31+
- **A home server** that runs all the time, as listed in the deploy guide's
32+
[Before you start](../deploy/README.md#before-you-start).
33+
- **A domain** whose DNS zone is hosted at Cloudflare, and a local DNS resolver you control.
34+
- **An SMTP account** that can send mail from an address of yours.
35+
- **An S3 bucket** off the home server for the database backups.
36+
- **One or two phones**: an iPhone with a Mac, Xcode and an Apple Developer Program membership,
37+
and/or an Android phone with a Firebase project
38+
([what the apps need](../build/apps.md#what-you-need)).
39+
- **A 2.4 GHz Wi-Fi network** with WPA2-Personal or mixed WPA2/WPA3. WPA3-only is not supported
40+
([`flash.md`, Wi-Fi](../build/flash.md#wi-fi)).
41+
- **A clean machine** to run the commands and builds from, with nothing of Coldframe on it yet.
42+
- A notebook (paper or a local file outside the repository) for the time each part takes and every
43+
stuck point.
44+
45+
Keep every key, token, password and setup code out of the repository, out of issues and out of the
46+
result record.
47+
48+
## A. Start clean
49+
50+
- [ ] You are not the author, **or** you are the author and every item below is true. Write which in
51+
the result record.
52+
53+
The remaining items are required for an author run. A non-author ticks each one only where it is
54+
true and writes n/a in the result record otherwise.
55+
56+
- [ ] The machine you run the commands and builds from has no esp toolchain, `espflash`, Rust
57+
target cache, Gradle or Xcode build cache for Coldframe, and no kubeconfig for a Coldframe
58+
cluster.
59+
- [ ] The home server has no RKE2, Fleet or Coldframe install on it.
60+
- [ ] The Hub and Node boards are fresh: never flashed with Coldframe (Part D checks the key
61+
blocks).
62+
- [ ] No Keycloak realm, account, Site or Device of an earlier Coldframe install exists anywhere you
63+
will use, and no Coldframe app is installed on the phones.
64+
- [ ] No Firebase project, APNs key, Cloudflare API token or S3 bucket made for an earlier Coldframe
65+
install is reused.
66+
- [ ] You have the repository from its public URL, checked out at the release tag of Part B, and no
67+
other notes than the docs in it.
68+
69+
## B. The release
70+
71+
Follow [`docs/operations/release.md`, What gets published](../operations/release.md#what-gets-published)
72+
and [Verify a download](../operations/release.md#verify-a-download).
73+
74+
- [ ] The GitHub Release for `vX.Y.Z` exists and carries `coldframe-hub-X.Y.Z.bin`,
75+
`coldframe-node-X.Y.Z.bin` and `SHA256SUMS`.
76+
- [ ] The download checks: with every Release asset downloaded next to `SHA256SUMS`, every line of
77+
the checksum check says `OK`.
78+
- [ ] The release notes link the build-your-own-apps guide.
79+
- [ ] Your clone is at that tag; the deploy guide, the firmware and the apps are all built from it.
80+
81+
## C. Build the Node and the Hub
82+
83+
Follow the [build guide](../build/README.md), steps
84+
[1. Get the parts](../build/README.md#1-get-the-parts) and
85+
[2. Assemble](../build/README.md#2-assemble).
86+
87+
- [ ] Every part you bought matches a line of the [BOM](../../hardware/bom.md), or a substitute meets
88+
that line's requirement.
89+
- [ ] The Node is wired exactly as in [`hardware/node.md`](../../hardware/node.md), without guessing a
90+
connection the page does not state.
91+
- [ ] The Node sits in its enclosure with the soil probe sealed as in
92+
[`hardware/enclosure.md`](../../hardware/enclosure.md).
93+
- [ ] The Hub is a dev board on USB power, placed as in [`hardware/hub.md`](../../hardware/hub.md).
94+
- [ ] The panel placement follows [power.md](../build/power.md#panel-placement).
95+
96+
## D. Flash the Hub and the Node
97+
98+
Follow [3. Install the toolchain](../build/README.md#3-install-the-toolchain),
99+
[4. Flash the Hub](../build/README.md#4-flash-the-hub) and
100+
[5. Flash the Node](../build/README.md#5-flash-the-node), through
101+
[`flash.md`](../build/flash.md). **Read its eFuse warning first**: the release binaries burn an
102+
eFuse key on the first boot, and that cannot be undone. Only boards meant to stay a Hub or a Node
103+
get them.
104+
105+
- [ ] The toolchain reports the versions [`flash.md`, Toolchain](../build/flash.md#toolchain) pins
106+
(at least `espflash` for the release binaries).
107+
- [ ] [The key-purpose check](../build/flash.md#before-you-flash-check-the-key-purposes) shows at
108+
least one unused `USER` key block on each board before you flash it.
109+
- [ ] The Hub's [first boot](../build/flash.md#first-boot-and-the-setup-code) logs its version
110+
`X.Y.Z`, `source=burned KEYn` once, a setup code, and that it advertises its BLE setup
111+
service. A reboot logs `source=existing KEYn` with the same Device ID.
112+
- [ ] The Node's first wake logs its version and its identity, then measures and sleeps. Its first
113+
wake logs `source=burned KEYn` once; a later wake logs `source=existing KEYn` with the same
114+
Device ID.
115+
- [ ] A long press (3 s) of the Node's setup button
116+
([the buttons](../build/flash.md#the-buttons)) logs `wake plan=setup`, a setup code and a
117+
180 s setup window (`window_ms=180000`).
118+
- [ ] Each setup code is on a sticker on its Device, and nowhere else.
119+
120+
## E. Deploy the Server at home
121+
122+
Follow the [deploy guide](../deploy/README.md), sections
123+
[1. Domain and DNS API token](../deploy/README.md#1-domain-and-dns-api-token) to
124+
[6. First sign-in](../deploy/README.md#6-first-sign-in), in order: single-node RKE2 with Fleet,
125+
Let's Encrypt certificates through DNS-01, split DNS. The Compose example does not count.
126+
127+
- [ ] RKE2 is installed and `kubectl` shows one node, Ready.
128+
- [ ] Fleet is installed, and every required Secret of section 3 exists before the GitRepo is
129+
applied (the optional `coldframe-push` may follow in Part F).
130+
- [ ] The `coldframe-realm` ConfigMap is written with `prepare-realm.sh` for `https://<domain>`
131+
([section 4](../deploy/README.md#4-keycloak-realm-and-phase-two)), and Keycloak imports the
132+
`coldframe` realm on its first start.
133+
- [ ] The GitRepo points at your release tag, and every bundle becomes Ready.
134+
- [ ] From a laptop on the home network the three hosts (`<domain>`, `api.<domain>`,
135+
`auth.<domain>`) resolve to the home server's LAN address and serve a Let's Encrypt
136+
certificate with no warning.
137+
- [ ] You register in the web app, the verification email arrives through your SMTP account, and
138+
you create a Site.
139+
- [ ] Keycloak's temporary bootstrap admin is replaced by a permanent admin in the master realm and
140+
deleted ([section 6](../deploy/README.md#6-first-sign-in)), and the `coldframe-keycloak-admin`
141+
Secret is kept.
142+
- [ ] Every item of the
143+
[verification checklist on the home server](../operations/install.md#verification-checklist-on-the-home-server)
144+
is ticked, including a backup in your S3 bucket.
145+
146+
## F. Build your own apps
147+
148+
Follow [`docs/build/apps.md`](../build/apps.md) from the same release tag:
149+
[Android](../build/apps.md#android) and/or [iOS](../build/apps.md#ios), with your own ids, then
150+
[Server push](../build/apps.md#server-push).
151+
152+
- [ ] Each app builds with your Server URL and Keycloak issuer, and installs on your phone. No key,
153+
team ID, keystore or `google-services.json` was added to the repository (`git status` is
154+
clean apart from the git-ignored files the guide names).
155+
- [ ] Each app signs in on the home Wi-Fi and shows the Site of Part E, with no Unreachable notice.
156+
- [ ] The Server's log has `PushChannelConfigured` for every provider you set up.
157+
- [ ] Each app asks for notification permission, and you allow it.
158+
159+
## G. Add the Hub and the Node, calibrate
160+
161+
Follow [6. Add them from the app](../build/README.md#6-add-them-from-the-app).
162+
163+
- [ ] **Add a Hub**: the app finds the unprovisioned Hub over BLE, takes its setup code from the
164+
sticker, and sends it your 2.4 GHz WPA2 (or mixed WPA2/WPA3) network and your Server's
165+
address. The app reports the Hub added to the Site, and its serial output no longer prints a
166+
setup code on boot.
167+
- [ ] Create a Lot for the Node if the Site has none.
168+
- [ ] **Add a Node**: long-press its setup button (3 s), pick the Lot, and enter its setup code
169+
within the 180 s setup window. The Node is listed on that Lot.
170+
- [ ] A short press of the Node's button sends a Reading now, and the Lot shows it.
171+
- [ ] Put the probe in the soil it stays in and leave it **2–3 days to settle**
172+
([why](../build/power.md#soil-moisture)). Readings keep arriving the whole time.
173+
- [ ] Calibrate the soil Sensor in the app (a dry point and a wet point). Afterwards the Lot shows
174+
soil moisture as a % (a multiple of 5) and the Sensor no longer asks for Calibration.
175+
- [ ] The Lot's low Threshold is the default **30 %** unless you changed it; note the value you use.
176+
177+
## H. A Threshold Alert inside the Notification Window
178+
179+
The Alert flow is described in the
180+
[push checklist, Part D](../bench/push-checklist.md#d-an-alert-on-both-phones). Do this inside your
181+
Notification Window (My notifications; the default is **07:00 to 22:00** in your time zone), with
182+
the app in the background.
183+
184+
- [ ] Let the Lot's soil read below its low Threshold for **three consecutive Readings**: take the
185+
probe out of the soil (a short press sends each Reading now).
186+
- [ ] Within a minute of the third Reading each phone shows **one** notification titled
187+
"‹Lot› needs water", with the body "~‹value› % in the soil, your low is ‹low› %."
188+
- [ ] Tapping the notification opens Lot detail of that Lot.
189+
- [ ] Put the probe back and let the Lot recover (three Readings within the Thresholds): the Lot
190+
shows within its Thresholds again (the Alert closes), and no new notification arrives.
191+
192+
## When you get stuck
193+
194+
A stuck point is any place where the docs alone did not get you to the next check: a missing step,
195+
a wrong command or value, a link that leads nowhere useful, an unexplained error, or a guess you had
196+
to make.
197+
198+
1. Open a new issue on GitHub and choose the **Reproduction stuck point** form. Name the part
199+
(A–H), the guide page and section, what you did, what you expected and what happened. Paste no
200+
secret, setup code, token or private domain credentials.
201+
2. Write the issue number in your notes, next to the part.
202+
3. Carry on only if you can without the author's help; otherwise stop the run there and record the
203+
result as failed at that part.
204+
205+
Each stuck point is fixed by a pull request to the docs. The story stays open until every issue
206+
listed in the result record is fixed. After a doc fix merges, rerun the affected parts following
207+
the fixed docs on `main`, with the same release artifacts and the boards already flashed, and note
208+
the rerun in the same record. A fix in the firmware, the Server, the charts or the apps ships in a
209+
new release tag; the run then continues from the first affected part on that tag.
210+
211+
## Record the result
212+
213+
Copy [`results/TEMPLATE.md`](results/TEMPLATE.md) to `docs/reproduce/results/YYYY-MM-DD-<tester>.md`,
214+
fill it in, and open a pull request with it ([`results/README.md`](results/README.md) has the
215+
rules). Fill it in truthfully, including the parts that failed.
216+
217+
## Result
218+
219+
Pass: parts A to H all ticked, with the attestation of Part A, on one release tag, and every
220+
stuck-point issue raised during the run fixed in the docs. A run where A to H passed but listed
221+
issues are still open is **pending doc fixes**; it becomes a pass once every listed issue's fix is
222+
merged. Anything else is a failed run of Story 10.5, and SM-5 does not hold until a later run
223+
passes.

‎docs/reproduce/results/README.md‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Reproduction results
2+
3+
This folder holds the result records of runs of the
4+
[reproduction checklist](../README.md), one file per run. They are the evidence for SM-5:
5+
someone other than the author (or the author on a clean machine with fresh hardware and no prior
6+
state) reproduced Coldframe from the public docs alone.
7+
8+
## Adding a record
9+
10+
1. Copy [`TEMPLATE.md`](TEMPLATE.md) to `YYYY-MM-DD-<tester>.md` in this folder: the date the run
11+
ended and your GitHub handle, or `author-clean` for an author run. A second run on the same day
12+
adds `-2`.
13+
2. Fill it in: the attestation, every part A to H, every stuck-point issue and the verdict
14+
(Passed, Pending doc fixes, or Failed at a part). Record failures as they happened.
15+
3. Open a pull request with the file. After the run, only the "Fixed by PR" column and the Verdict
16+
line (Pending doc fixes → Passed, once every listed fix is merged) may be edited, in the fix's
17+
pull request or a follow-up one.
18+
19+
Records never hold secrets: no setup code, key, token, password or credential of any account.
20+
21+
## When SM-5 holds
22+
23+
SM-5 holds, and Story 10.5 can close, only when a record here shows a passing run with the
24+
attestation ticked and **every** stuck-point issue it lists fixed in the docs by a merged pull
25+
request. A failed run stays in the folder as history; the next run gets its own record.

0 commit comments

Comments
 (0)