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
9 changes: 6 additions & 3 deletions milestones/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ 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:** **[numeric-config-tunables.md](numeric-config-tunables.md)** —
timestamps / compose / manim / validation numeric tunables must be YAML
numbers (`true` used to become `int` 1).
**Active:** **[hint-segment-create-bool.md](hint-segment-create-bool.md)** —
hint `docgen.segment.create` must be a YAML boolean (`"false"` used to
still insert the segment).

**Shipped:**
- **[numeric-config-tunables.md](numeric-config-tunables.md)** —
timestamps / compose / manim / validation numeric tunables must be
YAML numbers (#115).
- **[discovery-bool-flags.md](discovery-bool-flags.md)** —
`discovery.auto_visual_map` / `merge_hint_segments` must be YAML
booleans (#114).
Expand Down
42 changes: 42 additions & 0 deletions milestones/hint-segment-create-bool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Milestone: hint segment create must be a YAML boolean

**Status:** Active
**PR:** [#116](https://github.com/jmjava/documentation-generator/pull/116)
**Depends on:** `milestones/numeric-config-tunables.md` (PR #115),
`milestones/hint-front-matter-yaml.md` (PR #102),
`milestones/discovery-bool-flags.md` (PR #114)

## Problem

`yaml-generate` inserts `segments.all` ids from `hints/*.md` when
`docgen.segment.create` is truthy. Identity/`bool()` was not used —
any truthy value counted, so:

1. Quoted **`create: "false"`** still declared the segment (non-empty
strings are truthy).
2. A YAML **list** `stem` was `str()`'d into `segment_names`.
3. A YAML **list** `id` failed the `\d{2}` check and was **skipped**
(the hint looked like prose-only).

YAML `create: false` already skipped. Integer `id: 5` still pads to
`"05"` (existing contract).

## Goal

Fail closed in `parse_hint_segment_declaration`. Present `create` must
be a YAML boolean. `stem` must be a YAML string. `id` must be a YAML
string or integer (not bool/list).

## Done when

- [x] `create: "false"` raises instead of inserting a segment.
- [x] List `stem` / `id` raise.
- [x] YAML `create: false` still skips; integer `id: 5` still pads.
- [x] `ruff check src/ tests/`
- [x] `pytest tests/` (672 passed, 1 skipped)
- [x] `docgen benchmark` (no clock change; meets baseline)

## Out of scope

- Changing the integer `id` zfill recovery (`id: 5` → `"05"`).
- `docgen.wiring` value types beyond existing mapping checks.
2 changes: 1 addition & 1 deletion milestones/numeric-config-tunables.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Milestone: pipeline numeric tunables must be YAML numbers

**Status:** Active
**Status:** Shipped
**PR:** [#115](https://github.com/jmjava/documentation-generator/pull/115)
**Depends on:** `milestones/discovery-bool-flags.md` (PR #114),
`milestones/manim-font-quality.md` (PR #106)
Expand Down
28 changes: 24 additions & 4 deletions src/docgen/yaml_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,20 +264,40 @@ def parse_hint_docgen_front_matter(md_path: Path) -> dict[str, Any] | None:


def parse_hint_segment_declaration(md_path: Path) -> tuple[str, str] | None:
"""If ``md_path`` has YAML front matter declaring ``docgen.segment`` with ``create: true``, return (id, stem)."""
"""If ``md_path`` has YAML front matter declaring ``docgen.segment`` with ``create: true``, return (id, stem).

``create`` must be a YAML boolean when present. Quoted ``\"false\"`` used
to be truthy and still insert the segment into ``segments.all``.
Integer ``id`` values (unquoted ``01`` → ``1``) are still padded to two
digits; ``stem`` must be a YAML string.
"""
from docgen.config import require_yaml_bool, require_yaml_string

doc = parse_hint_docgen_front_matter(md_path)
if not doc:
return None
seg = doc.get("segment")
if not isinstance(seg, dict) or not seg.get("create"):
if not isinstance(seg, dict):
return None
create = seg.get("create")
if create is None:
return None
src = md_path.name
if not require_yaml_bool(create, label="docgen.segment.create", source=src):
return None
sid = seg.get("id")
stem = seg.get("stem")
if sid is None or stem is None:
return None
if isinstance(sid, bool) or not isinstance(sid, (int, str)):
raise ValueError(
f"{src}: docgen.segment.id must be a YAML string or integer, not "
f"{type(sid).__name__} ({sid!r})"
)
require_yaml_string(stem, label="docgen.segment.stem", source=src)
sid_s = str(sid).strip()
stem_s = str(stem).strip()
if not sid_s or not stem_s:
stem_s = stem.strip()
if not sid_s:
return None
if sid_s.isdigit():
sid_s = sid_s.zfill(2)
Expand Down
30 changes: 30 additions & 0 deletions tests/test_yaml_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,36 @@ def test_parse_hint_segment_declaration_requires_create_true(tmp_path: Path) ->
assert parse_hint_segment_declaration(h / "ok.md") == ("05", "05-from-hints")


def test_parse_hint_segment_declaration_string_create_false_raises(tmp_path: Path) -> None:
h = tmp_path / "seg.md"
h.write_text(
"---\ndocgen:\n segment:\n create: \"false\"\n id: \"05\"\n stem: 05-x\n---\n",
encoding="utf-8",
)
with pytest.raises(ConfigError, match="docgen.segment.create must be a YAML boolean"):
parse_hint_segment_declaration(h)


def test_parse_hint_segment_declaration_list_stem_raises(tmp_path: Path) -> None:
h = tmp_path / "seg.md"
h.write_text(
"---\ndocgen:\n segment:\n create: true\n id: \"05\"\n stem:\n - 05-x\n---\n",
encoding="utf-8",
)
with pytest.raises(ConfigError, match="docgen.segment.stem must be a YAML string"):
parse_hint_segment_declaration(h)


def test_parse_hint_segment_declaration_list_id_raises(tmp_path: Path) -> None:
h = tmp_path / "seg.md"
h.write_text(
"---\ndocgen:\n segment:\n create: true\n id:\n - \"05\"\n stem: 05-x\n---\n",
encoding="utf-8",
)
with pytest.raises(ValueError, match="docgen.segment.id must be a YAML string or integer"):
parse_hint_segment_declaration(h)


def test_merge_hint_declared_segments_inserts_sorted_id(tmp_path: Path) -> None:
hints = tmp_path / "hints"
hints.mkdir()
Expand Down