Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions milestones/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ repositories that install `docgen` and maintain their own demo bundle. The
library no longer ships an in-repo dogfood; consumers are the integration test
of record.

**Active:** **[scene-spec-bool-numerics.md](scene-spec-bool-numerics.md)** —
scene-spec `wait_word` / `run_time` / sizes must not coerce YAML bools.
**Active:** **[scene-spec-layout-gaps.md](scene-spec-layout-gaps.md)** —
scene-spec layout gaps must not coerce YAML bools to 1.0.

**Shipped:**
- **[scene-spec-bool-numerics.md](scene-spec-bool-numerics.md)** —
scene-spec `wait_word` / `run_time` / sizes must not coerce YAML bools
(#147).
- **[grok-stt-start-end.md](grok-stt-start-end.md)** —
Grok STT word/segment `start` / `end` must be JSON numbers, not bools
(#146).
Expand Down
2 changes: 1 addition & 1 deletion milestones/scene-spec-bool-numerics.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Milestone: scene-spec numerics must not coerce bools

**Status:** Active
**Status:** Shipped
**PR:** [#147](https://github.com/jmjava/documentation-generator/pull/147)
**Depends on:** `milestones/grok-stt-start-end.md` (PR #146),
`milestones/visual-beats-numeric.md` (PR #120)
Expand Down
38 changes: 38 additions & 0 deletions milestones/scene-spec-layout-gaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Milestone: scene-spec layout gaps must be YAML numbers

**Status:** Active
**PR:** [#148](https://github.com/jmjava/documentation-generator/pull/148)
**Depends on:** `milestones/scene-spec-bool-numerics.md` (PR #147)

## Problem

PR #147 typed `wait_word` / `run_time` / sizes / `page_transition_run_time`.
Layout gaps still go through ``float()`` at compile:

```python
first_row_title_buff = float(layout.get("first_row_title_buff", 0.5))
row_gap = float(layout.get("row_gap", 0.6))
column_gap = float(layout.get("column_gap", 0.8))
```

`bool` is a subclass of `int`: `first_row_title_buff: true` becomes
**1.0** (looks like a valid gap). A string raises at compile, not at
`validate_scene_spec`.

## Goal

Present `layout.first_row_title_buff` / `row_gap` / `column_gap` must
be YAML numbers (not bool). Missing keys keep compile defaults.

## Done when

- [x] Bool / string layout gaps raise `SceneSpecError`
- [x] Missing gaps still validate (defaults at compile)
- [x] `ruff check src/ tests/`
- [x] `pytest tests/` (821 passed, 1 skipped)
- [x] `docgen benchmark` (no clock change; meets baseline)

## Out of scope

- Range floors (`MIN_TITLE_ROW_BUFF`) stay density warnings
- Issue #56
9 changes: 9 additions & 0 deletions src/docgen/scene_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,15 @@ def validate_scene_spec(data: dict[str, Any], *, path_label: str = "spec") -> No
raise SceneSpecError(
f"{path_label}: layout.dwell_run_time must be a number in (0, 3] if set"
)
for gap_key in ("first_row_title_buff", "row_gap", "column_gap"):
if gap_key not in layout or layout.get(gap_key) is None:
continue
gap_val = layout[gap_key]
if not _is_yaml_number(gap_val):
raise SceneSpecError(
f"{path_label}: layout.{gap_key} must be a YAML number, not "
f"{type(gap_val).__name__} ({gap_val!r})"
)

if has_rows:
rows = data["rows"]
Expand Down
17 changes: 17 additions & 0 deletions tests/test_scene_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,23 @@ def test_validate_rejects_bool_page_transition_run_time() -> None:
validate_scene_spec(spec)


def test_validate_rejects_bool_first_row_title_buff() -> None:
spec = _spec_with(layout={"first_row_title_buff": True})
with pytest.raises(SceneSpecError, match="first_row_title_buff must be a YAML number"):
validate_scene_spec(spec)


def test_validate_rejects_string_row_gap() -> None:
spec = _spec_with(layout={"row_gap": "0.6"})
with pytest.raises(SceneSpecError, match="row_gap must be a YAML number"):
validate_scene_spec(spec)


def test_validate_accepts_numeric_layout_gaps() -> None:
spec = _spec_with(layout={"first_row_title_buff": 0.5, "row_gap": 0.6, "column_gap": 0.8})
validate_scene_spec(spec)


def test_validate_rejects_wait_word_and_wait_segment_together() -> None:
with pytest.raises(SceneSpecError, match="at most one"):
validate_scene_spec(
Expand Down