✅ fresh
last synced 2026-09-29T21:12:19.681221+00:00 · coverage 100% (
doc-shape-requirements)Validation by Beadloom
doc_sync— same source assync-check.
Doc Shape Requirements (component)
The shape a project's documents are held to.
Source: src/beadloom/application/doc_shape.py
Overview
The shape a generated document must keep is derived from the composed doc templates, which live in the onboarding domain. The check that reads a document back lives in doc-sync. The two are peers and neither may import the other, so the join happens here, in the layer whose job is that kind of orchestration.
The same module resolves the other input the document checks need from outside their domain: the placeholder vocabulary, derived from the shipped /templates command.
Public surface
section_requirements(project_root)— required sections per graph node kind, orNonewhen the flow config is malformed.Noneis returned rather than raised because a badflow.ymlisconfig-check's finding by name, and raising here would turn one configuration error into a failing freshness gate that names the wrong file.document_section_requirements(project_root)— required sections per planning document kind (BRIEF,RFC, …), derived from the composed/templatescommand. Returns{}rather than raising for a malformedflow.yml, for the same reason its sibling returnsNone.planning_document_globs(project_root)/planning_documents(project_root)— where the writing-standard checks read from. Defaults to.claude/development/docs/features/*/*.md, the convention/task-initscaffolds into; overridable bydoc_quality.pathsin.beadloom/config.yml, because the flow ships to projects with their own layout and a hardcoded path would make the check true only here.shipped_placeholders(project_root)— the placeholder tokens the composed templates leave for an author, read from fenced blocks only and excluding anything wholly inside an inline code span.shipped_decision_sections(project_root)— the section titles the composed templates put a reason-carrying decision table under, read from the same fenced blocks and by the same readerdecision-reasonuses on a real document (sections_with_a_decision_table). On this repository:architectural decisions,axes,non-behavioural declaration. A tabledecision-reasoncannot place against this list and that names noDecisioncolumn is answerednot classifiedrather than judged (BDL-UX #213). A malformedflow.ymlyields(), the answer its two siblings give for the same reason.
Where it is called
section_requirements is passed into check_sync by the four surfaces that REPORT freshness: the CI gate, beadloom sync-check, the MCP sync_check tool and the TUI dashboard. Three call sites deliberately do not pass it — sync-update (twice), where re-baselining cannot fix a missing section, and site_published, where publishing does not judge one.
planning_documents, shipped_placeholders and shipped_decision_sections are called by beadloom docs quality and by the docs-quality gate step, all three through planning_report().
Configuration
# .beadloom/config.yml
doc_quality:
paths:
- docs/rfcs/*.md# .beadloom/flow/docs/domain.md — the project layer, appended to the template
## Runbook
Who to page.A section appended by the project layer becomes a required section of that doc kind. There is one source of truth: the composed template. The same holds for the planning documents, whose project layer is .beadloom/flow/commands/templates.md — a fragment declaring ## RUNBOOK.md with its own headings makes them required of every RUNBOOK.md in the corpus.