utterplan 0.6.6__tar.gz → 0.6.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {utterplan-0.6.6 → utterplan-0.6.7}/PKG-INFO +1 -1
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/bundles.md +8 -1
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/changelog.md +8 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_replan.py +20 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_services.py +46 -2
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_bundle_compile_book.py +33 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_bundle_document.py +35 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ssmd_bundle.py +52 -1
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ssmd_bundle_document.py +1 -1
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/_book_replan.py +11 -3
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/_book_service.py +9 -2
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/_document_service.py +5 -14
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/_version.py +3 -3
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/bundle.py +4 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/bundle_replan.py +1 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/cli.py +9 -3
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/codecs/v4_toml.py +0 -14
- utterplan-0.6.7/utterplan/explain.py +295 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/ssmd_bundle.py +24 -20
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/PKG-INFO +1 -1
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/scm_file_list.json +2 -0
- utterplan-0.6.7/utterplan.egg-info/scm_version.json +8 -0
- utterplan-0.6.6/utterplan/explain.py +0 -643
- utterplan-0.6.6/utterplan.egg-info/scm_version.json +0 -8
- {utterplan-0.6.6 → utterplan-0.6.7}/.codecrate.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.github/workflows/codecov.yml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.github/workflows/pre-commit.yml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.github/workflows/python-publish.yml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.github/workflows/tests.yml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.gitignore +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/.pre-commit-config.yaml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/AGENTS.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/LICENSE +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/MANIFEST.in +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/NOTICE +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/README.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/Makefile +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/architecture.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/cli.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/conf.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/consumer-guide.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/coordinate-spaces.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/debugging.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/format.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/getting-started.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/index.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/make.bat +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/phase-a-completion.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/pykokoro-integration.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/python-api.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/docs/requirements.txt +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/basic.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/chapter.ssmd +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/compile_file.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/inspect_plan.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/multilingual.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/examples/ssmd_example.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/pyproject.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/setup.cfg +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/spec/schemas/v1.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/spec/schemas/v2.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/spec/schemas/v3.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/spec/schemas/v4.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/spec/utterplan.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/compiler_helpers.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/fixtures/canonical_consumer_contract.expected.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/fixtures/canonical_consumer_contract.ssmd +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/fixtures/document-bundle-v1/story.ssmd-bundle/document.ssmd.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/fixtures/document-bundle-v1/story.ssmd-bundle/manifest.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/fixtures/ssmd_09_comprehensive.ssmd +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/basic_en.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/directives.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/markers.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/multilingual.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/parenthetical.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/spokenform_offsets.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/ssmd_09_comprehensive.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/golden/ssmd_breaks.utterplan.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/cases.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/basic_en.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/directives.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/markers.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/multilingual.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/parenthetical.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/spokenform_offsets.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/ssmd_09_comprehensive.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/fixtures/v4/ssmd_breaks.utterplan.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/multilingual_preparation.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/spokenform_numbers.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/ssmd_break.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/ssmd_language_detection.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/ssmd_marker.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/goldens/ssmd_pronunciation.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/test_legacy_json_import.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/migration/test_semantic_migration_regressions.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/README.md +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/basic.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/directives.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/markers.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/multilingual.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/parenthetical.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/spokenform_offsets.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v1/ssmd_breaks.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v2/directives.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v3/multilingual.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v3/ssmd_09_comprehensive.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/schema_history/v5/canonical_consumer_contract.toml +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_atomic_io.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_batch.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_boundaries.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_book_replan.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_book_services.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_document_compile.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_bundle_document_render.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_batch.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_bundle_render_book.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_bundle_render_document.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_cli_bundle_replan_book.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_compiler.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_consumer_contract.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_consumer_readiness.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_coordinates.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_dependency_architecture.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_directives.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_explain.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_fake_renderer.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_flow_compilation.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_format.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_golden.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_identity_units.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_import_boundaries.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_language.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_linguistics.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_migration_framework.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_migration_v3_to_v4.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_migration_v4_to_v5.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_pauses.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_planner.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_preparation.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_preview.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_progress.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_public_identity.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderability.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderability_repair.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderplan_batch.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderplan_dependency_contract.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderplan_export.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderplan_replan.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_renderplan_v7_contract.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_replacement_provenance.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_role_coverage.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_schema_history.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_schema_registry.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_schema_strict.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_schema_v6_source.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_schema_v7.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_segment_topology.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_segmentation_adapter.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_segmentation_recovery.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_semantic_boundaries.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_sentence_topology.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_source_input.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ssmd_09_parser.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ssmd_bundle_book.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ssmd_substitution_preparation.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_token_topology.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_toml_format.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_ttsready_preparation_adapter.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/tests/test_version.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/__main__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/atomic_io.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/attempt_serialization.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/attempts.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/batch.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/boundaries.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/codecs/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/codecs/v5_toml.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/codecs/v6_toml.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/codecs/v7_toml.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/compiler.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/config.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/diagnostics.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/directives.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/exceptions.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/flow_projection.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/format.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/hashing.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/language.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/linguistics.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migration.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/registry.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v1_to_v2.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v2_to_v3.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v3_to_v4.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v4_to_v5.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v5_to_v6.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/migrations/v6_to_v7.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/model.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/parsers.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/pauses.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/planner.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/preparation.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/preview.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/progress.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/py.typed +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderability.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_batch.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_export.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_grouping.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_projection.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_replan.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/renderplan_workspace.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/role_coverage.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/schema_registry.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/schemas/v1.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/schemas/v2.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/schemas/v3.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/schemas/v4.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/segmentation.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/serialization.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/source_input.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/spacy_models.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/spans.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/document/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/document/plain.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/document/ssmd.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/preparation/__init__.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/preparation/identity.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/preparation/ssmd.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/preparation/ttsready.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/stages/protocols.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/token_topology.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/toml_codec.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/trace_codec.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/units.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/utterplan.schema.json +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/versioning.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan/workspace_paths.py +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/SOURCES.txt +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/dependency_links.txt +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/entry_points.txt +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/requires.txt +0 -0
- {utterplan-0.6.6 → utterplan-0.6.7}/utterplan.egg-info/top_level.txt +0 -0
|
@@ -26,6 +26,13 @@ utterplan bundle compile novel.ssmd-bundle --chapters 5-17
|
|
|
26
26
|
utterplan bundle compile story.ssmd-bundle --text-preparation identity
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
+
When already inside a bundle root, `.` is also accepted because the supplied path is resolved before the directory name is validated:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd story.ssmd-bundle
|
|
33
|
+
utterplan bundle compile --lang en .
|
|
34
|
+
```
|
|
35
|
+
|
|
29
36
|
Compilation defaults to all items. For book bundles, `--chapters` selects manifest `source_number` values: one number, an inclusive range, or comma-separated combinations such as `1,3-5,9`. Selected items retain manifest order. A document bundle accepts only `--chapters all`.
|
|
30
37
|
|
|
31
38
|
By default, one schema-v7 `.utterplan.toml` plan per selected item and `compile-report.toml` are written under `<bundle>/utterplan/`. `--output-dir` and `--report` override those destinations. Existing plans are protected unless `--force` is supplied; `--fail-fast` records later selected items as skipped after a failure. `--language` is a fallback for SSMD language metadata. Bundle sources are SSMD 0.9, so the command does not accept an input-format override. The report is operational metadata and does not affect plan identity.
|
|
@@ -58,7 +65,7 @@ The full variant directory name, including its profile fingerprint, is required.
|
|
|
58
65
|
|
|
59
66
|
## Safe and read-only behavior
|
|
60
67
|
|
|
61
|
-
The
|
|
68
|
+
The supplied workspace path is resolved first. The resolved directory must be named `<name>.ssmd-bundle` and contain a regular, non-symlink `manifest.json`. Therefore `.` and equivalent aliases are valid when they resolve to the bundle root; paths to `chapters/` or an item file remain invalid. Manifest item paths must be normalized relative POSIX paths, remain inside the resolved root, and resolve to regular files. Symlink escapes and unsafe output collisions are rejected. Manifest size and document size are bounded. Source digests are not used to replace current edited content; the manifest and source files are never refreshed or rewritten.
|
|
62
69
|
|
|
63
70
|
## Python API
|
|
64
71
|
|
|
@@ -10,8 +10,10 @@ from renderplan import codec as renderplan_codec
|
|
|
10
10
|
|
|
11
11
|
from tests.test_bundle_book_replan import _active_plan, _save_preflight, _setup
|
|
12
12
|
from tests.test_bundle_services import _planner_config, _profile
|
|
13
|
+
from utterplan._book_replan import BookReplanError, replan_book
|
|
13
14
|
from utterplan.bundle import compile_bundle, render_bundle
|
|
14
15
|
from utterplan.bundle_replan import BundleReplanError, replan_bundle
|
|
16
|
+
from utterplan.ssmd_bundle import load_ssmd_bundle
|
|
15
17
|
|
|
16
18
|
DOCUMENT_FIXTURE = Path(__file__).parent / "fixtures/document-bundle-v1/story.ssmd-bundle"
|
|
17
19
|
|
|
@@ -62,13 +64,24 @@ def _document_preflight(root: Path, variant: str, active_path: Path) -> Path:
|
|
|
62
64
|
|
|
63
65
|
def test_replan_bundle_keeps_book_set_selection_and_immutable_child_behavior(
|
|
64
66
|
tmp_path: Path,
|
|
67
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
65
68
|
) -> None:
|
|
66
69
|
root, variant, variant_dir, _ = _setup(tmp_path, numbers=(5, 6))
|
|
67
70
|
entry, parent, _ = _active_plan(variant_dir)
|
|
71
|
+
loaded_indexes = []
|
|
72
|
+
|
|
73
|
+
def tracked_load(path):
|
|
74
|
+
index = load_ssmd_bundle(path)
|
|
75
|
+
loaded_indexes.append(index)
|
|
76
|
+
return index
|
|
77
|
+
|
|
78
|
+
monkeypatch.setattr("utterplan.bundle_replan.load_ssmd_bundle", tracked_load)
|
|
79
|
+
monkeypatch.setattr("utterplan._book_replan.load_ssmd_bundle", tracked_load)
|
|
68
80
|
preflight_path = _save_preflight(root / "voicerender", variant, entry.id, parent)
|
|
69
81
|
starts = []
|
|
70
82
|
|
|
71
83
|
result = replan_bundle(root, variant=variant, chapters="5", on_start=starts.append)
|
|
84
|
+
assert len(loaded_indexes) == 1
|
|
72
85
|
|
|
73
86
|
assert result.kind == "book"
|
|
74
87
|
assert result.selected_item_ids == ("chapter-0005",)
|
|
@@ -133,3 +146,10 @@ def test_document_replan_rejects_non_all_selector(tmp_path: Path) -> None:
|
|
|
133
146
|
root = _document_bundle(tmp_path / "story.ssmd-bundle")
|
|
134
147
|
with pytest.raises(BundleReplanError, match="document bundles only support --chapters all"):
|
|
135
148
|
replan_bundle(root, variant="any", chapters="1")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_book_replan_rejects_document_bundle_direct_call(tmp_path: Path) -> None:
|
|
152
|
+
root = _document_bundle(tmp_path / "story.ssmd-bundle")
|
|
153
|
+
|
|
154
|
+
with pytest.raises(BookReplanError, match="bundle manifest format is not a book"):
|
|
155
|
+
replan_book(root, variant="not-a-book")
|
|
@@ -8,8 +8,10 @@ import pytest
|
|
|
8
8
|
from renderplan import PausePolicy, PlanningPolicy, RenderProfile, RoleProfile
|
|
9
9
|
from renderplan import codec as renderplan_codec
|
|
10
10
|
|
|
11
|
+
from utterplan._book_service import BookServiceError, compile_book, render_book
|
|
11
12
|
from utterplan.bundle import BundleServiceError, compile_bundle, render_bundle
|
|
12
13
|
from utterplan.config import LinguisticsConfig, PlannerConfig
|
|
14
|
+
from utterplan.ssmd_bundle import load_ssmd_bundle
|
|
13
15
|
|
|
14
16
|
DOCUMENT_FIXTURE = Path(__file__).parent / "fixtures/document-bundle-v1/story.ssmd-bundle"
|
|
15
17
|
|
|
@@ -76,7 +78,7 @@ def _profile(path: Path) -> RenderProfile:
|
|
|
76
78
|
|
|
77
79
|
@pytest.mark.parametrize("kind", ["book", "document"])
|
|
78
80
|
def test_compile_bundle_dispatches_both_kinds_and_returns_uniform_result(
|
|
79
|
-
tmp_path: Path, kind: str
|
|
81
|
+
tmp_path: Path, kind: str, monkeypatch: pytest.MonkeyPatch
|
|
80
82
|
) -> None:
|
|
81
83
|
root = (
|
|
82
84
|
_book(tmp_path / "novel.ssmd-bundle")
|
|
@@ -84,6 +86,19 @@ def test_compile_bundle_dispatches_both_kinds_and_returns_uniform_result(
|
|
|
84
86
|
else _document(tmp_path / "story.ssmd-bundle")
|
|
85
87
|
)
|
|
86
88
|
starts = []
|
|
89
|
+
loaded_indexes = []
|
|
90
|
+
|
|
91
|
+
def tracked_load(path):
|
|
92
|
+
index = load_ssmd_bundle(path)
|
|
93
|
+
loaded_indexes.append(index)
|
|
94
|
+
return index
|
|
95
|
+
|
|
96
|
+
for module in (
|
|
97
|
+
"utterplan.bundle",
|
|
98
|
+
"utterplan._book_service",
|
|
99
|
+
"utterplan._document_service",
|
|
100
|
+
):
|
|
101
|
+
monkeypatch.setattr(f"{module}.load_ssmd_bundle", tracked_load)
|
|
87
102
|
|
|
88
103
|
result = compile_bundle(root, planner_config=_planner_config(), on_start=starts.append)
|
|
89
104
|
|
|
@@ -100,6 +115,8 @@ def test_compile_bundle_dispatches_both_kinds_and_returns_uniform_result(
|
|
|
100
115
|
assert starts[0].selected_item_ids == result.selected_item_ids
|
|
101
116
|
assert result.report_path.is_file()
|
|
102
117
|
|
|
118
|
+
assert len(loaded_indexes) == 1
|
|
119
|
+
|
|
103
120
|
|
|
104
121
|
def test_document_bundle_only_accepts_all_chapters_for_compile_and_render(tmp_path: Path) -> None:
|
|
105
122
|
root = _document(tmp_path / "story.ssmd-bundle")
|
|
@@ -110,18 +127,45 @@ def test_document_bundle_only_accepts_all_chapters_for_compile_and_render(tmp_pa
|
|
|
110
127
|
render_bundle(root, profile=tmp_path / "missing.renderprofile.toml", chapters="2")
|
|
111
128
|
|
|
112
129
|
|
|
113
|
-
def
|
|
130
|
+
def test_book_services_reject_document_bundle_direct_calls(tmp_path: Path) -> None:
|
|
131
|
+
root = _document(tmp_path / "story.ssmd-bundle")
|
|
132
|
+
|
|
133
|
+
with pytest.raises(BookServiceError, match="bundle manifest format is not a book"):
|
|
134
|
+
compile_book(root)
|
|
135
|
+
with pytest.raises(BookServiceError, match="bundle manifest format is not a book"):
|
|
136
|
+
render_book(root, profile=tmp_path / "missing.renderprofile.toml")
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def test_render_bundle_dispatches_book_and_document_with_uniform_outputs(
|
|
140
|
+
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
141
|
+
) -> None:
|
|
142
|
+
loaded_indexes = []
|
|
143
|
+
|
|
144
|
+
def tracked_load(path):
|
|
145
|
+
index = load_ssmd_bundle(path)
|
|
146
|
+
loaded_indexes.append(index)
|
|
147
|
+
return index
|
|
148
|
+
|
|
149
|
+
for module in (
|
|
150
|
+
"utterplan.bundle",
|
|
151
|
+
"utterplan._book_service",
|
|
152
|
+
"utterplan._document_service",
|
|
153
|
+
):
|
|
154
|
+
monkeypatch.setattr(f"{module}.load_ssmd_bundle", tracked_load)
|
|
155
|
+
|
|
114
156
|
for kind, root in (
|
|
115
157
|
("book", _book(tmp_path / "novel.ssmd-bundle")),
|
|
116
158
|
("document", _document(tmp_path / "story.ssmd-bundle")),
|
|
117
159
|
):
|
|
118
160
|
compile_bundle(root, planner_config=_planner_config())
|
|
119
161
|
profile_path = root / f"{kind}.renderprofile.toml"
|
|
162
|
+
loaded_indexes.clear()
|
|
120
163
|
_profile(profile_path)
|
|
121
164
|
starts = []
|
|
122
165
|
|
|
123
166
|
result = render_bundle(root, profile=profile_path, on_start=starts.append)
|
|
124
167
|
|
|
168
|
+
assert len(loaded_indexes) == 1
|
|
125
169
|
assert result.kind == kind
|
|
126
170
|
assert result.workspace == root
|
|
127
171
|
assert result.exit_code == 0
|
|
@@ -166,6 +166,39 @@ def test_compile_book_root_range_defaults_to_utterplan_and_writes_v6_plans(
|
|
|
166
166
|
assert (root / "manifest.json").read_bytes() == manifest_before
|
|
167
167
|
|
|
168
168
|
|
|
169
|
+
def test_bundle_compile_accepts_dot_from_current_book_bundle(
|
|
170
|
+
tmp_path: Path,
|
|
171
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
172
|
+
capsys: pytest.CaptureFixture[str],
|
|
173
|
+
) -> None:
|
|
174
|
+
root = tmp_path / "book.ssmd-bundle"
|
|
175
|
+
_write_book(root, (5,), contents={5: _ssmd("Chapter 5.")})
|
|
176
|
+
manifest = root / "manifest.json"
|
|
177
|
+
manifest_before = manifest.read_bytes()
|
|
178
|
+
monkeypatch.chdir(root)
|
|
179
|
+
|
|
180
|
+
result = main(
|
|
181
|
+
[
|
|
182
|
+
"bundle",
|
|
183
|
+
"compile",
|
|
184
|
+
"--lang",
|
|
185
|
+
"en",
|
|
186
|
+
".",
|
|
187
|
+
"--text-preparation",
|
|
188
|
+
"identity",
|
|
189
|
+
"--spacy",
|
|
190
|
+
"off",
|
|
191
|
+
]
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
capsys.readouterr()
|
|
195
|
+
assert result == 0
|
|
196
|
+
assert (root / "utterplan/chapter-0005.utterplan.toml").is_file()
|
|
197
|
+
assert (root / "utterplan/compile-report.toml").is_file()
|
|
198
|
+
assert _plan_text(root / "utterplan/chapter-0005.utterplan.toml") == "Chapter 5."
|
|
199
|
+
assert manifest.read_bytes() == manifest_before
|
|
200
|
+
|
|
201
|
+
|
|
169
202
|
def test_compile_book_report_records_ssmd_mode_and_repaired_cut_details(
|
|
170
203
|
tmp_path: Path, capsys: pytest.CaptureFixture[str], monkeypatch: pytest.MonkeyPatch
|
|
171
204
|
) -> None:
|
|
@@ -84,6 +84,41 @@ def test_compile_document_uses_manifest_kind_with_canonical_root(
|
|
|
84
84
|
assert (root / "utterplan/document.utterplan.toml").is_file()
|
|
85
85
|
|
|
86
86
|
|
|
87
|
+
def test_bundle_compile_accepts_dot_from_current_document_bundle(
|
|
88
|
+
tmp_path: Path,
|
|
89
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
90
|
+
capsys: pytest.CaptureFixture[str],
|
|
91
|
+
) -> None:
|
|
92
|
+
root = _workspace(tmp_path)
|
|
93
|
+
manifest = root / "manifest.json"
|
|
94
|
+
source = root / "document.ssmd.md"
|
|
95
|
+
manifest_before = manifest.read_bytes()
|
|
96
|
+
source_before = source.read_bytes()
|
|
97
|
+
monkeypatch.chdir(root)
|
|
98
|
+
|
|
99
|
+
result = main(
|
|
100
|
+
[
|
|
101
|
+
"bundle",
|
|
102
|
+
"compile",
|
|
103
|
+
"--lang",
|
|
104
|
+
"en",
|
|
105
|
+
".",
|
|
106
|
+
"--text-preparation",
|
|
107
|
+
"identity",
|
|
108
|
+
"--spacy",
|
|
109
|
+
"off",
|
|
110
|
+
]
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
capsys.readouterr()
|
|
114
|
+
assert result == 0
|
|
115
|
+
assert (root / "utterplan/document.utterplan.toml").is_file()
|
|
116
|
+
assert (root / "utterplan/compile-report.toml").is_file()
|
|
117
|
+
assert "Original content." in _plan_text(root / "utterplan/document.utterplan.toml")
|
|
118
|
+
assert manifest.read_bytes() == manifest_before
|
|
119
|
+
assert source.read_bytes() == source_before
|
|
120
|
+
|
|
121
|
+
|
|
87
122
|
def test_compile_document_uses_dirty_current_content_without_refreshing_manifest(
|
|
88
123
|
tmp_path: Path, capsys: pytest.CaptureFixture[str]
|
|
89
124
|
) -> None:
|
|
@@ -111,6 +111,25 @@ def test_rejects_non_root_workspace_inputs(tmp_path: Path) -> None:
|
|
|
111
111
|
resolve_ssmd_bundle_root(tmp_path / "legacy-workspace")
|
|
112
112
|
|
|
113
113
|
|
|
114
|
+
@pytest.mark.parametrize(
|
|
115
|
+
("working_directory", "path"),
|
|
116
|
+
[("root", "."), ("root", "./"), ("child", "..")],
|
|
117
|
+
)
|
|
118
|
+
def test_resolves_bundle_root_path_aliases(
|
|
119
|
+
tmp_path: Path,
|
|
120
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
121
|
+
working_directory: str,
|
|
122
|
+
path: str,
|
|
123
|
+
) -> None:
|
|
124
|
+
root = tmp_path / "story.ssmd-bundle"
|
|
125
|
+
_write_manifest(root, _document_manifest())
|
|
126
|
+
(root / "child").mkdir()
|
|
127
|
+
monkeypatch.chdir(root if working_directory == "root" else root / "child")
|
|
128
|
+
|
|
129
|
+
assert resolve_ssmd_bundle_root(path) == root.resolve()
|
|
130
|
+
assert load_ssmd_bundle(path).root == root.resolve()
|
|
131
|
+
|
|
132
|
+
|
|
114
133
|
def test_rejects_bundle_root_without_manifest_or_regular_root_directory(tmp_path: Path) -> None:
|
|
115
134
|
root = tmp_path / "empty.ssmd-bundle"
|
|
116
135
|
root.mkdir()
|
|
@@ -207,5 +226,37 @@ def test_rejects_manifest_symlink_escape(tmp_path: Path) -> None:
|
|
|
207
226
|
except (OSError, NotImplementedError) as exc:
|
|
208
227
|
pytest.skip(f"symlinks unavailable: {exc}")
|
|
209
228
|
|
|
210
|
-
with pytest.raises(SsmdBundleError, match="
|
|
229
|
+
with pytest.raises(SsmdBundleError, match="regular file, not a symlink"):
|
|
211
230
|
load_ssmd_bundle(root)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def test_rejects_manifest_symlink_to_file_inside_bundle(tmp_path: Path) -> None:
|
|
234
|
+
root = tmp_path / "internal-manifest-link.ssmd-bundle"
|
|
235
|
+
root.mkdir()
|
|
236
|
+
target = root / "manifest-copy.json"
|
|
237
|
+
target.write_text(json.dumps(_book_manifest()), encoding="utf-8")
|
|
238
|
+
try:
|
|
239
|
+
(root / "manifest.json").symlink_to(target)
|
|
240
|
+
except (OSError, NotImplementedError) as exc:
|
|
241
|
+
pytest.skip(f"symlinks unavailable: {exc}")
|
|
242
|
+
|
|
243
|
+
with pytest.raises(SsmdBundleError, match="regular file, not a symlink"):
|
|
244
|
+
load_ssmd_bundle(root)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def test_allows_item_symlink_target_inside_bundle(tmp_path: Path) -> None:
|
|
248
|
+
root = tmp_path / "item-link.ssmd-bundle"
|
|
249
|
+
_write_manifest(root, _book_manifest())
|
|
250
|
+
target = root / "chapter-source.ssmd.md"
|
|
251
|
+
target.write_text("chapter content", encoding="utf-8")
|
|
252
|
+
item_path = root / "chapters/chapter-0005.ssmd.md"
|
|
253
|
+
item_path.parent.mkdir()
|
|
254
|
+
try:
|
|
255
|
+
item_path.symlink_to(target)
|
|
256
|
+
except (OSError, NotImplementedError) as exc:
|
|
257
|
+
pytest.skip(f"symlinks unavailable: {exc}")
|
|
258
|
+
|
|
259
|
+
index = load_ssmd_bundle(root)
|
|
260
|
+
resolved_item = bundle_item_path(index, index.items[0], require_exists=True)
|
|
261
|
+
assert resolved_item == item_path
|
|
262
|
+
assert resolved_item.read_text(encoding="utf-8") == "chapter content"
|
|
@@ -196,5 +196,5 @@ def test_rejects_manifest_symlink_escape(tmp_path: Path) -> None:
|
|
|
196
196
|
(root / "manifest.json").symlink_to(outside)
|
|
197
197
|
except (OSError, NotImplementedError) as exc:
|
|
198
198
|
pytest.skip(f"symlinks unavailable: {exc}")
|
|
199
|
-
with pytest.raises(SsmdBundleError, match="
|
|
199
|
+
with pytest.raises(SsmdBundleError, match="regular file, not a symlink"):
|
|
200
200
|
load_ssmd_bundle(root)
|
|
@@ -180,6 +180,7 @@ def replan_book(
|
|
|
180
180
|
fail_fast: bool = False,
|
|
181
181
|
on_progress: ReplanProgressCallback | None = None,
|
|
182
182
|
on_start: BookReplanStartCallback | None = None,
|
|
183
|
+
_index: SsmdBundleIndex | None = None,
|
|
183
184
|
) -> BookReplanResult:
|
|
184
185
|
"""Refine selected active RenderPlans using their exact matching preflight reports.
|
|
185
186
|
|
|
@@ -197,7 +198,7 @@ def replan_book(
|
|
|
197
198
|
dry_run=dry_run,
|
|
198
199
|
fail_fast=fail_fast,
|
|
199
200
|
)
|
|
200
|
-
context = _prepare_book(request)
|
|
201
|
+
context = _prepare_book(request, index=_index)
|
|
201
202
|
selected_ids = tuple(chapter.id for chapter in context.chapters)
|
|
202
203
|
_ensure_report_not_input(context)
|
|
203
204
|
if on_start is not None:
|
|
@@ -275,9 +276,16 @@ def replan_book(
|
|
|
275
276
|
)
|
|
276
277
|
|
|
277
278
|
|
|
278
|
-
def _prepare_book(
|
|
279
|
+
def _prepare_book(
|
|
280
|
+
request: BookReplanRequest, *, index: SsmdBundleIndex | None = None
|
|
281
|
+
) -> _BookContext:
|
|
279
282
|
try:
|
|
280
|
-
index = load_ssmd_bundle(request.book)
|
|
283
|
+
index = index if index is not None else load_ssmd_bundle(request.book)
|
|
284
|
+
if index.kind != "book":
|
|
285
|
+
raise BookReplanError(
|
|
286
|
+
"bundle manifest format is not a book",
|
|
287
|
+
code="renderplan.replan.book.bundle_invalid",
|
|
288
|
+
)
|
|
281
289
|
selected = select_bundle_items(index, request.chapters)
|
|
282
290
|
except SsmdBundleError as exc:
|
|
283
291
|
code = (
|
|
@@ -29,6 +29,7 @@ from .renderplan_batch import RenderOutcome, RenderRequest, new_renderplan_set,
|
|
|
29
29
|
from .role_coverage import profile_role_coverage
|
|
30
30
|
from .ssmd_bundle import (
|
|
31
31
|
SsmdBundleError,
|
|
32
|
+
SsmdBundleIndex,
|
|
32
33
|
bundle_item_path,
|
|
33
34
|
load_ssmd_bundle,
|
|
34
35
|
select_bundle_items,
|
|
@@ -182,6 +183,7 @@ def compile_book(
|
|
|
182
183
|
diagnostics: Literal["errors", "warnings", "all", "none"] = "errors",
|
|
183
184
|
on_progress: BatchProgressCallback | None = None,
|
|
184
185
|
on_start: BookCompileStartCallback | None = None,
|
|
186
|
+
_index: SsmdBundleIndex | None = None,
|
|
185
187
|
) -> BookCompileResult:
|
|
186
188
|
"""Compile selected chapters and atomically write schema-v7 UtterPlans.
|
|
187
189
|
|
|
@@ -201,7 +203,9 @@ def compile_book(
|
|
|
201
203
|
planner_config=planner_config,
|
|
202
204
|
)
|
|
203
205
|
try:
|
|
204
|
-
index = load_ssmd_bundle(request.book)
|
|
206
|
+
index = _index if _index is not None else load_ssmd_bundle(request.book)
|
|
207
|
+
if index.kind != "book":
|
|
208
|
+
raise BookServiceError("bundle manifest format is not a book")
|
|
205
209
|
chapters_selected = select_bundle_items(index, request.chapters)
|
|
206
210
|
sources = [bundle_item_path(index, chapter) for chapter in chapters_selected]
|
|
207
211
|
except SsmdBundleError as exc:
|
|
@@ -294,6 +298,7 @@ def render_book(
|
|
|
294
298
|
fail_fast: bool = False,
|
|
295
299
|
on_progress: RenderProgressCallback | None = None,
|
|
296
300
|
on_start: BookRenderStartCallback | None = None,
|
|
301
|
+
_index: SsmdBundleIndex | None = None,
|
|
297
302
|
) -> BookRenderResult:
|
|
298
303
|
"""Project selected schema-v7 FlowPlans to a profile-specific RenderPlan set."""
|
|
299
304
|
request = BookRenderRequest(
|
|
@@ -308,7 +313,9 @@ def render_book(
|
|
|
308
313
|
fail_fast=fail_fast,
|
|
309
314
|
)
|
|
310
315
|
try:
|
|
311
|
-
index = load_ssmd_bundle(request.book)
|
|
316
|
+
index = _index if _index is not None else load_ssmd_bundle(request.book)
|
|
317
|
+
if index.kind != "book":
|
|
318
|
+
raise BookServiceError("bundle manifest format is not a book")
|
|
312
319
|
chapters_selected = select_bundle_items(index, request.chapters)
|
|
313
320
|
sources = [bundle_item_path(index, chapter) for chapter in chapters_selected]
|
|
314
321
|
except SsmdBundleError as exc:
|
|
@@ -17,7 +17,7 @@ from .model import FlowPlan
|
|
|
17
17
|
from .renderplan_export import build_render_plan
|
|
18
18
|
from .renderplan_workspace import profile_fingerprint, render_variant_label
|
|
19
19
|
from .role_coverage import assert_profile_role_coverage
|
|
20
|
-
from .ssmd_bundle import SsmdBundleError, bundle_item_path, load_ssmd_bundle
|
|
20
|
+
from .ssmd_bundle import SsmdBundleError, SsmdBundleIndex, bundle_item_path, load_ssmd_bundle
|
|
21
21
|
from .workspace_paths import renderplan_output_name, utterplan_output_name
|
|
22
22
|
|
|
23
23
|
|
|
@@ -94,6 +94,7 @@ def _compile_document_service(
|
|
|
94
94
|
diagnostics: Literal["errors", "warnings", "all", "none"] = "errors",
|
|
95
95
|
on_progress: BatchProgressCallback | None = None,
|
|
96
96
|
on_start: DocumentCompileStartCallback | None = None,
|
|
97
|
+
bundle_index: SsmdBundleIndex | None = None,
|
|
97
98
|
) -> DocumentCompileResult:
|
|
98
99
|
"""Compile the current canonical SSMD document and write a one-item report."""
|
|
99
100
|
request = DocumentCompileRequest(
|
|
@@ -106,7 +107,7 @@ def _compile_document_service(
|
|
|
106
107
|
diagnostics=diagnostics,
|
|
107
108
|
)
|
|
108
109
|
try:
|
|
109
|
-
index = load_ssmd_bundle(request.workspace)
|
|
110
|
+
index = bundle_index if bundle_index is not None else load_ssmd_bundle(request.workspace)
|
|
110
111
|
if index.kind != "document":
|
|
111
112
|
raise _DocumentBundleServiceError("bundle manifest format is not a document")
|
|
112
113
|
item = index.items[0]
|
|
@@ -170,17 +171,6 @@ def _compile_document_service(
|
|
|
170
171
|
)
|
|
171
172
|
|
|
172
173
|
|
|
173
|
-
@dataclass(frozen=True, slots=True)
|
|
174
|
-
class DocumentRenderRequest:
|
|
175
|
-
workspace: Path
|
|
176
|
-
profile: Path
|
|
177
|
-
variant: str | None = None
|
|
178
|
-
utterplan_dir: Path | None = None
|
|
179
|
-
output_root: Path | None = None
|
|
180
|
-
report: Path | None = None
|
|
181
|
-
force: bool = False
|
|
182
|
-
|
|
183
|
-
|
|
184
174
|
@dataclass(frozen=True, slots=True)
|
|
185
175
|
class DocumentRenderStart:
|
|
186
176
|
workspace: Path
|
|
@@ -230,10 +220,11 @@ def _render_document_service(
|
|
|
230
220
|
report: str | Path | None = None,
|
|
231
221
|
force: bool = False,
|
|
232
222
|
on_start: DocumentRenderStartCallback | None = None,
|
|
223
|
+
bundle_index: SsmdBundleIndex | None = None,
|
|
233
224
|
) -> DocumentRenderResult:
|
|
234
225
|
"""Project the saved document FlowPlan to one profile-specific RenderPlan."""
|
|
235
226
|
try:
|
|
236
|
-
index = load_ssmd_bundle(workspace)
|
|
227
|
+
index = bundle_index if bundle_index is not None else load_ssmd_bundle(workspace)
|
|
237
228
|
if index.kind != "document":
|
|
238
229
|
raise _DocumentBundleServiceError("bundle manifest format is not a document")
|
|
239
230
|
item = index.items[0]
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '0.6.
|
|
22
|
-
__version_tuple__ = version_tuple = (0, 6,
|
|
21
|
+
__version__ = version = '0.6.7'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 6, 7)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5282696da'
|
|
@@ -119,6 +119,7 @@ def compile_bundle(
|
|
|
119
119
|
try:
|
|
120
120
|
book_result = compile_book(
|
|
121
121
|
index.root,
|
|
122
|
+
_index=index,
|
|
122
123
|
chapters=selector,
|
|
123
124
|
output_dir=output_dir,
|
|
124
125
|
report=report,
|
|
@@ -160,6 +161,7 @@ def compile_bundle(
|
|
|
160
161
|
try:
|
|
161
162
|
document_result = _compile_document_service(
|
|
162
163
|
index.root,
|
|
164
|
+
bundle_index=index,
|
|
163
165
|
output_dir=output_dir,
|
|
164
166
|
report=report,
|
|
165
167
|
language=language,
|
|
@@ -221,6 +223,7 @@ def render_bundle(
|
|
|
221
223
|
try:
|
|
222
224
|
book_result = render_book(
|
|
223
225
|
index.root,
|
|
226
|
+
_index=index,
|
|
224
227
|
profile=profile,
|
|
225
228
|
chapters=selector,
|
|
226
229
|
variant=variant,
|
|
@@ -273,6 +276,7 @@ def render_bundle(
|
|
|
273
276
|
try:
|
|
274
277
|
document_result = _render_document_service(
|
|
275
278
|
index.root,
|
|
279
|
+
bundle_index=index,
|
|
276
280
|
profile=profile,
|
|
277
281
|
variant=variant,
|
|
278
282
|
utterplan_dir=utterplan_dir,
|
|
@@ -186,7 +186,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
186
186
|
bundle_commands = bundle_parser.add_subparsers(dest="bundle_command", required=True)
|
|
187
187
|
|
|
188
188
|
bundle_compile = bundle_commands.add_parser("compile", help="compile a book or document bundle")
|
|
189
|
-
bundle_compile.add_argument(
|
|
189
|
+
bundle_compile.add_argument(
|
|
190
|
+
"workspace", type=Path, help="path resolving to a canonical NAME.ssmd-bundle directory"
|
|
191
|
+
)
|
|
190
192
|
bundle_compile.add_argument("--chapters", default="all", metavar="SELECTOR")
|
|
191
193
|
bundle_compile.add_argument("--output-dir", type=Path)
|
|
192
194
|
bundle_compile.add_argument("--language", "--lang", dest="language")
|
|
@@ -205,7 +207,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
205
207
|
)
|
|
206
208
|
|
|
207
209
|
bundle_render = bundle_commands.add_parser("render", help="render a book or document bundle")
|
|
208
|
-
bundle_render.add_argument(
|
|
210
|
+
bundle_render.add_argument(
|
|
211
|
+
"workspace", type=Path, help="path resolving to a canonical NAME.ssmd-bundle directory"
|
|
212
|
+
)
|
|
209
213
|
bundle_render.add_argument("--profile", type=Path, required=True)
|
|
210
214
|
bundle_render.add_argument("--chapters", default="all", metavar="SELECTOR")
|
|
211
215
|
bundle_render.add_argument("--variant")
|
|
@@ -216,7 +220,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
216
220
|
bundle_render.add_argument("--fail-fast", action="store_true")
|
|
217
221
|
|
|
218
222
|
bundle_replan = bundle_commands.add_parser("replan", help="refine active bundle RenderPlans")
|
|
219
|
-
bundle_replan.add_argument(
|
|
223
|
+
bundle_replan.add_argument(
|
|
224
|
+
"workspace", type=Path, help="path resolving to a canonical NAME.ssmd-bundle directory"
|
|
225
|
+
)
|
|
220
226
|
bundle_replan.add_argument("--variant", required=True, help="exact existing RenderPlan variant")
|
|
221
227
|
bundle_replan.add_argument("--chapters", default="all", metavar="SELECTOR")
|
|
222
228
|
bundle_replan.add_argument("--renderplan-root", type=Path)
|
|
@@ -218,20 +218,6 @@ def from_toml_data(data: Mapping[str, object]) -> UtterancePlan:
|
|
|
218
218
|
return UtterancePlan.from_dict(_decode_toml_data(data))
|
|
219
219
|
|
|
220
220
|
|
|
221
|
-
def _from_toml_data_draft(data: Mapping[str, object]) -> UtterancePlan:
|
|
222
|
-
"""Decode a candidate while enforcing topology but not renderability or identity."""
|
|
223
|
-
from ..model import _check_shape, _from_current_dict, validate_plan_structure
|
|
224
|
-
|
|
225
|
-
semantic = _decode_toml_data(data)
|
|
226
|
-
try:
|
|
227
|
-
_check_shape(semantic)
|
|
228
|
-
plan = _from_current_dict(semantic)
|
|
229
|
-
except (KeyError, TypeError, ValueError, IndexError) as exc:
|
|
230
|
-
raise PlanFormatError(f"invalid draft candidate: {exc}", code="plan.value") from exc
|
|
231
|
-
validate_plan_structure(plan)
|
|
232
|
-
return plan
|
|
233
|
-
|
|
234
|
-
|
|
235
221
|
def dumps_toml(plan: UtterancePlan) -> str:
|
|
236
222
|
"""Serialize a plan to deterministic, human-readable TOML text."""
|
|
237
223
|
wire = to_toml_data(plan)
|