Skip to content

Commit 5e14385

Browse files
alicodingclaude
andauthored
refactor: one durable pending-action store — the MCP park migrates up, the bespoke mechanism retires (#511)
guardrailsvc.PendingActionStore is the generic pending-action model brought up to the MCP write park's own guarantees (restart survival, retention-window sweep, at-most-once apply-on-approve, an opaque Payload for restart-safe re-dispatch). RequestGuardedAction now parks through it; mcpsvc's gated-write lifecycle (gateWrite/ResolveMCPWrite/ CancelMCPWrite/PendingMCPWrites/ResolvedMCPWrites/check_write_status) migrates onto the same store, and MCPWriteRecord plus its bespoke settings-key persistence are deleted. A settings file carrying the old mcp-pending-writes key upgrades automatically (MigrateLegacyPendingWrites, wired in main.go ahead of GuardrailService's own construction) so a user's parked write survives the upgrade. Every existing MCP-write/guardrail Go test and e2e spec passes unmodified against the new seam. 🤖 Generated with Claude Code Claude-Session: https://claude.ai/code/session_012im1JxQQV2ahnXzZDdVmZq Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent c6c9d81 commit 5e14385

12 files changed

Lines changed: 1390 additions & 505 deletions

internal/services/guardrailsvc/guardrailservice.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,34 @@ type GuardrailService struct {
5858
store settings.Store
5959
rules []guardrail.Rule
6060
comp *compositionsvc.CompositionService
61-
// guardedActionsMu guards guardedActions (guardrailservice_request.go)
62-
// -- a separate lock from mu (rule CRUD): the two protect unrelated
63-
// state, and a long-parked guarded action must never block a rule
64-
// save/list.
65-
guardedActionsMu sync.Mutex
66-
guardedActions map[string]*guardedActionRecord
61+
// pending is the durable generic pending-action store
62+
// (guardrailservice_pendingstore.go, docs/adr/0047 §5.4's follow-up)
63+
// -- its own internal lock, separate from mu (rule CRUD): the two
64+
// protect unrelated state, and a long-parked guarded action must
65+
// never block a rule save/list.
66+
pending *PendingActionStore
6767
}
6868

6969
func NewGuardrailService(store settings.Store, comp *compositionsvc.CompositionService) *GuardrailService {
70-
g := &GuardrailService{store: store, comp: comp}
70+
g := &GuardrailService{store: store, comp: comp, pending: NewPendingActionStore(store)}
7171
g.restore()
7272
g.reconcileBuiltInRules()
7373
return g
7474
}
7575

76+
// PendingActionStore exposes the shared durable pending-action store
77+
// for a caller that wants to park through the SAME persisted store this
78+
// service's own RequestGuardedAction uses (mcpsvc's SetGuardrailService
79+
// wiring, replacing its own constructor-time default -- see
80+
// millmcpservice.go's pendingActionStore field doc comment for why a
81+
// default exists at all). Go-internal wiring only, never a frontend
82+
// RPC.
83+
//
84+
//wails:ignore
85+
func (g *GuardrailService) PendingActionStore() *PendingActionStore {
86+
return g.pending
87+
}
88+
7689
func (g *GuardrailService) restore() {
7790
if raw, ok := g.store.Get(guardrailRulesKey).(string); ok && raw != "" {
7891
var rules []guardrail.Rule

0 commit comments

Comments
 (0)