feat(#39): IMP-30 first-render invariant + abort bypass (2 paths)
Restore first-render invariant: final.html + Step 20 slide_status MUST be written for every input where Step 0~5 succeed. Two abort paths replaced with provisional/empty-shell synthesis; MDX content preserved, AI-free. - u1 V4Match.provisional + lookup_v4_match_with_fallback(allow_provisional) chain_exhausted -> synthesize rank-1 provisional (opt-in, default-off) - u2 CompositionUnit.provisional propagation (single / parent_merged / parent_merged_inferred constructors) - u3 select_composition_units(allow_provisional_fill=True) last-resort fill + _candidate_state="selected_provisional" - u4 pipeline.py path-(a) abort guard replaced with provisional retry + terminal __empty__ shell (no sys.exit(1)) - u5 zones_data.provisional -> slide_base.html zone--provisional class + data-provisional + needs-adaptation badge (template-only) - u6 compute_slide_status additive provisional_first_render_count/_units (overall enum unchanged per IMP-05 Codex #10 D4) - u7 regression: tests/test_phase_z2_imp30_first_render.py (28 tests) + tests/test_phase_z2_v4_fallback.py (+5 cases) Guardrails verified: MVP1_ALLOWED_STATUSES unchanged, no calculate_fit, no LLM in fallback path, no MDX 03/04/05 hardcoding. Anchor sync (Rule 13): tests/orchestrator_unit/test_imp17_comment_anchor.py re-pinned 564/565 -> 570/571 to track V4Match.provisional shift at src/phase_z2_pipeline.py:179-184. Cross-ref: IMP-05 (#5) §5 defer + Codex #2 first-render invariant.
This commit is contained in:
@@ -114,6 +114,43 @@
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* ── IMP-30 u5 : provisional zone marker (first-render invariant) ──
|
||||
When V4 rank-1 candidate falls outside MVP1_ALLOWED_STATUSES (chain_exhausted)
|
||||
the pipeline still renders the rank-1 frame so the first-render invariant
|
||||
holds, but the zone is tagged `provisional` so the user/AI can adapt later
|
||||
(IMP-31). Visual contract:
|
||||
- dashed amber border + striped wash → "needs adaptation" at a glance
|
||||
- inline badge top-right → text label for non-color-perceiving readers
|
||||
MDX content is preserved as-is; no shrink, no rewrite. */
|
||||
.zone--provisional {
|
||||
outline: 2px dashed #b8860b;
|
||||
outline-offset: -2px;
|
||||
background-image: repeating-linear-gradient(
|
||||
45deg,
|
||||
rgba(184, 134, 11, 0.04) 0,
|
||||
rgba(184, 134, 11, 0.04) 8px,
|
||||
transparent 8px,
|
||||
transparent 16px
|
||||
);
|
||||
}
|
||||
.zone--provisional .zone__needs-adaptation-badge {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 10;
|
||||
padding: 2px 6px;
|
||||
background: #b8860b;
|
||||
color: #fff;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
letter-spacing: 0.04em;
|
||||
border-radius: 2px;
|
||||
text-transform: uppercase;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* ── Frame-family text layout contract (shared, reusable) ──
|
||||
feedback-1 (mvp1.5b_test7): visible improvement 강화.
|
||||
Stronger hanging indent + breathing line spacing + visible hierarchy. */
|
||||
@@ -264,7 +301,8 @@
|
||||
<div class="slide-body">
|
||||
<div class="layout-{{ layout_preset }}">
|
||||
{% for zone in zones %}
|
||||
<div class="zone" data-zone-position="{{ zone.position }}" data-template-id="{{ zone.template_id }}" style="grid-area: {{ zone.position }};">
|
||||
<div class="zone{% if zone.provisional %} zone--provisional{% endif %}" data-zone-position="{{ zone.position }}" data-template-id="{{ zone.template_id }}"{% if zone.provisional %} data-provisional="1"{% endif %} style="grid-area: {{ zone.position }};">
|
||||
{% if zone.provisional %}<span class="zone__needs-adaptation-badge" aria-label="needs user or AI adaptation">needs adaptation</span>{% endif %}
|
||||
{{ zone.partial_html | safe }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user