--- doc_id: DEV-202606-003 feature_id: FEAT-202606-001-unified-entry-client type: dev-progress title: Unified Entry Registration Demo Implementation Plan status: implemented owner: 医梦研发团队 created_at: 2026-06-02 updated_at: 2026-06-02 reviewers: [] related_docs: - PRD-202606-001 - DDS-202606-001 - API-202606-001 related_modules: - emoon-openplatform - emoon-ai-agent - emoon-ai-card - emoon-ai-mcp tags: - 统一入口客户端 - 挂号演示 - 开发计划 --- # Unified Entry Registration Demo Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Build a next-week demonstrable outpatient registration loop from unified Web client → AI platform → MCP tool service → SQLite Mock HIS, with card confirmation, idempotency, mock payment, and reproducible acceptance scripts. **Architecture:** Keep production-facing backend capabilities inside the existing AI platform modules. Add a separate `mock-his-service` demo service using SQLite; do not add it to the root Maven reactor and do not use MySQL. `emoon-openplatform` remains the only terminal-facing API, `emoon-ai-agent` owns routing/task orchestration, `emoon-ai-card` owns card state/actions, and `emoon-ai-mcp` owns the HIS tool facade and adapter boundary. **Tech Stack:** Java 17, Spring Boot 3, Maven, SQLite for Mock HIS, existing RuoYi-Vue-Plus backend modules, MyBatis-Plus where already used, OkHttp/RestTemplate-style HTTP adapter according to existing project conventions, JUnit 5, Maven module tests, curl-based acceptance scripts. --- ## Scope This plan implements one frozen demo flow: ```text patient message → POST /api/v1/agent/chat/stream → AgentRouter creates/continues REGISTRATION task → Dify or deterministic demo response suggests department card → card actions select department / doctor / time slot / confirm appointment → MCP tool facade calls SQLite Mock HIS → Mock HIS locks slot, creates mock payment order, marks mock paid, creates appointment → appointment-success card returns with mock label and traceId ``` Do not implement real HIS, real payment,医保,退号退费,三端完整硬件接入,舌诊,报告解读, or a public `/tasks` API in this plan. ## Existing Baseline The repo already contains useful skeletons and tests: - `emoon-openplatform/src/main/java/com/emoon/openplatform/controller/v1/AgentChatController.java` - `emoon-openplatform/src/main/java/com/emoon/openplatform/controller/v1/CardActionController.java` - `emoon-openplatform/src/main/java/com/emoon/openplatform/controller/v1/DeviceController.java` - `emoon-openplatform/src/main/java/com/emoon/openplatform/auth/HmacAuthInterceptor.java` - `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/AgentRouterService.java` - `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/AgentActionOrchestrator.java` - `emoon-infra/emoon-modules/emoon-ai/emoon-ai-card/src/main/java/com/emoon/ai/card/application/CardActionService.java` - `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/ai/mcp/application/McpToolService.java` - `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/mcp/his/client/MockHisClient.java` - `emoon-openplatform/src/test/java/com/emoon/openplatform/acceptance/TerminalMvpAcceptanceTest.java` Treat these as the starting point. Do not recreate modules that already exist. ## Task 1: Build SQLite Mock HIS Service **Files:** - Create: `mock-his-service/pom.xml` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/MockHisApplication.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/controller/PatientController.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/controller/CatalogController.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/controller/SlotController.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/controller/PaymentController.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/controller/AppointmentController.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/service/RegistrationFlowService.java` - Create: `mock-his-service/src/main/java/com/emoon/mockhis/domain/*.java` - Create: `mock-his-service/src/main/resources/application.yml` - Create: `mock-his-service/src/main/resources/schema.sql` - Create: `mock-his-service/src/main/resources/seed.sql` - Create: `mock-his-service/src/test/java/com/emoon/mockhis/RegistrationFlowServiceTest.java` - Create: `mock-his-service/src/test/java/com/emoon/mockhis/MockHisApiTest.java` - [ ] **Step 1: Write failing service tests for real HIS semantics** Add tests covering: ```java @Test void lockSlotDecreasesRemainingCountAndExpiresAfterFiveMinutes() { LockSlotResult first = service.lockSlot("slot_neuro_001", "patient_demo_001", "idem-lock-001"); assertThat(first.lockId()).isNotBlank(); assertThat(first.expiresAt()).isAfter(Instant.now()); assertThat(service.getSlot("slot_neuro_001").remainingCount()).isEqualTo(2); LockSlotResult replay = service.lockSlot("slot_neuro_001", "patient_demo_001", "idem-lock-001"); assertThat(replay.lockId()).isEqualTo(first.lockId()); assertThat(service.getSlot("slot_neuro_001").remainingCount()).isEqualTo(2); } @Test void createAppointmentRequiresPaidMockOrderAndIsIdempotent() { LockSlotResult lock = service.lockSlot("slot_neuro_001", "patient_demo_001", "idem-lock-002"); PaymentOrder order = service.createPaymentOrder(lock.lockId(), "idem-pay-001"); assertThatThrownBy(() -> service.createAppointment(lock.lockId(), order.orderId(), "idem-appt-001")) .hasMessageContaining("PAYMENT_NOT_PAID"); service.markMockPaid(order.orderId()); Appointment first = service.createAppointment(lock.lockId(), order.orderId(), "idem-appt-001"); Appointment replay = service.createAppointment(lock.lockId(), order.orderId(), "idem-appt-001"); assertThat(replay.appointmentId()).isEqualTo(first.appointmentId()); assertThat(first.mock()).isTrue(); } ``` - [ ] **Step 2: Run tests and verify they fail** Run: ```bash mvn -f mock-his-service/pom.xml -DskipTests=false test ``` Expected: compilation fails until the service, schema, and DTOs are implemented. - [ ] **Step 3: Implement SQLite schema and seed data** `schema.sql` must include these tables: ```sql create table if not exists his_patient ( patient_id text primary key, name text not null, identity_no text, phone text, created_at text not null ); create unique index if not exists uk_his_patient_identity on his_patient(identity_no) where identity_no is not null; create unique index if not exists uk_his_patient_phone on his_patient(phone) where phone is not null; create table if not exists his_department ( department_id text primary key, department_code text not null unique, name text not null, floor text not null ); create table if not exists his_doctor ( doctor_id text primary key, department_id text not null, name text not null, title text not null, specialties text not null, room text not null ); create table if not exists his_schedule ( schedule_id text primary key, doctor_id text not null, visit_date text not null, session_name text not null, amount_cent integer not null ); create table if not exists his_slot ( slot_id text primary key, schedule_id text not null, time_period text not null, total_count integer not null, remaining_count integer not null, version integer not null default 0 ); create table if not exists his_slot_lock ( lock_id text primary key, slot_id text not null, patient_id text not null, status text not null, expires_at text not null, idempotency_key text not null unique, created_at text not null ); create table if not exists his_payment_order ( order_id text primary key, lock_id text not null, amount_cent integer not null, status text not null, qr_content text not null, mock integer not null, idempotency_key text not null unique, created_at text not null ); create table if not exists his_appointment ( appointment_id text primary key, lock_id text not null, order_id text not null, appointment_no text not null, status text not null, mock integer not null, idempotency_key text not null unique, created_at text not null ); ``` Seed at least: ```text 神经内科: 李明 主任医师, 王佳 副主任医师 普通内科: 陈涛 主治医师 tomorrow morning slots: 09:30-09:45, 09:45-10:00 patient_demo_001: 张三 / 13800000000 ``` - [ ] **Step 4: Implement REST endpoints** Implement exactly these demo endpoints: ```text POST /mock-his/patients/search POST /mock-his/patients GET /mock-his/departments GET /mock-his/doctors?departmentId= GET /mock-his/schedules?doctorId=&date= POST /mock-his/slots/lock POST /mock-his/slots/release POST /mock-his/payments/orders POST /mock-his/payments/mock-paid GET /mock-his/payments/{orderId} POST /mock-his/appointments GET /mock-his/appointments/{appointmentId} ``` - [ ] **Step 5: Run Mock HIS tests** Run: ```bash mvn -f mock-his-service/pom.xml -DskipTests=false test ``` Expected: all Mock HIS tests pass. **Commit:** `feat(mock-his): add sqlite registration demo service` ## Task 2: Extend MCP Tool Facade For Registration **Files:** - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/ai/mcp/application/McpToolService.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/mcp/his/client/MockHisClient.java` - Create: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/mcp/his/domain/HisSlotLockResult.java` - Create: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/mcp/his/domain/HisPaymentOrder.java` - Create: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/main/java/com/emoon/mcp/his/domain/HisAppointment.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/ai/mcp/application/McpToolServiceTest.java` - [ ] **Step 1: Write failing MCP tests** Add tests that assert: ```java @Test void lockSlotDelegatesToMockHisAndReturnsLockId() { HisSlotLockResult result = service.lockSlot("slot_neuro_001", "patient_demo_001", "trace-001", "idem-lock-001"); assertThat(result.lockId()).startsWith("LOCK"); assertThat(result.expiresAt()).isNotNull(); } @Test void paymentAndAppointmentUseMockFlagAndIdempotencyKey() { HisPaymentOrder order = service.createPaymentOrder("LOCK202606020001", "trace-001", "idem-pay-001"); assertThat(order.qrContent()).startsWith("demo-payment://orderId="); assertThat(order.mock()).isTrue(); service.markMockPaid(order.orderId(), "trace-001"); HisAppointment appt = service.createAppointment("LOCK202606020001", order.orderId(), "trace-001", "idem-appt-001"); assertThat(appt.mock()).isTrue(); assertThat(appt.appointmentNo()).isNotBlank(); } ``` - [ ] **Step 2: Run MCP tests and verify failure** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp -DskipTests=false test ``` Expected: tests fail until new methods and DTOs exist. - [ ] **Step 3: Implement new tool methods** Add methods to `McpToolService`: ```java HisSlotLockResult lockSlot(String slotId, String patientId, String traceId, String idempotencyKey); void releaseSlot(String lockId, String traceId, String idempotencyKey); HisPaymentOrder createPaymentOrder(String lockId, String traceId, String idempotencyKey); void markMockPaid(String orderId, String traceId); HisPaymentOrder queryPaymentStatus(String orderId, String traceId); HisAppointment createAppointment(String lockId, String orderId, String traceId, String idempotencyKey); ``` These methods must log tool name, traceId, risk level, mock flag, and result status. Query methods are allowed from Dify workflow; write/financial methods must be called only from Card Action orchestration. - [ ] **Step 4: Run MCP tests** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp -DskipTests=false test ``` Expected: pass. **Commit:** `feat(mcp): add registration mock his tools` ## Task 3: Fix Card Action Registration Flow **Files:** - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/AgentActionOrchestrator.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-card/src/main/java/com/emoon/ai/card/application/CardActionService.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-card/src/main/java/com/emoon/ai/card/application/CardInstanceService.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/test/java/com/emoon/ai/agent/application/AgentActionOrchestratorTest.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-card/src/test/java/com/emoon/ai/card/application/CardActionServiceTest.java` - [ ] **Step 1: Write failing orchestration test for lock → payment → appointment** Assert the exact card sequence: ```text select_department -> doctor-selection select_doctor -> time-slot-selection select_time_slot -> confirm-appointment with lockId and expiresAt confirm_appointment -> payment-qrcode with mock qrContent mock_payment_paid -> appointment-success ``` Test expectation: ```java assertThat(confirmCard.nextCard().get("cardKey")).isEqualTo("payment-qrcode"); assertThat(paymentCard.nextCard().get("cardKey")).isEqualTo("appointment-success"); assertThat(paymentCard.nextCardData().get("mock")).isEqualTo(true); ``` - [ ] **Step 2: Run agent/card tests and verify failure** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent,emoon-infra/emoon-modules/emoon-ai/emoon-ai-card -DskipTests=false test ``` Expected: fail until the current direct `createAppointment` shortcut is replaced. - [ ] **Step 3: Implement proper action handlers** Change `AgentActionOrchestrator` behavior: ```text select_time_slot: read patientId from task context or use patient_demo_001 for demo call mcpToolService.lockSlot(slotId, patientId, traceId, idempotencyKey) patch task context with slotId, lockId, lockExpiresAt create confirm-appointment card confirm_appointment: read lockId from task context call mcpToolService.createPaymentOrder(lockId, traceId, idempotencyKey) patch task context with orderId create payment-qrcode card with mock:true mock_payment_paid: call mcpToolService.markMockPaid(orderId, traceId) call mcpToolService.createAppointment(lockId, orderId, traceId, idempotencyKey) complete task create appointment-success card with mock:true ``` Keep Card Runtime from directly calling MCP. The call chain must remain: ```text CardActionController -> CardActionService -> AgentActionOrchestrator -> McpToolService -> Mock HIS ``` - [ ] **Step 4: Enforce action idempotency** `CardActionService.submit()` must return the first result for repeated `idempotencyKey` on the same card/action. It must reject: ```text expired card completed card with a new idempotencyKey unknown actionName high-risk action without confirm:true ``` - [ ] **Step 5: Run tests** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent,emoon-infra/emoon-modules/emoon-ai/emoon-ai-card -DskipTests=false test ``` Expected: pass. **Commit:** `feat(agent): complete registration card action flow` ## Task 4: Make Agent/SSE Demo Entry Stable **Files:** - Modify: `emoon-openplatform/src/main/java/com/emoon/openplatform/controller/v1/AgentChatController.java` - Modify: `emoon-openplatform/src/main/java/com/emoon/openplatform/service/impl/AgentChatApplicationServiceImpl.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/AgentRouterService.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/TaskStateService.java` - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/application/TerminalReplyTemplateService.java` - Modify: `emoon-openplatform/src/test/java/com/emoon/openplatform/acceptance/TerminalMvpAcceptanceTest.java` - [ ] **Step 1: Add failing acceptance tests** Cover: ```text POST /agent/chat/stream with "我头疼三天想挂号" emits task_updated REGISTRATION emits message_delta emits card_created department-selection emits completed with conversationId and traceId POST /agent/chat/stream with "下午" while WAIT_SELECT_TIME_SLOT does not call DeepSeek routes to current REGISTRATION task guide_screen attempts registration emits blocked message and no registration card ``` - [ ] **Step 2: Run acceptance test and verify failure** Run: ```bash mvn -pl emoon-openplatform -DskipTests=false -Dtest=TerminalMvpAcceptanceTest test ``` Expected: fail until SSE events and task/card behavior match the frozen contract. - [ ] **Step 3: Implement stable SSE event order** The stream must emit: ```text event: task_updated event: message_delta event: message_completed event: card_created event: completed ``` For errors: ```text event: error event: completed ``` Do not expose Dify raw event names to the frontend. - [ ] **Step 4: Implement router priority** Enforce: ```text 1. device policy 2. activeTask unless explicit cancel/switch 3. waitingCard 4. deterministic registration/payment/cancel rules 5. DeepSeek JSON classification 6. clarification ``` - [ ] **Step 5: Run acceptance test** Run: ```bash mvn -pl emoon-openplatform -DskipTests=false -Dtest=TerminalMvpAcceptanceTest test ``` Expected: pass. **Commit:** `feat(openplatform): stabilize registration sse entry` ## Task 5: Wire Dify As Optional Demo Engine **Files:** - Modify: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/mcp/engine/impl/DifyAgentEngine.java` - Create: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/main/java/com/emoon/ai/agent/infrastructure/normalizer/DifyOutputNormalizer.java` - Create: `emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent/src/test/java/com/emoon/ai/agent/infrastructure/normalizer/DifyOutputNormalizerTest.java` - Modify: `docs/initiatives/FEAT-202606-001-unified-entry-client/需求文档.md` only if implementation finds a contract mismatch. - [ ] **Step 1: Write failing normalizer tests** Add tests: ```java @Test void validDepartmentCardOutputNormalizesToPlatformCard() { NormalizedAgentResponse result = normalizer.normalize(""" {"schemaVersion":"1.0","answer":"建议优先看神经内科", "taskUpdate":{"taskType":"REGISTRATION","currentStep":"TRIAGE_RECOMMEND_DEPARTMENT"}, "cards":[{"cardKey":"department-selection","cardData":{"departments":[{"departmentId":"D010","name":"神经内科","reason":"头痛伴恶心"}]}}], "safety":{"riskLevel":"LOW","needEmergencyWarning":false}} """); assertThat(result.cards()).hasSize(1); assertThat(result.cards().get(0).cardKey()).isEqualTo("department-selection"); } @Test void invalidJsonFallsBackToTextWithTraceId() { NormalizedAgentResponse result = normalizer.normalize("not json"); assertThat(result.cards()).isEmpty(); assertThat(result.degraded()).isTrue(); } ``` - [ ] **Step 2: Run normalizer tests and verify failure** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent -DskipTests=false -Dtest=DifyOutputNormalizerTest test ``` Expected: fail until the normalizer exists. - [ ] **Step 3: Implement normalizer** Normalizer rules: ```text invalid JSON -> text-only degraded response unknown cardKey -> no card, warning cardData schema mismatch -> no card, error message with traceId sensitive identity fields in Dify output -> reject card high risk output -> force confirm card or manual warning ``` - [ ] **Step 4: Configure one Dify app for demo** Use one Dify app: ```text outpatient-registration-agent ``` Branches inside the app: ```text registration_intake triage_recommendation registration_reply ``` Dify must not directly call write/financial HIS tools. Dify can suggest a card and explanation; Card Action performs writes. - [ ] **Step 5: Run agent tests** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent -DskipTests=false test ``` Expected: pass. **Commit:** `feat(agent): normalize dify registration output` ## Task 6: Add End-To-End Acceptance Scripts **Files:** - Create: `scripts/demo-registration/README.md` - Create: `scripts/demo-registration/start-demo.sh` - Create: `scripts/demo-registration/reset-mock-his.sh` - Create: `scripts/demo-registration/registration-happy-path.sh` - Create: `scripts/demo-registration/registration-edge-cases.sh` - Create: `scripts/demo-registration/assertions.sh` - [ ] **Step 1: Write executable happy-path script** `registration-happy-path.sh` must perform: ```text 1. health check Mock HIS 2. health check AI platform 3. call /agent/chat/stream with "我头疼三天,还有点恶心,想挂号" 4. extract department cardInstanceId 5. POST select_department 6. POST select_doctor 7. POST select_time_slot 8. POST confirm_appointment 9. POST mock_payment_paid 10. assert appointment-success card contains mock:true and appointmentNo ``` - [ ] **Step 2: Write edge-case script** `registration-edge-cases.sh` must cover: ```text duplicate confirm returns same result unpaid order cannot create appointment expired lock forces reselect time slot guide screen cannot register Mock HIS timeout returns error card with traceId Dify invalid JSON degrades to text and no card ``` - [ ] **Step 3: Run scripts locally** Run: ```bash bash scripts/demo-registration/reset-mock-his.sh bash scripts/demo-registration/registration-happy-path.sh bash scripts/demo-registration/registration-edge-cases.sh ``` Expected: all scripts exit 0 and print the final `traceId`, `appointmentId`, `appointmentNo`, and `mock:true`. **Commit:** `test(demo): add registration acceptance scripts` ## Task 7: Final Verification **Files:** - Review: all files changed in Tasks 1-6. - Update only if needed: `docs/initiatives/FEAT-202606-001-unified-entry-client/需求文档.md` - Update only if needed: `docs/initiatives/FEAT-202606-001-unified-entry-client/MVP接口契约.md` - [ ] **Step 1: Run module tests** Run: ```bash mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp -DskipTests=false test mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent -DskipTests=false test mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-card -DskipTests=false test mvn -pl emoon-openplatform -DskipTests=false test ``` Expected: all pass. - [ ] **Step 2: Run compile check** Run: ```bash mvn -pl emoon-openplatform -am -DskipTests compile ``` Expected: compile succeeds. - [ ] **Step 3: Run architecture test** Run: ```bash mvn -pl emoon-admin -DskipTests=false -Dprofiles.active= -Dtest=AiPlatformArchitectureTest test ``` Expected: architecture test passes. No Controller imports Mapper. No API module contains implementation classes. Card module does not call MCP directly. - [ ] **Step 4: Prepare demo evidence** Collect: ```text Mock HIS sqlite db path seed data version conversationId taskId cardInstanceId sequence traceId appointmentId appointmentNo mock:true screenshot or API response ``` **Commit:** `chore(demo): verify registration demo loop` ## Self-Review Spec coverage: - SQLite Mock HIS replaces the MySQL assumption. - Dify remains optional/controlled and cannot write HIS. - DeepSeek is a fallback classifier, not the task controller. - Card Action owns write confirmation and idempotency. - Mock payment is explicitly marked and cannot impersonate real payment. - Acceptance scripts cover happy path and core failure cases. Placeholder scan: - No unresolved placeholder terms or unspecified implementation steps remain. Type consistency: - `lockId`, `orderId`, `appointmentId`, `appointmentNo`, `traceId`, `idempotencyKey`, and `mock:true` are used consistently across Mock HIS, MCP, Card Action, and scripts. ## Execution Choice Plan complete and saved to `docs/initiatives/FEAT-202606-001-unified-entry-client/dev-progress/统一入口挂号演示实施计划.md`. Two execution options: 1. **Subagent-Driven (recommended)** - dispatch a fresh subagent per task, review between tasks, fast iteration. 2. **Inline Execution** - execute tasks in this session using executing-plans, batch execution with checkpoints. Recommended for this repo: Subagent-Driven, because Mock HIS, MCP/Card, OpenPlatform SSE, and Dify normalizer are separate review surfaces.