Skip to content

Commit c993094

Browse files
authored
Merge pull request #138 from bitmaster162/agent/r111a-noscript-form-fallback-local-r1
R111A: add no-JS application fallback
2 parents 73e2014 + 0d5395b commit c993094

9 files changed

Lines changed: 36 additions & 29 deletions

File tree

components/LeadForm.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ export function LeadForm({
7171
}
7272

7373
return (
74-
<form className="leadForm" onSubmit={onSubmit}>
74+
<>
75+
<noscript><p className="formNote">{en ? "The application form requires JavaScript. Contact us directly instead — Telegram, WhatsApp, LINE or email, all listed below on this page." : "Форма заявки работает только с включённым JavaScript. Напишите напрямую — Telegram, WhatsApp, LINE или email, контакты ниже на этой странице."}</p></noscript>
76+
<form className="leadForm" onSubmit={onSubmit}>
7577
<input type="hidden" name="locale" value={locale} />
7678
<input type="hidden" name="program" value={program} />
7779
<div className="formRow">
@@ -128,6 +130,7 @@ export function LeadForm({
128130
{en ? "For minors, applications and organizational communication use an adult contact only." : "Для несовершеннолетних заявка и организационная коммуникация идут только через взрослого."}
129131
</p>
130132
{message ? <p className={state === "sent" ? "formMessage success" : "formMessage error"}>{message}</p> : null}
131-
</form>
133+
</form>
134+
</>
132135
);
133136
}

deploy/live/_release.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@
128128
},
129129
{
130130
"path": "en/start.html",
131-
"sha256": "619779d32eb2528eb3838d42ab12fdf3c524f863186091b6fdd989418b235abb",
132-
"size": 11919
131+
"sha256": "50782c7fb4a22d836dd4d5affdb04bca5cdff3a49ea973b733b6664b9519af99",
132+
"size": 12103
133133
},
134134
{
135135
"path": "en/studio.html",
@@ -268,8 +268,8 @@
268268
},
269269
{
270270
"path": "start.html",
271-
"sha256": "d974de94cbe2bea2dfa449f403d7436d243fceb66acc1efb8151e84f82a5bd17",
272-
"size": 17184
271+
"sha256": "46fc0f6bfcfa1c3e9d72777232d19750f1e0c14be96e449dc02530890f5f040b",
272+
"size": 17453
273273
},
274274
{
275275
"path": "studio.html",
@@ -297,7 +297,7 @@
297297
"size": 21826
298298
}
299299
],
300-
"payload_sha256": "42b5b2d8cbaecf4091fe33abbb0715afa47bec37bf4410ff1fc423686f38a091",
301-
"release_id": "R110C_BRAND_LOGO",
300+
"payload_sha256": "6b02e1e7da6df0de7370c1956d3f1d6317146551ece2606cf91b88f7d222b8b9",
301+
"release_id": "R111A_NOSCRIPT_FORM_FALLBACK",
302302
"schema": "ai-skill-lab.static-release.v1"
303303
}

deploy/live/en/start.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

deploy/live/start.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

scripts/check_workshop_d2.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def need(rel,tokens):
104104
manifest=json.loads((LIVE/'_release.json').read_text(encoding='utf-8'));checks+=5
105105
if manifest.get('schema')!='ai-skill-lab.static-release.v1':errors.append('release manifest schema drift')
106106
# Current release identity is owned by the D3 release checker.
107-
expected_files=59 if manifest.get('release_id')=='R110C_BRAND_LOGO' else 58
107+
expected_files=59 if manifest.get('release_id') in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} else 58
108108
if manifest.get('file_count')!=expected_files:errors.append(f'manifest file_count {manifest.get("file_count")} != {expected_files}')
109109
listed={x.get('path') for x in manifest.get('files',[])}
110110
if not {'family.html','en/family.html'}<=listed:errors.append('manifest missing Family static pages')

scripts/check_workshop_d3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def handle_data(self, data):
111111
all_pages = list(LIVE.rglob('*.html'))
112112
require(len(all_pages) == 47, '47 HTML files')
113113
manifest = json.loads(read('deploy/live/_release.json'))
114-
expected_files=59 if manifest.get('release_id')=='R110C_BRAND_LOGO' else 58; require(manifest.get('file_count') == expected_files, f'{expected_files} release files')
114+
expected_files=59 if manifest.get('release_id') in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} else 58; require(manifest.get('file_count') == expected_files, f'{expected_files} release files')
115115
require(manifest.get('schema') == 'ai-skill-lab.static-release.v1', 'Release schema')
116116

117117
def luminance(value):

scripts/check_workshop_d4.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ def sha(rel):return hashlib.sha256((ROOT/rel).read_bytes()).hexdigest()
3535
'deploy/live/vercel.json':'0cc0517ab4581253c944148a5f6573353ed9159db030fa864fdaee408aca2316',
3636
}
3737
protected=dict(PROTECTED)
38-
if release in {'R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R102_PROTECTED_OVERRIDES)
39-
if release in {'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R103_PROTECTED_OVERRIDES)
40-
if release in {'R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R109D_PROTECTED_OVERRIDES)
41-
if release in {'R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R109F_PROTECTED_OVERRIDES)
42-
if release=='R110C_BRAND_LOGO':protected.update(R110C_PROTECTED_OVERRIDES)
38+
if release in {'R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R102_PROTECTED_OVERRIDES)
39+
if release in {'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R103_PROTECTED_OVERRIDES)
40+
if release in {'R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R109D_PROTECTED_OVERRIDES)
41+
if release in {'R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R109F_PROTECTED_OVERRIDES)
42+
if release in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R110C_PROTECTED_OVERRIDES)
4343
for rel,digest in protected.items():require(sha(rel)==digest,f'protected byte drift {rel}')
4444
for locale in ('ru','en'):
4545
en=locale=='en'; prefix='en/' if en else ''
@@ -80,17 +80,17 @@ def sha(rel):return hashlib.sha256((ROOT/rel).read_bytes()).hexdigest()
8080
all_html=list(LIVE.rglob('*.html'));public=[p for p in all_html if p.name!='404.html']
8181
require(len(all_html)==47,'47 static HTML files')
8282
workshop=sum('<header class="workshopHeader">' in p.read_text(encoding='utf-8') for p in public);legacy=sum('<header class="nav">' in p.read_text(encoding='utf-8') for p in public)
83-
require(manifest.get('schema')=='ai-skill-lab.static-release.v1','release schema');states={'R99_D4':(36,10),'R100_D5':(46,0),'R101B_D6_PUBLIC_FORM':(46,0),'R102_D7_CUSTOM_DOMAIN_CANONICAL':(46,0),'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT':(46,0),'R109A_CRITICAL_VISUAL_FIX':(46,0),'R109A_REVIEW_REPAIR':(46,0),'R109D_404_LEGACY_HOST':(46,0),'R109B_TRUTH_FORM_ALIGNMENT':(46,0),'R109E_GLYPH_SPACING_VISUAL':(46,0),'R109F_STRUCTURED_DATA':(46,0),'R110A_OPERATOR_LEAD_INBOX':(46,0),'R110B_LEAD_TELEGRAM_NOTIFICATION':(46,0),'R110C_BRAND_LOGO':(46,0)};require(release in states,f'unsupported release state {release!r}')
83+
require(manifest.get('schema')=='ai-skill-lab.static-release.v1','release schema');states={'R99_D4':(36,10),'R100_D5':(46,0),'R101B_D6_PUBLIC_FORM':(46,0),'R102_D7_CUSTOM_DOMAIN_CANONICAL':(46,0),'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT':(46,0),'R109A_CRITICAL_VISUAL_FIX':(46,0),'R109A_REVIEW_REPAIR':(46,0),'R109D_404_LEGACY_HOST':(46,0),'R109B_TRUTH_FORM_ALIGNMENT':(46,0),'R109E_GLYPH_SPACING_VISUAL':(46,0),'R109F_STRUCTURED_DATA':(46,0),'R110A_OPERATOR_LEAD_INBOX':(46,0),'R110B_LEAD_TELEGRAM_NOTIFICATION':(46,0),'R110C_BRAND_LOGO':(46,0),'R111A_NOSCRIPT_FORM_FALLBACK':(46,0)};require(release in states,f'unsupported release state {release!r}')
8484
if release in states:
8585
expected_workshop,expected_legacy=states[release];require(workshop==expected_workshop,f'Workshop pages {workshop} != {expected_workshop} for {release}');require(legacy==expected_legacy,f'legacy pages {legacy} != {expected_legacy} for {release}')
86-
expected_files=59 if release=='R110C_BRAND_LOGO' else 58;require(manifest.get('file_count')==expected_files,f'{expected_files} release files')
86+
expected_files=59 if release in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} else 58;require(manifest.get('file_count')==expected_files,f'{expected_files} release files')
8787
actual={p.relative_to(LIVE).as_posix():(len(p.read_bytes()),hashlib.sha256(p.read_bytes()).hexdigest()) for p in LIVE.rglob('*') if p.is_file() and p.name!='_release.json'}
8888
listed={x['path']:(x['size'],x['sha256']) for x in manifest.get('files',[])};require(actual==listed,'manifest exact file bytes');payload=sum(x[0] for x in actual.values());require(payload<=524288,f'payload {payload} > 524288')
8989
require(len({('/' if p.name=='index.html' else '/en' if p.relative_to(LIVE).as_posix()=='en.html' else '/'+p.relative_to(LIVE).as_posix()[:-5]) for p in public})==46,'46 public routes')
9090
css=read('deploy/live/workshop.css');guard='.labDialog :is(p,.proofConsoleTop,.proofConsoleFoot){display:flex;gap:8px;flex-wrap:wrap}.labDialog :is(a,button){padding:13px}'
9191
require(css.count(guard)==1,'C1 Lab spacing guard exactly once');require('@import' not in css and 'fonts.googleapis.com' not in css and 'fonts.gstatic.com' not in css,'Workshop CSS self-contained')
9292
r109e_guards=['.workshopFooter>div{display:flex;flex-direction:column}','.workshopFooter nav{display:flex;flex-wrap:wrap;gap:16px}','.workshopFooter{border-bottom:0;border-top:1px solid var(--b)}','.bandSteps{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--b)}','.heroActions,.sectionActions{display:flex;flex-wrap:wrap;gap:10px}','.proofFlow article>span,.proofFlow article>b{display:block}','.projectStudioStatus>strong,.projectStudioStatus>span{display:block}']
93-
if release in {'R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:
93+
if release in {'R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:
9494
for visual_guard in r109e_guards:require(visual_guard in css,f'R109E visual guard {visual_guard}')
9595
workflow=read('.github/workflows/static-qa.yml');preflight=read('scripts/preflight_release.py');require(workflow.count('python scripts/check_workshop_d4.py')==1,'workflow D4 exactly once');require(preflight.count('scripts/check_workshop_d4.py')==1,'preflight D4 exactly once')
9696
print(f'workshop_d4_checks={checks} target_pages=18 workshop_pages={workshop} legacy_pages={legacy} routes=46 html=47 files={expected_files} payload_bytes={payload} headroom={524288-payload}')

scripts/check_workshop_d5.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ def sha(rel): return hashlib.sha256((ROOT/rel).read_bytes()).hexdigest()
3434
'deploy/live/vercel.json':'0cc0517ab4581253c944148a5f6573353ed9159db030fa864fdaee408aca2316',
3535
}
3636
protected=dict(PROTECTED)
37-
if release in {'R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R102_PROTECTED_OVERRIDES)
38-
if release in {'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R103_PROTECTED_OVERRIDES)
39-
if release in {'R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R109D_PROTECTED_OVERRIDES)
40-
if release in {'R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:protected.update(R109F_PROTECTED_OVERRIDES)
41-
if release=='R110C_BRAND_LOGO':protected.update(R110C_PROTECTED_OVERRIDES)
37+
if release in {'R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R102_PROTECTED_OVERRIDES)
38+
if release in {'R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R103_PROTECTED_OVERRIDES)
39+
if release in {'R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R109D_PROTECTED_OVERRIDES)
40+
if release in {'R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R109F_PROTECTED_OVERRIDES)
41+
if release in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:protected.update(R110C_PROTECTED_OVERRIDES)
4242
legal=dict(LEGAL); static_main=dict(STATIC_MAIN)
4343
if release in {'R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST'}:
4444
legal.update({'app/safety/page.tsx': '644a48fbd7a10c2822649b2968015d990e07056b4ca6f1f5d7510ca5e9148e29', 'app/en/safety/page.tsx': 'ccd8f60727b6d1f6896c34b8229903286178548b2f65ee4ad56be8366b6d5f06'}); static_main.update({'safety.html': '464b2639f32ccb0eb07c53b73a1a823d516112cd63178f1f0f61a6364bd41a8a', 'en/safety.html': '79f1cd2e4e37066be8c23788438b2c965b9b88b3d926f6a9168a054d7c6c25b3'})
45-
if release in {'R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'}:
45+
if release in {'R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'}:
4646
legal.update({'app/safety/page.tsx':'a490cdc90298db70f247b5a8b55cf8b972dd9f0ed7bb4d312c893ca7b944a044','app/en/safety/page.tsx':'da5f276c6a95cc4d553cedb1731d063bb86181507e2c4d9a8f1993f81e761d3d'}); static_main.update({'safety.html':'6a9c89da1f6ffba2a842a4f35e04f42dc8edc5627e4f5b86b6544ed9269e92af','en/safety.html':'37f38ad15a191cd0d94070ca18a99a0552b688e1359bb8cd3a8c0faac7b62f49','terms.html':'22188c4e458ff37f8b34dc4c67781268cd813bdeac25d533a89df791585f572a','en/terms.html':'5a82ccc6a8ca2d0c756666e7bb780a0712d608dee4b16e80443df92ca83b6d9c'})
4747
def main_digest(text):
4848
m=re.search(r'<main id="main".*?</main>',text,re.S)
@@ -58,7 +58,7 @@ def main_digest(text):
5858
req('<link rel="stylesheet" href="/workshop.css">' in t and 'href="/style.css"' not in t,f'Workshop stylesheet {rel}'); req(t.count('data-lab-command-open')==1 and t.count('src="/lab-command.js"')==1,f'LAB runtime {rel}'); req(f'href="{alt}"' in t and f'href="{start}"' in t,f'alt/start {rel}')
5959
for bad in ('<form','fetch(','XMLHttpRequest','WebSocket(','localStorage','sessionStorage','document.cookie','sendBeacon('): req(bad not in t,f'forbidden client primitive {rel} {bad}')
6060

61-
policy_date='2026-09-14' if release in {'R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'} else '2026-08-15'
61+
policy_date='2026-09-14' if release in {'R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} else '2026-08-15'
6262
for rel in ['app/safety/page.tsx','app/en/safety/page.tsx','deploy/live/safety.html','deploy/live/en/safety.html']:
6363
t=read(rel); req(t.count(f'data-policy-verified="{policy_date}"')==1,f'policy date {rel}'); req('https://help.openai.com/en/articles/8313401' in t,f'age source {rel}'); req('https://help.openai.com/en/articles/12315553-parental-controls-on-chatgpt-faq/' in t,f'parental source {rel}')
6464
for rel in ['app/privacy/page.tsx','app/en/privacy/page.tsx']:
@@ -72,7 +72,7 @@ def main_digest(text):
7272
all_html=list(LIVE.rglob('*.html')); public=[p for p in all_html if p.name!='404.html']; req(len(all_html)==47,'47 html including 404')
7373
workshop=sum('<header class="workshopHeader">' in p.read_text(encoding='utf-8') for p in public); legacy=sum('<header class="nav">' in p.read_text(encoding='utf-8') for p in public); req(workshop==46,f'Workshop pages {workshop} != 46'); req(legacy==0,f'legacy pages {legacy} != 0')
7474
routes={('/' if p.name=='index.html' else '/en' if p.relative_to(LIVE).as_posix()=='en.html' else '/'+p.relative_to(LIVE).as_posix()[:-5]) for p in public}; req(len(routes)==46,'46 public routes')
75-
req(manifest.get('schema')=='ai-skill-lab.static-release.v1','release schema'); req(release in {'R101B_D6_PUBLIC_FORM','R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO'} ,'D6-or-newer release'); expected_files=59 if release=='R110C_BRAND_LOGO' else 58; req(manifest.get('file_count')==expected_files,f'{expected_files} release files')
75+
req(manifest.get('schema')=='ai-skill-lab.static-release.v1','release schema'); req(release in {'R101B_D6_PUBLIC_FORM','R102_D7_CUSTOM_DOMAIN_CANONICAL','R103_D8_LEGACY_PUBLIC_HOST_REDIRECT','R109A_CRITICAL_VISUAL_FIX','R109A_REVIEW_REPAIR','R109D_404_LEGACY_HOST','R109B_TRUTH_FORM_ALIGNMENT','R109E_GLYPH_SPACING_VISUAL','R109F_STRUCTURED_DATA','R110A_OPERATOR_LEAD_INBOX','R110B_LEAD_TELEGRAM_NOTIFICATION','R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} ,'D6-or-newer release'); expected_files=59 if release in {'R110C_BRAND_LOGO','R111A_NOSCRIPT_FORM_FALLBACK'} else 58; req(manifest.get('file_count')==expected_files,f'{expected_files} release files')
7676
actual={p.relative_to(LIVE).as_posix():(len(p.read_bytes()),hashlib.sha256(p.read_bytes()).hexdigest()) for p in LIVE.rglob('*') if p.is_file() and p.name!='_release.json'}; listed={x['path']:(x['size'],x['sha256']) for x in manifest.get('files',[])}; req(actual==listed,'manifest exact bytes'); payload=sum(x[0] for x in actual.values()); req(payload<=524288,f'payload {payload} > 524288')
7777
workflow=read('.github/workflows/static-qa.yml'); preflight=read('scripts/preflight_release.py'); req(workflow.count('python scripts/check_workshop_d5.py')==1,'workflow D5 once'); req(preflight.count('scripts/check_workshop_d5.py')==1,'preflight D5 once')
7878
print(f'workshop_d5_checks={checks} target_pages=10 workshop_pages={workshop} legacy_pages={legacy} routes={len(routes)} html={len(all_html)} files={manifest.get("file_count")} payload_bytes={payload} headroom={524288-payload}')

0 commit comments

Comments
 (0)