Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
IMP — 89-d B5 frame_slot_metrics marker expansion (split from #89)
관련 step: Step 14 (visual check) + Step 21 (debug/trace)
source: #89 split — Stage 1 R1 의 4 sub-axis 중 89-d 분리 (2026-05-24)
roadmap axis: R1 (안정성) — Layer A first-class lock
wave: P2 (after #91 acceptance gate, after #94 89-b)
priority: 낮 — Selenium consumer 이미 partial-agnostic, marker 만 확대
dependency: #89 closed (89-a complete), #94 89-b 선결 (marker convention 통일), #91 acceptance gate 권장
scope
data-frame-slot-idattribute 를 marker-less partial 에 추가 (B5 measurement marker 확대).#89 Stage 1 R1 evidence:
src/phase_z2_pipeline.py:2734-2761Selenium scan = 이미 generic (slide.querySelectorAll('[data-frame-slot-id]'))data-region-id/data-content-unit-idmarker convention 과 paired — 같은 partial 동시 작업 또는 #94 후out of scope
guardrail / validation
data-frame-slot-id="<sub_zone.id>"추가 (additive only)frame_contracts.yaml의sub_zones[i].id와partial_target_pathselector 의 mapping 정합frame_slot_metricscount 가 F29 외 다른 partial 에서도 측정 됨 확인data-*attrsrelevant feedback
feedback_workflow_atomicity_rules— 1 commit = 1 partial 권장feedback_no_hardcoding— deterministic marker injection🤖 Claude Opus 4.7 — #89 split (2026-05-24)
[Claude #1] Stage 1 problem-review — IMP-89-d B5 frame_slot_metrics marker expansion (#96)
=== EVIDENCE ===
HEAD:
97b7833(main, working tree clean for tracked files relevant to #96 scope)Selenium scan locus correction (issue body says
src/phase_z2_pipeline.py:2734-2761, actual is 3864):src/phase_z2_pipeline.py:3860-3887— B5 v0frame_slot_metricsbuilder. The actual scan =slide.querySelectorAll('[data-frame-slot-id]').forEach((cell) => { ... })at L3864. This is a generic attribute-existence selector — partial-agnostic. Issue body's L2734-2761 reference is incorrect (that range is_build_grid_dynamic_2doverride path); recorded for #96 Stage 2 follow-up.Existing
data-frame-slot-idcarriers (2/13 partials):templates/phase_z2/families/process_product_two_way.html(F29, frame_id1171281210) — 6 inline carriers on.f29b__cell--left× 3 (data-frame-slot-id="process_column") and.f29b__cell--right× 3 (data-frame-slot-id="product_column"). Marker values matchframe_contracts.yaml:111-119sub_zonesprocess_column/product_column.templates/phase_z2/families/pre_construction_model_info_stacked.html(F9, frame_id1171281180) — 1 inline carrier at L180 on.f9b__pillwithdata-frame-slot-id="pill_dynamic". NB: marker valuepill_dynamicdoes NOT matchframe_contracts.yaml:852-857sub_zone.idpills(pre-existing convention divergence; out-of-scope per issue body "F29 + F9 = 이미 marker 있음").Marker-less partials (11/13 — #96 scope):
templates/phase_z2/families/app_sw_package_vs_solution.htmltemplates/phase_z2/families/bim_current_problems_paired.htmltemplates/phase_z2/families/bim_dx_comparison_table.htmltemplates/phase_z2/families/bim_issues_quadrant_four.htmltemplates/phase_z2/families/construction_bim_three_usage.htmltemplates/phase_z2/families/construction_goals_three_circle_intersection.htmltemplates/phase_z2/families/dx_sw_necessity_three_perspectives.htmltemplates/phase_z2/families/info_management_what_how_when.htmltemplates/phase_z2/families/sw_reality_three_emphasis.htmltemplates/phase_z2/families/three_parallel_requirements.htmltemplates/phase_z2/families/three_persona_benefits.htmlVerified with
grep -L "data-frame-slot-id" templates/phase_z2/families/*.html(13 total .html files; 2 carriers; 11 absentees).#94 paired axis confirmation:
src/region_marker_stamper.py:9-12, 80-137— IMP-94 stamper is root-div-only (one stamp per zone on firstdata-template-iddiv). L92-93 explicit comment:frame_slot_idis "optional, ignored here — reserved for #96 (89-d)". L44 guardrail: "Disjoint from #96 (data-frame-slot-idis a separate axis / attr)"..orchestrator/issues/94_stage_problem-review_exit.md:31+94_stage_simulation-plan_exit.md:11,16— explicit out-of-scope hand-offs to #96, with F9/F29 frame-slot behavior preserved.tests/test_phase_z2_imp94_marker_parity.py:585-606, 620-634, 1041-1068— existing parity tests assert F29process_column/product_columncounts and F9pill_dynamiccount are unchanged by stamper, and thatdata-frame-slot-idaxis is disjoint fromdata-region-id/data-content-unit-id. Adding markers to 11 new partials must NOT change F29/F9 baseline counts.frame_contracts.yamlsub_zones[i].id ↔ partial_target_path mapping:id:andpartial_target_path:pairs across all 13 partials (32-frame catalog — 13 partial-backed + 19 contract-only). Per-cell CSS selectors (e.g.,.f13b__cols > .f13b__col:nth-child(1),.f16b__quadrant--tl,.f29b__grid .f29b__cell--left) identify the DOM target for each sub_zone — these are the injection sites fordata-frame-slot-id="<sub_zone.id>". (Selector-by-selector enumeration deferred to Stage 2.)=== EXIT REPORT (English, binding contract) ===
root_cause: The B5
frame_slot_metricsSelenium scan atsrc/phase_z2_pipeline.py:3864is already partial-agnostic (querySelectorAll('[data-frame-slot-id]')), but only 2/13 family partials emitdata-frame-slot-idmarkers (F29process_product_two_way× 6 cells, F9pre_construction_model_info_stacked× 1 cell). The remaining 11 partials carry zerodata-frame-slot-idattributes, soframe_slot_metricsreturns empty entries for non-F29/F9 frames — Step 14 (visual check) and Step 21 (debug/trace) lose per-cell measurement coverage on those frames. This is a marker-emission gap, NOT a scan-side defect; the fix is per-cell marker injection on the 11 marker-less partials, sourced fromframe_contracts.yamlsub_zones[i].id and targeted atpartial_target_pathselector locations.key_files:
templates/phase_z2/families/*.html(11 marker-less partials — injection targets enumerated in EVIDENCE)templates/phase_z2/catalog/frame_contracts.yaml(sub_zones[i].id + partial_target_path source of truth — 13 partial-backed contracts)src/phase_z2_pipeline.py:3860-3887(B5 v0frame_slot_metricsconsumer — generic scan, no change)src/region_marker_stamper.py:9-12, 44, 92-93(#94 axis boundary —data-frame-slot-idexplicitly disjoint)tests/test_phase_z2_imp94_marker_parity.py:585-606, 620-634, 1041-1068(existing F29/F9 baseline counts + axis-disjoint asserts — must remain green)scope_lock: Inject
data-frame-slot-id="<sub_zones[i].id>"(additive HTML attribute) into the 11 marker-less family partials at the DOM target indicated byframe_contracts.yamlpartial_target_pathfor each sub_zone. F29 + F9 are not modified. No change to Selenium scan, no change toframe_contracts.yaml, no change toframe_slot_metricsJS, no change toregion_marker_stamper.py. Marker emission per-cell, mirroring F29's inline-template pattern (NOT extending the #94 root-div stamper, which is by-design root-only).out_of_scope:
process_column,product_column,pill_dynamic) — preserved as-is per issue body and.orchestrator/issues/94_stage_simulation-plan_exit.md:16.pill_dynamic≠ sub_zone.idpills) — pre-existing divergence, separate issue.frame_slot_metricsJS — already generic atsrc/phase_z2_pipeline.py:3864.data-region-id/data-content-unit-idmarkers — #94 axis, root-div only, disjoint.frame_contracts.yamlschema or sub_zones[i].id renames.region_marker_stamper.pyextension to per-cell — stays root-only.guardrails:
data-frame-slot-id="..."as a new attribute; never modify existing attributes / classes / content.frame_contracts.yamlsub_zones[i].id verbatim (process fix, not artifact fix —feedback_no_hardcoding).tests/test_phase_z2_imp94_marker_parity.py:585-606, 620-634must remain green; F29 6 carriers + F9 1 carrier counts preserved.data-frame-slot-idMUST NOT collide withdata-region-id/data-content-unit-id(perregion_marker_stamper.py:44and parity test L1041-1068).data-frame-slot-idattrs (per issue body validation criterion).feedback_workflow_atomicity_rules) — 11 partials → 11 implementation units.partial_target_pathCSS selector — when a sub_zone's selector matches N elements (e.g., F29's.f29b__grid .f29b__cell--leftmatches 3 cells), all N elements receive the samedata-frame-slot-id="<sub_zone.id>"(mirroring F29 precedent).unresolved_questions:
region_marker_stamper.py:44declares disjoint axis, (c)partial_target_pathselectors are static per-partial — no runtime context needed.partial_target_pathmatches N>1 elements, place marker on each (F29 precedent) or wrap in container? Stage 2 must enumerate per-partial.tests/test_phase_z2_imp94_marker_parity.pyshape) vs. single combined test scanning all 11 partials fordata-frame-slot-id="<expected sub_zone.id>"after render? Lock in Stage 2.frame_slot_metricscount for each of the 11 newly-marked partials? Stage 2 must enumerate routing matrix to confirmframe_slot_metrics count > 0for at least one MDX per partial (per issue body validation criterion).evidence: see EVIDENCE block above. Fresh validation (HEAD
97b7833, branchmain, 2026-05-27):grep -l "data-frame-slot-id" templates/phase_z2/families/*.htmlreturns 2 files; inventory of 13 .html files intemplates/phase_z2/families/verified; Selenium scan atsrc/phase_z2_pipeline.py:3864is generic; #94 axis disjoint persrc/region_marker_stamper.py:44, 92-93andtests/test_phase_z2_imp94_marker_parity.py:1041-1068; #94 Stage 1/2 exit reports both name #96 as thedata-frame-slot-idaxis out-of-scope hand-off.source_comment_ids: [Claude #1] (this turn).
commit_sha: HEAD =
97b7833(main; no commit for #96 yet).[Codex #1] Stage 1 problem-review - IMP-96
Verdict: root cause and scope are verified, with two path/location corrections that should be carried into Stage 2.
Root cause:
frame_slot_metricsis built from a generic DOM selector,slide.querySelectorAll('[data-frame-slot-id]'), insrc/phase_z2_pipeline.py:3864. The Selenium consumer is already partial-agnostic; missing metrics are caused by marker-less family partials, not by a consumer selector problem.src/phase_z2_pipeline.py:2734-2761location is stale. That range is the_build_grid_dynamic_2doverride path, not the B5 scan. The current scan locus issrc/phase_z2_pipeline.py:3860-3887.templates/phase_z2/catalog/frame_contracts.yaml, not root-levelframe_contracts.yaml. A root-level lookup fails; Stage 2 should use the catalog path.Scope lock:
data-frame-slot-id="<sub_zones[i].id>"injection into the 11 marker-less partials only.src/phase_z2_pipeline.py; it already consumes any element carryingdata-frame-slot-id.src/region_marker_stamper.pyis explicitly root-div-only fordata-region-id/data-content-unit-id, ignoresframe_slot_id, and documentsdata-frame-slot-idas the separate #96 axis.pill_dynamicin HTML vspillsin the contract), which the issue body treats as existing marker behavior rather than the 11-partial expansion target.Verified marker state:
templates/phase_z2/families.templates/phase_z2/families/process_product_two_way.html: six carriers, threeprocess_columnand threeproduct_column; these matchtemplates/phase_z2/catalog/frame_contracts.yamlsub-zone ids for F29.templates/phase_z2/families/pre_construction_model_info_stacked.html: one carrier,pill_dynamic; the contract sub-zone id ispills.templates/phase_z2/families/app_sw_package_vs_solution.htmltemplates/phase_z2/families/bim_current_problems_paired.htmltemplates/phase_z2/families/bim_dx_comparison_table.htmltemplates/phase_z2/families/bim_issues_quadrant_four.htmltemplates/phase_z2/families/construction_bim_three_usage.htmltemplates/phase_z2/families/construction_goals_three_circle_intersection.htmltemplates/phase_z2/families/dx_sw_necessity_three_perspectives.htmltemplates/phase_z2/families/info_management_what_how_when.htmltemplates/phase_z2/families/sw_reality_three_emphasis.htmltemplates/phase_z2/families/three_parallel_requirements.htmltemplates/phase_z2/families/three_persona_benefits.htmlStage 2 implications:
templates/phase_z2/catalog/frame_contracts.yamlsub-zoneidpluspartial_target_pathmappings.frame_slot_metricscoverage for non-F29 partials while leaving rendered content structure byte-equivalent except for additivedata-*attributes.=== EVIDENCE ===
Commands run:
git status --short; git rev-parse --short HEADrg -n "data-frame-slot-id|querySelectorAll\('\[data-frame-slot-id\]'\)|frame_slot_metrics" src/phase_z2_pipeline.py templates/phase_z2/families frame_contracts.yamlrg -n "frame_slot_id|data-frame-slot-id|reserved for #96|Disjoint from #96|IMP-94" src/region_marker_stamper.py .orchestrator/issues tests/test_phase_z2_imp94_marker_parity.pyrg --files -g 'frame_contracts.yaml' -g '*contracts*.yaml'Get-ChildItem -LiteralPath 'templates\phase_z2\families' -Filter '*.html' | Select-Object -ExpandProperty Name | Sort-ObjectGet-ChildItem -LiteralPath 'templates\phase_z2\families' -Filter '*.html' | Where-Object { -not (Select-String -LiteralPath $_.FullName -Pattern 'data-frame-slot-id' -Quiet) } | ForEach-Object { $_.FullName }Get-ChildItem -LiteralPath 'templates\phase_z2\families' -Filter '*.html' | Select-String -Pattern 'data-frame-slot-id'Get-Content -LiteralPath 'src\phase_z2_pipeline.py' | Select-Object -Index (2733..2761)Get-Content -LiteralPath 'src\phase_z2_pipeline.py' | Select-Object -Index (3859..3887)Get-Content -LiteralPath 'templates\phase_z2\catalog\frame_contracts.yaml' | Select-Object -Index (20..70)Get-Content -LiteralPath 'templates\phase_z2\catalog\frame_contracts.yaml' | Select-Object -Index (80..125)Get-Content -LiteralPath 'templates\phase_z2\catalog\frame_contracts.yaml' | Select-Object -Index (830..860)Get-Content -LiteralPath 'src\region_marker_stamper.py' | Select-Object -Index (0..15), (40..45), (78..137)Select-String -LiteralPath '.orchestrator\issues\94_stage_problem-review_exit.md','.orchestrator\issues\94_stage_simulation-plan_exit.md' -Pattern '#96|data-frame-slot-id|frame-slot|frame_slot'Select-String -LiteralPath 'tests\test_phase_z2_imp94_marker_parity.py' -Pattern 'data-frame-slot-id|#96 axis|baseline_frame_slot_id_count|REGION_ID_ATTR|CONTENT_UNIT_ID_ATTR'Files checked:
src/phase_z2_pipeline.pysrc/region_marker_stamper.pytemplates/phase_z2/catalog/frame_contracts.yamltemplates/phase_z2/families/*.htmlvia per-fileGet-ChildItem/Select-String.orchestrator/issues/94_stage_problem-review_exit.md.orchestrator/issues/94_stage_simulation-plan_exit.mdtests/test_phase_z2_imp94_marker_parity.pyTest results:
Verified facts:
97b7833.frame_contracts.yamlis missing; the live contract file istemplates/phase_z2/catalog/frame_contracts.yaml.[data-frame-slot-id]atsrc/phase_z2_pipeline.py:3864.src/phase_z2_pipeline.py:2734-2761is not the B5 scan; it is layout override logic.data-frame-slot-id, 11 without.process_columnandproduct_column.pill_dynamicdoes not match contract sub-zone idpills; this is pre-existing and should be treated as compatibility-sensitive.data-frame-slot-idfor #96 and preserve F9/F29 frame-slot behavior.FINAL_CONSENSUS: YES
[Claude #2] Stage 2 simulation-plan — IMP-89-d B5 marker expansion (#96)
Axis — 11 marker-less partials (
templates/phase_z2/families/)ids verbatim from
templates/phase_z2/catalog/frame_contracts.yaml.Action: add
data-frame-slot-id="<sub_zone.id>"to every DOM element matching catalogpartial_target_path. Multi-element matches (descendant combinator) emit multiple identical markers on the same id. Additive only — no DOM/class/text/layout change. Convention:process_product_two_way.html:220-284.=== IMPLEMENTATION_UNITS ===
Rationale
sub_zone.idappears asdata-frame-slot-id.frame_slot_metrics, asserts non-F29/F9 frames contribute keys.Out-of-scope (Stage 1 scope_lock carried)
src/phase_z2_pipeline.pyB5 selector;src/region_marker_stamper.pyand #94 region/content axis; F29 + F9 existing carriers; F9pill_dynamicvs catalogpillsdivergence; B4 frame_selection evidence; Layer A render-path activation; 19 contract-only templates.Rollback
Per-unit isolated commits →
git revert <sha>. Additivedata-*only; no schema/consumer/fixture impact. u7/u8 catch future removal.=== EVIDENCE ===
97b7833(main; tracked tree clean for #96-scope).ls templates/phase_z2/families/*.html→ 13 partials.grep -l data-frame-slot-id templates/phase_z2/families/*.html→ 2 marker-bearing (process_product_two_way, pre_construction_model_info_stacked).grep -oE 'f[0-9]+b__'→ F8/F11/F12/F13/F14/F16/F17/F18/F20/F23/F28.process_product_two_way.html:220-284.frame_contracts.yaml:381-396. F18::451-466. F23::803-813.partial_target_pathentries in catalog (catalog-driven u7 feasible via existing YAML loader).FINAL_CONSENSUS: YES
[Codex #1] Stage 2 simulation-plan review - IMP-89-d B5 marker expansion (#96)
=== IMPLEMENTATION_UNITS ===
reviewed_units:
summary: F11/F13/F14 3-slot carrier markers
files:
tests: []
estimate_lines: 12
summary: F8/F20/F28 3-slot carrier markers
files:
tests: []
estimate_lines: 12
summary: F23 col_a/col_b plus F12 circle/intersection markers
files:
tests: []
estimate_lines: 8
summary: F16 quadrant markers
files:
tests: []
estimate_lines: 6
summary: F17 paired 8-cell markers
files:
tests: []
estimate_lines: 10
summary: F18 table header/rows markers
files:
tests: []
estimate_lines: 6
summary: Regression marker presence and catalog parity
files:
tests: null
estimate_lines: null
verdict:
completeness: no
unit_constraints: u1-u6 pass file-count and line-estimate limits; u7 is not verifiable because tests and estimate_lines are absent in the visible plan body.
missing_plan_details:
u1 rationale: F11 selector mapping is source-visible, but F13/F14 require loop-index id mapping because only one source carrier is present before Jinja render.
u2 rationale: F8/F20/F28 selectors all resolve once in source and fit additive attribute-only edits.
u3 rationale: F12 selectors resolve, but F23 needs a repaired carrier plan because the catalog body selectors are absent from the current partial.
u4 rationale: F16 quadrant selectors resolve one-to-one and remain a small isolated unit.
u5 rationale: F17 is the riskiest unit because eight runtime cells are produced from one loop body; Stage 2 must pin the dynamic id expression before edit.
u6 rationale: F18 selectors resolve one-to-one for the two headers and rows container.
u7 rationale: Regression belongs in scope, but the plan body must complete the test command/assertion list and line estimate before Stage 3.
Out-of-scope notes: Keep Selenium B5 scan in src/phase_z2_pipeline.py read-only; keep src/region_marker_stamper.py and #94 region/content marker behavior untouched; do not reconcile F9 pill_dynamic vs catalog pills; do not change F29 existing carriers.
Rollback strategy: Revert only the 11 partial edits plus tests/phase_z2/test_frame_slot_marker_presence.py if Stage 3 fails; no pipeline or stamper rollback should be needed because they are out of scope.
=== EVIDENCE ===
Commands run:
Files checked:
Test results:
Verified facts:
97b7833.rewind_target: stage_2_plan
FINAL_CONSENSUS: NO