feat: working on alignment to bDS - MCP proposal lifecycle
This commit is contained in:
@@ -1,13 +1,16 @@
|
|||||||
# Alignment Tasks
|
# Alignment Tasks
|
||||||
|
|
||||||
|
Allium CLI: `/opt/homebrew/bin/allium`. Use `allium check specs/<file>.allium` only when tending a spec; no Allium command is needed for code-only alignment tasks.
|
||||||
|
|
||||||
Goal: align bDS2 with old bDS behavior. Use the Allium specs as the contract only where they match old bDS. If old bDS and bDS2 agree but the spec differs, tend the spec.
|
Goal: align bDS2 with old bDS behavior. Use the Allium specs as the contract only where they match old bDS. If old bDS and bDS2 agree but the spec differs, tend the spec.
|
||||||
|
|
||||||
## P0: MCP Proposal Lifecycle
|
## P0: MCP Proposal Lifecycle (done)
|
||||||
|
|
||||||
- Old bDS: proposals are in-memory and removed after `accept_proposal` or `discard_proposal`.
|
- Old bDS: proposals are in-memory and removed after `accept_proposal` or `discard_proposal`.
|
||||||
- bDS2 now: proposals are persisted and marked `accepted` / `discarded`.
|
- bDS2 now: proposals are persisted and marked `accepted` / `discarded`.
|
||||||
- Spec: matches old bDS; accepted/discarded proposals should no longer exist.
|
- Spec: matches old bDS; accepted/discarded proposals should no longer exist.
|
||||||
- Action: change bDS2 to remove accepted/discarded proposals, update tests, and remove/adjust terminal-status expectations.
|
- Action: change bDS2 to remove accepted/discarded proposals, update tests, and remove/adjust terminal-status expectations.
|
||||||
|
- Status: done.
|
||||||
|
|
||||||
## P0: MCP Cursor Resources
|
## P0: MCP Cursor Resources
|
||||||
|
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ defmodule BDS.MCP.ProposalStore do
|
|||||||
Enum.map(expired, &Repo.get(Proposal, &1.id))
|
Enum.map(expired, &Repo.get(Proposal, &1.id))
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_accepted(id) when is_binary(id), do: mark_status(id, :accepted)
|
def mark_accepted(id) when is_binary(id), do: remove(id)
|
||||||
def mark_discarded(id) when is_binary(id), do: mark_status(id, :discarded)
|
def mark_discarded(id) when is_binary(id), do: remove(id)
|
||||||
|
|
||||||
defp mark_status(id, status) do
|
defp mark_status(id, status) do
|
||||||
case Repo.get(Proposal, id) do
|
case Repo.get(Proposal, id) do
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ use "./template.allium" as template
|
|||||||
|
|
||||||
enum ProposalStatus {
|
enum ProposalStatus {
|
||||||
pending
|
pending
|
||||||
accepted
|
|
||||||
discarded
|
|
||||||
expired
|
expired
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,8 +47,6 @@ entity Proposal {
|
|||||||
is_expired: expires_at <= now
|
is_expired: expires_at <= now
|
||||||
|
|
||||||
transitions status {
|
transitions status {
|
||||||
pending -> accepted
|
|
||||||
pending -> discarded
|
|
||||||
pending -> expired
|
pending -> expired
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,7 +338,6 @@ rule AcceptProposal {
|
|||||||
media/UpdateMediaRequested(proposal.target_media, deserialize_media_changes(proposal.data))
|
media/UpdateMediaRequested(proposal.target_media, deserialize_media_changes(proposal.data))
|
||||||
if proposal.kind = propose_post_metadata:
|
if proposal.kind = propose_post_metadata:
|
||||||
post/UpdatePostRequested(proposal.target_post, deserialize_post_changes(proposal.data))
|
post/UpdatePostRequested(proposal.target_post, deserialize_post_changes(proposal.data))
|
||||||
proposal.status = accepted
|
|
||||||
not exists proposal
|
not exists proposal
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +350,6 @@ rule DiscardProposal {
|
|||||||
script/DeleteScriptRequested(proposal.proposed_script)
|
script/DeleteScriptRequested(proposal.proposed_script)
|
||||||
if proposal.kind = propose_template:
|
if proposal.kind = propose_template:
|
||||||
template/DeleteTemplateRequested(proposal.proposed_template)
|
template/DeleteTemplateRequested(proposal.proposed_template)
|
||||||
proposal.status = discarded
|
|
||||||
not exists proposal
|
not exists proposal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ defmodule BDS.MCPTest do
|
|||||||
assert_raise Ecto.NoResultsError, fn -> BDS.Posts.get_post!(draft_post_id) end
|
assert_raise Ecto.NoResultsError, fn -> BDS.Posts.get_post!(draft_post_id) end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "proposal lifecycle is persisted with pending, accepted, discarded, and expired statuses" do
|
test "proposal lifecycle removes accepted and discarded proposals" do
|
||||||
assert {:ok, accepted_result} =
|
assert {:ok, accepted_result} =
|
||||||
BDS.MCP.call_tool("draft_post", %{title: "Accept Me", content: "Body"})
|
BDS.MCP.call_tool("draft_post", %{title: "Accept Me", content: "Body"})
|
||||||
|
|
||||||
@@ -188,19 +188,14 @@ defmodule BDS.MCPTest do
|
|||||||
assert ProposalStore.get(accepted_id).status == :pending
|
assert ProposalStore.get(accepted_id).status == :pending
|
||||||
|
|
||||||
assert {:ok, _accepted} = BDS.MCP.call_tool("accept_proposal", %{proposalId: accepted_id})
|
assert {:ok, _accepted} = BDS.MCP.call_tool("accept_proposal", %{proposalId: accepted_id})
|
||||||
|
assert ProposalStore.get(accepted_id) == nil
|
||||||
accepted_proposal = ProposalStore.get(accepted_id)
|
|
||||||
assert accepted_proposal.status == :accepted
|
|
||||||
assert accepted_proposal.entity_id == accepted_result["post"]["id"]
|
|
||||||
|
|
||||||
assert {:ok, discarded_result} =
|
assert {:ok, discarded_result} =
|
||||||
BDS.MCP.call_tool("draft_post", %{title: "Discard Me Later", content: "Body"})
|
BDS.MCP.call_tool("draft_post", %{title: "Discard Me Later", content: "Body"})
|
||||||
|
|
||||||
discarded_id = discarded_result["proposal_id"]
|
discarded_id = discarded_result["proposal_id"]
|
||||||
assert {:ok, _discarded} = BDS.MCP.call_tool("discard_proposal", %{proposalId: discarded_id})
|
assert {:ok, _discarded} = BDS.MCP.call_tool("discard_proposal", %{proposalId: discarded_id})
|
||||||
|
assert ProposalStore.get(discarded_id) == nil
|
||||||
discarded_proposal = ProposalStore.get(discarded_id)
|
|
||||||
assert discarded_proposal.status == :discarded
|
|
||||||
|
|
||||||
expired =
|
expired =
|
||||||
ProposalStore.create("draft_post", %{"post_id" => "expired-post"},
|
ProposalStore.create("draft_post", %{"post_id" => "expired-post"},
|
||||||
|
|||||||
Reference in New Issue
Block a user