ADJCJH commited on
Commit
36ebc46
·
verified ·
1 Parent(s): a65c040

Sync Devpost submission preview

Browse files
.github/workflows/ci.yml CHANGED
@@ -111,6 +111,9 @@ jobs:
111
  - name: Submission audit
112
  run: python scripts/submission_audit.py
113
 
 
 
 
114
  - name: Devpost submission receipt
115
  run: python scripts/devpost_submission_receipt.py
116
 
 
111
  - name: Submission audit
112
  run: python scripts/submission_audit.py
113
 
114
+ - name: Devpost submission preview
115
+ run: python scripts/devpost_submission_preview.py
116
+
117
  - name: Devpost submission receipt
118
  run: python scripts/devpost_submission_receipt.py
119
 
docs/assets/devpost-submission-preview.json ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "proofframe.devpost_submission_preview.v1",
3
+ "created_at": "2026-06-28T17:59:53Z",
4
+ "mode": "pre_live_preview_ready",
5
+ "ok": true,
6
+ "safe_to_share": true,
7
+ "safe_to_submit": false,
8
+ "project": {
9
+ "name": "ProofFrame",
10
+ "tagline": "B2-ready provenance desk for GenAI media.",
11
+ "one_liner": "ProofFrame turns generated media into approved evidence packets with B2-ready manifests, Genblaze-gated provider metadata, checksums, review status, and an exportable proof bundle.",
12
+ "repository_url": "https://github.com/adjcjh777/backblaze-proofframe",
13
+ "demo_url": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
14
+ "video_url": "TBD after final B2 and Genblaze proof."
15
+ },
16
+ "copy_blocks": {
17
+ "thirty_second_pitch": "ProofFrame is not another image generator. It is a media operations desk that turns each generated asset into a reviewable packet: prompt, provider/model metadata, storage reference, checksum, approval state, risk note, manifest, and exportable evidence.",
18
+ "short_description": "ProofFrame is a review desk for generated media. The local demo creates a campaign, generates mock variants, approves or rejects assets, exports a manifest, and downloads an evidence ZIP with prompts, provider/model fields, storage references, hashes, and approval status. The final hackathon submission gate is to verify the same flow with Genblaze-backed generation and Backblaze B2-backed storage.",
19
+ "backblaze_b2_usage": "ProofFrame treats Backblaze B2 as the final durable evidence layer, not as a late file-upload checkbox. The public demo currently runs in local/mock mode, but every asset packet already carries the B2-ready object model: storage backend, storage key, checksum, byte size, prompt, provider/model metadata, approval state, and risk note. The repo includes a dedicated B2 S3-compatible storage adapter, a recorded private B2 bucket setup, and a one-command B2 proof runner that will upload one generated asset and one manifest with environment-only credentials. That live upload remains the final submission gate before any public claim is upgraded to completed B2 storage.",
20
+ "genblaze_usage": "ProofFrame includes a Genblaze/GMICloud provider adapter built around the official Genblaze Pipeline API. In the public mock demo, deterministic generation keeps the workflow inspectable without secrets; the same manifest fields are reserved for the final provider, model, request/run metadata, prompt, and asset checksum. The final submission gate is a live Genblaze-compatible run that proves the provider path and then carries the resulting asset into the ProofFrame review and storage packet.",
21
+ "accomplishments": [
22
+ "Built a working local product, not just a pitch.",
23
+ "Deployed a credential-free public mock demo.",
24
+ "Added a one-click Judge Demo path.",
25
+ "Added a review console with evidence search, status filtering, decision coverage, and safe summary copy.",
26
+ "Added downloadable evidence ZIPs.",
27
+ "Added B2-compatible storage and Genblaze/GMICloud provider code paths.",
28
+ "Added CI that runs readiness checks, lint, tests, API smoke, and secret scan.",
29
+ "Added fail-closed gates for evidence JSON exports and final submission audits.",
30
+ "Kept public claims gated until live sponsor proof exists."
31
+ ],
32
+ "whats_next": [
33
+ "Live B2 proof with a dedicated bucket and least-privilege key.",
34
+ "Live Genblaze proof with provider/model/run metadata.",
35
+ "Demo video under the event limit.",
36
+ "Final Devpost submission."
37
+ ],
38
+ "judge_note": "Use this preview as a copy/reference pack. It is not final-submittable until safe_to_submit becomes true."
39
+ },
40
+ "submission_readiness": {
41
+ "packet_mode": "pre_live_safe",
42
+ "form_mode": "pre_live_form_ready",
43
+ "final_control_mode": "pre_live_control",
44
+ "submit_checklist_mode": "pre_submit_blocked",
45
+ "submission_audit_mode": "pre_submit_audit_blocked",
46
+ "secret_scan_mode": "clear",
47
+ "public_space_mode": "public_space_synced",
48
+ "public_screenshot_mode": "public_judge_screenshot_ready",
49
+ "final_blockers": [
50
+ {
51
+ "id": "devpost_submission_checklist",
52
+ "label": "Final Devpost web submission checklist is ready",
53
+ "detail": "Devpost submission checklist mode is pre_submit_blocked; safe_to_submit is False.",
54
+ "evidence": "docs/assets/devpost-submission-checklist.json"
55
+ },
56
+ {
57
+ "id": "b2_live_proof",
58
+ "label": "live Backblaze B2 proof",
59
+ "detail": "T020 is doing; B2 evidence status is missing; final evidence status is missing.",
60
+ "evidence": "tasks.json, docs/assets/b2-live-proof-evidence.json, and docs/assets/final-live-proof-evidence.json"
61
+ },
62
+ {
63
+ "id": "genblaze_live_proof",
64
+ "label": "live Genblaze proof",
65
+ "detail": "T021 is doing; final evidence status is missing.",
66
+ "evidence": "tasks.json and docs/assets/final-live-proof-evidence.json"
67
+ },
68
+ {
69
+ "id": "credential_handoff",
70
+ "label": "Live credential handoff is ready",
71
+ "detail": "Credential handoff mode is missing_live_env; missing ids: b2_key_id, b2_application_key, genblaze_api_key.",
72
+ "evidence": "docs/assets/live-credential-handoff.json"
73
+ },
74
+ {
75
+ "id": "public_video",
76
+ "label": "final public video",
77
+ "detail": "Storyboard mode is mock_storyboard_ready; public video ready is False.",
78
+ "evidence": "docs/assets/demo-storyboard.json"
79
+ },
80
+ {
81
+ "id": "public_video_check",
82
+ "label": "public video URL check",
83
+ "detail": "Public video check mode is pending_video_url; safe_to_submit is False.",
84
+ "evidence": "docs/assets/public-video-check.json"
85
+ },
86
+ {
87
+ "id": "final_recording",
88
+ "label": "Final recording gate is ready",
89
+ "detail": "Demo readiness mode is pre_live_mock_ready; final recording ready is False.",
90
+ "evidence": "docs/assets/demo-readiness-report.json"
91
+ },
92
+ {
93
+ "id": "final_secret_scan",
94
+ "label": "final secret scan task completion",
95
+ "detail": "T041A is todo; secret scan mode is clear; secret scan ok is True.",
96
+ "evidence": "tasks.json and docs/assets/secret-scan-report.json"
97
+ },
98
+ {
99
+ "id": "final_submission_audit",
100
+ "label": "strict final submission audit",
101
+ "detail": "T041 is todo; audit mode is pre_submit_audit_blocked; audit ok is False.",
102
+ "evidence": "tasks.json and docs/assets/submission-audit-report.json"
103
+ },
104
+ {
105
+ "id": "devpost_submitted",
106
+ "label": "Devpost submission receipt",
107
+ "detail": "T042 is todo; receipt mode is pending_submission; receipt ok is False.",
108
+ "evidence": "tasks.json and docs/assets/devpost-submission-receipt.json"
109
+ }
110
+ ]
111
+ },
112
+ "field_rollup": {
113
+ "field_count": 19,
114
+ "mock_ready": true,
115
+ "final_ready": false,
116
+ "public_video_ready": false,
117
+ "final_pending_fields": [
118
+ {
119
+ "id": "video_url",
120
+ "label": "Demo video URL"
121
+ }
122
+ ]
123
+ },
124
+ "criteria_rollup": {
125
+ "mode": "pre_live_crosswalk_ready",
126
+ "safe_to_submit": false,
127
+ "official_criteria": [
128
+ "Real-world Utility",
129
+ "Production Readiness",
130
+ "B2 Storage + Data Orchestration",
131
+ "Use of Genblaze"
132
+ ],
133
+ "row_count": 4
134
+ },
135
+ "evidence_links": {
136
+ "public_demo": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
137
+ "repository": "https://github.com/adjcjh777/backblaze-proofframe",
138
+ "public_screenshot": "docs/assets/proofframe-hf-public-smoke.png",
139
+ "screenshot_report": "docs/assets/public-demo-screenshot-report.json",
140
+ "public_space_sync": "docs/assets/public-space-sync-report.json",
141
+ "judge_brief": "docs/assets/judge-brief.json",
142
+ "judge_crosswalk": "docs/assets/judge-crosswalk.json",
143
+ "form_kit": "docs/assets/devpost-form-kit.json",
144
+ "final_control": "docs/assets/final-submission-control.json",
145
+ "submission_bundle": "docs/assets/submission-bundle-manifest.json"
146
+ },
147
+ "claim_boundary": [
148
+ "Public demo evidence proves only the credential-free local/mock judge flow.",
149
+ "Do not claim completed live Backblaze B2 storage until T020 has sanitized live evidence.",
150
+ "Do not claim completed live Genblaze generation until T021 has sanitized live evidence.",
151
+ "Do not submit this packet as final until safe_to_submit is true."
152
+ ],
153
+ "source_status": {
154
+ "packet": {
155
+ "id": "packet",
156
+ "path": "docs/assets/devpost-submission-packet.json",
157
+ "present": true,
158
+ "schema": "proofframe.devpost_packet.v1",
159
+ "schema_ok": true,
160
+ "mode": "pre_live_safe",
161
+ "ok": null
162
+ },
163
+ "form_kit": {
164
+ "id": "form_kit",
165
+ "path": "docs/assets/devpost-form-kit.json",
166
+ "present": true,
167
+ "schema": "proofframe.devpost_form_kit.v1",
168
+ "schema_ok": true,
169
+ "mode": "pre_live_form_ready",
170
+ "ok": null
171
+ },
172
+ "judge_brief": {
173
+ "id": "judge_brief",
174
+ "path": "docs/assets/judge-brief.json",
175
+ "present": true,
176
+ "schema": "proofframe.judge_brief.v1",
177
+ "schema_ok": true,
178
+ "mode": null,
179
+ "ok": null
180
+ },
181
+ "judge_crosswalk": {
182
+ "id": "judge_crosswalk",
183
+ "path": "docs/assets/judge-crosswalk.json",
184
+ "present": true,
185
+ "schema": "proofframe.judge_crosswalk.v1",
186
+ "schema_ok": true,
187
+ "mode": "pre_live_crosswalk_ready",
188
+ "ok": true
189
+ },
190
+ "public_screenshot": {
191
+ "id": "public_screenshot",
192
+ "path": "docs/assets/public-demo-screenshot-report.json",
193
+ "present": true,
194
+ "schema": "proofframe.public_demo_screenshot.v1",
195
+ "schema_ok": true,
196
+ "mode": "public_judge_screenshot_ready",
197
+ "ok": true
198
+ },
199
+ "public_space_sync": {
200
+ "id": "public_space_sync",
201
+ "path": "docs/assets/public-space-sync-report.json",
202
+ "present": true,
203
+ "schema": "proofframe.public_space_sync.v1",
204
+ "schema_ok": true,
205
+ "mode": "public_space_synced",
206
+ "ok": true
207
+ },
208
+ "final_control": {
209
+ "id": "final_control",
210
+ "path": "docs/assets/final-submission-control.json",
211
+ "present": true,
212
+ "schema": "proofframe.final_submission_control.v1",
213
+ "schema_ok": true,
214
+ "mode": "pre_live_control",
215
+ "ok": null
216
+ },
217
+ "submit_checklist": {
218
+ "id": "submit_checklist",
219
+ "path": "docs/assets/devpost-submission-checklist.json",
220
+ "present": true,
221
+ "schema": "proofframe.devpost_submission_checklist.v1",
222
+ "schema_ok": true,
223
+ "mode": "pre_submit_blocked",
224
+ "ok": false
225
+ },
226
+ "submission_audit": {
227
+ "id": "submission_audit",
228
+ "path": "docs/assets/submission-audit-report.json",
229
+ "present": true,
230
+ "schema": "proofframe.submission_audit.v1",
231
+ "schema_ok": true,
232
+ "mode": "pre_submit_audit_blocked",
233
+ "ok": false
234
+ },
235
+ "secret_scan": {
236
+ "id": "secret_scan",
237
+ "path": "docs/assets/secret-scan-report.json",
238
+ "present": true,
239
+ "schema": "proofframe.secret_scan.v1",
240
+ "schema_ok": true,
241
+ "mode": "clear",
242
+ "ok": true
243
+ }
244
+ },
245
+ "next_actions": [
246
+ "Finalize Devpost fields: Demo video URL.",
247
+ "Resolve final blocker: Final Devpost web submission checklist is ready.",
248
+ "Resolve final blocker: live Backblaze B2 proof.",
249
+ "Resolve final blocker: live Genblaze proof.",
250
+ "Resolve final blocker: Live credential handoff is ready.",
251
+ "Resolve final blocker: final public video.",
252
+ "Resolve final blocker: public video URL check.",
253
+ "Resolve final blocker: Final recording gate is ready."
254
+ ]
255
+ }
docs/assets/devpost-submission-preview.md ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ProofFrame Devpost Submission Preview
2
+
3
+ Mode: `pre_live_preview_ready`
4
+ Safe to share: `true`
5
+ Safe to submit: `false`
6
+
7
+ ## Project
8
+
9
+ - Name: ProofFrame
10
+ - Tagline: B2-ready provenance desk for GenAI media.
11
+ - Repository: https://github.com/adjcjh777/backblaze-proofframe
12
+ - Demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
13
+ - Video: TBD after final B2 and Genblaze proof.
14
+
15
+ ## Copy Blocks
16
+
17
+ ### 30-Second Pitch
18
+
19
+ ProofFrame is not another image generator. It is a media operations desk that turns each generated asset into a reviewable packet: prompt, provider/model metadata, storage reference, checksum, approval state, risk note, manifest, and exportable evidence.
20
+
21
+ ### Short Description
22
+
23
+ ProofFrame is a review desk for generated media. The local demo creates a campaign, generates mock variants, approves or rejects assets, exports a manifest, and downloads an evidence ZIP with prompts, provider/model fields, storage references, hashes, and approval status. The final hackathon submission gate is to verify the same flow with Genblaze-backed generation and Backblaze B2-backed storage.
24
+
25
+ ### Backblaze B2 Usage
26
+
27
+ ProofFrame treats Backblaze B2 as the final durable evidence layer, not as a late file-upload checkbox. The public demo currently runs in local/mock mode, but every asset packet already carries the B2-ready object model: storage backend, storage key, checksum, byte size, prompt, provider/model metadata, approval state, and risk note. The repo includes a dedicated B2 S3-compatible storage adapter, a recorded private B2 bucket setup, and a one-command B2 proof runner that will upload one generated asset and one manifest with environment-only credentials. That live upload remains the final submission gate before any public claim is upgraded to completed B2 storage.
28
+
29
+ ### Genblaze Usage
30
+
31
+ ProofFrame includes a Genblaze/GMICloud provider adapter built around the official Genblaze Pipeline API. In the public mock demo, deterministic generation keeps the workflow inspectable without secrets; the same manifest fields are reserved for the final provider, model, request/run metadata, prompt, and asset checksum. The final submission gate is a live Genblaze-compatible run that proves the provider path and then carries the resulting asset into the ProofFrame review and storage packet.
32
+
33
+ ## Evidence Links
34
+
35
+ - `public_demo`: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
36
+ - `repository`: https://github.com/adjcjh777/backblaze-proofframe
37
+ - `public_screenshot`: docs/assets/proofframe-hf-public-smoke.png
38
+ - `screenshot_report`: docs/assets/public-demo-screenshot-report.json
39
+ - `public_space_sync`: docs/assets/public-space-sync-report.json
40
+ - `judge_brief`: docs/assets/judge-brief.json
41
+ - `judge_crosswalk`: docs/assets/judge-crosswalk.json
42
+ - `form_kit`: docs/assets/devpost-form-kit.json
43
+ - `final_control`: docs/assets/final-submission-control.json
44
+ - `submission_bundle`: docs/assets/submission-bundle-manifest.json
45
+
46
+ ## Readiness
47
+
48
+ - `packet_mode`: `pre_live_safe`
49
+ - `form_mode`: `pre_live_form_ready`
50
+ - `final_control_mode`: `pre_live_control`
51
+ - `submit_checklist_mode`: `pre_submit_blocked`
52
+ - `submission_audit_mode`: `pre_submit_audit_blocked`
53
+ - `secret_scan_mode`: `clear`
54
+ - `public_space_mode`: `public_space_synced`
55
+ - `public_screenshot_mode`: `public_judge_screenshot_ready`
56
+
57
+ ## Final Blockers
58
+
59
+ - `devpost_submission_checklist`: Final Devpost web submission checklist is ready - Devpost submission checklist mode is pre_submit_blocked; safe_to_submit is False.
60
+ - `b2_live_proof`: live Backblaze B2 proof - T020 is doing; B2 evidence status is missing; final evidence status is missing.
61
+ - `genblaze_live_proof`: live Genblaze proof - T021 is doing; final evidence status is missing.
62
+ - `credential_handoff`: Live credential handoff is ready - Credential handoff mode is missing_live_env; missing ids: b2_key_id, b2_application_key, genblaze_api_key.
63
+ - `public_video`: final public video - Storyboard mode is mock_storyboard_ready; public video ready is False.
64
+ - `public_video_check`: public video URL check - Public video check mode is pending_video_url; safe_to_submit is False.
65
+ - `final_recording`: Final recording gate is ready - Demo readiness mode is pre_live_mock_ready; final recording ready is False.
66
+ - `final_secret_scan`: final secret scan task completion - T041A is todo; secret scan mode is clear; secret scan ok is True.
67
+ - `final_submission_audit`: strict final submission audit - T041 is todo; audit mode is pre_submit_audit_blocked; audit ok is False.
68
+ - `devpost_submitted`: Devpost submission receipt - T042 is todo; receipt mode is pending_submission; receipt ok is False.
69
+
70
+ ## Claim Boundary
71
+
72
+ - Public demo evidence proves only the credential-free local/mock judge flow.
73
+ - Do not claim completed live Backblaze B2 storage until T020 has sanitized live evidence.
74
+ - Do not claim completed live Genblaze generation until T021 has sanitized live evidence.
75
+ - Do not submit this packet as final until safe_to_submit is true.
76
+
77
+ ## Next Actions
78
+
79
+ - Finalize Devpost fields: Demo video URL.
80
+ - Resolve final blocker: Final Devpost web submission checklist is ready.
81
+ - Resolve final blocker: live Backblaze B2 proof.
82
+ - Resolve final blocker: live Genblaze proof.
83
+ - Resolve final blocker: Live credential handoff is ready.
84
+ - Resolve final blocker: final public video.
85
+ - Resolve final blocker: public video URL check.
86
+ - Resolve final blocker: Final recording gate is ready.
docs/assets/final-rehearsal-checklist.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.final_rehearsal.v1",
3
- "created_at": "2026-06-28T17:45:46Z",
4
  "mode": "ready_for_credential_rehearsal",
5
  "ok": true,
6
  "safe_to_submit": false,
@@ -36,7 +36,7 @@
36
  {
37
  "id": "public_space_synced",
38
  "ok": true,
39
- "detail": "Runtime sha: 6a909b229afd3f08099877fb4cff633438f72ba5.",
40
  "evidence": "docs/assets/public-space-sync-report.json"
41
  },
42
  {
@@ -347,7 +347,7 @@
347
  "final_form_ready": null,
348
  "mock_recording_ready": null,
349
  "final_video_ready": null,
350
- "runtime_sha": "6a909b229afd3f08099877fb4cff633438f72ba5",
351
  "failed_checks": [],
352
  "missing_ids": [],
353
  "blocking_items": []
 
1
  {
2
  "schema": "proofframe.final_rehearsal.v1",
3
+ "created_at": "2026-06-28T17:50:06Z",
4
  "mode": "ready_for_credential_rehearsal",
5
  "ok": true,
6
  "safe_to_submit": false,
 
36
  {
37
  "id": "public_space_synced",
38
  "ok": true,
39
+ "detail": "Runtime sha: a65c040e9f61df8a46d31af418f5ed67051ea4d9.",
40
  "evidence": "docs/assets/public-space-sync-report.json"
41
  },
42
  {
 
347
  "final_form_ready": null,
348
  "mock_recording_ready": null,
349
  "final_video_ready": null,
350
+ "runtime_sha": "a65c040e9f61df8a46d31af418f5ed67051ea4d9",
351
  "failed_checks": [],
352
  "missing_ids": [],
353
  "blocking_items": []
docs/assets/final-rehearsal-checklist.md CHANGED
@@ -11,7 +11,7 @@ Next command: `python scripts/final_env_wizard.py --output .env.final.local --mi
11
  - OK `operator_ready`: Operator brief mode is credential_entry_ready. Evidence: `docs/assets/final-operator-brief.json`
12
  - OK `only_expected_secrets_missing`: Missing ids: b2_application_key, b2_key_id, genblaze_api_key. Evidence: `docs/assets/final-operator-brief.json`
13
  - OK `launch_plan_at_credential_entry`: Current phase is credential_entry. Evidence: `docs/assets/final-launch-plan.json`
14
- - OK `public_space_synced`: Runtime sha: 6a909b229afd3f08099877fb4cff633438f72ba5. Evidence: `docs/assets/public-space-sync-report.json`
15
  - OK `mock_form_ready`: Devpost form mode is pre_live_form_ready. Evidence: `docs/assets/devpost-form-kit.json`
16
  - OK `mock_recording_ready`: Recording assets mode is public_mock_verified. Evidence: `docs/assets/recording-assets.json`
17
  - OK `secret_scan_currently_clear`: Secret scan mode is clear. Evidence: `docs/assets/secret-scan-report.json`
 
11
  - OK `operator_ready`: Operator brief mode is credential_entry_ready. Evidence: `docs/assets/final-operator-brief.json`
12
  - OK `only_expected_secrets_missing`: Missing ids: b2_application_key, b2_key_id, genblaze_api_key. Evidence: `docs/assets/final-operator-brief.json`
13
  - OK `launch_plan_at_credential_entry`: Current phase is credential_entry. Evidence: `docs/assets/final-launch-plan.json`
14
+ - OK `public_space_synced`: Runtime sha: a65c040e9f61df8a46d31af418f5ed67051ea4d9. Evidence: `docs/assets/public-space-sync-report.json`
15
  - OK `mock_form_ready`: Devpost form mode is pre_live_form_ready. Evidence: `docs/assets/devpost-form-kit.json`
16
  - OK `mock_recording_ready`: Recording assets mode is public_mock_verified. Evidence: `docs/assets/recording-assets.json`
17
  - OK `secret_scan_currently_clear`: Secret scan mode is clear. Evidence: `docs/assets/secret-scan-report.json`
docs/assets/final-submission-control.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.final_submission_control.v1",
3
- "created_at": "2026-06-28T17:45:31Z",
4
  "mode": "pre_live_control",
5
  "safe_to_submit": false,
6
  "event": {
 
1
  {
2
  "schema": "proofframe.final_submission_control.v1",
3
+ "created_at": "2026-06-28T17:59:46Z",
4
  "mode": "pre_live_control",
5
  "safe_to_submit": false,
6
  "event": {
docs/assets/final-submission-control.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  Mode: `pre_live_control`
4
  Safe to submit: `false`
5
- Created: `2026-06-28T17:45:31Z`
6
  Public demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
7
  Repository: https://github.com/adjcjh777/backblaze-proofframe
8
 
 
2
 
3
  Mode: `pre_live_control`
4
  Safe to submit: `false`
5
+ Created: `2026-06-28T17:59:46Z`
6
  Public demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
7
  Repository: https://github.com/adjcjh777/backblaze-proofframe
8
 
docs/assets/judge-brief.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.judge_brief.v1",
3
- "created_at": "2026-06-28T17:45:15Z",
4
  "project": "ProofFrame",
5
  "tagline": "B2-ready provenance desk for GenAI media.",
6
  "one_liner": "ProofFrame turns generated media into approved evidence packets with B2-ready manifests, Genblaze-gated provider metadata, checksums, review status, and an exportable proof bundle.",
 
1
  {
2
  "schema": "proofframe.judge_brief.v1",
3
+ "created_at": "2026-06-28T17:59:46Z",
4
  "project": "ProofFrame",
5
  "tagline": "B2-ready provenance desk for GenAI media.",
6
  "one_liner": "ProofFrame turns generated media into approved evidence packets with B2-ready manifests, Genblaze-gated provider metadata, checksums, review status, and an exportable proof bundle.",
docs/assets/judge-brief.md CHANGED
@@ -1,6 +1,6 @@
1
  # ProofFrame Judge Brief
2
 
3
- Created: `2026-06-28T17:45:15Z`
4
  Tagline: B2-ready provenance desk for GenAI media.
5
  Public demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
6
  Repository: https://github.com/adjcjh777/backblaze-proofframe
 
1
  # ProofFrame Judge Brief
2
 
3
+ Created: `2026-06-28T17:59:46Z`
4
  Tagline: B2-ready provenance desk for GenAI media.
5
  Public demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
6
  Repository: https://github.com/adjcjh777/backblaze-proofframe
docs/assets/judge-crosswalk.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.judge_crosswalk.v1",
3
- "created_at": "2026-06-28T17:45:15Z",
4
  "mode": "pre_live_crosswalk_ready",
5
  "ok": true,
6
  "safe_to_submit": false,
 
1
  {
2
  "schema": "proofframe.judge_crosswalk.v1",
3
+ "created_at": "2026-06-28T17:59:46Z",
4
  "mode": "pre_live_crosswalk_ready",
5
  "ok": true,
6
  "safe_to_submit": false,
docs/assets/judge-crosswalk.md CHANGED
@@ -1,6 +1,6 @@
1
  # ProofFrame Judge Crosswalk
2
 
3
- Created: `2026-06-28T17:45:15Z`
4
  Mode: `pre_live_crosswalk_ready`
5
  OK: `true`
6
  Safe to submit: `false`
 
1
  # ProofFrame Judge Crosswalk
2
 
3
+ Created: `2026-06-28T17:59:46Z`
4
  Mode: `pre_live_crosswalk_ready`
5
  OK: `true`
6
  Safe to submit: `false`
docs/assets/public-space-sync-report.json CHANGED
@@ -1,17 +1,17 @@
1
  {
2
  "schema": "proofframe.public_space_sync.v1",
3
- "created_at": "2026-06-28T17:44:10Z",
4
  "ok": true,
5
  "mode": "public_space_synced",
6
  "space_id": "ADJCJH/backblaze-proofframe",
7
  "public_host": "https://adjcjh-backblaze-proofframe.hf.space",
8
- "expected_sha": "6a909b229afd3f08099877fb4cff633438f72ba5",
9
  "observed": {
10
- "space_sha": "6a909b229afd3f08099877fb4cff633438f72ba5",
11
- "runtime_sha": "6a909b229afd3f08099877fb4cff633438f72ba5",
12
  "runtime_stage": "RUNNING",
13
  "domain_ready": true,
14
- "last_modified": "2026-06-28T17:43:16.000Z",
15
  "health": {
16
  "ready": true,
17
  "storage_backend": "local",
@@ -129,14 +129,14 @@
129
  "id": "space_metadata",
130
  "label": "Space metadata points at the expected commit",
131
  "ok": true,
132
- "detail": "Space sha is 6a909b229afd3f08099877fb4cff633438f72ba5; expected 6a909b229afd3f08099877fb4cff633438f72ba5.",
133
  "evidence": "https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe"
134
  },
135
  {
136
  "id": "runtime_ready",
137
  "label": "Space runtime is running the expected commit",
138
  "ok": true,
139
- "detail": "Runtime stage is RUNNING; runtime sha is 6a909b229afd3f08099877fb4cff633438f72ba5; domain ready is True.",
140
  "evidence": "https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe/runtime"
141
  },
142
  {
 
1
  {
2
  "schema": "proofframe.public_space_sync.v1",
3
+ "created_at": "2026-06-28T17:49:15Z",
4
  "ok": true,
5
  "mode": "public_space_synced",
6
  "space_id": "ADJCJH/backblaze-proofframe",
7
  "public_host": "https://adjcjh-backblaze-proofframe.hf.space",
8
+ "expected_sha": "a65c040e9f61df8a46d31af418f5ed67051ea4d9",
9
  "observed": {
10
+ "space_sha": "a65c040e9f61df8a46d31af418f5ed67051ea4d9",
11
+ "runtime_sha": "a65c040e9f61df8a46d31af418f5ed67051ea4d9",
12
  "runtime_stage": "RUNNING",
13
  "domain_ready": true,
14
+ "last_modified": "2026-06-28T17:46:04.000Z",
15
  "health": {
16
  "ready": true,
17
  "storage_backend": "local",
 
129
  "id": "space_metadata",
130
  "label": "Space metadata points at the expected commit",
131
  "ok": true,
132
+ "detail": "Space sha is a65c040e9f61df8a46d31af418f5ed67051ea4d9; expected a65c040e9f61df8a46d31af418f5ed67051ea4d9.",
133
  "evidence": "https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe"
134
  },
135
  {
136
  "id": "runtime_ready",
137
  "label": "Space runtime is running the expected commit",
138
  "ok": true,
139
+ "detail": "Runtime stage is RUNNING; runtime sha is a65c040e9f61df8a46d31af418f5ed67051ea4d9; domain ready is True.",
140
  "evidence": "https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe/runtime"
141
  },
142
  {
docs/assets/public-space-sync-report.md CHANGED
@@ -2,19 +2,19 @@
2
 
3
  Mode: `public_space_synced`
4
  OK: `true`
5
- Created: `2026-06-28T17:44:10Z`
6
  Space: `ADJCJH/backblaze-proofframe`
7
  Public host: https://adjcjh-backblaze-proofframe.hf.space
8
- Expected sha: `6a909b229afd3f08099877fb4cff633438f72ba5`
9
- Runtime sha: `6a909b229afd3f08099877fb4cff633438f72ba5`
10
  Runtime stage: `RUNNING`
11
 
12
  ## Checks
13
 
14
  | Status | Check | Detail | Evidence |
15
  | --- | --- | --- | --- |
16
- | OK | Space metadata points at the expected commit | Space sha is 6a909b229afd3f08099877fb4cff633438f72ba5; expected 6a909b229afd3f08099877fb4cff633438f72ba5. | https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe |
17
- | OK | Space runtime is running the expected commit | Runtime stage is RUNNING; runtime sha is 6a909b229afd3f08099877fb4cff633438f72ba5; domain ready is True. | https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe/runtime |
18
  | OK | Raw handoff report is public and ready | Handoff schema is proofframe.agent_handoff.v1; mode is handoff_ready. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/agent-handoff-report.json |
19
  | OK | Raw Devpost event snapshot is public and fresh | Event snapshot schema is proofframe.devpost_event_snapshot.v1; submission_open=True; age_days=0; participants=365. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/devpost-event-snapshot.json |
20
  | OK | Raw final launch plan is public and phase-aware | Launch plan schema is proofframe.final_launch_plan.v1; mode is ready_for_credential_entry; current phase is credential_entry. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/final-launch-plan.json |
 
2
 
3
  Mode: `public_space_synced`
4
  OK: `true`
5
+ Created: `2026-06-28T17:49:15Z`
6
  Space: `ADJCJH/backblaze-proofframe`
7
  Public host: https://adjcjh-backblaze-proofframe.hf.space
8
+ Expected sha: `a65c040e9f61df8a46d31af418f5ed67051ea4d9`
9
+ Runtime sha: `a65c040e9f61df8a46d31af418f5ed67051ea4d9`
10
  Runtime stage: `RUNNING`
11
 
12
  ## Checks
13
 
14
  | Status | Check | Detail | Evidence |
15
  | --- | --- | --- | --- |
16
+ | OK | Space metadata points at the expected commit | Space sha is a65c040e9f61df8a46d31af418f5ed67051ea4d9; expected a65c040e9f61df8a46d31af418f5ed67051ea4d9. | https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe |
17
+ | OK | Space runtime is running the expected commit | Runtime stage is RUNNING; runtime sha is a65c040e9f61df8a46d31af418f5ed67051ea4d9; domain ready is True. | https://huggingface.co/api/spaces/ADJCJH/backblaze-proofframe/runtime |
18
  | OK | Raw handoff report is public and ready | Handoff schema is proofframe.agent_handoff.v1; mode is handoff_ready. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/agent-handoff-report.json |
19
  | OK | Raw Devpost event snapshot is public and fresh | Event snapshot schema is proofframe.devpost_event_snapshot.v1; submission_open=True; age_days=0; participants=365. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/devpost-event-snapshot.json |
20
  | OK | Raw final launch plan is public and phase-aware | Launch plan schema is proofframe.final_launch_plan.v1; mode is ready_for_credential_entry; current phase is credential_entry. | https://huggingface.co/spaces/ADJCJH/backblaze-proofframe/raw/main/docs/assets/final-launch-plan.json |
docs/assets/secret-scan-report.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.secret_scan.v1",
3
- "created_at": "2026-06-28T17:45:25Z",
4
  "mode": "clear",
5
  "ok": true,
6
  "root": ".",
@@ -9,7 +9,7 @@
9
  "scanned_text_files": 199,
10
  "inventoried_binary_files": 6,
11
  "skipped_local_secret_files": 1,
12
- "skipped_hard_files": 12953,
13
  "findings": 0
14
  },
15
  "coverage": {
 
1
  {
2
  "schema": "proofframe.secret_scan.v1",
3
+ "created_at": "2026-06-28T17:49:02Z",
4
  "mode": "clear",
5
  "ok": true,
6
  "root": ".",
 
9
  "scanned_text_files": 199,
10
  "inventoried_binary_files": 6,
11
  "skipped_local_secret_files": 1,
12
+ "skipped_hard_files": 13013,
13
  "findings": 0
14
  },
15
  "coverage": {
docs/assets/secret-scan-report.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  Mode: `clear`
4
  OK: `true`
5
- Created: `2026-06-28T17:45:25Z`
6
 
7
  ## Counts
8
 
 
2
 
3
  Mode: `clear`
4
  OK: `true`
5
+ Created: `2026-06-28T17:49:02Z`
6
 
7
  ## Counts
8
 
docs/assets/submission-audit-report.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.submission_audit.v1",
3
- "created_at": "2026-06-28T17:45:24Z",
4
  "mode": "pre_submit_audit_blocked",
5
  "ok": false,
6
  "root": ".",
 
1
  {
2
  "schema": "proofframe.submission_audit.v1",
3
+ "created_at": "2026-06-28T17:59:46Z",
4
  "mode": "pre_submit_audit_blocked",
5
  "ok": false,
6
  "root": ".",
docs/assets/submission-audit-report.md CHANGED
@@ -2,7 +2,7 @@
2
 
3
  Mode: `pre_submit_audit_blocked`
4
  OK: `false`
5
- Created: `2026-06-28T17:45:24Z`
6
  Final evidence: `docs/assets/final-live-proof-evidence.json`
7
 
8
  ## Task Statuses
 
2
 
3
  Mode: `pre_submit_audit_blocked`
4
  OK: `false`
5
+ Created: `2026-06-28T17:59:46Z`
6
  Final evidence: `docs/assets/final-live-proof-evidence.json`
7
 
8
  ## Task Statuses
docs/assets/submission-bundle-manifest.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "schema": "proofframe.submission_bundle.v1",
3
- "created_at": "2026-06-28T17:45:46Z",
4
  "project": "ProofFrame",
5
  "repository_url": "https://github.com/adjcjh777/backblaze-proofframe",
6
  "public_demo_url": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
@@ -156,8 +156,8 @@
156
  "path": "docs/deployment.md",
157
  "label": "Public demo deployment runbook",
158
  "present": true,
159
- "bytes": 5925,
160
- "sha256": "202a47b9123b07c4768642806310b92f8c1091179b38bf3de07c183d6adec453"
161
  },
162
  {
163
  "id": "devpost_draft",
@@ -236,8 +236,8 @@
236
  "path": "scripts/public_space_sync.py",
237
  "label": "Public Hugging Face Space sync verifier",
238
  "present": true,
239
- "bytes": 49648,
240
- "sha256": "8214726d7896081902aafea5b70fed4f23b1dd920a554b7df4c64477e6fd8479"
241
  },
242
  {
243
  "id": "public_space_sync_json",
@@ -245,7 +245,7 @@
245
  "label": "Machine-readable public Space sync report",
246
  "present": true,
247
  "bytes": 12768,
248
- "sha256": "f95e72fca0d561547a3670489b83ae5b293bfe6a4b108bc577eb9f9f0f119a8b"
249
  },
250
  {
251
  "id": "public_space_sync_md",
@@ -253,7 +253,7 @@
253
  "label": "Human-readable public Space sync report",
254
  "present": true,
255
  "bytes": 5737,
256
- "sha256": "630138a081deb99fc618362417a423e24be2be173e7efd5211031b259dd213d6"
257
  },
258
  {
259
  "id": "public_demo_screenshot_script",
@@ -303,6 +303,30 @@
303
  "bytes": 7496,
304
  "sha256": "f6beeb3fe9e7f94d2e8be0aeceda8a7523e6912462fef2201290670af1a2c143"
305
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  {
307
  "id": "devpost_submission_checklist_script",
308
  "path": "scripts/devpost_submission_checklist.py",
@@ -341,7 +365,7 @@
341
  "label": "Machine-readable judge brief",
342
  "present": true,
343
  "bytes": 3734,
344
- "sha256": "e22cf8b12d0c4dde73de1fe6f3c41bdd0e5bc8121098c2514141849642744f0a"
345
  },
346
  {
347
  "id": "judge_brief_md",
@@ -349,7 +373,7 @@
349
  "label": "Human-readable judge brief",
350
  "present": true,
351
  "bytes": 3000,
352
- "sha256": "1e61b76997304aa9240329eda25cbd2cc1d4bf43d38f2011742e0cf38d4c8a9f"
353
  },
354
  {
355
  "id": "judge_crosswalk_script",
@@ -365,7 +389,7 @@
365
  "label": "Machine-readable judge crosswalk",
366
  "present": true,
367
  "bytes": 10219,
368
- "sha256": "a460c9e293a9c405dae481d84556134cd2eb05f7900f91cb0519c15831bc8d06"
369
  },
370
  {
371
  "id": "judge_crosswalk_md",
@@ -373,7 +397,7 @@
373
  "label": "Human-readable judge crosswalk",
374
  "present": true,
375
  "bytes": 6157,
376
- "sha256": "85a92cce3f7cb19726c9918d70caacebe7e3c818eb8b8b62019f92e33dfc5c17"
377
  },
378
  {
379
  "id": "frontend_ui",
@@ -541,7 +565,7 @@
541
  "label": "Machine-readable final control report",
542
  "present": true,
543
  "bytes": 23824,
544
- "sha256": "a27ba923b0d6fc93371f4533618909a7913e5eea6cffea47a7604caaea0ece83"
545
  },
546
  {
547
  "id": "final_submission_control_md",
@@ -549,7 +573,7 @@
549
  "label": "Human-readable final control report",
550
  "present": true,
551
  "bytes": 6633,
552
- "sha256": "79ad9beae2cd85a34f66db812418b96536cedbf7b750c1f2e80c72cb87f8d95a"
553
  },
554
  {
555
  "id": "final_operator_brief_script",
@@ -613,7 +637,7 @@
613
  "label": "Machine-readable final rehearsal checklist",
614
  "present": true,
615
  "bytes": 16384,
616
- "sha256": "6786bd7f18ac088a868d4d5e9f74c3b6c97a5b5b194e5342d2abd9790fa13a00"
617
  },
618
  {
619
  "id": "final_rehearsal_md",
@@ -621,7 +645,7 @@
621
  "label": "Human-readable final rehearsal checklist",
622
  "present": true,
623
  "bytes": 6746,
624
- "sha256": "04eabbf8b4f78757802b91a521e235afafd79a29b80ddbeff40513336480b3d3"
625
  },
626
  {
627
  "id": "submission_audit_script",
@@ -637,7 +661,7 @@
637
  "label": "Machine-readable submission audit report",
638
  "present": true,
639
  "bytes": 5925,
640
- "sha256": "b9a990a3e53e6209fe3544a4298ad1a435d7d1be7545aa4ec288497fff9dcf65"
641
  },
642
  {
643
  "id": "submission_audit_md",
@@ -645,7 +669,7 @@
645
  "label": "Human-readable submission audit report",
646
  "present": true,
647
  "bytes": 4459,
648
- "sha256": "07ff00518307afeb5ad5ed4fcaa40f061b9b634eeeb6886e355f1b2e8abee19a"
649
  },
650
  {
651
  "id": "devpost_receipt_script",
@@ -676,8 +700,8 @@
676
  "path": "docs/evidence_package.md",
677
  "label": "Evidence package plan",
678
  "present": true,
679
- "bytes": 19668,
680
- "sha256": "7fcb8d85ce03b47a02742144da721c04b1522651258e4736e6a7896d1342edcc"
681
  },
682
  {
683
  "id": "public_claim_freeze",
@@ -717,7 +741,7 @@
717
  "label": "Machine-readable secret scan report",
718
  "present": true,
719
  "bytes": 10339,
720
- "sha256": "8d2d6bb3732fb4726b8aac09c2459a285a9abde261aaf04cf2ff6172a7b3807a"
721
  },
722
  {
723
  "id": "secret_scan_md",
@@ -725,7 +749,7 @@
725
  "label": "Human-readable secret scan report",
726
  "present": true,
727
  "bytes": 846,
728
- "sha256": "c2503236d2f3ac6981cc30451327f465e2b8b938d332306faa8a61c21d3b02b1"
729
  },
730
  {
731
  "id": "b2_live_setup_json",
@@ -900,16 +924,16 @@
900
  "path": "docs/submission.md",
901
  "label": "Registration and submission plan",
902
  "present": true,
903
- "bytes": 3900,
904
- "sha256": "53505f9edadbfa38e5908f6361d74629f039c2a2b79f06bb411f986d95310872"
905
  },
906
  {
907
  "id": "task_ledger",
908
  "path": "tasks.json",
909
  "label": "Machine-readable task board",
910
  "present": true,
911
- "bytes": 53812,
912
- "sha256": "efcc82d093e67abf366461d9eb5a4cde768c590d6e1a90013d7512a959e7e60d"
913
  },
914
  {
915
  "id": "local_ui_smoke",
 
1
  {
2
  "schema": "proofframe.submission_bundle.v1",
3
+ "created_at": "2026-06-28T17:59:53Z",
4
  "project": "ProofFrame",
5
  "repository_url": "https://github.com/adjcjh777/backblaze-proofframe",
6
  "public_demo_url": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
 
156
  "path": "docs/deployment.md",
157
  "label": "Public demo deployment runbook",
158
  "present": true,
159
+ "bytes": 6104,
160
+ "sha256": "1a95d966a8c6b7408b3fc8e1741cd1fdf0a93554d16d695ea9cb54abc2007b14"
161
  },
162
  {
163
  "id": "devpost_draft",
 
236
  "path": "scripts/public_space_sync.py",
237
  "label": "Public Hugging Face Space sync verifier",
238
  "present": true,
239
+ "bytes": 53157,
240
+ "sha256": "ee612700851206db93e3d80b98db29ebc9820d538a4c454d1d3241219fc1084e"
241
  },
242
  {
243
  "id": "public_space_sync_json",
 
245
  "label": "Machine-readable public Space sync report",
246
  "present": true,
247
  "bytes": 12768,
248
+ "sha256": "ce2a6e145fd7db8b6b7ae404afc38b9f67f0ee5de6d7913c34330282be1a39a4"
249
  },
250
  {
251
  "id": "public_space_sync_md",
 
253
  "label": "Human-readable public Space sync report",
254
  "present": true,
255
  "bytes": 5737,
256
+ "sha256": "b2f375fac4e211d74859728d4baaf9421e53a181bec0683351032ee9706a1bec"
257
  },
258
  {
259
  "id": "public_demo_screenshot_script",
 
303
  "bytes": 7496,
304
  "sha256": "f6beeb3fe9e7f94d2e8be0aeceda8a7523e6912462fef2201290670af1a2c143"
305
  },
306
+ {
307
+ "id": "devpost_preview_script",
308
+ "path": "scripts/devpost_submission_preview.py",
309
+ "label": "One-page claim-safe Devpost preview",
310
+ "present": true,
311
+ "bytes": 17329,
312
+ "sha256": "28ed8703ca6479fc772cdad0dc6e237d6495df13e68bb785a359f92d2c4f1c21"
313
+ },
314
+ {
315
+ "id": "devpost_preview_json",
316
+ "path": "docs/assets/devpost-submission-preview.json",
317
+ "label": "Machine-readable Devpost preview",
318
+ "present": true,
319
+ "bytes": 11611,
320
+ "sha256": "4b879e8ef57d4c47c9149d69d1d32a901b160ef3303963793bf06150d2e82e4e"
321
+ },
322
+ {
323
+ "id": "devpost_preview_md",
324
+ "path": "docs/assets/devpost-submission-preview.md",
325
+ "label": "Human-readable Devpost preview",
326
+ "present": true,
327
+ "bytes": 5407,
328
+ "sha256": "760d948b804fbe97cc61f437643c3f0b23748b864ed112076d3c2ed910b8a9fe"
329
+ },
330
  {
331
  "id": "devpost_submission_checklist_script",
332
  "path": "scripts/devpost_submission_checklist.py",
 
365
  "label": "Machine-readable judge brief",
366
  "present": true,
367
  "bytes": 3734,
368
+ "sha256": "ec78162143608efffffa4c35c056f7f56041a7017feca401f8b06245e594b5d7"
369
  },
370
  {
371
  "id": "judge_brief_md",
 
373
  "label": "Human-readable judge brief",
374
  "present": true,
375
  "bytes": 3000,
376
+ "sha256": "3bef5f0c09f383735d52410b7b1c8f8dae048280fb7bd3cc8836c3f958b2667a"
377
  },
378
  {
379
  "id": "judge_crosswalk_script",
 
389
  "label": "Machine-readable judge crosswalk",
390
  "present": true,
391
  "bytes": 10219,
392
+ "sha256": "b0cadd6d3ab4a38fae1444bb766bbe2dc9553522843c3b018dfe1a75518def32"
393
  },
394
  {
395
  "id": "judge_crosswalk_md",
 
397
  "label": "Human-readable judge crosswalk",
398
  "present": true,
399
  "bytes": 6157,
400
+ "sha256": "8123b9b158fe6cccdcee14615d840a1b474b17ab72836810b6530a41554b98f3"
401
  },
402
  {
403
  "id": "frontend_ui",
 
565
  "label": "Machine-readable final control report",
566
  "present": true,
567
  "bytes": 23824,
568
+ "sha256": "ee8fd964a4468f58ce3557d7bdc63026656486aa60031f2a038886cf1eadb96b"
569
  },
570
  {
571
  "id": "final_submission_control_md",
 
573
  "label": "Human-readable final control report",
574
  "present": true,
575
  "bytes": 6633,
576
+ "sha256": "61f7c21341b1faa2d9fd4f7b0c6390d9b2876932703b75a5221989cb2f96688a"
577
  },
578
  {
579
  "id": "final_operator_brief_script",
 
637
  "label": "Machine-readable final rehearsal checklist",
638
  "present": true,
639
  "bytes": 16384,
640
+ "sha256": "cbe61ad2213e6dcc076f78f62dfb2b2f1449c4c5b2736005912e5ccd62a7045b"
641
  },
642
  {
643
  "id": "final_rehearsal_md",
 
645
  "label": "Human-readable final rehearsal checklist",
646
  "present": true,
647
  "bytes": 6746,
648
+ "sha256": "f52eff10bd41671c35041d3a8a5c2fd4af4a67df5c361fc2c637c35a870d1fb2"
649
  },
650
  {
651
  "id": "submission_audit_script",
 
661
  "label": "Machine-readable submission audit report",
662
  "present": true,
663
  "bytes": 5925,
664
+ "sha256": "b4fb975e9c749a5b2180a7078a7ca68cf86bdb048b7a5cc4bb5cca4c018542a1"
665
  },
666
  {
667
  "id": "submission_audit_md",
 
669
  "label": "Human-readable submission audit report",
670
  "present": true,
671
  "bytes": 4459,
672
+ "sha256": "b962c5802d9b2b3a704f0031ee7064b0d83d95301ae428fc91eb800c8792680f"
673
  },
674
  {
675
  "id": "devpost_receipt_script",
 
700
  "path": "docs/evidence_package.md",
701
  "label": "Evidence package plan",
702
  "present": true,
703
+ "bytes": 20209,
704
+ "sha256": "82e60fd2fa515d66b0fc7e0cdac8472350e83066d1a3637e20003fa104ffdbf6"
705
  },
706
  {
707
  "id": "public_claim_freeze",
 
741
  "label": "Machine-readable secret scan report",
742
  "present": true,
743
  "bytes": 10339,
744
+ "sha256": "43107e3685aecf4979b38f88756bdcd4f31cb3d4c5694f893940e6ff15cded4f"
745
  },
746
  {
747
  "id": "secret_scan_md",
 
749
  "label": "Human-readable secret scan report",
750
  "present": true,
751
  "bytes": 846,
752
+ "sha256": "8f194c402306736f8e84695f93adf61b4abc5d1948d8429b49a5706b78de24e9"
753
  },
754
  {
755
  "id": "b2_live_setup_json",
 
924
  "path": "docs/submission.md",
925
  "label": "Registration and submission plan",
926
  "present": true,
927
+ "bytes": 4000,
928
+ "sha256": "3800b9a0950779d01fe61b19bef2344c1bbd4d545ce766bad5b675938318ed7b"
929
  },
930
  {
931
  "id": "task_ledger",
932
  "path": "tasks.json",
933
  "label": "Machine-readable task board",
934
  "present": true,
935
+ "bytes": 54412,
936
+ "sha256": "32355ab8e3c566aed98e85e71dcc19be14e49f68e7c45f1f262cac28bb0ff824"
937
  },
938
  {
939
  "id": "local_ui_smoke",
docs/assets/submission-bundle-manifest.md CHANGED
@@ -1,6 +1,6 @@
1
  # ProofFrame Submission Bundle
2
 
3
- Created: `2026-06-28T17:45:46Z`
4
  Repository: https://github.com/adjcjh777/backblaze-proofframe
5
  Public mock demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
6
  Devpost packet mode: `pre_live_safe`
@@ -28,7 +28,7 @@ Final gate ready: `false`
28
  - `Dockerfile` (522 bytes, sha256 `6764f101746a802d...`) - Docker deployment image contract
29
  - `docs/prd.md` (3918 bytes, sha256 `ada7e9161b86483c...`) - Product requirements
30
  - `docs/spec.md` (6177 bytes, sha256 `d0d24f751da92adc...`) - Implementation specification
31
- - `docs/deployment.md` (5925 bytes, sha256 `202a47b9123b07c4...`) - Public demo deployment runbook
32
  - `docs/devpost_draft.md` (5613 bytes, sha256 `e08e3f25a04bab48...`) - Copy-ready Devpost fields
33
  - `docs/assets/devpost-submission-packet.json` (6270 bytes, sha256 `92b06cc47f68c410...`) - Machine-readable Devpost copy
34
  - `docs/assets/devpost-submission-packet.md` (5159 bytes, sha256 `00e03e34b62dfdfc...`) - Human-readable Devpost copy
@@ -38,24 +38,27 @@ Final gate ready: `false`
38
  - `scripts/agent_handoff_check.py` (14559 bytes, sha256 `3ef180b6a92eb987...`) - Agent Bus and Codex handoff path checker
39
  - `docs/assets/agent-handoff-report.json` (2253 bytes, sha256 `d7db6502dbb8b257...`) - Machine-readable Agent handoff report
40
  - `docs/assets/agent-handoff-report.md` (1571 bytes, sha256 `058883dbe2520ad3...`) - Human-readable Agent handoff report
41
- - `scripts/public_space_sync.py` (49648 bytes, sha256 `8214726d78960819...`) - Public Hugging Face Space sync verifier
42
- - `docs/assets/public-space-sync-report.json` (12768 bytes, sha256 `f95e72fca0d56154...`) - Machine-readable public Space sync report
43
- - `docs/assets/public-space-sync-report.md` (5737 bytes, sha256 `630138a081deb99f...`) - Human-readable public Space sync report
44
  - `scripts/public_demo_screenshot.py` (8926 bytes, sha256 `3eb5b0a003e383dd...`) - Public judge-mode screenshot verifier
45
  - `docs/assets/public-demo-screenshot-report.json` (2421 bytes, sha256 `e8ce08735a86a920...`) - Machine-readable public screenshot report
46
  - `docs/assets/public-demo-screenshot-report.md` (1418 bytes, sha256 `dce44c3bc2188131...`) - Human-readable public screenshot report
47
  - `scripts/devpost_form_kit.py` (12830 bytes, sha256 `b0173e698f4c3629...`) - Field-by-field Devpost form kit
48
  - `docs/assets/devpost-form-kit.json` (12483 bytes, sha256 `96196519c036e0aa...`) - Machine-readable Devpost form kit
49
  - `docs/assets/devpost-form-kit.md` (7496 bytes, sha256 `f6beeb3fe9e7f94d...`) - Human-readable Devpost form kit
 
 
 
50
  - `scripts/devpost_submission_checklist.py` (11252 bytes, sha256 `78b8e1b70da428fd...`) - No-secret final Devpost web submission checklist
51
  - `docs/assets/devpost-submission-checklist.json` (16428 bytes, sha256 `c0076a55f6931805...`) - Machine-readable final Devpost submission checklist
52
  - `docs/assets/devpost-submission-checklist.md` (9319 bytes, sha256 `e45546c7334e78e3...`) - Human-readable final Devpost submission checklist
53
  - `scripts/judge_brief.py` (9968 bytes, sha256 `605a72a56e24b330...`) - Public-safe 30-second judge brief
54
- - `docs/assets/judge-brief.json` (3734 bytes, sha256 `e22cf8b12d0c4dde...`) - Machine-readable judge brief
55
- - `docs/assets/judge-brief.md` (3000 bytes, sha256 `1e61b76997304aa9...`) - Human-readable judge brief
56
  - `scripts/judge_crosswalk.py` (17642 bytes, sha256 `d9153174e330fd53...`) - Official criteria to evidence crosswalk
57
- - `docs/assets/judge-crosswalk.json` (10219 bytes, sha256 `a460c9e293a9c405...`) - Machine-readable judge crosswalk
58
- - `docs/assets/judge-crosswalk.md` (6157 bytes, sha256 `85a92cce3f7cb197...`) - Human-readable judge crosswalk
59
  - `apps/web/index.html` (65568 bytes, sha256 `8a6c22850ffd3fc9...`) - Browser proof ledger UI
60
  - `docs/demo_script.md` (5856 bytes, sha256 `fbabf38ff87cca9b...`) - Video shot list and narration
61
  - `scripts/demo_storyboard.py` (11025 bytes, sha256 `e5d75956d6d4a20b...`) - Machine-checked demo video storyboard
@@ -76,8 +79,8 @@ Final gate ready: `false`
76
  - `docs/assets/award-readiness-report.json` (11377 bytes, sha256 `66417f6e0c2a15d9...`) - Machine-readable award readiness report
77
  - `docs/assets/award-readiness-report.md` (4390 bytes, sha256 `5be57ca5d9cab53d...`) - Human-readable award readiness report
78
  - `scripts/final_submission_control.py` (31549 bytes, sha256 `c5ac3a7e236a122c...`) - Final submission control tower
79
- - `docs/assets/final-submission-control.json` (23824 bytes, sha256 `a27ba923b0d6fc93...`) - Machine-readable final control report
80
- - `docs/assets/final-submission-control.md` (6633 bytes, sha256 `79ad9beae2cd85a3...`) - Human-readable final control report
81
  - `scripts/final_operator_brief.py` (14478 bytes, sha256 `d64dd7c9b4a3f756...`) - No-secret final operator brief
82
  - `docs/assets/final-operator-brief.json` (8394 bytes, sha256 `48863d7be71d8618...`) - Machine-readable final operator brief
83
  - `docs/assets/final-operator-brief.md` (3618 bytes, sha256 `585065cd0eb9ee15...`) - Human-readable final operator brief
@@ -85,21 +88,21 @@ Final gate ready: `false`
85
  - `docs/assets/final-launch-plan.json` (5650 bytes, sha256 `cdc3d112db423132...`) - Machine-readable final launch plan
86
  - `docs/assets/final-launch-plan.md` (4596 bytes, sha256 `7747b3177be9562a...`) - Human-readable final launch plan
87
  - `scripts/final_rehearsal.py` (17468 bytes, sha256 `bc44abb94771023f...`) - No-secret final submission rehearsal checklist
88
- - `docs/assets/final-rehearsal-checklist.json` (16384 bytes, sha256 `6786bd7f18ac088a...`) - Machine-readable final rehearsal checklist
89
- - `docs/assets/final-rehearsal-checklist.md` (6746 bytes, sha256 `04eabbf8b4f78757...`) - Human-readable final rehearsal checklist
90
  - `scripts/submission_audit.py` (20524 bytes, sha256 `877f7e7c3e2f26d0...`) - Pre-submit audit gate
91
- - `docs/assets/submission-audit-report.json` (5925 bytes, sha256 `b9a990a3e53e6209...`) - Machine-readable submission audit report
92
- - `docs/assets/submission-audit-report.md` (4459 bytes, sha256 `07ff00518307afeb...`) - Human-readable submission audit report
93
  - `scripts/devpost_submission_receipt.py` (9209 bytes, sha256 `76c55e8ff1aeaa52...`) - Public-safe Devpost submission receipt generator
94
  - `docs/assets/devpost-submission-receipt.json` (1298 bytes, sha256 `bf646cf968665c8c...`) - Machine-readable Devpost submission receipt
95
  - `docs/assets/devpost-submission-receipt.md` (996 bytes, sha256 `af2fa18349d5c017...`) - Human-readable Devpost submission receipt
96
- - `docs/evidence_package.md` (19668 bytes, sha256 `7fcb8d85ce03b47a...`) - Evidence package plan
97
  - `docs/public_claim_freeze.md` (4089 bytes, sha256 `735b9188feae74ea...`) - Verified-claim boundary
98
  - `docs/verification.md` (9585 bytes, sha256 `1e796ae03eebf21d...`) - Local, CI, Docker, and live proof runbook
99
  - `.env.final.example` (352 bytes, sha256 `d250e97bb0a653fa...`) - Redacted final B2 plus Genblaze env template
100
  - `scripts/secret_scan.py` (11105 bytes, sha256 `02aec3a4a6e9fd47...`) - Final secret scanner
101
- - `docs/assets/secret-scan-report.json` (10339 bytes, sha256 `8d2d6bb3732fb472...`) - Machine-readable secret scan report
102
- - `docs/assets/secret-scan-report.md` (846 bytes, sha256 `c2503236d2f3ac69...`) - Human-readable secret scan report
103
  - `docs/assets/b2-live-setup.json` (719 bytes, sha256 `a377923f48e112b1...`) - Non-secret B2 bucket setup record
104
  - `docs/assets/b2-live-setup.md` (864 bytes, sha256 `863b2a02e3d2824f...`) - Human-readable B2 bucket setup record
105
  - `scripts/b2_key_scope_checklist.py` (17240 bytes, sha256 `bb1e6140f10aa3ac...`) - No-secret Backblaze B2 application key scope checklist
@@ -121,8 +124,8 @@ Final gate ready: `false`
121
  - `docs/assets/recording-assets.json` (7856 bytes, sha256 `e596b255c02916d7...`) - Machine-readable recording asset report
122
  - `docs/assets/recording-assets.md` (3566 bytes, sha256 `762375e6d7a8d984...`) - Human-readable recording asset report
123
  - `scripts/run_final_live_proof.py` (5814 bytes, sha256 `c6b9dc2fc9d7c670...`) - One-command final B2 plus Genblaze proof runner
124
- - `docs/submission.md` (3900 bytes, sha256 `53505f9edadbfa38...`) - Registration and submission plan
125
- - `tasks.json` (53812 bytes, sha256 `efcc82d093e67abf...`) - Machine-readable task board
126
  - `docs/assets/proofframe-local-ui-smoke.png` (364927 bytes, sha256 `cca671ad38bda4dc...`) - Local UI screenshot
127
  - `docs/assets/proofframe-review-console-smoke.png` (343618 bytes, sha256 `30620a33e3c7ab28...`) - Review console screenshot
128
  - `docs/assets/proofframe-hf-public-smoke.png` (741074 bytes, sha256 `5d6f68f7a4a2fdee...`) - Public mock demo screenshot
 
1
  # ProofFrame Submission Bundle
2
 
3
+ Created: `2026-06-28T17:59:53Z`
4
  Repository: https://github.com/adjcjh777/backblaze-proofframe
5
  Public mock demo: https://adjcjh-backblaze-proofframe.hf.space/?judge=1
6
  Devpost packet mode: `pre_live_safe`
 
28
  - `Dockerfile` (522 bytes, sha256 `6764f101746a802d...`) - Docker deployment image contract
29
  - `docs/prd.md` (3918 bytes, sha256 `ada7e9161b86483c...`) - Product requirements
30
  - `docs/spec.md` (6177 bytes, sha256 `d0d24f751da92adc...`) - Implementation specification
31
+ - `docs/deployment.md` (6104 bytes, sha256 `1a95d966a8c6b740...`) - Public demo deployment runbook
32
  - `docs/devpost_draft.md` (5613 bytes, sha256 `e08e3f25a04bab48...`) - Copy-ready Devpost fields
33
  - `docs/assets/devpost-submission-packet.json` (6270 bytes, sha256 `92b06cc47f68c410...`) - Machine-readable Devpost copy
34
  - `docs/assets/devpost-submission-packet.md` (5159 bytes, sha256 `00e03e34b62dfdfc...`) - Human-readable Devpost copy
 
38
  - `scripts/agent_handoff_check.py` (14559 bytes, sha256 `3ef180b6a92eb987...`) - Agent Bus and Codex handoff path checker
39
  - `docs/assets/agent-handoff-report.json` (2253 bytes, sha256 `d7db6502dbb8b257...`) - Machine-readable Agent handoff report
40
  - `docs/assets/agent-handoff-report.md` (1571 bytes, sha256 `058883dbe2520ad3...`) - Human-readable Agent handoff report
41
+ - `scripts/public_space_sync.py` (53157 bytes, sha256 `ee612700851206db...`) - Public Hugging Face Space sync verifier
42
+ - `docs/assets/public-space-sync-report.json` (12768 bytes, sha256 `ce2a6e145fd7db8b...`) - Machine-readable public Space sync report
43
+ - `docs/assets/public-space-sync-report.md` (5737 bytes, sha256 `b2f375fac4e211d7...`) - Human-readable public Space sync report
44
  - `scripts/public_demo_screenshot.py` (8926 bytes, sha256 `3eb5b0a003e383dd...`) - Public judge-mode screenshot verifier
45
  - `docs/assets/public-demo-screenshot-report.json` (2421 bytes, sha256 `e8ce08735a86a920...`) - Machine-readable public screenshot report
46
  - `docs/assets/public-demo-screenshot-report.md` (1418 bytes, sha256 `dce44c3bc2188131...`) - Human-readable public screenshot report
47
  - `scripts/devpost_form_kit.py` (12830 bytes, sha256 `b0173e698f4c3629...`) - Field-by-field Devpost form kit
48
  - `docs/assets/devpost-form-kit.json` (12483 bytes, sha256 `96196519c036e0aa...`) - Machine-readable Devpost form kit
49
  - `docs/assets/devpost-form-kit.md` (7496 bytes, sha256 `f6beeb3fe9e7f94d...`) - Human-readable Devpost form kit
50
+ - `scripts/devpost_submission_preview.py` (17329 bytes, sha256 `28ed8703ca6479fc...`) - One-page claim-safe Devpost preview
51
+ - `docs/assets/devpost-submission-preview.json` (11611 bytes, sha256 `4b879e8ef57d4c47...`) - Machine-readable Devpost preview
52
+ - `docs/assets/devpost-submission-preview.md` (5407 bytes, sha256 `760d948b804fbe97...`) - Human-readable Devpost preview
53
  - `scripts/devpost_submission_checklist.py` (11252 bytes, sha256 `78b8e1b70da428fd...`) - No-secret final Devpost web submission checklist
54
  - `docs/assets/devpost-submission-checklist.json` (16428 bytes, sha256 `c0076a55f6931805...`) - Machine-readable final Devpost submission checklist
55
  - `docs/assets/devpost-submission-checklist.md` (9319 bytes, sha256 `e45546c7334e78e3...`) - Human-readable final Devpost submission checklist
56
  - `scripts/judge_brief.py` (9968 bytes, sha256 `605a72a56e24b330...`) - Public-safe 30-second judge brief
57
+ - `docs/assets/judge-brief.json` (3734 bytes, sha256 `ec78162143608eff...`) - Machine-readable judge brief
58
+ - `docs/assets/judge-brief.md` (3000 bytes, sha256 `3bef5f0c09f38373...`) - Human-readable judge brief
59
  - `scripts/judge_crosswalk.py` (17642 bytes, sha256 `d9153174e330fd53...`) - Official criteria to evidence crosswalk
60
+ - `docs/assets/judge-crosswalk.json` (10219 bytes, sha256 `b0cadd6d3ab4a38f...`) - Machine-readable judge crosswalk
61
+ - `docs/assets/judge-crosswalk.md` (6157 bytes, sha256 `8123b9b158fe6ccc...`) - Human-readable judge crosswalk
62
  - `apps/web/index.html` (65568 bytes, sha256 `8a6c22850ffd3fc9...`) - Browser proof ledger UI
63
  - `docs/demo_script.md` (5856 bytes, sha256 `fbabf38ff87cca9b...`) - Video shot list and narration
64
  - `scripts/demo_storyboard.py` (11025 bytes, sha256 `e5d75956d6d4a20b...`) - Machine-checked demo video storyboard
 
79
  - `docs/assets/award-readiness-report.json` (11377 bytes, sha256 `66417f6e0c2a15d9...`) - Machine-readable award readiness report
80
  - `docs/assets/award-readiness-report.md` (4390 bytes, sha256 `5be57ca5d9cab53d...`) - Human-readable award readiness report
81
  - `scripts/final_submission_control.py` (31549 bytes, sha256 `c5ac3a7e236a122c...`) - Final submission control tower
82
+ - `docs/assets/final-submission-control.json` (23824 bytes, sha256 `ee8fd964a4468f58...`) - Machine-readable final control report
83
+ - `docs/assets/final-submission-control.md` (6633 bytes, sha256 `61f7c21341b1faa2...`) - Human-readable final control report
84
  - `scripts/final_operator_brief.py` (14478 bytes, sha256 `d64dd7c9b4a3f756...`) - No-secret final operator brief
85
  - `docs/assets/final-operator-brief.json` (8394 bytes, sha256 `48863d7be71d8618...`) - Machine-readable final operator brief
86
  - `docs/assets/final-operator-brief.md` (3618 bytes, sha256 `585065cd0eb9ee15...`) - Human-readable final operator brief
 
88
  - `docs/assets/final-launch-plan.json` (5650 bytes, sha256 `cdc3d112db423132...`) - Machine-readable final launch plan
89
  - `docs/assets/final-launch-plan.md` (4596 bytes, sha256 `7747b3177be9562a...`) - Human-readable final launch plan
90
  - `scripts/final_rehearsal.py` (17468 bytes, sha256 `bc44abb94771023f...`) - No-secret final submission rehearsal checklist
91
+ - `docs/assets/final-rehearsal-checklist.json` (16384 bytes, sha256 `cbe61ad2213e6dcc...`) - Machine-readable final rehearsal checklist
92
+ - `docs/assets/final-rehearsal-checklist.md` (6746 bytes, sha256 `f52eff10bd41671c...`) - Human-readable final rehearsal checklist
93
  - `scripts/submission_audit.py` (20524 bytes, sha256 `877f7e7c3e2f26d0...`) - Pre-submit audit gate
94
+ - `docs/assets/submission-audit-report.json` (5925 bytes, sha256 `b4fb975e9c749a5b...`) - Machine-readable submission audit report
95
+ - `docs/assets/submission-audit-report.md` (4459 bytes, sha256 `b962c5802d9b2b3a...`) - Human-readable submission audit report
96
  - `scripts/devpost_submission_receipt.py` (9209 bytes, sha256 `76c55e8ff1aeaa52...`) - Public-safe Devpost submission receipt generator
97
  - `docs/assets/devpost-submission-receipt.json` (1298 bytes, sha256 `bf646cf968665c8c...`) - Machine-readable Devpost submission receipt
98
  - `docs/assets/devpost-submission-receipt.md` (996 bytes, sha256 `af2fa18349d5c017...`) - Human-readable Devpost submission receipt
99
+ - `docs/evidence_package.md` (20209 bytes, sha256 `82e60fd2fa515d66...`) - Evidence package plan
100
  - `docs/public_claim_freeze.md` (4089 bytes, sha256 `735b9188feae74ea...`) - Verified-claim boundary
101
  - `docs/verification.md` (9585 bytes, sha256 `1e796ae03eebf21d...`) - Local, CI, Docker, and live proof runbook
102
  - `.env.final.example` (352 bytes, sha256 `d250e97bb0a653fa...`) - Redacted final B2 plus Genblaze env template
103
  - `scripts/secret_scan.py` (11105 bytes, sha256 `02aec3a4a6e9fd47...`) - Final secret scanner
104
+ - `docs/assets/secret-scan-report.json` (10339 bytes, sha256 `43107e3685aecf49...`) - Machine-readable secret scan report
105
+ - `docs/assets/secret-scan-report.md` (846 bytes, sha256 `8f194c402306736f...`) - Human-readable secret scan report
106
  - `docs/assets/b2-live-setup.json` (719 bytes, sha256 `a377923f48e112b1...`) - Non-secret B2 bucket setup record
107
  - `docs/assets/b2-live-setup.md` (864 bytes, sha256 `863b2a02e3d2824f...`) - Human-readable B2 bucket setup record
108
  - `scripts/b2_key_scope_checklist.py` (17240 bytes, sha256 `bb1e6140f10aa3ac...`) - No-secret Backblaze B2 application key scope checklist
 
124
  - `docs/assets/recording-assets.json` (7856 bytes, sha256 `e596b255c02916d7...`) - Machine-readable recording asset report
125
  - `docs/assets/recording-assets.md` (3566 bytes, sha256 `762375e6d7a8d984...`) - Human-readable recording asset report
126
  - `scripts/run_final_live_proof.py` (5814 bytes, sha256 `c6b9dc2fc9d7c670...`) - One-command final B2 plus Genblaze proof runner
127
+ - `docs/submission.md` (4000 bytes, sha256 `3800b9a0950779d0...`) - Registration and submission plan
128
+ - `tasks.json` (54412 bytes, sha256 `32355ab8e3c566ae...`) - Machine-readable task board
129
  - `docs/assets/proofframe-local-ui-smoke.png` (364927 bytes, sha256 `cca671ad38bda4dc...`) - Local UI screenshot
130
  - `docs/assets/proofframe-review-console-smoke.png` (343618 bytes, sha256 `30620a33e3c7ab28...`) - Review console screenshot
131
  - `docs/assets/proofframe-hf-public-smoke.png` (741074 bytes, sha256 `5d6f68f7a4a2fdee...`) - Public mock demo screenshot
docs/deployment.md CHANGED
@@ -9,7 +9,7 @@ Status: public mock demo deployed. A B2/Genblaze-backed public URL is still a fi
9
  - Space repo: https://huggingface.co/spaces/ADJCJH/backblaze-proofframe
10
  - Runtime: Docker Space, local storage, mock generation
11
  - Verified with: `python scripts/api_smoke.py --base-url https://adjcjh-backblaze-proofframe.hf.space`
12
- - Judge-mode slate, sponsor evidence model, in-app Judge Brief panel, in-app Criteria Crosswalk panel, in-app Recording Runbook panel, in-app Devpost Kit panel, in-app Submit Checklist panel, final report gate, Agent handoff report, final launch plan, B2 key scope checklist, judge brief, judge crosswalk, recording assets, mock video draft, Devpost form kit, submit checklist, post-credential live proof plan, submission bundle, and final control alignment verified after HF Space commit `a3aa614`: runtime reports sha `a3aa614b569d277d81229606783c4444ff5d2155`; public HTML contains `Judge recording slate`, `Sponsor Evidence Model`, `30-Second Judge Brief`, `Criteria Crosswalk`, `Recording Runbook`, `Devpost Kit`, `Submit Checklist`, `shouldAutoLoadJudgeDemo`, and `Final reports pending`; `/api/submission/gate` returns `pre_live_safe` with `pre_live_packet_pending` and `report_gate`; `/api/judge/crosswalk` returns `proofframe.judge_crosswalk.v1` with four rows and `safe_to_submit=false`; `/api/judge/recording` returns `proofframe.recording_assets.v1` with six shots and `final_video_ready=false`; `/api/judge/devpost` returns `proofframe.devpost_form_kit.v1` with 19 fields and `final_form_ready=false`; `/api/judge/submission-checklist` returns `proofframe.devpost_submission_checklist.v1` with preflight rows and `safe_to_submit=false`; raw Space artifacts `docs/assets/devpost-event-snapshot.json`, `docs/assets/final-submission-control.json`, `docs/assets/agent-handoff-report.json`, `docs/assets/final-launch-plan.json`, `docs/assets/b2-key-scope-checklist.json`, `docs/assets/judge-brief.json`, `docs/assets/judge-crosswalk.json`, `docs/assets/recording-assets.json`, `docs/assets/demo-video-draft.json`, `docs/assets/devpost-form-kit.json`, `docs/assets/devpost-submission-checklist.json`, `docs/assets/post-credential-live-proof-plan.json`, and `docs/assets/submission-bundle-manifest.json` return a fresh dynamic event snapshot, `safe_to_submit=false`, `handoff_ready`, `ready_for_credential_entry`, `safe_to_commit=true` plus `required_before_key_creation`, `safe_to_submit=false`, `pre_live_crosswalk_ready`, `mock_recording_ready`, `mock_video_draft_ready`, `pre_live_form_ready`, `pre_submit_blocked`, `plan_only`, and `safe_to_share=true` with `safe_to_submit=false`; public MP4 `docs/assets/proofframe-demo-draft.mp4` returns `video/mp4` with 761356 bytes; public API smoke passes in local/mock mode.
13
  - Screenshot: `docs/assets/proofframe-hf-public-smoke.png`
14
 
15
  This URL is safe to use in Devpost as a credential-free public demo before live B2/Genblaze proof, as long as the description says local/mock mode.
 
9
  - Space repo: https://huggingface.co/spaces/ADJCJH/backblaze-proofframe
10
  - Runtime: Docker Space, local storage, mock generation
11
  - Verified with: `python scripts/api_smoke.py --base-url https://adjcjh-backblaze-proofframe.hf.space`
12
+ - Judge-mode slate, sponsor evidence model, in-app Judge Brief panel, in-app Criteria Crosswalk panel, in-app Recording Runbook panel, in-app Devpost Kit panel, in-app Submit Checklist panel, final report gate, Agent handoff report, final launch plan, B2 key scope checklist, judge brief, judge crosswalk, public screenshot report, recording assets, mock video draft, Devpost form kit, submit checklist, post-credential live proof plan, submission bundle, and final control alignment verified after HF Space commit `a65c040`: runtime reports sha `a65c040e9f61df8a46d31af418f5ed67051ea4d9`; public HTML contains `Judge recording slate`, `Sponsor Evidence Model`, `30-Second Judge Brief`, `Criteria Crosswalk`, `Recording Runbook`, `Devpost Kit`, `Submit Checklist`, `shouldAutoLoadJudgeDemo`, and `Final reports pending`; `/api/submission/gate` returns `pre_live_safe` with `pre_live_packet_pending` and `report_gate`; `/api/judge/crosswalk` returns `proofframe.judge_crosswalk.v1` with four rows and `safe_to_submit=false`; `/api/judge/recording` returns `proofframe.recording_assets.v1` with six shots and `final_video_ready=false`; `/api/judge/devpost` returns `proofframe.devpost_form_kit.v1` with 19 fields and `final_form_ready=false`; `/api/judge/submission-checklist` returns `proofframe.devpost_submission_checklist.v1` with preflight rows and `safe_to_submit=false`; raw Space artifacts `docs/assets/devpost-event-snapshot.json`, `docs/assets/final-submission-control.json`, `docs/assets/agent-handoff-report.json`, `docs/assets/final-launch-plan.json`, `docs/assets/b2-key-scope-checklist.json`, `docs/assets/judge-brief.json`, `docs/assets/judge-crosswalk.json`, `docs/assets/public-demo-screenshot-report.json`, `docs/assets/recording-assets.json`, `docs/assets/demo-video-draft.json`, `docs/assets/devpost-form-kit.json`, `docs/assets/devpost-submission-checklist.json`, `docs/assets/post-credential-live-proof-plan.json`, and `docs/assets/submission-bundle-manifest.json` return a fresh dynamic event snapshot, `safe_to_submit=false`, `handoff_ready`, `ready_for_credential_entry`, `safe_to_commit=true` plus `required_before_key_creation`, `safe_to_submit=false`, `pre_live_crosswalk_ready`, `public_judge_screenshot_ready` with verified markers and 741074 screenshot bytes, `public_mock_verified`, `mock_video_draft_ready`, `pre_live_form_ready`, `pre_submit_blocked`, `plan_only`, and `safe_to_share=true` with `safe_to_submit=false`; public MP4 `docs/assets/proofframe-demo-draft.mp4` returns `video/mp4` with 761356 bytes; public API smoke and public_space_sync pass in local/mock mode.
13
  - Screenshot: `docs/assets/proofframe-hf-public-smoke.png`
14
 
15
  This URL is safe to use in Devpost as a credential-free public demo before live B2/Genblaze proof, as long as the description says local/mock mode.
docs/evidence_package.md CHANGED
@@ -51,10 +51,11 @@ This file is the internal source of truth for Devpost submission assets. Anythin
51
  | Public HF Space smoke screenshot | `docs/assets/proofframe-hf-public-smoke.png` | Public-ready in local/mock mode |
52
  | Public HF Space screenshot verification | `scripts/public_demo_screenshot.py`, `docs/assets/public-demo-screenshot-report.json`, `docs/assets/public-demo-screenshot-report.md` | Public-ready; refreshes the public judge-mode screenshot and verifies visible judge/sponsor/final-gate markers plus nonblank image stats |
53
  | Public HF Space API smoke | `python scripts/api_smoke.py --base-url https://adjcjh-backblaze-proofframe.hf.space` | Passed in local/mock mode; verifies judge brief, judge crosswalk, recording runbook, Devpost kit, and submit checklist endpoints stay schema-valid and claim-safe |
54
- | Public HF Space judge-mode sync | HF Space commit `a3aa614`; runtime sha `a3aa614b569d277d81229606783c4444ff5d2155`; public HTML contains `Judge recording slate`, `Sponsor Evidence Model`, `30-Second Judge Brief`, `Criteria Crosswalk`, `Recording Runbook`, `Devpost Kit`, `Submit Checklist`, `shouldAutoLoadJudgeDemo`, and `Final reports pending`; `/api/submission/gate` returns `pre_live_safe` with `pre_live_packet_pending` and `report_gate`; `/api/judge/crosswalk` returns `proofframe.judge_crosswalk.v1` with four rows and `safe_to_submit=false`; `/api/judge/recording` returns `proofframe.recording_assets.v1` with six shots and `final_video_ready=false`; `/api/judge/devpost` returns `proofframe.devpost_form_kit.v1` with 19 fields and `final_form_ready=false`; `/api/judge/submission-checklist` returns `proofframe.devpost_submission_checklist.v1` with preflight rows and `safe_to_submit=false`; raw Space `docs/assets/devpost-event-snapshot.json` returns a fresh dynamic participant count and `submission_open=true`; raw Space `docs/assets/final-submission-control.json` returns the same event snapshot context and `safe_to_submit=false`; raw Space `docs/assets/agent-handoff-report.json` returns `handoff_ready`; raw Space `docs/assets/final-launch-plan.json` returns `ready_for_credential_entry`; raw Space `docs/assets/b2-key-scope-checklist.json` returns `proofframe.b2_key_scope_checklist.v1` with `safe_to_commit=true`, pre-key confirmation status `required_before_key_creation`, bucket `proofframe-demo-a6b4e49`, prefix `campaigns/`, and required `writeFiles` plus `listAllBucketNames`; raw Space `docs/assets/judge-brief.json` returns `safe_to_submit=false`; raw Space `docs/assets/judge-crosswalk.json` returns `pre_live_crosswalk_ready` with `safe_to_submit=false`; raw Space `docs/assets/recording-assets.json` returns `public_mock_verified` with `final_video_ready=false`; raw Space `docs/assets/demo-video-draft.json` returns `mock_video_draft_ready` with `safe_to_submit=false`; public MP4 `docs/assets/proofframe-demo-draft.mp4` returns `video/mp4` with 761356 bytes; raw Space `docs/assets/devpost-form-kit.json` returns `pre_live_form_ready` with `final_form_ready=false`; raw Space `docs/assets/devpost-submission-checklist.json` returns `pre_submit_blocked` with `safe_to_submit=false`; API smoke passes | Public-ready in local/mock mode |
 
55
  | Official Devpost event snapshot | `scripts/devpost_event_snapshot.py`, `docs/assets/devpost-event-snapshot.json`, `docs/assets/devpost-event-snapshot.md` | Public-ready; refreshes deadline, participant count, requirements, and judging criteria from official Devpost pages |
56
  | Agent handoff consistency | `scripts/agent_handoff_check.py`, `docs/assets/agent-handoff-report.json`, `docs/assets/agent-handoff-report.md` | Public-ready; verifies AGENTS.md points future Codex and Agent Bus sessions at the current repo path |
57
- | Public Space sync report | `scripts/public_space_sync.py`, `docs/assets/public-space-sync-report.json`, `docs/assets/public-space-sync-report.md` | Public-ready; verifies HF Space metadata/runtime sha, raw handoff report, raw Devpost event snapshot, raw final launch plan, raw B2 key scope checklist, raw judge brief, raw judge crosswalk, raw recording assets, raw mock video draft report, public MP4 readability, raw Devpost kit, raw submit checklist, raw post-credential live proof plan, raw submission bundle manifest, local/mock health, fail-closed submission gate, and judge HTML markers |
58
  | Judge brief | `scripts/judge_brief.py`, `docs/assets/judge-brief.json`, `docs/assets/judge-brief.md` | Public-ready; 30-second judge framing with safe claims, current blockers, walkthrough, and evidence links |
59
  | Judge crosswalk | `scripts/judge_crosswalk.py`, `GET /api/judge/crosswalk`, `docs/assets/judge-crosswalk.json`, `docs/assets/judge-crosswalk.md` | Public-ready; maps official judging criteria and submission requirements to evidence artifacts, safe claims, final gates, and demo shots, and powers the in-app Criteria Crosswalk panel |
60
  | Final rehearsal checklist | `scripts/final_rehearsal.py`, `docs/assets/final-rehearsal-checklist.json`, `docs/assets/final-rehearsal-checklist.md` | Internal-ready; no-secret sequence for credential entry, live proof, video, audit, Devpost receipt, and final green gate |
 
51
  | Public HF Space smoke screenshot | `docs/assets/proofframe-hf-public-smoke.png` | Public-ready in local/mock mode |
52
  | Public HF Space screenshot verification | `scripts/public_demo_screenshot.py`, `docs/assets/public-demo-screenshot-report.json`, `docs/assets/public-demo-screenshot-report.md` | Public-ready; refreshes the public judge-mode screenshot and verifies visible judge/sponsor/final-gate markers plus nonblank image stats |
53
  | Public HF Space API smoke | `python scripts/api_smoke.py --base-url https://adjcjh-backblaze-proofframe.hf.space` | Passed in local/mock mode; verifies judge brief, judge crosswalk, recording runbook, Devpost kit, and submit checklist endpoints stay schema-valid and claim-safe |
54
+ | Public HF Space judge-mode sync | HF Space commit `a65c040`; runtime sha `a65c040e9f61df8a46d31af418f5ed67051ea4d9`; public HTML contains `Judge recording slate`, `Sponsor Evidence Model`, `30-Second Judge Brief`, `Criteria Crosswalk`, `Recording Runbook`, `Devpost Kit`, `Submit Checklist`, `shouldAutoLoadJudgeDemo`, and `Final reports pending`; `/api/submission/gate` returns `pre_live_safe` with `pre_live_packet_pending` and `report_gate`; `/api/judge/crosswalk` returns `proofframe.judge_crosswalk.v1` with four rows and `safe_to_submit=false`; `/api/judge/recording` returns `proofframe.recording_assets.v1` with six shots and `final_video_ready=false`; `/api/judge/devpost` returns `proofframe.devpost_form_kit.v1` with 19 fields and `final_form_ready=false`; `/api/judge/submission-checklist` returns `proofframe.devpost_submission_checklist.v1` with preflight rows and `safe_to_submit=false`; raw Space `docs/assets/devpost-event-snapshot.json` returns a fresh dynamic participant count and `submission_open=true`; raw Space `docs/assets/final-submission-control.json` returns the same event snapshot context and `safe_to_submit=false`; raw Space `docs/assets/agent-handoff-report.json` returns `handoff_ready`; raw Space `docs/assets/final-launch-plan.json` returns `ready_for_credential_entry`; raw Space `docs/assets/b2-key-scope-checklist.json` returns `proofframe.b2_key_scope_checklist.v1` with `safe_to_commit=true`, pre-key confirmation status `required_before_key_creation`, bucket `proofframe-demo-a6b4e49`, prefix `campaigns/`, and required `writeFiles` plus `listAllBucketNames`; raw Space `docs/assets/judge-brief.json` returns `safe_to_submit=false`; raw Space `docs/assets/judge-crosswalk.json` returns `pre_live_crosswalk_ready` with `safe_to_submit=false`; raw Space `docs/assets/public-demo-screenshot-report.json` returns `public_judge_screenshot_ready` with visible/html markers verified and 741074 screenshot bytes; raw Space `docs/assets/recording-assets.json` returns `public_mock_verified` with `final_video_ready=false`; raw Space `docs/assets/demo-video-draft.json` returns `mock_video_draft_ready` with `safe_to_submit=false`; public MP4 `docs/assets/proofframe-demo-draft.mp4` returns `video/mp4` with 761356 bytes; raw Space `docs/assets/devpost-form-kit.json` returns `pre_live_form_ready` with `final_form_ready=false`; raw Space `docs/assets/devpost-submission-checklist.json` returns `pre_submit_blocked` with `safe_to_submit=false`; API smoke and public_space_sync pass | Public-ready in local/mock mode |
55
+ | Devpost submission preview | `scripts/devpost_submission_preview.py`, `docs/assets/devpost-submission-preview.json`, `docs/assets/devpost-submission-preview.md` | Public-ready; one-page copy/evidence/readiness preview that is safe to share before live proof but explicitly not safe to submit |
56
  | Official Devpost event snapshot | `scripts/devpost_event_snapshot.py`, `docs/assets/devpost-event-snapshot.json`, `docs/assets/devpost-event-snapshot.md` | Public-ready; refreshes deadline, participant count, requirements, and judging criteria from official Devpost pages |
57
  | Agent handoff consistency | `scripts/agent_handoff_check.py`, `docs/assets/agent-handoff-report.json`, `docs/assets/agent-handoff-report.md` | Public-ready; verifies AGENTS.md points future Codex and Agent Bus sessions at the current repo path |
58
+ | Public Space sync report | `scripts/public_space_sync.py`, `docs/assets/public-space-sync-report.json`, `docs/assets/public-space-sync-report.md` | Public-ready; verifies HF Space metadata/runtime sha, raw handoff report, raw Devpost event snapshot, raw final launch plan, raw B2 key scope checklist, raw judge brief, raw judge crosswalk, raw public screenshot report, raw recording assets, raw mock video draft report, public MP4 readability, raw Devpost kit, raw Devpost submission preview, raw submit checklist, raw post-credential live proof plan, raw submission bundle manifest, local/mock health, fail-closed submission gate, and judge HTML markers |
59
  | Judge brief | `scripts/judge_brief.py`, `docs/assets/judge-brief.json`, `docs/assets/judge-brief.md` | Public-ready; 30-second judge framing with safe claims, current blockers, walkthrough, and evidence links |
60
  | Judge crosswalk | `scripts/judge_crosswalk.py`, `GET /api/judge/crosswalk`, `docs/assets/judge-crosswalk.json`, `docs/assets/judge-crosswalk.md` | Public-ready; maps official judging criteria and submission requirements to evidence artifacts, safe claims, final gates, and demo shots, and powers the in-app Criteria Crosswalk panel |
61
  | Final rehearsal checklist | `scripts/final_rehearsal.py`, `docs/assets/final-rehearsal-checklist.json`, `docs/assets/final-rehearsal-checklist.md` | Internal-ready; no-secret sequence for credential entry, live proof, video, audit, Devpost receipt, and final green gate |
docs/submission.md CHANGED
@@ -43,6 +43,7 @@ Codex can handle:
43
  - B2/Genblaze-backed demo URL or Docker instructions after T020/T021.
44
  - Devpost text from `docs/devpost_draft.md`.
45
  - Field-by-field Devpost form kit from `docs/assets/devpost-form-kit.md` and `.json`.
 
46
  - Final Devpost web submission checklist from `docs/assets/devpost-submission-checklist.md` and `.json`.
47
  - No-secret B2 key scope checklist from `docs/assets/b2-key-scope-checklist.md` and `.json`.
48
  - Official criteria crosswalk from `docs/assets/judge-crosswalk.md` and `.json`.
 
43
  - B2/Genblaze-backed demo URL or Docker instructions after T020/T021.
44
  - Devpost text from `docs/devpost_draft.md`.
45
  - Field-by-field Devpost form kit from `docs/assets/devpost-form-kit.md` and `.json`.
46
+ - One-page Devpost submission preview from `docs/assets/devpost-submission-preview.md` and `.json`.
47
  - Final Devpost web submission checklist from `docs/assets/devpost-submission-checklist.md` and `.json`.
48
  - No-secret B2 key scope checklist from `docs/assets/b2-key-scope-checklist.md` and `.json`.
49
  - Official criteria crosswalk from `docs/assets/judge-crosswalk.md` and `.json`.
scripts/devpost_submission_preview.py ADDED
@@ -0,0 +1,430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Build a one-page, claim-safe Devpost preview for judges and final review."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ from datetime import datetime, timezone
8
+ import json
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+
13
+ ROOT = Path(__file__).resolve().parents[1]
14
+ DEFAULT_JSON = ROOT / "docs" / "assets" / "devpost-submission-preview.json"
15
+ DEFAULT_MD = ROOT / "docs" / "assets" / "devpost-submission-preview.md"
16
+ SCHEMA = "proofframe.devpost_submission_preview.v1"
17
+
18
+ SOURCE_SPECS = {
19
+ "packet": ("docs/assets/devpost-submission-packet.json", "proofframe.devpost_packet.v1"),
20
+ "form_kit": ("docs/assets/devpost-form-kit.json", "proofframe.devpost_form_kit.v1"),
21
+ "judge_brief": ("docs/assets/judge-brief.json", "proofframe.judge_brief.v1"),
22
+ "judge_crosswalk": ("docs/assets/judge-crosswalk.json", "proofframe.judge_crosswalk.v1"),
23
+ "public_screenshot": (
24
+ "docs/assets/public-demo-screenshot-report.json",
25
+ "proofframe.public_demo_screenshot.v1",
26
+ ),
27
+ "public_space_sync": (
28
+ "docs/assets/public-space-sync-report.json",
29
+ "proofframe.public_space_sync.v1",
30
+ ),
31
+ "final_control": (
32
+ "docs/assets/final-submission-control.json",
33
+ "proofframe.final_submission_control.v1",
34
+ ),
35
+ "submit_checklist": (
36
+ "docs/assets/devpost-submission-checklist.json",
37
+ "proofframe.devpost_submission_checklist.v1",
38
+ ),
39
+ "submission_audit": (
40
+ "docs/assets/submission-audit-report.json",
41
+ "proofframe.submission_audit.v1",
42
+ ),
43
+ "secret_scan": ("docs/assets/secret-scan-report.json", "proofframe.secret_scan.v1"),
44
+ }
45
+
46
+ FINAL_BLOCKER_LABELS = {
47
+ "b2_live_proof": "live Backblaze B2 proof",
48
+ "genblaze_live_proof": "live Genblaze proof",
49
+ "public_video": "final public video",
50
+ "public_video_check": "public video URL check",
51
+ "final_secret_scan": "final secret scan task completion",
52
+ "final_submission_audit": "strict final submission audit",
53
+ "devpost_submitted": "Devpost submission receipt",
54
+ }
55
+
56
+
57
+ def utc_now() -> str:
58
+ return datetime.now(timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
59
+
60
+
61
+ def load_json(path: Path) -> dict[str, Any] | None:
62
+ try:
63
+ data = json.loads(path.read_text(encoding="utf-8"))
64
+ except (FileNotFoundError, json.JSONDecodeError):
65
+ return None
66
+ return data if isinstance(data, dict) else None
67
+
68
+
69
+ def dict_field(value: dict[str, Any] | None, key: str) -> dict[str, Any]:
70
+ if not value:
71
+ return {}
72
+ field = value.get(key)
73
+ return field if isinstance(field, dict) else {}
74
+
75
+
76
+ def list_field(value: dict[str, Any] | None, key: str) -> list[Any]:
77
+ if not value:
78
+ return []
79
+ field = value.get(key)
80
+ return field if isinstance(field, list) else []
81
+
82
+
83
+ def source_record(root: Path, source_id: str, relative_path: str, expected_schema: str) -> dict[str, Any]:
84
+ data = load_json(root / relative_path)
85
+ return {
86
+ "id": source_id,
87
+ "path": relative_path,
88
+ "present": data is not None,
89
+ "schema": data.get("schema") if data else None,
90
+ "schema_ok": bool(data and data.get("schema") == expected_schema),
91
+ "mode": data.get("mode") if data else None,
92
+ "ok": data.get("ok") if data else None,
93
+ }
94
+
95
+
96
+ def source_status(root: Path) -> dict[str, dict[str, Any]]:
97
+ return {
98
+ source_id: source_record(root, source_id, relative_path, expected_schema)
99
+ for source_id, (relative_path, expected_schema) in SOURCE_SPECS.items()
100
+ }
101
+
102
+
103
+ def text_list(items: list[Any]) -> list[str]:
104
+ return [str(item).strip() for item in items if str(item).strip()]
105
+
106
+
107
+ def screenshot_ready(report: dict[str, Any] | None) -> bool:
108
+ markers = dict_field(report, "markers")
109
+ screenshot = dict_field(report, "screenshot")
110
+ return bool(
111
+ report
112
+ and report.get("schema") == "proofframe.public_demo_screenshot.v1"
113
+ and report.get("ok") is True
114
+ and report.get("safe_to_commit") is True
115
+ and markers.get("visible_ok") is True
116
+ and markers.get("html_ok") is True
117
+ and screenshot.get("path") == "docs/assets/proofframe-hf-public-smoke.png"
118
+ and (screenshot.get("bytes") or 0) >= 100_000
119
+ and (screenshot.get("width") or 0) >= 1200
120
+ and (screenshot.get("height") or 0) >= 900
121
+ )
122
+
123
+
124
+ def public_space_ready(report: dict[str, Any] | None) -> bool:
125
+ observed = dict_field(report, "observed")
126
+ screenshot = dict_field(observed, "public_demo_screenshot")
127
+ return bool(
128
+ report
129
+ and report.get("schema") == "proofframe.public_space_sync.v1"
130
+ and report.get("ok") is True
131
+ and report.get("mode") == "public_space_synced"
132
+ and screenshot.get("ok") is True
133
+ and screenshot.get("visible_ok") is True
134
+ and screenshot.get("html_ok") is True
135
+ )
136
+
137
+
138
+ def final_blockers(control: dict[str, Any] | None) -> list[dict[str, Any]]:
139
+ blockers = []
140
+ for item in list_field(control, "blocking_items"):
141
+ if not isinstance(item, dict):
142
+ continue
143
+ blocker_id = str(item.get("id") or "")
144
+ blockers.append(
145
+ {
146
+ "id": blocker_id,
147
+ "label": FINAL_BLOCKER_LABELS.get(blocker_id, str(item.get("label") or blocker_id)),
148
+ "detail": str(item.get("detail") or ""),
149
+ "evidence": str(item.get("evidence") or ""),
150
+ }
151
+ )
152
+ return blockers
153
+
154
+
155
+ def field_rollup(form_kit: dict[str, Any] | None) -> dict[str, Any]:
156
+ fields = [field for field in list_field(form_kit, "fields") if isinstance(field, dict)]
157
+ final_pending = [
158
+ {"id": field.get("id"), "label": field.get("label")}
159
+ for field in fields
160
+ if field.get("ok_for_final") is not True
161
+ ]
162
+ return {
163
+ "field_count": len(fields),
164
+ "mock_ready": bool(form_kit and form_kit.get("mock_form_ready") is True),
165
+ "final_ready": bool(form_kit and form_kit.get("final_form_ready") is True),
166
+ "public_video_ready": bool(form_kit and form_kit.get("public_video_ready") is True),
167
+ "final_pending_fields": final_pending,
168
+ }
169
+
170
+
171
+ def criteria_rollup(crosswalk: dict[str, Any] | None) -> dict[str, Any]:
172
+ rows = [row for row in list_field(crosswalk, "rows") if isinstance(row, dict)]
173
+ official_criteria = [
174
+ str(item.get("name"))
175
+ for item in list_field(crosswalk, "official_criteria")
176
+ if isinstance(item, dict) and item.get("present") is True
177
+ ]
178
+ return {
179
+ "mode": crosswalk.get("mode") if crosswalk else None,
180
+ "safe_to_submit": crosswalk.get("safe_to_submit") if crosswalk else None,
181
+ "official_criteria": official_criteria,
182
+ "row_count": len(rows),
183
+ }
184
+
185
+
186
+ def build_preview(root: Path = ROOT) -> dict[str, Any]:
187
+ root = root.resolve()
188
+ packet = load_json(root / "docs/assets/devpost-submission-packet.json")
189
+ form_kit = load_json(root / "docs/assets/devpost-form-kit.json")
190
+ judge_brief = load_json(root / "docs/assets/judge-brief.json")
191
+ crosswalk = load_json(root / "docs/assets/judge-crosswalk.json")
192
+ public_screenshot = load_json(root / "docs/assets/public-demo-screenshot-report.json")
193
+ public_space = load_json(root / "docs/assets/public-space-sync-report.json")
194
+ final_control = load_json(root / "docs/assets/final-submission-control.json")
195
+ submit_checklist = load_json(root / "docs/assets/devpost-submission-checklist.json")
196
+ submission_audit = load_json(root / "docs/assets/submission-audit-report.json")
197
+ secret_scan = load_json(root / "docs/assets/secret-scan-report.json")
198
+
199
+ sources = source_status(root)
200
+ source_schemas_ok = all(source["schema_ok"] for source in sources.values())
201
+ screenshot_ok = screenshot_ready(public_screenshot)
202
+ public_space_ok = public_space_ready(public_space)
203
+ form = field_rollup(form_kit)
204
+ blockers = final_blockers(final_control)
205
+ safe_to_share = bool(
206
+ source_schemas_ok
207
+ and screenshot_ok
208
+ and public_space_ok
209
+ and form["mock_ready"]
210
+ and secret_scan
211
+ and secret_scan.get("ok") is True
212
+ and packet
213
+ and packet.get("mode") in {"pre_live_safe", "post_live_verified"}
214
+ )
215
+ safe_to_submit = bool(
216
+ safe_to_share
217
+ and packet
218
+ and packet.get("mode") == "post_live_verified"
219
+ and form["final_ready"]
220
+ and final_control
221
+ and final_control.get("safe_to_submit") is True
222
+ and submit_checklist
223
+ and submit_checklist.get("safe_to_submit") is True
224
+ and submission_audit
225
+ and submission_audit.get("ok") is True
226
+ and not blockers
227
+ )
228
+ mode = "final_preview_ready" if safe_to_submit else "pre_live_preview_ready" if safe_to_share else "preview_blocked"
229
+
230
+ links = dict_field(judge_brief, "links")
231
+ project = {
232
+ "name": packet.get("project_name") if packet else "ProofFrame",
233
+ "tagline": packet.get("tagline") if packet else None,
234
+ "one_liner": packet.get("one_liner") if packet else None,
235
+ "repository_url": packet.get("repository_url") if packet else links.get("repository"),
236
+ "demo_url": packet.get("demo_url") if packet else links.get("public_demo"),
237
+ "video_url": packet.get("video_url") if packet else links.get("devpost_video"),
238
+ }
239
+ return {
240
+ "schema": SCHEMA,
241
+ "created_at": utc_now(),
242
+ "mode": mode,
243
+ "ok": safe_to_share,
244
+ "safe_to_share": safe_to_share,
245
+ "safe_to_submit": safe_to_submit,
246
+ "project": project,
247
+ "copy_blocks": {
248
+ "thirty_second_pitch": judge_brief.get("judge_opening_30s") if judge_brief else "",
249
+ "short_description": packet.get("short_description") if packet else "",
250
+ "backblaze_b2_usage": packet.get("b2_usage") if packet else "",
251
+ "genblaze_usage": packet.get("genblaze_usage") if packet else "",
252
+ "accomplishments": text_list(packet.get("accomplishments", []) if packet else []),
253
+ "whats_next": text_list(packet.get("whats_next", []) if packet else []),
254
+ "judge_note": (
255
+ "Use this preview as a copy/reference pack. It is not final-submittable until "
256
+ "safe_to_submit becomes true."
257
+ ),
258
+ },
259
+ "submission_readiness": {
260
+ "packet_mode": packet.get("mode") if packet else None,
261
+ "form_mode": form_kit.get("mode") if form_kit else None,
262
+ "final_control_mode": final_control.get("mode") if final_control else None,
263
+ "submit_checklist_mode": submit_checklist.get("mode") if submit_checklist else None,
264
+ "submission_audit_mode": submission_audit.get("mode") if submission_audit else None,
265
+ "secret_scan_mode": secret_scan.get("mode") if secret_scan else None,
266
+ "public_space_mode": public_space.get("mode") if public_space else None,
267
+ "public_screenshot_mode": public_screenshot.get("mode") if public_screenshot else None,
268
+ "final_blockers": blockers,
269
+ },
270
+ "field_rollup": form,
271
+ "criteria_rollup": criteria_rollup(crosswalk),
272
+ "evidence_links": {
273
+ "public_demo": project["demo_url"],
274
+ "repository": project["repository_url"],
275
+ "public_screenshot": "docs/assets/proofframe-hf-public-smoke.png",
276
+ "screenshot_report": "docs/assets/public-demo-screenshot-report.json",
277
+ "public_space_sync": "docs/assets/public-space-sync-report.json",
278
+ "judge_brief": "docs/assets/judge-brief.json",
279
+ "judge_crosswalk": "docs/assets/judge-crosswalk.json",
280
+ "form_kit": "docs/assets/devpost-form-kit.json",
281
+ "final_control": "docs/assets/final-submission-control.json",
282
+ "submission_bundle": "docs/assets/submission-bundle-manifest.json",
283
+ },
284
+ "claim_boundary": [
285
+ "Public demo evidence proves only the credential-free local/mock judge flow.",
286
+ "Do not claim completed live Backblaze B2 storage until T020 has sanitized live evidence.",
287
+ "Do not claim completed live Genblaze generation until T021 has sanitized live evidence.",
288
+ "Do not submit this packet as final until safe_to_submit is true.",
289
+ ],
290
+ "source_status": sources,
291
+ "next_actions": next_actions(
292
+ safe_to_submit=safe_to_submit,
293
+ blockers=blockers,
294
+ form=form,
295
+ public_space_ok=public_space_ok,
296
+ screenshot_ok=screenshot_ok,
297
+ ),
298
+ }
299
+
300
+
301
+ def next_actions(
302
+ *,
303
+ safe_to_submit: bool,
304
+ blockers: list[dict[str, Any]],
305
+ form: dict[str, Any],
306
+ public_space_ok: bool,
307
+ screenshot_ok: bool,
308
+ ) -> list[str]:
309
+ if safe_to_submit:
310
+ return ["Use this preview to fill Devpost and archive the submission receipt."]
311
+ actions: list[str] = []
312
+ if not public_space_ok:
313
+ actions.append("Refresh the public Hugging Face Space and rerun public_space_sync.")
314
+ if not screenshot_ok:
315
+ actions.append("Regenerate the public judge-mode screenshot report.")
316
+ if form["final_pending_fields"]:
317
+ labels = ", ".join(str(item["label"]) for item in form["final_pending_fields"][:4])
318
+ actions.append(f"Finalize Devpost fields: {labels}.")
319
+ for blocker in blockers:
320
+ actions.append(f"Resolve final blocker: {blocker['label']}.")
321
+ actions.append("Rerun secret scan, strict final audit, and final submission control before Devpost submit.")
322
+ return list(dict.fromkeys(actions))[:8]
323
+
324
+
325
+ def render_markdown(preview: dict[str, Any]) -> str:
326
+ project = preview["project"]
327
+ readiness = preview["submission_readiness"]
328
+ lines = [
329
+ "# ProofFrame Devpost Submission Preview",
330
+ "",
331
+ f"Mode: `{preview['mode']}`",
332
+ f"Safe to share: `{str(preview['safe_to_share']).lower()}`",
333
+ f"Safe to submit: `{str(preview['safe_to_submit']).lower()}`",
334
+ "",
335
+ "## Project",
336
+ "",
337
+ f"- Name: {project.get('name')}",
338
+ f"- Tagline: {project.get('tagline')}",
339
+ f"- Repository: {project.get('repository_url')}",
340
+ f"- Demo: {project.get('demo_url')}",
341
+ f"- Video: {project.get('video_url')}",
342
+ "",
343
+ "## Copy Blocks",
344
+ "",
345
+ "### 30-Second Pitch",
346
+ "",
347
+ preview["copy_blocks"]["thirty_second_pitch"],
348
+ "",
349
+ "### Short Description",
350
+ "",
351
+ preview["copy_blocks"]["short_description"],
352
+ "",
353
+ "### Backblaze B2 Usage",
354
+ "",
355
+ preview["copy_blocks"]["backblaze_b2_usage"],
356
+ "",
357
+ "### Genblaze Usage",
358
+ "",
359
+ preview["copy_blocks"]["genblaze_usage"],
360
+ "",
361
+ "## Evidence Links",
362
+ "",
363
+ ]
364
+ for label, value in preview["evidence_links"].items():
365
+ lines.append(f"- `{label}`: {value}")
366
+ lines.extend(["", "## Readiness", ""])
367
+ for key in [
368
+ "packet_mode",
369
+ "form_mode",
370
+ "final_control_mode",
371
+ "submit_checklist_mode",
372
+ "submission_audit_mode",
373
+ "secret_scan_mode",
374
+ "public_space_mode",
375
+ "public_screenshot_mode",
376
+ ]:
377
+ lines.append(f"- `{key}`: `{readiness.get(key)}`")
378
+ lines.extend(["", "## Final Blockers", ""])
379
+ if readiness["final_blockers"]:
380
+ for blocker in readiness["final_blockers"]:
381
+ lines.append(f"- `{blocker['id']}`: {blocker['label']} - {blocker['detail']}")
382
+ else:
383
+ lines.append("- None.")
384
+ lines.extend(["", "## Claim Boundary", ""])
385
+ lines.extend(f"- {item}" for item in preview["claim_boundary"])
386
+ lines.extend(["", "## Next Actions", ""])
387
+ lines.extend(f"- {action}" for action in preview["next_actions"])
388
+ return "\n".join(lines).rstrip() + "\n"
389
+
390
+
391
+ def write_outputs(preview: dict[str, Any], json_path: Path, markdown_path: Path) -> None:
392
+ json_path.parent.mkdir(parents=True, exist_ok=True)
393
+ markdown_path.parent.mkdir(parents=True, exist_ok=True)
394
+ json_path.write_text(json.dumps(preview, indent=2) + "\n", encoding="utf-8")
395
+ markdown_path.write_text(render_markdown(preview), encoding="utf-8")
396
+
397
+
398
+ def build_parser() -> argparse.ArgumentParser:
399
+ parser = argparse.ArgumentParser(description="Build a claim-safe ProofFrame Devpost preview.")
400
+ parser.add_argument("--root", type=Path, default=ROOT)
401
+ parser.add_argument("--json-out", type=Path, default=DEFAULT_JSON)
402
+ parser.add_argument("--markdown-out", type=Path, default=DEFAULT_MD)
403
+ parser.add_argument("--strict-final", action="store_true", help="Fail unless safe_to_submit is true.")
404
+ return parser
405
+
406
+
407
+ def main() -> None:
408
+ args = build_parser().parse_args()
409
+ preview = build_preview(args.root)
410
+ write_outputs(preview, args.json_out, args.markdown_out)
411
+ ok = preview["safe_to_submit"] if args.strict_final else preview["safe_to_share"]
412
+ print(
413
+ json.dumps(
414
+ {
415
+ "ok": ok,
416
+ "mode": preview["mode"],
417
+ "safe_to_share": preview["safe_to_share"],
418
+ "safe_to_submit": preview["safe_to_submit"],
419
+ "json": str(args.json_out),
420
+ "markdown": str(args.markdown_out),
421
+ "next_actions": preview["next_actions"][:4],
422
+ },
423
+ indent=2,
424
+ )
425
+ )
426
+ raise SystemExit(0 if ok else 2)
427
+
428
+
429
+ if __name__ == "__main__":
430
+ main()
scripts/public_space_sync.py CHANGED
@@ -19,7 +19,7 @@ SCHEMA = "proofframe.public_space_sync.v1"
19
 
20
  SPACE_ID = "ADJCJH/backblaze-proofframe"
21
  SPACE_HOST = "https://adjcjh-backblaze-proofframe.hf.space"
22
- EXPECTED_SPACE_SHA = "6a909b229afd3f08099877fb4cff633438f72ba5"
23
  TIMEOUT_SECONDS = 30
24
  DRAFT_VIDEO_MIN_BYTES = 100_000
25
  EVENT_SNAPSHOT_MAX_AGE_DAYS = 14
@@ -57,6 +57,8 @@ REQUIRED_BUNDLE_ARTIFACT_IDS = {
57
  "public_space_sync_json",
58
  "public_demo_screenshot_json",
59
  "public_demo_screenshot_script",
 
 
60
  "post_credential_live_proof_json",
61
  "post_credential_live_proof_script",
62
  "b2_key_scope_checklist_json",
@@ -262,6 +264,7 @@ def build_report(
262
  demo_video_draft_url = raw_file_url(space_id, "docs/assets/demo-video-draft.json")
263
  demo_video_draft_mp4_url = resolve_file_url(space_id, "docs/assets/proofframe-demo-draft.mp4")
264
  devpost_form_kit_url = raw_file_url(space_id, "docs/assets/devpost-form-kit.json")
 
265
  submit_checklist_url = raw_file_url(space_id, "docs/assets/devpost-submission-checklist.json")
266
  post_credential_plan_url = raw_file_url(space_id, "docs/assets/post-credential-live-proof-plan.json")
267
  submission_bundle_url = raw_file_url(space_id, "docs/assets/submission-bundle-manifest.json")
@@ -282,6 +285,7 @@ def build_report(
282
  demo_video_draft_result = fetcher(demo_video_draft_url, TIMEOUT_SECONDS)
283
  demo_video_draft_mp4_result = fetcher(demo_video_draft_mp4_url, TIMEOUT_SECONDS)
284
  devpost_form_kit_result = fetcher(devpost_form_kit_url, TIMEOUT_SECONDS)
 
285
  submit_checklist_result = fetcher(submit_checklist_url, TIMEOUT_SECONDS)
286
  post_credential_plan_result = fetcher(post_credential_plan_url, TIMEOUT_SECONDS)
287
  submission_bundle_result = fetcher(submission_bundle_url, TIMEOUT_SECONDS)
@@ -301,6 +305,7 @@ def build_report(
301
  public_demo_screenshot = parse_json(public_demo_screenshot_result)
302
  demo_video_draft = parse_json(demo_video_draft_result)
303
  devpost_form_kit = parse_json(devpost_form_kit_result)
 
304
  submit_checklist = parse_json(submit_checklist_result)
305
  post_credential_plan = parse_json(post_credential_plan_result)
306
  submission_bundle = parse_json(submission_bundle_result)
@@ -390,6 +395,36 @@ def build_report(
390
  and (public_demo_screenshot_image.get("width") or 0) >= 1200
391
  and (public_demo_screenshot_image.get("height") or 0) >= 900
392
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  b2_key_scope_expected = dict_field(b2_key_scope_checklist, "expected_key")
394
  b2_key_scope_bucket = dict_field(b2_key_scope_expected, "bucket_scope")
395
  b2_key_scope_prefix = dict_field(b2_key_scope_expected, "file_name_prefix")
@@ -646,6 +681,19 @@ def build_report(
646
  ),
647
  devpost_form_kit_url,
648
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
649
  check_item(
650
  "raw_submit_checklist",
651
  "Raw Devpost submit checklist is public and fail-closed",
@@ -844,6 +892,13 @@ def build_report(
844
  public_demo_screenshot_image.get("height"),
845
  ],
846
  },
 
 
 
 
 
 
 
847
  "demo_video_draft_mode": demo_video_draft.get("mode") if demo_video_draft else None,
848
  "demo_video_draft_safe_to_submit": (
849
  demo_video_draft.get("safe_to_submit") if demo_video_draft else None
@@ -884,6 +939,9 @@ def build_report(
884
  "raw_public_demo_screenshot": public_demo_screenshot_url,
885
  "raw_demo_video_draft": demo_video_draft_url,
886
  "demo_video_draft_mp4": demo_video_draft_mp4_url,
 
 
 
887
  "raw_post_credential_plan": post_credential_plan_url,
888
  "raw_submission_bundle": submission_bundle_url,
889
  "judge": judge_url,
@@ -922,6 +980,8 @@ def next_actions(checks: list[dict[str, Any]]) -> list[str]:
922
  actions.append("Regenerate and upload docs/assets/proofframe-demo-draft.mp4 to the Space.")
923
  if "raw_devpost_form_kit" in failed:
924
  actions.append("Regenerate and upload docs/assets/devpost-form-kit.json to the Space.")
 
 
925
  if "raw_submit_checklist" in failed:
926
  actions.append("Regenerate and upload docs/assets/devpost-submission-checklist.json to the Space.")
927
  if "raw_post_credential_plan" in failed:
 
19
 
20
  SPACE_ID = "ADJCJH/backblaze-proofframe"
21
  SPACE_HOST = "https://adjcjh-backblaze-proofframe.hf.space"
22
+ EXPECTED_SPACE_SHA = "a65c040e9f61df8a46d31af418f5ed67051ea4d9"
23
  TIMEOUT_SECONDS = 30
24
  DRAFT_VIDEO_MIN_BYTES = 100_000
25
  EVENT_SNAPSHOT_MAX_AGE_DAYS = 14
 
57
  "public_space_sync_json",
58
  "public_demo_screenshot_json",
59
  "public_demo_screenshot_script",
60
+ "devpost_preview_json",
61
+ "devpost_preview_script",
62
  "post_credential_live_proof_json",
63
  "post_credential_live_proof_script",
64
  "b2_key_scope_checklist_json",
 
264
  demo_video_draft_url = raw_file_url(space_id, "docs/assets/demo-video-draft.json")
265
  demo_video_draft_mp4_url = resolve_file_url(space_id, "docs/assets/proofframe-demo-draft.mp4")
266
  devpost_form_kit_url = raw_file_url(space_id, "docs/assets/devpost-form-kit.json")
267
+ devpost_preview_url = raw_file_url(space_id, "docs/assets/devpost-submission-preview.json")
268
  submit_checklist_url = raw_file_url(space_id, "docs/assets/devpost-submission-checklist.json")
269
  post_credential_plan_url = raw_file_url(space_id, "docs/assets/post-credential-live-proof-plan.json")
270
  submission_bundle_url = raw_file_url(space_id, "docs/assets/submission-bundle-manifest.json")
 
285
  demo_video_draft_result = fetcher(demo_video_draft_url, TIMEOUT_SECONDS)
286
  demo_video_draft_mp4_result = fetcher(demo_video_draft_mp4_url, TIMEOUT_SECONDS)
287
  devpost_form_kit_result = fetcher(devpost_form_kit_url, TIMEOUT_SECONDS)
288
+ devpost_preview_result = fetcher(devpost_preview_url, TIMEOUT_SECONDS)
289
  submit_checklist_result = fetcher(submit_checklist_url, TIMEOUT_SECONDS)
290
  post_credential_plan_result = fetcher(post_credential_plan_url, TIMEOUT_SECONDS)
291
  submission_bundle_result = fetcher(submission_bundle_url, TIMEOUT_SECONDS)
 
305
  public_demo_screenshot = parse_json(public_demo_screenshot_result)
306
  demo_video_draft = parse_json(demo_video_draft_result)
307
  devpost_form_kit = parse_json(devpost_form_kit_result)
308
+ devpost_preview = parse_json(devpost_preview_result)
309
  submit_checklist = parse_json(submit_checklist_result)
310
  post_credential_plan = parse_json(post_credential_plan_result)
311
  submission_bundle = parse_json(submission_bundle_result)
 
395
  and (public_demo_screenshot_image.get("width") or 0) >= 1200
396
  and (public_demo_screenshot_image.get("height") or 0) >= 900
397
  )
398
+ devpost_preview_readiness = dict_field(devpost_preview, "submission_readiness")
399
+ devpost_preview_field_rollup = dict_field(devpost_preview, "field_rollup")
400
+ devpost_preview_blockers = list_field(devpost_preview_readiness, "final_blockers")
401
+ devpost_preview_evidence_links = dict_field(devpost_preview, "evidence_links")
402
+ devpost_preview_ok = bool(
403
+ devpost_preview_result.get("ok")
404
+ and devpost_preview
405
+ and devpost_preview.get("schema") == "proofframe.devpost_submission_preview.v1"
406
+ and devpost_preview.get("ok") is True
407
+ and devpost_preview.get("safe_to_share") is True
408
+ and devpost_preview.get("safe_to_submit") is False
409
+ and devpost_preview.get("mode") == "pre_live_preview_ready"
410
+ and devpost_preview_readiness.get("packet_mode") == "pre_live_safe"
411
+ and devpost_preview_readiness.get("public_space_mode") == "public_space_synced"
412
+ and devpost_preview_readiness.get("public_screenshot_mode") == "public_judge_screenshot_ready"
413
+ and devpost_preview_field_rollup.get("mock_ready") is True
414
+ and devpost_preview_field_rollup.get("final_ready") is False
415
+ and any(
416
+ isinstance(blocker, dict) and blocker.get("id") == "b2_live_proof"
417
+ for blocker in devpost_preview_blockers
418
+ )
419
+ and any(
420
+ isinstance(blocker, dict) and blocker.get("id") == "genblaze_live_proof"
421
+ for blocker in devpost_preview_blockers
422
+ )
423
+ and devpost_preview_evidence_links.get("public_demo")
424
+ == "https://adjcjh-backblaze-proofframe.hf.space/?judge=1"
425
+ and devpost_preview_evidence_links.get("public_screenshot")
426
+ == "docs/assets/proofframe-hf-public-smoke.png"
427
+ )
428
  b2_key_scope_expected = dict_field(b2_key_scope_checklist, "expected_key")
429
  b2_key_scope_bucket = dict_field(b2_key_scope_expected, "bucket_scope")
430
  b2_key_scope_prefix = dict_field(b2_key_scope_expected, "file_name_prefix")
 
681
  ),
682
  devpost_form_kit_url,
683
  ),
684
+ check_item(
685
+ "raw_devpost_preview",
686
+ "Raw Devpost submission preview is public and claim-safe",
687
+ devpost_preview_ok,
688
+ (
689
+ f"Preview schema is {devpost_preview.get('schema') if devpost_preview else None}; "
690
+ f"mode is {devpost_preview.get('mode') if devpost_preview else None}; "
691
+ f"safe_to_share={devpost_preview.get('safe_to_share') if devpost_preview else None}; "
692
+ f"safe_to_submit={devpost_preview.get('safe_to_submit') if devpost_preview else None}; "
693
+ f"blockers={len(devpost_preview_blockers)}."
694
+ ),
695
+ devpost_preview_url,
696
+ ),
697
  check_item(
698
  "raw_submit_checklist",
699
  "Raw Devpost submit checklist is public and fail-closed",
 
892
  public_demo_screenshot_image.get("height"),
893
  ],
894
  },
895
+ "devpost_preview": {
896
+ "mode": devpost_preview.get("mode") if devpost_preview else None,
897
+ "safe_to_share": devpost_preview.get("safe_to_share") if devpost_preview else None,
898
+ "safe_to_submit": devpost_preview.get("safe_to_submit") if devpost_preview else None,
899
+ "field_final_ready": devpost_preview_field_rollup.get("final_ready"),
900
+ "blocker_count": len(devpost_preview_blockers),
901
+ },
902
  "demo_video_draft_mode": demo_video_draft.get("mode") if demo_video_draft else None,
903
  "demo_video_draft_safe_to_submit": (
904
  demo_video_draft.get("safe_to_submit") if demo_video_draft else None
 
939
  "raw_public_demo_screenshot": public_demo_screenshot_url,
940
  "raw_demo_video_draft": demo_video_draft_url,
941
  "demo_video_draft_mp4": demo_video_draft_mp4_url,
942
+ "raw_devpost_form_kit": devpost_form_kit_url,
943
+ "raw_devpost_preview": devpost_preview_url,
944
+ "raw_submit_checklist": submit_checklist_url,
945
  "raw_post_credential_plan": post_credential_plan_url,
946
  "raw_submission_bundle": submission_bundle_url,
947
  "judge": judge_url,
 
980
  actions.append("Regenerate and upload docs/assets/proofframe-demo-draft.mp4 to the Space.")
981
  if "raw_devpost_form_kit" in failed:
982
  actions.append("Regenerate and upload docs/assets/devpost-form-kit.json to the Space.")
983
+ if "raw_devpost_preview" in failed:
984
+ actions.append("Regenerate and upload docs/assets/devpost-submission-preview.json to the Space.")
985
  if "raw_submit_checklist" in failed:
986
  actions.append("Regenerate and upload docs/assets/devpost-submission-checklist.json to the Space.")
987
  if "raw_post_credential_plan" in failed:
scripts/submission_bundle.py CHANGED
@@ -42,6 +42,9 @@ ARTIFACTS = [
42
  ("devpost_form_kit_script", "scripts/devpost_form_kit.py", "Field-by-field Devpost form kit"),
43
  ("devpost_form_kit_json", "docs/assets/devpost-form-kit.json", "Machine-readable Devpost form kit"),
44
  ("devpost_form_kit_md", "docs/assets/devpost-form-kit.md", "Human-readable Devpost form kit"),
 
 
 
45
  ("devpost_submission_checklist_script", "scripts/devpost_submission_checklist.py", "No-secret final Devpost web submission checklist"),
46
  ("devpost_submission_checklist_json", "docs/assets/devpost-submission-checklist.json", "Machine-readable final Devpost submission checklist"),
47
  ("devpost_submission_checklist_md", "docs/assets/devpost-submission-checklist.md", "Human-readable final Devpost submission checklist"),
 
42
  ("devpost_form_kit_script", "scripts/devpost_form_kit.py", "Field-by-field Devpost form kit"),
43
  ("devpost_form_kit_json", "docs/assets/devpost-form-kit.json", "Machine-readable Devpost form kit"),
44
  ("devpost_form_kit_md", "docs/assets/devpost-form-kit.md", "Human-readable Devpost form kit"),
45
+ ("devpost_preview_script", "scripts/devpost_submission_preview.py", "One-page claim-safe Devpost preview"),
46
+ ("devpost_preview_json", "docs/assets/devpost-submission-preview.json", "Machine-readable Devpost preview"),
47
+ ("devpost_preview_md", "docs/assets/devpost-submission-preview.md", "Human-readable Devpost preview"),
48
  ("devpost_submission_checklist_script", "scripts/devpost_submission_checklist.py", "No-secret final Devpost web submission checklist"),
49
  ("devpost_submission_checklist_json", "docs/assets/devpost-submission-checklist.json", "Machine-readable final Devpost submission checklist"),
50
  ("devpost_submission_checklist_md", "docs/assets/devpost-submission-checklist.md", "Human-readable final Devpost submission checklist"),
tasks.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "project": "ProofFrame",
3
- "updated_at": "2026-06-28T17:44:35Z",
4
  "tasks": [
5
  {
6
  "id": "T001",
@@ -946,6 +946,15 @@
946
  "status": "done",
947
  "done_criteria": "Public judge screenshot is refreshed from the live HF Space, verified for visible/html judge markers and nonblank image stats, included in recording assets/submission bundle/public Space sync gates, and synced to the public Space.",
948
  "notes": "Captured docs/assets/proofframe-hf-public-smoke.png via scripts/public_demo_screenshot.py; uploaded HF Space commit 6a909b229afd3f08099877fb4cff633438f72ba5; public_space_sync and public API smoke pass with raw public-demo-screenshot-report verification."
 
 
 
 
 
 
 
 
 
949
  }
950
  ]
951
  }
 
1
  {
2
  "project": "ProofFrame",
3
+ "updated_at": "2026-06-28T17:59:35Z",
4
  "tasks": [
5
  {
6
  "id": "T001",
 
946
  "status": "done",
947
  "done_criteria": "Public judge screenshot is refreshed from the live HF Space, verified for visible/html judge markers and nonblank image stats, included in recording assets/submission bundle/public Space sync gates, and synced to the public Space.",
948
  "notes": "Captured docs/assets/proofframe-hf-public-smoke.png via scripts/public_demo_screenshot.py; uploaded HF Space commit 6a909b229afd3f08099877fb4cff633438f72ba5; public_space_sync and public API smoke pass with raw public-demo-screenshot-report verification."
949
+ },
950
+ {
951
+ "id": "T068",
952
+ "title": "Add Devpost submission preview",
953
+ "phase": "P4 Submit",
954
+ "owner": "reviewer",
955
+ "status": "done",
956
+ "done_criteria": "A one-page Devpost preview consolidates copy blocks, public demo evidence, screenshot evidence, readiness modes, and final blockers while separating safe_to_share from safe_to_submit.",
957
+ "notes": "Added scripts/devpost_submission_preview.py with tests; generated docs/assets/devpost-submission-preview.*; wired preview into CI, submission bundle, evidence docs, and public_space_sync raw artifact validation."
958
  }
959
  ]
960
  }
tests/test_devpost_submission_preview.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import importlib.util
2
+ import json
3
+ from pathlib import Path
4
+
5
+
6
+ SCRIPT_PATH = Path(__file__).resolve().parents[1] / "scripts" / "devpost_submission_preview.py"
7
+ SPEC = importlib.util.spec_from_file_location("devpost_submission_preview", SCRIPT_PATH)
8
+ devpost_submission_preview = importlib.util.module_from_spec(SPEC)
9
+ assert SPEC.loader is not None
10
+ SPEC.loader.exec_module(devpost_submission_preview)
11
+
12
+
13
+ def write_json(root: Path, relative_path: str, payload: dict) -> None:
14
+ path = root / relative_path
15
+ path.parent.mkdir(parents=True, exist_ok=True)
16
+ path.write_text(json.dumps(payload), encoding="utf-8")
17
+
18
+
19
+ def packet(*, live: bool = False) -> dict:
20
+ return {
21
+ "schema": "proofframe.devpost_packet.v1",
22
+ "mode": "post_live_verified" if live else "pre_live_safe",
23
+ "project_name": "ProofFrame",
24
+ "tagline": "B2-ready provenance desk for GenAI media.",
25
+ "one_liner": "ProofFrame turns generated media into evidence packets.",
26
+ "repository_url": "https://github.com/adjcjh777/backblaze-proofframe",
27
+ "demo_url": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
28
+ "video_url": "https://youtu.be/final-proof" if live else "TBD after final B2 and Genblaze proof.",
29
+ "short_description": "A review desk for generated media evidence packets.",
30
+ "b2_usage": "B2 live proof is a final submission gate.",
31
+ "genblaze_usage": "Genblaze live proof is a final submission gate.",
32
+ "accomplishments": ["Working product.", "Public mock demo."],
33
+ "whats_next": ["Live B2 proof.", "Live Genblaze proof."],
34
+ }
35
+
36
+
37
+ def form_kit(*, live: bool = False) -> dict:
38
+ return {
39
+ "schema": "proofframe.devpost_form_kit.v1",
40
+ "mode": "final_form_ready" if live else "pre_live_form_ready",
41
+ "mock_form_ready": True,
42
+ "final_form_ready": live,
43
+ "public_video_ready": live,
44
+ "fields": [
45
+ {
46
+ "id": "project_name",
47
+ "label": "Project name",
48
+ "ok_for_mock": True,
49
+ "ok_for_final": True,
50
+ },
51
+ {
52
+ "id": "video_url",
53
+ "label": "Demo video URL",
54
+ "ok_for_mock": True,
55
+ "ok_for_final": live,
56
+ },
57
+ ],
58
+ }
59
+
60
+
61
+ def screenshot_report(*, ok: bool = True) -> dict:
62
+ return {
63
+ "schema": "proofframe.public_demo_screenshot.v1",
64
+ "mode": "public_judge_screenshot_ready" if ok else "public_judge_screenshot_blocked",
65
+ "ok": ok,
66
+ "safe_to_commit": True,
67
+ "screenshot": {
68
+ "path": "docs/assets/proofframe-hf-public-smoke.png",
69
+ "bytes": 741074 if ok else 100,
70
+ "width": 1440,
71
+ "height": 2692,
72
+ },
73
+ "markers": {"visible_ok": ok, "html_ok": ok},
74
+ }
75
+
76
+
77
+ def public_space_sync(*, ok: bool = True) -> dict:
78
+ return {
79
+ "schema": "proofframe.public_space_sync.v1",
80
+ "mode": "public_space_synced" if ok else "public_space_mismatch",
81
+ "ok": ok,
82
+ "observed": {
83
+ "public_demo_screenshot": {
84
+ "ok": ok,
85
+ "visible_ok": ok,
86
+ "html_ok": ok,
87
+ }
88
+ },
89
+ }
90
+
91
+
92
+ def final_control(*, live: bool = False) -> dict:
93
+ return {
94
+ "schema": "proofframe.final_submission_control.v1",
95
+ "mode": "final_ready" if live else "pre_live_control",
96
+ "safe_to_submit": live,
97
+ "blocking_items": []
98
+ if live
99
+ else [
100
+ {
101
+ "id": "b2_live_proof",
102
+ "label": "Backblaze B2 live proof captured",
103
+ "detail": "T020 is doing.",
104
+ "evidence": "tasks.json",
105
+ },
106
+ {
107
+ "id": "genblaze_live_proof",
108
+ "label": "Genblaze live proof captured",
109
+ "detail": "T021 is doing.",
110
+ "evidence": "tasks.json",
111
+ },
112
+ ],
113
+ }
114
+
115
+
116
+ def write_fixtures(root: Path, *, live: bool = False, screenshot_ok: bool = True) -> None:
117
+ write_json(root, "docs/assets/devpost-submission-packet.json", packet(live=live))
118
+ write_json(root, "docs/assets/devpost-form-kit.json", form_kit(live=live))
119
+ write_json(
120
+ root,
121
+ "docs/assets/judge-brief.json",
122
+ {
123
+ "schema": "proofframe.judge_brief.v1",
124
+ "judge_opening_30s": "ProofFrame is a media operations desk.",
125
+ "links": {
126
+ "public_demo": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
127
+ "repository": "https://github.com/adjcjh777/backblaze-proofframe",
128
+ },
129
+ },
130
+ )
131
+ write_json(
132
+ root,
133
+ "docs/assets/judge-crosswalk.json",
134
+ {
135
+ "schema": "proofframe.judge_crosswalk.v1",
136
+ "mode": "final_crosswalk_ready" if live else "pre_live_crosswalk_ready",
137
+ "safe_to_submit": live,
138
+ "official_criteria": [{"name": "Production Readiness", "present": True}],
139
+ "rows": [{"id": "production"}],
140
+ },
141
+ )
142
+ write_json(root, "docs/assets/public-demo-screenshot-report.json", screenshot_report(ok=screenshot_ok))
143
+ write_json(root, "docs/assets/public-space-sync-report.json", public_space_sync(ok=screenshot_ok))
144
+ write_json(root, "docs/assets/final-submission-control.json", final_control(live=live))
145
+ write_json(
146
+ root,
147
+ "docs/assets/devpost-submission-checklist.json",
148
+ {
149
+ "schema": "proofframe.devpost_submission_checklist.v1",
150
+ "mode": "ready" if live else "pre_submit_blocked",
151
+ "safe_to_submit": live,
152
+ },
153
+ )
154
+ write_json(
155
+ root,
156
+ "docs/assets/submission-audit-report.json",
157
+ {
158
+ "schema": "proofframe.submission_audit.v1",
159
+ "mode": "final_submit_ready" if live else "pre_submit_audit_blocked",
160
+ "ok": live,
161
+ },
162
+ )
163
+ write_json(
164
+ root,
165
+ "docs/assets/secret-scan-report.json",
166
+ {"schema": "proofframe.secret_scan.v1", "mode": "clear", "ok": True},
167
+ )
168
+
169
+
170
+ def test_devpost_submission_preview_is_shareable_but_not_submittable_before_live_proof(tmp_path):
171
+ write_fixtures(tmp_path)
172
+
173
+ preview = devpost_submission_preview.build_preview(tmp_path)
174
+
175
+ assert preview["schema"] == "proofframe.devpost_submission_preview.v1"
176
+ assert preview["mode"] == "pre_live_preview_ready"
177
+ assert preview["safe_to_share"] is True
178
+ assert preview["safe_to_submit"] is False
179
+ assert preview["field_rollup"]["mock_ready"] is True
180
+ assert preview["field_rollup"]["final_ready"] is False
181
+ assert {item["id"] for item in preview["submission_readiness"]["final_blockers"]} == {
182
+ "b2_live_proof",
183
+ "genblaze_live_proof",
184
+ }
185
+ assert "Do not claim completed live Backblaze B2 storage" in preview["claim_boundary"][1]
186
+
187
+
188
+ def test_devpost_submission_preview_blocks_when_public_screenshot_is_not_verified(tmp_path):
189
+ write_fixtures(tmp_path, screenshot_ok=False)
190
+
191
+ preview = devpost_submission_preview.build_preview(tmp_path)
192
+
193
+ assert preview["mode"] == "preview_blocked"
194
+ assert preview["safe_to_share"] is False
195
+ assert "Regenerate the public judge-mode screenshot report." in preview["next_actions"]
196
+
197
+
198
+ def test_devpost_submission_preview_can_be_final_ready_after_live_gates(tmp_path):
199
+ write_fixtures(tmp_path, live=True)
200
+
201
+ preview = devpost_submission_preview.build_preview(tmp_path)
202
+
203
+ assert preview["mode"] == "final_preview_ready"
204
+ assert preview["safe_to_share"] is True
205
+ assert preview["safe_to_submit"] is True
206
+ assert preview["submission_readiness"]["final_blockers"] == []
207
+
208
+
209
+ def test_devpost_submission_preview_writes_outputs(tmp_path):
210
+ write_fixtures(tmp_path)
211
+ preview = devpost_submission_preview.build_preview(tmp_path)
212
+ json_path = tmp_path / "out" / "preview.json"
213
+ markdown_path = tmp_path / "out" / "preview.md"
214
+
215
+ devpost_submission_preview.write_outputs(preview, json_path, markdown_path)
216
+
217
+ saved = json.loads(json_path.read_text(encoding="utf-8"))
218
+ markdown = markdown_path.read_text(encoding="utf-8")
219
+ assert saved["schema"] == "proofframe.devpost_submission_preview.v1"
220
+ assert "# ProofFrame Devpost Submission Preview" in markdown
221
+ assert "## Final Blockers" in markdown
tests/test_public_space_sync.py CHANGED
@@ -180,6 +180,33 @@ def valid_public_demo_screenshot() -> dict:
180
  }
181
 
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  def fake_fetcher(url: str, timeout: int) -> dict:
184
  assert timeout == public_space_sync.TIMEOUT_SECONDS
185
  if url.endswith("/api/spaces/ADJCJH/backblaze-proofframe"):
@@ -347,6 +374,13 @@ def fake_fetcher(url: str, timeout: int) -> dict:
347
  ),
348
  "error": None,
349
  }
 
 
 
 
 
 
 
350
  if url.endswith("/docs/assets/devpost-submission-checklist.json"):
351
  return {
352
  "ok": True,
@@ -474,6 +508,11 @@ def test_public_space_sync_report_passes_when_space_is_current():
474
  assert report["observed"]["public_demo_screenshot"]["html_ok"] is True
475
  assert report["observed"]["public_demo_screenshot"]["bytes"] == 717007
476
  assert report["observed"]["public_demo_screenshot"]["size"] == [1440, 2692]
 
 
 
 
 
477
  assert report["observed"]["post_credential_plan_mode"] == "plan_only"
478
  assert report["observed"]["post_credential_plan_validators"] == {
479
  "validate_b2_evidence": True,
@@ -579,6 +618,28 @@ def test_public_space_sync_fails_on_unsafe_public_demo_screenshot_with_action():
579
  )
580
 
581
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
582
  def test_public_space_sync_fails_on_stale_event_snapshot_with_action():
583
  def broken_fetcher(url: str, timeout: int) -> dict:
584
  result = fake_fetcher(url, timeout)
 
180
  }
181
 
182
 
183
+ def valid_devpost_preview() -> dict:
184
+ return {
185
+ "schema": "proofframe.devpost_submission_preview.v1",
186
+ "mode": "pre_live_preview_ready",
187
+ "ok": True,
188
+ "safe_to_share": True,
189
+ "safe_to_submit": False,
190
+ "submission_readiness": {
191
+ "packet_mode": "pre_live_safe",
192
+ "public_space_mode": "public_space_synced",
193
+ "public_screenshot_mode": "public_judge_screenshot_ready",
194
+ "final_blockers": [
195
+ {"id": "b2_live_proof"},
196
+ {"id": "genblaze_live_proof"},
197
+ ],
198
+ },
199
+ "field_rollup": {
200
+ "mock_ready": True,
201
+ "final_ready": False,
202
+ },
203
+ "evidence_links": {
204
+ "public_demo": "https://adjcjh-backblaze-proofframe.hf.space/?judge=1",
205
+ "public_screenshot": "docs/assets/proofframe-hf-public-smoke.png",
206
+ },
207
+ }
208
+
209
+
210
  def fake_fetcher(url: str, timeout: int) -> dict:
211
  assert timeout == public_space_sync.TIMEOUT_SECONDS
212
  if url.endswith("/api/spaces/ADJCJH/backblaze-proofframe"):
 
374
  ),
375
  "error": None,
376
  }
377
+ if url.endswith("/docs/assets/devpost-submission-preview.json"):
378
+ return {
379
+ "ok": True,
380
+ "status": 200,
381
+ "body": json.dumps(valid_devpost_preview()),
382
+ "error": None,
383
+ }
384
  if url.endswith("/docs/assets/devpost-submission-checklist.json"):
385
  return {
386
  "ok": True,
 
508
  assert report["observed"]["public_demo_screenshot"]["html_ok"] is True
509
  assert report["observed"]["public_demo_screenshot"]["bytes"] == 717007
510
  assert report["observed"]["public_demo_screenshot"]["size"] == [1440, 2692]
511
+ assert report["observed"]["devpost_preview"]["mode"] == "pre_live_preview_ready"
512
+ assert report["observed"]["devpost_preview"]["safe_to_share"] is True
513
+ assert report["observed"]["devpost_preview"]["safe_to_submit"] is False
514
+ assert report["observed"]["devpost_preview"]["field_final_ready"] is False
515
+ assert report["observed"]["devpost_preview"]["blocker_count"] == 2
516
  assert report["observed"]["post_credential_plan_mode"] == "plan_only"
517
  assert report["observed"]["post_credential_plan_validators"] == {
518
  "validate_b2_evidence": True,
 
618
  )
619
 
620
 
621
+ def test_public_space_sync_fails_on_unsafe_devpost_preview_with_action():
622
+ def broken_fetcher(url: str, timeout: int) -> dict:
623
+ result = fake_fetcher(url, timeout)
624
+ if url.endswith("/docs/assets/devpost-submission-preview.json"):
625
+ preview = valid_devpost_preview()
626
+ preview["safe_to_share"] = False
627
+ preview["submission_readiness"]["final_blockers"] = []
628
+ result = {**result, "body": json.dumps(preview)}
629
+ return result
630
+
631
+ report = public_space_sync.build_report(expected_sha=EXPECTED_SHA, fetcher=broken_fetcher)
632
+
633
+ failed = {item["id"] for item in report["checks"] if not item["ok"]}
634
+ assert report["ok"] is False
635
+ assert "raw_devpost_preview" in failed
636
+ assert report["observed"]["devpost_preview"]["safe_to_share"] is False
637
+ assert (
638
+ "Regenerate and upload docs/assets/devpost-submission-preview.json to the Space."
639
+ in report["next_actions"]
640
+ )
641
+
642
+
643
  def test_public_space_sync_fails_on_stale_event_snapshot_with_action():
644
  def broken_fetcher(url: str, timeout: int) -> dict:
645
  result = fake_fetcher(url, timeout)