diff --git a/.gitignore b/.gitignore
index 25e923da98..19d9626bd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -70,3 +70,6 @@ scratch/
.qa-smoke/
*.pid
tmp_output.txt
+
+# machine-local tooling hook cache (session ids, timestamps, local paths)
+.impeccable/
diff --git a/.impeccable/hook.cache.json b/.impeccable/hook.cache.json
deleted file mode 100644
index a2d4e16581..0000000000
--- a/.impeccable/hook.cache.json
+++ /dev/null
@@ -1 +0,0 @@
-{"version":1,"sessions":{"70c96a73-49a6-4422-a310-d0294a45dc49":{"updatedAt":1782977742215,"files":{"C:\\Users\\joshs\\.copilot\\repos\\copilot-worktrees\\Database\\bigsimmo-bookish-barnacle\\supabase\\functions\\indexing-v3-agent\\index.ts":{"editCount":1,"findings":[]}}}}}
\ No newline at end of file
diff --git a/.prettierignore b/.prettierignore
index fa1ce8a5ae..ebda744c78 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -15,3 +15,6 @@ scratch/
# Generated by `supabase gen types`; keep the generator's formatting so
# regeneration stays churn-free.
src/lib/supabase/database.types.ts
+
+# Machine-local tooling hook cache (session ids, timestamps, local paths).
+.impeccable/
diff --git a/docs/superpowers/specs/2026-07-02-triage-security-reliability-design.md b/docs/superpowers/specs/2026-07-02-triage-security-reliability-design.md
index e586e7e852..16b5958357 100644
--- a/docs/superpowers/specs/2026-07-02-triage-security-reliability-design.md
+++ b/docs/superpowers/specs/2026-07-02-triage-security-reliability-design.md
@@ -6,6 +6,7 @@ Scope: Issue #53 (security), #55 (reliability gaps only), #56 (no change unless
## 1. Goals and non-goals
### Goals
+
- Remove authentication bypass behavior so protected APIs fail closed.
- Stop client-side reliance on persisted localStorage auth token hints.
- Redact high-risk identifiers from generated image captions before persistence.
@@ -13,6 +14,7 @@ Scope: Issue #53 (security), #55 (reliability gaps only), #56 (no change unless
- Close currently open reliability gaps from #55 with minimal, targeted changes (especially embedding-dimension drift safeguards).
### Non-goals
+
- No front-end refactor work from #51.
- No performance-oriented search/ingestion optimization from #52.
- No broad operational redesign for #56; only patch ops docs/scripts if implementation reveals a concrete missing step.
@@ -32,16 +34,19 @@ This is preferred over broader rewrites because it directly addresses active ris
## 3. Architecture and component changes
### 3.1 Authentication boundary
+
- Primary file: `src/lib/supabase/auth.ts`.
- Change: remove environment-based no-auth fallback paths for protected API authorization.
- Result: auth gate requires valid Supabase-authenticated user identity; invalid/missing identity returns explicit unauthorized response paths.
### 3.2 Client-side session handling
+
- Primary files: `src/lib/supabase/client.tsx`, `src/components/ClinicalDashboard.tsx`.
- Change: stop relying on localStorage token presence scans and persisted auth-email hints for deciding private API/session capability.
- Result: UI behavior follows actual Supabase session/auth state only.
### 3.3 Caption redaction before persistence
+
- Primary file: `worker/main.ts` (with helper placement in shared privacy utility area where appropriate).
- Change: sanitize generated caption text before database/cache writes.
- Baseline redaction targets:
@@ -51,11 +56,13 @@ This is preferred over broader rewrites because it directly addresses active ris
- Result: ingestion remains functional, but persisted captions are safer by default.
### 3.4 Safe Supabase logging
+
- Primary files: worker/server/script callsites identified during implementation.
- Change: route Supabase-related error detail formatting through existing safe redaction utilities instead of direct raw detail logging.
- Result: operational logs remain actionable without leaking secret/token/identifier content.
### 3.5 Embedding-dimension drift safeguards
+
- Primary file: `src/lib/embedding-dimensions.ts` and nearby ingestion assertions/tests.
- Change: align expected dimension checks to a single configuration source used by ingestion-time assertions.
- Result: mismatches fail fast and predictably, avoiding silent search-quality corruption.
diff --git a/src/app/api/documents/[id]/reindex/route.ts b/src/app/api/documents/[id]/reindex/route.ts
index f2a05b0f74..32057ab417 100644
--- a/src/app/api/documents/[id]/reindex/route.ts
+++ b/src/app/api/documents/[id]/reindex/route.ts
@@ -115,7 +115,9 @@ export async function POST(request: Request, { params }: { params: Promise<{ id:
const { data: document, error: documentError } = await supabase
.from("documents")
- .select("id,owner_id,title,file_name,source_path,import_batch_id,status,error_message,page_count,chunk_count,image_count,metadata")
+ .select(
+ "id,owner_id,title,file_name,source_path,import_batch_id,status,error_message,page_count,chunk_count,image_count,metadata",
+ )
.eq("id", id)
.eq("owner_id", user.id)
.maybeSingle();
@@ -240,7 +242,9 @@ export async function POST(request: Request, { params }: { params: Promise<{ id:
.in("status", ["pending", "processing"])
.limit(1);
if (competingJobsError) {
- throw new Error(`Failed to enqueue reindex job: ${jobError.message}; competing-job check failed: ${competingJobsError.message}`);
+ throw new Error(
+ `Failed to enqueue reindex job: ${jobError.message}; competing-job check failed: ${competingJobsError.message}`,
+ );
}
if ((competingJobs?.length ?? 0) === 0) {
const { error: rollbackError } = await supabase
@@ -250,7 +254,9 @@ export async function POST(request: Request, { params }: { params: Promise<{ id:
.eq("owner_id", user.id)
.eq("updated_at", rollbackFence);
if (rollbackError) {
- throw new Error(`Failed to enqueue reindex job: ${jobError.message}; rollback failed: ${rollbackError.message}`);
+ throw new Error(
+ `Failed to enqueue reindex job: ${jobError.message}; rollback failed: ${rollbackError.message}`,
+ );
}
}
throw new Error(jobError.message);
diff --git a/src/app/api/documents/bulk/reindex/route.ts b/src/app/api/documents/bulk/reindex/route.ts
index 06391bfcb6..15d3270121 100644
--- a/src/app/api/documents/bulk/reindex/route.ts
+++ b/src/app/api/documents/bulk/reindex/route.ts
@@ -105,7 +105,9 @@ export async function POST(request: Request) {
const documentIds = Array.from(new Set(parsed.documentIds));
const { data: documents, error: documentError } = await supabase
.from("documents")
- .select("id,owner_id,title,file_name,source_path,import_batch_id,status,error_message,page_count,chunk_count,image_count,metadata")
+ .select(
+ "id,owner_id,title,file_name,source_path,import_batch_id,status,error_message,page_count,chunk_count,image_count,metadata",
+ )
.eq("owner_id", user.id)
.in("id", documentIds);
if (documentError) throw new Error(documentError.message);
@@ -244,7 +246,9 @@ export async function POST(request: Request) {
.eq("owner_id", user.id)
.eq("updated_at", rollbackFence);
if (rollbackError) {
- throw new Error(`Failed to enqueue bulk reindex job: ${jobError.message}; rollback failed: ${rollbackError.message}`);
+ throw new Error(
+ `Failed to enqueue bulk reindex job: ${jobError.message}; rollback failed: ${rollbackError.message}`,
+ );
}
}
throw new Error(jobError.message);
diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts
index 36dff1c2d4..7aacea2c03 100644
--- a/src/app/api/upload/route.ts
+++ b/src/app/api/upload/route.ts
@@ -166,7 +166,9 @@ export async function POST(request: Request) {
.eq("id", documentId)
.eq("owner_id", user.id);
if (rollbackDocumentError) {
- throw new Error(`Failed to enqueue ingestion job: ${jobError.message}; rollback failed: ${rollbackDocumentError.message}`);
+ throw new Error(
+ `Failed to enqueue ingestion job: ${jobError.message}; rollback failed: ${rollbackDocumentError.message}`,
+ );
}
insertedDocumentId = null;
insertedDocumentOwnerId = null;
@@ -208,7 +210,9 @@ export async function POST(request: Request) {
if (uploadedPath && supabase) {
try {
- const { error: cleanupStorageError } = await supabase.storage.from(env.SUPABASE_DOCUMENT_BUCKET).remove([uploadedPath]);
+ const { error: cleanupStorageError } = await supabase.storage
+ .from(env.SUPABASE_DOCUMENT_BUCKET)
+ .remove([uploadedPath]);
if (cleanupStorageError) {
logger.error("Upload cleanup failed; storage object may be orphaned", {
storagePath: uploadedPath,
diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx
index 02172e1ae9..7276ea2614 100644
--- a/src/components/ClinicalDashboard.tsx
+++ b/src/components/ClinicalDashboard.tsx
@@ -5778,8 +5778,7 @@ export function ClinicalDashboard({
demoMode || process.env.NEXT_PUBLIC_DEMO_MODE === "true" || browserAuthUnavailableDemoFallback;
const localDevCanAttemptPrivateApis = process.env.NODE_ENV !== "production" && hasReadyPublicSearchSetup(setupChecks);
const canUsePrivateApis =
- localProjectReady &&
- (localNoAuthMode || localDevCanAttemptPrivateApis || authStatus === "authenticated");
+ localProjectReady && (localNoAuthMode || localDevCanAttemptPrivateApis || authStatus === "authenticated");
const canRunSearch = explicitDemoMode || (hasReadyPublicSearchSetup(setupChecks) && canUsePrivateApis);
const closeDashboardTransientSurfaces = useCallback(
(except?: "guide" | "settings" | "mobileSidebar" | "documents" | "upload") => {
diff --git a/src/components/applications-launcher-page.tsx b/src/components/applications-launcher-page.tsx
index dcfca0b373..9406747327 100644
--- a/src/components/applications-launcher-page.tsx
+++ b/src/components/applications-launcher-page.tsx
@@ -934,9 +934,7 @@ export function ApplicationsLauncherWorkspace({
);
}
- return (
-