Skip to content

Fix: 4 issues (#95, #96, #97, #98) - #133

Merged
victorisiguzoruzoma874 merged 3 commits into
SynapsVault:mainfrom
jasmine874:simple/95-96-97-98
Oct 18, 2026
Merged

victorisiguzoruzoma874 merged 3 commits into
SynapsVault:mainfrom
jasmine874:simple/95-96-97-98

Conversation

@jasmine874

Copy link
Copy Markdown
Contributor

Closes #95
Closes #96
Closes #97
Closes #98

Issues

#95 Error response shapes differ across the paywall, multer, not-found and app errors

Where

src/middleware/dynamicPaywall.ts (res.status(...).json({ error })); src/middleware/uploadGuards.ts (413, 400, 415); src/middleware/errorHandler.ts (notFoundHandler adds code).

Problem

Clients have to handle several body shapes. Some responses have no code or requestId.

Expected

Route all of these through AppError so every error has error, code and requestId.

Acceptance criteria

  • Snapshot tests cover each error path.
  • The OpenAPI error schema matches.

#96 Verification prompt includes the listing text with no separation from instructions

Where

src/services/verificationService.ts (checkOriginality puts content.slice(0, 10000) into the user message); POST /verify-content.

Problem

The caller controls the text the model judges. Instructions embedded in the text can push the model to approve it, and an approval lists the resource automatically.

Expected

Delimit the input, tell the model to ignore instructions inside it, and add a deterministic check or a review step before a listing changes.

Acceptance criteria

  • An adversarial test set lives in the repo.
  • An injected 'approve this' instruction does not change the outcome.

#97 Verification output parsing is fragile

Where

src/services/verificationService.ts (replace(/^```json\s*/i, ...); Number(parsed.confidence) || 0).

Problem

Replies wrapped in a plain ``` fence fail to parse and are recorded as rejected. Confidence is not clamped, so 5 or -1 is stored as-is.

Expected

Strip any fence or extract the first JSON object. Clamp confidence to 0–1 and reject non-finite values.

Acceptance criteria

  • Plain fences, bare JSON and out-of-range confidence are each covered by a test.

#98 /agent/status loads every verification into memory to compute counters

Where

src/routes/verify.ts (GET /agent/status).

Problem

Each request reads the whole verifications table. Cost grows with usage.

Expected

Compute counts and sums with SQL aggregates, and fetch only the 10 most recent rows for the activity list.

Acceptance criteria

  • No request reads the full table.
  • The totals match the old values in a test.

Summary

The unified error shape must preserve the existing error message field for backward compatibility while always adding code and requestId. For #96, the deterministic check should be conservative: suspicious content should force a non-original result or a review flag rather than auto-approving. For #97, use a balanced-brace extractor rather than a greedy regex to find the first JSON object. For #98, use drizzle sql template expressions for aggregates and keep the response shape identical; the test should compare against the old in-memory totals.

Changes

  • Add a shared helper sendError(res, error) (or respondWithError) that serializes any thrown value via serializeError(error, getRequestId()) and writes it with getStatusCode(error). Also add convenience constructors or ensure AppError covers the codes needed by the paywall (e.g. a SERVICE_UNAVAILABLE for chain_unavailable and CONFLICT for price_mismatch). Keep serializeError as the single source of truth so every body has error, code and requestId. (src/lib/errors.ts)
  • Replace the ad-hoc res.status(...).json({...}) calls in dynamicPaywall with AppError throws (or sendError): 404 NOT_FOUND for missing/unlisted resources, 503 SERVICE_UNAVAILABLE for chain lookup failure (preserve the human message and resourceId in details), and 409 CONFLICT for price mismatch (same). This makes every paywall error body include error, code and requestId. (src/middleware/dynamicPaywall.ts)
  • Route multer/upload-guard failures through AppError: map LIMIT_FILE_SIZE to PAYLOAD_TOO_LARGE (413), other MulterErrors to VALIDATION_ERROR (400), and validateUpload failures to AppError with the mapped status (415 → VALIDATION_ERROR or a dedicated code) instead of writing { error } directly. Use next(new AppError(...)) so the global handler emits error, code and requestId. (src/middleware/uploadGuards.ts)
  • Make notFoundHandler delegate to the shared serializer (e.g. res.status(404).json(serializeError(new AppError("NOT_FOUND", Route ${req.method} ${req.path} not found), getRequestId()))) so the not-found body has the same shape as every other error. Keep the existing errorHandler behaviour. (src/middleware/errorHandler.ts)
  • Update the paywall tests to assert the unified error shape (error, code, requestId) for the 404, 503 and 409 paths, using toMatchSnapshot() or explicit object assertions. Mock getRequestId to a fixed value so snapshots are stable. (src/middleware/dynamicPaywall.test.ts)
  • Add snapshot/assertion coverage for the 413, 400 and 415 upload-guard responses, checking that each body contains error, code and requestId (mock getRequestId). (src/middleware/uploadGuards.test.ts)
  • Extend the error-handler tests with snapshot assertions for the not-found handler and generic app errors, confirming all bodies include error, code and requestId. (src/middleware/errorHandler.test.ts)
  • Update the OpenAPI Error schema (and any paywall-specific error responses) so it documents error, code (enum of ErrorCode), optional details and requestId, matching the unified serializer output. Ensure the 402/404/409/413/415/503 responses reference this schema. (src/openapi.ts)
  • Harden checkOriginality: wrap the untrusted content.slice(0, 10000) in explicit delimiters (e.g. <untrusted_content>...</untrusted_content>) and add system instructions telling the model to treat everything inside as data and ignore any instructions it contains. Add a deterministic heuristic scan (e.g. regex for 'ignore previous instructions', 'approve this', etc.) that forces isOriginal: false / a review flag when suspicious patterns are found, and require a confidence threshold before auto-approving. Also replace the fragile fence regex with a helper that strips any code fence or extracts the first balanced JSON object, and clamp confidence with Number.isFinite to [0,1] (rejecting non-finite values). (src/services/verificationService.ts)
  • Add tests for the hardened verification service: an adversarial fixture set (injected 'approve this' / 'ignore previous instructions' content) asserting the outcome is unchanged, plus parsing tests for plain ``` fences, bare JSON, and out-of-range/non-finite confidence values (clamped or rejected). (src/services/verificationService.usage.test.ts)
  • Rewrite GET /agent/status to compute counters with SQL aggregates (COUNT(*), COUNT(*) FILTER (WHERE is_original), SUM(estimated_cost), AVG(confidence)) via drizzle sql expressions, and fetch only the 10 most recent rows with ORDER BY checked_at DESC LIMIT 10 for the activity list. Keep the existing response shape and the batched title lookup for those 10 rows. Also ensure the verification route respects the new review/deterministic check from Verification prompt includes the listing text with no separation from instructions #96 before setting listed: true. (src/routes/verify.ts)
  • Update the agent-status tests to mock the aggregate query results and assert the totals match the previous in-memory computation, and that only 10 recent rows are fetched. Add a test that an injected 'approve this' instruction in content does not cause the resource to be listed. (src/routes/verify.agent-status.test.ts)
  • Update the verify route tests to reflect the new aggregate-based /agent/status and the review/deterministic check before listing, ensuring existing behaviour (ownership, hash match, admin delist) still passes. (src/routes/verify.test.ts)
  • Add any index needed to support the aggregate and recent-activity queries efficiently (e.g. an index on verifications.checked_at for ORDER BY checked_at DESC LIMIT 10). (src/db/schema.ts)

Co-authored-by: Simple Agent <agent@simple.dev>
@vercel

vercel Bot commented Oct 18, 2026

Copy link
Copy Markdown

@jasmine874 is attempting to deploy a commit to the work Team on Vercel.

A member of the Team first needs to authorize it.

@drips-wave

drips-wave Bot commented Oct 18, 2026

Copy link
Copy Markdown

@jasmine874 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

- src/db/schema.ts: merged [markers] — model resolved the conflict markers
- src/middleware/dynamicPaywall.ts: merged [markers] — model resolved the conflict markers
- src/middleware/uploadGuards.ts: merged [markers] — model resolved the conflict markers

Co-authored-by: Simple Agent <agent@simple.dev>
- src/routes/verify.ts: merged [markers] — model resolved the conflict markers

Co-authored-by: Simple Agent <agent@simple.dev>
@victorisiguzoruzoma874
victorisiguzoruzoma874 merged commit 193a586 into SynapsVault:main Oct 18, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants