migrate text id's to int #15
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_shrimp#15
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
in line to other services, we try to use autoincrement int's (u32, but in sqlite i64)
we also found in this codebase there are some mix up's in the DB, this will fix this too
Migration spec: text IDs →
i64autoincrement integersBranch:
development_idIssue: #15
Strategy: wipe-and-replace, no data migration. After this lands, on first
service_shrimp start --cleareveryone gets a fresh integer-keyed DB.1. Goals
TEXTbecomesINTEGER PRIMARY KEY AUTOINCREMENT(SQLiteINTEGER=i64).SessionId,RunId, conversation/run/phase/etc. on the wire) becomes a wrapper aroundi64, notString.integer.SessionIdtypes are unified.2. Non-goals
service_shrimp start --clear. There is no ALTER TABLE / move-data-into-new-schema path.ClientIdstaysString. It identifies an external client install, not a row PK.PhaseIdstaysString. It's a label (e.g."runtime","reflect"), not a row primary key. There is nophasestable.String—external_id(idempotency keys),dedup_key,user_idinuser_profiles,cache_key,briefings.date. Same for the user-facingcrypto.uuid_v4Rhai tool — that's a tool output for users, not a hero_shrimp row identifier.format!("run:{run_id}:phase:runtime:attempt:1"). After the migration,run_idinside that format is ani64, but the resulting string is still a string.3. Wire-format change (OpenRPC)
Every field below in
crates/hero_shrimp_types/src/openrpc.jsonflips from"type": "string"to"type": "integer"(with"format": "int64").session.createparams.conversation_id,result.session_id,result.conversation_idsession.closeparams.session_idsession.listresult.sessions[].id,result.sessions[].conversation_idsession.subscribeparams.session_id,result.subscription_idsession.cancelparams.session_idmessage.sendparams.session_idmessage.listparams.conversation_idtool.callparams.session_idaudit.listparams.session_idrun.cancel,run.files,run.file,run.execution_control,run.rollback_file,run.commit,run.bundle,run.workspace_bundleparams.run_iddoai.startparams.session_iddoai.follow_upparams.run_id,params.session_iddoai.statusparams.run_idAlready integer (no change):
memory.update_status,memory.drilldown,episode.drilldown,playbook.export.Result schemas typed as
"object"/array-of-object inherit the change automatically when the Rust struct fields flip toi64and serde re-serializes — but the OpenRPC schema should also be tightened to declare the integer type explicitly. Out of scope for the first PR if it bloats the diff; flag as follow-up.4. Schema change (SQLite)
crates/hero_shrimp_store/src/db/. Before-and-after, tables only:Tables whose PK changes from
TEXT→INTEGER PRIMARY KEY AUTOINCREMENTschema.rsconversations,subagent_jobs,detached_tasks,task_flowssessions.rssessionsautonomy_runs.rsautonomy_runscouncil.rscouncil_sessionsdreams.rsdream_cyclesprojects.rsprojectsscheduled_jobs.rsscheduled_jobsTables whose PK is the FK of another table (1:1 satellite tables) — PK becomes
INTEGERmatching the parentconversation_briefs.rsconversation_briefs(conversation_idPK)conversationsrun_briefs.rsrun_briefs(run_idPK)autonomy_runsrun_state.rsrun_state_snapshots(run_idPK)autonomy_runsForeign-key columns that change from
TEXT NOT NULL→INTEGER NOT NULLschema.rsaudit_logrun_id,session_id(phase_idstays TEXT — it's a label)schema.rsmemoriessource_run_id(andsource_phase_idstays TEXT)schema.rsmemory_outboxconversation_id,run_idschema.rssubagent_jobsparent_id(self),related_run_idschema.rsdetached_tasksflow_id,related_run_id,parent_task_idschema.rstask_flowsrelated_run_id,root_task_idcouncil.rscouncil_positionssession_id(councilor_idstays TEXT — string label)autonomy_runs.rsautonomy_runsparent_run_id(self)dreams.rsdream_insights,dream_open_questionscycle_idartifacts.rsphase_artifactsrun_idmigrations.rsconversation_compactionsconversation_idconversation_briefs.rsconversation_briefsproject_idTables NOT changing (already integer, or correctly using TEXT for natural keys)
✅ Already integer:
messages,audit_logPK,usage_log,skill_usage_log,memories,memory_recalls,memory_outbox,council_positions,dream_insights,dream_open_questions,autonomy_lessons,memory_episodes,memory_playbooks,phase_artifacts,todos,conversation_compactions,user_facts.✅ Correctly TEXT (natural / external keys):
briefings.date,tool_cache.cache_key,inbound_dedup.dedup_key,tool_invocations.key,secrets.key,state.key,user_profiles.user_id.5. Newtype changes (
hero_shrimp_types)Unify
SessionIdToday there are two:
proto::ids::SessionId(String)anddomain::ids::SessionId(String). Keep one inproto::ids, deletedomain::ids::SessionId, re-export fromdomain::idsso existing imports keep working.Newtype inner type changes
proto::ids::SessionIdStringi64domain::ids::RunIdStringi64domain::ids::PhaseIdStringString(label, not PK)proto::ids::ClientIdStringString(external identity)Other ID-bearing fields in the types crate (drop directly to
i64, no newtype)proto/rpc.rs:74SessionInit.conversation_idOption<String>Option<i64>proto/rpc.rs:92SessionSummary.conversation_idOption<String>Option<i64>domain/state_store.rs:5RunStateSnapshot.run_idStringi64domain/run.rs:64,103,219,220,233,249run_id/left_run_id/right_run_id/job_idStringi64(each)domain/run.rs(same file)phase_idinstancesStringStringdomain/contracts.rs:32requirement_idStringi64domain/contracts.rs:35phase_idOption<String>Option<String>6. ID-generation strategy
Today there are ~15 places that mint or derive IDs by
format!. The migration introduces a small number of canonical mint sites in the store crate, and replaces every formerformat!site that produced a row PK with one of:Database::lookup_or_create_session(channel: &str, user_key: &str) -> i64— replacesformat!("session:cli:{n}"),format!("session:admin:{n}"),format!("session:whatsapp:chat:{chat_id}"),format!("session:telegram:chat:{chat_id}"),format!("session:schedule:{schedule_name}"). Inserts on miss usingINSERT ... RETURNING id. The(channel, user_key)pair is stored on the row and reads use it directly instead of parsing the id string.Database::next_autonomy_run_id() -> i64— replaces whereverrequested_autonomy_run_idwas injected as a string. Implementation:INSERT INTO autonomy_runs(...) RETURNING id.Database::next_conversation_id() -> i64— replacesformat!("run:{run_id}")insertions intoconversations. SameINSERT ... RETURNING idpattern.Idempotency-scope strings (e.g.
format!("run:{run_id}:phase:runtime:attempt:1")) keep usingformat!; the substitutedrun_idis nowi64. The resulting string is still used as a string key intool_invocationsetc.Graph-edge labels (
db/work_history.rs:50,db/conversation_graph.rs:93,102doingformat!("run:{}", run_id)) keep being strings — they're not row PKs, they're typed edge tags in a graph store. Those tags now embed an integer instead of a UUID. The string"run:42"is just as good as the string"run:UUID-..."for graph-edge purposes.7. RPC handlers (
hero_shrimp_server)crates/hero_shrimp_server/src/rpc/jsonrpc.rs— single 5600-line file.optional_i64(params: &Value, key: &str) -> Option<i64>next to existingoptional_string. Same forrequire_i64.optional_string(params, "session_id" | "run_id" | "conversation_id" | "subscription_id")with the integer variant.method_session_create,method_session_close,method_session_list,method_session_subscribe,method_session_cancel,method_message_send,method_message_list,method_audit_list,method_tool_call,method_run_status,method_run_files,method_run_file,method_run_execution_control,method_run_rollback_file,method_run_commit,method_run_bundle,method_run_workspace_bundle,method_doai_start,method_doai_follow_up,method_doai_status.serde_json::json!({...})macros need no change beyond passing the integer values —serde_jsonserializesi64as a JSON number automatically."session:cli:1"etc. need updating.8. Engine (
hero_shrimp_engine)Per-file change list (these are the intent edits — the rest is mechanical):
src/engine_client/in_process.rs:56— replaceSessionId::new(format!(...))with a call todb.lookup_or_create_session(channel, user_key) -> SessionId(i64).src/pipeline.rs:29,63,67,296,300— everyformat!("session:...")andformat!("run:...")site: drop the format if it produced a row PK; keep it if it produced an idempotency-scope string with the inner ID nowi64.src/autonomy.rs:177-212—requested_autonomy_run_id(&ToolContext) -> Option<i64>(wasOption<String>); parse the integer instead of the string.src/autonomy/persistence.rs:120,222,src/autonomy/promote.rs:183,188,src/subagents.rs:306,326,356,src/agent/mod.rs:166,src/execution_control.rs:1175,1179,1684,1726— all idempotency/graph-label format strings; just propagate the type change of the embedded ID.src/gateways/whatsapp.rs:314,src/gateways/telegram.rs:490,src/schedules.rs:158— channel-specific session creation: replace theformat!mint withdb.lookup_or_create_session(channel, user_key).src/gateways/admin/filters.rs:129—from == format!("run:{run_id}")graph-walk match:run_idis nowi64, the format produces"run:42", comparison still works structurally — but audit this site: it relies on the string-id format being predictable.src/gateways/admin/routes/chat.rs:139— same.EngineClienttrait method whose signature mentionsSessionId/RunId— signature change is automatic once the newtype's inner changes; affects in-process and any out-of-process implementations.9. CLI (
hero_shrimpbinary — manager + client)src/main.rs:151—Cancel { session_id: String }→i64. Change clap tovalue_parser = clap::value_parser!(i64).src/main.rs:205,272-294,317,326—session_idplumbing throughrun_send/run_cancel. Type signatures change; print sites useDisplay(already implemented on the newtype).src/tui.rs:117,140,169,213,223,310—AppState.session_id: String → i64; format strings usingsession_idneed.to_string()or rely onDisplay.10. UI (
hero_shrimp_ui)src/routes.rs:252,287—RunFileDownloadQuery { run_id: String }andRunDownloadQuery { run_id: String }→i64. Axum'sQuery<>+ serde will deserialize numeric query strings asi64if the target field isi64.src/routes.rs:269,300,325— JSON forwarding to backend; serde handles the type switch.static/js/dashboard.js:850— breaking change:conversation_id: \ui-${kind}-${nonce}`is a client-supplied string. After migration, the UI must callsession.create*without* aconversation_id` and use the integer the server returns.static/js/dashboard.jsother sites — IDs flow through as JS numbers (JSON numbers parse to JS numbers); call sites pass them back unchanged. Audit any===comparisons that today assume string equality (none found in survey, but worth a grep before merging).templates/*.html) — none interpolate IDs directly. No change.11. SDK (
hero_shrimp_sdk)Auto-generated from
openrpc.jsonviaopenrpc_client!macro. Onceopenrpc.jsonis updated, the SDK regenerates automatically on nextcargo build. No manual edits. Consumers of the SDK incrates/hero_shrimp_examples/will fail to compile until their call sites are fixed; treat as part of the migration.12. Test plan
db/*.rsmodule hasmod tests(~20 fixture sites use hardcoded string IDs like"run:test-1"). Update each to usei64literals from freshly-minted IDs (INSERT ... RETURNING) or fixed integer literals.crates/hero_shrimp_examples/tests/integration.rs::test_openrpc_spec_validalready verifies the spec parses. Add: walk every method, assert that ID-typed params/results are"type": "integer".session.create → message.send → session.closewith real integer IDs over HTTP/UDS.hero_shrimp send "hi"must complete;hero_shrimp cancel <int>must accept an integer.13. Rollout (wipe-and-replace)
Strict ordering:
development_idwith all changes squashed.service_shrimp start --reset --clear. The--clearwipes the existingdefault.dbwhose schema is incompatible.development_id→development.--clear. Any saved sessions / runs / memories from before are gone.The wipe is mandatory because the schema migration goes from
TEXT PRIMARY KEYtoINTEGER PRIMARY KEY AUTOINCREMENT— SQLite has no in-place ALTER for that. Adding a migration path was considered and rejected per Issue #15: data lifetime in this DB is short, value of preserving old rows is low.14. Sanity checks called out for the reviewer
format!("session:cli:{n}")today encodes the channel name in the ID string. Thesessions.channelcolumn already stores it separately, so the migration preserves the information — but every code site that today doesif id.starts_with("session:cli:")(or grep equivalents) must be replaced by reading.channelfrom the row. Survey lists call sites; PR must address every one.SessionIdtypes. Don't leave both in the tree post-migration. If domain layer needs richer invariants, that's a separate refactor — the migration's job is to unify on the integer wire type.requirement_idindomain::contracts. Migrating toi64along with everything else (decided 2026-04-30 in this thread). Ifrequirement_idis currently a runtime-only field with no SQLite table backing it, the change is purely type-level — no schema work. If arequirementstable is later added, give itINTEGER PRIMARY KEY AUTOINCREMENTfrom the start.phase_idstaysString. Nophasestable exists. If the team later adds one with anINTEGER PRIMARY KEY, do that change in a separate PR — it's larger than it looks becausephase_idis referenced from many FK columns.EngineClientimpls. Survey only inspectedInProcessEngineClient. If any out-of-process implementation exists outside this repo, it needs updating in lockstep.rg -n '"(run|session|flow):[a-z0-9_:-]*"' crates/before declaring done.15. Estimated PR size
hero_shrimp_types: ~5 files, ~50 LOC delta + openrpc.json changeshero_shrimp_store: ~30 files, ~600 LOC delta (mostly mechanical query/RowMapper updates)hero_shrimp_engine: ~15 files, ~80 LOC delta (most call sites are leaf format!s that stay)hero_shrimp_server: 1 file (rpc/jsonrpc.rs), ~150 LOC deltahero_shrimp(CLI): 2 files, ~20 LOChero_shrimp_ui: 2 files (routes.rs,dashboard.js), ~10 LOCTotal: ~900 LOC, single squashed PR.
Implementation Spec for Issue #15
Objective
Migrate internal database and API identifiers for sessions and runs from text IDs to autoincrementing integer IDs, using a wipe-and-replace rollout with no data migration. Preserve string IDs for natural, external, or scoped identifiers such as
ClientId,PhaseId, external IDs, cache keys, dedup keys, conversation IDs, user IDs, and channel names.Requirements
sessions,autonomy_runs,run_briefs, andrun_state_snapshotsmust becomeINTEGER PRIMARY KEY AUTOINCREMENT.SessionIdandRunIdmust serialize as JSON integers and map cleanly to SQLitei64.PhaseIdmust remain a string.SessionIddefinitions indomain::idsandproto::idsmust be unified.session_id,run_id, and related result fields must useintegerwithformat: int64.ClientId,PhaseId,conversation_id,external_id,idempotency_key,cache_key,dedup_key,from_user,user_id, and channel names.as_i64()instead ofas_str()for session/run IDs.crates/hero_shrimp/src/main.rs,crates/hero_shrimp/src/tui.rs,crates/hero_shrimp_server/src/rpc/jsonrpc.rs, andscripts/service_shrimp.nu; implementation should avoid overwriting unrelated edits in those files.Files to Modify/Create
crates/hero_shrimp_types/src/domain/ids.rscrates/hero_shrimp_types/src/proto/ids.rscrates/hero_shrimp_types/src/proto/rpc.rscrates/hero_shrimp_types/src/proto/events.rscrates/hero_shrimp_types/src/domain/state_store.rscrates/hero_shrimp_types/src/domain/run.rscrates/hero_shrimp_types/src/openrpc.jsoncrates/hero_shrimp_types/src/openrpc.client.generated.rscrates/hero_shrimp_store/src/db/schema.rscrates/hero_shrimp_store/src/db/sessions.rscrates/hero_shrimp_store/src/db/autonomy_runs.rscrates/hero_shrimp_store/src/db/run_briefs.rscrates/hero_shrimp_store/src/db/run_state.rscrates/hero_shrimp_store/src/db/artifacts.rscrates/hero_shrimp_store/src/db/types.rscrates/hero_shrimp_store/src/db/work_history.rscrates/hero_shrimp_store/src/runtime_artifacts.rscrates/hero_shrimp_store/src/runtime_context.rscrates/hero_shrimp_store/src/events.rscrates/hero_shrimp_store/src/inbound.rscrates/hero_shrimp_engine/src/engine_client/mod.rscrates/hero_shrimp_engine/src/engine_client/in_process.rscrates/hero_shrimp_engine/src/engine_client/rpc_client.rscrates/hero_shrimp_engine/src/runtime_state.rscrates/hero_shrimp_engine/src/types.rscrates/hero_shrimp_engine/src/pipeline.rscrates/hero_shrimp_engine/src/autonomy.rscrates/hero_shrimp_engine/src/agent/context.rscrates/hero_shrimp_engine/src/agent/persistence.rscrates/hero_shrimp_server/src/lib.rscrates/hero_shrimp_server/src/main.rscrates/hero_shrimp_server/src/rpc/jsonrpc.rscrates/hero_shrimp/src/main.rscrates/hero_shrimp/src/tui.rscrates/hero_shrimp/src/service.rscrates/hero_shrimp_ui/static/js/dashboard.jscrates/hero_shrimp_sdk/src/lib.rscrates/hero_shrimp_examples/examples/basic_usage.rscrates/hero_shrimp_examples/tests/integration.rscrates/hero_shrimp_types/src/proto/tests.rscrates/hero_shrimp_store/src/db/tests/core.rscrates/**/tests/*.rsfiles that currently assert string session/run IDsImplementation Plan
Step 1: Unify ID Types and Numeric Serialization
Files:
crates/hero_shrimp_types/src/domain/ids.rs,crates/hero_shrimp_types/src/proto/ids.rs,crates/hero_shrimp_types/src/proto/rpc.rs,crates/hero_shrimp_types/src/proto/events.rs,crates/hero_shrimp_types/src/domain/state_store.rs,crates/hero_shrimp_types/src/domain/run.rsSessionId(pub String)andRunId(pub String)with integer-backed newtypes, preferablyi64to match SQLite and OpenRPCint64.PhaseId(pub String)unchanged.SessionIdimplementation by re-exporting or importing the domainSessionId.as_str()callers for numeric IDs withvalue(),as_i64(), orto_string()only at file/path/logging boundaries.ClientIdas string inproto::ids.Dependencies: none
Step 2: Change Core SQLite Schemas to Autoincrement Integers
Files:
crates/hero_shrimp_store/src/db/sessions.rs,crates/hero_shrimp_store/src/db/autonomy_runs.rs,crates/hero_shrimp_store/src/db/run_briefs.rs,crates/hero_shrimp_store/src/db/run_state.rs,crates/hero_shrimp_store/src/db/artifacts.rs,crates/hero_shrimp_store/src/db/types.rs,crates/hero_shrimp_store/src/db/schema.rssessions.idfromTEXT PRIMARY KEYtoINTEGER PRIMARY KEY AUTOINCREMENT.autonomy_runs.idfromTEXT PRIMARY KEYtoINTEGER PRIMARY KEY AUTOINCREMENT.run_briefs.run_idandrun_state_snapshots.run_idto integer references keyed by run ID.phase_artifacts.run_idto integer while keepingphase_artifacts.phase_id TEXT.i64.parent_run_idonly if it is truly an external/natural link; otherwise convert it to nullable integer consistently withautonomy_runs.id.phase_id,source_phase_id,conversation_id,related_run_idif they are external/natural or workspace-facing identifiers.Dependencies: Step 1
Step 3: Add Explicit Wipe-and-Replace Startup Path
Files:
crates/hero_shrimp_server/src/lib.rs,crates/hero_shrimp_server/src/main.rs,crates/hero_shrimp/src/main.rs,crates/hero_shrimp/src/service.rs--clearhandling for startup rollout.hero_shrimp --start --clearremoves the configured SQLite database before registering/restarting services.hero_shrimp_server --cleardaemon startup also clears the DB beforeDatabase::open.Dependencies: Step 2
Step 4: Allocate Session IDs from SQLite
Files:
crates/hero_shrimp_store/src/db/sessions.rs,crates/hero_shrimp_engine/src/engine_client/in_process.rs,crates/hero_shrimp_engine/src/engine_client/mod.rs,crates/hero_shrimp_server/src/rpc/jsonrpc.rssession:cli:<nonce>with SQLite-created integer IDs.InProcessEngineClient::create_sessionto allocate through the DB instead of generating a string.channel,user_key, and metadata separate so channel values do not leak into encoded session IDs.SessionId.Dependencies: Step 2
Step 5: Allocate Run IDs from SQLite and Preserve Artifact Path Compatibility
Files:
crates/hero_shrimp_store/src/db/autonomy_runs.rs,crates/hero_shrimp_store/src/db/run_briefs.rs,crates/hero_shrimp_store/src/db/run_state.rs,crates/hero_shrimp_store/src/runtime_artifacts.rs,crates/hero_shrimp_engine/src/autonomy.rs,crates/hero_shrimp_server/src/rpc/jsonrpc.rsAutonomyRunRow,RunBriefRow, andRunStateSnapshotRowto use integer run IDs.artifact_run_idas a separate string only where it refers to an existing filesystem/live-run directory identifier.Dependencies: Step 2
Step 6: Update RPC Parsing and Responses
Files:
crates/hero_shrimp_server/src/rpc/jsonrpc.rssession_idandrun_id.session.create,session.close,session.cancel,session.subscribe,message.send,audit.list,tool.call,doai.start,doai.follow_up,doai.status,run.cancel,run.files,run.file,run.execution_control,run.rollback_file,run.commit,run.bundle, andrun.workspace_bundle.session_id,run_id, and rowidfields where the ID is DB-owned.phase_id,conversation_id,artifact_run_id, cache keys, dedup keys, and external IDs as strings.optional_stringand add numeric equivalents where needed.Dependencies: Step 4, Step 5
Step 7: Update OpenRPC and Generated SDK Surface
Files:
crates/hero_shrimp_types/src/openrpc.json,crates/hero_shrimp_types/src/openrpc.client.generated.rs,crates/hero_shrimp_sdk/src/lib.rs,crates/hero_shrimp_examples/examples/basic_usage.rs,crates/hero_shrimp_examples/tests/integration.rssession_id,run_id, DB rowid, and subscription IDs fromstringto{ "type": "integer", "format": "int64" }.phase_id,conversation_id,workspace_path,artifact_run_id, and natural/external identifiers as strings.session_idas an integer.Dependencies: Step 6
Step 8: Update CLI and TUI Clients
Files:
crates/hero_shrimp/src/main.rs,crates/hero_shrimp/src/tui.rscancel <session>parsing from string to integer.session_idfromsession.createresponses with numeric JSON access.session_idvalues inmessage.send,session.close, andsession.cancel.Dependencies: Step 7
Step 9: Update Admin UI JavaScript
Files:
crates/hero_shrimp_ui/static/js/dashboard.jssession_idandrun_idas numbers in RPC params.runId,runSessionId,runArtifactRunId,selectRun, console session handling, cancel/follow-up/run file actions, and diagnostics.phase_idcommand handling as string.Dependencies: Step 7
Step 10: Update Engine and Store ID Plumbing
Files:
crates/hero_shrimp_engine/src/runtime_state.rs,crates/hero_shrimp_engine/src/types.rs,crates/hero_shrimp_engine/src/pipeline.rs,crates/hero_shrimp_engine/src/agent/context.rs,crates/hero_shrimp_engine/src/agent/persistence.rs,crates/hero_shrimp_store/src/runtime_context.rs,crates/hero_shrimp_store/src/events.rs,crates/hero_shrimp_store/src/inbound.rs,crates/hero_shrimp_store/src/db/work_history.rsexternal_idand idempotency keys as strings.session_idandrun_idcolumns where converted.Dependencies: Step 6
Step 11: Update Tests and Fixtures
Files:
crates/hero_shrimp_types/src/proto/tests.rs,crates/hero_shrimp_store/src/db/tests/core.rs, relevantcrates/**/tests/*.rs"session":1.PhaseIdstays string.--clearwipes old incompatible schemas only when explicitly requested.Dependencies: Step 10
Step 12: Verification
Files:
Cargo.toml, all modified cratescargo check --workspace.hero_shrimp_types,hero_shrimp_store,hero_shrimp_engine,hero_shrimp_server,hero_shrimp, SDK examples, and UI-adjacent RPC behavior.hero_shrimp --start --clear,hero_shrimp send,hero_shrimp cancel <numeric-session-id>,session.create,message.send,doai.start,doai.status,run.status, and UI run selection.Dependencies: Step 11
Acceptance Criteria
sessions.idandautonomy_runs.idasINTEGER PRIMARY KEY AUTOINCREMENT.hero_shrimp --start --clearand direct server clear startup paths wipe incompatible old DBs explicitly.SessionIdexists as one shared type and serializes as a JSON integer.RunIdserializes as a JSON integer.PhaseIdremains string typed in Rust, SQLite, OpenRPC, RPC handlers, and UI code.session_idandrun_id.session_idandrun_idvalues for endpoints whose schema is now integer.Notes
crates/hero_shrimp/src/main.rs,crates/hero_shrimp/src/tui.rs,crates/hero_shrimp_server/src/rpc/jsonrpc.rs, andscripts/service_shrimp.nu.artifact_run_idexplicit where filesystem paths or live workspace IDs still require strings.phase_id,conversation_id,ClientId,external_id,cache_key,dedup_key,from_user, anduser_idshould remain strings.