@@ -51,6 +51,19 @@ def setUpClass(cls) -> None:
5151 / "v0.4.2-production.json"
5252 ).read_text (encoding = "utf-8" )
5353 )
54+ cls .browser_attestation = (
55+ REPO_ROOT
56+ / "docs"
57+ / "validation"
58+ / "browser-flashing"
59+ / "v0.4.2-production.md"
60+ ).read_text (encoding = "utf-8" )
61+ cls .changelog = (REPO_ROOT / "CHANGELOG.md" ).read_text (
62+ encoding = "utf-8"
63+ )
64+ cls .flash_page = (
65+ REPO_ROOT / "tools" / "web" / "src" / "app" / "flash" / "page.tsx"
66+ ).read_text (encoding = "utf-8" )
5467
5568 def test_readme_identifies_the_exact_hardware_tested_public_beta (self ) -> None :
5669 firmware = markdown_section (self .readme , "What works" )
@@ -160,13 +173,64 @@ def test_production_browser_claim_is_bound_to_public_evidence(self) -> None:
160173 self .assertTrue (profile ["serial_route_released" ])
161174 self .assertEqual (profile ["interruption_fetch_rounds" ]["firmware" ], 2 )
162175 self .assertEqual (profile ["recovery_fetch_rounds" ]["firmware" ], 2 )
176+ self .assertEqual (
177+ [profile ["firmware_sha256" ] for profile in evidence ["profiles" ]],
178+ [
179+ "3bd148df6163d21dd6ee86eecdff47820f3b20323e7cc39a3253937c60af1245" ,
180+ "7cb73313b7108d9ee7bcd34780ecc25f6fef1590dfeee49bb08c424e58f741ff" ,
181+ ],
182+ )
163183 self .assertTrue (
164184 any (
165185 "not the formal" in limitation
166186 for limitation in evidence ["limitations" ]
167187 )
168188 )
169189
190+ def test_post_release_attestation_bounds_the_completed_hil_scope (self ) -> None :
191+ attestation = self .browser_attestation
192+
193+ for identity in (
194+ "firmware-v0.4.2" ,
195+ "ce02b68ab73da903035aa9f992c1f7e8eb2a3691" ,
196+ "5d1b0db8c4b90cccf054cd244530afb3b9112d489aa02f7c5da650e92161acde" ,
197+ "3bd148df6163d21dd6ee86eecdff47820f3b20323e7cc39a3253937c60af1245" ,
198+ "7cb73313b7108d9ee7bcd34780ecc25f6fef1590dfeee49bb08c424e58f741ff" ,
199+ ):
200+ self .assertIn (identity , attestation )
201+
202+ for wording in (
203+ "Supplemental production-browser result: **passed**" ,
204+ "`esp32-4mb`" ,
205+ "`esp32-s3-n16r8`" ,
206+ "7%" ,
207+ "immutable pre-public qualification ledger" ,
208+ "supersedes only its pending browser-installation and interrupted-recovery rows" ,
209+ "does not change its other pending qualification rows" ,
210+ "not a qualified release" ,
211+ "ESP32-C3 was not tested and remains unavailable" ,
212+ ):
213+ self .assertIn (wording , attestation )
214+
215+ def test_public_surfaces_link_the_release_evidence_and_changelog (self ) -> None :
216+ self .assertIn (
217+ "(docs/validation/browser-flashing/v0.4.2-production.md)" ,
218+ self .readme ,
219+ )
220+ self .assertIn (
221+ "https://github.com/PyBLE-dev/PyBLE/releases/tag/firmware-v0.4.2" ,
222+ self .flash_page ,
223+ )
224+ self .assertIn ("Release evidence and exact hashes" , self .flash_page )
225+
226+ release = markdown_section (self .changelog , "Firmware 0.4.2 — 2026-07-31" )
227+ self .assertIn ("hardware-tested beta" , release )
228+ self .assertIn ("`esp32-4mb`" , release )
229+ self .assertIn ("`esp32-s3-n16r8`" , release )
230+ self .assertIn ("interrupted-flash recovery" , release )
231+ self .assertIn ("complete release qualification remains pending" , release )
232+ self .assertNotIn ("qualified release" , release )
233+
170234 def test_bug_template_collects_the_exact_installer_diagnostics (self ) -> None :
171235 for field_id in (
172236 "profile" ,
0 commit comments