Spaces:
Sleeping
Sleeping
CourtMitra M1-M9 Gap Audit
Audit Date: 2026-05-29
Commit Under Review: f892836 "Implement CourtMitra autopilot roadmap"
M0 β Core Automation Loop
Status: Mostly complete. Intake, evidence, facts, legal grounding, route plan, action preview/consent, email send, reply ingestion, follow-up, resolution, ledger all have code paths. Tests green.
M1 β Rate-Limit & Action Executor Idempotency
Current:
checkRateLimitlives inaction-execution-policy.tsand is called fromexecuteAction.- Source is
submissionstable withstatus = "sent"in a rolling window.
Gaps / Bugs:
- Single source of truth risk. The comment says "counted from
submissions/action_attempts", but onlysubmissionsis queried. If the post-send DB transaction rolls back, the email was sent butsubmissionsrow is missing β under-count on retry. - Idempotency gap.
canExecuteallowsstatus === "executing". If the DB transaction fails afteremailAdapter.submitsucceeds, Inngest retries and the email is sent again because nothing blocks a second execution of an "executing" action. - Env vars undocumented.
ACTION_RATE_WINDOW_MINUTESandACTION_RATE_MAX_PER_WINDOWare not inHANDOFF.md.
Fix plan:
- Count from
action_attempts(status = "succeeded") as a fallback / dual source. - In
executeAction, query existing attempts before calling the adapter. If a non-failed attempt exists and the prior attempt has astartedAtolder than a short threshold, assume send succeeded and reconcile DB state without re-sending.
M2 β Escalation Deadline Timezone
Current:
deadline-checkercron runs hourly.escalation-policy.tsaddDays()usesnew Date(from.getTime() + days * 24 * 60 * 60 * 1000).action-executor.tssetscurrentDeadlineAt: addDays(new Date(), deadlineDays).
Gaps / Bugs:
- Timezone not Asia/Kolkata.
addDaysoperates on server-local UTC time. If the server is not in IST, deadlines drift by 5.5 hours, causing the hourly checker to fire too early or too late. - State rank mismatch.
resolution-verify.tsuses its ownSTATE_RANKmap with different numeric values (resolution_claimed: 17,resolved: 18) compared to the canonical map in other workers (resolution_claimed: 18,resolved: 19). This can cause state regression or incorrect transitions.
Fix plan:
- Create a
deadlineInKolkata(from, days)helper that computes the deadline inAsia/Kolkatatimezone. - Align
resolution-verify.tsSTATE_RANK with the canonical map used byroute-plan.ts,reply-classify.ts, etc.
M3 β Autopilot Triggers & Resolution Flow
Current:
autopilot-tickInngest function listens tomission.autopilot_tick.- Emitted by
route-plan.ts(after plan ready) andreply-classify.ts(after reply classified). runAutopilotTickuses a ToolLoopAgent with tools:halt,draftFirstAction,openParallelTracks,requestResolution,waitForUser.
Gaps / Bugs:
- Auto-claims resolution without user consent. The
requestResolutiontool creates aresolutionOutcomesrow, sets mission state toresolution_claimed, and emitsmission.resolution_claimedβ all without explicit user approval. Phase 1 spec requires user-confirmed resolution. - Missing triggers. Autopilot does NOT tick on:
mission.deadline_breached(should evaluate next step)action_executed/action_execution_failed(should decide follow-up)followup.due(should draft escalation)
- No mode-gated behavior.
autopilotModeon the mission row is read but never used. TherequestResolutiontool should be blocked in "moderate" mode.
Fix plan:
- Change
requestResolutionto emit aresolution.proposedsnapshot and wait for user confirmation, instead of auto-claiming. - Add autopilot tick emission in
escalation.ts(deadline breached) and after action execution. - Respect
autopilotMode: only auto-claim resolution in an explicit "aggressive" mode; "moderate" should always wait for user.
M4 β Parallel Tracks (routeGraph AND/OR, parent_action_id)
Current:
- Schema has
actions.parentActionIdandactions.trackLabel. draftConsentGatedActionacceptsparentActionIdandtrackLabel.openParallelTrackstool in autopilot.ts drafts up to 2 actions with different authorities.resolution-verify.tssupersedes danglingproposed/preview_ready/approvedactions on resolution.
Gaps / Bugs:
parentActionIdnever set. InopenParallelTracks, each track action is drafted withtrackLabelbutparentActionIdis alwaysnull. There is no "parent" action that spawned the parallel tracks, so the link is unused.- Route plan has no AND/OR encoding. The generated
RoutePlanStepDto[]is linear. TherouteGraphin route_rules hasnodes/edges, but the LLM-generated plan steps do not encode which steps can run in parallel. - Escalation policy ignores tracks.
getNextEscalationTieradvances linearly; it doesn't respect track boundaries. If two parallel tracks are open, escalating one should not automatically advance the other.
Fix plan:
- When
openParallelTracksopens tracks, create a synthetic "parent" action (or use the first action) and setparentActionIdon subsequent tracks. - Add
parallelGroupfield toRoutePlanStepDtoso the plan can encode parallelizable steps. - Update
getNextEscalationTierto accept an optionaltrackLabelfilter so each track escalates independently.
M5 β Settlement Flow
Current:
reply-classify.v2prompt extracts settlement offers.decideSettlementNextActioninsettlement-policy.tsrecommends accept/counter/escalate/wait.reply-classify.tsauto-drafts a counter-offer action if policy says "counter".
Gaps / Bugs:
- No settlement acceptance action. If the user wants to accept a settlement, there's no UI action or API endpoint to generate an acceptance email.
- No integration tests for settlement end-to-end. The unit tests for
settlement-policy.tsexist, but there's no test covering the reply-classify β settlement policy β draft action flow. - Counter-offer authority may be wrong.
from(the raw reply email) is used as the authority/destination, but it could be a no-reply address.
Fix plan:
- Add a settlement-accept endpoint stub and UI button.
- Add an integration test for the settlement classification β counter-offer flow.
- Document the counter-offer authority caveat.
M6 β RTI Seeds & Prompts
Current:
legal-data.tshas RTI Act 2005 chunks (Sections 6, 7, 19, 19(6)).route-rules-data.tshasgovernmentRtiRouteRulewith RTI0βRTI1βRTI2 steps.- Schema supports
issueDomain = "government".
Gaps / Bugs:
- Intake prompt missing government domain.
intake.v1prompt only lists"consumer" | "payment" | "cyber_fraud", so LLM will never classify a government/RTI grievance correctly. - No RTI-specific prompt. There is no dedicated
rti-application.v1orrti-packet.v1prompt for generating RTI application text. - No E2E test. The test suite has no fixture for a government-domain mission.
Fix plan:
- Update
intake.v1prompt to include"government"domain. - Add
rti-packet.v1prompt stub. - Add a government mission fixture to the seed/integration test data.
M7 β Voice / Indic Intake
Current:
evidence.tsroutes audio to ASR adapter, stores transcript intranscriptstable.transcriptsschema exists (Module 2 migration).- Redacted text is fed into claim extraction.
Gaps / Bugs:
- Original transcript lost.
evidence.tspassesredactedTextasrawTextto the claim extraction flow. The original unredacted transcript is stored intranscripts.textbut never preserved separately for audit. - Missing unique constraint / idempotency.
db.insert(schema.transcripts).values(...).onConflictDoNothing()has no explicit target constraint. On Inngest retry, duplicate rows could accumulate if the table has no unique index onevidenceItemId. - No language persistence for intake. ASR returns
language, but it's only stored intranscripts.language. It's not propagated to the mission'sfactsor used to trigger translation.
Fix plan:
- Store both
originalTextandredactedTextin the ASR result / evidence flow. - Add a unique index on
transcripts(evidenceItemId)(or ensure one exists) and specify the conflict target. - Propagate detected language to mission facts.
M8 β Portal Assist
Current:
portal-assist.tscontracts definePortalAssistState,PortalAssistSession, etc.- Schema has
portal_assist_sessionstable. - No Inngest function, no API controller, no UI panel.
Gaps / Bugs:
- No web session viewer. The mission page has no portal-assist panel.
- No screenshot/receipt flow. There is no endpoint to upload a receipt after a portal submission.
- No honest
receipt_verifiedpath. TheProofStateenum includesreceipt_verified, but no code path sets it. Portal actions are alwaysready_for_user_submissionoruser_confirmed_external_submission.
Fix plan:
- Add
POST /api/missions/:id/portal-receiptendpoint that accepts a receipt file and updates the action'sproofStatetoreceipt_verified. - Add a minimal portal-assist panel in the mission UI.
- Document that portal automation is manual-packet only until Browserbase/Stagehand is configured.
M9 β Swarm / Social / DPDP
Current:
- Swarm and social contracts exist (
swarm.ts,social.ts). - Schema has
entities,swarms,swarm_members,social_accounts,social_poststables. copy-ready-fallback.tssocial adapter exists.- DPDP controller exists in API.
Gaps / Bugs:
- No swarm UI on mission page.
SwarmWithEntityis imported but never rendered. - Social publisher not consent-gated.
social.tscontract hasconsentGrantId, but there's no check in the adapter or API that a social post has a valid consent grant before publishing. - DPDP consent flow incomplete. No evidence that the first-contact consent notice is actually delivered to WhatsApp/Telegram users.
Fix plan:
- Add a swarm membership opt-in stub to the mission UI.
- Add a
canPublishSocialguard that validatesconsentGrantId+ action preview hash before any social adapter call. - Document DPDP first-contact delivery in the intake flow.
Summary of Priority Fixes
| Priority | Module | Fix |
|---|---|---|
| P0 | M1 | Dual-source rate limit (submissions + attempts); executor attempt guard |
| P0 | M2 | Asia/Kolkata deadline helper; align STATE_RANK |
| P0 | M3 | Stop autopilot auto-claiming resolution; add missing tick triggers |
| P1 | M4 | Set parentActionId in openParallelTracks; add parallelGroup to steps |
| P1 | M6 | Add "government" to intake.v1 prompt |
| P1 | M7 | Preserve original transcript; fix transcript conflict target |
| P1 | M8 | Add receipt_verified endpoint stub |
| P1 | M9 | Add social publish consent guard |
| P2 | M5 | Settlement integration test |