mednotes-opencode 0.1.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/.opencode/agents/med-chat-triager.md +204 -0
- package/.opencode/agents/med-flashcard-maker.md +63 -0
- package/.opencode/agents/med-knowledge-architect.md +230 -0
- package/.opencode/agents/med-link-graph-curator.md +177 -0
- package/.opencode/agents/med-publish-guard.md +62 -0
- package/.opencode/commands/flashcards.md +25 -0
- package/.opencode/commands/mednotes/create.md +25 -0
- package/.opencode/commands/mednotes/enrich.md +27 -0
- package/.opencode/commands/mednotes/fix-wiki.md +27 -0
- package/.opencode/commands/mednotes/history.md +22 -0
- package/.opencode/commands/mednotes/link-body.md +25 -0
- package/.opencode/commands/mednotes/link-related.md +27 -0
- package/.opencode/commands/mednotes/link.md +27 -0
- package/.opencode/commands/mednotes/pdf-library.md +27 -0
- package/.opencode/commands/mednotes/process-chats.md +23 -0
- package/.opencode/commands/mednotes/setup.md +21 -0
- package/.opencode/commands/mednotes/status.md +27 -0
- package/.opencode/commands/mednotes/telemetry.md +27 -0
- package/.opencode/commands/report.md +26 -0
- package/.opencode/mednotes/AGENTS.md +57 -0
- package/.opencode/mednotes/agents/med-chat-triager.md +197 -0
- package/.opencode/mednotes/agents/med-flashcard-maker.md +56 -0
- package/.opencode/mednotes/agents/med-knowledge-architect.md +224 -0
- package/.opencode/mednotes/agents/med-link-graph-curator.md +171 -0
- package/.opencode/mednotes/agents/med-publish-guard.md +55 -0
- package/.opencode/mednotes/contracts/.gitkeep +1 -0
- package/.opencode/mednotes/contracts/agents.json +116 -0
- package/.opencode/mednotes/contracts/opencode-plugin.json +70 -0
- package/.opencode/mednotes/docs/agent-prompt-hardening.md +567 -0
- package/.opencode/mednotes/docs/agent-role-contracts.md +94 -0
- package/.opencode/mednotes/docs/anki-mcp-twenty-rules.md +214 -0
- package/.opencode/mednotes/docs/anki-templates/README.md +39 -0
- package/.opencode/mednotes/docs/anki-templates/cloze.back.html +23 -0
- package/.opencode/mednotes/docs/anki-templates/cloze.front.html +14 -0
- package/.opencode/mednotes/docs/anki-templates/qa.back.html +24 -0
- package/.opencode/mednotes/docs/anki-templates/qa.front.html +14 -0
- package/.opencode/mednotes/docs/anki-templates/style.css +182 -0
- package/.opencode/mednotes/docs/atomicity-splitting-policy.md +113 -0
- package/.opencode/mednotes/docs/extension-docs.md +40 -0
- package/.opencode/mednotes/docs/flashcard-ingestion.md +278 -0
- package/.opencode/mednotes/docs/knowledge-architect.md +208 -0
- package/.opencode/mednotes/docs/merge-policy.md +110 -0
- package/.opencode/mednotes/docs/public-vocabulary.md +104 -0
- package/.opencode/mednotes/docs/semantic-linker.md +141 -0
- package/.opencode/mednotes/docs/taxonomy-policy.md +90 -0
- package/.opencode/mednotes/docs/triage-policy.md +187 -0
- package/.opencode/mednotes/docs/vault-version-control.md +758 -0
- package/.opencode/mednotes/docs/vocabulary-db-recovery.md +58 -0
- package/.opencode/mednotes/docs/workflow-output-contract.md +779 -0
- package/.opencode/mednotes/hooks/hooks.json +79 -0
- package/.opencode/mednotes/package-lock.json +6361 -0
- package/.opencode/mednotes/package.json +15 -0
- package/.opencode/mednotes/pyproject.toml +48 -0
- package/.opencode/mednotes/scripts/bootstrap_windows_python_uv.cmd +13 -0
- package/.opencode/mednotes/scripts/bootstrap_windows_python_uv.ps1 +172 -0
- package/.opencode/mednotes/scripts/enrich_notes.py +23 -0
- package/.opencode/mednotes/scripts/full_reset_windows_python_uv.cmd +13 -0
- package/.opencode/mednotes/scripts/hooks/antigravity_hook_status.mjs +212 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/antigravity.mjs +169 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/harness_payload.mjs +103 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/opencode_plugin.mjs +341 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/adapters/opencode_user_config_sync.mjs +177 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/anki_preflight.mjs +214 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/cli.mjs +143 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/diagnostics.mjs +11 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/domain/agent_directive_core.mjs +160 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/fsm_directive.mjs +1470 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/hook_errors.mjs +120 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/retention.mjs +114 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/runtime.mjs +174 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/telemetry_capture.mjs +511 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook/vault_guard.mjs +624 -0
- package/.opencode/mednotes/scripts/hooks/mednotes_hook.mjs +5 -0
- package/.opencode/mednotes/scripts/mednotes/_runtime_paths.py +24 -0
- package/.opencode/mednotes/scripts/mednotes/anki_model_validator.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/capture_extension_diff.py +1562 -0
- package/.opencode/mednotes/scripts/mednotes/feedback_report.py +16 -0
- package/.opencode/mednotes/scripts/mednotes/flashcard_index.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/flashcard_pipeline.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/flashcard_report.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/flashcard_sources.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/obsidian/README.md +6 -0
- package/.opencode/mednotes/scripts/mednotes/obsidian_note_utils.py +20 -0
- package/.opencode/mednotes/scripts/mednotes/pdf_library/cli.py +16 -0
- package/.opencode/mednotes/scripts/mednotes/project_fsm.py +229 -0
- package/.opencode/mednotes/scripts/mednotes/setup_telemetry_email.py +404 -0
- package/.opencode/mednotes/scripts/mednotes/sync_anki_twenty_rules.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/sync_opencode_user_config.py +36 -0
- package/.opencode/mednotes/scripts/mednotes/wiki/cli.py +20 -0
- package/.opencode/mednotes/scripts/mednotes/wiki_graph.py +18 -0
- package/.opencode/mednotes/scripts/mednotes/wiki_tree.py +134 -0
- package/.opencode/mednotes/scripts/reset_windows_python_uv.ps1 +625 -0
- package/.opencode/mednotes/scripts/run_python.mjs +109 -0
- package/.opencode/mednotes/scripts/vault/vault_commit.ps1 +19 -0
- package/.opencode/mednotes/scripts/vault/vault_commit.sh +18 -0
- package/.opencode/mednotes/scripts/vault/vault_git.ps1 +19 -0
- package/.opencode/mednotes/scripts/vault/vault_git.py +3107 -0
- package/.opencode/mednotes/scripts/vault/vault_git.sh +18 -0
- package/.opencode/mednotes/scripts/vault/vault_precommit.ps1 +19 -0
- package/.opencode/mednotes/scripts/vault/vault_precommit.sh +18 -0
- package/.opencode/mednotes/skills/THIRD_PARTY_NOTICES.md +45 -0
- package/.opencode/mednotes/skills/create-medical-flashcards/SKILL.md +113 -0
- package/.opencode/mednotes/skills/create-medical-note/SKILL.md +90 -0
- package/.opencode/mednotes/skills/enrich-medical-note/SKILL.md +120 -0
- package/.opencode/mednotes/skills/fix-medical-wiki/SKILL.md +559 -0
- package/.opencode/mednotes/skills/link-medical-wiki/SKILL.md +224 -0
- package/.opencode/mednotes/skills/obsidian-cli/SKILL.md +118 -0
- package/.opencode/mednotes/skills/obsidian-markdown/SKILL.md +207 -0
- package/.opencode/mednotes/skills/obsidian-markdown/references/CALLOUTS.md +58 -0
- package/.opencode/mednotes/skills/obsidian-markdown/references/EMBEDS.md +63 -0
- package/.opencode/mednotes/skills/obsidian-markdown/references/PROPERTIES.md +61 -0
- package/.opencode/mednotes/skills/obsidian-ops/SKILL.md +136 -0
- package/.opencode/mednotes/skills/pdf-library/SKILL.md +45 -0
- package/.opencode/mednotes/skills/process-medical-chats/SKILL.md +246 -0
- package/.opencode/mednotes/skills/workflow-report/SKILL.md +100 -0
- package/.opencode/mednotes/src/mednotes/__init__.py +5 -0
- package/.opencode/mednotes/src/mednotes/domains/__init__.py +5 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/README.md +26 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/__init__.py +2 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/build_demo_apkg.py +177 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/contracts.py +385 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/flashcards_machine.py +522 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/fsm.py +817 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/index.py +630 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/install_models.py +445 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/model.py +359 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/obsidian_links.py +135 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/obsidian_note_utils.py +546 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/pipeline.py +580 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/report.py +510 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/sources.py +682 -0
- package/.opencode/mednotes/src/mednotes/domains/flashcards/sync_rules.py +184 -0
- package/.opencode/mednotes/src/mednotes/domains/history/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/history/history_fsm.py +852 -0
- package/.opencode/mednotes/src/mednotes/domains/history/history_machine.py +453 -0
- package/.opencode/mednotes/src/mednotes/domains/setup/__init__.py +7 -0
- package/.opencode/mednotes/src/mednotes/domains/setup/setup_fsm.py +808 -0
- package/.opencode/mednotes/src/mednotes/domains/setup/setup_machine.py +973 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/README.md +64 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/api.py +668 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/batch_state.py +102 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/atomicity/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/atomicity/atomicity.py +877 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/body_link/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/body_link/body_linker.py +1562 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/effect_adapters.py +949 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/effects/fix_wiki_runtime_adapters.py +433 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/coverage.py +413 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/graph.py +396 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/graph/graph_fixes.py +161 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/hygiene/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/hygiene/hygiene.py +483 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/__init__.py +2 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/anchors.py +185 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/__init__.py +0 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/cache.py +223 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/config.py +131 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/download.py +224 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/frontmatter.py +59 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/insert.py +227 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/core/local_import.py +54 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/__init__.py +42 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/web_profiles.py +99 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/web_search.py +203 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/illustrate/sources/wikimedia.py +102 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_db_adapter.mjs +434 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_node_runtime.py +274 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/markdown/markdown_query.py +227 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/artifacts.py +605 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/canonical_merge.py +277 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/markdown_zones.py +85 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/meaning_planner.py +307 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_iter.py +67 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_merge.py +278 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_plan.py +409 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_policy.py +22 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/__init__.py +79 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/fixes.py +264 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/frontmatter.py +435 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/models.py +208 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/prompts.py +37 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/tables.py +236 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/note_style/validate.py +404 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/provenance.py +478 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/raw_chats.py +273 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/notes/sources_backfill.py +235 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/__init__.py +10 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/anchors.py +16 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/captions.py +47 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/cli.py +179 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/cloud.py +52 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/config.py +196 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/context_packets.py +76 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/db.py +81 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/doctor.py +102 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/figure_ids.py +42 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/ingest.py +326 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/insert.py +316 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/mentions.py +57 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/ocr.py +71 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/paths.py +35 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/pdf_engine.py +77 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/schema.py +155 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/search.py +188 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/app.py +89 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/image_backend.py +29 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/pdf/tui/state.py +65 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish.py +1139 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish_receipts.py +365 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/publish/publish_recovery.py +240 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_behavior_corpus.py +2069 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_report_validation.py +4448 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/agent_run_audit.py +852 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/architect_prompt_eval.py +341 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/body_linker_eval.py +240 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/curator_output_validation.py +175 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/curator_prompt_eval.py +865 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/quality/triager_prompt_eval.py +1295 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/related_notes.py +1920 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/related_notes/related_notes_headless.py +1186 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/plan_attestation.py +148 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_receipts.py +360 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_runtime.py +52 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/specialist/specialist_task_runner.py +2470 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/style/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/style/style.py +1952 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/subagents/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/subagents/agents.py +1767 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/alias_projection.py +331 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/link_terms.py +151 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/llm_disambiguation.py +182 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/__init__.py +116 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/audit.py +201 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/migration.py +314 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/normalize.py +72 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/policy.py +135 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/resolve.py +413 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/schema.py +157 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/taxonomy/status.py +137 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_bootstrap.py +509 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_curator_batch.py +1115 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_ingestion.py +632 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_map.py +930 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/capabilities/vocabulary/vocabulary_recovery.py +1388 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/cli.py +6665 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/common.py +69 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/config.py +210 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/__init__.py +74 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agent_report.py +242 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agent_run_audit.py +196 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/agents.py +601 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/curator.py +256 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/effect_payloads.py +519 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/happy_path.py +190 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/link_git.py +110 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/link_runtime_artifact.py +52 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/note_plan.py +75 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/paths.py +114 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/public_report.py +53 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/publish.py +111 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/raw_coverage.py +217 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes.py +136 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes_headless.py +153 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/related_notes_runtime.py +395 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/schema_registry.py +637 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/specialist.py +432 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/status.py +62 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/style_rewrite.py +568 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/vocabulary_ingestion.py +223 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_blockers.py +510 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_guardrails.py +637 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_outcomes.py +121 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/contracts/workflow_receipts.py +100 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/__main__.py +4 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/cli.py +275 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/__init__.py +2 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/candidates.py +193 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/cli.py +189 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/gemini.py +220 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/inputs.py +120 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/models.py +34 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/parsing.py +48 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/prompts.py +216 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/quality.py +54 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/reporting.py +24 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/runner.py +433 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/utils.py +39 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/enrich/workflow/vault_guard_bridge.py +17 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_context_packets.py +454 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_decision_projection.py +133 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_effects.py +1260 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_fsm.py +2768 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_machine.py +1588 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_plan.py +306 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_primary_objective.py +316 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_problem.py +153 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_receipt_evidence.py +306 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_states.py +290 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/fix_wiki_user_report.py +342 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/fix_wiki/health.py +6332 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_fsm.py +1119 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_git.py +638 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_machine.py +1106 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_retry_governance.py +374 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_runtime_result.py +485 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/link_triggers.py +183 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/linking.py +2758 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/reference_repair.py +718 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link/related_notes_fsm.py +1855 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link_related/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/link_related/link_related_machine.py +834 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/__init__.py +1 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_fsm.py +1592 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_machine.py +3097 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_primary_objective.py +28 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/flows/process_chats/process_chats_runtime_result.py +185 -0
- package/.opencode/mednotes/src/mednotes/domains/wiki/performance.py +97 -0
- package/.opencode/mednotes/src/mednotes/kernel/__init__.py +6 -0
- package/.opencode/mednotes/src/mednotes/kernel/agent_directive.py +336 -0
- package/.opencode/mednotes/src/mednotes/kernel/base.py +51 -0
- package/.opencode/mednotes/src/mednotes/kernel/blockers.py +39 -0
- package/.opencode/mednotes/src/mednotes/kernel/effect_executor.py +55 -0
- package/.opencode/mednotes/src/mednotes/kernel/effect_intent.py +69 -0
- package/.opencode/mednotes/src/mednotes/kernel/effects.py +160 -0
- package/.opencode/mednotes/src/mednotes/kernel/errors.py +38 -0
- package/.opencode/mednotes/src/mednotes/kernel/fsm_event.py +35 -0
- package/.opencode/mednotes/src/mednotes/kernel/fsm_model.py +55 -0
- package/.opencode/mednotes/src/mednotes/kernel/fsm_transition_result.py +75 -0
- package/.opencode/mednotes/src/mednotes/kernel/guardrails.py +188 -0
- package/.opencode/mednotes/src/mednotes/kernel/progress.py +319 -0
- package/.opencode/mednotes/src/mednotes/kernel/public_report.py +346 -0
- package/.opencode/mednotes/src/mednotes/kernel/state_machine.py +164 -0
- package/.opencode/mednotes/src/mednotes/kernel/workflow.py +619 -0
- package/.opencode/mednotes/src/mednotes/platform/__init__.py +5 -0
- package/.opencode/mednotes/src/mednotes/platform/backup_policy.py +382 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/__init__.py +62 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/cli.py +275 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/contracts.py +83 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/core.py +4168 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/integrity.py +989 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/operational_contract.py +2293 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/telemetry.py +875 -0
- package/.opencode/mednotes/src/mednotes/platform/feedback/telemetry_config.py +65 -0
- package/.opencode/mednotes/src/mednotes/platform/opencode_runtime_config.py +182 -0
- package/.opencode/mednotes/src/mednotes/platform/paths/__init__.py +1560 -0
- package/.opencode/mednotes/src/mednotes/platform/secrets.py +89 -0
- package/.opencode/mednotes/src/mednotes/platform/user_config.py +103 -0
- package/.opencode/mednotes/src/mednotes/platform/vault_guard.py +214 -0
- package/.opencode/mednotes/uv.lock +932 -0
- package/.opencode/mednotes.generated.json +395 -0
- package/.opencode/opencode.json +31 -0
- package/.opencode/plugins/mednotes-fsm.mjs +7 -0
- package/.opencode/plugins/mednotes_hook/adapters/antigravity.mjs +169 -0
- package/.opencode/plugins/mednotes_hook/adapters/harness_payload.mjs +103 -0
- package/.opencode/plugins/mednotes_hook/adapters/opencode_plugin.mjs +341 -0
- package/.opencode/plugins/mednotes_hook/adapters/opencode_user_config_sync.mjs +177 -0
- package/.opencode/plugins/mednotes_hook/anki_preflight.mjs +214 -0
- package/.opencode/plugins/mednotes_hook/cli.mjs +143 -0
- package/.opencode/plugins/mednotes_hook/diagnostics.mjs +11 -0
- package/.opencode/plugins/mednotes_hook/domain/agent_directive_core.mjs +160 -0
- package/.opencode/plugins/mednotes_hook/fsm_directive.mjs +1470 -0
- package/.opencode/plugins/mednotes_hook/hook_errors.mjs +120 -0
- package/.opencode/plugins/mednotes_hook/retention.mjs +114 -0
- package/.opencode/plugins/mednotes_hook/runtime.mjs +174 -0
- package/.opencode/plugins/mednotes_hook/telemetry_capture.mjs +511 -0
- package/.opencode/plugins/mednotes_hook/vault_guard.mjs +624 -0
- package/AGENTS.md +57 -0
- package/README.md +194 -0
- package/adapters/antigravity/agents.json +80 -0
- package/adapters/antigravity/templates/med-chat-triager.md +214 -0
- package/adapters/antigravity/templates/med-flashcard-maker.md +72 -0
- package/adapters/antigravity/templates/med-knowledge-architect.md +241 -0
- package/adapters/antigravity/templates/med-link-graph-curator.md +187 -0
- package/adapters/antigravity/templates/med-publish-guard.md +71 -0
- package/adapters/gemini-cli/gemini-extension.json +14 -0
- package/adapters/gemini-cli/package.json +15 -0
- package/adapters/gemini-cli/pyproject.toml +48 -0
- package/bin/mednotes-opencode.mjs +155 -0
- package/contracts/agents.json +116 -0
- package/core/agents/med-chat-triager.md +197 -0
- package/core/agents/med-flashcard-maker.md +56 -0
- package/core/agents/med-knowledge-architect.md +224 -0
- package/core/agents/med-link-graph-curator.md +171 -0
- package/core/agents/med-publish-guard.md +55 -0
- package/core/commands/flashcards.toml +22 -0
- package/core/commands/mednotes/create.toml +22 -0
- package/core/commands/mednotes/enrich.toml +24 -0
- package/core/commands/mednotes/fix-wiki.toml +24 -0
- package/core/commands/mednotes/history.toml +19 -0
- package/core/commands/mednotes/link-body.toml +22 -0
- package/core/commands/mednotes/link-related.toml +24 -0
- package/core/commands/mednotes/link.toml +24 -0
- package/core/commands/mednotes/pdf-library.toml +24 -0
- package/core/commands/mednotes/process-chats.toml +20 -0
- package/core/commands/mednotes/setup.toml +18 -0
- package/core/commands/mednotes/status.toml +24 -0
- package/core/commands/mednotes/telemetry.toml +24 -0
- package/core/commands/report.toml +23 -0
- package/core/skills/THIRD_PARTY_NOTICES.md +45 -0
- package/core/skills/create-medical-flashcards/SKILL.md +113 -0
- package/core/skills/create-medical-note/SKILL.md +90 -0
- package/core/skills/enrich-medical-note/SKILL.md +120 -0
- package/core/skills/fix-medical-wiki/SKILL.md +559 -0
- package/core/skills/link-medical-wiki/SKILL.md +224 -0
- package/core/skills/obsidian-cli/SKILL.md +118 -0
- package/core/skills/obsidian-markdown/SKILL.md +207 -0
- package/core/skills/obsidian-markdown/references/CALLOUTS.md +58 -0
- package/core/skills/obsidian-markdown/references/EMBEDS.md +63 -0
- package/core/skills/obsidian-markdown/references/PROPERTIES.md +61 -0
- package/core/skills/obsidian-ops/SKILL.md +136 -0
- package/core/skills/pdf-library/SKILL.md +45 -0
- package/core/skills/process-medical-chats/SKILL.md +246 -0
- package/core/skills/workflow-report/SKILL.md +100 -0
- package/package.json +45 -0
|
@@ -0,0 +1,1588 @@
|
|
|
1
|
+
"""Flat StateChart for `/mednotes:fix-wiki`.
|
|
2
|
+
|
|
3
|
+
The first fix-wiki StateChart is intentionally flat: every operational lane is a
|
|
4
|
+
leaf state, and `category_for_state()` derives the public category. That keeps
|
|
5
|
+
diagnosis, blockers, agent handoff, link routing and final validation observable
|
|
6
|
+
without introducing generic container states as a second source of truth.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Annotated, Literal
|
|
12
|
+
|
|
13
|
+
from pydantic import Field, TypeAdapter, field_validator, model_validator
|
|
14
|
+
from statemachine import StateChart
|
|
15
|
+
from statemachine.states import States
|
|
16
|
+
|
|
17
|
+
from mednotes.domains.wiki.contracts.effect_payloads import (
|
|
18
|
+
LinkWorkflowRunEffectPayload,
|
|
19
|
+
RelatedNotesExportEffectPayload,
|
|
20
|
+
RelatedNotesRecoveryStateEffectPayload,
|
|
21
|
+
WaitExternalEffectPayload,
|
|
22
|
+
)
|
|
23
|
+
from mednotes.domains.wiki.contracts.workflow_outcomes import (
|
|
24
|
+
DecisionEvidence,
|
|
25
|
+
HumanDecisionOption,
|
|
26
|
+
RejectedAutomation,
|
|
27
|
+
WorkflowDecision,
|
|
28
|
+
)
|
|
29
|
+
from mednotes.domains.wiki.flows.fix_wiki.fix_wiki_states import (
|
|
30
|
+
FIX_WIKI_DIAGNOSIS_PRIORITY,
|
|
31
|
+
FIX_WIKI_WORKFLOW,
|
|
32
|
+
FixWikiDiagnosisLane,
|
|
33
|
+
FixWikiState,
|
|
34
|
+
reason_for_state,
|
|
35
|
+
)
|
|
36
|
+
from mednotes.domains.wiki.flows.fix_wiki.fix_wiki_states import (
|
|
37
|
+
category_for_state as fix_wiki_category_for_state,
|
|
38
|
+
)
|
|
39
|
+
from mednotes.kernel.base import ContractModel, JsonObject
|
|
40
|
+
from mednotes.kernel.effects import WorkflowEffect, WorkflowEffectKind
|
|
41
|
+
from mednotes.kernel.fsm_model import WorkflowModel
|
|
42
|
+
from mednotes.kernel.fsm_transition_result import WorkflowTransitionResult
|
|
43
|
+
from mednotes.kernel.state_machine import WorkflowStateCategory
|
|
44
|
+
from mednotes.kernel.workflow import HumanDecisionPacket
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class FixWikiEvent(ContractModel):
|
|
48
|
+
"""Base event for fix-wiki facts accepted by the StateChart."""
|
|
49
|
+
|
|
50
|
+
workflow: str = FIX_WIKI_WORKFLOW
|
|
51
|
+
run_id: str = Field(min_length=1)
|
|
52
|
+
current_state: str = Field(min_length=1)
|
|
53
|
+
audit_evidence: JsonObject = Field(default_factory=dict)
|
|
54
|
+
|
|
55
|
+
@field_validator("workflow")
|
|
56
|
+
@classmethod
|
|
57
|
+
def _workflow_must_be_fix_wiki(cls, value: str) -> str:
|
|
58
|
+
if value != FIX_WIKI_WORKFLOW:
|
|
59
|
+
raise ValueError(f"fix-wiki event workflow must be {FIX_WIKI_WORKFLOW}")
|
|
60
|
+
return value
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _event_name(event: FixWikiEvent) -> str:
|
|
64
|
+
"""Return the concrete Literal discriminator declared by each event class."""
|
|
65
|
+
|
|
66
|
+
name = getattr(event, "name", "")
|
|
67
|
+
if not isinstance(name, str) or not name.strip():
|
|
68
|
+
raise ValueError("fix-wiki events must declare a name discriminator")
|
|
69
|
+
return name
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class DiagnosisQueueEvent(FixWikiEvent):
|
|
73
|
+
"""Canonical diagnosis queue; concrete events supply the trigger name."""
|
|
74
|
+
|
|
75
|
+
pending_lanes: list[FixWikiDiagnosisLane] = Field(min_length=1)
|
|
76
|
+
selected_lane: FixWikiDiagnosisLane
|
|
77
|
+
style_rewrite_effect: WorkflowEffect | None = None
|
|
78
|
+
|
|
79
|
+
@field_validator("pending_lanes")
|
|
80
|
+
@classmethod
|
|
81
|
+
def _reject_duplicate_lanes(cls, value: list[FixWikiDiagnosisLane]) -> list[FixWikiDiagnosisLane]:
|
|
82
|
+
if len(set(value)) != len(value):
|
|
83
|
+
raise ValueError("duplicate diagnosis lanes are not allowed")
|
|
84
|
+
expected_order = sorted(value, key=FIX_WIKI_DIAGNOSIS_PRIORITY.index)
|
|
85
|
+
if list(value) != expected_order:
|
|
86
|
+
raise ValueError("diagnosis lanes must follow FIX_WIKI_DIAGNOSIS_PRIORITY")
|
|
87
|
+
return value
|
|
88
|
+
|
|
89
|
+
@model_validator(mode="after")
|
|
90
|
+
def _selected_lane_must_be_priority_head(self) -> DiagnosisQueueEvent:
|
|
91
|
+
if self.selected_lane not in self.pending_lanes:
|
|
92
|
+
raise ValueError("selected_lane must be present in pending_lanes")
|
|
93
|
+
expected = self.pending_lanes[0]
|
|
94
|
+
if self.selected_lane != expected:
|
|
95
|
+
raise ValueError("selected_lane must match the highest-priority pending lane")
|
|
96
|
+
if self.style_rewrite_effect is not None:
|
|
97
|
+
if self.selected_lane != FixWikiDiagnosisLane.STYLE_REWRITE:
|
|
98
|
+
raise ValueError("style_rewrite_effect is only valid for the style rewrite lane")
|
|
99
|
+
if self.style_rewrite_effect.kind != WorkflowEffectKind.CALL_SPECIALIST_MODEL:
|
|
100
|
+
raise ValueError("style_rewrite_effect must be a specialist model effect")
|
|
101
|
+
if self.style_rewrite_effect.origin_state != FixWikiState.STYLE_REWRITE_SPECIALIST_REQUESTED.value:
|
|
102
|
+
raise ValueError("style_rewrite_effect origin_state must match style_rewrite.specialist_requested")
|
|
103
|
+
return self
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class DiagnosisProducedEvent(DiagnosisQueueEvent):
|
|
107
|
+
"""Typed diagnosis fan-out; guards must inspect only `selected_lane`."""
|
|
108
|
+
|
|
109
|
+
name: Literal["diagnosis_produced"] = "diagnosis_produced"
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class FixWikiRuntimeObservation(ContractModel):
|
|
113
|
+
"""Runtime facts normalized at the boundary; StateChart guards choose state."""
|
|
114
|
+
|
|
115
|
+
failed: bool = False
|
|
116
|
+
failed_reason_code: str = ""
|
|
117
|
+
vault_guard_required: bool = False
|
|
118
|
+
environment_windows_path_or_venv_blocked: bool = False
|
|
119
|
+
next_action: str = ""
|
|
120
|
+
human_decision_required: bool = False
|
|
121
|
+
external_wait_reason_code: str = ""
|
|
122
|
+
related_notes_waiting_external: bool = False
|
|
123
|
+
vocabulary_semantic_ingestion_pending: bool = False
|
|
124
|
+
vocabulary_eval_needs_review: bool = False
|
|
125
|
+
atomicity_split_required: bool = False
|
|
126
|
+
merge_review_required: bool = False
|
|
127
|
+
graph_review_required: bool = False
|
|
128
|
+
graph_blocker_count: int = Field(default=0, ge=0)
|
|
129
|
+
graph_error_count: int = Field(default=0, ge=0)
|
|
130
|
+
related_notes_blocked: bool = False
|
|
131
|
+
linker_blocked: bool = False
|
|
132
|
+
taxonomy_action_required: bool = False
|
|
133
|
+
specialist_model_waiting_agent: bool = False
|
|
134
|
+
requires_llm_rewrite_count: int = Field(default=0, ge=0)
|
|
135
|
+
effective_apply: bool = False
|
|
136
|
+
warning_count: int = Field(default=0, ge=0)
|
|
137
|
+
style_rewrite_effect: WorkflowEffect | None = None
|
|
138
|
+
link_subworkflow_required: bool = False
|
|
139
|
+
link_effect: WorkflowEffect | None = None
|
|
140
|
+
related_notes_recovery_state: RelatedNotesRecoveryStateEffectPayload = Field(
|
|
141
|
+
default_factory=RelatedNotesRecoveryStateEffectPayload
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
@model_validator(mode="after")
|
|
145
|
+
def _style_effect_matches_observed_lane(self) -> FixWikiRuntimeObservation:
|
|
146
|
+
if self.style_rewrite_effect is not None:
|
|
147
|
+
if not self.specialist_model_waiting_agent:
|
|
148
|
+
raise ValueError("style_rewrite_effect requires specialist_model_waiting_agent")
|
|
149
|
+
if self.style_rewrite_effect.kind != WorkflowEffectKind.CALL_SPECIALIST_MODEL:
|
|
150
|
+
raise ValueError("style_rewrite_effect must be a specialist model effect")
|
|
151
|
+
if self.style_rewrite_effect.origin_state != FixWikiState.STYLE_REWRITE_SPECIALIST_REQUESTED.value:
|
|
152
|
+
raise ValueError("style_rewrite_effect origin_state must match style_rewrite.specialist_requested")
|
|
153
|
+
if self.link_effect is not None and not self.link_subworkflow_required:
|
|
154
|
+
raise ValueError("link_effect requires link_subworkflow_required")
|
|
155
|
+
if self.link_subworkflow_required and self.link_effect is None:
|
|
156
|
+
raise ValueError("link_subworkflow_required requires link_effect")
|
|
157
|
+
if self.link_effect is not None:
|
|
158
|
+
if self.link_effect.kind != WorkflowEffectKind.RUN_SUBWORKFLOW:
|
|
159
|
+
raise ValueError("link_effect must be a run_subworkflow effect")
|
|
160
|
+
if self.link_effect.target != "/mednotes:link":
|
|
161
|
+
raise ValueError("link_effect target must be /mednotes:link")
|
|
162
|
+
if self.link_effect.origin_state != FixWikiState.LINK_RUN_REQUESTED.value:
|
|
163
|
+
raise ValueError("link_effect origin_state must match link.run_requested")
|
|
164
|
+
return self
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class RuntimeObservedEvent(FixWikiEvent):
|
|
168
|
+
"""Single adapter event; StateChart guards own priority and leaf selection."""
|
|
169
|
+
|
|
170
|
+
name: Literal["runtime_observed"] = "runtime_observed"
|
|
171
|
+
observation: FixWikiRuntimeObservation
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class DiagnosisCleanEvent(FixWikiEvent):
|
|
175
|
+
"""Clean diagnosis path; no pending lane is fabricated for final validation."""
|
|
176
|
+
name: Literal["diagnosis_clean"] = "diagnosis_clean"
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
class BlockerRetryRequestedEvent(FixWikiEvent):
|
|
180
|
+
"""Recoverable blocker retry; the next step is a fresh diagnosis."""
|
|
181
|
+
name: Literal["blocker_retry_requested"] = "blocker_retry_requested"
|
|
182
|
+
reason_code: str = "retry_requested"
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class SetupBootstrapReadyEvent(FixWikiEvent):
|
|
186
|
+
name: Literal["setup_bootstrap_ready"] = "setup_bootstrap_ready"
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
class SetupBootstrapBlockedEvent(FixWikiEvent):
|
|
190
|
+
name: Literal["setup_bootstrap_blocked"] = "setup_bootstrap_blocked"
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
class VaultGuardReadyEvent(FixWikiEvent):
|
|
194
|
+
name: Literal["vault_guard_ready"] = "vault_guard_ready"
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class VaultGuardDecisionApprovedEvent(FixWikiEvent):
|
|
198
|
+
name: Literal["vault_guard_decision_approved"] = "vault_guard_decision_approved"
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
class VaultGuardBlockedEvent(FixWikiEvent):
|
|
202
|
+
name: Literal["vault_guard_blocked"] = "vault_guard_blocked"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class DeterministicRepairsAppliedEvent(FixWikiEvent):
|
|
206
|
+
name: Literal["deterministic_repairs_applied"] = "deterministic_repairs_applied"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class DeterministicRepairsBlockedEvent(FixWikiEvent):
|
|
210
|
+
name: Literal["deterministic_repairs_blocked"] = "deterministic_repairs_blocked"
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class StyleRewriteSpecialistCompletedEvent(FixWikiEvent):
|
|
214
|
+
name: Literal["style_rewrite_specialist_completed"] = "style_rewrite_specialist_completed"
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class StyleRewriteCapacityWaitEvent(FixWikiEvent):
|
|
218
|
+
name: Literal["style_rewrite_capacity_wait"] = "style_rewrite_capacity_wait"
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class StyleRewriteReviewRequiredEvent(FixWikiEvent):
|
|
222
|
+
name: Literal["style_rewrite_review_required"] = "style_rewrite_review_required"
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
class StyleRewriteReviewApprovedEvent(FixWikiEvent):
|
|
226
|
+
name: Literal["style_rewrite_review_approved"] = "style_rewrite_review_approved"
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
class StyleRewriteAppliedEvent(FixWikiEvent):
|
|
230
|
+
name: Literal["style_rewrite_applied"] = "style_rewrite_applied"
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class StyleRewriteBlockedEvent(FixWikiEvent):
|
|
234
|
+
name: Literal["style_rewrite_blocked"] = "style_rewrite_blocked"
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class TaxonomyDecisionRequiredEvent(FixWikiEvent):
|
|
238
|
+
name: Literal["taxonomy_decision_required"] = "taxonomy_decision_required"
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class TaxonomyDecisionApprovedEvent(FixWikiEvent):
|
|
242
|
+
name: Literal["taxonomy_decision_approved"] = "taxonomy_decision_approved"
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
class TaxonomyAppliedEvent(FixWikiEvent):
|
|
246
|
+
name: Literal["taxonomy_applied"] = "taxonomy_applied"
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
class TaxonomyBlockedEvent(FixWikiEvent):
|
|
250
|
+
name: Literal["taxonomy_blocked"] = "taxonomy_blocked"
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class VocabularyCuratorCompletedEvent(FixWikiEvent):
|
|
254
|
+
name: Literal["vocabulary_curator_completed"] = "vocabulary_curator_completed"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class VocabularyEvalNeedsReviewEvent(FixWikiEvent):
|
|
258
|
+
name: Literal["vocabulary_eval_needs_review"] = "vocabulary_eval_needs_review"
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class VocabularyEvalPassedEvent(FixWikiEvent):
|
|
262
|
+
name: Literal["vocabulary_eval_passed"] = "vocabulary_eval_passed"
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class VocabularyAppliedEvent(FixWikiEvent):
|
|
266
|
+
name: Literal["vocabulary_applied"] = "vocabulary_applied"
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
class VocabularyIntegrityFailedEvent(FixWikiEvent):
|
|
270
|
+
name: Literal["vocabulary_integrity_failed"] = "vocabulary_integrity_failed"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class AtomicitySplitAppliedEvent(FixWikiEvent):
|
|
274
|
+
name: Literal["atomicity_split_applied"] = "atomicity_split_applied"
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
class AtomicitySplitBlockedEvent(FixWikiEvent):
|
|
278
|
+
name: Literal["atomicity_split_blocked"] = "atomicity_split_blocked"
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
class MergeAppliedEvent(FixWikiEvent):
|
|
282
|
+
name: Literal["merge_applied"] = "merge_applied"
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class MergeBlockedEvent(FixWikiEvent):
|
|
286
|
+
name: Literal["merge_blocked"] = "merge_blocked"
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class RelatedNotesExportCompletedEvent(FixWikiEvent):
|
|
290
|
+
name: Literal["related_notes_export_completed"] = "related_notes_export_completed"
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class RelatedNotesQuotaWaitEvent(FixWikiEvent):
|
|
294
|
+
name: Literal["related_notes_quota_wait"] = "related_notes_quota_wait"
|
|
295
|
+
related_notes_recovery_state: RelatedNotesRecoveryStateEffectPayload = Field(
|
|
296
|
+
default_factory=RelatedNotesRecoveryStateEffectPayload
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
@field_validator("related_notes_recovery_state", mode="before")
|
|
300
|
+
@classmethod
|
|
301
|
+
def _coerce_related_notes_recovery_state(cls, value: object) -> RelatedNotesRecoveryStateEffectPayload:
|
|
302
|
+
return RelatedNotesRecoveryStateEffectPayload.from_payload(value)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class RelatedNotesObsidianNotReadyEvent(FixWikiEvent):
|
|
306
|
+
name: Literal["related_notes_obsidian_not_ready"] = "related_notes_obsidian_not_ready"
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class RelatedNotesBlockedEvent(FixWikiEvent):
|
|
310
|
+
name: Literal["related_notes_blocked"] = "related_notes_blocked"
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class LinkCompletedEvent(FixWikiEvent):
|
|
314
|
+
name: Literal["link_completed"] = "link_completed"
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
class LinkGraphBlockedEvent(FixWikiEvent):
|
|
318
|
+
name: Literal["link_graph_blocked"] = "link_graph_blocked"
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class LinkerBlockedEvent(FixWikiEvent):
|
|
322
|
+
name: Literal["linker_blocked"] = "linker_blocked"
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
class FinalValidationPassedEvent(FixWikiEvent):
|
|
326
|
+
name: Literal["final_validation_passed"] = "final_validation_passed"
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
class PreviewReadyEvent(FixWikiEvent):
|
|
330
|
+
name: Literal["preview_ready"] = "preview_ready"
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class FinalValidationWarningsEvent(FixWikiEvent):
|
|
334
|
+
name: Literal["final_validation_warnings"] = "final_validation_warnings"
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
class FinalValidationFoundMoreWorkEvent(DiagnosisQueueEvent):
|
|
338
|
+
name: Literal["final_validation_found_more_work"] = "final_validation_found_more_work"
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
class FinalValidationFailedEvent(FixWikiEvent):
|
|
342
|
+
name: Literal["final_validation_failed"] = "final_validation_failed"
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
class RollbackCompletedEvent(FixWikiEvent):
|
|
346
|
+
name: Literal["rollback_completed"] = "rollback_completed"
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
class RollbackFailedEvent(FixWikiEvent):
|
|
350
|
+
name: Literal["rollback_failed"] = "rollback_failed"
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
FixWikiBoundaryEvent = Annotated[
|
|
354
|
+
DiagnosisProducedEvent
|
|
355
|
+
| RuntimeObservedEvent
|
|
356
|
+
| DiagnosisCleanEvent
|
|
357
|
+
| BlockerRetryRequestedEvent
|
|
358
|
+
| SetupBootstrapReadyEvent
|
|
359
|
+
| SetupBootstrapBlockedEvent
|
|
360
|
+
| VaultGuardReadyEvent
|
|
361
|
+
| VaultGuardDecisionApprovedEvent
|
|
362
|
+
| VaultGuardBlockedEvent
|
|
363
|
+
| DeterministicRepairsAppliedEvent
|
|
364
|
+
| DeterministicRepairsBlockedEvent
|
|
365
|
+
| StyleRewriteSpecialistCompletedEvent
|
|
366
|
+
| StyleRewriteCapacityWaitEvent
|
|
367
|
+
| StyleRewriteReviewRequiredEvent
|
|
368
|
+
| StyleRewriteReviewApprovedEvent
|
|
369
|
+
| StyleRewriteAppliedEvent
|
|
370
|
+
| StyleRewriteBlockedEvent
|
|
371
|
+
| TaxonomyDecisionRequiredEvent
|
|
372
|
+
| TaxonomyDecisionApprovedEvent
|
|
373
|
+
| TaxonomyAppliedEvent
|
|
374
|
+
| TaxonomyBlockedEvent
|
|
375
|
+
| VocabularyCuratorCompletedEvent
|
|
376
|
+
| VocabularyEvalNeedsReviewEvent
|
|
377
|
+
| VocabularyEvalPassedEvent
|
|
378
|
+
| VocabularyAppliedEvent
|
|
379
|
+
| VocabularyIntegrityFailedEvent
|
|
380
|
+
| AtomicitySplitAppliedEvent
|
|
381
|
+
| AtomicitySplitBlockedEvent
|
|
382
|
+
| MergeAppliedEvent
|
|
383
|
+
| MergeBlockedEvent
|
|
384
|
+
| RelatedNotesExportCompletedEvent
|
|
385
|
+
| RelatedNotesQuotaWaitEvent
|
|
386
|
+
| RelatedNotesObsidianNotReadyEvent
|
|
387
|
+
| RelatedNotesBlockedEvent
|
|
388
|
+
| LinkCompletedEvent
|
|
389
|
+
| LinkGraphBlockedEvent
|
|
390
|
+
| LinkerBlockedEvent
|
|
391
|
+
| FinalValidationPassedEvent
|
|
392
|
+
| PreviewReadyEvent
|
|
393
|
+
| FinalValidationWarningsEvent
|
|
394
|
+
| FinalValidationFoundMoreWorkEvent
|
|
395
|
+
| FinalValidationFailedEvent
|
|
396
|
+
| RollbackCompletedEvent
|
|
397
|
+
| RollbackFailedEvent,
|
|
398
|
+
Field(discriminator="name"),
|
|
399
|
+
]
|
|
400
|
+
FixWikiBoundaryEventAdapter = TypeAdapter(FixWikiBoundaryEvent)
|
|
401
|
+
|
|
402
|
+
FIX_WIKI_BOUNDARY_EVENT_NAMES = frozenset(
|
|
403
|
+
FixWikiBoundaryEventAdapter.json_schema()["discriminator"]["mapping"]
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class FixWikiMachine(StateChart[WorkflowModel]):
|
|
408
|
+
"""Pure domain StateChart; callbacks only return typed transition results."""
|
|
409
|
+
|
|
410
|
+
allow_event_without_transition = False
|
|
411
|
+
catch_errors_as_events = False
|
|
412
|
+
states = States.from_enum(
|
|
413
|
+
FixWikiState,
|
|
414
|
+
initial=FixWikiState.DIAGNOSIS_RUNNING,
|
|
415
|
+
final={
|
|
416
|
+
FixWikiState.AGENT_TOOL_CONTRACT_VIOLATION,
|
|
417
|
+
FixWikiState.CONTRACT_GAP_MISSING_NEXT_ACTION,
|
|
418
|
+
FixWikiState.CONTRACT_GAP_MISSING_ERROR_CONTEXT,
|
|
419
|
+
FixWikiState.DETERMINISTIC_REPAIRS_FAILED,
|
|
420
|
+
FixWikiState.VOCABULARY_SQLITE_INTEGRITY_FAILED,
|
|
421
|
+
FixWikiState.ROLLBACK_PERFORMED,
|
|
422
|
+
FixWikiState.FINAL_VALIDATION_FAILED,
|
|
423
|
+
FixWikiState.FAILED,
|
|
424
|
+
FixWikiState.PREVIEW_READY,
|
|
425
|
+
FixWikiState.COMPLETED,
|
|
426
|
+
FixWikiState.COMPLETED_WITH_WARNINGS,
|
|
427
|
+
},
|
|
428
|
+
use_enum_instance=False,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
diagnosis_clean = states.DIAGNOSIS_RUNNING.to(
|
|
432
|
+
states.FINAL_VALIDATION_RUNNING,
|
|
433
|
+
on="_on_enter_final_validation",
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
diagnosis_produced = (
|
|
437
|
+
states.DIAGNOSIS_RUNNING.to(
|
|
438
|
+
states.ENVIRONMENT_PATHS_MISSING,
|
|
439
|
+
cond="_selected_environment_paths_missing",
|
|
440
|
+
on="_on_diagnosis_produced",
|
|
441
|
+
)
|
|
442
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
443
|
+
states.ENVIRONMENT_WIKI_DIR_MISSING,
|
|
444
|
+
cond="_selected_environment_wiki_dir_missing",
|
|
445
|
+
on="_on_diagnosis_produced",
|
|
446
|
+
)
|
|
447
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
448
|
+
states.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED,
|
|
449
|
+
cond="_selected_environment_windows_path_or_venv_blocked",
|
|
450
|
+
on="_on_diagnosis_produced",
|
|
451
|
+
)
|
|
452
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
453
|
+
states.VAULT_GUARD_DECISION_REQUIRED,
|
|
454
|
+
cond="_selected_vault_guard_decision_required",
|
|
455
|
+
on="_on_diagnosis_produced",
|
|
456
|
+
)
|
|
457
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
458
|
+
states.SUBAGENT_PLAN_ATTESTATION_REQUIRED,
|
|
459
|
+
cond="_selected_subagent_plan_attestation_required",
|
|
460
|
+
on="_on_diagnosis_produced",
|
|
461
|
+
)
|
|
462
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
463
|
+
states.SUBAGENT_PLAN_ATTESTATION_INVALID,
|
|
464
|
+
cond="_selected_subagent_plan_attestation_invalid",
|
|
465
|
+
on="_on_diagnosis_produced",
|
|
466
|
+
)
|
|
467
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
468
|
+
states.AGENT_TOOL_CONTRACT_VIOLATION,
|
|
469
|
+
cond="_selected_agent_tool_contract_violation",
|
|
470
|
+
on="_on_diagnosis_produced",
|
|
471
|
+
)
|
|
472
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
473
|
+
states.DETERMINISTIC_REPAIRS_RUNNING,
|
|
474
|
+
cond="_selected_deterministic_repairs",
|
|
475
|
+
on="_on_diagnosis_produced",
|
|
476
|
+
)
|
|
477
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
478
|
+
states.STYLE_REWRITE_SPECIALIST_REQUESTED,
|
|
479
|
+
cond="_selected_style_rewrite",
|
|
480
|
+
on="_on_diagnosis_produced",
|
|
481
|
+
)
|
|
482
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
483
|
+
states.TAXONOMY_DECISION_REQUIRED,
|
|
484
|
+
cond="_selected_taxonomy",
|
|
485
|
+
on="_on_diagnosis_produced",
|
|
486
|
+
)
|
|
487
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
488
|
+
states.VOCABULARY_SEMANTIC_INGESTION_PENDING,
|
|
489
|
+
cond="_selected_vocabulary_semantic_ingestion_pending",
|
|
490
|
+
on="_on_diagnosis_produced",
|
|
491
|
+
)
|
|
492
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
493
|
+
states.VOCABULARY_CURATOR_RUNNING,
|
|
494
|
+
cond="_selected_vocabulary",
|
|
495
|
+
on="_on_diagnosis_produced",
|
|
496
|
+
)
|
|
497
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
498
|
+
states.ATOMICITY_SPLIT_RUNNING,
|
|
499
|
+
cond="_selected_atomicity_split",
|
|
500
|
+
on="_on_diagnosis_produced",
|
|
501
|
+
)
|
|
502
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
503
|
+
states.MERGE_RUNNING,
|
|
504
|
+
cond="_selected_merge",
|
|
505
|
+
on="_on_diagnosis_produced",
|
|
506
|
+
)
|
|
507
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
508
|
+
states.RELATED_NOTES_EXPORT_RUNNING,
|
|
509
|
+
cond="_selected_related_notes",
|
|
510
|
+
on="_on_diagnosis_produced",
|
|
511
|
+
)
|
|
512
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
513
|
+
states.LINK_RUN_REQUESTED,
|
|
514
|
+
cond="_selected_link",
|
|
515
|
+
on="_on_diagnosis_produced",
|
|
516
|
+
)
|
|
517
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
518
|
+
states.CONTRACT_GAP_MISSING_NEXT_ACTION,
|
|
519
|
+
cond="_selected_contract_gap_missing_next_action",
|
|
520
|
+
on="_on_diagnosis_produced",
|
|
521
|
+
)
|
|
522
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
523
|
+
states.CONTRACT_GAP_MISSING_ERROR_CONTEXT,
|
|
524
|
+
cond="_selected_contract_gap_missing_error_context",
|
|
525
|
+
on="_on_diagnosis_produced",
|
|
526
|
+
)
|
|
527
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
528
|
+
states.ROLLBACK_RUNNING,
|
|
529
|
+
cond="_selected_rollback",
|
|
530
|
+
on="_on_diagnosis_produced",
|
|
531
|
+
)
|
|
532
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
533
|
+
states.FINAL_VALIDATION_RUNNING,
|
|
534
|
+
cond="_selected_final_validation",
|
|
535
|
+
on="_on_diagnosis_produced",
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
|
|
539
|
+
runtime_observed = (
|
|
540
|
+
states.DIAGNOSIS_RUNNING.to(
|
|
541
|
+
states.VAULT_GUARD_DECISION_REQUIRED,
|
|
542
|
+
cond="_observed_vault_guard_required",
|
|
543
|
+
on="_on_blocked",
|
|
544
|
+
)
|
|
545
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
546
|
+
states.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED,
|
|
547
|
+
cond="_observed_environment_blocked",
|
|
548
|
+
on="_on_blocked",
|
|
549
|
+
)
|
|
550
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
551
|
+
states.FAILED,
|
|
552
|
+
cond="_observed_failed",
|
|
553
|
+
on="_on_failed",
|
|
554
|
+
)
|
|
555
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
556
|
+
states.RELATED_NOTES_QUOTA_WAIT,
|
|
557
|
+
cond="_observed_related_notes_quota_wait",
|
|
558
|
+
on="_on_wait_external",
|
|
559
|
+
)
|
|
560
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
561
|
+
states.STYLE_REWRITE_CAPACITY_WAIT,
|
|
562
|
+
cond="_observed_style_rewrite_capacity_wait",
|
|
563
|
+
on="_on_wait_external",
|
|
564
|
+
)
|
|
565
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
566
|
+
states.VOCABULARY_SEMANTIC_INGESTION_PENDING,
|
|
567
|
+
cond="_observed_vocabulary_semantic_ingestion_pending",
|
|
568
|
+
on="_on_runtime_observed",
|
|
569
|
+
)
|
|
570
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
571
|
+
states.VOCABULARY_EVAL_NEEDS_REVIEW,
|
|
572
|
+
cond="_observed_vocabulary_eval_needs_review",
|
|
573
|
+
on="_on_human_review",
|
|
574
|
+
)
|
|
575
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
576
|
+
states.ATOMICITY_SPLIT_REVIEW_REQUIRED,
|
|
577
|
+
cond="_observed_atomicity_split_required",
|
|
578
|
+
on="_on_human_review",
|
|
579
|
+
)
|
|
580
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
581
|
+
states.MERGE_REVIEW_REQUIRED,
|
|
582
|
+
cond="_observed_merge_review_required",
|
|
583
|
+
on="_on_human_review",
|
|
584
|
+
)
|
|
585
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
586
|
+
states.LINK_GRAPH_REVIEW_REQUIRED,
|
|
587
|
+
cond="_observed_graph_review_required",
|
|
588
|
+
on="_on_human_review",
|
|
589
|
+
)
|
|
590
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
591
|
+
states.LINK_GRAPH_BLOCKED,
|
|
592
|
+
cond="_observed_graph_blocked",
|
|
593
|
+
on="_on_blocked",
|
|
594
|
+
)
|
|
595
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
596
|
+
states.TAXONOMY_DECISION_REQUIRED,
|
|
597
|
+
cond="_observed_taxonomy_action_required",
|
|
598
|
+
on="_on_human_review",
|
|
599
|
+
)
|
|
600
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
601
|
+
states.RELATED_NOTES_BLOCKED,
|
|
602
|
+
cond="_observed_related_notes_blocked",
|
|
603
|
+
on="_on_blocked",
|
|
604
|
+
)
|
|
605
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
606
|
+
states.LINKER_BLOCKED,
|
|
607
|
+
cond="_observed_linker_blocked",
|
|
608
|
+
on="_on_blocked",
|
|
609
|
+
)
|
|
610
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
611
|
+
states.STYLE_REWRITE_SPECIALIST_REQUESTED,
|
|
612
|
+
cond="_observed_specialist_model_waiting_agent",
|
|
613
|
+
on="_on_runtime_observed",
|
|
614
|
+
)
|
|
615
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
616
|
+
states.STYLE_REWRITE_REVIEW_REQUIRED,
|
|
617
|
+
cond="_observed_style_rewrite_review_required",
|
|
618
|
+
on="_on_human_review",
|
|
619
|
+
)
|
|
620
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
621
|
+
states.CONTRACT_GAP_MISSING_ERROR_CONTEXT,
|
|
622
|
+
cond="_observed_human_decision_contract_gap",
|
|
623
|
+
on="_on_failed",
|
|
624
|
+
)
|
|
625
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
626
|
+
states.LINK_RUN_REQUESTED,
|
|
627
|
+
cond="_observed_link_subworkflow_required",
|
|
628
|
+
on="_on_runtime_observed",
|
|
629
|
+
)
|
|
630
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
631
|
+
states.PREVIEW_READY,
|
|
632
|
+
cond="_observed_preview_ready",
|
|
633
|
+
on="_on_completed",
|
|
634
|
+
)
|
|
635
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
636
|
+
states.COMPLETED_WITH_WARNINGS,
|
|
637
|
+
cond="_observed_completed_with_warnings",
|
|
638
|
+
on="_on_completed",
|
|
639
|
+
)
|
|
640
|
+
| states.DIAGNOSIS_RUNNING.to(
|
|
641
|
+
states.COMPLETED,
|
|
642
|
+
cond="_observed_completed",
|
|
643
|
+
on="_on_completed",
|
|
644
|
+
)
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
blocker_retry_requested = (
|
|
648
|
+
states.ENVIRONMENT_PATHS_MISSING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
649
|
+
| states.ENVIRONMENT_WIKI_DIR_MISSING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
650
|
+
| states.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED.to(
|
|
651
|
+
states.DIAGNOSIS_RUNNING,
|
|
652
|
+
on="_on_resume_diagnosis",
|
|
653
|
+
)
|
|
654
|
+
| states.VAULT_GUARD_DECISION_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
655
|
+
| states.SUBAGENT_PLAN_ATTESTATION_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
656
|
+
| states.SUBAGENT_PLAN_ATTESTATION_INVALID.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
657
|
+
| states.STYLE_REWRITE_CAPACITY_WAIT.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
658
|
+
| states.STYLE_REWRITE_REVIEW_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
659
|
+
| states.TAXONOMY_DECISION_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
660
|
+
| states.VOCABULARY_SEMANTIC_INGESTION_PENDING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
661
|
+
| states.VOCABULARY_EVAL_NEEDS_REVIEW.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
662
|
+
| states.ATOMICITY_SPLIT_REVIEW_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
663
|
+
| states.RELATED_NOTES_QUOTA_WAIT.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
664
|
+
| states.RELATED_NOTES_OBSIDIAN_NOT_READY.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
665
|
+
| states.RELATED_NOTES_BLOCKED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
666
|
+
| states.LINK_GRAPH_REVIEW_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
667
|
+
| states.LINK_GRAPH_BLOCKED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
668
|
+
| states.LINKER_BLOCKED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
669
|
+
| states.MERGE_REVIEW_REQUIRED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
670
|
+
| states.ROLLBACK_FAILED.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
setup_bootstrap_ready = (
|
|
674
|
+
states.ENVIRONMENT_PATHS_MISSING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
675
|
+
| states.ENVIRONMENT_WIKI_DIR_MISSING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
676
|
+
| states.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED.to(
|
|
677
|
+
states.DIAGNOSIS_RUNNING,
|
|
678
|
+
on="_on_resume_diagnosis",
|
|
679
|
+
)
|
|
680
|
+
)
|
|
681
|
+
setup_bootstrap_blocked = (
|
|
682
|
+
states.ENVIRONMENT_PATHS_MISSING.to(states.FAILED, on="_on_failed")
|
|
683
|
+
| states.ENVIRONMENT_WIKI_DIR_MISSING.to(states.FAILED, on="_on_failed")
|
|
684
|
+
| states.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED.to(states.FAILED, on="_on_failed")
|
|
685
|
+
)
|
|
686
|
+
vault_guard_decision_approved = states.VAULT_GUARD_DECISION_REQUIRED.to(
|
|
687
|
+
states.VAULT_GUARD_RUNNING,
|
|
688
|
+
on="_on_vault_guard_run",
|
|
689
|
+
)
|
|
690
|
+
vault_guard_ready = states.VAULT_GUARD_RUNNING.to(states.DIAGNOSIS_RUNNING, on="_on_resume_diagnosis")
|
|
691
|
+
vault_guard_blocked = states.VAULT_GUARD_RUNNING.to(
|
|
692
|
+
states.VAULT_GUARD_DECISION_REQUIRED,
|
|
693
|
+
on="_on_blocked",
|
|
694
|
+
)
|
|
695
|
+
deterministic_repairs_applied = states.DETERMINISTIC_REPAIRS_RUNNING.to(
|
|
696
|
+
states.LINK_RUN_REQUESTED,
|
|
697
|
+
on="_on_route_link",
|
|
698
|
+
)
|
|
699
|
+
deterministic_repairs_blocked = states.DETERMINISTIC_REPAIRS_RUNNING.to(
|
|
700
|
+
states.DETERMINISTIC_REPAIRS_FAILED,
|
|
701
|
+
on="_on_failed",
|
|
702
|
+
)
|
|
703
|
+
style_rewrite_specialist_completed = states.STYLE_REWRITE_SPECIALIST_REQUESTED.to(
|
|
704
|
+
states.STYLE_REWRITE_REVIEW_REQUIRED,
|
|
705
|
+
on="_on_human_review",
|
|
706
|
+
)
|
|
707
|
+
style_rewrite_capacity_wait = states.STYLE_REWRITE_SPECIALIST_REQUESTED.to(
|
|
708
|
+
states.STYLE_REWRITE_CAPACITY_WAIT,
|
|
709
|
+
on="_on_wait_external",
|
|
710
|
+
)
|
|
711
|
+
style_rewrite_review_required = states.STYLE_REWRITE_SPECIALIST_REQUESTED.to(
|
|
712
|
+
states.STYLE_REWRITE_REVIEW_REQUIRED,
|
|
713
|
+
on="_on_human_review",
|
|
714
|
+
)
|
|
715
|
+
style_rewrite_review_approved = states.STYLE_REWRITE_REVIEW_REQUIRED.to(
|
|
716
|
+
states.STYLE_REWRITE_APPLY_RUNNING,
|
|
717
|
+
on="_on_style_rewrite_apply",
|
|
718
|
+
)
|
|
719
|
+
style_rewrite_applied = states.STYLE_REWRITE_APPLY_RUNNING.to(states.LINK_RUN_REQUESTED, on="_on_route_link")
|
|
720
|
+
style_rewrite_blocked = states.STYLE_REWRITE_APPLY_RUNNING.to(states.FAILED, on="_on_failed")
|
|
721
|
+
taxonomy_decision_required = states.TAXONOMY_APPLY_RUNNING.to(
|
|
722
|
+
states.TAXONOMY_DECISION_REQUIRED,
|
|
723
|
+
on="_on_human_review",
|
|
724
|
+
)
|
|
725
|
+
taxonomy_decision_approved = states.TAXONOMY_DECISION_REQUIRED.to(
|
|
726
|
+
states.TAXONOMY_APPLY_RUNNING,
|
|
727
|
+
on="_on_taxonomy_apply",
|
|
728
|
+
)
|
|
729
|
+
taxonomy_applied = states.TAXONOMY_APPLY_RUNNING.to(states.LINK_RUN_REQUESTED, on="_on_route_link")
|
|
730
|
+
taxonomy_blocked = states.TAXONOMY_APPLY_RUNNING.to(
|
|
731
|
+
states.TAXONOMY_DECISION_REQUIRED,
|
|
732
|
+
on="_on_human_review",
|
|
733
|
+
)
|
|
734
|
+
vocabulary_curator_completed = (
|
|
735
|
+
states.VOCABULARY_CURATOR_RUNNING.to(
|
|
736
|
+
states.VOCABULARY_EVAL_RUNNING,
|
|
737
|
+
on="_on_vocabulary_eval",
|
|
738
|
+
)
|
|
739
|
+
| states.VOCABULARY_SEMANTIC_INGESTION_PENDING.to(
|
|
740
|
+
states.VOCABULARY_EVAL_RUNNING,
|
|
741
|
+
on="_on_vocabulary_eval",
|
|
742
|
+
)
|
|
743
|
+
)
|
|
744
|
+
vocabulary_eval_needs_review = states.VOCABULARY_EVAL_RUNNING.to(
|
|
745
|
+
states.VOCABULARY_EVAL_NEEDS_REVIEW,
|
|
746
|
+
on="_on_human_review",
|
|
747
|
+
)
|
|
748
|
+
vocabulary_eval_passed = states.VOCABULARY_EVAL_RUNNING.to(
|
|
749
|
+
states.VOCABULARY_APPLY_RUNNING,
|
|
750
|
+
on="_on_vocabulary_apply",
|
|
751
|
+
)
|
|
752
|
+
vocabulary_applied = states.VOCABULARY_APPLY_RUNNING.to(states.LINK_RUN_REQUESTED, on="_on_route_link")
|
|
753
|
+
vocabulary_integrity_failed = states.VOCABULARY_APPLY_RUNNING.to(
|
|
754
|
+
states.VOCABULARY_SQLITE_INTEGRITY_FAILED,
|
|
755
|
+
on="_on_failed",
|
|
756
|
+
)
|
|
757
|
+
atomicity_split_applied = states.ATOMICITY_SPLIT_RUNNING.to(states.LINK_RUN_REQUESTED, on="_on_route_link")
|
|
758
|
+
atomicity_split_blocked = states.ATOMICITY_SPLIT_RUNNING.to(
|
|
759
|
+
states.ATOMICITY_SPLIT_REVIEW_REQUIRED,
|
|
760
|
+
on="_on_human_review",
|
|
761
|
+
)
|
|
762
|
+
merge_applied = states.MERGE_RUNNING.to(states.LINK_RUN_REQUESTED, on="_on_route_link")
|
|
763
|
+
merge_blocked = states.MERGE_RUNNING.to(states.MERGE_REVIEW_REQUIRED, on="_on_human_review")
|
|
764
|
+
related_notes_export_completed = states.RELATED_NOTES_EXPORT_RUNNING.to(
|
|
765
|
+
states.LINK_RUN_REQUESTED,
|
|
766
|
+
on="_on_route_link",
|
|
767
|
+
)
|
|
768
|
+
related_notes_quota_wait = (
|
|
769
|
+
states.RELATED_NOTES_EXPORT_RUNNING.to(
|
|
770
|
+
states.RELATED_NOTES_QUOTA_WAIT,
|
|
771
|
+
on="_on_wait_external",
|
|
772
|
+
)
|
|
773
|
+
| states.LINK_RUN_REQUESTED.to(
|
|
774
|
+
states.RELATED_NOTES_QUOTA_WAIT,
|
|
775
|
+
on="_on_wait_external",
|
|
776
|
+
)
|
|
777
|
+
)
|
|
778
|
+
related_notes_obsidian_not_ready = states.RELATED_NOTES_EXPORT_RUNNING.to(
|
|
779
|
+
states.RELATED_NOTES_OBSIDIAN_NOT_READY,
|
|
780
|
+
on="_on_blocked",
|
|
781
|
+
)
|
|
782
|
+
related_notes_blocked = states.RELATED_NOTES_EXPORT_RUNNING.to(
|
|
783
|
+
states.RELATED_NOTES_BLOCKED,
|
|
784
|
+
on="_on_blocked",
|
|
785
|
+
)
|
|
786
|
+
link_completed = states.LINK_RUN_REQUESTED.to(states.FINAL_VALIDATION_RUNNING, on="_on_enter_final_validation")
|
|
787
|
+
link_graph_blocked = states.LINK_RUN_REQUESTED.to(states.LINK_GRAPH_BLOCKED, on="_on_blocked")
|
|
788
|
+
linker_blocked = states.LINK_RUN_REQUESTED.to(states.LINKER_BLOCKED, on="_on_blocked")
|
|
789
|
+
preview_ready = states.FINAL_VALIDATION_RUNNING.to(states.PREVIEW_READY, on="_on_completed")
|
|
790
|
+
final_validation_passed = states.FINAL_VALIDATION_RUNNING.to(states.COMPLETED, on="_on_completed")
|
|
791
|
+
final_validation_warnings = states.FINAL_VALIDATION_RUNNING.to(
|
|
792
|
+
states.COMPLETED_WITH_WARNINGS,
|
|
793
|
+
on="_on_completed",
|
|
794
|
+
)
|
|
795
|
+
final_validation_found_more_work = states.FINAL_VALIDATION_RUNNING.to(
|
|
796
|
+
states.DIAGNOSIS_RUNNING,
|
|
797
|
+
on="_on_resume_diagnosis",
|
|
798
|
+
)
|
|
799
|
+
final_validation_failed = states.FINAL_VALIDATION_RUNNING.to(states.FINAL_VALIDATION_FAILED, on="_on_failed")
|
|
800
|
+
rollback_completed = states.ROLLBACK_RUNNING.to(states.ROLLBACK_PERFORMED, on="_on_failed")
|
|
801
|
+
rollback_failed = states.ROLLBACK_RUNNING.to(states.ROLLBACK_FAILED, on="_on_blocked")
|
|
802
|
+
|
|
803
|
+
def category_for_state(self, state: str) -> WorkflowStateCategory:
|
|
804
|
+
return fix_wiki_category_for_state(state)
|
|
805
|
+
|
|
806
|
+
def _selected_environment_paths_missing(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
807
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.ENVIRONMENT_PATHS_MISSING
|
|
808
|
+
|
|
809
|
+
def _selected_environment_wiki_dir_missing(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
810
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.ENVIRONMENT_WIKI_DIR_MISSING
|
|
811
|
+
|
|
812
|
+
def _selected_environment_windows_path_or_venv_blocked(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
813
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED
|
|
814
|
+
|
|
815
|
+
def _selected_vault_guard_decision_required(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
816
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.VAULT_GUARD_DECISION_REQUIRED
|
|
817
|
+
|
|
818
|
+
def _selected_subagent_plan_attestation_required(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
819
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.SUBAGENT_PLAN_ATTESTATION_REQUIRED
|
|
820
|
+
|
|
821
|
+
def _selected_subagent_plan_attestation_invalid(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
822
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.SUBAGENT_PLAN_ATTESTATION_INVALID
|
|
823
|
+
|
|
824
|
+
def _selected_agent_tool_contract_violation(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
825
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.AGENT_TOOL_CONTRACT_VIOLATION
|
|
826
|
+
|
|
827
|
+
def _selected_deterministic_repairs(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
828
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.DETERMINISTIC_REPAIRS
|
|
829
|
+
|
|
830
|
+
def _selected_style_rewrite(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
831
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.STYLE_REWRITE
|
|
832
|
+
|
|
833
|
+
def _selected_taxonomy(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
834
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.TAXONOMY
|
|
835
|
+
|
|
836
|
+
def _selected_vocabulary_semantic_ingestion_pending(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
837
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.VOCABULARY_SEMANTIC_INGESTION_PENDING
|
|
838
|
+
|
|
839
|
+
def _selected_vocabulary(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
840
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.VOCABULARY
|
|
841
|
+
|
|
842
|
+
def _selected_atomicity_split(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
843
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.ATOMICITY_SPLIT
|
|
844
|
+
|
|
845
|
+
def _selected_merge(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
846
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.MERGE
|
|
847
|
+
|
|
848
|
+
def _selected_related_notes(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
849
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.RELATED_NOTES
|
|
850
|
+
|
|
851
|
+
def _selected_link(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
852
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.LINK
|
|
853
|
+
|
|
854
|
+
def _selected_contract_gap_missing_next_action(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
855
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.CONTRACT_GAP_MISSING_NEXT_ACTION
|
|
856
|
+
|
|
857
|
+
def _selected_contract_gap_missing_error_context(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
858
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.CONTRACT_GAP_MISSING_ERROR_CONTEXT
|
|
859
|
+
|
|
860
|
+
def _selected_rollback(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
861
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.ROLLBACK
|
|
862
|
+
|
|
863
|
+
def _selected_final_validation(self, workflow_event: DiagnosisProducedEvent) -> bool:
|
|
864
|
+
return workflow_event.selected_lane == FixWikiDiagnosisLane.FINAL_VALIDATION
|
|
865
|
+
|
|
866
|
+
def _observed_vault_guard_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
867
|
+
return workflow_event.observation.vault_guard_required
|
|
868
|
+
|
|
869
|
+
def _observed_environment_blocked(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
870
|
+
return workflow_event.observation.environment_windows_path_or_venv_blocked
|
|
871
|
+
|
|
872
|
+
def _observed_related_notes_quota_wait(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
873
|
+
return bool(
|
|
874
|
+
workflow_event.observation.external_wait_reason_code
|
|
875
|
+
and workflow_event.observation.related_notes_recovery_state.status
|
|
876
|
+
) or workflow_event.observation.related_notes_waiting_external
|
|
877
|
+
|
|
878
|
+
def _observed_style_rewrite_capacity_wait(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
879
|
+
observation = workflow_event.observation
|
|
880
|
+
return bool(observation.external_wait_reason_code) and not self._observed_related_notes_quota_wait(
|
|
881
|
+
workflow_event
|
|
882
|
+
)
|
|
883
|
+
|
|
884
|
+
def _observed_vocabulary_semantic_ingestion_pending(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
885
|
+
return workflow_event.observation.vocabulary_semantic_ingestion_pending
|
|
886
|
+
|
|
887
|
+
def _observed_vocabulary_eval_needs_review(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
888
|
+
return workflow_event.observation.vocabulary_eval_needs_review
|
|
889
|
+
|
|
890
|
+
def _observed_atomicity_split_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
891
|
+
return workflow_event.observation.atomicity_split_required
|
|
892
|
+
|
|
893
|
+
def _observed_merge_review_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
894
|
+
return workflow_event.observation.merge_review_required
|
|
895
|
+
|
|
896
|
+
def _observed_graph_review_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
897
|
+
observation = workflow_event.observation
|
|
898
|
+
return observation.graph_review_required and (observation.graph_blocker_count > 0 or observation.graph_error_count > 0)
|
|
899
|
+
|
|
900
|
+
def _observed_graph_blocked(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
901
|
+
observation = workflow_event.observation
|
|
902
|
+
return observation.graph_blocker_count > 0 or observation.graph_error_count > 0
|
|
903
|
+
|
|
904
|
+
def _observed_related_notes_blocked(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
905
|
+
return workflow_event.observation.related_notes_blocked
|
|
906
|
+
|
|
907
|
+
def _observed_linker_blocked(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
908
|
+
return workflow_event.observation.linker_blocked
|
|
909
|
+
|
|
910
|
+
def _observed_taxonomy_action_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
911
|
+
return workflow_event.observation.taxonomy_action_required
|
|
912
|
+
|
|
913
|
+
def _observed_specialist_model_waiting_agent(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
914
|
+
return workflow_event.observation.specialist_model_waiting_agent
|
|
915
|
+
|
|
916
|
+
def _observed_style_rewrite_review_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
917
|
+
return workflow_event.observation.requires_llm_rewrite_count > 0
|
|
918
|
+
|
|
919
|
+
def _observed_human_decision_contract_gap(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
920
|
+
return workflow_event.observation.human_decision_required
|
|
921
|
+
|
|
922
|
+
def _observed_link_subworkflow_required(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
923
|
+
return workflow_event.observation.link_subworkflow_required
|
|
924
|
+
|
|
925
|
+
def _observed_failed(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
926
|
+
return workflow_event.observation.failed
|
|
927
|
+
|
|
928
|
+
def _observed_preview_ready(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
929
|
+
return not workflow_event.observation.effective_apply
|
|
930
|
+
|
|
931
|
+
def _observed_completed_with_warnings(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
932
|
+
return workflow_event.observation.warning_count > 0
|
|
933
|
+
|
|
934
|
+
def _observed_completed(self, workflow_event: RuntimeObservedEvent) -> bool:
|
|
935
|
+
return workflow_event.observation.effective_apply
|
|
936
|
+
|
|
937
|
+
def _on_diagnosis_produced(
|
|
938
|
+
self,
|
|
939
|
+
workflow_event: DiagnosisProducedEvent,
|
|
940
|
+
target: object,
|
|
941
|
+
) -> WorkflowTransitionResult:
|
|
942
|
+
to_state = _target_state(target)
|
|
943
|
+
match to_state:
|
|
944
|
+
case (
|
|
945
|
+
FixWikiState.ENVIRONMENT_PATHS_MISSING
|
|
946
|
+
| FixWikiState.ENVIRONMENT_WIKI_DIR_MISSING
|
|
947
|
+
| FixWikiState.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED
|
|
948
|
+
):
|
|
949
|
+
return _setup_recovery_transition(workflow_event, to_state)
|
|
950
|
+
case FixWikiState.VAULT_GUARD_DECISION_REQUIRED:
|
|
951
|
+
return _blocked_transition(workflow_event, to_state)
|
|
952
|
+
case (
|
|
953
|
+
FixWikiState.SUBAGENT_PLAN_ATTESTATION_REQUIRED
|
|
954
|
+
| FixWikiState.SUBAGENT_PLAN_ATTESTATION_INVALID
|
|
955
|
+
):
|
|
956
|
+
return _human_transition(workflow_event, to_state)
|
|
957
|
+
case FixWikiState.AGENT_TOOL_CONTRACT_VIOLATION:
|
|
958
|
+
return _failed_transition(workflow_event, to_state)
|
|
959
|
+
case FixWikiState.DETERMINISTIC_REPAIRS_RUNNING:
|
|
960
|
+
return _transition(
|
|
961
|
+
workflow_event,
|
|
962
|
+
to_state,
|
|
963
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.deterministic_repairs")],
|
|
964
|
+
)
|
|
965
|
+
case FixWikiState.STYLE_REWRITE_SPECIALIST_REQUESTED:
|
|
966
|
+
return _transition(workflow_event, to_state, effects=[_style_rewrite_effect(workflow_event, to_state)])
|
|
967
|
+
case FixWikiState.TAXONOMY_DECISION_REQUIRED:
|
|
968
|
+
return _human_transition(workflow_event, to_state)
|
|
969
|
+
case (
|
|
970
|
+
FixWikiState.VOCABULARY_CURATOR_RUNNING
|
|
971
|
+
| FixWikiState.VOCABULARY_SEMANTIC_INGESTION_PENDING
|
|
972
|
+
):
|
|
973
|
+
return _transition(
|
|
974
|
+
workflow_event,
|
|
975
|
+
to_state,
|
|
976
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.vocabulary_curator")],
|
|
977
|
+
)
|
|
978
|
+
case FixWikiState.ATOMICITY_SPLIT_RUNNING:
|
|
979
|
+
return _transition(
|
|
980
|
+
workflow_event,
|
|
981
|
+
to_state,
|
|
982
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.atomicity_split")],
|
|
983
|
+
)
|
|
984
|
+
case FixWikiState.MERGE_RUNNING:
|
|
985
|
+
return _transition(
|
|
986
|
+
workflow_event,
|
|
987
|
+
to_state,
|
|
988
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.note_merge")],
|
|
989
|
+
)
|
|
990
|
+
case FixWikiState.RELATED_NOTES_EXPORT_RUNNING:
|
|
991
|
+
return _transition(workflow_event, to_state, effects=[_related_notes_effect(workflow_event, to_state)])
|
|
992
|
+
case FixWikiState.LINK_RUN_REQUESTED:
|
|
993
|
+
return _transition(workflow_event, to_state, effects=[_link_effect(workflow_event, to_state)])
|
|
994
|
+
case (
|
|
995
|
+
FixWikiState.CONTRACT_GAP_MISSING_NEXT_ACTION
|
|
996
|
+
| FixWikiState.CONTRACT_GAP_MISSING_ERROR_CONTEXT
|
|
997
|
+
):
|
|
998
|
+
return _failed_transition(workflow_event, to_state)
|
|
999
|
+
case FixWikiState.ROLLBACK_RUNNING:
|
|
1000
|
+
return _transition(
|
|
1001
|
+
workflow_event,
|
|
1002
|
+
to_state,
|
|
1003
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.rollback")],
|
|
1004
|
+
)
|
|
1005
|
+
case FixWikiState.FINAL_VALIDATION_RUNNING:
|
|
1006
|
+
return _transition(
|
|
1007
|
+
workflow_event,
|
|
1008
|
+
to_state,
|
|
1009
|
+
effects=[_final_validation_effect(workflow_event, to_state)],
|
|
1010
|
+
)
|
|
1011
|
+
case _:
|
|
1012
|
+
raise AssertionError(f"unexpected diagnosis target: {to_state}")
|
|
1013
|
+
|
|
1014
|
+
def _on_runtime_observed(self, workflow_event: RuntimeObservedEvent, target: object) -> WorkflowTransitionResult:
|
|
1015
|
+
to_state = _target_state(target)
|
|
1016
|
+
match to_state:
|
|
1017
|
+
case FixWikiState.STYLE_REWRITE_SPECIALIST_REQUESTED:
|
|
1018
|
+
return _transition(workflow_event, to_state, effects=[_style_rewrite_effect(workflow_event, to_state)])
|
|
1019
|
+
case FixWikiState.VOCABULARY_SEMANTIC_INGESTION_PENDING:
|
|
1020
|
+
return _transition(
|
|
1021
|
+
workflow_event,
|
|
1022
|
+
to_state,
|
|
1023
|
+
effects=[_domain_effect(workflow_event, to_state, target="fix_wiki.vocabulary_curator")],
|
|
1024
|
+
)
|
|
1025
|
+
case FixWikiState.LINK_RUN_REQUESTED:
|
|
1026
|
+
return _transition(workflow_event, to_state, effects=[_link_effect(workflow_event, to_state)])
|
|
1027
|
+
case _:
|
|
1028
|
+
return _transition(workflow_event, to_state)
|
|
1029
|
+
|
|
1030
|
+
def _on_resume_diagnosis(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1031
|
+
return _transition(workflow_event, FixWikiState.DIAGNOSIS_RUNNING)
|
|
1032
|
+
|
|
1033
|
+
def _on_route_link(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1034
|
+
return _transition(
|
|
1035
|
+
workflow_event,
|
|
1036
|
+
FixWikiState.LINK_RUN_REQUESTED,
|
|
1037
|
+
effects=[_link_effect(workflow_event, FixWikiState.LINK_RUN_REQUESTED)],
|
|
1038
|
+
)
|
|
1039
|
+
|
|
1040
|
+
def _on_vault_guard_run(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1041
|
+
return _transition(
|
|
1042
|
+
workflow_event,
|
|
1043
|
+
FixWikiState.VAULT_GUARD_RUNNING,
|
|
1044
|
+
effects=[_vault_guard_effect(workflow_event, FixWikiState.VAULT_GUARD_RUNNING)],
|
|
1045
|
+
)
|
|
1046
|
+
|
|
1047
|
+
def _on_enter_final_validation(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1048
|
+
return _transition(
|
|
1049
|
+
workflow_event,
|
|
1050
|
+
FixWikiState.FINAL_VALIDATION_RUNNING,
|
|
1051
|
+
effects=[_final_validation_effect(workflow_event, FixWikiState.FINAL_VALIDATION_RUNNING)],
|
|
1052
|
+
)
|
|
1053
|
+
|
|
1054
|
+
def _on_vocabulary_eval(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1055
|
+
return _transition(
|
|
1056
|
+
workflow_event,
|
|
1057
|
+
FixWikiState.VOCABULARY_EVAL_RUNNING,
|
|
1058
|
+
effects=[
|
|
1059
|
+
_domain_effect(
|
|
1060
|
+
workflow_event,
|
|
1061
|
+
FixWikiState.VOCABULARY_EVAL_RUNNING,
|
|
1062
|
+
target="fix_wiki.vocabulary_eval",
|
|
1063
|
+
)
|
|
1064
|
+
],
|
|
1065
|
+
)
|
|
1066
|
+
|
|
1067
|
+
def _on_style_rewrite_apply(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1068
|
+
return _transition(
|
|
1069
|
+
workflow_event,
|
|
1070
|
+
FixWikiState.STYLE_REWRITE_APPLY_RUNNING,
|
|
1071
|
+
effects=[
|
|
1072
|
+
_domain_effect(
|
|
1073
|
+
workflow_event,
|
|
1074
|
+
FixWikiState.STYLE_REWRITE_APPLY_RUNNING,
|
|
1075
|
+
target="fix_wiki.style_rewrite_apply",
|
|
1076
|
+
)
|
|
1077
|
+
],
|
|
1078
|
+
)
|
|
1079
|
+
|
|
1080
|
+
def _on_taxonomy_apply(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1081
|
+
return _transition(
|
|
1082
|
+
workflow_event,
|
|
1083
|
+
FixWikiState.TAXONOMY_APPLY_RUNNING,
|
|
1084
|
+
effects=[_domain_effect(workflow_event, FixWikiState.TAXONOMY_APPLY_RUNNING, target="fix_wiki.taxonomy")],
|
|
1085
|
+
)
|
|
1086
|
+
|
|
1087
|
+
def _on_vocabulary_apply(self, workflow_event: FixWikiEvent) -> WorkflowTransitionResult:
|
|
1088
|
+
return _transition(
|
|
1089
|
+
workflow_event,
|
|
1090
|
+
FixWikiState.VOCABULARY_APPLY_RUNNING,
|
|
1091
|
+
effects=[
|
|
1092
|
+
_domain_effect(
|
|
1093
|
+
workflow_event,
|
|
1094
|
+
FixWikiState.VOCABULARY_APPLY_RUNNING,
|
|
1095
|
+
target="fix_wiki.vocabulary_apply",
|
|
1096
|
+
)
|
|
1097
|
+
],
|
|
1098
|
+
)
|
|
1099
|
+
|
|
1100
|
+
def _on_wait_external(self, workflow_event: FixWikiEvent, target: object) -> WorkflowTransitionResult:
|
|
1101
|
+
to_state = _target_state(target)
|
|
1102
|
+
return _transition(
|
|
1103
|
+
workflow_event,
|
|
1104
|
+
to_state,
|
|
1105
|
+
effects=[_wait_external_effect(workflow_event, to_state)],
|
|
1106
|
+
resume_action="Retomar pela rota oficial depois que a condição externa estiver resolvida.",
|
|
1107
|
+
)
|
|
1108
|
+
|
|
1109
|
+
def _on_human_review(self, workflow_event: FixWikiEvent, target: object) -> WorkflowTransitionResult:
|
|
1110
|
+
to_state = _target_state(target)
|
|
1111
|
+
return _human_transition(workflow_event, to_state)
|
|
1112
|
+
|
|
1113
|
+
def _on_blocked(self, workflow_event: FixWikiEvent, target: object) -> WorkflowTransitionResult:
|
|
1114
|
+
to_state = _target_state(target)
|
|
1115
|
+
return _blocked_transition(workflow_event, to_state)
|
|
1116
|
+
|
|
1117
|
+
def _on_failed(self, workflow_event: FixWikiEvent, target: object) -> WorkflowTransitionResult:
|
|
1118
|
+
to_state = _target_state(target)
|
|
1119
|
+
return _failed_transition(workflow_event, to_state)
|
|
1120
|
+
|
|
1121
|
+
def _on_completed(self, workflow_event: FixWikiEvent, target: object) -> WorkflowTransitionResult:
|
|
1122
|
+
to_state = _target_state(target)
|
|
1123
|
+
return _transition(workflow_event, to_state)
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
def _transition(
|
|
1127
|
+
workflow_event: FixWikiEvent,
|
|
1128
|
+
to_state: FixWikiState,
|
|
1129
|
+
*,
|
|
1130
|
+
reason_code: str | None = None,
|
|
1131
|
+
effects: list[WorkflowEffect] | None = None,
|
|
1132
|
+
decision: WorkflowDecision | None = None,
|
|
1133
|
+
human_decision_packet: HumanDecisionPacket | None = None,
|
|
1134
|
+
resume_action: str = "",
|
|
1135
|
+
) -> WorkflowTransitionResult:
|
|
1136
|
+
trigger = _event_name(workflow_event)
|
|
1137
|
+
state_reason = _transition_reason_for_state(to_state)
|
|
1138
|
+
return WorkflowTransitionResult(
|
|
1139
|
+
workflow=workflow_event.workflow,
|
|
1140
|
+
run_id=workflow_event.run_id,
|
|
1141
|
+
from_state=workflow_event.current_state,
|
|
1142
|
+
to_state=to_state.value,
|
|
1143
|
+
trigger=trigger,
|
|
1144
|
+
reason_code=reason_code or state_reason,
|
|
1145
|
+
effects=list(effects or []),
|
|
1146
|
+
decision=decision,
|
|
1147
|
+
human_decision_packet=human_decision_packet,
|
|
1148
|
+
resume_action=resume_action,
|
|
1149
|
+
)
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
def _transition_reason_for_state(state: FixWikiState) -> str:
|
|
1153
|
+
"""Record the reached leaf for running states and public state reason otherwise."""
|
|
1154
|
+
|
|
1155
|
+
if fix_wiki_category_for_state(state) == WorkflowStateCategory.RUNNING:
|
|
1156
|
+
return state.value
|
|
1157
|
+
return reason_for_state(state).value
|
|
1158
|
+
|
|
1159
|
+
|
|
1160
|
+
def _target_state(target: object) -> FixWikiState:
|
|
1161
|
+
"""Read the python-statemachine transition target without touching IO."""
|
|
1162
|
+
|
|
1163
|
+
value = getattr(target, "value", target)
|
|
1164
|
+
return FixWikiState(str(value))
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
def _blocked_transition(
|
|
1168
|
+
workflow_event: FixWikiEvent,
|
|
1169
|
+
to_state: FixWikiState,
|
|
1170
|
+
) -> WorkflowTransitionResult:
|
|
1171
|
+
reason_code = reason_for_state(to_state).value
|
|
1172
|
+
return _transition(
|
|
1173
|
+
workflow_event,
|
|
1174
|
+
to_state,
|
|
1175
|
+
reason_code=reason_code,
|
|
1176
|
+
decision=_decision(kind="hard_block", phase=to_state.value, reason_code=reason_code),
|
|
1177
|
+
)
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
def _setup_recovery_transition(
|
|
1181
|
+
workflow_event: FixWikiEvent,
|
|
1182
|
+
to_state: FixWikiState,
|
|
1183
|
+
) -> WorkflowTransitionResult:
|
|
1184
|
+
reason_code = reason_for_state(to_state).value
|
|
1185
|
+
resume_action = _setup_resume_action(to_state)
|
|
1186
|
+
return _transition(
|
|
1187
|
+
workflow_event,
|
|
1188
|
+
to_state,
|
|
1189
|
+
reason_code=reason_code,
|
|
1190
|
+
effects=[_setup_recovery_effect(workflow_event, to_state, reason_code=reason_code)],
|
|
1191
|
+
decision=_decision(
|
|
1192
|
+
kind="hard_block",
|
|
1193
|
+
phase=to_state.value,
|
|
1194
|
+
reason_code=reason_code,
|
|
1195
|
+
next_action=resume_action,
|
|
1196
|
+
),
|
|
1197
|
+
resume_action=resume_action,
|
|
1198
|
+
)
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
def _failed_transition(
|
|
1202
|
+
workflow_event: FixWikiEvent,
|
|
1203
|
+
to_state: FixWikiState,
|
|
1204
|
+
) -> WorkflowTransitionResult:
|
|
1205
|
+
reason_code = reason_for_state(to_state).value
|
|
1206
|
+
return _transition(
|
|
1207
|
+
workflow_event,
|
|
1208
|
+
to_state,
|
|
1209
|
+
reason_code=reason_code,
|
|
1210
|
+
decision=_decision(kind="failed", phase=to_state.value, reason_code=reason_code),
|
|
1211
|
+
)
|
|
1212
|
+
|
|
1213
|
+
|
|
1214
|
+
def _human_transition(
|
|
1215
|
+
workflow_event: FixWikiEvent,
|
|
1216
|
+
to_state: FixWikiState,
|
|
1217
|
+
) -> WorkflowTransitionResult:
|
|
1218
|
+
reason_code = reason_for_state(to_state).value
|
|
1219
|
+
decision = _decision(
|
|
1220
|
+
kind="ask_human",
|
|
1221
|
+
phase=to_state.value,
|
|
1222
|
+
reason_code=reason_code,
|
|
1223
|
+
next_action=_human_next_action(to_state),
|
|
1224
|
+
)
|
|
1225
|
+
packet = HumanDecisionPacket.model_validate(decision.to_human_decision_packet())
|
|
1226
|
+
effect = WorkflowEffect(
|
|
1227
|
+
workflow=workflow_event.workflow,
|
|
1228
|
+
run_id=workflow_event.run_id,
|
|
1229
|
+
effect_id=f"fix-wiki-{to_state.value.replace('.', '-')}-human-decision",
|
|
1230
|
+
origin_state=to_state.value,
|
|
1231
|
+
kind=WorkflowEffectKind.ASK_HUMAN,
|
|
1232
|
+
payload={"kind": "human_decision", "reason_code": reason_code},
|
|
1233
|
+
requires_receipt=False,
|
|
1234
|
+
no_resource_mutation=True,
|
|
1235
|
+
)
|
|
1236
|
+
return _transition(
|
|
1237
|
+
workflow_event,
|
|
1238
|
+
to_state,
|
|
1239
|
+
reason_code=reason_code,
|
|
1240
|
+
effects=[effect],
|
|
1241
|
+
decision=decision,
|
|
1242
|
+
human_decision_packet=packet,
|
|
1243
|
+
resume_action=decision.resume_action,
|
|
1244
|
+
)
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
def _human_next_action(to_state: FixWikiState) -> str:
|
|
1248
|
+
"""Keep human-decision actions tied to the reached operational leaf."""
|
|
1249
|
+
|
|
1250
|
+
match to_state:
|
|
1251
|
+
case FixWikiState.STYLE_REWRITE_REVIEW_REQUIRED:
|
|
1252
|
+
return "Executar a reescrita semantica oficial antes de concluir."
|
|
1253
|
+
case FixWikiState.TAXONOMY_DECISION_REQUIRED:
|
|
1254
|
+
return "Resolver a acao de taxonomia pela rota oficial antes de concluir."
|
|
1255
|
+
case FixWikiState.ATOMICITY_SPLIT_REVIEW_REQUIRED:
|
|
1256
|
+
return "Resolver o split de atomicidade pela rota oficial."
|
|
1257
|
+
case FixWikiState.VOCABULARY_EVAL_NEEDS_REVIEW:
|
|
1258
|
+
return "Revisar a avaliacao do vocabulario e retomar pela rota oficial."
|
|
1259
|
+
case FixWikiState.LINK_GRAPH_REVIEW_REQUIRED:
|
|
1260
|
+
return "Revisar os bloqueios de grafo e retomar pela rota oficial."
|
|
1261
|
+
case FixWikiState.MERGE_REVIEW_REQUIRED:
|
|
1262
|
+
return "Revisar o merge de notas e retomar pela rota oficial."
|
|
1263
|
+
case (
|
|
1264
|
+
FixWikiState.SUBAGENT_PLAN_ATTESTATION_REQUIRED
|
|
1265
|
+
| FixWikiState.SUBAGENT_PLAN_ATTESTATION_INVALID
|
|
1266
|
+
):
|
|
1267
|
+
return "Reemitir o plano de subagente pela rota oficial com atestacao valida."
|
|
1268
|
+
case _:
|
|
1269
|
+
return "Responder a decisao solicitada para continuar."
|
|
1270
|
+
|
|
1271
|
+
|
|
1272
|
+
def _decision(
|
|
1273
|
+
*,
|
|
1274
|
+
kind: Literal["hard_block", "failed", "ask_human"],
|
|
1275
|
+
phase: str,
|
|
1276
|
+
reason_code: str,
|
|
1277
|
+
next_action: str = "Retomar pela rota oficial indicada pelo workflow.",
|
|
1278
|
+
) -> WorkflowDecision:
|
|
1279
|
+
evidence = [
|
|
1280
|
+
DecisionEvidence(
|
|
1281
|
+
summary=f"fix-wiki StateChart reached {phase}.",
|
|
1282
|
+
technical_code=reason_code,
|
|
1283
|
+
source="fix_wiki_machine",
|
|
1284
|
+
)
|
|
1285
|
+
]
|
|
1286
|
+
base: JsonObject = {
|
|
1287
|
+
"kind": kind,
|
|
1288
|
+
"phase": phase,
|
|
1289
|
+
"reason_code": reason_code,
|
|
1290
|
+
"public_summary": "O fix-wiki precisa parar nesta etapa.",
|
|
1291
|
+
"developer_summary": f"StateChart transition stopped at {phase}:{reason_code}.",
|
|
1292
|
+
"evidence": evidence,
|
|
1293
|
+
"next_action": next_action,
|
|
1294
|
+
"resume_action": next_action,
|
|
1295
|
+
}
|
|
1296
|
+
if kind == "ask_human":
|
|
1297
|
+
base.update(
|
|
1298
|
+
{
|
|
1299
|
+
"public_summary": "Preciso de uma decisão sua antes de continuar.",
|
|
1300
|
+
"human_decision_kind": reason_code,
|
|
1301
|
+
"recommended_option_id": "continue",
|
|
1302
|
+
"options": [
|
|
1303
|
+
HumanDecisionOption(
|
|
1304
|
+
id="continue",
|
|
1305
|
+
label="Continuar",
|
|
1306
|
+
description="Retoma pela rota oficial depois da confirmação.",
|
|
1307
|
+
)
|
|
1308
|
+
],
|
|
1309
|
+
"rejected_automations": _rejected_automations(reason_code),
|
|
1310
|
+
}
|
|
1311
|
+
)
|
|
1312
|
+
return WorkflowDecision(**base)
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
def _rejected_automations(reason_code: str) -> list[RejectedAutomation]:
|
|
1316
|
+
return [
|
|
1317
|
+
RejectedAutomation(kind="auto_fix", reason_code=reason_code, reason="Requer confirmação humana."),
|
|
1318
|
+
RejectedAutomation(
|
|
1319
|
+
kind="auto_defer",
|
|
1320
|
+
reason_code=reason_code,
|
|
1321
|
+
reason="Adiar sem decisão deixaria o fluxo ambíguo.",
|
|
1322
|
+
),
|
|
1323
|
+
RejectedAutomation(
|
|
1324
|
+
kind="auto_plan",
|
|
1325
|
+
reason_code=reason_code,
|
|
1326
|
+
reason="Planejar sem escolha humana não resolve o bloqueio.",
|
|
1327
|
+
),
|
|
1328
|
+
]
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
def _payload(kind: str) -> JsonObject:
|
|
1332
|
+
return {"kind": kind}
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
def _domain_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState, *, target: str) -> WorkflowEffect:
|
|
1336
|
+
payload_kind = target.removeprefix("fix_wiki.")
|
|
1337
|
+
return WorkflowEffect(
|
|
1338
|
+
workflow=workflow_event.workflow,
|
|
1339
|
+
run_id=workflow_event.run_id,
|
|
1340
|
+
effect_id=f"fix-wiki-{origin_state.value.replace('.', '-')}",
|
|
1341
|
+
origin_state=origin_state.value,
|
|
1342
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1343
|
+
target=target,
|
|
1344
|
+
payload=_payload(payload_kind),
|
|
1345
|
+
mutates_resources=True,
|
|
1346
|
+
rollback_declared=True,
|
|
1347
|
+
requires_receipt=False,
|
|
1348
|
+
)
|
|
1349
|
+
|
|
1350
|
+
|
|
1351
|
+
def _setup_recovery_effect(
|
|
1352
|
+
workflow_event: FixWikiEvent,
|
|
1353
|
+
origin_state: FixWikiState,
|
|
1354
|
+
*,
|
|
1355
|
+
reason_code: str,
|
|
1356
|
+
) -> WorkflowEffect:
|
|
1357
|
+
resume_action = _setup_resume_action(origin_state)
|
|
1358
|
+
return WorkflowEffect(
|
|
1359
|
+
workflow=workflow_event.workflow,
|
|
1360
|
+
run_id=workflow_event.run_id,
|
|
1361
|
+
effect_id=f"fix-wiki-{origin_state.value.replace('.', '-')}-setup",
|
|
1362
|
+
origin_state=origin_state.value,
|
|
1363
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1364
|
+
target="/mednotes:setup",
|
|
1365
|
+
payload={
|
|
1366
|
+
"kind": "setup_recovery",
|
|
1367
|
+
"reason_code": reason_code,
|
|
1368
|
+
"setup_state": _setup_state_for_fix_wiki_environment(origin_state),
|
|
1369
|
+
"resume_action": resume_action,
|
|
1370
|
+
},
|
|
1371
|
+
requires_receipt=False,
|
|
1372
|
+
no_resource_mutation=True,
|
|
1373
|
+
resume_action=resume_action,
|
|
1374
|
+
)
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
def _setup_resume_action(state: FixWikiState) -> str:
|
|
1378
|
+
match state:
|
|
1379
|
+
case FixWikiState.ENVIRONMENT_PATHS_MISSING | FixWikiState.ENVIRONMENT_WIKI_DIR_MISSING:
|
|
1380
|
+
return "setup:set-paths"
|
|
1381
|
+
case FixWikiState.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED:
|
|
1382
|
+
return "setup:bootstrap-python"
|
|
1383
|
+
case _:
|
|
1384
|
+
return "/mednotes:setup"
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
def _setup_state_for_fix_wiki_environment(state: FixWikiState) -> str:
|
|
1388
|
+
match state:
|
|
1389
|
+
case FixWikiState.ENVIRONMENT_PATHS_MISSING | FixWikiState.ENVIRONMENT_WIKI_DIR_MISSING:
|
|
1390
|
+
return "paths_required"
|
|
1391
|
+
case FixWikiState.ENVIRONMENT_WINDOWS_PATH_OR_VENV_BLOCKED:
|
|
1392
|
+
return "python_env_required"
|
|
1393
|
+
case _:
|
|
1394
|
+
return "checking_environment"
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
def _vault_guard_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1398
|
+
return WorkflowEffect(
|
|
1399
|
+
workflow=workflow_event.workflow,
|
|
1400
|
+
run_id=workflow_event.run_id,
|
|
1401
|
+
effect_id="fix-wiki-vault-guard",
|
|
1402
|
+
origin_state=origin_state.value,
|
|
1403
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1404
|
+
target="fix_wiki.vault_guard",
|
|
1405
|
+
payload=_payload("vault_guard"),
|
|
1406
|
+
requires_receipt=False,
|
|
1407
|
+
no_resource_mutation=True,
|
|
1408
|
+
)
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
def _style_rewrite_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1412
|
+
"""Emit the executable specialist effect from the StateChart transition.
|
|
1413
|
+
|
|
1414
|
+
Runtime evidence may carry the batch payload, but the transition owns the
|
|
1415
|
+
public effect identity, target, origin state and model policy.
|
|
1416
|
+
"""
|
|
1417
|
+
|
|
1418
|
+
runtime_effect: WorkflowEffect | None = None
|
|
1419
|
+
if isinstance(workflow_event, DiagnosisQueueEvent):
|
|
1420
|
+
runtime_effect = workflow_event.style_rewrite_effect
|
|
1421
|
+
elif isinstance(workflow_event, RuntimeObservedEvent):
|
|
1422
|
+
runtime_effect = workflow_event.observation.style_rewrite_effect
|
|
1423
|
+
|
|
1424
|
+
if runtime_effect is not None:
|
|
1425
|
+
payload = dict(runtime_effect.payload)
|
|
1426
|
+
if "kind" not in payload:
|
|
1427
|
+
payload["kind"] = "style_rewrite"
|
|
1428
|
+
return WorkflowEffect(
|
|
1429
|
+
workflow=workflow_event.workflow,
|
|
1430
|
+
run_id=workflow_event.run_id,
|
|
1431
|
+
effect_id="fix-wiki-style-rewrite-specialist",
|
|
1432
|
+
origin_state=origin_state.value,
|
|
1433
|
+
kind=WorkflowEffectKind.CALL_SPECIALIST_MODEL,
|
|
1434
|
+
target="med-knowledge-architect",
|
|
1435
|
+
payload=payload,
|
|
1436
|
+
requires_receipt=True,
|
|
1437
|
+
requires_attestation=True,
|
|
1438
|
+
model_policy=_style_rewrite_model_policy(runtime_effect.model_policy),
|
|
1439
|
+
)
|
|
1440
|
+
return WorkflowEffect(
|
|
1441
|
+
workflow=workflow_event.workflow,
|
|
1442
|
+
run_id=workflow_event.run_id,
|
|
1443
|
+
effect_id="fix-wiki-style-rewrite-specialist",
|
|
1444
|
+
origin_state=origin_state.value,
|
|
1445
|
+
kind=WorkflowEffectKind.CALL_SPECIALIST_MODEL,
|
|
1446
|
+
target="med-knowledge-architect",
|
|
1447
|
+
payload=_payload("style_rewrite"),
|
|
1448
|
+
requires_receipt=True,
|
|
1449
|
+
requires_attestation=True,
|
|
1450
|
+
model_policy=_style_rewrite_model_policy(),
|
|
1451
|
+
)
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
def _style_rewrite_model_policy(override: JsonObject | None = None) -> JsonObject:
|
|
1455
|
+
"""Keep specialist policy canonical even when runtime supplied batch data."""
|
|
1456
|
+
|
|
1457
|
+
policy = {
|
|
1458
|
+
"policy": "medical_specialist_authoring.v1",
|
|
1459
|
+
"required_model_tier": "specialist",
|
|
1460
|
+
"preferred_model_tier": "pro",
|
|
1461
|
+
"forbid_flash_fallback": True,
|
|
1462
|
+
}
|
|
1463
|
+
if override:
|
|
1464
|
+
policy.update(override)
|
|
1465
|
+
policy["forbid_flash_fallback"] = True
|
|
1466
|
+
policy["required_model_tier"] = "specialist"
|
|
1467
|
+
return policy
|
|
1468
|
+
|
|
1469
|
+
|
|
1470
|
+
def _related_notes_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1471
|
+
return WorkflowEffect(
|
|
1472
|
+
workflow=workflow_event.workflow,
|
|
1473
|
+
run_id=workflow_event.run_id,
|
|
1474
|
+
effect_id="fix-wiki-related-notes-export",
|
|
1475
|
+
origin_state=origin_state.value,
|
|
1476
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1477
|
+
target="related_notes.export",
|
|
1478
|
+
payload=RelatedNotesExportEffectPayload(reason_code="related_notes").to_payload(),
|
|
1479
|
+
requires_receipt=False,
|
|
1480
|
+
no_resource_mutation=True,
|
|
1481
|
+
)
|
|
1482
|
+
|
|
1483
|
+
|
|
1484
|
+
def _link_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1485
|
+
runtime_effect: WorkflowEffect | None = None
|
|
1486
|
+
if isinstance(workflow_event, RuntimeObservedEvent):
|
|
1487
|
+
runtime_effect = workflow_event.observation.link_effect
|
|
1488
|
+
if runtime_effect is not None:
|
|
1489
|
+
payload = dict(runtime_effect.payload)
|
|
1490
|
+
return WorkflowEffect(
|
|
1491
|
+
workflow=workflow_event.workflow,
|
|
1492
|
+
run_id=workflow_event.run_id,
|
|
1493
|
+
effect_id="fix-wiki-link-run",
|
|
1494
|
+
origin_state=origin_state.value,
|
|
1495
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1496
|
+
target="/mednotes:link",
|
|
1497
|
+
payload=payload,
|
|
1498
|
+
mutates_resources=True,
|
|
1499
|
+
rollback_declared=True,
|
|
1500
|
+
requires_receipt=False,
|
|
1501
|
+
)
|
|
1502
|
+
payload = LinkWorkflowRunEffectPayload(
|
|
1503
|
+
kind="link_run",
|
|
1504
|
+
diagnose=False,
|
|
1505
|
+
apply=True,
|
|
1506
|
+
no_related_notes=False,
|
|
1507
|
+
).to_payload()
|
|
1508
|
+
return WorkflowEffect(
|
|
1509
|
+
workflow=workflow_event.workflow,
|
|
1510
|
+
run_id=workflow_event.run_id,
|
|
1511
|
+
effect_id="fix-wiki-link-run",
|
|
1512
|
+
origin_state=origin_state.value,
|
|
1513
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1514
|
+
target="/mednotes:link",
|
|
1515
|
+
payload=payload,
|
|
1516
|
+
mutates_resources=True,
|
|
1517
|
+
rollback_declared=True,
|
|
1518
|
+
requires_receipt=False,
|
|
1519
|
+
)
|
|
1520
|
+
|
|
1521
|
+
|
|
1522
|
+
def _wait_external_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1523
|
+
target = (
|
|
1524
|
+
"related_notes.quota"
|
|
1525
|
+
if origin_state == FixWikiState.RELATED_NOTES_QUOTA_WAIT
|
|
1526
|
+
else "specialist_model.capacity"
|
|
1527
|
+
)
|
|
1528
|
+
resume_action = "Retomar pela rota oficial depois que a condição externa estiver resolvida."
|
|
1529
|
+
payload = WaitExternalEffectPayload(
|
|
1530
|
+
wait_target=target,
|
|
1531
|
+
blocked_reason=reason_for_state(origin_state).value,
|
|
1532
|
+
next_action=resume_action,
|
|
1533
|
+
resume_supported=True,
|
|
1534
|
+
).to_payload()
|
|
1535
|
+
if isinstance(workflow_event, RelatedNotesQuotaWaitEvent):
|
|
1536
|
+
recovery_state = workflow_event.related_notes_recovery_state
|
|
1537
|
+
elif isinstance(workflow_event, RuntimeObservedEvent) and origin_state == FixWikiState.RELATED_NOTES_QUOTA_WAIT:
|
|
1538
|
+
recovery_state = workflow_event.observation.related_notes_recovery_state
|
|
1539
|
+
else:
|
|
1540
|
+
recovery_state = None
|
|
1541
|
+
if recovery_state is not None:
|
|
1542
|
+
if not recovery_state.status:
|
|
1543
|
+
recovery_state = RelatedNotesRecoveryStateEffectPayload.from_payload(
|
|
1544
|
+
{
|
|
1545
|
+
"schema": "medical-notes-workbench.related-notes-recovery-state.v1",
|
|
1546
|
+
"status": "waiting_for_retry",
|
|
1547
|
+
"blocked_reason": "related_notes_headless_quota_exhausted",
|
|
1548
|
+
"next_action": resume_action,
|
|
1549
|
+
"resume_supported": True,
|
|
1550
|
+
}
|
|
1551
|
+
)
|
|
1552
|
+
if isinstance(workflow_event, RuntimeObservedEvent):
|
|
1553
|
+
resume_action = recovery_state.next_action or workflow_event.observation.next_action or resume_action
|
|
1554
|
+
else:
|
|
1555
|
+
resume_action = recovery_state.next_action or resume_action
|
|
1556
|
+
payload = WaitExternalEffectPayload.model_validate(
|
|
1557
|
+
{
|
|
1558
|
+
"wait_target": target,
|
|
1559
|
+
"related_notes_recovery_state": recovery_state,
|
|
1560
|
+
"next_action": resume_action,
|
|
1561
|
+
}
|
|
1562
|
+
).to_payload()
|
|
1563
|
+
return WorkflowEffect(
|
|
1564
|
+
workflow=workflow_event.workflow,
|
|
1565
|
+
run_id=workflow_event.run_id,
|
|
1566
|
+
effect_id=f"fix-wiki-{origin_state.value.replace('.', '-')}-wait",
|
|
1567
|
+
origin_state=origin_state.value,
|
|
1568
|
+
kind=WorkflowEffectKind.WAIT_EXTERNAL,
|
|
1569
|
+
target=target,
|
|
1570
|
+
payload=payload,
|
|
1571
|
+
requires_receipt=False,
|
|
1572
|
+
no_resource_mutation=True,
|
|
1573
|
+
resume_action=resume_action,
|
|
1574
|
+
)
|
|
1575
|
+
|
|
1576
|
+
|
|
1577
|
+
def _final_validation_effect(workflow_event: FixWikiEvent, origin_state: FixWikiState) -> WorkflowEffect:
|
|
1578
|
+
return WorkflowEffect(
|
|
1579
|
+
workflow=workflow_event.workflow,
|
|
1580
|
+
run_id=workflow_event.run_id,
|
|
1581
|
+
effect_id="fix-wiki-final-validation",
|
|
1582
|
+
origin_state=origin_state.value,
|
|
1583
|
+
kind=WorkflowEffectKind.RUN_SUBWORKFLOW,
|
|
1584
|
+
target="fix_wiki.final_validation",
|
|
1585
|
+
payload=_payload("final_validation"),
|
|
1586
|
+
requires_receipt=False,
|
|
1587
|
+
no_resource_mutation=True,
|
|
1588
|
+
)
|