pipeworks_mud_mapper.services.validation_service ================================================ .. py:module:: pipeworks_mud_mapper.services.validation_service .. autoapi-nested-parse:: Validation service for map integrity checks. This module provides validation functions that check map files for common issues. Validations are non-destructive - they return warnings but don't modify the map. Validation Categories --------------------- **Connectivity** - Unreachable rooms (no path from spawn) - Dead-end rooms (no exits) - Broken exit references **Exit Consistency** - Asymmetric exits (A→B exists but B→A doesn't) - Direction conflicts (exit says "north" but coords say "south") **Language-Direction** - Room names with vertical words ("Upper", "Basement") that don't match their navigational reality - This catches the "Upper Landing" problem from goblin_cartography.md Warning Severity ---------------- Warnings have severity levels: - **ERROR**: Must be fixed before export (broken references) - **WARNING**: Should be reviewed but may be intentional (dead ends) - **INFO**: Informational only (asymmetric exits may be intended) Usage ----- Run all validations:: from pipeworks_mud_mapper.services import validation_service warnings = validation_service.validate_all(map_file) for warning in warnings: print(f"[{warning.severity}] {warning.room_id}: {warning.message}") Run specific validations:: conn_warnings = validation_service.validate_connectivity(map_file) exit_warnings = validation_service.validate_exit_consistency(map_file) .. seealso:: :py:obj:`-`, :py:obj:`-` Classes ------- .. autoapisummary:: pipeworks_mud_mapper.services.validation_service.Severity pipeworks_mud_mapper.services.validation_service.ValidationWarning Functions --------- .. autoapisummary:: pipeworks_mud_mapper.services.validation_service.validate_all pipeworks_mud_mapper.services.validation_service.validate_connectivity pipeworks_mud_mapper.services.validation_service.validate_exit_consistency pipeworks_mud_mapper.services.validation_service.validate_language_direction pipeworks_mud_mapper.services.validation_service.has_errors pipeworks_mud_mapper.services.validation_service.filter_by_severity pipeworks_mud_mapper.services.validation_service.filter_by_category pipeworks_mud_mapper.services.validation_service.create_validation_report pipeworks_mud_mapper.services.validation_service.write_validation_report Module Contents --------------- .. py:class:: Severity Bases: :py:obj:`enum.StrEnum` Severity level for validation warnings. .. py:class:: ValidationWarning A validation warning or error. .. attribute:: severity How serious this issue is. :type: :py:class:`Severity` .. attribute:: category Category of the warning (connectivity, consistency, language). :type: :py:class:`str` .. attribute:: room_id Room ID related to the warning, if applicable. :type: :py:class:`str` or :py:obj:`None` .. attribute:: message Human-readable description of the issue. :type: :py:class:`str` .. attribute:: details Additional structured data about the issue. :type: :py:class:`dict` .. py:function:: validate_all(map_file) Run all validation checks on a map file. :param map_file: The map file to validate. :type map_file: :py:class:`MapFile` :returns: All warnings from all validation checks, sorted by severity. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Examples >>> warnings = validate_all(map_file) >>> errors = [w for w in warnings if w.severity == Severity.ERROR] >>> if errors: ... print("Cannot export: fix errors first") .. py:function:: validate_connectivity(map_file) Check for connectivity issues. Checks for: - Unreachable rooms (no path from spawn) - Dead-end rooms (no exits) - Broken exit references (exit to nonexistent room) :param map_file: The map file to validate. :type map_file: :py:class:`MapFile` :returns: Connectivity warnings. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Examples >>> warnings = validate_connectivity(map_file) >>> for w in warnings: ... if "unreachable" in w.message: ... print(f"Orphan room: {w.room_id}") .. py:function:: validate_exit_consistency(map_file) Check for exit consistency issues. Checks for: - Asymmetric exits (A→north→B but B has no south→A) - Direction/coordinate mismatches (exit says "north" but room is south) :param map_file: The map file to validate. :type map_file: :py:class:`MapFile` :returns: Exit consistency warnings. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Notes Asymmetric exits are flagged as INFO, not errors, because some asymmetry is intentional (one-way doors, hidden passages, trapdoors). .. py:function:: validate_language_direction(map_file) Check for language-direction conflicts in room names. Flags rooms whose names contain vertical words (like "Upper", "Basement") but are not reached via the corresponding vertical direction (up/down). This catches the "Upper Landing" problem from goblin_cartography.md: a room named "Upper Landing" reached via "north" creates cognitive dissonance for players trying to build a mental map. :param map_file: The map file to validate. :type map_file: :py:class:`MapFile` :returns: Language-direction conflict warnings. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Notes These are flagged as INFO because the author may have intentional reasons for the naming, or may be using the word in a non-directional sense. .. py:function:: has_errors(warnings) Check if any warnings are errors. :param warnings: List of validation warnings. :type warnings: :py:class:`list[ValidationWarning]` :returns: True if any warning has ERROR severity. :rtype: :py:class:`bool` .. admonition:: Examples >>> warnings = validate_all(map_file) >>> if has_errors(warnings): ... print("Fix errors before exporting") .. py:function:: filter_by_severity(warnings, severity) Filter warnings by severity level. :param warnings: List of validation warnings. :type warnings: :py:class:`list[ValidationWarning]` :param severity: Severity level to filter for. :type severity: :py:class:`Severity` :returns: Warnings matching the specified severity. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Examples >>> errors = filter_by_severity(warnings, Severity.ERROR) .. py:function:: filter_by_category(warnings, category) Filter warnings by category. :param warnings: List of validation warnings. :type warnings: :py:class:`list[ValidationWarning]` :param category: Category to filter for (connectivity, consistency, language). :type category: :py:class:`str` :returns: Warnings matching the specified category. :rtype: :py:class:`list[ValidationWarning]` .. admonition:: Examples >>> conn_issues = filter_by_category(warnings, "connectivity") .. py:function:: create_validation_report(map_file_name, warnings) Create a validation report dictionary. Creates a structured report suitable for JSON serialization and display in the UI. The report includes a summary with counts by severity and a pass/fail status based on whether any errors exist. :param map_file_name: Name of the map file that was validated. :type map_file_name: :py:class:`str` :param warnings: List of validation warnings from validate_all(). :type warnings: :py:class:`list[ValidationWarning]` :returns: Validation report with the following structure:: { "timestamp": "2026-02-02T17:00:00Z", "map_file": "ledgerfall_alley.map.json", "summary": { "errors": 0, "warnings": 2, "info": 3, "total": 5, "passed": true }, "warnings": [ { "severity": "warning", "category": "connectivity", "room_id": "room_1", "message": "Room is unreachable from spawn" } ] } :rtype: :py:class:`dict` .. admonition:: Examples >>> warnings = validate_all(map_file) >>> report = create_validation_report("my_zone.map.json", warnings) >>> if report["summary"]["passed"]: ... print("Validation passed!") .. py:function:: write_validation_report(map_file_name, warnings, output_dir = None) Write a validation report to a JSON file. Creates a validation report and writes it to the data/validation/ directory. The file is named after the map file with a .validation.json extension. :param map_file_name: Name of the map file that was validated (e.g., "my_zone.map.json"). :type map_file_name: :py:class:`str` :param warnings: List of validation warnings from validate_all(). :type warnings: :py:class:`list[ValidationWarning]` :param output_dir: Directory to write the report to. Defaults to "data/validation/". :type output_dir: :py:class:`str`, *optional* :returns: Absolute path to the written validation report file. :rtype: :py:class:`str` :raises OSError: If the output directory cannot be created or the file cannot be written. .. admonition:: Examples >>> warnings = validate_all(map_file) >>> report_path = write_validation_report("my_zone.map.json", warnings) >>> print(f"Report written to: {report_path}") .. admonition:: Notes The validation directory is created if it doesn't exist. Previous validation reports for the same map file are overwritten. The report file uses the naming convention: ``{zone_id}.validation.json`` where zone_id is extracted from the map file name (e.g., "my_zone.map.json" -> "my_zone.validation.json").