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,519 @@
|
|
|
1
|
+
"""Domain effect payloads carried by workflow effects.
|
|
2
|
+
|
|
3
|
+
These are MedNotes **domain** contracts — the concrete payloads (link subworkflow,
|
|
4
|
+
related-notes, specialist) attached to the framework's WorkflowEffect/Result
|
|
5
|
+
(which live in the pure-framework mednotes.kernel.effects). They are kept out of
|
|
6
|
+
the framework so the FSM kernel stays domain-agnostic. Layering rule: framework
|
|
7
|
+
<- domain <- adapters; enforced by tools/audit/import_layering.py.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from typing import Literal
|
|
12
|
+
|
|
13
|
+
from pydantic import Field, model_validator
|
|
14
|
+
|
|
15
|
+
from mednotes.domains.wiki.contracts.related_notes_runtime import RelatedNotesRecoveryState
|
|
16
|
+
from mednotes.domains.wiki.contracts.specialist import SpecialistTaskRunReceipt
|
|
17
|
+
from mednotes.kernel.base import ContractModel, JsonObject, JsonObjectAdapter, JsonValue
|
|
18
|
+
from mednotes.kernel.progress import WorkflowProgressViewModel
|
|
19
|
+
from mednotes.kernel.workflow import VersionControlSafety, WorkflowReceiptPayload
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LinkEffectCompletedOutcome(ContractModel):
|
|
23
|
+
"""Domain outcome for a link effect that finished with safe evidence."""
|
|
24
|
+
|
|
25
|
+
code: Literal["link.completed"] = "link.completed"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class LinkEffectBlockedOutcome(ContractModel):
|
|
29
|
+
"""Domain outcome for a link effect blocked before safe continuation."""
|
|
30
|
+
|
|
31
|
+
code: Literal["link.blocked"] = "link.blocked"
|
|
32
|
+
reason_code: str = ""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class LinkEffectGraphBlockedOutcome(ContractModel):
|
|
36
|
+
"""Domain outcome for graph-level blockers returned by the link workflow."""
|
|
37
|
+
|
|
38
|
+
code: Literal["graph_blocked"] = "graph_blocked"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class LinkEffectLinkerBlockedOutcome(ContractModel):
|
|
42
|
+
"""Domain outcome for linker/runtime blockers returned by the link workflow."""
|
|
43
|
+
|
|
44
|
+
code: Literal["linker_blocked"] = "linker_blocked"
|
|
45
|
+
reason_code: str = ""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class LinkEffectFailedOutcome(ContractModel):
|
|
49
|
+
"""Domain outcome for failed link effect execution."""
|
|
50
|
+
|
|
51
|
+
code: Literal["link.failed"] = "link.failed"
|
|
52
|
+
reason_code: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class RelatedNotesExportCompletedOutcome(ContractModel):
|
|
56
|
+
"""Domain outcome for a refreshed Related Notes export."""
|
|
57
|
+
|
|
58
|
+
code: Literal["related_notes.export_completed"] = "related_notes.export_completed"
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RelatedNotesQuotaWaitOutcome(ContractModel):
|
|
62
|
+
"""Domain outcome for resumable external waits while preserving progress."""
|
|
63
|
+
|
|
64
|
+
code: Literal["related_notes.quota_wait"] = "related_notes.quota_wait"
|
|
65
|
+
reason_code: str = ""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class RelatedNotesBlockedOutcome(ContractModel):
|
|
69
|
+
"""Domain outcome for non-resumable Related Notes blockers."""
|
|
70
|
+
|
|
71
|
+
code: Literal["related_notes.blocked"] = "related_notes.blocked"
|
|
72
|
+
reason_code: str = ""
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class RelatedNotesSyncCompletedOutcome(ContractModel):
|
|
76
|
+
"""Domain outcome for mutating Related Notes section sync."""
|
|
77
|
+
|
|
78
|
+
code: Literal["related_notes.sync_completed"] = "related_notes.sync_completed"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class RelatedNotesSyncWarningOutcome(ContractModel):
|
|
82
|
+
"""Domain outcome for non-mutating previews or warning states."""
|
|
83
|
+
|
|
84
|
+
code: Literal["related_notes.sync_warning"] = "related_notes.sync_warning"
|
|
85
|
+
reason_code: str = ""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class SpecialistModelCompletedOutcome(ContractModel):
|
|
89
|
+
"""Domain outcome for a validated specialist model receipt."""
|
|
90
|
+
|
|
91
|
+
code: Literal["style.specialist_completed"] = "style.specialist_completed"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class SpecialistModelCapacityWaitOutcome(ContractModel):
|
|
95
|
+
"""Domain outcome for resumable specialist-capacity waits."""
|
|
96
|
+
|
|
97
|
+
code: Literal["style.capacity_wait"] = "style.capacity_wait"
|
|
98
|
+
reason_code: str = ""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class SpecialistModelBlockedOutcome(ContractModel):
|
|
102
|
+
"""Domain outcome for specialist output that cannot be applied."""
|
|
103
|
+
|
|
104
|
+
code: Literal["style.blocked"] = "style.blocked"
|
|
105
|
+
reason_code: str = ""
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class WaitExternalEffectOutcome(ContractModel):
|
|
109
|
+
"""Domain-level wait outcome for generic resumable external waits."""
|
|
110
|
+
|
|
111
|
+
code: Literal["wait_external.waiting"] = "wait_external.waiting"
|
|
112
|
+
reason_code: str = ""
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _json_object(payload: object) -> JsonObject:
|
|
116
|
+
return JsonObjectAdapter.validate_python(payload)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _json_field(source: JsonObject, key: str, default: JsonValue = None) -> JsonValue:
|
|
120
|
+
return source[key] if key in source else default
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _text_or_empty(value: object) -> str:
|
|
124
|
+
if value is None:
|
|
125
|
+
return ""
|
|
126
|
+
if isinstance(value, str):
|
|
127
|
+
return value
|
|
128
|
+
return f"{value}"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _json_object_or_none(value: JsonValue) -> JsonObject | None:
|
|
132
|
+
return _json_object(value) if isinstance(value, dict) else None
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _json_object_or_empty(value: JsonValue) -> JsonObject:
|
|
136
|
+
return _json_object(value) if isinstance(value, dict) else {}
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _json_list_or_empty(value: JsonValue) -> list[JsonValue]:
|
|
140
|
+
return list(value) if isinstance(value, list) else []
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class LinkSubworkflowEffectPayload(ContractModel):
|
|
144
|
+
"""Typed result returned by the public `/mednotes:link` workflow adapter."""
|
|
145
|
+
|
|
146
|
+
schema_id: Literal["medical-notes-workbench.link-fsm-result.v1"] = Field(
|
|
147
|
+
default="medical-notes-workbench.link-fsm-result.v1",
|
|
148
|
+
alias="schema",
|
|
149
|
+
)
|
|
150
|
+
progress_view_model: WorkflowProgressViewModel
|
|
151
|
+
receipt: WorkflowReceiptPayload
|
|
152
|
+
reports: JsonObject
|
|
153
|
+
error_context: JsonObject = Field(default_factory=dict)
|
|
154
|
+
fsm_payload: JsonObject
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
LinkWorkflowRunKind = Literal[
|
|
158
|
+
"diagnose",
|
|
159
|
+
"link_run",
|
|
160
|
+
"vocabulary_bootstrap",
|
|
161
|
+
"agent_disambiguation",
|
|
162
|
+
"vocabulary_curator",
|
|
163
|
+
"apply_body_links",
|
|
164
|
+
"apply_related_notes",
|
|
165
|
+
"apply_vocabulary_semantic_repair",
|
|
166
|
+
]
|
|
167
|
+
LINK_WORKFLOW_DIAGNOSTIC_KINDS = frozenset(
|
|
168
|
+
{"diagnose", "vocabulary_bootstrap", "agent_disambiguation", "vocabulary_curator"}
|
|
169
|
+
)
|
|
170
|
+
LINK_WORKFLOW_APPLY_KINDS = frozenset(
|
|
171
|
+
{"link_run", "apply_body_links", "apply_related_notes", "apply_vocabulary_semantic_repair"}
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
class LinkWorkflowRunEffectPayload(ContractModel):
|
|
176
|
+
"""Typed intent for executing the public `/mednotes:link` workflow.
|
|
177
|
+
|
|
178
|
+
Parent FSMs and the link FSM itself must not ask the adapter to infer
|
|
179
|
+
mutation from loose booleans or legacy targets. This payload is the single
|
|
180
|
+
command contract consumed before `run_linker` or any equivalent adapter path
|
|
181
|
+
is allowed to touch the vault.
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
schema_id: Literal["medical-notes-workbench.link-workflow-run-effect.v1"] = Field(
|
|
185
|
+
default="medical-notes-workbench.link-workflow-run-effect.v1",
|
|
186
|
+
alias="schema",
|
|
187
|
+
)
|
|
188
|
+
kind: LinkWorkflowRunKind
|
|
189
|
+
diagnose: bool = Field(strict=True)
|
|
190
|
+
apply: bool = Field(strict=True)
|
|
191
|
+
diagnosis_path: str = ""
|
|
192
|
+
receipt_path: str = ""
|
|
193
|
+
trigger_context_path: str = ""
|
|
194
|
+
no_related_notes: bool = Field(default=False, strict=True)
|
|
195
|
+
force_diagnose: bool = Field(default=False, strict=True)
|
|
196
|
+
llm_disambiguation: str = "auto"
|
|
197
|
+
llm_model: str = ""
|
|
198
|
+
llm_timeout: int = Field(default=120, ge=1, strict=True)
|
|
199
|
+
db_path: str = ""
|
|
200
|
+
work_item_count: int = Field(default=0, ge=0, strict=True)
|
|
201
|
+
batch_plan_path: str = ""
|
|
202
|
+
# Mutating parent workflows pass the guard receipt as a first-class field so
|
|
203
|
+
# the adapter does not have to infer safety from opaque operation payloads.
|
|
204
|
+
version_control_safety: VersionControlSafety | None = None
|
|
205
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
206
|
+
|
|
207
|
+
@model_validator(mode="after")
|
|
208
|
+
def _run_linker_mode_must_be_explicit(self) -> LinkWorkflowRunEffectPayload:
|
|
209
|
+
if self.diagnose == self.apply:
|
|
210
|
+
raise ValueError("link workflow effect requires exactly one of diagnose/apply")
|
|
211
|
+
if self.kind in LINK_WORKFLOW_DIAGNOSTIC_KINDS and not self.diagnose:
|
|
212
|
+
raise ValueError(f"link workflow effect kind {self.kind!r} requires diagnose mode")
|
|
213
|
+
if self.kind in LINK_WORKFLOW_APPLY_KINDS and not self.apply:
|
|
214
|
+
raise ValueError(f"link workflow effect kind {self.kind!r} requires apply mode")
|
|
215
|
+
return self
|
|
216
|
+
|
|
217
|
+
@classmethod
|
|
218
|
+
def from_effect_payload(cls, payload: object) -> LinkWorkflowRunEffectPayload:
|
|
219
|
+
operation_payload = _json_object(payload)
|
|
220
|
+
return cls.model_validate(
|
|
221
|
+
{
|
|
222
|
+
"schema": _json_field(operation_payload, "schema")
|
|
223
|
+
or "medical-notes-workbench.link-workflow-run-effect.v1",
|
|
224
|
+
"kind": _json_field(operation_payload, "kind"),
|
|
225
|
+
"diagnose": _json_field(operation_payload, "diagnose"),
|
|
226
|
+
"apply": _json_field(operation_payload, "apply"),
|
|
227
|
+
"diagnosis_path": _json_field(operation_payload, "diagnosis_path", ""),
|
|
228
|
+
"receipt_path": _json_field(operation_payload, "receipt_path", ""),
|
|
229
|
+
"trigger_context_path": _json_field(operation_payload, "trigger_context_path", ""),
|
|
230
|
+
"no_related_notes": _json_field(operation_payload, "no_related_notes", False),
|
|
231
|
+
"force_diagnose": _json_field(operation_payload, "force_diagnose", False),
|
|
232
|
+
"llm_disambiguation": _json_field(operation_payload, "llm_disambiguation", "auto"),
|
|
233
|
+
"llm_model": _json_field(operation_payload, "llm_model", ""),
|
|
234
|
+
"llm_timeout": _json_field(operation_payload, "llm_timeout", 120),
|
|
235
|
+
"db_path": _json_field(operation_payload, "db_path", ""),
|
|
236
|
+
"work_item_count": _json_field(operation_payload, "work_item_count", 0),
|
|
237
|
+
"batch_plan_path": _json_field(operation_payload, "batch_plan_path", ""),
|
|
238
|
+
"version_control_safety": _json_field(operation_payload, "version_control_safety"),
|
|
239
|
+
"operation_payload": operation_payload,
|
|
240
|
+
}
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class RelatedNotesRecoveryStateEffectPayload(RelatedNotesRecoveryState):
|
|
245
|
+
"""Effect-facing alias of the canonical Related Notes recovery state.
|
|
246
|
+
|
|
247
|
+
The wait-external adapter must validate the same recovery payload emitted by
|
|
248
|
+
link, link-related and fix-wiki. Keeping this as a subclass preserves the
|
|
249
|
+
effect schema name while avoiding a narrower parallel contract.
|
|
250
|
+
"""
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
class WaitExternalEffectPayload(ContractModel):
|
|
254
|
+
"""Typed intent payload for an actual resumable external wait.
|
|
255
|
+
|
|
256
|
+
This prevents adapters from converting an arbitrary loose payload into
|
|
257
|
+
`waiting_external`. Related Notes waits carry their full recovery state;
|
|
258
|
+
other external waits carry an explicit target/blocker/resume contract.
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
schema_id: Literal["medical-notes-workbench.wait-external-effect-payload.v1"] = Field(
|
|
262
|
+
default="medical-notes-workbench.wait-external-effect-payload.v1",
|
|
263
|
+
alias="schema",
|
|
264
|
+
)
|
|
265
|
+
kind: Literal["wait_external"] = "wait_external"
|
|
266
|
+
related_notes_recovery_state: RelatedNotesRecoveryStateEffectPayload | None = None
|
|
267
|
+
wait_target: str = ""
|
|
268
|
+
blocked_reason: str = ""
|
|
269
|
+
next_action: str = ""
|
|
270
|
+
resume_supported: bool = Field(default=True, strict=True)
|
|
271
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
272
|
+
|
|
273
|
+
@model_validator(mode="after")
|
|
274
|
+
def _external_wait_requires_resumable_state(self) -> WaitExternalEffectPayload:
|
|
275
|
+
if not self.resume_supported:
|
|
276
|
+
raise ValueError("wait_external effect requires resume_supported")
|
|
277
|
+
if self.related_notes_recovery_state is not None:
|
|
278
|
+
if self.related_notes_recovery_state.status != "waiting_for_retry":
|
|
279
|
+
raise ValueError("wait_external effect requires waiting_for_retry recovery state")
|
|
280
|
+
if not self.related_notes_recovery_state.resume_supported:
|
|
281
|
+
raise ValueError("wait_external effect requires resume_supported recovery state")
|
|
282
|
+
if not self.related_notes_recovery_state.blocked_reason:
|
|
283
|
+
raise ValueError("wait_external effect requires blocked_reason")
|
|
284
|
+
return self
|
|
285
|
+
if not self.wait_target:
|
|
286
|
+
raise ValueError("wait_external effect requires wait_target when no recovery state exists")
|
|
287
|
+
if not self.blocked_reason:
|
|
288
|
+
raise ValueError("wait_external effect requires blocked_reason")
|
|
289
|
+
return self
|
|
290
|
+
|
|
291
|
+
@classmethod
|
|
292
|
+
def from_effect_payload(cls, payload: object) -> WaitExternalEffectPayload:
|
|
293
|
+
operation_payload = _json_object(payload)
|
|
294
|
+
return cls.model_validate(
|
|
295
|
+
{
|
|
296
|
+
"schema": _json_field(operation_payload, "schema")
|
|
297
|
+
or "medical-notes-workbench.wait-external-effect-payload.v1",
|
|
298
|
+
"kind": _json_field(operation_payload, "kind", "wait_external"),
|
|
299
|
+
"related_notes_recovery_state": _json_field(operation_payload, "related_notes_recovery_state"),
|
|
300
|
+
"wait_target": _json_field(operation_payload, "wait_target", ""),
|
|
301
|
+
"blocked_reason": _json_field(operation_payload, "blocked_reason", ""),
|
|
302
|
+
"next_action": _json_field(operation_payload, "next_action", ""),
|
|
303
|
+
"resume_supported": _json_field(operation_payload, "resume_supported", True),
|
|
304
|
+
"operation_payload": operation_payload,
|
|
305
|
+
}
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class RelatedNotesSyncSectionEffectPayload(ContractModel):
|
|
310
|
+
"""Typed intent for applying the Related Notes section sync.
|
|
311
|
+
|
|
312
|
+
The operation result uses `RelatedNotesSyncEffectPayload`; this class is the
|
|
313
|
+
FSM-owned command payload that decides whether the adapter may mutate.
|
|
314
|
+
"""
|
|
315
|
+
|
|
316
|
+
schema_id: Literal["medical-notes-workbench.related-notes-sync-section-effect.v1"] = Field(
|
|
317
|
+
default="medical-notes-workbench.related-notes-sync-section-effect.v1",
|
|
318
|
+
alias="schema",
|
|
319
|
+
)
|
|
320
|
+
kind: Literal["sync_related_notes_section"] = "sync_related_notes_section"
|
|
321
|
+
apply: bool = Field(strict=True)
|
|
322
|
+
export_path: str = ""
|
|
323
|
+
receipt_path: str = ""
|
|
324
|
+
min_score: float = 0.2
|
|
325
|
+
max_links: int = Field(default=10, ge=0, strict=True)
|
|
326
|
+
max_age_hours: float = 168.0
|
|
327
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
328
|
+
|
|
329
|
+
@classmethod
|
|
330
|
+
def from_effect_payload(cls, payload: object) -> RelatedNotesSyncSectionEffectPayload:
|
|
331
|
+
operation_payload = _json_object(payload)
|
|
332
|
+
return cls.model_validate(
|
|
333
|
+
{
|
|
334
|
+
"schema": _json_field(operation_payload, "schema")
|
|
335
|
+
or "medical-notes-workbench.related-notes-sync-section-effect.v1",
|
|
336
|
+
"kind": _json_field(operation_payload, "kind", "sync_related_notes_section"),
|
|
337
|
+
"apply": _json_field(operation_payload, "apply"),
|
|
338
|
+
"export_path": _json_field(operation_payload, "export_path", ""),
|
|
339
|
+
"receipt_path": _json_field(operation_payload, "receipt_path", ""),
|
|
340
|
+
"min_score": _json_field(operation_payload, "min_score", 0.2),
|
|
341
|
+
"max_links": _json_field(operation_payload, "max_links", 10),
|
|
342
|
+
"max_age_hours": _json_field(operation_payload, "max_age_hours", 168.0),
|
|
343
|
+
"operation_payload": operation_payload,
|
|
344
|
+
}
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
class RelatedNotesExportEffectPayload(ContractModel):
|
|
349
|
+
"""Typed intent for recovering or refreshing the Related Notes export.
|
|
350
|
+
|
|
351
|
+
Export recovery is non-mutating, but it still decides whether the workflow
|
|
352
|
+
can continue, must wait for quota, or needs Obsidian/user recovery. Adapters
|
|
353
|
+
must validate this command before invoking the runtime so a loose dict cannot
|
|
354
|
+
fabricate a recovery lane.
|
|
355
|
+
"""
|
|
356
|
+
|
|
357
|
+
schema_id: Literal["medical-notes-workbench.related-notes-export-effect.v1"] = Field(
|
|
358
|
+
default="medical-notes-workbench.related-notes-export-effect.v1",
|
|
359
|
+
alias="schema",
|
|
360
|
+
)
|
|
361
|
+
kind: Literal["related_notes_export"] = "related_notes_export"
|
|
362
|
+
mode: str = "auto"
|
|
363
|
+
export_path: str = ""
|
|
364
|
+
reason_code: str = ""
|
|
365
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
366
|
+
|
|
367
|
+
@model_validator(mode="after")
|
|
368
|
+
def _export_mode_must_be_explicit(self) -> RelatedNotesExportEffectPayload:
|
|
369
|
+
normalized = self.mode.replace("-", "_").strip()
|
|
370
|
+
allowed = {
|
|
371
|
+
"auto",
|
|
372
|
+
"reindex_vault",
|
|
373
|
+
"index_missing",
|
|
374
|
+
"index_missing_notes",
|
|
375
|
+
"export_only_diagnostic",
|
|
376
|
+
}
|
|
377
|
+
if normalized not in allowed:
|
|
378
|
+
raise ValueError(f"unsupported related notes export mode: {self.mode!r}")
|
|
379
|
+
return self
|
|
380
|
+
|
|
381
|
+
@classmethod
|
|
382
|
+
def from_effect_payload(cls, payload: object) -> RelatedNotesExportEffectPayload:
|
|
383
|
+
operation_payload = _json_object(payload)
|
|
384
|
+
return cls.model_validate(
|
|
385
|
+
{
|
|
386
|
+
"schema": _json_field(operation_payload, "schema")
|
|
387
|
+
or "medical-notes-workbench.related-notes-export-effect.v1",
|
|
388
|
+
"kind": _json_field(operation_payload, "kind"),
|
|
389
|
+
"mode": _json_field(operation_payload, "mode", "auto"),
|
|
390
|
+
"export_path": _json_field(operation_payload, "export_path", ""),
|
|
391
|
+
"reason_code": _json_field(operation_payload, "reason_code", ""),
|
|
392
|
+
"operation_payload": operation_payload,
|
|
393
|
+
}
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class RelatedNotesRecoveryEffectPayload(ContractModel):
|
|
398
|
+
schema_id: Literal["medical-notes-workbench.related-notes-export-recovery.v1"] = Field(
|
|
399
|
+
default="medical-notes-workbench.related-notes-export-recovery.v1",
|
|
400
|
+
alias="schema",
|
|
401
|
+
)
|
|
402
|
+
status: Literal["recovered", "completed", "blocked", "failed"]
|
|
403
|
+
blocked_reason: str = ""
|
|
404
|
+
next_action: str = ""
|
|
405
|
+
related_notes_recovery_state: RelatedNotesRecoveryStateEffectPayload | None = None
|
|
406
|
+
receipt: JsonObject | None = None
|
|
407
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
408
|
+
|
|
409
|
+
@classmethod
|
|
410
|
+
def from_operation_payload(cls, payload: object) -> RelatedNotesRecoveryEffectPayload:
|
|
411
|
+
operation_payload = _json_object(payload)
|
|
412
|
+
receipt = _json_object_or_none(_json_field(operation_payload, "receipt"))
|
|
413
|
+
return cls.model_validate(
|
|
414
|
+
{
|
|
415
|
+
"schema": _json_field(operation_payload, "schema")
|
|
416
|
+
or "medical-notes-workbench.related-notes-export-recovery.v1",
|
|
417
|
+
"status": _json_field(operation_payload, "status"),
|
|
418
|
+
"blocked_reason": _json_field(operation_payload, "blocked_reason", ""),
|
|
419
|
+
"next_action": _json_field(operation_payload, "next_action", ""),
|
|
420
|
+
"related_notes_recovery_state": _json_field(operation_payload, "related_notes_recovery_state"),
|
|
421
|
+
"receipt": receipt,
|
|
422
|
+
"operation_payload": operation_payload,
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
class RelatedNotesSyncEffectPayload(ContractModel):
|
|
428
|
+
schema_id: Literal["medical-notes-workbench.related-notes-sync.v1"] = Field(
|
|
429
|
+
default="medical-notes-workbench.related-notes-sync.v1",
|
|
430
|
+
alias="schema",
|
|
431
|
+
)
|
|
432
|
+
status: Literal["completed", "preview_ready", "completed_with_warnings", "blocked", "skipped"]
|
|
433
|
+
phase: str = ""
|
|
434
|
+
blocked_reason: str = ""
|
|
435
|
+
next_action: str = ""
|
|
436
|
+
applied_note_count: int = Field(default=0, ge=0, strict=True)
|
|
437
|
+
updates: list[JsonObject] = Field(default_factory=list)
|
|
438
|
+
receipt: JsonObject | None = None
|
|
439
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
440
|
+
|
|
441
|
+
@model_validator(mode="after")
|
|
442
|
+
def _completed_requires_receipt(self) -> RelatedNotesSyncEffectPayload:
|
|
443
|
+
if self.status == "completed" and self.receipt is None:
|
|
444
|
+
raise ValueError("completed related notes sync effect payload requires receipt")
|
|
445
|
+
return self
|
|
446
|
+
|
|
447
|
+
@classmethod
|
|
448
|
+
def from_operation_payload(cls, payload: object) -> RelatedNotesSyncEffectPayload:
|
|
449
|
+
operation_payload = _json_object(payload)
|
|
450
|
+
updates = _json_list_or_empty(_json_field(operation_payload, "updates"))
|
|
451
|
+
receipt = _json_object_or_none(_json_field(operation_payload, "receipt"))
|
|
452
|
+
return cls.model_validate(
|
|
453
|
+
{
|
|
454
|
+
"schema": _json_field(operation_payload, "schema") or "medical-notes-workbench.related-notes-sync.v1",
|
|
455
|
+
"status": _json_field(operation_payload, "status"),
|
|
456
|
+
"phase": _json_field(operation_payload, "phase", ""),
|
|
457
|
+
"blocked_reason": _json_field(operation_payload, "blocked_reason", ""),
|
|
458
|
+
"next_action": _json_field(operation_payload, "next_action", ""),
|
|
459
|
+
"applied_note_count": _json_field(operation_payload, "applied_note_count", 0),
|
|
460
|
+
"updates": updates,
|
|
461
|
+
"receipt": receipt,
|
|
462
|
+
"operation_payload": operation_payload,
|
|
463
|
+
}
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
class SpecialistModelEffectPayload(ContractModel):
|
|
468
|
+
schema_id: Literal["medical-notes-workbench.specialist-model-effect-payload.v1"] = Field(
|
|
469
|
+
default="medical-notes-workbench.specialist-model-effect-payload.v1",
|
|
470
|
+
alias="schema",
|
|
471
|
+
)
|
|
472
|
+
status: str = Field(min_length=1)
|
|
473
|
+
blocked_reason: str = ""
|
|
474
|
+
payload: JsonObject = Field(default_factory=dict)
|
|
475
|
+
receipt: SpecialistTaskRunReceipt | None = None
|
|
476
|
+
attestation: JsonObject | None = None
|
|
477
|
+
next_action: str = ""
|
|
478
|
+
required_inputs: list[str] = Field(default_factory=list)
|
|
479
|
+
operation_payload: JsonObject = Field(default_factory=dict)
|
|
480
|
+
|
|
481
|
+
@model_validator(mode="after")
|
|
482
|
+
def _completed_requires_receipt_and_attestation(self) -> SpecialistModelEffectPayload:
|
|
483
|
+
if self.status == "completed":
|
|
484
|
+
if self.receipt is None:
|
|
485
|
+
raise ValueError("completed specialist model effect payload requires receipt")
|
|
486
|
+
if self.attestation is None:
|
|
487
|
+
raise ValueError("completed specialist model effect payload requires attestation")
|
|
488
|
+
if self.receipt.specialist_output_attestation is None:
|
|
489
|
+
raise ValueError("completed specialist model effect payload requires receipt attestation")
|
|
490
|
+
expected_attestation = self.receipt.specialist_output_attestation.to_payload()
|
|
491
|
+
if self.attestation != expected_attestation:
|
|
492
|
+
raise ValueError("completed specialist model effect payload attestation must match receipt attestation")
|
|
493
|
+
return self
|
|
494
|
+
|
|
495
|
+
@classmethod
|
|
496
|
+
def from_operation_payload(cls, payload: object) -> SpecialistModelEffectPayload:
|
|
497
|
+
operation_payload = _json_object(payload)
|
|
498
|
+
specialist_payload = _json_object_or_empty(_json_field(operation_payload, "payload"))
|
|
499
|
+
receipt_payload = _json_object_or_none(_json_field(operation_payload, "receipt"))
|
|
500
|
+
attestation = _json_object_or_none(_json_field(operation_payload, "attestation"))
|
|
501
|
+
receipt = (
|
|
502
|
+
SpecialistTaskRunReceipt.from_operation_payload(receipt_payload)
|
|
503
|
+
if receipt_payload is not None
|
|
504
|
+
else None
|
|
505
|
+
)
|
|
506
|
+
return cls.model_validate(
|
|
507
|
+
{
|
|
508
|
+
"schema": _json_field(operation_payload, "schema")
|
|
509
|
+
or "medical-notes-workbench.specialist-model-effect-payload.v1",
|
|
510
|
+
"status": _json_field(operation_payload, "status"),
|
|
511
|
+
"blocked_reason": _text_or_empty(_json_field(operation_payload, "blocked_reason")),
|
|
512
|
+
"payload": specialist_payload,
|
|
513
|
+
"receipt": receipt,
|
|
514
|
+
"attestation": attestation,
|
|
515
|
+
"next_action": _text_or_empty(_json_field(operation_payload, "next_action")),
|
|
516
|
+
"required_inputs": _json_list_or_empty(_json_field(operation_payload, "required_inputs")),
|
|
517
|
+
"operation_payload": operation_payload,
|
|
518
|
+
}
|
|
519
|
+
)
|