mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-01 23:43:16 +01:00
fix: scope status-card deletion notifications to its company
This commit is contained in:
1 parent
cd4caaab26
commit
32044a63e1
3 files changed
+42
-2
No files matched your search
@@ -135,3 +135,9 @@ scheduled work after settlement. Real issue/comment producer acceptance measures
|
||||
due/next queries and actual searches under 100 writes, preserves both companies'
|
||||
hints, dispatches another company's saved deadline inside the batching window,
|
||||
and checks SQL quietness after authorized results.
|
||||
|
||||
Card deletion resolves the card's owning company and emits only that company's
|
||||
deadline-reconstruction hint. Every card mutation requires a company ID; only
|
||||
instance-level settings retain wildcard ingress. Deleting an already-missing
|
||||
card emits no hint. The real two-company regression proves deletion does not
|
||||
re-run unchanged reactive searches or wake either summarizer, then stays quiet.
|
||||
@@ -144,6 +144,38 @@ const support = external ? { supported: true } : await getEmbeddedPostgresTestSu
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps card deletion scoped to its company and a missing deletion quiet", async () => {
|
||||
const removed = await card();
|
||||
await card();
|
||||
const ownCompany = companyId, ownAgent = agentId;
|
||||
companyId = randomUUID(); agentId = randomUUID();
|
||||
await db.insert(companies).values({ id: companyId, name: "Other", issuePrefix: `O${companyId.slice(0, 6)}` });
|
||||
await db.insert(agents).values({ id: agentId, companyId, name: "Other summarizer", role: "general", status: "idle", adapterType: "process", adapterConfig: {} });
|
||||
const other = await card();
|
||||
companyId = ownCompany; agentId = ownAgent;
|
||||
const factory = companySearch.companySearchService;
|
||||
const searchedCompanies: string[] = [];
|
||||
vi.spyOn(companySearch, "companySearchService").mockImplementation(owner => {
|
||||
const search = factory(owner), actual = search.search;
|
||||
search.search = async (...args) => { searchedCompanies.push(args[0]); return actual(...args); };
|
||||
return search;
|
||||
});
|
||||
await start(); await quiet(); searchedCompanies.length = 0;
|
||||
const cards = statusCardService(db);
|
||||
expect(await cards.remove(removed.id)).toMatchObject({ id: removed.id, companyId: ownCompany });
|
||||
await settled();
|
||||
// Deleting a card only reconstructs deadlines; it is not an issue change
|
||||
// that warrants re-running any unchanged reactive card's saved search.
|
||||
expect(searchedCompanies).toEqual([]);
|
||||
expect(await cards.getById(other.id)).toMatchObject({ nextEvalAt: null, generatingIssueId: null, pendingChangeCount: 0 });
|
||||
expect(wakeup).not.toHaveBeenCalled();
|
||||
searchedCompanies.length = 0;
|
||||
expect(await cards.remove(removed.id)).toBeNull();
|
||||
await quiet();
|
||||
expect(searchedCompanies).toEqual([]);
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
|
||||
it("coalesces one hundred committed source writes without delaying another company's saved deadline", async () => {
|
||||
const reactive = await card();
|
||||
const originalCompany = companyId, originalAgent = agentId;
|
||||
|
||||
@@ -158,7 +158,7 @@ export function statusCardService(
|
||||
const issuesSvc = () => deps.issuesSvc ?? issueService(db);
|
||||
const searchSvc = companySearchService(db);
|
||||
type Transaction = Parameters<Parameters<Db["transaction"]>[0]>[0];
|
||||
function mutate<T>(companyId: string | undefined, write: (tx: Transaction) => Promise<T>) {
|
||||
function mutate<T>(companyId: string, write: (tx: Transaction) => Promise<T>) {
|
||||
return db.transaction(async tx => {
|
||||
await notifyStatusCardEvaluation(tx, companyId);
|
||||
return write(tx);
|
||||
@@ -335,7 +335,9 @@ export function statusCardService(
|
||||
}
|
||||
|
||||
async function remove(id: string) {
|
||||
return mutate(undefined, tx => tx.delete(statusCards).where(eq(statusCards.id, id)).returning().then((rows) => rows[0] ?? null));
|
||||
const card = await getById(id);
|
||||
if (!card) return null;
|
||||
return mutate(card.companyId, tx => tx.delete(statusCards).where(eq(statusCards.id, id)).returning().then((rows) => rows[0] ?? null));
|
||||
}
|
||||
|
||||
async function listUpdates(cardId: string) {
|
||||
|
||||
Reference in new issue
Block a user