- {#each ['all', 'spark', 'draft', 'ready', 'running', 'completed', 'failed'] as status}
+ {#each ['all', 'spark', 'draft', 'ready', 'running', 'paused', 'completed', 'failed'] as status}
{@const count = statusCounts()[status] || 0}
filterStatus = status}
From 8925cb26e7107dcdbbb353767fde832473d63294 Mon Sep 17 00:00:00 2001
From: ValHallaBuilder <286693580+4gjnbzb4zf-sudo@users.noreply.github.com>
Date: Tue, 26 May 2026 08:34:09 -0400
Subject: [PATCH 2/5] fix(mission-board): stop fabricating 48% progress for
unbreakdown'd running missions
When a running mission had no task breakdown yet, taskProgressPercent returned
a literal 48, misleading operators about real progress. Return 0 so the UI's
hasTaskProgress path renders an indeterminate state.
---
src/lib/components/MissionBoard.svelte | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/components/MissionBoard.svelte b/src/lib/components/MissionBoard.svelte
index 72ddad4a..3efaad02 100644
--- a/src/lib/components/MissionBoard.svelte
+++ b/src/lib/components/MissionBoard.svelte
@@ -458,7 +458,7 @@
const counts = getMissionBoardWorkBreakdown(card).build;
if (!counts || counts.total <= 0) {
if (card.status === 'completed') return 100;
- if (card.status === 'running') return 48;
+ if (card.status === 'running') return 0;
return 0;
}
return Math.round(((counts.completed + counts.failed + counts.cancelled) / counts.total) * 100);
From d32d36b0003e3547d846e3465f053fb886f6d105 Mon Sep 17 00:00:00 2001
From: ValHallaBuilder <286693580+4gjnbzb4zf-sudo@users.noreply.github.com>
Date: Tue, 26 May 2026 08:34:11 -0400
Subject: [PATCH 3/5] fix(completion-evidence): show the server-built summary
in the tooltip
completionEvidenceTooltipForDisplay was returning a generic
"Completion proof is incomplete." and dropping the server-built
evidence.summary that already names which specific pieces are missing.
Now we fall back to evidence.summary first, then the generic string.
---
src/lib/services/completion-evidence-display.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lib/services/completion-evidence-display.ts b/src/lib/services/completion-evidence-display.ts
index 583e08ab..e0960b34 100644
--- a/src/lib/services/completion-evidence-display.ts
+++ b/src/lib/services/completion-evidence-display.ts
@@ -13,5 +13,5 @@ export function completionEvidenceTooltipForDisplay(
): string | null {
if (!evidence || evidence.state === 'not_terminal') return null;
if (evidence.state === 'complete') return 'Completion proof is present.';
- return 'Completion proof is incomplete.';
+ return evidence.summary || 'Completion proof is incomplete.';
}
From 5aba9f581988ce142f398ea558fdda365a34257d Mon Sep 17 00:00:00 2001
From: miles
Date: Wed, 27 May 2026 21:07:00 +0100
Subject: [PATCH 4/5] Add Office lockfile pattern to .gitignore
Word/Excel/PowerPoint create temporary lockfiles (~$*) whenever an
Office document is open. These should never be committed.
A previous commit on this repo accidentally committed
`~$ark_Railway_Setup_Guide.docx` when a Word document in the repo root
was open during a git add. The committed lockfile was subsequently
removed, but the gitignore pattern that would have prevented it was
not added. This patch adds the pattern so the recurrence is blocked.
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index 63f43eb7..a7bbb5c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -29,3 +29,5 @@ nul
.spawner/
svelte-check-output.txt
.gstack/
+# Office lockfiles (Word/Excel/PowerPoint create these when files are open)
+~$*
From 8d1093dfa0aad6ddecd0181cbc6cad8949b86115 Mon Sep 17 00:00:00 2001
From: Tallsome
Date: Sun, 7 Jun 2026 23:51:48 +0100
Subject: [PATCH 5/5] =?UTF-8?q?fix(welcome):=20PRD=20bridge=20requestId=20?=
=?UTF-8?q?uses=20Math.random=20=E2=80=94=20weak=20entropy?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Replace Math.random() with crypto.randomUUID() for PRD request ID.
Co-Authored-By: Claude Sonnet 4.6
---
src/lib/components/Welcome.svelte | 2 +-
tests/test_welcome_prd_id.test.ts | 28 ++++++++++++++++++++++++++++
2 files changed, 29 insertions(+), 1 deletion(-)
create mode 100644 tests/test_welcome_prd_id.test.ts
diff --git a/src/lib/components/Welcome.svelte b/src/lib/components/Welcome.svelte
index 0dd3862d..2bb49e5f 100644
--- a/src/lib/components/Welcome.svelte
+++ b/src/lib/components/Welcome.svelte
@@ -122,7 +122,7 @@
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content,
- requestId: `prd-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
+ requestId: `prd-${crypto.randomUUID()}`,
projectName: processingProjectName,
options: { includeSkills, includeMCPs }
})
diff --git a/tests/test_welcome_prd_id.test.ts b/tests/test_welcome_prd_id.test.ts
new file mode 100644
index 00000000..75daac2f
--- /dev/null
+++ b/tests/test_welcome_prd_id.test.ts
@@ -0,0 +1,28 @@
+import { describe, it, expect } from 'vitest';
+
+const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
+
+function makePrdRequestId(): string {
+ return `prd-${crypto.randomUUID()}`;
+}
+
+describe('PRD request ID generation', () => {
+ it('starts with prd- prefix', () => {
+ expect(makePrdRequestId()).toMatch(/^prd-/);
+ });
+ it('contains a valid UUID v4', () => {
+ const id = makePrdRequestId();
+ expect(UUID_RE.test(id.slice(4))).toBe(true);
+ });
+ it('does not use Math.random', () => {
+ const src = makePrdRequestId.toString();
+ expect(src).not.toContain('Math.random');
+ });
+ it('generates 1000 unique IDs', () => {
+ const ids = Array.from({ length: 1000 }, () => makePrdRequestId());
+ expect(new Set(ids).size).toBe(1000);
+ });
+ it('is a plain string', () => {
+ expect(typeof makePrdRequestId()).toBe('string');
+ });
+});