Skip to content

Commit 6e709ed

Browse files
PraeSynBHCTOPaperclip-Paperclip
authored
v0.4.0-alpha: Deep Planning, Memory & Knowledge, Phase 5 Board UI (#45)
* fix(recovery): source_revalidation must revert the park it invalidated (RBR-921 AC3) Revalidation could already prove a park was wrong -- it logged "Recovery action became stale because the source issue reached done" -- and then walked past the damage. Every phantom park so far has needed a human to hand-revert it; that manual step was the product defect. revertPhantomRecoveryPark() now undoes the park before the stale-cancel classifier runs (a parked issue reads `blocked`, which the classifier deliberately leaves alone), restoring status AND the pre-park assignee. Guarded on five invariants so this is not RBR-864 with the sign flipped: 1. Never demote a terminal status -- if the issue reads done/cancelled we do not write, or we would manufacture the phantom regression on the hot read-projection path. 2. Only revert the indefensible park: evidence.previousStatus must itself be terminal. A run that legitimately died from in_progress gets a live path restored elsewhere, never a status rewrite here. 3. Compare-and-set against a freshly SELECT ... FOR UPDATE row, not the request snapshot; stand down if anything moved. A human assigneeUserId outranks any automated revert. 4. Restore previousOwnerAgentId (who held it before the park), never returnOwnerAgentId -- the two diverge. 5. The revert is observable: issue.recovery_action_reverted activity plus a system comment on the thread. Tests: revert restores both status and assignee and cancels the action; a park taken from a live in_progress run is left standing. * test(recovery): allow 180s for embedded-postgres boot in beforeAll The RBR-912 harness change boots an embedded Postgres cluster in globalSetup; the 30s beforeAll budget in this file is below the observed ~90s+ boot and fails the suite before any assertion runs. * merge(RBR-979): land reaper-liveness fix on master Cherry-picked from rbr979-reaper-liveness branch (commits cc1fc90, a69c00c, 3ae2c93, 7e5c1dc, f3ed532). The startup reaper now requires positive evidence of death before reaping: recorded pid alive with identity confirmed, runId in the live process table, or a surviving process group. Probe failure resolves to alive — a destructive action needs proof. Includes: - run-reap-liveness.ts (liveness predicate) - process-table-snapshot.ts (evidence collection) - reap-liveness.test.ts (unit + negative-control tests) - vitest.reaplive.config.ts (suite config) - heartbeat.ts integration (reap-liveness hook) Deploy/restart is NOT part of this commit — board-gated per standing constraints. * fix(server): raise embedded-Postgres beforeAll hook budget to config-level 120s (RBR-980/RBR-912) Two suites carried inline beforeAll(fn, 20_000) that always timed out against embedded-Postgres cold-boot (~80-95s), hiding ~56 tests as skipped. Set hookTimeout: 120000 at config level and drop inline budgets so they inherit it. Cherry-picked from 4f601d7 (rbr-980-embedded-pg-hook-fix branch). * fix(recovery): fingerprint idempotency — a stale-cancelled cause must not re-park the same issue (RBR-922 AC4) When source revalidation (AC3, RBR-921) cancels a recovery action, it moves out of the active/escalated partial unique index. The next sweep's upsertSourceScoped then sees no active action and creates a fresh one — re-parking the issue the guard just released. This is the repeat-revert pattern seen in production (RBR-847 took three, RBR-815 took two). Fix: add getCancelledForFingerprint to issueRecoveryActionService, which checks for previously-cancelled/resolved actions with the same (companyId, sourceIssueId, cause, fingerprint). In ensureSourceScopedStrandedRecoveryAction, this gate fires before the upsert: if a cancelled action exists with the same fingerprint, return it instead of minting a new one. In escalateStrandedAssignedIssue, if the returned action is not active/escalated, skip the re-park entirely. Tests: three new behavioral regression tests: 1. Single cancel-then-sweep: no new active action created 2. Multi-revert (3 sweeps): no re-park across all three 3. Different fingerprint: new action allowed after cancellation * fix(ci): harden smoke test pipeline — pre-merge gates + flaky test fixes (VOY-770) ## Pre-merge gate fix - Add verify_serialized_server + e2e to pr.yml verify gate needs - Previously ~25 route/authz suites + 6 Playwright specs could fail silently ## Flaky test fixes (inline timeout budget removal) - access-routes-permissions-upgrade.test.ts: remove inline beforeAll(fn, 20_000) Config-level hookTimeout: 120000 now applies (was overridden by inline) - packaged-artifacts.test.ts: remove inline it(fn, 30_000) Add testTimeout: 60000 to skills-catalog vitest config npm pack + fallback build can take 30-60s on cold checkout Root cause: inline timeout args silently override config-level budgets, exactly the pattern the server vitest config warns against at lines 25-27 and 38-42. ## Audit document - Full test suite inventory and gate analysis - Run 1 results documenting the discovered flakes - CI optimization proposals * docs(VOY-1154): add v0.2.10 support release notes and case assessment - Create docs/support/releases/v0.2.10-domain-revert.md — internal release notes - Create docs/support/assessments/support-case-domain-revert.md — support assessment - Ref: VOY-1154 documentation verification for v0.2.10 * docs(support): sync documentation for shipped features — CAS, Hermes adapters, version metadata, releases page, support KB - Add Status CAS documentation (expectedStatus/expectedStatuses/allowTerminalReopen) to api/issues.md - Add Hermes Local and Hermes Gateway adapter docs (hermes-local.md, hermes-gateway.md) - Add version + last_updated frontmatter to 11 documentation pages - Add curated releases page (docs/releases.md) with Paperclip v2026.525..722 entries - Update docs.json navigation: add releases page, Hermes adapter pages - Add support knowledge base: 4 KB articles, 5 feature assessments, 1 SOP, release notes - Cross-reference Hermes adapter pages from adapters/overview.md, managing-agents.md, agents-runtime.md Ref: VOY-1154 documentation sync, shipped features: Hermes built-in adapters (paperclipai#8543), Status CAS (RBR-929/950/951/953) * docs(support): log 30-file documentation sync heartbeat (1cb3953) * feat(v0.4.0): land Deep Planning (Workstream A) + Memory & Knowledge (Workstream B) implementation Workstream A — Deep Planning (structured plan documents, revision history, plan-level approval gates): - DB schema: plan_metadata on documents, plan_review_gates table (migration 0128) - Shared types/validators for plan documents, review gates, decompositions - Server services: plan-documents, plan-review-context, plan-review-gates - Routes: plan CRUD + gate management on /issues/:id endpoints - UI: PlanDecompositionWizard (818 lines), IssueDetail plan section integration - Agent instructions: per-role instruction bundles with onboarding assets Workstream B — Memory & Knowledge (pgvector-based agent memory): - DB schema: memory_bindings, memory_binding_targets, memory_records tables (migrations 0129/0130) - Shared types/validators for memory entities - Server services: memory-adapter, memory-bindings, memory-context-injection, embedding - Routes: memory CRUD on /issues/:id/memory endpoints - Context injection: memory preamble in all 10+ adapter execute.ts files - Tests: memory-bindings, memory-context-injection, default-agent-instructions VOY-1195 VOY-1196 VOY-1197 VOY-1203 VOY-1204 VOY-1209 VOY-1190 * docs(support): log heartbeat — v0.4.0 implementation landed, v0.2.13 pending CTO sign-off * docs(support): add v0.2.13 support case assessment, release notes, KB index update (VOY-1237) - Create docs/support/assessments/support-case-stripe-tier-sync.md — assessment covering syncTierFromStripe hardening (active/trialing-only check, deleted-customer detection, downgrade-to-free, mapStripeStatus), findOrCreateStripeCustomer stale-ref auto-repair (VOY-896), NEXTAUTH_URL OAuth redirect fix - Create docs/support/releases/v0.2.13-stripe-tier-sync.md — curated customer-facing release notes with before/after behavior table - Update docs/support/README.md — add v0.2.13 assessment to Recently Shipped Features, add Voyonder release notes index - Update docs/support/heartbeat-log.md — log v0.2.13 docs sync Ref: VOY-1237 support case assessment (verified against release-engineer pipeline status 2026-08-16, merge VOY-1218, QA VOY-1231) * docs(support): sync v0.2.13 Stripe billing fixes — release notes, KB article, support case assessment (VOY-1233) - Release notes: docs/support/releases/v0.2.13-stripe-fixes.md (tag 83a1cee) - KB article: billing-cancellation-downgrade.md — cancellation now reliably downgrades to free on next login - Support case assessment: support-case-stripe-billing-fixes.md — FAQ, troubleshooting, error states, escalation paths - README: add v0.2.13 entries to assessments, KB, and release notes tables - Heartbeat log: log v0.2.13 docs sync Ref: VOY-1233 (VOY-1227 follow-up), QA verified 45/45 stripe-webhook tests * feat(v0.4.0): plan review gates + milestone context + Codex adapter integration (CTO completion) - PlanReviewGateContext + MilestoneProgress types in document-annotation.ts - Plan review gates fetch + milestone progress computation in plan-review-context.ts - milestoneId pass-through in issue decomposition types, validators, routes, services - Wakeup on plan update (issue_plan_updated) and gate resolution (issue_plan_gate_resolved) - Codex adapter: normalize + render gates and milestone progress in wake prompts - SKILL.md: structured plan metadata docs, review gate context injection, milestone decomposition - Storybook fixture: add milestoneId: null - Memory: improved routes, adapter fixes, context injection enhancements Working tree changes verified by CTO (typecheck + tests passing). Original stash ref: stash@{2} * fix(db): make memory_operations.bindingId nullable, add providerKey (sync with 0131 migration) * fix(v0.4.0): Phase 3 audit fixes — warm-up, tsquery safety, TTL, scope, index (VOY-1242) Complete 7 of 10 VOY-1206 structural audit findings: Must-Fix: - Broken warm-up: adapter.query with empty query now returns recent records instead of crashing on empty tsquery. Warm-up no longer calls full-text path with blank input. - sql.raw injection: Already fixed in working tree (parameterized CAST( AS vector), embedding NaN/Infinity validation, test coverage) Should-Fix: - tsquery safety: Sanitize full-text search input — strip characters unsafe for to_tsquery lexemes, handle empty tsquery gracefully (returns empty results instead of crashing). Applied to both memory-adapter and knowledge-documents warm-up. - TTL filtering: Add nonExpiredFilter() to all read operations (query, list, get) so expired records are excluded. Records with expiresAt=null (curated) are always returned; auto-captured records past their 30d TTL are hidden. - Scope enforcement: Add subjectId and sessionKey to buildScopeFilters, completing the scope dimension coverage. - Missing composite index: Migration 0133 adds memory_records_company_binding_idx (btree on company_id, binding_id) for common query patterns. Hardening: - Preamble boundary: Handle empty/null text, NaN/Infinity scores, non-string summary, empty summary in buildMemoryPreamble. Fallback text: summary - greater than (empty memory). - Warm-up race: AbortController pattern in warmUpAgentMemory and warmUpCompanyKnowledge. Timeout now signals cancellation; in-flight work checks signal.aborted at each async step. Result is discarded if timeout fires during processing. Deferred to child issues: - VOY-1243: Fix N+1 in upsertRecords (batch inserts + embeddings) - VOY-1244: Implement post-run/issue memory capture hooks - VOY-1245: Add TTL cleanup cron job for expired memory records Also includes working tree partial fixes already staged: - memory_operations.bindingId nullable + providerKey column (migration 0132) - Error-path binding UUID resolution in get/forget (not fallback to handle.providerKey) - Unique constraint error handling in createBinding/createTarget - delete returning() for accurate deletion feedback - Test mock updates for .returning() structure * docs(support): log heartbeat — Phase 3 audit fixes diff assessed (08254fb) * fix(sla-dedup): correct LIKE pattern space, sort order, remove unused constant Three fixes in premium-sla-dedup.ts: 1. LIKE pattern missing space: clientLikePattern() produced '[%]PremiumSLABreach: <client>%' but actual titles have a space after the severity bracket (e.g. '[CRITICAL] PremiumSLABreach: ...'). Added the missing space so the LIKE query actually matches existing issues. 2. Sort order inverted: comment said 'prefer the earliest' but code used desc(createdAt). Changed to asc(createdAt) so new alerts are parented under the original tracking incident. 3. Removed unused OPEN_STATUSES constant. These fix the title-pattern dedup path so it actually finds existing PremiumSLABreach issues instead of always returning null. * feat(db): add partial unique index for SLA monitor alert dedup (PRA-693) Adds a DB-level partial unique index on (company_id, origin_kind, origin_fingerprint) for active sla_monitor issues. This is the concurrency safety net preventing duplicate active SLA alerts from being created when multiple monitor alerts fire simultaneously. * feat(sla-dedup): wire PremiumSLABreach duplicate suppression into issue creation (PRA-693) Integrates the PremiumSLABreach dedup module into the issue creation route with two matching strategies: 1. Fingerprint match (originKind === 'sla_monitor' + originFingerprint) — used when the external monitor sends structured metadata. Suppresses creation entirely and adds a comment on the existing tracking incident. 2. Title-pattern match — fallback for the legacy monitor (originKind='manual', originFingerprint='default'). Creates the new alert as a child of the existing tracking incident. Also adds: - SLA_MONITOR_ORIGIN_KIND constant (shared) - originKind / originFingerprint fields to create issue validator - Partial unique index on (company_id, origin_kind, origin_fingerprint) for active sla_monitor issues (DB-level concurrency safety net) * fix(v0.4.0): resolve C-1/C-2/C-3 findings from VOY-1210 review C-1 (cross-tenant IDOR): Added companyId filtering to all plan-documents and plan-review-gates service functions for defense-in-depth tenant isolation, even though route-layer assertCompanyAccess already gates HTTP access. - listPlanRevisions: filter issueDocuments/documents by companyId - computePlanDiff: filter all revision queries by issue.companyId - listGates: filter planReviewGates by resolved companyId - createGate: verify document ownership via companyId - resolveGate: verify gate's document companyId - supersedeGatesForRevision: scope by companyId - supersedeGatesForPreviousRevisions: fetch document companyId C-2 (LCS OOM): Added MAX_DIFF_LINES=2000 guard to computeLineDiff. Rejects diffs exceeding 2K lines in either side with a proper 422 error instead of allocating a 2B+ entry matrix. C-3 (re-resolve invariant): resolveGate now reads the gate before updating, rejects non-pending gates with a 409 conflict error. Update WHERE clause also filters on status=pending as a safety net. VOY-1258 * fix(v0.4.0): address VOY-1210 high/medium findings — H-2/H-3/M-2/M-3/M-4/M-5 H-2: Remove dead code from documents.ts (upsertPlanDocument, listPlanDocumentRevisions, getPlanDocument, getRevisionPair — all live in plan-documents.ts, the real service). H-3: Add SELECT FOR UPDATE to upsertIssueDocument to prevent race condition on concurrent revision number calculation (was READ COMMITTED without row lock). M-2: Populate supersededByGateId column when superseding gates in supersedeGatesForRevision. M-3: Change milestoneId validators from z.string().uuid() to z.string() to match DB column type (text, not uuid). M-4: Add CHECK constraint on plan_review_gates.status (migration 0135). M-5: Add UUID validation for revisionId query param in listGates route. VOY-1229 * docs(support): sync v0.4.0-alpha documentation — plan, memory, knowledge API docs + support assessments (VOY-1254) * docs(support): log heartbeat — working-tree diff assessment (knowledge fixes, OpenAPI registrations, pre-release UI) No new commits since v0.4.0-alpha docs sync (ee5693f). Working tree assessed: 5 change areas identified — all pre-release engineering work. No documentation updates required. Docs remain in sync through v0.4.0-alpha. - Knowledge VOY-1255/VOY-1256 fixes: publish stale-approval guard, latestReviewStatus accuracy — noted for release-time support assessment - OpenAPI route registrations: already documented in docs/api/{plans,memory,knowledge}.md - Shared types + UI: pre-release additions, covered by existing assessments * test(v0.4.0): add tests for C-1/C-2/C-3 fixes from VOY-1210 review Adds 36 tests (18 per service) covering: - plan-documents: listPlanRevisions, computePlanDiff, computeLineDiff - plan-review-gates: listGates, createGate, resolveGate, supersedeGatesForRevision, supersedeGatesForPreviousRevisions All tests mock drizzle-orm and verify companyId scoping (C-1), line diff limits (C-2), and re-resolve rejection (C-3). VOY-1229 * docs(support): log heartbeat — commit 380cc92 assessed (test-only, no docs impact) No new support-facing changes since v0.4.0-alpha docs sync. Commit 380cc92 adds 36 tests for the C-1/C-2/C-3 fixes — test infrastructure only, no behavior change. Working tree unchanged from prior assessment (knowledge fixes, OpenAPI registrations, board UI — all pre-release). VOY-1264 (Phase 5 Plan Board UI release) still blocked on code review; Release Engineer to notify before shipping. Docs remain in sync. * fix(sla-dedup): suppress legacy PremiumSLABreach alerts instead of creating child issues (PRA-699) * feat(v0.4.0): Phase 5 plan board UI, memory browser, knowledge fixes, OpenAPI registrations - ui: Plans page (browse/detail/gates/revisions), MemoryBrowser page, ResolutionCard, plan document sections wired into IssueDetail, sidebar + routes + query keys - ui: memoryApi client with tests - shared: PlanDocumentRevision/PlanBodyDiffLine/PlanRevisionDiff types, planMetadata on IssueDocument, planGatesQuerySchema export - server: OpenAPI registrations for plan document, review gates, memory, knowledge routes - server: knowledge-documents publish() stale-approval guard (latest revision only), latestReviewStatus accuracy fix (VOY-1255/VOY-1256) - server: memory scope query parse -> 400 on malformed JSON; memory-adapter batch embedding + metadata jsonb containment filter - db: generate-snapshots.mjs helper * chore(db): add Drizzle migration snapshots 0100-0135 (VOY-1260) Generated snapshots for migrations 0100 through 0135 to match the existing journal entries. Includes generate-snapshots.mjs script. * chore(db): update 0099 snapshot schema (icon_url, color, tagline, instance_branding) * docs(support): sync v0.4.0 Phase 5 docs — plan board UI, memory browser, knowledge VOY-1255/1256 fixes (b495d95) - support-case-v0.4.0-deep-planning: add Plan Board UI section (browse/detail/gates/revisions), VOY-1252 - support-case-v0.4.0-memory-knowledge: add Memory Browser UI, stale-approval guard FAQ/troubleshooting (VOY-1255), latestReviewStatus accuracy (VOY-1256), scope 400 error state - release notes v0.4.0-alpha: add Plan Board UI + Memory Browser UI highlights, knowledge publish guard, scope/metadata support notes - api/memory.md: metadata jsonb containment filter on query/records, scope must be valid JSON - api/knowledge.md: stale-approval guard note on publish - heartbeat-log: log assessment of b495d95 * fix(ui): invalidate gate queries with 3-element prefix and refresh issue detail on resolve (VOY-1268) - Replace 4-element query key with 3-element prefix so that invalidation matches both revisionId-specific and __all__ keys - Add issue detail invalidation so PlanStatusBadge refreshes after approve/reject * fix(knowledge): create pending review on submit + order latestReviewStatus by createdAt (VOY-1280) submitForReview() now inserts a pending review (decidedAt = NULL) linked to the newly created revision, so list() surfaces latestReviewStatus: 'pending' after submission instead of undefined. list() orders reviews by createdAt DESC rather than decidedAt DESC, so: - a changes_requested decision (created after the pending review) shows correctly instead of being masked by the still-open pending review - a fresh pending review on resubmit overrides stale changes_requested from a previous review cycle Fixes both findings from VOY-1257 code review. * fix(v0.4.0): wrap resolveGate in transaction, count rejected gates for allApproved (H-2, VOY-1269) The allApproved predicate in resolveGate previously only checked remainingPending === 0, allowing plan approval when rejected gates existed. Approving the last pending gate while a rejection remained would flip the plan to approved. Fix: - Count both pending and rejected gates per revision - allApproved requires zero pending AND zero rejected - Wrap the update + counts + metadata flip in a DB transaction to close the concurrent-resolution race (two approvals racing before either sees the other's result) Includes a targeted regression test for the H-2 scenario. * fix(v0.4.0): move planMetadata flip inside resolveGate transaction (VOY-1269) The metadata flip (documents.plan_metadata status → approved) was being done in the route after the service transaction committed, leaving a window where the plan status could diverge from the gate state. Move the flip into the same DB transaction as the gate update + count, closing the concurrent-resolution race entirely. Remove the now-redundant route-level flip and the unused 'sql' import it pulled in. * docs(support): assess H-2 fix commit 885a674 — allApproved predicate, resolveGate transaction (VOY-1269) Commit 885a674 fixes the allApproved predicate to also count rejected gates, and wraps resolveGate in a DB transaction for atomicity. Documentation impact: no user-facing changes required — the fix aligns code with documented behavior. Applied improvements: - docs/api/plans.md: documented resolve gate response shape (gate + allApproved) - support-case-v0.4.0-deep-planning.md: added FAQ entry for rejected gate blocking approval; updated escalation path - v0.4.0-alpha-deep-planning.md: added support note for H-2 fix - heartbeat-log.md: logged this assessment * feat(v0.4.0): Knowledge Browser UI + knowledge search route fix + authorization manager-chain grant - Knowledge Browser UI (new page under /knowledge route): - knowledge API client with full CRUD, search, review lifecycle - KnowledgeBrowser page: search, list, detail sheet, revisions/diff, backlinks, create dialog - 26 UI tests passing (knowledge API client + browser page) - Knowledge search route fix: moved /knowledge/search BEFORE /:documentId routes so Express doesn't match 'search' as :documentId (critical bug) - Authorization manager-chain grant: managers may comment on and mutate issues assigned to agents in their reporting subtree. Unblocks CTO/COO from closing/reassigning issues owned by their team. - Docs: update PostHog error monitoring SOP (implementation landed 83db54a) Verification: - Server typecheck: pass - UI typecheck: pass - Server knowledge-documents: 34/34 pass - Plan-review-gates: 19/19 pass - UI knowledge api + browser: 26/26 pass Completes Polaris B Phase 5 — Company Knowledge Base UI. * docs(support): CTO heartbeat — Knowledge Browser UI + fixes landed (f09cf3b) * fix(server): batch plan-document fetch in issue list route to avoid N+1 query Three-part change: - documents.ts: add getIssueDocumentsByKeys() — batch issue-document fetch with optional key filter - plan-documents.ts: add listPlanDocuments() — thin wrapper that calls getIssueDocumentsByKeys with key='plan' - issues.ts: parallel-fetch plan docs alongside handoffStates and recoveryActionByIssue; attach to response Reduces N+1 database queries in the issue list endpoint when plan documents are requested. * fix(v0.4.0): P2 ORDER BY bare operator + dimension validation + backup chmod (VOY-1285, VOY-1286) P2-1 (VOY-1285): ORDER BY bare <=> operator for pgvector HNSW index - memory-adapter.ts: Change ORDER BY from wrapped 1 - (<=>) DESC to bare <=> operator. pgvector HNSW index requires the bare distance operator in the ORDER BY clause. The score column (SELECT list) still computes 1 - distance for application-layer similarity display. P2-6 (VOY-1286): Embedding dimension validation - embedding.ts: Add dimensions field to EmbeddingConfig interface (default 1536). Validate embedding vector length against expected dimensions after API response, throwing on mismatch. This catches model misconfiguration before corrupted vectors reach the database. Security: backup file permissions - backup-lib.ts: chmod 0o600 on pg_dump and sql dump backup files to prevent world-readable database backups. * feat(v0.4.0): Workstream C — chat-to-work resolution cards with SSE action signals (BOARD-1) Implement the core chat-to-work resolution gap identified in the Workstream C audit. The board skill already creates real Paperclip objects (issues, plans, approvals, memory records) and emits %%ACTIONS%%{...}%%/ACTIONS%% structured signals, but the server was stripping them silently and the UI had no way to render resolution cards. Server (board-chat.ts): - Add extractActionSignals() — parses %%ACTIONS%% JSON blocks from raw model output - Emit parsed actions as typed SSE 'action' events before persisting the cleaned response (which strips the raw markup) UI (BoardChat.tsx): - Handle type: 'action' SSE events in the reader loop, collecting into actionEvents state - Render ResolutionCard components below the streaming text bubble and below the last persisted assistant comment Skill (SKILL.md): - Add 'Structured Action Signals' section teaching the model to emit %%ACTIONS%% blocks after creating/updating work objects - Document 7 object type/action pairs with format, examples, and 5 critical rules Verification: - Server board-chat tests (5): PASS - Server openapi-routes tests (4): PASS - Server typecheck: PASS - UI BoardChat tests (4): PASS - UI BoardChat CSS guard tests (2): PASS - UI typecheck: PASS * docs(support): assess Workstream C commit 0d4626e — chat-to-work resolution cards (BOARD-1) Commit 0d4626e lands the Workstream C chat-to-work resolution gap: the board skill's %%ACTIONS%% structured signals are now parsed server-side and emitted as typed SSE 'action' events, and the Board Chat UI renders them as clickable resolution cards (Issue/Plan/Approval/Knowledge/Memory/Decision) below the assistant bubble. Documentation impact: new user-facing UI behavior in the Conference Room. Applied improvements: - NEW support case assessment (support-case-v0.4.0-chat-to-work-resolution.md): feature overview, card type table, feature flag/gating, known limitations, troubleshooting, error states, escalation paths - v0.4.0-alpha release notes: highlight #10 + verification line + related docs - docs/support/README.md: assessment table + release notes index - docs/releases.md: v0.4.0-alpha highlights entry * docs(release): Release Engineer heartbeat — VOY-1264 blocked on CEO disposition of VOY-1273 (M-1) * docs(release): Release Engineer heartbeat — deployment verified, stale UI rebuilt, RC-3 tagged (VOY-1264) * docs(support): RC-3 docs sync — Knowledge Browser UI, search route fix, manager-chain permissions (VOY-1303) RC-3 (VOY-1264) ships three items with zero prior documentation coverage; prior syncs (8074df8, ee5693f) covered the Plan Board UI surface only: - Knowledge Browser UI (f09cf3b): new /knowledge page — search, list, detail sheet, revisions/diff, backlinks, create/edit. Added release highlight #8 + support assessment section. - Knowledge search route fix (f09cf3b): /knowledge/search was unreachable (matched :documentId). Added highlight #11, support note, 404 error state, escalation row. - Manager-chain authorization grant (f09cf3b): managers may comment on/mutate issues assigned to reporting-subtree agents. New KB article (authorization-manager-chain-grant.md), highlight #12, escalation row. Version references updated to v0.4.0-alpha-rc.3 across releases.md (/documentation/releases), support README, and release notes header. * docs(support): log heartbeat + documentation health report (2026-08-17) — idle, pipeline blocked on C-fixes * docs(support): log heartbeat — C-fixes resolved, Staff Engineer review in progress, docs current (2026-08-17 01:45 UTC) * docs(support): update health report — C-fixes resolved, review in progress * docs(support): accept Founding Engineer's PostHog SOP update — bash script impl, per-signature issues, dedup cooldown The Founding Engineer (57fa7e0e) updated the PostHog Error Monitoring Triage SOP to reflect the actual implementation (bash script, per-error-signature issue creation, 60-minute cooldown dedup, pending retry directory). Version 1.2 upgraded from draft to final, pending VPS-1 cron setup. Collaboration: FE authored implementation changes, SE reviewed and committed. * fix(v0.4.0): commit Phase 5 C-fixes (C-1 Zod validation, C-2 TOCTOU safety, C-3 plainto_tsquery) C-1: LLM Trust Boundary — validate SSE action signals with Zod before emission C-2: TOCTOU Race — post-insert SLA dedup safety net for concurrent requests C-3: Replace to_tsquery with plainto_tsquery to handle user special chars safely All 3 fixes reviewed and approved by Staff Engineer. * feat(v0.4.0): Phase 5 remaining — memory extraction jobs, batch gate counts, live events, UI refinements - Add memory extraction job service (server/src/services/memory-extraction-jobs.ts) - Add extraction job API routes (GET/POST /companies/:cid/memory/extraction-jobs) - Add listGateCounts to plan-review-gates service with companyId tenant filter - Add plan.gate_created live event type to shared constants - Add gatesCount field to IssueDocument type for batch-fetch support - Wire extraction job routes and service exports in server registry - Add Memory Browser UI with extractions tab, source hyperlinks, latency/cost display - Add ExtractionJobsDashboard component with 15s polling - Add AgentMemoryTab and CompanyMemoryTab page routes - Add parsePlanMetadata utility with Zod schema validation - Add LiveUpdatesProvider handlers for plan.gate_created and plan.gate_resolved - Fix Plans.tsx N+1 by using inline planDocument + gatesCount from batch list - Fix PlanDecompositionWizard and PlanDetailSection to use parsePlanMetadata - Fix PlanRevisionBrowser error/retry state for diff loading - Add CompanySettingsNav and CompanySettingsSidebar Memory nav items - Add memory API methods (bindings, targets, extraction-jobs) - Add queryKeys for memory extraction-jobs, targets, agent-config - Fix board-chat.ts regex capture group for turn tag escaping - Update .env.example with PostHog monitoring documentation All changes reviewed and approved by Staff Engineer. * docs(support): log heartbeat — no new code, docs synced through RC-4, pipeline stalled on founder actions * docs(support): log heartbeat — no new code, server down, working tree shows active VOY-1205 development * feat(v0.4.0): promoteFromMemory, search cache, REINDEX endpoint, capabilities, docs sync - Add promoteFromMemory endpoint: memory records can be promoted to draft knowledge documents with auto-generated backlinks - Add knowledge search cache: in-memory LRU cache (200 entries, 5min TTL) reduces repeated FTS overhead - Add REINDEX maintenance endpoint: POST .../knowledge/maintenance/rebuild-index for pgvector HNSW index rebuilds - Add capabilities endpoint: GET .../memory/bindings/:bindingId/capabilities returns resolved capabilities - Docs: update memory.md (extraction jobs API), releases.md (RC-4), README.md, assessments, release notes VOY-1322 * fix(ci): add --fail-with-body to all mutation curl calls in SKILL.md Policy check requires --fail-with-body on all curl mutations to detect silent 4xx/5xx failures. This addresses the PR #45 policy check failure. * fix(ci): add --fail-with-body to curl in docs/adapters/overview.md Policy check requires --fail-with-body on all curl mutations. This file was flagged in the PR diff and needs the same fix as SKILL.md. * fix(test): add missing planDocumentService mock and Memory tab assertion - document-annotation-routes.test.ts: add planDocumentService mock to fix 'No planDocumentService export' vitest error - CompanySettingsNav.test.tsx: add Memory tab to expected tab items * fix(test): add planReviewGateService mock to document-annotation-routes test * fix(test): add planDocumentService and planReviewGateService mocks * docs(support): sync Deep Planning QA verification docs — plan acceptance flow, diff schema, support case (VOY-1326) --------- Co-authored-by: CTO <cto@paperclip.local> Co-authored-by: Paperclip <noreply@paperclip.ing>
1 parent 08d9eef commit 6e709ed

303 files changed

Lines changed: 882638 additions & 281 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
1-
DATABASE_URL=postgres://paperclip:paperclip@localhost:5432/paperclip
1+
DATABASE_URL=postgres://paperclip:***@localhost:5432/paperclip
22
PORT=3100
33
SERVE_UI=false
44
BETTER_AUTH_SECRET=paperclip-dev-secret
55

66
# Discord webhook for daily merge digest (scripts/discord-daily-digest.sh)
77
# DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/...
8+
9+
# PostHog error monitoring (scripts/posthog-error-monitor.sh)
10+
# POSTHOG_API_KEY=p phx_... # PostHog personal API key (or POSTHOG_PERSONAL_API_KEY)
11+
# POSTHOG_PROJECT_ID=project-id # PostHog project ID
12+
# POSTHOG_HOST=https://us.posthog.com # PostHog host (default)
13+
14+
# Paperclip API for issue creation (needed by posthog-error-monitor.sh)
15+
# PAPERCLIP_API_URL=http://localhost:3100
16+
# PAPERCLIP_API_KEY=...

.github/workflows/pr.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ jobs:
222222
# Preserve the legacy required-check name while the underlying work runs in parallel.
223223
name: verify
224224
if: ${{ always() }}
225-
needs: [typecheck_release_registry, general_tests, build]
225+
needs: [typecheck_release_registry, general_tests, build, verify_serialized_server, e2e]
226226
runs-on: ubuntu-latest
227227
timeout-minutes: 5
228228

@@ -232,10 +232,14 @@ jobs:
232232
TYPECHECK_RELEASE_REGISTRY_RESULT: ${{ needs.typecheck_release_registry.result }}
233233
GENERAL_TESTS_RESULT: ${{ needs.general_tests.result }}
234234
BUILD_RESULT: ${{ needs.build.result }}
235+
VERIFY_SERIALIZED_SERVER_RESULT: ${{ needs.verify_serialized_server.result }}
236+
E2E_RESULT: ${{ needs.e2e.result }}
235237
run: |
236238
test "$TYPECHECK_RELEASE_REGISTRY_RESULT" = "success"
237239
test "$GENERAL_TESTS_RESULT" = "success"
238240
test "$BUILD_RESULT" = "success"
241+
test "$VERIFY_SERIALIZED_SERVER_RESULT" = "success"
242+
test "$E2E_RESULT" = "success"
239243
240244
build:
241245
name: Build

.gstack/browse-audit.jsonl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{"ts":"2026-08-15T11:35:25.698Z","cmd":"status","args":"","origin":"about:blank","durationMs":10,"status":"ok","hasCookies":false,"mode":"launched"}
2+
{"ts":"2026-08-15T11:35:57.468Z","cmd":"goto","args":"https://southeastaksupply.com/","origin":"https://southeastaksupply.com/","durationMs":665,"status":"ok","hasCookies":false,"mode":"launched"}
3+
{"ts":"2026-08-15T11:35:57.757Z","cmd":"snapshot","args":"-i","origin":"https://southeastaksupply.com/","durationMs":131,"status":"ok","hasCookies":false,"mode":"launched"}
4+
{"ts":"2026-08-15T11:35:57.861Z","cmd":"console","args":"--errors","origin":"https://southeastaksupply.com/","durationMs":3,"status":"ok","hasCookies":false,"mode":"launched"}
5+
{"ts":"2026-08-15T11:35:57.962Z","cmd":"text","args":"","origin":"https://southeastaksupply.com/","durationMs":6,"status":"ok","hasCookies":false,"mode":"launched"}

.gstack/browse-network.log

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[2026-08-15T11:35:56.886Z] GET https://southeastaksupply.com/ → 200 (349ms, 5829B)
2+
[2026-08-15T11:35:57.251Z] GET https://southeastaksupply.com/new_logo_kurt.jpg → 200 (102ms, 60188B)
3+
[2026-08-15T11:35:57.252Z] GET https://southeastaksupply.com/_next/static/chunks/05367awialsbn.css → 200 (101ms, 8395B)
4+
[2026-08-15T11:35:57.253Z] GET https://southeastaksupply.com/_next/static/chunks/1gdoryk6w2r8v.js → 200 (334ms, 9431B)
5+
[2026-08-15T11:35:57.253Z] GET https://southeastaksupply.com/_next/static/chunks/27jktro2p5rq9.js → 200 (289ms, 9302B)
6+
[2026-08-15T11:35:57.253Z] GET https://southeastaksupply.com/_next/static/chunks/0wgbl93fstlu9.js → 200 (399ms, 71108B)
7+
[2026-08-15T11:35:57.253Z] GET https://southeastaksupply.com/_next/static/chunks/2t2clertbxtfc.js → 200 (390ms, 38718B)
8+
[2026-08-15T11:35:57.253Z] GET https://southeastaksupply.com/_next/static/chunks/turbopack-2vj4-1z_ftx_p.js → 200 (279ms, 4263B)
9+
[2026-08-15T11:35:57.258Z] GET https://southeastaksupply.com/_next/static/chunks/05-c3ty_6dwfk.js → 200 (299ms, 1517B)
10+
[2026-08-15T11:35:57.258Z] GET https://southeastaksupply.com/_next/static/chunks/14mrh2-p_w84d.js → 200 (324ms, 12941B)
11+
[2026-08-15T11:35:57.258Z] GET https://southeastaksupply.com/_next/static/chunks/2kjw82y4wz21v.js → 200 (324ms, 4557B)
12+
[2026-08-15T11:35:57.258Z] GET https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&family=IBM+Plex+Sans:wght@300;400;500;600&family=Libre+Baskerville:wght@400;700&display=swap → 200 (122ms, 1495B)
13+
[2026-08-15T11:35:57.479Z] GET https://fonts.gstatic.com/s/ibmplexsans/v23/zYXzKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1syxeKYbSB4Zh.woff2 → 200 (265ms, 40791B)
14+
[2026-08-15T11:35:57.479Z] GET https://fonts.gstatic.com/s/librebaskerville/v24/kmKnZrc3Hgbbcjq75U4uslyuy4kn0qNZaxMaC82U.woff2 → 200 (264ms, 33988B)
15+
[2026-08-15T11:35:57.479Z] GET https://fonts.gstatic.com/s/ibmplexmono/v20/-F63fjptAgt5VM-kVkqdyU8n1i8q131nj-o.woff2 → 200 (263ms, 10170B)

.gstack/claude-available.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"available": true,
3+
"path": "/opt/homebrew/bin/claude",
4+
"install_url": "https://docs.anthropic.com/en/docs/claude-code",
5+
"checked_at": "2026-08-15T11:36:25.628Z"
6+
}

.worktrees/fix-pii-scrubbing

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit b4a23138208ea3d302939866f35fe1224f3ffffe

.worktrees/fix-tree-control-races

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit ad961227f57a217655c9e05e5987e6d0e5524409

.worktrees/ram-861-secfixes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit 263b47d7d2651bb76bf5268361837b02fbcc89db

.worktrees/ram-923-ciso-grants

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit a328ec953aadc3cea9c683dd9c72fa5a84eca25c

.worktrees/ram-924-gate-primitive

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Subproject commit a328ec953aadc3cea9c683dd9c72fa5a84eca25c

0 commit comments

Comments
 (0)