Q203: automation rules that never ran are removed, so none can claim to be enabled
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a64b44e3ea
commit
9f44e0bdee
14 files changed
+23
-119
No files matched your search
@@ -5,7 +5,6 @@ const id = z.string();
|
||||
const nullableId = z.string().nullable();
|
||||
const actor = z.enum(["employee", "agent"]);
|
||||
const sender = z.enum(["employee", "agent", "board", "system"]);
|
||||
const settings = z.record(z.string(), z.unknown());
|
||||
|
||||
export const collaborationContracts = {
|
||||
createDocument: z.strictObject({
|
||||
@@ -27,15 +26,6 @@ export const collaborationContracts = {
|
||||
}) satisfies z.ZodType<C.UpdateKnowledgeEntryInput>,
|
||||
deleteKnowledgeEntry: z.strictObject({ orgId: id, entryId: id, deletedByEmployeeId: id }) satisfies z.ZodType<C.DeleteKnowledgeEntryInput>,
|
||||
listKnowledgeRevisions: z.strictObject({ orgId: id, entryId: id }) satisfies z.ZodType<C.ListKnowledgeRevisionsInput>,
|
||||
createAutomationRule: z.strictObject({
|
||||
orgId: id, name: z.string(), triggerEvent: z.string(), conditions: settings, actionType: z.string(), actionConfig: settings,
|
||||
priority: z.number(), enabled: z.boolean(),
|
||||
}) satisfies z.ZodType<C.CreateAutomationRuleInput>,
|
||||
updateAutomationRule: z.strictObject({
|
||||
orgId: id, ruleId: id, name: z.string(), triggerEvent: z.string(), conditions: settings, actionType: z.string(), actionConfig: settings,
|
||||
priority: z.number(), enabled: z.boolean(),
|
||||
}) satisfies z.ZodType<C.UpdateAutomationRuleInput>,
|
||||
deleteAutomationRule: z.strictObject({ orgId: id, ruleId: id }) satisfies z.ZodType<C.DeleteAutomationRuleInput>,
|
||||
createMeeting: z.strictObject({
|
||||
orgId: id, title: z.string(), meetingType: z.string(), scheduledAt: z.string().nullable(), durationMinutes: z.number(), agenda: z.string(),
|
||||
}) satisfies z.ZodType<C.CreateMeetingInput>,
|
||||
|
||||
@@ -23,7 +23,6 @@ import { OperationsService } from "../services/operations-service";
|
||||
import { TaskExecutionService } from "../services/task-execution-service";
|
||||
import { DocumentService } from "../services/document-service";
|
||||
import { KnowledgeService } from "../services/knowledge-service";
|
||||
import { AutomationService } from "../services/automation-service";
|
||||
import { MeetingService } from "../services/meeting-service";
|
||||
import { SprintService } from "../services/sprint-service";
|
||||
import { ComposioConnectionService } from "../services/composio/composio-connection-service";
|
||||
@@ -92,7 +91,6 @@ export function registerIpcHandlers(deps: IpcDeps): void {
|
||||
const operations = new OperationsService(deps.connection.db);
|
||||
const documents = new DocumentService(deps.connection.db);
|
||||
const knowledge = new KnowledgeService(deps.connection.db);
|
||||
const automation = new AutomationService(deps.connection.db);
|
||||
const meetingService = new MeetingService(deps.connection.db);
|
||||
const sprintService = new SprintService(deps.connection.db);
|
||||
const onboarding = new OnboardingService({
|
||||
@@ -242,9 +240,6 @@ export function registerIpcHandlers(deps: IpcDeps): void {
|
||||
revision: r.revision, topic: r.topic, category: r.category, content: r.content, importance: r.importance,
|
||||
changedByType: r.changed_by_type, changedById: r.changed_by_id, reason: r.reason, createdAt: r.created_at,
|
||||
}))));
|
||||
handle("createAutomationRule", (input) => mutate(() => automation.create(input)));
|
||||
handle("updateAutomationRule", (input) => mutate(() => automation.update(input)));
|
||||
handle("deleteAutomationRule", (input) => mutate(() => automation.delete(input)));
|
||||
handle("createMeeting", (input) => mutate(() => meetingService.create(input)));
|
||||
handle("deleteMeeting", (input) => mutate(() => meetingService.delete(input)));
|
||||
handle("createSprint", (input) => mutate(() => sprintService.create(input)));
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Automation rules were saved but never ran; the records are removed rather than kept as a promise.
|
||||
export const dropAutomationRulesSchema = `
|
||||
drop index if exists idx_automation_org;
|
||||
drop table if exists automation_rules;
|
||||
`;
|
||||
@@ -106,6 +106,7 @@ import { workLanguageSchema } from "./migrations/104-work-language";
|
||||
import { onboardingProgressSchema } from "./migrations/105-onboarding-progress";
|
||||
import { viewStateSchema } from "./migrations/106-view-state";
|
||||
import { searchPendingSchema } from "./migrations/107-search-pending";
|
||||
import { dropAutomationRulesSchema } from "./migrations/108-drop-automation-rules";
|
||||
|
||||
interface Migration {
|
||||
version: number;
|
||||
@@ -221,6 +222,7 @@ const MIGRATIONS: Migration[] = [
|
||||
{ version: 105, name: "onboarding_progress", sql: onboardingProgressSchema },
|
||||
{ version: 106, name: "view_state", sql: viewStateSchema },
|
||||
{ version: 107, name: "search_pending", sql: searchPendingSchema },
|
||||
{ version: 108, name: "drop_automation_rules", sql: dropAutomationRulesSchema },
|
||||
];
|
||||
|
||||
const SCHEMA_VERSION = MIGRATIONS[MIGRATIONS.length - 1].version;
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
import type { CreateAutomationRuleInput, UpdateAutomationRuleInput, DeleteAutomationRuleInput } from "../../shared/commands";
|
||||
import { createId } from "../../shared/ids";
|
||||
import { AuditService } from "./audit-service";
|
||||
|
||||
export class AutomationService {
|
||||
private readonly audit: AuditService;
|
||||
|
||||
constructor(private readonly db: DatabaseSync) {
|
||||
this.audit = new AuditService(db);
|
||||
}
|
||||
|
||||
create(input: CreateAutomationRuleInput): string {
|
||||
const id = createId("aut");
|
||||
const now = new Date().toISOString();
|
||||
this.db.prepare(`
|
||||
insert into automation_rules(id, org_id, name, trigger_event, condition_json, action_type, action_config_json, priority, enabled, fire_count, created_at, updated_at)
|
||||
values (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?)
|
||||
`).run(id, input.orgId, input.name.trim(), input.triggerEvent, JSON.stringify(input.conditions), input.actionType, JSON.stringify(input.actionConfig), input.priority, input.enabled ? 1 : 0, now, now);
|
||||
this.audit.record({
|
||||
orgId: input.orgId,
|
||||
entityType: "automation_rule",
|
||||
entityId: id,
|
||||
actorType: "system",
|
||||
actorId: null,
|
||||
action: "created",
|
||||
payload: { name: input.name.trim(), triggerEvent: input.triggerEvent },
|
||||
});
|
||||
return id;
|
||||
}
|
||||
|
||||
update(input: UpdateAutomationRuleInput): void {
|
||||
const result = this.db.prepare(`
|
||||
update automation_rules set name = ?, trigger_event = ?, condition_json = ?, action_type = ?, action_config_json = ?, priority = ?, enabled = ?, updated_at = ?
|
||||
where id = ? and org_id = ?
|
||||
`).run(input.name.trim(), input.triggerEvent, JSON.stringify(input.conditions), input.actionType, JSON.stringify(input.actionConfig), input.priority, input.enabled ? 1 : 0, new Date().toISOString(), input.ruleId, input.orgId);
|
||||
if (result.changes === 0) throw new Error("Automation rule was not found.");
|
||||
}
|
||||
|
||||
delete(input: DeleteAutomationRuleInput): void {
|
||||
const result = this.db.prepare("delete from automation_rules where id = ? and org_id = ?").run(input.ruleId, input.orgId);
|
||||
if (result.changes === 0) throw new Error("Automation rule was not found.");
|
||||
}
|
||||
}
|
||||
@@ -151,8 +151,6 @@ export class SnapshotService {
|
||||
auditEvents: recentInOrg<AppSnapshot["auditEvents"][number]>(this.db, "audit_events", "created_at desc", 200, activeOrgId),
|
||||
documents: list(this.db, "documents", "updated_at desc"),
|
||||
knowledgeEntries: list(this.db, "knowledge_entries", "updated_at desc"),
|
||||
automationRules: list<AppSnapshot["automationRules"][number]>(this.db, "automation_rules", "priority asc")
|
||||
.map((rule) => ({ ...rule, enabled: toBool(rule.enabled) })),
|
||||
meetings: list(this.db, "meetings", "scheduled_at desc"),
|
||||
sprints: list(this.db, "sprints", "start_date desc"),
|
||||
connectorAccounts: list(this.db, "connector_accounts", "toolkit_slug asc"),
|
||||
|
||||
Reference in new issue
Block a user