claude-dev-env 2.9.0 → 2.10.0
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.
- package/CLAUDE.md +1 -1
- package/_shared/pr-loop/CLAUDE.md +1 -1
- package/_shared/pr-loop/audit-contract.md +17 -6
- package/_shared/pr-loop/audit-reply-template.md +4 -4
- package/_shared/pr-loop/code-rules-gate.md +3 -5
- package/_shared/pr-loop/fix-protocol.md +2 -3
- package/_shared/pr-loop/gh-payloads.md +1 -1
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
- package/_shared/pr-loop/scripts/README.md +1 -1
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
- package/_shared/pr-loop/scripts/preflight.py +9 -4
- package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
- package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
- package/_shared/pr-loop/state-schema.md +5 -14
- package/agents/CLAUDE.md +2 -2
- package/agents/clean-coder.md +58 -548
- package/agents/code-quality-agent.md +10 -2
- package/agents/code-verifier.md +1 -1
- package/agents/test_agent_frontmatter.py +32 -40
- package/audit-rubrics/CLAUDE.md +2 -1
- package/audit-rubrics/audit-categories.json +704 -0
- package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
- package/bin/CLAUDE.md +16 -5
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/install-plan.mjs +402 -0
- package/bin/install-transaction.mjs +455 -0
- package/bin/install.mjs +593 -147
- package/bin/install.plan.test.mjs +194 -0
- package/bin/install.profile-root.test.mjs +154 -0
- package/bin/install.profiles.test.mjs +253 -0
- package/bin/install.settings-defaults.test.mjs +200 -0
- package/bin/install.transaction.test.mjs +400 -0
- package/bin/install.uninstall-transaction.test.mjs +418 -0
- package/bin/merge_managed_permissions.mjs +130 -0
- package/bin/resolve-install-root.mjs +181 -0
- package/bin/select-install-targets.mjs +401 -0
- package/commands/CLAUDE.md +0 -2
- package/docs/references/CLAUDE.md +1 -0
- package/docs/references/advisor-tool.md +1 -1
- package/docs/references/prose-style-enforcement.md +25 -0
- package/hooks/blocking/CLAUDE.md +6 -6
- package/hooks/blocking/_path_setup.py +9 -5
- package/hooks/blocking/code_rules_docstrings.py +124 -30
- package/hooks/blocking/code_rules_enforcer.py +161 -16
- package/hooks/blocking/code_rules_shared.py +40 -23
- package/hooks/blocking/config/CLAUDE.md +3 -5
- package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
- package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
- package/hooks/blocking/eli11_reply_enforcer.py +70 -113
- package/hooks/blocking/hedging_language_blocker.py +103 -20
- package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
- package/hooks/blocking/intent_only_ending_blocker.py +6 -0
- package/hooks/blocking/plain_language_blocker.py +139 -20
- package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
- package/hooks/blocking/state_description_blocker.py +7 -1
- package/hooks/blocking/tdd_enforcer.py +8 -0
- package/hooks/blocking/test__path_setup.py +28 -0
- package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
- package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
- package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
- package/hooks/blocking/test_hedging_language_blocker.py +120 -1
- package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
- package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
- package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
- package/hooks/blocking/test_plain_language_blocker.py +129 -19
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
- package/hooks/blocking/test_state_description_blocker.py +45 -2
- package/hooks/blocking/test_stop_dispatcher.py +11 -7
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
- package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
- package/hooks/hooks.json +15 -0
- package/hooks/hooks_constants/CLAUDE.md +14 -3
- package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
- package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
- package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
- package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
- package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
- package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/project_paths_reader.py +31 -4
- package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
- package/hooks/hooks_constants/pytest_invocation.py +354 -0
- package/hooks/hooks_constants/session_start_injector.py +163 -0
- package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
- package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
- package/hooks/hooks_constants/shell_command_segments.py +5 -0
- package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
- package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
- package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
- package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
- package/hooks/hooks_constants/test_session_start_injector.py +168 -0
- package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/prose_matcher_advisory.py +237 -0
- package/hooks/observability/test_prose_matcher_advisory.py +143 -0
- package/hooks/session/CLAUDE.md +9 -1
- package/hooks/session/_path_setup.py +13 -0
- package/hooks/session/issue_tracker_session_starter.py +135 -0
- package/hooks/session/orchestrator_auto_starter.py +100 -0
- package/hooks/session/test__path_setup.py +28 -0
- package/hooks/session/test_issue_tracker_session_starter.py +104 -0
- package/hooks/session/test_orchestrator_auto_starter.py +99 -0
- package/hooks/session/test_working_style_prompt.py +47 -0
- package/hooks/session/untracked_repo_detector.py +1 -24
- package/hooks/session/working_style_prompt.py +36 -0
- package/hooks/validators/_path_setup.py +19 -0
- package/hooks/validators/run_all_validators.py +8 -13
- package/installable-surfaces.manifest.json +21 -0
- package/output-styles/CLAUDE.md +1 -3
- package/package.json +4 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/durable-post-artifacts.md +2 -2
- package/rules/eli11-replies.md +6 -1
- package/rules/hedging-claims.md +4 -2
- package/rules/long-horizon-autonomy.md +3 -1
- package/rules/opus5-communication-contract.md +45 -0
- package/rules/plain-language.md +2 -2
- package/rules/research-mode.md +1 -1
- package/scripts/CLAUDE.md +11 -0
- package/scripts/Sync-RepoMain.ps1 +215 -0
- package/scripts/active_capability_references.py +218 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
- package/scripts/claude_chain_runner.py +394 -6
- package/scripts/claude_chain_usage.py +1 -1
- package/scripts/codex_compat_materializer.py +105 -85
- package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -0
- package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
- package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
- package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
- package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
- package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
- package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
- package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
- package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
- package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
- package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
- package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
- package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
- package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
- package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
- package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
- package/scripts/spawn_grok_batch.py +3 -0
- package/scripts/test_active_capability_references.py +108 -0
- package/scripts/test_claude_chain_runner.py +414 -82
- package/scripts/test_claude_chain_usage.py +12 -12
- package/scripts/test_resolve_worker_spawn.py +2 -2
- package/scripts/test_verify_installable_package.py +208 -0
- package/scripts/tests/test_codex_compat_materializer.py +33 -0
- package/scripts/verify_installable_package.py +612 -0
- package/settings.json +10 -0
- package/skills/CLAUDE.md +2 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
- package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
- package/skills/autoconverge/reference/convergence.md +2 -1
- package/skills/autoconverge/reference/stop-conditions.md +5 -3
- package/skills/beat-sheet/SKILL.md +54 -0
- package/skills/beat-sheet/reference/visual-beats.md +29 -0
- package/skills/bugteam/CONSTRAINTS.md +4 -4
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/e-code-review/SKILL.md +26 -5
- package/skills/e-code-review/reference/effort-evaluation.md +35 -0
- package/skills/e-code-review/reference/medium.md +15 -4
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
- package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
- package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
- package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
- package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
- package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
- package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
- package/skills/e-code-review/scripts/grok_code_review.py +16 -7
- package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
- package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
- package/skills/e-code-review/scripts/test_grok_code_review.py +77 -0
- package/skills/plan-to-pr/scripts/create_packet.py +4 -4
- package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
- package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
- package/skills/plan-to-pr/scripts/validate_run.py +4 -1
- package/skills/pr-converge/scripts/check_convergence.py +21 -19
- package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
- package/skills/pr-converge/scripts/conftest.py +35 -0
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/rebase/SKILL.md +15 -3
- package/skills/reviewer-gates/SKILL.md +2 -2
- package/skills/show/SKILL.md +51 -0
- package/skills/show/references/accessibility.md +7 -0
- package/skills/show/references/art.md +3 -0
- package/skills/show/references/charts.md +3 -0
- package/skills/show/references/core-design.md +14 -0
- package/skills/show/references/erds.md +3 -0
- package/skills/show/references/flowcharts.md +3 -0
- package/skills/show/references/host-and-html.md +3 -0
- package/skills/show/references/illustrative-diagrams.md +10 -0
- package/skills/show/references/interaction.md +3 -0
- package/skills/show/references/mockups.md +3 -0
- package/skills/show/references/quality-gates.md +7 -0
- package/skills/show/references/structural-diagrams.md +3 -0
- package/skills/show/references/subject-inventory.md +21 -0
- package/skills/show/references/svg-contract.md +22 -0
- package/skills/show/routing.yaml +30 -0
- package/skills/show/samples/pr1262-v2.svg +222 -0
- package/skills/show/scripts/README.md +6 -0
- package/skills/show/scripts/validate-artifact.py +91 -0
- package/skills/show/scripts/validate-package.py +18 -0
- package/skills/show/templates/html-widget.html +4 -0
- package/skills/show/templates/svg-base.svg +19 -0
- package/skills/show/tests/fixtures/css-var.svg +6 -0
- package/skills/show/tests/fixtures/dead-ref.svg +7 -0
- package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
- package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
- package/skills/show/tests/fixtures/invalid.svg +1 -0
- package/skills/show/tests/fixtures/large-canvas.svg +21 -0
- package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
- package/skills/show/tests/fixtures/valid.html +1 -0
- package/skills/show/tests/test_validate-artifact.py +74 -0
- package/skills/show/tests/test_validators.py +59 -0
- package/skills/show/workflows/create-visual.md +13 -0
- package/skills/show/workflows/review-visual.md +20 -0
- package/skills/split-pr/SKILL.md +85 -0
- package/skills/split-pr/reference/path-layers.md +16 -0
- package/skills/split-pr/reference/proposal-format.md +15 -0
- package/skills/split-pr/reference/split-further-loop.md +10 -0
- package/skills/split-pr/reference/splitting-principles.md +26 -0
- package/skills/split-pr/scripts/analyze_pr.py +279 -0
- package/skills/split-pr/scripts/categorize_files.py +106 -0
- package/skills/split-pr/scripts/config/__init__.py +1 -0
- package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
- package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
- package/skills/split-pr/scripts/config/packing_constants.py +61 -0
- package/skills/split-pr/scripts/config/plan_constants.py +49 -0
- package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
- package/skills/split-pr/scripts/execute_split_slices.py +82 -0
- package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
- package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
- package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
- package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
- package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
- package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
- package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
- package/skills/split-pr/scripts/split_pr_title.py +41 -0
- package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
- package/skills/split-pr/scripts/test_categorize_files.py +55 -0
- package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
- package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
- package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
- package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
- package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
- package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
- package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
- package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
- package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
- package/skills/split-pr/scripts/test_verify_plan.py +56 -0
- package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
- package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
- package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
- package/skills/split-pr/scripts/verify_plan.py +139 -0
- package/system-prompts/software-engineer.xml +11 -2
- package/commands/initialize.md +0 -90
- package/commands/stubcheck.md +0 -88
- package/output-styles/caveman-agent.md +0 -37
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
<svg viewBox="0 0 1340 1680" xmlns="http://www.w3.org/2000/svg" width="1340" height="1680" role="img">
|
|
2
|
+
<title>PR 1262: unreachable checkpoint-skip branches removed</title>
|
|
3
|
+
<desc>Three panels. One: submit() stamps not_started, a value absent from workflow_order, so every should_skip_checkpoint reading is False and all five skip outlets are dead ends. Two: the four valves, the review bypass, and the LIVE_WALLPAPER spur are deleted; the checkpoint stamps remain on the straight pipe. Three: real resume is a product-level sieve in the orchestrator that turns THEME, WALLPAPER into WALLPAPER.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="aRed" markerUnits="userSpaceOnUse" markerWidth="16" markerHeight="14" refX="15" refY="7" orient="auto">
|
|
6
|
+
<path d="M0,0 L16,7 L0,14 Z" fill="#C0392B"/>
|
|
7
|
+
</marker>
|
|
8
|
+
<marker id="aGrn" markerUnits="userSpaceOnUse" markerWidth="16" markerHeight="14" refX="15" refY="7" orient="auto">
|
|
9
|
+
<path d="M0,0 L16,7 L0,14 Z" fill="#1E8449"/>
|
|
10
|
+
</marker>
|
|
11
|
+
<marker id="aAmb" markerUnits="userSpaceOnUse" markerWidth="16" markerHeight="14" refX="15" refY="7" orient="auto">
|
|
12
|
+
<path d="M0,0 L16,7 L0,14 Z" fill="#B9770E"/>
|
|
13
|
+
</marker>
|
|
14
|
+
<marker id="aGry" markerUnits="userSpaceOnUse" markerWidth="14" markerHeight="12" refX="13" refY="6" orient="auto">
|
|
15
|
+
<path d="M0,0 L14,6 L0,12 Z" fill="#7A7A7A"/>
|
|
16
|
+
</marker>
|
|
17
|
+
</defs>
|
|
18
|
+
|
|
19
|
+
<rect x="0" y="0" width="1340" height="1680" fill="#FAF7EF"/>
|
|
20
|
+
|
|
21
|
+
<!-- ================= PANEL 1 ================= -->
|
|
22
|
+
<text x="60" y="56" font-family="Helvetica,Arial,sans-serif" font-size="30" font-weight="bold" fill="#C0392B">1 · TODAY — every gate reads a blank stamp</text>
|
|
23
|
+
|
|
24
|
+
<rect x="58" y="94" width="286" height="230" rx="12" fill="#EDEAE1" stroke="#3A3A3A" stroke-width="3"/>
|
|
25
|
+
<text x="201" y="128" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="23" font-weight="bold" fill="#1A1A1A">submit()</text>
|
|
26
|
+
<rect x="175" y="144" width="52" height="32" fill="#8A8A8A" stroke="#3A3A3A" stroke-width="3"/>
|
|
27
|
+
<rect x="191" y="176" width="20" height="24" fill="#8A8A8A" stroke="#3A3A3A" stroke-width="3"/>
|
|
28
|
+
<rect x="147" y="200" width="108" height="26" fill="#C0392B" stroke="#7B241C" stroke-width="3"/>
|
|
29
|
+
<rect x="96" y="248" width="212" height="52" rx="6" fill="#FFFFFF" stroke="#C0392B" stroke-width="3"/>
|
|
30
|
+
<text x="202" y="281" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="22" fill="#C0392B">not_started</text>
|
|
31
|
+
<text x="201" y="346" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">submission_service.py:173</text>
|
|
32
|
+
|
|
33
|
+
<line x1="348" y1="274" x2="404" y2="274" stroke="#C0392B" stroke-width="6" marker-end="url(#aRed)"/>
|
|
34
|
+
|
|
35
|
+
<rect x="416" y="94" width="308" height="268" rx="12" fill="#FFFFFF" stroke="#3A3A3A" stroke-width="3"/>
|
|
36
|
+
<text x="570" y="124" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="21" font-weight="bold" fill="#1A1A1A">workflow_order()</text>
|
|
37
|
+
<rect x="438" y="136" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
38
|
+
<text x="570" y="159" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">binary_apks_uploaded</text>
|
|
39
|
+
<rect x="438" y="172" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
40
|
+
<text x="570" y="195" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">app_info_saved</text>
|
|
41
|
+
<rect x="438" y="208" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
42
|
+
<text x="570" y="231" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">country_price_saved</text>
|
|
43
|
+
<rect x="438" y="244" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
44
|
+
<text x="570" y="267" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">publication_saved</text>
|
|
45
|
+
<rect x="438" y="280" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
46
|
+
<text x="570" y="303" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">review_saved</text>
|
|
47
|
+
<rect x="438" y="316" width="264" height="32" rx="5" fill="#F2EFE6" stroke="#9A9A9A" stroke-width="2"/>
|
|
48
|
+
<text x="570" y="339" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#3A3A3A">submitted_for_review</text>
|
|
49
|
+
|
|
50
|
+
<rect x="740" y="130" width="152" height="40" rx="6" fill="#FFFFFF" stroke="#C0392B" stroke-width="3" stroke-dasharray="7 5"/>
|
|
51
|
+
<text x="816" y="158" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#C0392B">not_started</text>
|
|
52
|
+
<rect x="740" y="214" width="152" height="40" rx="6" fill="#FFFFFF" stroke="#C0392B" stroke-width="3" stroke-dasharray="7 5" opacity="0.5"/>
|
|
53
|
+
<text x="816" y="242" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#C0392B" opacity="0.5">not_started</text>
|
|
54
|
+
<rect x="740" y="298" width="152" height="40" rx="6" fill="#FFFFFF" stroke="#C0392B" stroke-width="3" stroke-dasharray="7 5" opacity="0.26"/>
|
|
55
|
+
<text x="816" y="326" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#C0392B" opacity="0.26">not_started</text>
|
|
56
|
+
<line x1="816" y1="174" x2="816" y2="356" stroke="#C0392B" stroke-width="5" stroke-dasharray="10 8" marker-end="url(#aRed)"/>
|
|
57
|
+
<text x="816" y="394" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="28" font-weight="bold" fill="#C0392B">False</text>
|
|
58
|
+
|
|
59
|
+
<text x="944" y="196" font-family="Menlo,Consolas,monospace" font-size="20" fill="#C0392B">no slot matches</text>
|
|
60
|
+
<text x="944" y="222" font-family="Menlo,Consolas,monospace" font-size="20" fill="#C0392B">not_started</text>
|
|
61
|
+
<text x="944" y="254" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">checkpoint.py · workflow_order</text>
|
|
62
|
+
<text x="944" y="276" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">excludes NOT_STARTED</text>
|
|
63
|
+
<text x="944" y="326" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">should_skip_checkpoint</text>
|
|
64
|
+
<text x="944" y="350" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">submission_checkpoints.py:47</text>
|
|
65
|
+
|
|
66
|
+
<line x1="816" y1="402" x2="816" y2="426" stroke="#C0392B" stroke-width="5"/>
|
|
67
|
+
<line x1="210" y1="426" x2="1170" y2="426" stroke="#C0392B" stroke-width="5"/>
|
|
68
|
+
|
|
69
|
+
<rect x="86" y="480" width="1204" height="56" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
70
|
+
<line x1="86" y1="508" x2="1312" y2="508" stroke="#1E8449" stroke-width="8" marker-end="url(#aGrn)"/>
|
|
71
|
+
|
|
72
|
+
<g>
|
|
73
|
+
<line x1="210" y1="426" x2="210" y2="460" stroke="#C0392B" stroke-width="5" marker-end="url(#aRed)"/>
|
|
74
|
+
<rect x="166" y="462" width="88" height="92" rx="8" fill="#FFFFFF" stroke="#C0392B" stroke-width="3"/>
|
|
75
|
+
<circle cx="210" cy="508" r="16" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
76
|
+
<line x1="210" y1="554" x2="210" y2="584" stroke="#C0392B" stroke-width="5" stroke-dasharray="8 6"/>
|
|
77
|
+
<rect x="176" y="584" width="68" height="30" fill="#F6DDD9" stroke="#C0392B" stroke-width="3"/>
|
|
78
|
+
<line x1="188" y1="590" x2="232" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
79
|
+
<line x1="232" y1="590" x2="188" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
80
|
+
<text x="210" y="648" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#1A1A1A">binary_apks_uploaded</text>
|
|
81
|
+
<text x="210" y="672" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="16" fill="#6E6E6E">pipeline.py:114</text>
|
|
82
|
+
</g>
|
|
83
|
+
<g>
|
|
84
|
+
<line x1="450" y1="426" x2="450" y2="460" stroke="#C0392B" stroke-width="5" marker-end="url(#aRed)"/>
|
|
85
|
+
<rect x="406" y="462" width="88" height="92" rx="8" fill="#FFFFFF" stroke="#C0392B" stroke-width="3"/>
|
|
86
|
+
<circle cx="450" cy="508" r="16" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
87
|
+
<line x1="450" y1="554" x2="450" y2="584" stroke="#C0392B" stroke-width="5" stroke-dasharray="8 6"/>
|
|
88
|
+
<rect x="416" y="584" width="68" height="30" fill="#F6DDD9" stroke="#C0392B" stroke-width="3"/>
|
|
89
|
+
<line x1="428" y1="590" x2="472" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
90
|
+
<line x1="472" y1="590" x2="428" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
91
|
+
<text x="450" y="648" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#1A1A1A">app_info_saved</text>
|
|
92
|
+
<text x="450" y="672" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="16" fill="#6E6E6E">pipeline.py:174</text>
|
|
93
|
+
</g>
|
|
94
|
+
<g>
|
|
95
|
+
<line x1="690" y1="426" x2="690" y2="460" stroke="#C0392B" stroke-width="5" marker-end="url(#aRed)"/>
|
|
96
|
+
<rect x="646" y="462" width="88" height="92" rx="8" fill="#FFFFFF" stroke="#C0392B" stroke-width="3"/>
|
|
97
|
+
<circle cx="690" cy="508" r="16" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
98
|
+
<line x1="690" y1="554" x2="690" y2="584" stroke="#C0392B" stroke-width="5" stroke-dasharray="8 6"/>
|
|
99
|
+
<rect x="656" y="584" width="68" height="30" fill="#F6DDD9" stroke="#C0392B" stroke-width="3"/>
|
|
100
|
+
<line x1="668" y1="590" x2="712" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
101
|
+
<line x1="712" y1="590" x2="668" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
102
|
+
<text x="690" y="648" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#1A1A1A">country_price_saved</text>
|
|
103
|
+
<text x="690" y="672" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="16" fill="#6E6E6E">pipeline.py:208</text>
|
|
104
|
+
</g>
|
|
105
|
+
<g>
|
|
106
|
+
<line x1="930" y1="426" x2="930" y2="460" stroke="#C0392B" stroke-width="5" marker-end="url(#aRed)"/>
|
|
107
|
+
<rect x="886" y="462" width="88" height="92" rx="8" fill="#FFFFFF" stroke="#C0392B" stroke-width="3"/>
|
|
108
|
+
<circle cx="930" cy="508" r="16" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
109
|
+
<line x1="930" y1="554" x2="930" y2="584" stroke="#C0392B" stroke-width="5" stroke-dasharray="8 6"/>
|
|
110
|
+
<rect x="896" y="584" width="68" height="30" fill="#F6DDD9" stroke="#C0392B" stroke-width="3"/>
|
|
111
|
+
<line x1="908" y1="590" x2="952" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
112
|
+
<line x1="952" y1="590" x2="908" y2="608" stroke="#C0392B" stroke-width="4"/>
|
|
113
|
+
<text x="930" y="648" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#1A1A1A">publication_saved</text>
|
|
114
|
+
<text x="930" y="672" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="16" fill="#6E6E6E">pipeline.py:242</text>
|
|
115
|
+
</g>
|
|
116
|
+
<g>
|
|
117
|
+
<line x1="1170" y1="426" x2="1170" y2="460" stroke="#C0392B" stroke-width="5" marker-end="url(#aRed)"/>
|
|
118
|
+
<rect x="1126" y="462" width="88" height="92" rx="8" fill="#FFFFFF" stroke="#C0392B" stroke-width="3" stroke-dasharray="8 6"/>
|
|
119
|
+
<circle cx="1170" cy="508" r="16" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
120
|
+
<path d="M 1170 554 L 1170 588 L 1272 588 L 1272 540" fill="none" stroke="#C0392B" stroke-width="5" stroke-dasharray="8 6"/>
|
|
121
|
+
<line x1="1248" y1="562" x2="1280" y2="582" stroke="#C0392B" stroke-width="4"/>
|
|
122
|
+
<line x1="1280" y1="562" x2="1248" y2="582" stroke="#C0392B" stroke-width="4"/>
|
|
123
|
+
<text x="1170" y="648" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#1A1A1A">review_saved</text>
|
|
124
|
+
<text x="1170" y="672" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="16" fill="#6E6E6E">pipeline.py:314 · early return</text>
|
|
125
|
+
</g>
|
|
126
|
+
|
|
127
|
+
<line x1="60" y1="712" x2="1280" y2="712" stroke="#D5D0C2" stroke-width="3"/>
|
|
128
|
+
|
|
129
|
+
<!-- ================= PANEL 2 ================= -->
|
|
130
|
+
<text x="60" y="774" font-family="Helvetica,Arial,sans-serif" font-size="30" font-weight="bold" fill="#B9770E">2 · THE CUT — the gates come off, the stamps stay</text>
|
|
131
|
+
|
|
132
|
+
<path d="M 92 820 L 566 820 L 530 1058 L 128 1058 Z" fill="#FDF3E0" stroke="#B9770E" stroke-width="4"/>
|
|
133
|
+
<text x="329" y="856" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="22" font-weight="bold" fill="#B9770E">should_skip_checkpoint</text>
|
|
134
|
+
<text x="329" y="882" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#B9770E">−993 lines</text>
|
|
135
|
+
|
|
136
|
+
<rect x="126" y="900" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3"/>
|
|
137
|
+
<text x="217" y="928" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">valve :114</text>
|
|
138
|
+
<rect x="326" y="900" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3"/>
|
|
139
|
+
<text x="417" y="928" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">valve :174</text>
|
|
140
|
+
<rect x="138" y="954" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3"/>
|
|
141
|
+
<text x="229" y="982" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">valve :208</text>
|
|
142
|
+
<rect x="338" y="954" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3"/>
|
|
143
|
+
<text x="429" y="982" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">valve :242</text>
|
|
144
|
+
<rect x="150" y="1008" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3" stroke-dasharray="7 5"/>
|
|
145
|
+
<text x="241" y="1036" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">bypass :314</text>
|
|
146
|
+
<rect x="350" y="1008" width="182" height="42" rx="8" fill="#FFFFFF" stroke="#B9770E" stroke-width="3" stroke-dasharray="7 5"/>
|
|
147
|
+
<text x="441" y="1036" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="18" fill="#B9770E">spur :124</text>
|
|
148
|
+
|
|
149
|
+
<rect x="92" y="1084" width="474" height="98" rx="10" fill="#FFFFFF" stroke="#B9770E" stroke-width="3"/>
|
|
150
|
+
<text x="114" y="1118" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">elif LIVE_WALLPAPER:</text>
|
|
151
|
+
<text x="140" y="1146" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">capture_content_id()</text>
|
|
152
|
+
<text x="114" y="1172" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">its only inlet was the valve above it</text>
|
|
153
|
+
<line x1="478" y1="1112" x2="518" y2="1140" stroke="#C0392B" stroke-width="5"/>
|
|
154
|
+
<line x1="518" y1="1112" x2="478" y2="1140" stroke="#C0392B" stroke-width="5"/>
|
|
155
|
+
|
|
156
|
+
<path d="M 706 946 L 624 900" fill="none" stroke="#B9770E" stroke-width="6" marker-end="url(#aAmb)"/>
|
|
157
|
+
|
|
158
|
+
<rect x="732" y="820" width="68" height="332" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
159
|
+
<line x1="766" y1="820" x2="766" y2="1188" stroke="#1E8449" stroke-width="8" marker-end="url(#aGrn)"/>
|
|
160
|
+
|
|
161
|
+
<g>
|
|
162
|
+
<rect x="814" y="828" width="40" height="40" rx="6" fill="#1E8449"/>
|
|
163
|
+
<text x="834" y="857" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="24" font-weight="bold" fill="#FFFFFF">✓</text>
|
|
164
|
+
<text x="870" y="844" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">binary_apks_uploaded</text>
|
|
165
|
+
<text x="870" y="866" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">binary_devices_configured</text>
|
|
166
|
+
</g>
|
|
167
|
+
<g>
|
|
168
|
+
<rect x="814" y="894" width="40" height="40" rx="6" fill="#1E8449"/>
|
|
169
|
+
<text x="834" y="923" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="24" font-weight="bold" fill="#FFFFFF">✓</text>
|
|
170
|
+
<text x="870" y="922" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">app_info_saved</text>
|
|
171
|
+
</g>
|
|
172
|
+
<g>
|
|
173
|
+
<rect x="814" y="960" width="40" height="40" rx="6" fill="#1E8449"/>
|
|
174
|
+
<text x="834" y="989" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="24" font-weight="bold" fill="#FFFFFF">✓</text>
|
|
175
|
+
<text x="870" y="988" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">country_price_saved</text>
|
|
176
|
+
</g>
|
|
177
|
+
<g>
|
|
178
|
+
<rect x="814" y="1026" width="40" height="40" rx="6" fill="#1E8449"/>
|
|
179
|
+
<text x="834" y="1055" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="24" font-weight="bold" fill="#FFFFFF">✓</text>
|
|
180
|
+
<text x="870" y="1054" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">publication_saved</text>
|
|
181
|
+
</g>
|
|
182
|
+
<g>
|
|
183
|
+
<rect x="814" y="1092" width="40" height="40" rx="6" fill="#FFFFFF" stroke="#1E8449" stroke-width="3"/>
|
|
184
|
+
<text x="834" y="1121" text-anchor="middle" font-family="Helvetica,Arial,sans-serif" font-size="24" font-weight="bold" fill="#1E8449">✓</text>
|
|
185
|
+
<text x="870" y="1120" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">review_saved</text>
|
|
186
|
+
<text x="870" y="1144" font-family="Menlo,Consolas,monospace" font-size="17" fill="#6E6E6E">withheld when the save is unverified</text>
|
|
187
|
+
</g>
|
|
188
|
+
|
|
189
|
+
<line x1="60" y1="1226" x2="1280" y2="1226" stroke="#D5D0C2" stroke-width="3"/>
|
|
190
|
+
|
|
191
|
+
<!-- ================= PANEL 3 ================= -->
|
|
192
|
+
<text x="60" y="1288" font-family="Helvetica,Arial,sans-serif" font-size="30" font-weight="bold" fill="#1E8449">3 · RESUME LIVES ONE FLOOR UP — a sieve, not a valve</text>
|
|
193
|
+
|
|
194
|
+
<rect x="80" y="1338" width="300" height="118" rx="10" fill="#FFFFFF" stroke="#1E8449" stroke-width="3"/>
|
|
195
|
+
<text x="230" y="1370" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#6E6E6E">detected order</text>
|
|
196
|
+
<rect x="104" y="1386" width="118" height="46" rx="6" fill="#EDEAE1" stroke="#3A3A3A" stroke-width="2"/>
|
|
197
|
+
<text x="163" y="1417" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">THEME</text>
|
|
198
|
+
<rect x="234" y="1386" width="126" height="46" rx="6" fill="#EDEAE1" stroke="#3A3A3A" stroke-width="2"/>
|
|
199
|
+
<text x="297" y="1417" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1A1A1A">WALLPAPER</text>
|
|
200
|
+
|
|
201
|
+
<line x1="388" y1="1396" x2="452" y2="1396" stroke="#1E8449" stroke-width="6" marker-end="url(#aGrn)"/>
|
|
202
|
+
|
|
203
|
+
<path d="M 464 1328 L 792 1328 L 690 1458 L 566 1458 Z" fill="#DFF0E4" stroke="#1E8449" stroke-width="4"/>
|
|
204
|
+
<text x="628" y="1364" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="21" font-weight="bold" fill="#1A1A1A">is_product_submitted</text>
|
|
205
|
+
<text x="628" y="1392" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="17" fill="#1E8449">_orchestrator_theme_runner.py:253</text>
|
|
206
|
+
<line x1="528" y1="1418" x2="726" y2="1418" stroke="#1E8449" stroke-width="3" stroke-dasharray="6 8"/>
|
|
207
|
+
|
|
208
|
+
<path d="M 566 1462 L 566 1538 L 476 1538" fill="none" stroke="#7A7A7A" stroke-width="5" marker-end="url(#aGry)"/>
|
|
209
|
+
<rect x="304" y="1514" width="150" height="48" rx="6" fill="#EDEAE1" stroke="#7A7A7A" stroke-width="3"/>
|
|
210
|
+
<text x="379" y="1546" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#7A7A7A">THEME</text>
|
|
211
|
+
<text x="304" y="1598" font-family="Menlo,Consolas,monospace" font-size="18" fill="#7A7A7A">already submitted per tracker</text>
|
|
212
|
+
|
|
213
|
+
<line x1="798" y1="1388" x2="860" y2="1388" stroke="#1E8449" stroke-width="6" marker-end="url(#aGrn)"/>
|
|
214
|
+
<rect x="874" y="1338" width="300" height="118" rx="10" fill="#FFFFFF" stroke="#1E8449" stroke-width="3"/>
|
|
215
|
+
<text x="1024" y="1370" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="19" fill="#6E6E6E">order sent to submit()</text>
|
|
216
|
+
<rect x="960" y="1386" width="126" height="46" rx="6" fill="#DFF0E4" stroke="#1E8449" stroke-width="3"/>
|
|
217
|
+
<text x="1023" y="1417" text-anchor="middle" font-family="Menlo,Consolas,monospace" font-size="20" fill="#1E8449">WALLPAPER</text>
|
|
218
|
+
|
|
219
|
+
<text x="874" y="1518" font-family="Menlo,Consolas,monospace" font-size="22" fill="#1A1A1A">[THEME, WALLPAPER] → [WALLPAPER]</text>
|
|
220
|
+
<text x="874" y="1548" font-family="Menlo,Consolas,monospace" font-size="18" fill="#6E6E6E">product granularity · one submit() per product</text>
|
|
221
|
+
<text x="874" y="1598" font-family="Menlo,Consolas,monospace" font-size="18" fill="#6E6E6E">PR #1262 · base 5b40e42</text>
|
|
222
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Show scripts
|
|
2
|
+
|
|
3
|
+
Run these scripts from any directory by passing an absolute artifact path. They use only the Python standard library.
|
|
4
|
+
|
|
5
|
+
- `validate-package.py` checks the package skeleton and hub links.
|
|
6
|
+
- `validate-artifact.py` checks SVG or HTML output contracts.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import re
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
standard_canvas_width = 680.0
|
|
6
|
+
large_canvas_minimum_width = 1360.0
|
|
7
|
+
large_canvas_maximum_width = 2000.0
|
|
8
|
+
text_floor_at_standard_width = 16.0
|
|
9
|
+
connector_tags = {"line", "path", "polyline"}
|
|
10
|
+
tag_pattern = re.compile(r"<(/?)([a-zA-Z][\w:.-]*)([^>]*?)(/?)>", re.DOTALL)
|
|
11
|
+
fill_pattern = re.compile(r'\bfill=["\']([^"\']*)["\']')
|
|
12
|
+
style_fill_pattern = re.compile(r'style=["\'][^"\']*\bfill\s*:\s*([^;"\']+)')
|
|
13
|
+
marker_pattern = re.compile(r"\bmarker-(?:start|mid|end)=")
|
|
14
|
+
comment_pattern = re.compile(r"<!--.*?-->", re.DOTALL)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def find_unfilled_connectors(markup: str) -> list[str]:
|
|
18
|
+
"""Name every connector whose fill resolves to something other than none.
|
|
19
|
+
|
|
20
|
+
A connector is a line, path, or polyline carrying a marker. Its fill comes
|
|
21
|
+
from its own attribute when it has one, and from the nearest enclosing
|
|
22
|
+
element otherwise::
|
|
23
|
+
|
|
24
|
+
<g fill="none"><line marker-end="url(#a)"/></g> ok: inherits none
|
|
25
|
+
<line fill="red" marker-end="url(#a)"/> flag: own fill wins
|
|
26
|
+
<path d="M0 0L9 9Z" fill="currentColor"/> ok: glyph, no marker
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
markup: The full SVG or HTML source text.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
The tag name of each offending connector, in document order.
|
|
33
|
+
"""
|
|
34
|
+
inherited_fills = [""]
|
|
35
|
+
offenders = []
|
|
36
|
+
for each_tag in tag_pattern.finditer(markup):
|
|
37
|
+
is_closing, tag_name, attributes, is_self_closing = each_tag.groups()
|
|
38
|
+
if is_closing:
|
|
39
|
+
inherited_fills = inherited_fills[:-1] or [""]
|
|
40
|
+
continue
|
|
41
|
+
own_fill = style_fill_pattern.search(attributes) or fill_pattern.search(attributes)
|
|
42
|
+
effective_fill = own_fill.group(1).strip() if own_fill else inherited_fills[-1]
|
|
43
|
+
is_connector = tag_name in connector_tags and bool(marker_pattern.search(attributes))
|
|
44
|
+
if is_connector and effective_fill != "none": offenders.append(tag_name)
|
|
45
|
+
if not is_self_closing: inherited_fills.append(effective_fill)
|
|
46
|
+
return offenders
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
if len(sys.argv[1:]) != 1:
|
|
50
|
+
raise SystemExit("usage: validate-artifact.py <svg-or-html>")
|
|
51
|
+
path = Path(sys.argv[1])
|
|
52
|
+
if not path.is_file():
|
|
53
|
+
raise SystemExit(f"missing artifact: {path}")
|
|
54
|
+
text = comment_pattern.sub("", path.read_text(encoding="utf-8"))
|
|
55
|
+
errors = []
|
|
56
|
+
warnings = []
|
|
57
|
+
defined_properties = set(re.findall(r'(--[\w-]+)\s*:', text))
|
|
58
|
+
for each_property_name in re.findall(r'var\(\s*(--[\w-]+)', text):
|
|
59
|
+
if each_property_name not in defined_properties: errors.append(f"undefined custom property {each_property_name}")
|
|
60
|
+
defined_ids = set(re.findall(r'\bid=["\']([^"\']+)["\']', text))
|
|
61
|
+
referenced_ids = re.findall(r'href=["\']#([^"\']+)["\']', text) + re.findall(r'url\(\s*#([^)\s"\']+)', text)
|
|
62
|
+
for each_referenced_id in referenced_ids:
|
|
63
|
+
if each_referenced_id not in defined_ids: errors.append(f"reference to missing id #{each_referenced_id}")
|
|
64
|
+
if path.suffix.lower() == ".svg":
|
|
65
|
+
if not re.search(r'<svg[^>]+role=["\']img["\']', text): errors.append("SVG needs role=img")
|
|
66
|
+
viewbox = re.search(r'<svg[^>]+viewBox=["\']0 0 ([0-9.]+) ', text)
|
|
67
|
+
canvas_width = float(viewbox.group(1)) if viewbox else 0.0
|
|
68
|
+
is_standard_canvas = canvas_width == standard_canvas_width
|
|
69
|
+
is_large_canvas = large_canvas_minimum_width <= canvas_width <= large_canvas_maximum_width
|
|
70
|
+
if not is_standard_canvas and not is_large_canvas: errors.append("SVG viewBox width must be 680 or 1360-2000")
|
|
71
|
+
if not re.search(r'<svg[^>]*>\s*<title>.*?</title>\s*<desc>', text, re.DOTALL): errors.append("SVG title and desc must be first")
|
|
72
|
+
unfilled_connectors = find_unfilled_connectors(text)
|
|
73
|
+
if unfilled_connectors: errors.append(f"connectors need fill=none: {', '.join(sorted(set(unfilled_connectors)))}")
|
|
74
|
+
floor_width = max(canvas_width, standard_canvas_width)
|
|
75
|
+
text_floor = round(text_floor_at_standard_width * floor_width / standard_canvas_width)
|
|
76
|
+
sizes = [float(x) for x in re.findall(r'font-size=["\']([0-9.]+)', text)]
|
|
77
|
+
if any(size < text_floor for size in sizes): errors.append(f"text below {text_floor}px")
|
|
78
|
+
for each_marker in re.findall(r'<marker\b[^>]*>', text):
|
|
79
|
+
if not re.search(r'markerUnits=["\']userSpaceOnUse["\']', each_marker): warnings.append("marker without markerUnits=userSpaceOnUse scales with stroke width")
|
|
80
|
+
elif path.suffix.lower() in {".html", ".htm"}:
|
|
81
|
+
if not re.match(r'\s*<h2[^>]+class=["\']sr-only["\']', text): errors.append("HTML needs a first sr-only h2")
|
|
82
|
+
if re.search(r'position\s*:\s*fixed|overflow\s*:\s*(?:auto|scroll)', text): errors.append("fixed positioning and nested scrolling are forbidden")
|
|
83
|
+
else:
|
|
84
|
+
errors.append("artifact must be SVG or HTML")
|
|
85
|
+
for each_warning in warnings:
|
|
86
|
+
print(f"ARTIFACT WARNING: {each_warning}")
|
|
87
|
+
if errors:
|
|
88
|
+
print("ARTIFACT INVALID")
|
|
89
|
+
print("\n".join(errors))
|
|
90
|
+
sys.exit(1)
|
|
91
|
+
print(f"ARTIFACT VALID: {path.name}")
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
skill_root = Path(__file__).resolve().parents[1]
|
|
6
|
+
routing_text = (skill_root / "routing.yaml").read_text(encoding="utf-8")
|
|
7
|
+
routed = re.findall(r"(?:references|workflows|templates)/[\w.-]+", routing_text)
|
|
8
|
+
required = ["SKILL.md", "routing.yaml", "workflows/review-visual.md", *sorted(set(routed))]
|
|
9
|
+
text = (skill_root / "SKILL.md").read_text(encoding="utf-8")
|
|
10
|
+
errors = [p for p in required if not (skill_root / p).is_file()]
|
|
11
|
+
for each_token in ["routing.yaml", "workflows/create-visual.md"]:
|
|
12
|
+
if each_token not in text:
|
|
13
|
+
errors.append(f"SKILL.md missing {each_token}")
|
|
14
|
+
if errors:
|
|
15
|
+
print("PACKAGE INVALID")
|
|
16
|
+
print("\n".join(errors))
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
print(f"PACKAGE VALID: {len(required)} required files present")
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 180" role="img">
|
|
2
|
+
<title>Accessible visual title</title>
|
|
3
|
+
<desc>One-sentence description of the visual.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerUnits="userSpaceOnUse" markerWidth="6" markerHeight="6" orient="auto">
|
|
6
|
+
<path d="M2 1L8 5L2 9" fill="none" stroke="#3A3A3A" stroke-width="1.5" />
|
|
7
|
+
</marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<rect x="0" y="0" width="680" height="180" fill="#F2EFE6" />
|
|
10
|
+
<g stroke-width="1">
|
|
11
|
+
<rect x="40" y="40" width="180" height="44" rx="8" fill="#FFFFFF" stroke="#9A9A9A" />
|
|
12
|
+
<line x1="220" y1="62" x2="300" y2="62" fill="none" stroke="#3A3A3A" marker-end="url(#arrow)" />
|
|
13
|
+
<rect x="300" y="40" width="180" height="44" rx="8" fill="#DFF0E4" stroke="#1E8449" />
|
|
14
|
+
</g>
|
|
15
|
+
<g fill="#1A1A1A" font-family="sans-serif" font-size="16" text-anchor="middle">
|
|
16
|
+
<text x="130" y="62" dominant-baseline="central">Start</text>
|
|
17
|
+
<text x="390" y="62" dominant-baseline="central">Next step</text>
|
|
18
|
+
</g>
|
|
19
|
+
</svg>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 120" role="img">
|
|
2
|
+
<title>Variable fill</title>
|
|
3
|
+
<desc>A labelled box whose text fill comes from a CSS custom property.</desc>
|
|
4
|
+
<g fill="none" stroke="currentColor" stroke-width="1"><rect x="40" y="40" width="240" height="44" rx="8"/></g>
|
|
5
|
+
<g fill="var(--ink)" font-family="sans-serif" font-size="16"><text x="60" y="68">Label</text></g>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 120" role="img">
|
|
2
|
+
<title>Dead reference</title>
|
|
3
|
+
<desc>A use element pointing at a symbol the file never defines.</desc>
|
|
4
|
+
<g fill="none" stroke="currentColor" stroke-width="1"><rect x="40" y="40" width="240" height="44" rx="8"/></g>
|
|
5
|
+
<use href="#ghost" x="320" y="40"/>
|
|
6
|
+
<g fill="currentColor" font-family="sans-serif" font-size="16"><text x="60" y="68">Label</text></g>
|
|
7
|
+
</svg>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 140" role="img">
|
|
2
|
+
<title>Filled glyph</title>
|
|
3
|
+
<desc>A solid check mark drawn as a filled path beside its label.</desc>
|
|
4
|
+
<path d="M40 70L60 90L100 46Z" fill="currentColor"/>
|
|
5
|
+
<g fill="currentColor" font-family="sans-serif" font-size="16">
|
|
6
|
+
<text x="120" y="76">Done</text>
|
|
7
|
+
</g>
|
|
8
|
+
</svg>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 140" role="img">
|
|
2
|
+
<title>Inherited connector fill</title>
|
|
3
|
+
<desc>Two boxes joined by a connector that takes its fill from the surrounding group.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerUnits="userSpaceOnUse" markerWidth="6" markerHeight="6" orient="auto">
|
|
6
|
+
<path d="M2 1L8 5L2 9" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
|
7
|
+
</marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<g fill="none" stroke="currentColor" stroke-width="1">
|
|
10
|
+
<rect x="40" y="48" width="200" height="44" rx="8"/>
|
|
11
|
+
<line x1="240" y1="70" x2="320" y2="70" marker-end="url(#arrow)"/>
|
|
12
|
+
<rect x="320" y="48" width="200" height="44" rx="8"/>
|
|
13
|
+
</g>
|
|
14
|
+
<g fill="currentColor" font-family="sans-serif" font-size="16" text-anchor="middle">
|
|
15
|
+
<text x="140" y="70" dominant-baseline="central">Start</text>
|
|
16
|
+
<text x="420" y="70" dominant-baseline="central">End</text>
|
|
17
|
+
</g>
|
|
18
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg viewBox="0 0 300 100"><text font-size="8">Too small</text></svg>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 1760 640" role="img">
|
|
2
|
+
<title>Large canvas review flow</title>
|
|
3
|
+
<desc>A three-step flow across a large infographic canvas, from request to review to result.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerUnits="userSpaceOnUse" markerWidth="16" markerHeight="16" orient="auto">
|
|
6
|
+
<path d="M2 1L8 5L2 9" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
|
7
|
+
</marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<g fill="none" stroke="currentColor" stroke-width="2">
|
|
10
|
+
<rect x="80" y="240" width="440" height="120" rx="20"/>
|
|
11
|
+
<line x1="520" y1="300" x2="660" y2="300" fill="none" marker-end="url(#arrow)"/>
|
|
12
|
+
<rect x="660" y="240" width="440" height="120" rx="20"/>
|
|
13
|
+
<line x1="1100" y1="300" x2="1240" y2="300" fill="none" marker-end="url(#arrow)"/>
|
|
14
|
+
<rect x="1240" y="240" width="440" height="120" rx="20"/>
|
|
15
|
+
</g>
|
|
16
|
+
<g fill="currentColor" font-family="sans-serif" font-size="41" text-anchor="middle">
|
|
17
|
+
<text x="300" y="300" dominant-baseline="central">Request</text>
|
|
18
|
+
<text x="880" y="300" dominant-baseline="central">Review</text>
|
|
19
|
+
<text x="1460" y="300" dominant-baseline="central">Result</text>
|
|
20
|
+
</g>
|
|
21
|
+
</svg>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<svg width="100%" viewBox="0 0 680 140" role="img">
|
|
2
|
+
<title>Connector carrying a solid fill</title>
|
|
3
|
+
<desc>An arrow whose own fill is a solid colour rather than none.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerUnits="userSpaceOnUse" markerWidth="6" markerHeight="6" orient="auto">
|
|
6
|
+
<path d="M2 1L8 5L2 9" fill="none" stroke="currentColor" stroke-width="1.5"/>
|
|
7
|
+
</marker>
|
|
8
|
+
</defs>
|
|
9
|
+
<g stroke="currentColor" stroke-width="1">
|
|
10
|
+
<line x1="240" y1="70" x2="320" y2="70" fill="currentColor" marker-end="url(#arrow)"/>
|
|
11
|
+
</g>
|
|
12
|
+
<g fill="currentColor" font-family="sans-serif" font-size="16">
|
|
13
|
+
<text x="40" y="76">Label</text>
|
|
14
|
+
</g>
|
|
15
|
+
</svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<h2 class="sr-only">A valid visual.</h2><section aria-label="Visual"></section>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
ROOT = Path(__file__).parents[1]
|
|
6
|
+
SCRIPT = ROOT / "scripts" / "validate-artifact.py"
|
|
7
|
+
HEADER = (
|
|
8
|
+
'<svg width="100%" viewBox="0 0 680 120" role="img"><title>T</title><desc>D</desc>'
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def check(artifact: Path) -> subprocess.CompletedProcess[str]:
|
|
13
|
+
return subprocess.run(
|
|
14
|
+
[sys.executable, str(SCRIPT), str(artifact)], text=True, capture_output=True
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def write_svg(directory: Path, name: str, body: str) -> Path:
|
|
19
|
+
artifact = directory / name
|
|
20
|
+
artifact.write_text(body, encoding="utf-8")
|
|
21
|
+
return artifact
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_text_floor_reports_tiny_text_when_the_viewbox_is_unreadable(
|
|
25
|
+
tmp_path: Path,
|
|
26
|
+
) -> None:
|
|
27
|
+
artifact = write_svg(
|
|
28
|
+
tmp_path,
|
|
29
|
+
"no-viewbox.svg",
|
|
30
|
+
'<svg role="img"><title>T</title><desc>D</desc><text font-size="4">tiny</text></svg>',
|
|
31
|
+
)
|
|
32
|
+
finished = check(artifact)
|
|
33
|
+
assert "text below" in finished.stdout, finished.stdout + finished.stderr
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_commented_out_connector_is_not_reported(tmp_path: Path) -> None:
|
|
37
|
+
artifact = write_svg(
|
|
38
|
+
tmp_path,
|
|
39
|
+
"commented.svg",
|
|
40
|
+
f'{HEADER}\n<!-- <line fill="red" marker-end="url(#a)"/> -->\n</svg>',
|
|
41
|
+
)
|
|
42
|
+
finished = check(artifact)
|
|
43
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_live_connector_after_a_comment_is_still_reported(tmp_path: Path) -> None:
|
|
47
|
+
artifact = write_svg(
|
|
48
|
+
tmp_path,
|
|
49
|
+
"after-comment.svg",
|
|
50
|
+
f"{HEADER}\n<!-- an explanatory note -->\n"
|
|
51
|
+
'<defs><marker id="a" markerUnits="userSpaceOnUse"><path d="M2 1L8 5"/></marker></defs>\n'
|
|
52
|
+
'<line x1="10" y1="10" x2="90" y2="10" fill="red" marker-end="url(#a)"/>\n</svg>',
|
|
53
|
+
)
|
|
54
|
+
finished = check(artifact)
|
|
55
|
+
assert "connectors need fill=none" in finished.stdout, (
|
|
56
|
+
finished.stdout + finished.stderr
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_connector_error_names_the_offending_tag(tmp_path: Path) -> None:
|
|
61
|
+
artifact = write_svg(
|
|
62
|
+
tmp_path,
|
|
63
|
+
"named.svg",
|
|
64
|
+
f"{HEADER}\n"
|
|
65
|
+
'<defs><marker id="a" markerUnits="userSpaceOnUse"><path d="M2 1L8 5"/></marker></defs>\n'
|
|
66
|
+
'<line x1="10" y1="10" x2="90" y2="10" fill="red" marker-end="url(#a)"/>\n</svg>',
|
|
67
|
+
)
|
|
68
|
+
finished = check(artifact)
|
|
69
|
+
connector_error = [
|
|
70
|
+
line for line in finished.stdout.splitlines() if "fill=none" in line
|
|
71
|
+
]
|
|
72
|
+
assert connector_error and "line" in connector_error[0], (
|
|
73
|
+
finished.stdout + finished.stderr
|
|
74
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
ROOT = Path(__file__).parents[1]
|
|
6
|
+
|
|
7
|
+
def run(*args: str) -> subprocess.CompletedProcess[str]:
|
|
8
|
+
return subprocess.run([sys.executable, *args], cwd=ROOT, text=True, capture_output=True)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def test_package() -> None:
|
|
12
|
+
finished = run("scripts/validate-package.py")
|
|
13
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_template_svg() -> None:
|
|
17
|
+
finished = run("scripts/validate-artifact.py", "templates/svg-base.svg")
|
|
18
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_valid_html_passes() -> None:
|
|
22
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/valid.html")
|
|
23
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def test_invalid_fixture_fails() -> None:
|
|
27
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/invalid.svg")
|
|
28
|
+
assert finished.returncode != 0, finished.stdout + finished.stderr
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_css_variable_fixture_fails() -> None:
|
|
32
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/css-var.svg")
|
|
33
|
+
assert finished.returncode != 0, finished.stdout + finished.stderr
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_dead_reference_fixture_fails() -> None:
|
|
37
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/dead-ref.svg")
|
|
38
|
+
assert finished.returncode != 0, finished.stdout + finished.stderr
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_large_canvas_fixture_passes() -> None:
|
|
42
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/large-canvas.svg")
|
|
43
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_connector_inheriting_group_fill_passes() -> None:
|
|
47
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/inherited-fill.svg")
|
|
48
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_filled_glyph_without_markers_passes() -> None:
|
|
52
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/filled-glyph.svg")
|
|
53
|
+
assert finished.returncode == 0, finished.stdout + finished.stderr
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_connector_with_solid_fill_fails() -> None:
|
|
57
|
+
finished = run("scripts/validate-artifact.py", "tests/fixtures/unfilled-connector.svg")
|
|
58
|
+
assert finished.returncode != 0, finished.stdout + finished.stderr
|
|
59
|
+
assert "connectors need fill=none" in finished.stdout
|