@vantageos/backend-doctor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +94 -0
- package/dist/contract.d.ts +18 -0
- package/dist/contract.js +29 -0
- package/dist/coverage-cli.d.ts +2 -0
- package/dist/coverage-cli.js +17 -0
- package/dist/coverage.d.ts +32 -0
- package/dist/coverage.js +77 -0
- package/dist/detectors/oracle-axis1.d.ts +86 -0
- package/dist/detectors/oracle-axis1.js +221 -0
- package/dist/detectors/oracle-axis2.d.ts +22 -0
- package/dist/detectors/oracle-axis2.js +149 -0
- package/dist/detectors/predicates.d.ts +19 -0
- package/dist/detectors/predicates.js +334 -0
- package/dist/detectors/shared.d.ts +56 -0
- package/dist/detectors/shared.js +103 -0
- package/dist/detectors/source/_scan.d.ts +43 -0
- package/dist/detectors/source/_scan.js +82 -0
- package/dist/detectors/source/backfill.d.ts +27 -0
- package/dist/detectors/source/backfill.js +211 -0
- package/dist/detectors/source/contract.d.ts +33 -0
- package/dist/detectors/source/contract.js +385 -0
- package/dist/detectors/source/identity.d.ts +47 -0
- package/dist/detectors/source/identity.js +410 -0
- package/dist/detectors/source/jobs.d.ts +10 -0
- package/dist/detectors/source/jobs.js +209 -0
- package/dist/detectors/source/lifecycle.d.ts +6 -0
- package/dist/detectors/source/lifecycle.js +147 -0
- package/dist/detectors/source/readbudget.d.ts +6 -0
- package/dist/detectors/source/readbudget.js +133 -0
- package/dist/detectors/source/refusal.d.ts +6 -0
- package/dist/detectors/source/refusal.js +125 -0
- package/dist/detectors/source/security.d.ts +37 -0
- package/dist/detectors/source/security.js +392 -0
- package/dist/detectors/source/writesafety.d.ts +14 -0
- package/dist/detectors/source/writesafety.js +345 -0
- package/dist/detectors/standard/_doc.d.ts +66 -0
- package/dist/detectors/standard/_doc.js +152 -0
- package/dist/detectors/standard/r41-frontier.d.ts +58 -0
- package/dist/detectors/standard/r41-frontier.js +176 -0
- package/dist/detectors/standard/r46-returns-validator.d.ts +61 -0
- package/dist/detectors/standard/r46-returns-validator.js +474 -0
- package/dist/detectors/standard/standard-doc.d.ts +12 -0
- package/dist/detectors/standard/standard-doc.js +271 -0
- package/dist/detectors/structural.d.ts +14 -0
- package/dist/detectors/structural.js +83 -0
- package/dist/engine-types.d.ts +10 -0
- package/dist/engine-types.js +1 -0
- package/dist/not-checkable.d.ts +22 -0
- package/dist/not-checkable.js +37 -0
- package/dist/oracle.d.ts +33 -0
- package/dist/oracle.js +133 -0
- package/dist/registry.d.ts +11 -0
- package/dist/registry.js +140 -0
- package/dist/report.d.ts +35 -0
- package/dist/report.js +138 -0
- package/dist/severity.d.ts +30 -0
- package/dist/severity.js +121 -0
- package/dist/tally.d.ts +57 -0
- package/dist/tally.js +152 -0
- package/dist/trigger.d.ts +47 -0
- package/dist/trigger.js +143 -0
- package/fixtures/backend-standard-51ec7af1.md +648 -0
- package/fixtures/backend-standard-a9d7877b.md +629 -0
- package/fixtures/mcp-app-standard-a74a042b.md +279 -0
- package/fixtures/mcp-extension-standard-a74a042b.md +259 -0
- package/fixtures/mcp-server-standard-a74a042b.md +434 -0
- package/fixtures/mcp-standard-a74a042b.md +354 -0
- package/fixtures/vp-1200-green/.pin +1 -0
- package/fixtures/vp-1200-green/convex/migrations.ts +350 -0
- package/fixtures/vp-1200-green/convex/schema.ts +1243 -0
- package/fixtures/vp-1200-red/.pin +1 -0
- package/fixtures/vp-1200-red/convex/migrations.ts +239 -0
- package/fixtures/vp-1200-red/convex/schema.ts +1243 -0
- package/fixtures/vp-by-tool-day158.csv +190 -0
- package/fixtures/vp-convex/.github/workflows/npm-publish.yml +163 -0
- package/fixtures/vp-convex/.pin +1 -0
- package/fixtures/vp-convex/bun.lock +783 -0
- package/fixtures/vp-convex/convex/auth.config.ts +8 -0
- package/fixtures/vp-convex/convex/briefingNotes.ts +321 -0
- package/fixtures/vp-convex/convex/convex.config.ts +14 -0
- package/fixtures/vp-convex/convex/credentials.ts +591 -0
- package/fixtures/vp-convex/convex/crons.ts +72 -0
- package/fixtures/vp-convex/convex/dashboard.ts +199 -0
- package/fixtures/vp-convex/convex/gumroadWebhook.ts +815 -0
- package/fixtures/vp-convex/convex/issues.ts +544 -0
- package/fixtures/vp-convex/convex/kb.ts +305 -0
- package/fixtures/vp-convex/convex/kbMutations.ts +192 -0
- package/fixtures/vp-convex/convex/kbShared.ts +56 -0
- package/fixtures/vp-convex/convex/licenses.ts +443 -0
- package/fixtures/vp-convex/convex/memories.ts +406 -0
- package/fixtures/vp-convex/convex/memoriesScoped.ts +220 -0
- package/fixtures/vp-convex/convex/messages.ts +971 -0
- package/fixtures/vp-convex/convex/migrations.ts +239 -0
- package/fixtures/vp-convex/convex/missionTemplates.ts +369 -0
- package/fixtures/vp-convex/convex/oauth.ts +1608 -0
- package/fixtures/vp-convex/convex/oauthMigrations.ts +96 -0
- package/fixtures/vp-convex/convex/okfBundleNode.ts +1031 -0
- package/fixtures/vp-convex/convex/recurringTasks.ts +386 -0
- package/fixtures/vp-convex/convex/schema.ts +1229 -0
- package/fixtures/vp-convex/convex/tasks.ts +2782 -0
- package/fixtures/vp-r31-green/.pin +1 -0
- package/fixtures/vp-r31-green/convex/migrations.ts +350 -0
- package/fixtures/vp-r31-red/.pin +1 -0
- package/fixtures/vp-r31-red/convex/migrations.ts +286 -0
- package/fixtures/vr-by-tool-day159.csv +89 -0
- package/package.json +39 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { v } from "convex/values";
|
|
2
|
+
import { ConvexError } from "convex/values";
|
|
3
|
+
import { mutation, query } from "./_generated/server";
|
|
4
|
+
import type { Doc } from "./_generated/dataModel";
|
|
5
|
+
import { creatorValidator } from "./schema";
|
|
6
|
+
import { withOrgScope, filterByOrgScope, requireScope } from "./lib/auth";
|
|
7
|
+
import { requireId } from "./lib/ids";
|
|
8
|
+
|
|
9
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
// create — insert a new briefing note
|
|
11
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export const create = mutation({
|
|
14
|
+
args: {
|
|
15
|
+
title: v.string(),
|
|
16
|
+
topic: v.string(),
|
|
17
|
+
participants: v.array(v.string()),
|
|
18
|
+
content: v.string(),
|
|
19
|
+
decisions: v.optional(v.array(v.string())),
|
|
20
|
+
linkedMemoryIds: v.optional(v.array(v.id("memories"))),
|
|
21
|
+
createdBy: creatorValidator,
|
|
22
|
+
},
|
|
23
|
+
returns: v.id("briefingNotes"),
|
|
24
|
+
handler: async (ctx, args) => {
|
|
25
|
+
return await ctx.db.insert("briefingNotes", {
|
|
26
|
+
...args,
|
|
27
|
+
createdAt: Date.now(),
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
33
|
+
// get — fetch a single briefing note by ID
|
|
34
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
export const get = query({
|
|
37
|
+
// Accept a raw string, not `v.id("briefingNotes")`: the v.id() validator
|
|
38
|
+
// runs BEFORE the handler, so a wrong-table ID is rejected with a message
|
|
39
|
+
// Convex redacts in prod (`Server Error`, `error.data` undefined —
|
|
40
|
+
// measured). Narrowing inside the handler via requireId() throws a
|
|
41
|
+
// ConvexError whose payload survives redaction. Same contract as PR #1072
|
|
42
|
+
// (tasks.getById).
|
|
43
|
+
args: { noteId: v.string() },
|
|
44
|
+
returns: v.union(
|
|
45
|
+
v.object({
|
|
46
|
+
_id: v.id("briefingNotes"),
|
|
47
|
+
_creationTime: v.number(),
|
|
48
|
+
title: v.string(),
|
|
49
|
+
topic: v.string(),
|
|
50
|
+
participants: v.array(v.string()),
|
|
51
|
+
content: v.string(),
|
|
52
|
+
decisions: v.optional(v.array(v.string())),
|
|
53
|
+
linkedMemoryIds: v.optional(v.array(v.id("memories"))),
|
|
54
|
+
createdBy: creatorValidator,
|
|
55
|
+
createdAt: v.number(),
|
|
56
|
+
updatedAt: v.optional(v.number()),
|
|
57
|
+
updatedBy: v.optional(creatorValidator),
|
|
58
|
+
// PR #360 — Beta multi-tenant scope field. Optional so pre-PR #360 docs pass.
|
|
59
|
+
orgId: v.optional(v.string()),
|
|
60
|
+
}),
|
|
61
|
+
v.null(),
|
|
62
|
+
),
|
|
63
|
+
handler: async (ctx, args) => {
|
|
64
|
+
const noteId = requireId(
|
|
65
|
+
ctx,
|
|
66
|
+
"briefingNotes",
|
|
67
|
+
args.noteId,
|
|
68
|
+
"noteId",
|
|
69
|
+
"Use the full 32-char noteId returned by list_briefing_notes or create_briefing_note.",
|
|
70
|
+
);
|
|
71
|
+
return await ctx.db.get(noteId);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
76
|
+
// Lite projection helper
|
|
77
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
type BriefingNoteLite = {
|
|
80
|
+
_id: string;
|
|
81
|
+
_creationTime: number;
|
|
82
|
+
topic: string;
|
|
83
|
+
title: string;
|
|
84
|
+
participants: string[];
|
|
85
|
+
createdBy: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
function projectBriefingNoteLite(doc: Doc<"briefingNotes">): BriefingNoteLite {
|
|
89
|
+
return {
|
|
90
|
+
_id: doc._id,
|
|
91
|
+
_creationTime: doc._creationTime,
|
|
92
|
+
topic: doc.topic,
|
|
93
|
+
title: doc.title,
|
|
94
|
+
participants: doc.participants,
|
|
95
|
+
createdBy: doc.createdBy,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
100
|
+
// list — list briefing notes, optional topic filter, ordered by createdAt desc
|
|
101
|
+
//
|
|
102
|
+
// New in v1.1:
|
|
103
|
+
// fields="lite" — compact projection: {_id,_creationTime,topic,title,participants,createdBy}
|
|
104
|
+
// fields="full" (default) — full doc (backward-compatible)
|
|
105
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
106
|
+
|
|
107
|
+
// updatedSince widened-scan fix (same defect class as #1110 on billing, and
|
|
108
|
+
// convex/tasks.ts `list`/`listByMission`, convex/missions.ts `list`): the
|
|
109
|
+
// filter used to run in-memory after a `.take(limit)` that had already
|
|
110
|
+
// bounded the page in creation-descending order — a note updated recently
|
|
111
|
+
// but created outside that page was invisible while the response looked
|
|
112
|
+
// complete. When updatedSince is supplied, the fetch is widened to
|
|
113
|
+
// BRIEFING_NOTES_LIST_SCAN_CAP + 1 rows before the filter runs, then
|
|
114
|
+
// re-sliced to `limit`. If the widened scan itself hits its cap, we refuse
|
|
115
|
+
// to return a silently-incomplete page.
|
|
116
|
+
export const BRIEFING_NOTES_LIST_SCAN_CAP = 2000;
|
|
117
|
+
|
|
118
|
+
export const list = query({
|
|
119
|
+
args: {
|
|
120
|
+
topic: v.optional(v.string()),
|
|
121
|
+
limit: v.optional(v.number()),
|
|
122
|
+
fields: v.optional(v.union(v.literal("lite"), v.literal("full"))),
|
|
123
|
+
updatedSince: v.optional(v.number()),
|
|
124
|
+
// S3.3 B8 — cursor paging anchor (forward pagination, newest-first).
|
|
125
|
+
createdBefore: v.optional(v.number()),
|
|
126
|
+
},
|
|
127
|
+
// Returns validator omitted because union of full+lite produces overly strict types vs Doc<"briefingNotes"> optionality
|
|
128
|
+
handler: async (ctx, args) => {
|
|
129
|
+
const lite = args.fields === "lite";
|
|
130
|
+
// v2.3.3 — auto-clamp limit when fields=full + no explicit limit
|
|
131
|
+
const explicitLimit = args.limit !== undefined;
|
|
132
|
+
let limit = args.limit ?? 20;
|
|
133
|
+
if (!explicitLimit && !lite) {
|
|
134
|
+
limit = 15;
|
|
135
|
+
console.warn(
|
|
136
|
+
`[briefingNotes.list] auto-clamp: limit=15 applied (fields=full, no explicit limit).`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
const needsWideScan = args.updatedSince !== undefined;
|
|
140
|
+
const fetchCap = needsWideScan ? BRIEFING_NOTES_LIST_SCAN_CAP + 1 : limit;
|
|
141
|
+
|
|
142
|
+
let rows: Doc<"briefingNotes">[];
|
|
143
|
+
|
|
144
|
+
if (args.topic !== undefined) {
|
|
145
|
+
rows = await ctx.db
|
|
146
|
+
.query("briefingNotes")
|
|
147
|
+
.withIndex("by_topic", (q) => q.eq("topic", args.topic as string))
|
|
148
|
+
.order("desc")
|
|
149
|
+
.take(fetchCap);
|
|
150
|
+
} else {
|
|
151
|
+
rows = await ctx.db.query("briefingNotes").order("desc").take(fetchCap);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Refuse to return a silently-incomplete page: if the widened scan
|
|
155
|
+
// itself hit its cap, there may be matching rows we never looked at.
|
|
156
|
+
// "I couldn't measure" must never render identically to "complete".
|
|
157
|
+
// No branch here was measured to exceed the cap in production (unlike
|
|
158
|
+
// tasks.list's assignedTo branches), so no index was added and the
|
|
159
|
+
// fetch is still a fixed-size widened scan — "shrink the updatedSince
|
|
160
|
+
// window" would be a false remedy and is left out of the message.
|
|
161
|
+
if (needsWideScan && rows.length > BRIEFING_NOTES_LIST_SCAN_CAP) {
|
|
162
|
+
throw new ConvexError(
|
|
163
|
+
`briefingNotes.list: SCAN_CAP_EXCEEDED — widened scan for updatedSince hit the cap of ${BRIEFING_NOTES_LIST_SCAN_CAP} candidate rows before the filter ran. The result would be incomplete and indistinguishable from a full match. Narrow with topic.`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// v2.3.3 — updatedSince filter on updatedAt (fallback to _creationTime if missing)
|
|
168
|
+
if (args.updatedSince !== undefined) {
|
|
169
|
+
const since = args.updatedSince;
|
|
170
|
+
rows = rows.filter(
|
|
171
|
+
(r) => (r.updatedAt ?? r._creationTime) >= since,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
// Re-bound to the requested page size now that the filter has run over
|
|
175
|
+
// the widened superset (no-op when a wide scan wasn't needed).
|
|
176
|
+
rows = rows.slice(0, limit);
|
|
177
|
+
// S3.3 B8 — cursor paging anchor: drop rows newer-or-equal to before.
|
|
178
|
+
if (args.createdBefore !== undefined) {
|
|
179
|
+
const before = args.createdBefore;
|
|
180
|
+
rows = rows.filter((r) => r._creationTime < before);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (lite) return rows.map(projectBriefingNoteLite);
|
|
184
|
+
return rows;
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
189
|
+
// deleteBriefingNote — hard delete a briefing note by ID
|
|
190
|
+
// RBAC: callerOrchestrator must match note.createdBy or be "system"
|
|
191
|
+
// Pass callerOrchestrator=undefined to bypass (server-to-server / admin use).
|
|
192
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
export const deleteBriefingNote = mutation({
|
|
195
|
+
args: {
|
|
196
|
+
noteId: v.id("briefingNotes"),
|
|
197
|
+
callerOrchestrator: v.optional(creatorValidator),
|
|
198
|
+
},
|
|
199
|
+
returns: v.object({ deleted: v.boolean() }),
|
|
200
|
+
handler: async (ctx, args) => {
|
|
201
|
+
const note = await ctx.db.get(args.noteId);
|
|
202
|
+
if (!note) throw new Error("Briefing note not found");
|
|
203
|
+
|
|
204
|
+
if (args.callerOrchestrator === undefined) {
|
|
205
|
+
throw new Error(
|
|
206
|
+
"Unauthorized: callerOrchestrator is required to delete a briefing note — omitting it is refused, not exempted",
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
if (
|
|
210
|
+
args.callerOrchestrator !== "system" &&
|
|
211
|
+
note.createdBy !== args.callerOrchestrator
|
|
212
|
+
) {
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Unauthorized: only ${note.createdBy} (creator) or system can delete this briefing note`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
await ctx.db.delete(args.noteId);
|
|
219
|
+
return { deleted: true };
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
224
|
+
// update — partial update of any mutable briefing note field
|
|
225
|
+
// RBAC deny-by-default: callerOrchestrator MUST be createdBy or "system"
|
|
226
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
227
|
+
|
|
228
|
+
export const update = mutation({
|
|
229
|
+
args: {
|
|
230
|
+
noteId: v.id("briefingNotes"),
|
|
231
|
+
callerOrchestrator: creatorValidator, // REQUIRED — deny-by-default per memory j573cwcs3znp0xsvtg34x435jh84b0eg
|
|
232
|
+
title: v.optional(v.string()),
|
|
233
|
+
topic: v.optional(v.string()),
|
|
234
|
+
participants: v.optional(v.array(v.string())),
|
|
235
|
+
content: v.optional(v.string()),
|
|
236
|
+
decisions: v.optional(v.array(v.string())),
|
|
237
|
+
linkedMemoryIds: v.optional(v.array(v.id("memories"))),
|
|
238
|
+
},
|
|
239
|
+
returns: v.null(),
|
|
240
|
+
handler: async (ctx, args) => {
|
|
241
|
+
const { noteId, callerOrchestrator, ...fields } = args;
|
|
242
|
+
const note = await ctx.db.get(noteId);
|
|
243
|
+
if (note === null) {
|
|
244
|
+
throw new Error(`BriefingNote ${noteId} not found`);
|
|
245
|
+
}
|
|
246
|
+
const isAuthorized =
|
|
247
|
+
note.createdBy === callerOrchestrator || callerOrchestrator === "system";
|
|
248
|
+
if (!isAuthorized) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`Unauthorized: ${callerOrchestrator} is not creator of this briefing note`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
const patch: Record<string, unknown> = {
|
|
254
|
+
updatedAt: Date.now(),
|
|
255
|
+
updatedBy: callerOrchestrator,
|
|
256
|
+
};
|
|
257
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
258
|
+
if (value !== undefined) {
|
|
259
|
+
patch[key] = value;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
await ctx.db.patch(noteId, patch);
|
|
263
|
+
return null;
|
|
264
|
+
},
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
268
|
+
// Day 102 v2.11.0 — CRUD baseline PR-C-bis option B (mission k575kc1r).
|
|
269
|
+
// BM25 keyword search over briefing note content via Convex native .searchIndex().
|
|
270
|
+
//
|
|
271
|
+
// Backed by the `search_content` searchIndex declared in schema.ts.
|
|
272
|
+
// Filter axes: topic, createdBy.
|
|
273
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
274
|
+
|
|
275
|
+
export const searchBriefingNotesByKeyword = query({
|
|
276
|
+
args: {
|
|
277
|
+
query: v.string(),
|
|
278
|
+
topic: v.optional(v.string()),
|
|
279
|
+
createdBy: v.optional(creatorValidator),
|
|
280
|
+
limit: v.optional(v.number()),
|
|
281
|
+
fields: v.optional(v.union(v.literal("lite"), v.literal("full"))),
|
|
282
|
+
},
|
|
283
|
+
handler: async (ctx, args) => {
|
|
284
|
+
const scope = await withOrgScope(ctx);
|
|
285
|
+
requireScope(scope, "view-own-tasks");
|
|
286
|
+
|
|
287
|
+
const limit = Math.min(Math.max(args.limit ?? 20, 1), 200);
|
|
288
|
+
const lite = args.fields === "lite";
|
|
289
|
+
|
|
290
|
+
const results = await ctx.db
|
|
291
|
+
.query("briefingNotes")
|
|
292
|
+
.withSearchIndex("search_content", (q) => {
|
|
293
|
+
let qb = q.search("content", args.query);
|
|
294
|
+
if (args.topic !== undefined) qb = qb.eq("topic", args.topic);
|
|
295
|
+
if (args.createdBy !== undefined)
|
|
296
|
+
qb = qb.eq("createdBy", args.createdBy);
|
|
297
|
+
if (!scope.isMaster && scope.orgSlug !== null) {
|
|
298
|
+
qb = qb.eq("orgId", scope.orgSlug);
|
|
299
|
+
}
|
|
300
|
+
return qb;
|
|
301
|
+
})
|
|
302
|
+
.take(limit);
|
|
303
|
+
|
|
304
|
+
// Defense-in-depth: briefingNotes have no pilot/assignedTo so
|
|
305
|
+
// filterByOrgScope() does not fit. Enforce orgId match inline for
|
|
306
|
+
// non-master scopes — the index .eq("orgId", scope.orgSlug) above
|
|
307
|
+
// is the primary isolation; this is the belt-and-suspenders pass.
|
|
308
|
+
const filtered = scope.isMaster
|
|
309
|
+
? results
|
|
310
|
+
: results.filter((r) => r.orgId === scope.orgSlug);
|
|
311
|
+
|
|
312
|
+
if (!lite) return filtered;
|
|
313
|
+
return filtered.map((b) => ({
|
|
314
|
+
_id: b._id,
|
|
315
|
+
title: b.title,
|
|
316
|
+
topic: b.topic,
|
|
317
|
+
createdBy: b.createdBy,
|
|
318
|
+
createdAt: b.createdAt,
|
|
319
|
+
}));
|
|
320
|
+
},
|
|
321
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineApp } from "convex/server";
|
|
2
|
+
import rag from "@convex-dev/rag/convex.config.js";
|
|
3
|
+
// Durable long-task engine (I1 — long-task survival). Verified real (not
|
|
4
|
+
// the empty-shell alpha.1 dist-tag): dist/component/engine/durableJob.js
|
|
5
|
+
// exports start/getStatus/cancel/getJobInternal/runStepInternal. Pinned
|
|
6
|
+
// exactly at 0.1.0-alpha.2 in package.json — do NOT loosen to `^`/`@alpha`,
|
|
7
|
+
// `latest` still resolves to the empty shell.
|
|
8
|
+
import agentEngine from "@vantageos/agent-engine/convex.config";
|
|
9
|
+
|
|
10
|
+
const app = defineApp();
|
|
11
|
+
app.use(rag);
|
|
12
|
+
app.use(agentEngine); // registered under the default name "agentEngine"
|
|
13
|
+
|
|
14
|
+
export default app;
|