refactor(management): replace LangGraph with native PostgreSQL state runner #113
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "refactor/112-remove-langgraph"
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?
Closes #112.
What changed
bot_sessionstable inschema.tsand migration0014_safe_arachne.sqldropping LangGraph checkpoint tables.runner.tsand pure domain types instate.ts.lib/bot/tools/.bot_sessionswith 60-minute session expiry.@langchain/core,@langchain/langgraph,@langchain/langgraph-checkpoint-postgres,@langchain/openrouter,langchain,langfuse-langchain) and 21 transitive dependencies.graph.ts,checkpointer.ts,cleanup-turn-state.ts, andreply.ts.Verified
pnpm --filter=garage exec tsc --noEmit: 0 errorspnpm --filter=garage test: 19 test files passed (431 tests)pnpm --filter=garage test lib/bot/: 2 test files passed (11 tests).forgejo/scripts/biome-gate.sh: PASSED (32 findings vs 34 baseline)Deviations
None.
VERDICT: request-changes
apps/management/lib/bot/runner.ts:L116: blocker: Two distinct confirmation messages can both read the same AWAITING_CONFIRM session before either clears it, executing the purchase/order twice; webhook deduplication only covers the same message ID. Atomically claim/lock the session before executing an action.
apps/management/lib/bot/nodes/classify-intent.ts:L285: blocker: The new order filter accepts a missing selling price as 0, so an LLM extraction without price can confirm and save a free sale while depleting stock. Require a positive price for every item and clarify rather than silently omitting it.
apps/management/lib/bot/nodes/classify-intent.ts:L297: should: Casting any model-provided orderStatus to OrderStatus allows invalid values into the unconstrained orders.status column; status-based revenue reports omit those orders. Validate against OrderStatusEnum and fall back to menunggu as before.
apps/management/lib/bot/runner.ts:L246: should: A clarification reply is followed by a fresh classification using only the next message; the former pendingIntent and conversation are no longer persisted, so replies like an item name after a purchase clarification lose the command context. Persist the pending intent/context in bot_sessions and supply it to classification.
apps/management/lib/bot/runner.ts:L116: should: A receipt image with caption ya during purchase confirmation takes the confirmation branch and executes the old action before the media branch sees the image. Prioritize receipt media before interpreting the caption as confirmation.
apps/management/lib/db/schema.ts:L278: should: The new state varchar accepts arbitrary values rather than the specified IDLE/AWAITING_CONFIRM states, and the runner does not repair unknown states on conflict. Add a DB enum or CHECK constraint in schema and migration.
The migration and six dependency removals are present. PR metadata reports 19 passing test files and a passing baseline biome gate, but does not show a pnpm verify:management run; I did not rerun tests or checks in this read-only review.
round 1 addressed
VERDICT: request-changes
[P2] Preserve a recoverable claim until execution is resolved (
apps/management/lib/bot/runner.ts:142). The new confirmation claim setsstate: IDLEandpendingAction: nullbeforeexecuteAction. If execution fails before writing (for example,executePurchaseNodecallsfindInventoryByPrefixoutside its try/catch and that lookup rejects), the webhook sends a generic error but the confirmed purchase is now permanently absent frombot_sessions; another "ya" is treated as a new message, so the operator must reconstruct/resend the purchase or receipt. Previously that failure left the pending action available. Keep the claim exclusive without discarding the action until execution has reached a recoverable outcome, and ensure failures before a write can be retried safely.The price/status guards, media-first ordering, and matching schema/migration CHECK constraint address the other Round 1 requests.
round 2 addressed
VERDICT: request-changes
apps/management/lib/bot/runner.ts:161-170 — The catch also covers messenger.send. If the gateway fetch fails after executeAction has committed, restoring AWAITING_CONFIRM lets a second confirmation repeat a successful purchase/order/stock adjustment. Catch only execution failures; do not make an already-committed action retryable when reply delivery fails.
apps/management/lib/bot/runner.ts:157-166 — After the confirmation claim sets the row to IDLE, a concurrent message from the same phone can create a new pending action. The newly added unconditional completion update clears that newer action (or the failure branch reinstates the old one), losing a request already offered for confirmation. Scope both follow-up updates to the claimed session or serialize per-phone processing.
round 3 addressed
VERDICT: approve
Round 4: The successful action and gateway reply are now separated, so a send failure no longer restores the pending action. The claim-scoped session updates also avoid overwriting a session that changed while execution ran. No new blocking issue found in
f9acc91.Pre-merge verification summary
approve(Review #110)pr.mergeable:truef9acc91:pnpm --filter=garage exec tsc --noEmit: 0 errorspnpm --filter=garage test: 19 test files passed (431 tests).forgejo/scripts/biome-gate.sh: PASSED (32 findings vs 34 baseline)Checks / test garage,Checks / test @garage/catalog,Checks / test garage-store,Checks / typecheck apps/store,Checks / typecheck apps/management,Checks / lint (biome))