Skip to content

refactor(ipns): drop folder/file record_type discriminator#562

Merged
FSM1 merged 3 commits into
mainfrom
refactor/drop-ipns-record-type-discriminator
Jun 25, 2026
Merged

refactor(ipns): drop folder/file record_type discriminator#562
FSM1 merged 3 commits into
mainfrom
refactor/drop-ipns-record-type-discriminator

Conversation

@FSM1

@FSM1 FSM1 commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Summary

Completely removes the record_type / recordType discriminator ('folder' vs 'file') for IPNS records across the whole monorepo.

It was write-only metadata the client volunteered to a zero-knowledge server: nothing functional (TS or Rust) branched on it, the server never returned it, and it was consumed only by a single Prometheus gauge label plus two log strings. Rather than teach the client to tag every record, the field is deleted end to end. The functional expectedSequenceNumber CAS field is left untouched.

Layers touched

  • Client / SDK — drop recordType from the sdk-core registration builders and the ipns / shared-write batch payloads, and from the apps/web ipns.service.
  • API — remove recordType from PublishIpnsEntryDto, from the publishRecord / upsertFolderIpns signatures and object literals, and strip the ${recordType} prefix from the two republish-enrollment log strings.
  • Database — drop the folder_ipns.record_type column (entity + new migration DropFolderIpnsRecordType that inverts AddRecordTypeToFolderIpns).
  • Metrics — collapse cipherbox_ipns_entries_total from a record_type-labelled, group-by-and-seed collection to a single untyped folder_ipns row count.
  • Grafana — remove the record_type-broken-down "IPNS Entries by Type" panel (a "Total IPNS Entries" panel already exists) and convert "IPNS Entry Growth" to a single sum(cipherbox_ipns_entries_total) series; update docker/MONITORING.md. No panel references the record_type label anymore and the JSON still parses.
  • Generated client — regenerated @cipherbox/api-client (removed the orphaned publishIpnsEntryDtoRecordType model + barrel export, refreshed openapi.json).

Tests

Updated to drop recordType fixtures/assertions:

  • packages/sdk-core/src/__tests__/folder.test.ts — assert via expectedSequenceNumber instead of recordType.
  • apps/api/src/ipns/ipns.service.spec.ts and apps/api/src/ipns/ipns-verify-cache.spec.ts — dropped recordType fixtures.
  • apps/api/src/metrics/metrics.service.spec.ts — regression block now asserts a single untyped gauge value; mockFolderIpnsRepo exposes count().

Verification

  • Typecheck: api (nest build), sdk-core, sdk, web (tsc -b) — all clean.
  • Lint / prettier: clean on changed files.
  • Targeted tests: metrics.service (11), ipns.service (98), sdk-core folder suite (252) — all pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • IPNS publishing now uses a simpler payload format without record type selection in batch actions.
    • Metrics and dashboards now show total IPNS entries instead of separate folder/file breakdowns.
  • Bug Fixes

    • Improved consistency across IPNS publishing, storage, and verification flows.
    • Updated monitoring visuals and documentation to match the new total-count metric.

The record_type ('folder' vs 'file') discriminator was write-only metadata
the client volunteered to a zero-knowledge server. Nothing functional (TS or
Rust) branched on it and the server never returned it — it fed only a single
Prometheus gauge label and two log strings. Rather than teach the client to tag
every record, remove the field entirely across the stack. The functional
expectedSequenceNumber CAS field is untouched.

Layers touched:

- Client / SDK: drop recordType from sdk-core registration builders and the
  ipns/shared-write batch payloads, and from apps/web ipns.service.
- API: remove recordType from the PublishIpnsEntryDto, the publishRecord /
  upsertFolderIpns signatures and object literals, and strip the type prefix
  from the two republish-enrollment log strings.
- DB: drop the folder_ipns.record_type column (entity + a new migration
  DropFolderIpnsRecordType inverting AddRecordTypeToFolderIpns).
- Metrics: collapse the cipherbox_ipns_entries_total gauge from a
  record_type-labelled, group-by-and-seed collection to a single untyped
  folder_ipns row count.
- Grafana: drop the record_type-broken-down "IPNS Entries by Type" panel (a
  "Total IPNS Entries" panel already exists) and convert "IPNS Entry Growth"
  to a single sum() series; update docker/MONITORING.md.
- Regenerated @cipherbox/api-client (removed the orphaned
  publishIpnsEntryDtoRecordType model + barrel export, refreshed openapi.json).

Tests updated to drop recordType fixtures/assertions; the metrics regression
test now asserts a single untyped gauge value.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SDNQVLoAw4DbPrPvtQPobh
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@FSM1, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 34 minutes and 53 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 244f7081-000c-4e67-9a4f-eebd26792d84

📥 Commits

Reviewing files that changed from the base of the PR and between 89805b6 and 89bc5d0.

📒 Files selected for processing (4)
  • apps/api/src/ipns/ipns.service.ts
  • apps/api/src/metrics/metrics.service.spec.ts
  • docker/grafana/dashboards/cipherbox-staging.json
  • packages/sdk-core/src/__tests__/folder.test.ts

Walkthrough

IPNS publish contracts, storage, SDK payloads, and dashboards stop using recordType; the API migration drops the column, and release target versions are bumped for affected packages.

Changes

IPNS recordType removal

Layer / File(s) Summary
Publish contract and storage shape
apps/api/src/ipns/dto/publish.dto.ts, apps/api/src/ipns/entities/folder-ipns.entity.ts, apps/api/src/migrations/1749400000000-DropFolderIpnsRecordType.ts
PublishIpnsEntryDto, FolderIpns, and the migration remove the recordType field and column.
API publish flow
apps/api/src/ipns/ipns.service.ts, apps/api/src/ipns/ipns.service.spec.ts, apps/api/src/ipns/ipns-verify-cache.spec.ts
publishRecord, publishBatch, and upsertFolderIpns stop threading recordType, and the service fixtures and batch tests drop the field.
SDK batch publish requests
packages/sdk-core/src/ipns/index.ts, apps/web/src/services/ipns.service.ts, packages/sdk/src/share/shared-write.ts
batchPublishIpnsRecords stops carrying recordType, and the web and shared-write callers stop adding it to outgoing batch items.
Folder registration payloads
packages/sdk-core/src/folder/registration.ts, packages/sdk-core/src/__tests__/folder.test.ts
buildFolderIpnsRecord and folder batch publish call sites stop injecting recordType, and the folder tests assert sequencing instead of type labels.
IPNS total metric
apps/api/src/metrics/metrics.service.ts, apps/api/src/metrics/metrics.service.spec.ts, docker/MONITORING.md, docker/grafana/dashboards/cipherbox-staging.json
ipnsEntriesTotal switches to a single total count, and the metric tests, monitoring table, and Grafana panels follow that shape.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • FSM1/cipher-box#133: Adds the recordType/record_type contract that this PR removes from the API, storage, and SDK flows.
  • FSM1/cipher-box#309: Touches the same web IPNS batch-publish service file and related recordType type import that this PR deletes.
  • FSM1/cipher-box#561: Changes the same IPNS total metric code path and tests in metrics.service.ts.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing the folder/file record_type discriminator from IPNS records.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/drop-ipns-record-type-discriminator

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added release:api:refactor Patch version bump (code refactoring) for api release:web:refactor Patch version bump (code refactoring) for web release:sdk-core:refactor Patch version bump (code refactoring) for sdk-core release:sdk:refactor Patch version bump (code refactoring) for sdk release:tee-worker:fix Patch version bump (bug fix) for tee-worker release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Release Preview

Package Bump Label Source
api patch release:api:refactor Direct (refactor commit)
cipherbox-fuse patch release:cipherbox-fuse:fix Cascade (api patch)
cipherbox-sdk patch release:cipherbox-sdk:fix Cascade (api patch)
desktop minor release:desktop:fix Cascade (api patch)
sdk patch release:sdk:refactor Direct (refactor commit)
sdk-core patch release:sdk-core:refactor Direct (refactor commit)
tee-worker patch release:tee-worker:fix Cascade (sdk-core patch)
web minor release:web:refactor Direct (refactor commit)

Cascade Details

  • sdk-core patch -> tee-worker patch (direct dependency)
  • api patch -> cipherbox-fuse patch (direct dependency)
  • api patch -> cipherbox-sdk patch (direct dependency)
  • api patch -> desktop patch (direct dependency)

@github-actions github-actions Bot added the release:desktop:fix Patch version bump (bug fix) for desktop label Jun 25, 2026
@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR removes the record_type / recordType discriminator ('folder' vs 'file') end-to-end across the monorepo. The field was write-only — the server never returned it, no control flow branched on it — so the cleanup is purely mechanical: DTO, entity, service signatures, SDK payloads, generated client, Prometheus gauge label, Grafana panels, and a column-drop migration.

  • API/DB layer: recordType removed from PublishIpnsEntryDto, FolderIpns entity, and both publishRecord/upsertFolderIpns signatures; migration 1749400000000-DropFolderIpnsRecordType drops the column and inverts cleanly.
  • Metrics: cipherbox_ipns_entries_total simplified from a record_type-labelled group-by gauge to a single repository.count() gauge; Grafana panels updated and the "IPNS Entries by Type" pie chart removed.
  • Client/SDK: publishIpnsEntryDtoRecordType model and barrel export deleted, batchPublishIpnsRecords type signatures narrowed, tests updated to assert via ipnsName and expectedSequenceNumber instead of the former recordType field.

Confidence Score: 5/5

The change is safe to merge: it removes write-only metadata that nothing functional depended on, with consistent updates across every layer (DB migration, entity, DTO, service, SDK, generated client, metrics, Grafana) and passing targeted test suites.

The field being dropped was confirmed write-only (no server return path, no branching logic). The migration is guarded with IF EXISTS / IF NOT EXISTS, all call sites were updated in the same PR, and the metrics simplification is mechanically correct. No orphaned references remain in the checked files.

No files require special attention. The most sensitive file — the TypeORM migration — is straightforward and properly invertible.

Important Files Changed

Filename Overview
apps/api/src/migrations/1749400000000-DropFolderIpnsRecordType.ts New migration: up drops the column with IF EXISTS guard; down re-adds it idempotently via a PL/pgSQL DO block. Straightforward inverse of AddRecordTypeToFolderIpns.
apps/api/src/metrics/metrics.service.ts Gauge changed from labelled (record_type) group-by query to a single repository.count() call; reset()/seed loop removed. Correctly reports an explicit 0 on an empty table without stale label issues.
apps/api/src/ipns/ipns.service.ts recordType parameter removed from publishRecord and upsertFolderIpns; all call sites updated. Log strings improved to use err instanceof Error ? err.message : String(err).
apps/api/src/ipns/dto/publish.dto.ts recordType field and its @IsIn(['folder','file']) validator removed from PublishIpnsEntryDto; IsIn import cleaned up.
packages/sdk-core/src/folder/registration.ts recordType: 'file' spread removed from all three batch-publish call sites (addFileToFolder, addFilesToFolder, replaceFileInFolder); return type of buildFolderIpnsRecord narrowed accordingly.
packages/sdk-core/src/tests/folder.test.ts Assertions migrated from recordType checks to positive ipnsName and expectedSequenceNumber identity checks; the previous thread's concern about weak identity was addressed here.
apps/api/src/metrics/metrics.service.spec.ts Mock simplified to count() stub; regression tests now assert a single sample line and guard record_type= never appears in the serialized metric.
packages/api-client/src/models/publishIpnsEntryDtoRecordType.ts File deleted; barrel export in index.ts updated; all imports of PublishIpnsEntryDtoRecordType in the SDK and web service removed.
docker/grafana/dashboards/cipherbox-staging.json "IPNS Entries by Type" pie chart panel removed; "Total IPNS Entries" and "IPNS Entry Growth" queries updated to max(cipherbox_ipns_entries_total) for the now-unlabelled single-series gauge.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client as Client / SDK
    participant API as API (publishRecord)
    participant DB as folder_ipns table
    participant Metrics as MetricsService

    Note over Client,Metrics: Before — recordType threaded through every layer
    Client->>API: "{ ipnsName, record, metadataCid, recordType: 'file'|'folder', ... }"
    API->>DB: upsertFolderIpns(..., recordType)
    DB-->>API: saved row (record_type column updated)
    Metrics->>DB: GROUP BY record_type
    DB-->>Metrics: "[{recordType:'folder',count:'N'},{recordType:'file',count:'M'}]"
    Metrics->>Metrics: gauge.labels('folder').set(N) / gauge.labels('file').set(M)

    Note over Client,Metrics: After — recordType removed end-to-end
    Client->>API: "{ ipnsName, record, metadataCid, ... }"
    API->>DB: upsertFolderIpns(...)
    DB-->>API: saved row (record_type column dropped)
    Metrics->>DB: repository.count()
    DB-->>Metrics: total row count
    Metrics->>Metrics: gauge.set(total)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client as Client / SDK
    participant API as API (publishRecord)
    participant DB as folder_ipns table
    participant Metrics as MetricsService

    Note over Client,Metrics: Before — recordType threaded through every layer
    Client->>API: "{ ipnsName, record, metadataCid, recordType: 'file'|'folder', ... }"
    API->>DB: upsertFolderIpns(..., recordType)
    DB-->>API: saved row (record_type column updated)
    Metrics->>DB: GROUP BY record_type
    DB-->>Metrics: "[{recordType:'folder',count:'N'},{recordType:'file',count:'M'}]"
    Metrics->>Metrics: gauge.labels('folder').set(N) / gauge.labels('file').set(M)

    Note over Client,Metrics: After — recordType removed end-to-end
    Client->>API: "{ ipnsName, record, metadataCid, ... }"
    API->>DB: upsertFolderIpns(...)
    DB-->>API: saved row (record_type column dropped)
    Metrics->>DB: repository.count()
    DB-->>Metrics: total row count
    Metrics->>Metrics: gauge.set(total)
Loading

Reviews (2): Last reviewed commit: "fix: address PR review comments" | Re-trigger Greptile

Comment thread packages/sdk-core/src/__tests__/folder.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/api/src/ipns/ipns.service.ts (1)

349-360: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Normalize the enrollment rejection before logging it.

Lines 360 and 397 assume enrollFolder() always rejects with an Error. If it rejects with a string, null, or another non-Error value, err.message throws inside this detached .catch(), which drops the warning and can surface as an unhandled rejection. Please format these the same way as the delegated-routing error handling above.

Suggested fix
-          .catch((err) =>
-            this.logger.warn(`Failed to enroll ${ipnsName} for republishing: ${err.message}`)
-          );
+          .catch((err) =>
+            this.logger.warn(
+              `Failed to enroll ${ipnsName} for republishing: ${err instanceof Error ? err.message : String(err)}`
+            )
+          );

Also applies to: 386-397

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/src/ipns/ipns.service.ts` around lines 349 - 360, Normalize the
`enrollFolder()` rejection before logging in `ipns.service.ts`, since the
detached `.catch()` in the republish flow assumes an `Error` and can throw again
if the rejection is a string, null, or other value. Update the warning handling
in the `republishService.enrollFolder(...)` branches to match the
delegated-routing error normalization pattern already used nearby, and log a
safe message derived from the normalized error instead of directly accessing
`err.message`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/metrics/metrics.service.spec.ts`:
- Around line 149-152: Tighten the assertions in metrics.service.spec.ts around
the metric rendering for metric names like cipherbox_ipns_entries_total so the
test fails if collectGauges() emits legacy record_type-labeled series again.
Update the existing expectations near the single-metric checks to verify the
rendered output contains exactly one sample line for the aggregate metric and
explicitly does not include any record_type= labels, rather than only matching a
0 or 5 value. Use the existing service.registry.getSingleMetricAsString and
metric variable assertions to locate the affected tests.

In `@apps/api/src/migrations/1749400000000-DropFolderIpnsRecordType.ts`:
- Around line 16-34: The migration in DropFolderIpnsRecordType is not truly
reversible because up() drops the only stored record_type values and down()
repopulates every row with a fabricated default. Fix this by either preserving
the existing discriminator values before ALTER TABLE in up() so down() can
restore them correctly, or by making the down() path explicitly irreversible
instead of recreating the column with a blanket 'folder' value. Keep the fix
centered on the QueryRunner migration methods up() and down() and ensure
rollback does not silently relabel file entries.

In `@docker/grafana/dashboards/cipherbox-staging.json`:
- Around line 772-773: The Grafana panel query for cipherbox_ipns_entries_total
is overcounting because it uses a summing aggregate across replicas; update the
dashboard expression in the IPNS entries panel to use a deduping single-series
aggregate such as max() instead of sum(), so it reflects the actual DB total
from MetricsService.collectGauges() and the folder_ipns row count exported by
each API instance.

In `@release-please-config.json`:
- Line 69: The current release-as targets for the contract removals are patch
versions, which under-version these breaking pre-1.0 changes. Update the
release-please configuration entries tied to the public API DTO and sdk-core
surface removals so they use minor release-as targets instead of 0.44.1 /
0.39.1, keeping the change aligned with the relevant release config symbols in
release-please-config.json.

---

Outside diff comments:
In `@apps/api/src/ipns/ipns.service.ts`:
- Around line 349-360: Normalize the `enrollFolder()` rejection before logging
in `ipns.service.ts`, since the detached `.catch()` in the republish flow
assumes an `Error` and can throw again if the rejection is a string, null, or
other value. Update the warning handling in the
`republishService.enrollFolder(...)` branches to match the delegated-routing
error normalization pattern already used nearby, and log a safe message derived
from the normalized error instead of directly accessing `err.message`.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e0426664-ab16-4dcd-8405-b0a557d0c214

📥 Commits

Reviewing files that changed from the base of the PR and between 99b2586 and 89805b6.

⛔ Files ignored due to path filters (131)
  • packages/api-client/openapi.json is excluded by !packages/api-client/**
  • packages/api-client/src/generated/auth/auth.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/device-approval/device-approval.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/health/health.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/identity/identity.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/invites/invites.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/ipfs/ipfs.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/ipns/ipns.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/root/root.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/share-invites/share-invites.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/shares/shares.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/tee/tee.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/generated/vault/vault.ts is excluded by !**/generated/**, !**/generated/**, !packages/api-client/**
  • packages/api-client/src/models/addShareKeysDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/authMethodResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/authMethodResponseDtoType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/batchPublishIpnsDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/batchPublishIpnsResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/batchUnenrollIpnsDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/batchUnenrollIpnsResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/childKeyDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/childKeyDtoKeyType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/claimChildKeyDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/claimChildKeyDtoKeyType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/claimInviteDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/claimInviteResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/connectionTestRequestDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/connectionTestResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/connectionTestResponseDtoProtocol.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createApprovalDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createInviteDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createInviteDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareDtoPermission.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/createShareResponseDtoPermission.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deleteAccountDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deleteAccountResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/desktopRefreshDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deviceApprovalControllerCreateRequest201.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deviceApprovalControllerGetPending200Item.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deviceApprovalControllerGetStatus200.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/deviceApprovalControllerGetStatus200Status.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/googleLoginDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/googleLoginDtoIntent.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200Details.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200DetailsDatabase.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200Error.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200Info.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/healthControllerCheck200InfoDatabase.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/identityControllerGetJwks200.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/identityControllerGetJwks200KeysItem.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/identityControllerGetWalletNonce200.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/identityTokenResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/index.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/initVaultDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteChildKeyDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteChildKeyDtoKeyType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteDataResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteDataResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteDataResponseDtoStatus.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteResponseDtoStatus.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteStatusResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/inviteStatusResponseDtoStatus.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/ipfsControllerUploadBody.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/ipnsControllerResolveRecordParams.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/linkMethodDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/linkMethodDtoLoginType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/loginDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/loginDtoLoginType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/loginResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/logoutResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/lookupUserResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/paginatedReceivedSharesDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/paginatedSentSharesDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/pendingRotationResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/pendingRotationResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/publishIpnsDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/publishIpnsEntryDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/publishIpnsEntryDtoRecordType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/publishIpnsResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/quotaResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/receivedShareResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/receivedShareResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/receivedShareResponseDtoPermission.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/registerCidDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/registerCidResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/resolveIpnsResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/respondApprovalDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/respondApprovalDtoAction.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sendOtpDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sendOtpResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sentShareResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sentShareResponseDtoItemType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sentShareResponseDtoPermission.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/setByoStatusDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/setByoStatusResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/shareInvitesControllerListInvitesParams.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/shareKeyEntryDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/shareKeyEntryDtoKeyType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/shareKeyResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/shareKeyResponseDtoKeyType.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sharesControllerGetReceivedSharesParams.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sharesControllerGetSentSharesParams.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/sharesControllerLookupUserParams.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/teeKeysDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/testLoginDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/testLoginResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/tokenResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/unlinkMethodDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/unlinkMethodResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/unpinDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/unpinResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/updateEncryptedKeyDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/updateItemNameDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/updatePermissionDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/updatePermissionDtoPermission.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/uploadResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/vaultConfigResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/vaultExportDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/vaultResponseDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/vaultResponseDtoTeeKeys.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/verifyOtpDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/verifyOtpDtoIntent.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/walletVerifyDto.ts is excluded by !packages/api-client/**
  • packages/api-client/src/models/walletVerifyDtoIntent.ts is excluded by !packages/api-client/**
📒 Files selected for processing (16)
  • apps/api/src/ipns/dto/publish.dto.ts
  • apps/api/src/ipns/entities/folder-ipns.entity.ts
  • apps/api/src/ipns/ipns-verify-cache.spec.ts
  • apps/api/src/ipns/ipns.service.spec.ts
  • apps/api/src/ipns/ipns.service.ts
  • apps/api/src/metrics/metrics.service.spec.ts
  • apps/api/src/metrics/metrics.service.ts
  • apps/api/src/migrations/1749400000000-DropFolderIpnsRecordType.ts
  • apps/web/src/services/ipns.service.ts
  • docker/MONITORING.md
  • docker/grafana/dashboards/cipherbox-staging.json
  • packages/sdk-core/src/__tests__/folder.test.ts
  • packages/sdk-core/src/folder/registration.ts
  • packages/sdk-core/src/ipns/index.ts
  • packages/sdk/src/share/shared-write.ts
  • release-please-config.json
💤 Files with no reviewable changes (6)
  • apps/api/src/ipns/entities/folder-ipns.entity.ts
  • packages/sdk/src/share/shared-write.ts
  • packages/sdk-core/src/ipns/index.ts
  • apps/api/src/ipns/ipns-verify-cache.spec.ts
  • apps/web/src/services/ipns.service.ts
  • apps/api/src/ipns/ipns.service.spec.ts

Comment thread apps/api/src/metrics/metrics.service.spec.ts Outdated
Comment thread apps/api/src/migrations/1749400000000-DropFolderIpnsRecordType.ts
Comment thread docker/grafana/dashboards/cipherbox-staging.json Outdated
Comment thread release-please-config.json
- ipns.service: normalize enroll-failure errors before logging (instanceof Error guard)
- metrics spec: assert single ipns_entries_total sample, no record_type label
- folder.test: positive ipnsName identity assertions for file/folder records
- grafana: use max() not sum() for cipherbox_ipns_entries_total (multi-replica dedup)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SDNQVLoAw4DbPrPvtQPobh
@FSM1

FSM1 commented Jun 25, 2026

Copy link
Copy Markdown
Owner Author

Resolved CodeRabbit / greptile review feedback in 89bc5d0c0.

Fixed:

  • Outside-diff (CodeRabbit, apps/api/src/ipns/ipns.service.ts ~349-360 / 386-397): normalized both detached enrollFolder().catch() log paths to err instanceof Error ? err.message : String(err), matching the delegated-routing pattern already used at lines 129/142/195. This PR modified those exact log strings, so the fix is in scope.
  • apps/api/src/metrics/metrics.service.spec.ts: both cipherbox_ipns_entries_total regressions now assert exactly one sample line and not.toContain('record_type=').
  • packages/sdk-core/src/__tests__/folder.test.ts: added positive ipnsName identity assertions for the file/folder records.
  • docker/grafana/dashboards/cipherbox-staging.json: sum() -> max(cipherbox_ipns_entries_total) on both affected panels (243 and 772).

Declined / deferred (replied inline on the threads):

  • Migration down() "irreversibility": record_type was write-only metadata no read path consumes; a schema-only restore with a default is intentional, no historical data is lost.
  • release-please-config.json patch vs minor release-as: the targets were bot-computed from the refactor: commit type; bumping pre-1.0 minor is a release-policy call left to @FSM1.

Verification: targeted jest suites (metrics.service.spec, ipns.service.spec — 109 passed) and sdk-core vitest (252 passed) green; dashboard JSON valid + prettier clean. The 4 pre-existing tsc --noEmit errors in unrelated spec files (ipns-verify-cache.spec.ts, http-metrics.interceptor.spec.ts, share specs) are present on the base and untouched by this change.

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.93%. Comparing base (99b2586) to head (89bc5d0).

Files with missing lines Patch % Lines
apps/api/src/ipns/ipns.service.ts 33.33% 2 Missing ⚠️

❌ Your patch check has failed because the patch coverage (66.66%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #562      +/-   ##
==========================================
- Coverage   65.96%   65.93%   -0.03%     
==========================================
  Files         149      149              
  Lines       11503    11494       -9     
  Branches     1305     1305              
==========================================
- Hits         7588     7579       -9     
- Misses       3673     3674       +1     
+ Partials      242      241       -1     
Flag Coverage Δ
api 85.94% <66.66%> (-0.02%) ⬇️
api-client 85.94% <66.66%> (-0.02%) ⬇️
core 85.94% <66.66%> (-0.02%) ⬇️
crypto 85.94% <66.66%> (-0.02%) ⬇️
sdk 85.94% <66.66%> (-0.02%) ⬇️
sdk-core 85.94% <66.66%> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/sdk-core/src/folder/registration.ts 99.54% <100.00%> (-0.02%) ⬇️
packages/sdk/src/share/shared-write.ts 98.69% <ø> (-0.01%) ⬇️
apps/api/src/ipns/ipns.service.ts 87.24% <33.33%> (-0.07%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@FSM1 FSM1 merged commit 1efb3a4 into main Jun 25, 2026
29 checks passed
@FSM1 FSM1 deleted the refactor/drop-ipns-record-type-discriminator branch June 25, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release:api:refactor Patch version bump (code refactoring) for api release:cipherbox-fuse:fix Patch version bump (bug fix) for cipherbox-fuse release:cipherbox-sdk:fix Patch version bump (bug fix) for cipherbox-sdk release:desktop:fix Patch version bump (bug fix) for desktop release:sdk:refactor Patch version bump (code refactoring) for sdk release:sdk-core:refactor Patch version bump (code refactoring) for sdk-core release:tee-worker:fix Patch version bump (bug fix) for tee-worker release:web:refactor Patch version bump (code refactoring) for web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant