T7.2 - F6/D3: the form gets structure - a section rail, one section open
F6 as amended by D3 (Aug 18): one page, persistent side navigation, sections collapsible, only the current one open by default, plus Expand all. Tabs were rejected in D3 because they hide sections a first-time author does not know exist. What changed: - The jump-chip strip (#section-nav, span onclick) is gone. In its place a <nav> section rail of real <button> entries, aria-current on the current section, 44px tap targets, above the form at 390px and beside it at 1440px. - Every section heading is now a disclosure <button> with aria-expanded and aria-controls. One section open at rest; Expand all (aria-pressed) opens everything and is remembered per browser. - Sections are URL-addressable (?section=, T4.2 machinery) and a deep link to a collapsed section expands it. Positional-id fallback removed: a card without an id gets a console.error and no rail entry, never an invented sec-N id that would ride into shareable URLs and move between visits. - General Information (1,288px on its own) split into #general-card and #assign-card (Assignment & Schedule). The split is presentational: both cards are the ONE CR-006 section `general` (WP_SECTION_NODES lists both), so wp-sections.js and the SOP wizard are untouched. CR-001's adjacency (P6 activity beside due date) is preserved and asserted. - gotoSection() flushes autosave, which the deleted chips used to do. - secMakeToggle() preserves every element child of a heading - help tips go outside the button, everything else inside the label. The first version cleared textContent and destroyed #saved-count, which killed boot one line short of wpCreatorReady with the page still visibly rendered. - BL-013 folded in per the task: the T3.4 focus ring on the rebuilt form. frame_check reports outline solid 2px on creator inputs. Height, measured not asserted: 5,399px before; 1,995px at rest at 1440x900. DONE-WHEN NOT FULLY MET - stated per CLAUDE.md rather than marked complete: "no single view exceeds roughly two screen heights at rest" reads 2.22 screens (1995/900). The remaining gap is page chrome this wave reworks: .ctx-bar (67px, T7.4) and .release-banner (45px, T7.5). The criterion was already amended once (D3, "at rest") and is not being moved again to fit; tests/form_structure_check.py keeps the check red and it is re-measured at the end of wave 7. Every other done-when entry passes. Backlog: BL-001's cause corrected a third time - at rest the overflow is help.js's .help-tip::after tooltip (481 vs 390), the S8 component T9.5 rebuilds; the tables still overflow only when expanded. Deliberately not fixed here - a fix would be thrown away with the component at T9.5. Verification (each probe run alone): form_structure_check 50/51 (the height check above), sections_check 95/95, generalinfo_check 49/49, frame_check 39/39 regression pass. Items: F6, D3, BL-013, BL-001 (re-measured) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,11 @@ true
|
||||
# read from wp-sections.js so the probe checks the mapping instead of agreeing
|
||||
# with it.
|
||||
SECTIONS = [
|
||||
("general", "General Information", "#general-card"),
|
||||
# T7.2 split General Information into two cards under the ONE section id, so
|
||||
# this row carries both selectors. It is the only row that does, and the probe
|
||||
# asserts every selector - which is what catches the failure mode the split
|
||||
# could have had: half the section hidden and half of it still rendering.
|
||||
("general", "General Information", "#general-card, #assign-card"),
|
||||
("location", "Location", "#location-card"),
|
||||
("scope", "Scope of Work", "#scope-card"),
|
||||
("assets", "Assets", "#asset-card"),
|
||||
@@ -247,8 +251,13 @@ def run(page, base, tok, db_path):
|
||||
settle(1.4)
|
||||
page.eval(STUB)
|
||||
vis = json.loads(page.eval("""JSON.stringify(%s.map(sel => {
|
||||
const el = document.querySelector(sel);
|
||||
return [sel, !el ? 'missing' : (el.hidden ? 'hidden' : 'shown')];
|
||||
const els = [...document.querySelectorAll(sel)];
|
||||
if (!els.length) return [sel, 'missing'];
|
||||
// A section may own more than one card (T7.2 split General Information).
|
||||
// querySelector() would answer for the first and quietly ignore the rest,
|
||||
// which is exactly the half-hidden failure this check exists to catch.
|
||||
const hidden = els.filter(e => e.hidden).length;
|
||||
return [sel, hidden === els.length ? 'hidden' : (hidden ? 'part-hidden' : 'shown')];
|
||||
}))""" % json.dumps([s[2] for s in SECTIONS])))
|
||||
by_sel = dict(vis)
|
||||
chk("Assets is absent from the form", by_sel["#asset-card"] == "hidden", vis)
|
||||
@@ -256,8 +265,12 @@ def run(page, base, tok, db_path):
|
||||
chk("...and every other section is still there",
|
||||
all(v == "shown" for k, v in by_sel.items() if k not in ("#asset-card", "#mimo-card")),
|
||||
vis)
|
||||
chips = page.eval("(document.getElementById('section-nav')||{}).textContent||''")
|
||||
chk("the section chip strip loses the same entries",
|
||||
# T7.2 replaced the #section-nav chip strip with the #section-rail. Re-pointed
|
||||
# rather than deleted: the proposition - a suppressed section leaves the table
|
||||
# of contents with the form - is the same one, and it is the half of CR-006
|
||||
# that a reader of the form would notice first.
|
||||
chips = page.eval("(document.getElementById('section-rail')||{}).textContent||''")
|
||||
chk("the section rail loses the same entries",
|
||||
"Assets" not in chips and "Kitting" not in chips, repr(chips))
|
||||
chk("...and keeps the rest", "Scope" in chips and "Constraints" in chips, repr(chips))
|
||||
|
||||
@@ -285,8 +298,13 @@ def run(page, base, tok, db_path):
|
||||
settle(1.4)
|
||||
page.eval(STUB)
|
||||
back = json.loads(page.eval("""JSON.stringify(%s.map(sel => {
|
||||
const el = document.querySelector(sel);
|
||||
return [sel, !el ? 'missing' : (el.hidden ? 'hidden' : 'shown')];
|
||||
const els = [...document.querySelectorAll(sel)];
|
||||
if (!els.length) return [sel, 'missing'];
|
||||
// A section may own more than one card (T7.2 split General Information).
|
||||
// querySelector() would answer for the first and quietly ignore the rest,
|
||||
// which is exactly the half-hidden failure this check exists to catch.
|
||||
const hidden = els.filter(e => e.hidden).length;
|
||||
return [sel, hidden === els.length ? 'hidden' : (hidden ? 'part-hidden' : 'shown')];
|
||||
}))""" % json.dumps([s[2] for s in SECTIONS])))
|
||||
chk("every section is back in the form", all(v == "shown" for _k, v in back), back)
|
||||
doc2 = render_full(page)
|
||||
@@ -416,8 +434,13 @@ def run(page, base, tok, db_path):
|
||||
chk("the creator boots on a SOP with no sections key", wait_creator(page))
|
||||
settle(1.2)
|
||||
legacy = json.loads(page.eval("""JSON.stringify(%s.map(sel => {
|
||||
const el = document.querySelector(sel);
|
||||
return [sel, !el ? 'missing' : (el.hidden ? 'hidden' : 'shown')];
|
||||
const els = [...document.querySelectorAll(sel)];
|
||||
if (!els.length) return [sel, 'missing'];
|
||||
// A section may own more than one card (T7.2 split General Information).
|
||||
// querySelector() would answer for the first and quietly ignore the rest,
|
||||
// which is exactly the half-hidden failure this check exists to catch.
|
||||
const hidden = els.filter(e => e.hidden).length;
|
||||
return [sel, hidden === els.length ? 'hidden' : (hidden ? 'part-hidden' : 'shown')];
|
||||
}))""" % json.dumps([s[2] for s in SECTIONS])))
|
||||
chk("...and shows all ten, because silence means on", all(v == "shown" for _k, v in legacy),
|
||||
legacy)
|
||||
@@ -533,8 +556,14 @@ def run(page, base, tok, db_path):
|
||||
page.goto(base + "/wp-creation-index.html?project=projA")
|
||||
chk("the creator boots with General Information off", wait_creator(page))
|
||||
settle(1.2)
|
||||
chk("the whole section is hidden",
|
||||
page.eval("document.getElementById('general-card').hidden"))
|
||||
chk("the whole section is hidden - BOTH of its cards",
|
||||
page.eval("""(() => ['#general-card', '#assign-card']
|
||||
.map(s => document.querySelector(s))
|
||||
.every(el => !!el && el.hidden))()"""),
|
||||
page.eval("""(() => JSON.stringify(['#general-card', '#assign-card'].map(s => {
|
||||
const el = document.querySelector(s);
|
||||
return [s, !el ? 'missing' : (el.hidden ? 'hidden' : 'shown')];
|
||||
})))()"""))
|
||||
page.eval("renderPackage(%s)" % json.dumps(withcost))
|
||||
settle(0.7)
|
||||
doc5 = page.eval("document.getElementById('pkg-doc').innerHTML")
|
||||
|
||||
Reference in New Issue
Block a user