Skip to content

Per-file metadata: post-ship follow-ups (#157/#158) #159

Description

@zachdunn

Per-file metadata shipped in #157 (+ the #158 route hotfix) and the gh backfill has run in production (40/40 objects in the default workspace). This issue tracks the deliberately deferred follow-ups.

Ship the CLI

  • Merge the version-packages PR (chore: version packages #144) so put --meta, meta get|set, ls --meta, find, and the MCP set_metadata/find_files tools actually reach npm. Nothing published today (0.7.0) has the new commands.

Product follow-ups

  • Web search UI — a metadata search page (likely under /me), now that the API/CLI filter path is proven. Out of scope for feat: per-file metadata — PR/issue context, custom tags, and search #157 by design.
  • Presigned-upload capturePOST /sign uploads bypass the API worker, so they capture no metadata. Fold into the /v1/sign roadmap item (accept metadata in the sign request or reconcile after).
  • Legacy buildinternet workspace sweep — all current gh/ attachment keys live in default, but if the BYO buildinternet bucket holds pre-API gh/ objects, mint a workspace token (/admin/tokens) and re-run apps/api/scripts/backfill-gh-metadata.mjs against it.
  • Consider metadata on gallery items, value-type schemas, and per-workspace key policies (all explicitly out of scope in the design doc).

Small engineering debts (from review, none merge-blocking)

  • Remote MCP set_metadata throws a bare Error("object not found") instead of a typed NotFoundError — inconsistent with the worker's other handlers.
  • Metadata-filtered listings (?meta.*) carry no visibility annotation (it lives in R2 custom metadata; hydrating costs a HEAD per result). Documented caveat in routes/files.ts — decide if it ever needs a real fix.
  • getFileMetadata doesn't wrap raw D1 failures in an AppError; a transient D1 error on the public /f/ path surfaces as an untyped 500.
  • Extract the repeated badKey + store.exists block shared by the raw and metadata handlers in routes/files.ts.
  • packages/errors has no exhaustiveness check tying code: string literals to the ERROR_CODES registry — file_metadata_duplicate_filter shipped unregistered until review caught it.
  • Backfill script niceties: UPLOADS_API_URL silently defaults to prod (matches sibling-script precedent but this one bulk-writes); --workspace=foo form unsupported.

Accepted tradeoffs (documented in code — listed so nobody re-litigates by accident)

  • Caps enforcement has a read-validate-write race under concurrent merges (same accepted last-write-wins model as visibility rewrites; single-tenant behind the write rate limiter).
  • Re-PUT semantics: custom X-Uploads-Meta-* headers present → full metadata replace; absent → preserve. Documented in SKILL.md and the CLI help.
  • Hono router lesson from fix: metadata endpoints 404 on real keys in production #158: never register a route with a static suffix after a {.+} param — vitest matches it, the deployed router doesn't. Verify routing on a preview worker.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions