renderplan MVP
renderplan is a deliberately small Python contract package shared by UtterPlan, VoiceRender, and AudioCompose. It contains no SSMD compiler, NLP, TTS engine, G2P, waveform, DSP, or orchestration implementation.
The intended dependency graph is:
utterplan ──────┐
voicerender ────┼──> renderplan
audiocompose ──┘
The applications do not depend on each other; the contract package is their only shared dependency.
RenderPlan-set collection contract
RenderPlan owns the immutable renderplan-set v1 collection/index contract shared by the
speech pipeline. UtterPlan's render-book operation produces the index alongside its
per-chapter RenderPlans; UtterPlan continues to own book-workspace discovery,
segmentation, and its invocation report. The set contract records chapter ordering,
profile identity, and normalized artifact references without performing orchestration.
RenderPlan provides RenderPlanSet and RenderPlanSetChapter, strict TOML codecs,
profile snapshot identity validation, and load_any() dispatch for renderplan-set.
Filesystem containment and symlink checks remain the consumers' responsibility.
RenderPlan does not discover SSMDBook workspaces, batch chapter files, import UtterPlan
or VoiceRender, or add execution/runtime orchestration.
Contracts
The package defines five TOML contract documents:
renderprofile.toml— seeded by VoiceRender and user-owned. It contains opaque, self-contained renderer bindings, portable requirements, optional capacity descriptions, split/fallback policy, and explicit pause durations. Shared pause modes aremanualandnone; orchestration pass limits do not belong in this contract.renderplan.toml— produced by UtterPlan. Its ordered flow is the exact serial execution contract: numbered speech requests, exactNNNNNN.wavnames, generic pauses, audio items, controls, tokens, source provenance, and role bindings copied from the profile.renderplan-preflight.toml— produced by VoiceRender for one exact RenderPlan. It has statusok,replan, orrejectand refers to speech occurrences by(segment_number, segment_id).render-manifest.toml— produced by VoiceRender. It binds WAV metadata to exact(segment_number, segment_id)plan occurrences. A complete manifest contains exactly every plan speech occurrence; an incomplete one may contain only occurrences from that plan.renderplan-set.toml— produced by UtterPlan inrender-bookworkflows and defined by RenderPlan. It records a safe variant, profile identity/snapshot references, upstream workspace references, and ordered chapter references with source-plan and RenderPlan identities.
Consumers can use the shared joins instead of implementing their own parsers:
plan.validate_against_profile(profile)
report.validate_against(plan)
manifest.validate_against(plan)
validate_plan_profile(plan, profile)
validate_preflight_handoff(plan, report, require_ok=True)
validate_manifest_handoff(plan, manifest, require_complete=True)
validate_set_chapter_plan(renderplan_set, chapter, plan)
These are portable contract checks only; they do not resolve engines, inspect WAV files, or orchestrate a pipeline.
UtterPlan v7 source and token mapping
The first producer uses zero-based v7 provenance locators such as f000000.s000, f000000.s001, and f000001.s000: six digits for the flow index and three for the segment index. A locator is an opaque provenance address, meaningful only together with RenderPlan.source_plan_id; it is not a globally stable segment ID. renderplan does not parse or resolve locators and has no UtterPlan dependency.
SourceSpan.start and .end are Python string/code-point offsets into the prepared FlowSegment.text. For every speech request, UtterPlan must prove:
SpeechItem.text == concatenation, in order, of each referenced FlowSegment.text[start:end]
Do not trim request-edge whitespace. These offsets also map source spans and request-local controls/tokens deterministically. Source-to-text equality is proved by UtterPlan against its source document, not by renderplan.
The destination start offset of source span N inside the request is the sum of the lengths of all preceding source slices. This preserves a direct mapping without trimming or a second offset table.
TokenBundle.span is a dense, ordered list of request-local [start, end] character ranges; pos and tag, when present, are dense parallel arrays. lemma and morph are sparse arrays of [token_index, value]. VoiceRender derives a token surface from speech.text[start:end]. Profile-required token fields must be complete under those semantics; available optional fields should be preserved, but lemma and morph should not be declared required unless an adapter genuinely requires them.
SpeechControl is request-local and renderer-neutral: it carries start, end, name, and TOML-safe params. Initial semantic names include pronunciation, prosody, emphasis, say_as, and extension:<name>. Controls participate in segment_id; renderers decide support, and unsupported controls must fail preflight rather than be ignored. Control ranges may overlap only when the source semantics permit it. Engine-specific voice selection is resolved into the opaque logical role/binding; audio directives become AudioItems.
Bindings copied into plans must be self-contained enough to execute without reopening the RenderProfile. This contract does not define renderer-specific path keys or local-asset resolution. This schema has no generic asset-reference type yet. A VoiceRender profile producer must refuse bindings that depend on profile-local or otherwise uncopied asset state; do not introduce renderer-specific asset-path keys into this shared contract.
Identity and replan contract
segment_id identifies the exact synthesis request: text, language, role, binding, tokens, and controls. It excludes display number and plan provenance such as source spans, split reason, planning level, and semantic end. Duplicate requests may therefore share a segment_id; (segment_number, segment_id) identifies each occurrence within a plan, report, or manifest.
plan_id identifies the complete ordered execution flow, including speech numbers/order, request IDs, provenance and planning semantics, preflight requirements, every pause, and every audio item. Producer package versions do not change semantic profile or plan identity. Exact source-file bytes are not included in RenderPlan identity.
A PreflightReport describes failures only for its concrete RenderPlan; it cannot preserve successful capacity splits from earlier attempts. The replan join is therefore:
original UtterPlan + RenderProfile + previous RenderPlan
+ PreflightReport for that previous RenderPlan
-> new RenderPlan
UtterPlan uses the previous plan as the partition baseline and rebuilds only failed source ranges. Each replan request must correspond to a too_long check and exactly match that speech occurrence's source coverage and current planning level. VoiceRender preflight never edits the plan. replan is only for recoverable capacity failures; missing engines, unknown voices, unsupported controls, invalid token fields, and frontend/API failures are reject conditions.
A PauseItem is a generic serial event positioned by flow, with duration, reason, and optional provenance; it can lead a flow or follow speech, audio, or another operation. No preceding speech number is required. The ordered flow is authoritative for AudioCompose.
Example preflight occurrence
[[checks]]
segment_number = 37
segment_id = "sha256:..."
status = "too_long"
metric = "model_tokens"
measured = 532
maximum = 510
source = "pykokoro.prepare"
[[replan]]
segment_number = 37
segment_id = "sha256:..."
current_level = "sentence"
action = "split"
reason = "capacity"
metric = "model_tokens"
measured = 532
maximum = 510
[[replan.source]]
locator = "f000123.s004"
start = 0
end = 42
UtterPlan does not need to understand model_tokens; the source-plan ID, copied profile ID, exact plan ID, source ranges, and generic split level/action allow stale feedback to be rejected without importing VoiceRender.
Install for development
This repository intentionally has no src/ directory.
python -m pip install -e '.[dev]'
pytest
ruff check .
mypy renderplan
Versioning is dynamic through setuptools-scm; create Git tags such as v0.1.0. A source tree without Git metadata uses the configured development fallback version.
Example API
from renderplan import load_plan, load_preflight
plan = load_plan("chapter.renderplan.toml")
report = load_preflight("chapter.preflight.toml")
report.validate_against(plan)
if report.status == "replan":
for request in report.replan:
print(request.segment_number, request.action, request.source)
MVP invariants
- Persisted identities are SHA-256 over canonical semantic payloads; producer versions are provenance, not identity.
- Speech numbers are contiguous starting at 1; speech
Nmaps toNNNNNN.wav. - Speech-request identity is stable across renumbering; full plan identity changes when flow order or execution semantics change.
RenderPlan.validate_against_profile,PreflightReport.validate_against, andRenderManifest.validate_againstenforce portable joins and exact occurrence matching.- VoiceRender preflight never changes the plan, and rendering never introduces unplanned speech segments.
- AudioCompose consumes RenderPlan flow and RenderManifest artifacts; it does not reconstruct pauses from UtterPlan.
- Engine-specific binding tables are opaque to UtterPlan and AudioCompose.
Metadata
Release files for renderplan 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| renderplan-0.1.2.tar.gz | 82.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| renderplan-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 116.4 kB
Release files / renderplan-0.1.2.tar.gz
| Download URL | renderplan-0.1.2.tar.gz |
|---|---|
| Size | 82.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5b979aa5da4f3cc77fbcaf00088f265ae77e9172eaa1f722d4d13db9e2f1b7b7
|
|
BLAKE2b-256 checksum How to use checksums |
c5f87ed94426c2413852dc46e575ce16ef838884c12e2d7c77b68d9ee7e4acf3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|
Release files / renderplan-0.1.2-py3-none-any.whl
| Download URL | renderplan-0.1.2-py3-none-any.whl |
|---|---|
| Size | 33.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77008cd83dc67f2d9aebc34d39381cbe912827d810d6a243eb43b5b42d7a3d47
|
|
BLAKE2b-256 checksum How to use checksums |
78a7efbafe8a59aa2a98a8cedd0575922ca00c20867fcf0457d713e57df733b2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.14
|