Files
C.E.L_Slide_test2/docs/architecture/PHASE-Z-OVERLAY-SCHEMA.md
kyeongmin 7762f6766a Lock Phase Z overlay schema for Option E migration
- categorize F13/F29/F16 frame_contracts fields as overlay-only, templates_v1-derived, or validation duplicate
- lock duplicate hard-error, 1:1 keyspace, manual trigger, semantic-identical rollback
- defer analysis.md direction inversion and 32-frame audit as separate axes
2026-05-07 11:19:52 +09:00

178 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase Z Overlay Schema (Option E first migration)
**Status**: Step 0 schema lock — pre-execution spec.
**Scope**: F13 / F29 / F16 only (3 active Phase Z frames).
**Last updated**: 2026-05-07.
---
## 0. Why this doc exists
`templates/phase_z2/catalog/frame_contracts.yaml` is currently a hand-curated island. It must be hand-edited whenever a Phase Z frame's slot/sub_zone/payload structure changes, even though most of its sibling Phase Z artifacts (V4 matching results, `structure_ontology.yaml` `templates_v1` section, `figma_to_html_agent/blocks/{frame_id}/analysis.md`) are auto-generated from upstream sources.
Option E first migration converts `frame_contracts.yaml` to a **generated artifact**:
```
runtime_overlay/{template_id}.yaml (per-template Phase Z fields, hand-edited)
+
templates_v1[frame_id] (cross-validation only in first migration)
build_phase_z2_frame_contracts.py (generator)
templates/phase_z2/catalog/frame_contracts.yaml (committed, generated)
Phase Z runtime (unchanged — reads frame_contracts.yaml the same way)
```
This doc locks the schema/keyspace/trigger/rollback rules **before** any overlay file or generator code is written.
---
## 0-1. Field owner table
Each field in current `frame_contracts.yaml` is classified as one of:
- **(a) templates_v1-derived** — generator looks up from `tests/matching/structure_ontology.yaml` `templates_v1` section. **Not declared in overlay.**
- **(b) overlay-only** — Phase Z 전용 operational config. **Declared in `runtime_overlay/{template_id}.yaml`.**
- **(c) validation duplicate** — generator cross-checks overlay value against `templates_v1`. Disagreement → hard error.
### F13 — three_parallel_requirements (frame_id 1171281190)
| Field | Current value | Category | Note |
|---|---|---|---|
| `template_id` | `three_parallel_requirements` | (c) | overlay filename = template_id; cross-check `templates_v1['1171281190'].template_id` |
| `frame_id` | `1171281190` | (b) | overlay declares; generator confirms it exists as a `templates_v1` key |
| `family` | `three_parallel` | (b) | Phase Z categorization. Not the same as `templates_v1.visual_pattern.family` (= `list`) — different semantic axis. Name overlap is incidental. |
| `source_shape` | `top_bullets` | (b) | Phase Z B1 extractor signal. Not in `templates_v1`. |
| `cardinality.strict` | `3` | (c) | cross-check against `templates_v1.visual_pattern.cardinality` — must equal `min` (and `max` if min==max). |
| `cardinality.overflow_policy` | `abort_or_review` | (b) | Phase Z fallback policy. |
| `role_order` | `[tech, people, nature]` | (b) | F13-specific visual role mapping. Not in `templates_v1`. |
| `visual_hints.min_height_px` | `230` | (b) | Phase Z layout calculation. Not in `templates_v1`. |
| `accepted_content_types` | `[text_block]` | (b) | SPEC v1 §3 Layer A→B input. Not in `templates_v1`. |
| `sub_zones` | `[pillar_1, pillar_2, pillar_3]` (with `partial_target_path`) | (b) | Phase Z Frame Slot declaration. Conceptually overlaps with `templates_v1.slots` (`pillar_*_label/body`) but different shape (sub_zones = column units; slots = label+body pairs). |
| `payload.*` | `{title, builder, builder_options}` | (b) | Phase Z mapper directives. Not in `templates_v1`. |
### F29 — process_product_two_way (frame_id 1171281210)
| Field | Current value | Category | Note |
|---|---|---|---|
| `template_id` | `process_product_two_way` | (c) | filename = template_id; cross-check |
| `frame_id` | `1171281210` | (b) | |
| `family` | `two_column_h3` | (b) | `templates_v1.visual_pattern.family` = `compare`; intentionally different |
| `source_shape` | `h3_subsections` | (b) | F29-specific B1 path |
| `cardinality.strict` | `2` | (c) | cross-check against `templates_v1.visual_pattern.cardinality.{ideal:2, min:2, max:2}` |
| `cardinality.overflow_policy` | `abort_or_review` | (b) | |
| `visual_hints.min_height_px` | `345` | (b) | |
| `accepted_content_types` | `[text_block, transform_table]` | (b) | F29 process column accepts AS-IS/TO-BE table |
| `sub_zones` | `[process_column, product_column]` (each `cardinality.strict: 3`) | (b) | 2 column × 3 sections; sub_zone unit = column |
| `payload.*` | `{title, builder=process_product_pair, builder_options}` | (b) | |
### F16 — bim_issues_quadrant_four (frame_id 1171281193)
| Field | Current value | Category | Note |
|---|---|---|---|
| `template_id` | `bim_issues_quadrant_four` | (c) | |
| `frame_id` | `1171281193` | (b) | |
| `family` | `bim_issues_quadrant` | (b) | `templates_v1.visual_pattern.family` = `cards` |
| `source_shape` | `top_bullets` | (b) | |
| `cardinality.strict` | **(not declared)** | n/a | F16 intentionally omits — uses `pad_to=4` + `truncate>4` policy in `payload.builder_options`. `templates_v1.cardinality` has `{ideal:4, min:4, max:4}` but Phase Z does not enforce strict here. **Generator must NOT auto-derive this from `templates_v1`.** |
| `accepted_content_types` | `[text_block]` | (b) | |
| `sub_zones` | `[quadrant_1, quadrant_2, quadrant_3, quadrant_4]` (each `cardinality.strict: 1`) | (b) | sub_zone-level cardinality = capacity; not the same as frame-level |
| `payload.*` | `{title, builder=quadrant_flat_slots, builder_options.{item_parser, pad_to, truncate_at, label_key_pattern, body_key_pattern, empty_label, empty_body}}` | (b) | |
### Summary
- **(a) templates_v1-derived**: **none** in first migration. Overlay declares all operational config.
- **(b) overlay-only**: ~all fields. Overlay file is essentially a per-template extract of the current `frame_contracts.yaml` entry.
- **(c) validation duplicate**: 2 fields per template — `template_id` (overlay filename matches `templates_v1[frame_id].template_id`) and `cardinality.strict` when present (must match `templates_v1.visual_pattern.cardinality.min`).
**Implication**: first migration is mostly a **split-and-concatenate** refactor with light cross-validation. Migration value is (i) per-template editing isolation, (ii) `templates_v1` consistency check at build time. Heavier derivation (e.g., generating `cardinality.strict` from `templates_v1` automatically) is **별 axis** — defer until a concrete need surfaces.
---
## 0-2. Duplicate rule — hard error
If an overlay file declares a field that is classified as **(a) templates_v1-derived**, generator **fails immediately** with a clear message. No silent override semantics.
Currently no fields are in (a), so this rule is dormant for first migration. It exists to prevent regression: a future overlay author cannot quietly duplicate a `templates_v1`-owned field without removing the (a) classification first.
For **(c) validation duplicate** fields, the rule is:
- Overlay declares the value.
- Generator looks up the corresponding value in `templates_v1`.
- If the two **disagree**, hard error with both values printed and a pointer to this doc.
This preserves the lock-layer "overlay = single source of truth for declared values" while making `templates_v1` drift visible.
---
## 0-3. Keyspace rule
- **Source ref** = `frame_id` (Figma origin).
- **Overlay identity** = `template_id` (filename: `runtime_overlay/{template_id}.yaml`).
- **First-migration assumption**: `frame_id``template_id` is **1:1** for all active Phase Z frames (F13/F29/F16).
- **Generator verification**: for each overlay, the generator looks up `templates_v1[overlay.frame_id].template_id` and asserts it equals the overlay filename's `{template_id}`. Mismatch → hard error.
- **Multi-variant** (one frame ↔ multiple templates) = **별 axis**. When that case appears, this doc is updated and the keyspace becomes a composite key. Until then, 1:1 is locked.
---
## 0-4. Trigger
- **Manual run** for first migration:
```
python scripts/build_phase_z2_frame_contracts.py
```
- **Verification** (semantic-identical) is **required** after each run. Generator should refuse to write output if the result differs semantically from current `frame_contracts.yaml` during first migration.
- **CI / pre-commit automation** = **별 axis**. Will be considered after first migration ships and a drift incident actually occurs. Adding it now is over-engineering for 3 templates.
---
## 0-5. Rollback / failure path
If `semantic-identical` verification fails (`yaml.safe_load(current) != yaml.safe_load(generated)`):
1. **Generated artifact is NOT adopted.** No write to `frame_contracts.yaml`.
2. Current `frame_contracts.yaml` remains canonical (status quo preserved).
3. Diff source: overlay schema, generator implementation, or `templates_v1` cross-check rule. Identify root cause.
4. Fix overlay/schema/generator. Retry from Step 1.
5. **Migration is incomplete**: 3 active templates partially migrated count as failure — either all 3 ship or none.
The migration commit (Step 5) is **only made after** all 3 templates pass both (a) semantic-identical and (b) Phase Z runtime regression (final.html identical).
---
## 0-6. Scope boundary
**Option E first migration solves**:
- `frame_contracts.yaml` island problem (hand-curated → generated).
- Per-template editing isolation.
- Light `templates_v1` consistency check at build time.
**Option E first migration does NOT solve** (= 별 axis, NOT addressed by this migration):
- `analysis.md` ↔ `structure_ontology.yaml` ownership direction conflict. Specifically: `figma_to_html_agent/CLAUDE.md` implies forward direction (agent owns `analysis.md`), while `tests/matching/sync_analysis_from_ontology.py` enforces reverse direction (`structure_ontology.yaml` is source, `analysis.md` is mirror). This is a separate architectural decision and is out of scope here.
- `templates/blocks/structures` legacy retirement.
- `legacy templates/catalog/blocks.yaml` removal.
- `zone_extract` rule formalization (long-term zone_application policy).
- 32-frame full audit (only active F13/F29/F16 in first migration).
When the user resumes work on the direction inversion axis, this doc is **not invalidated** — overlay schema and generator continue to work because they read `templates_v1` (not `analysis.md`).
---
## Migration steps (post-Step 0)
1. Create `templates/phase_z2/catalog/runtime_overlay/{F13,F29,F16}.yaml` files. Each contains the (b) overlay-only fields + (c) validation duplicate values for one template.
2. Write `scripts/build_phase_z2_frame_contracts.py` generator. Reads overlays + `templates_v1`, applies 0-2 / 0-3 rules, writes generated `frame_contracts.yaml`.
3. Run generator. Verify `yaml.safe_load(current) == yaml.safe_load(generated)`. List order preserved (sub_zones especially). On disagreement → 0-5 rollback.
4. Run Phase Z pipeline once (regression MDX) — confirm `final.html` is byte-identical to current run.
5. Commit Option E migration (overlay files + generator + new generated `frame_contracts.yaml` with header). Separate commit from Step 0 schema doc.
---
## Out of scope for this doc
- Generator implementation details (parsing, emit format, error message templates) — captured in the script itself.
- Overlay file format details beyond field categorization — captured in the overlay files themselves.
- Direction inversion fixes — see future axis docs.