Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @jongan69
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Relay or protocol bug
about: Report reproducible backend, wire-contract, storage, or deployment behavior
title: ""
labels: bug
assignees: ""
---

## Observed behavior

## Expected behavior

## Reproduction

Include the protocol version, message type, environment, and a minimal redacted request shape. Never include private keys, decrypted messages, raw identity data, or production secrets.

## Evidence

Provide random request IDs, timestamps, safe logs, failing test names, or a minimal repository reproduction.
8 changes: 8 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Security vulnerability
url: https://github.com/jongan69/OpenDating/security/advisories/new
about: Report security issues privately; never include service keys, decrypted payloads, or personal data in a public issue.
- name: Mobile application issue
url: https://github.com/jongan69/opendating-mobile/issues/new/choose
about: File screens, device behavior, and mobile-client issues in the mobile repository.
19 changes: 19 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
name: Protocol or relay proposal
about: Propose a contract, storage, reliability, privacy, or operations change
title: ""
labels: enhancement
assignees: ""
---

## Problem

## Proposed outcome

## Protocol and compatibility impact

Describe roles, request/result types, versioning, migration behavior, and the mobile coordination required.

## Privacy, abuse, and operations impact

## Acceptance evidence
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2

updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
groups:
github-actions:
patterns:
- "*"
open-pull-requests-limit: 5
20 changes: 20 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Summary

## Contract and migration impact

- [ ] No wire change, or the protocol version/schema/compatibility path is documented
- [ ] Migrations are additive and forward-only
- [ ] Generated protocol artifacts are current

## Verification

- [ ] `npm run ci` passes
- [ ] `npm audit --audit-level=low` reports no unresolved vulnerability
- [ ] `npx wrangler deploy --dry-run` passes when deployment configuration changes
- [ ] Protocol package builds and `npm pack --dry-run` contains only intended files
- [ ] No secrets, private keys, raw identity keys, or decrypted payloads are logged or committed
- [ ] Mobile contract changes are coordinated with `jongan69/opendating-mobile`

## Release and rollback

Describe deployment order, data migration, monitoring, rollback, and any feature flag or compatibility window.
40 changes: 40 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Contributing to OpenDating

Start with `docs/opendating/BACKEND-HANDOFF.md`, then read the architecture, security, privacy, deployment, and protocol documents relevant to the change.

## Setup

```bash
npm ci
npm run ci
```

Node.js 22 is the supported development and CI runtime. Local Worker development also requires Wrangler and local D1 state.

## Change rules

1. Create a branch from protected `main` and use a pull request.
2. Treat `packages/protocol` as the canonical client contract. Do not change request/result shapes without a compatibility and mobile-migration plan.
3. Keep backend implementation code out of the published protocol package.
4. Keep migrations additive and forward-only.
5. Never commit `.dev.vars`, service private keys, data/index keys, decrypted payloads, production exports, or personal data.
6. Do not claim a deployment is current without evidence from the exact commit.

## Required checks

```bash
npm run ci
npm audit --audit-level=low
npx wrangler deploy --dry-run
Comment on lines +26 to +28

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -C2 'npm audit|npm run ci' CONTRIBUTING.md .github/workflows/ci.yml package.json

Repository: jongan69/OpenDating

Length of output: 743


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf '--- CONTRIBUTING.md relevant section ---\n'
sed -n '1,35p' CONTRIBUTING.md
printf '\n--- .github/workflows/ci.yml relevant section ---\n'
sed -n '22,36p' .github/workflows/ci.yml
printf '\n--- package.json scripts ---\n'
node -e "const p=require('./package.json'); console.log(JSON.stringify(p.scripts, null, 2))"

Repository: jongan69/OpenDating

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo '--- CONTRIBUTING.md relevant section ---'
sed -n '1,35p' CONTRIBUTING.md
echo
echo '--- .github/workflows/ci.yml relevant section ---'
sed -n '22,36p' .github/workflows/ci.yml
echo
echo '--- package.json scripts ---'
node -e "const p=require('./package.json'); console.log(JSON.stringify(p.scripts, null, 2))"

Repository: jongan69/OpenDating

Length of output: 2916


Align or label the required audit scope.

npm run ci does not include the production audit that CI runs: npm audit --omit=dev --audit-level=high. If Required checks describes CI requirements, include the same command here; otherwise clarify that npm audit --audit-level=low is a separate, stricter local check.

🤖 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 `@CONTRIBUTING.md` around lines 26 - 28, Update the Required checks section in
CONTRIBUTING.md to match CI’s production audit by replacing the current audit
command with npm audit --omit=dev --audit-level=high, or explicitly label the
existing low-level audit as an additional stricter local check.


cd packages/protocol
npm ci
npm run build
npm pack --dry-run
```

Lint warnings are tracked debt; new changes should not introduce additional warnings.

## Documentation

Update the protocol release note, handoff, deployment instructions, and mobile coordination notes whenever a change affects a service role, request route, migration, secret, binding, retention rule, or production procedure.
34 changes: 19 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,32 @@
</p>

<p align="center">
<strong>The privacy-first, decentralized dating protocol.</strong><br>
<strong>A privacy-focused open dating protocol.</strong><br>
Protocol specification, reference relay, and <code>opendating-protocol</code> npm package.
</p>

<p align="center">
<a href="https://github.com/jongan69/OpenDating/blob/main/LICENSE"><img alt="License MIT" src="https://img.shields.io/badge/license-MIT-coral"></a>
<a href="https://www.npmjs.com/package/opendating-protocol"><img alt="npm" src="https://img.shields.io/badge/npm-opendating--protocol-coral"></a>
<a href="https://opendating-relay.jonathang132298.workers.dev"><img alt="Relay status" src="https://img.shields.io/badge/relay-live-brightgreen"></a>
<a href="https://opendating-relay.jonathang132298.workers.dev"><img alt="Configured relay endpoint" src="https://img.shields.io/badge/relay-configured-blue"></a>
<img alt="Protocol version" src="https://img.shields.io/badge/protocol-v0.1-blue">
</p>

<br>

## What is OpenDating?

**OpenDating** is a domain-specific protocol built on [Nostr](https://github.com/nostr-protocol/nostr) for private, decentralized dating. It provides:
**OpenDating** is a domain-specific open protocol built on [Nostr](https://github.com/nostr-protocol/nostr) for private dating. The current services are operated by OpenDating on one first-party Cloudflare stack; independent providers and federation are post-GA work. It provides:

- **Self-sovereign identity** — Your account is a cryptographic keypair you own, portable across any OpenDating client
- **Client-held identity** — A cryptographic keypair can be used by compatible clients; portable profile and cross-provider state transfer are not implemented yet
- **Location privacy** — Only a 5-character geohash (~5 km precision) is shared; exact coordinates never reach the relay
- **Private likes** — One-way likes are encrypted gift wraps visible only to the matcher service; no public reactions
- **End-to-end encrypted messaging** — NIP-17 DMs via NIP-44 encryption, enforced match-only by relay policy
- **Private safety** — Blocks and reports are encrypted, never public; blocks enforced server-side

The relay is a fork of [Nosflare](https://github.com/Spl0itable/nosflare) v7.9.45 (MIT), hardened and extended for dating-specific privacy and safety requirements.

> **Reference client:** [OpenDating Mobile](https://github.com/jongan69/opendating-mobile) — a production-quality Expo React Native app with Tinder-comparable UX.
> **Reference client:** [OpenDating Mobile](https://github.com/jongan69/opendating-mobile) — a pre-release Expo React Native client. It is explicitly blocked from production while its security, safety, legal, reliability, and marketplace gates remain open.

<br>

Expand All @@ -51,7 +51,7 @@ The relay is a fork of [Nosflare](https://github.com/Spl0itable/nosflare) v7.9.4
│ └──────────────────────────────────────┘ │
├──────────────────────────────────────────────┤
│ System │ Profile │ Discovery │ Matcher │ ← Service roles
│ DM Policy │ Moderation
│ DM Policy │ Moderation │ Deletion
└──────────────────────────────────────────────┘
```

Expand All @@ -72,7 +72,7 @@ OpenDating/
│ ├── durable-object.ts # Durable Object mesh for real-time broadcast
│ └── opendating/ # OpenDating extension registry
├── schemas/ # JSON Schema definitions
├── tests/ # 82-test suite (unit, integration, security, protocol)
├── tests/ # Unit, integration, security, protocol, and service coverage
├── migrations/ # D1 database migrations
├── docs/ # Protocol documentation
├── examples/ # Client demo scripts
Expand All @@ -93,11 +93,12 @@ Accept: application/nostr+json
| Service | Role |
|---|---|
| **System** | Health checks (`system.ping`), capability discovery |
| **Profile** | CRUD operations, visibility, pause/resume, verification |
| **Profile** | CRUD operations, visibility, pause/resume |
| **Discovery** | Location updates (coarse geohash), preferences, candidate queries |
| **Matcher** | Private one-way likes, match creation, unmatch |
| **DM Policy** | Block/unblock management, relay-enforced message gating |
| **Matcher** | Private one-way likes and match creation |
| **DM Policy** | Block/unblock/unmatch management and relay-enforced message gating |
| **Moderation** | Encrypted report submission with optional evidence |
| **Deletion** | Account deletion request and cascade orchestration |

All service communication uses NIP-59 gift wraps. Every request carries a unique `request_id` for idempotency.

Expand All @@ -108,17 +109,16 @@ All service communication uses NIP-59 gift wraps. Every request carries a unique
```bash
git clone https://github.com/jongan69/OpenDating.git
cd OpenDating
npm install
npm ci

# Build the worker
npm run build

# Run tests
npm test # Full suite (245 tests at 0.1.1 branch cut)
npm test # Full suite (248 tests across 17 files at this handoff)
npm run opendating:test:e2e # Protocol conformance tests

# Deploy (requires Cloudflare account + wrangler config)
npm run deploy
# Production deployment is separately gated; see docs/DEPLOYMENT.md.
```

<br>
Expand Down Expand Up @@ -153,6 +153,10 @@ See the [protocol package README](packages/protocol/README.md) for the full API
| [PRD](PRD.md) | Product requirements document |
| [Mobile Integration](SPEC.md) | Client integration guide for mobile developers |
| [Conformance Tests](tests/opendating/conformance/) | Protocol compliance test suite |
| [Backend Handoff](docs/opendating/BACKEND-HANDOFF.md) | Current boundary, access inventory, blockers, and continuation order |
| [0.1.1 Release Note](docs/opendating/PROTOCOL-0.1.1-RELEASE.md) | Contract repair and publication gate |
| [Security](docs/SECURITY.md) | Current security controls and limitations |
| [Contributing](CONTRIBUTING.md) | Development, validation, privacy, and migration rules |

<br>

Expand All @@ -164,7 +168,7 @@ See the [protocol package README](packages/protocol/README.md) for the full API
- **Gift-wrap privacy protections** — NIP-59 envelope validation
- **Query complexity protection** — prevents enumeration attacks
- **Extension registry** — domain-specific protocol extensions (OpenDating)
- **Free-tier-aware configuration** — runs on Cloudflare's free plan
- **Cloudflare-native configuration** — Workers, D1, Durable Objects, R2, KV, Queues, and AI bindings
- **Database migration system** — versioned D1 schema management

<br>
Expand Down
64 changes: 27 additions & 37 deletions docs/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
# Deployment Guide

> **Production status:** repository CI proves the source builds; it does not prove the configured endpoint runs the same commit. Production deployment remains gated until the live Worker SHA, migrations, bindings, secret names, rollback, and restore evidence are recorded. GitHub `staging` and reviewer-gated `production` environments exist, but deployment workflows and isolated Cloudflare staging resources still need to consume them.

## Profiles

### Local Development

```bash
npm install
npm ci
cp .env.example .env
npm run db:migrate:local
npm run dev
```
Comment on lines 9 to 14

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Provide the required local secrets before npm run dev.

This bootstrap copies .env.example but does not create or load OD_INDEX_KEY_V1 and OD_DATA_KEY_V1. docs/SECRETS.md states that the data/index layer fails closed without these keys, and the key generator documents .dev.vars for local secrets. Add the repository’s key-generation step or an explicit .dev.vars setup step before starting the worker.

Suggested documentation change
 npm ci
 cp .env.example .env
+# Create .dev.vars with the required local OpenDating keys.
 npm run db:migrate:local
 npm run dev
🤖 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 `@docs/DEPLOYMENT.md` around lines 9 - 14, Update the local deployment
bootstrap in the documented command sequence to generate or explicitly configure
OD_INDEX_KEY_V1 and OD_DATA_KEY_V1 before npm run dev, using the repository’s
documented key-generation command or .dev.vars setup described in
docs/SECRETS.md and the key generator documentation.


### Free Production
### Development and limited testing

Target: Cloudflare free tier (5GB D1, 10ms CPU per request)
Cloudflare quotas and product limits change over time. Check the current official limits before sizing or enabling a market; do not treat an old limit copied into this repository as capacity evidence.

Configuration:
- `RELAY_INFRA_PROFILE=free`
- DB pruning at 4.0GB (target 3.5GB)
- Conservative rate limits
- Pay-to-relay disabled

### Paid Production
### Production

Target: Cloudflare Workers Paid plan
Production requires a paid capacity plan validated by load tests, storage projections, alerting, backup/restore drills, and vendor/legal signoff. The current repository does not contain that evidence.

Configuration:
- Higher CPU limits in wrangler.toml
Expand All @@ -33,10 +35,10 @@ Configuration:

## Deployment Steps

### 1. Create D1 Database
### 1. Provision an isolated environment

```bash
wrangler d1 create nostr-relay
wrangler d1 create opendating-relay-<environment>
```

Update `wrangler.toml` with the database ID.
Expand All @@ -47,51 +49,36 @@ Update `wrangler.toml` with the database ID.
npm run db:migrate:remote
```

### 3. Set Secrets
### 3. Set every required secret

```bash
wrangler secret put RELAY_PRIVATE_KEY
wrangler secret put OD_INDEX_KEY_V1
wrangler secret put OD_DATA_KEY_V1
# Repeat for each OD_<ROLE>_SERVICE_PRIVKEY in docs/SECRETS.md.
```
Comment on lines +52 to 58

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)DEPLOYMENT\.md$|(^|/)SECRETS\.md$|wrangler\.toml|package\.json|README\.md' || true

echo
echo "== deployment relevant =="
if [ -f docs/DEPLOYMENT.md ]; then
  nl -ba docs/DEPLOYMENT.md | sed -n '1,110p'
fi

echo
echo "== secrets relevant =="
if [ -f docs/SECRETS.md ]; then
  nl -ba docs/SECRETS.md | sed -n '1,130p'
fi

echo
echo "== wrangler configs relevant =="
files=$(git ls-files | rg 'wrangler\.toml$|wrangler\.json$|package\.json$' || true)
for f in $files; do
  echo "--- $f"
  nl -ba "$f" | sed -n '1,220p'
done

echo
echo "== env-related docs/code snippets =="
rg -n --hidden --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' \
  'wrangler (deploy|dev|secret put|secret)|environments|environments:|production|staging|development|[[.*]]' \
  docs wrangler.toml wrangler.json package.json 2>/dev/null || true

Repository: jongan69/OpenDating

Length of output: 425


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Examine environment and secret command semantics from local docs/config only.
python3 - <<'PY'
from pathlib import Path
import re

for p in [Path('docs/SECRETS.md'), Path('docs/DEPLOYMENT.md')]:
    if not p.exists():
        continue
    text = p.read_text()
    print(f"--- {p} secret-put occurrences ---")
    for m in re.finditer(r'wrangler\s+secret\s+put\b([^\n]{0,120})', text):
        start_line = text[:m.start()].count('\n') + 1
        # include relevant block context lines
        before = text.rfind('\n', 0, m.start())
        post = text.find('\n', m.end())
        print(f"L{start_line}: {text[before+1:post].strip()}")

config_paths = [Path('wrangler.toml'), Path('wrangler.json')]
for cfg in config_paths:
    if not cfg.exists():
        continue
    text = cfg.read_text()
    print(f"\n--- {cfg} environment-related lines ---")
    for i,line in enumerate(text.splitlines(), 1):
        if re.search(r'((production|development|staging)|name\s*=|main\s*=|wrangler)', line, re.I):
            print(f"{i}: {line}")
PY

Repository: jongan69/OpenDating

Length of output: 733


🌐 Web query:

Cloudflare Wrangler secret put environment selector documentation

💡 Result:

To manage secrets for specific environments in Cloudflare Workers using Wrangler, you use the --env flag with the wrangler secret put command [1][2]. The command syntax is: npx wrangler secret put --env <ENVIRONMENT_NAME> When you run this command, Wrangler will prompt you to enter the secret value securely in your terminal [1]. If you are not in an interactive terminal (such as in a CI/CD pipeline), you can pipe the value via stdin [1]: echo "your-secret-value" | npx wrangler secret put --env <ENVIRONMENT_NAME> Key details: - Environment Selection: The --env flag (or its alias -e) specifies the target environment defined in your Wrangler configuration [3][4]. - Persistence: Secrets managed via wrangler secret put are stored securely by Cloudflare and are not visible in the dashboard or Wrangler once set [5][6]. - Local Development: For local development, secrets are typically managed via.dev.vars or.env files rather than the wrangler secret put command [5][7]. You can create environment-specific files (e.g.,.dev.vars.staging) to simulate different settings locally [2][7]. For more information on managing environment-specific configurations, see the official Cloudflare Workers documentation on Environments and Secrets [5][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deployment relevant =="
if [ -f docs/DEPLOYMENT.md ]; then
  awk '{printf "%5\t%s\n", NR, $0}' docs/DEPLOYMENT.md | sed -n '1,90p'
fi

echo
echo "== secrets relevant =="
if [ -f docs/SECRETS.md ]; then
  awk '{printf "%5\t%s\n", NR, $0}' docs/SECRETS.md | sed -n '1,110p'
fi

echo
echo "== wrangler config =="
if [ -f wrangler.toml ]; then
  awk '{printf "%5\t%s\n", NR, $0}' wrangler.toml
fi

echo
echo "== secret and environment references =="
awk '{printf "%5\t%s\n", NR, $@}' docs/DEPLOYMENT.md docs/SECRETS.md README.md 2>/dev/null | rg -n -i 'secret|environment|staging|production|development|--env|-e|dev\.vars|wrangler' || true

Repository: jongan69/OpenDating

Length of output: 1528


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in docs/DEPLOYMENT.md docs/SECRETS.md wrangler.toml README.md; do
  if [ -f "$f" ]; then
    echo "===== $f ====="
    sed -n '1,120p' "$f"
  fi
done

echo "===== grep summary ====="
grep -RInE -i 'wrangler secret put|secret put|secret-management|development|staging|production|environment|environments|dev\.vars|--env|-e' docs README.md wrangler.toml package.json 2>/dev/null || true

Repository: jongan69/OpenDating

Length of output: 22448


Scope all secret writes to the selected Cloudflare environment.

wrangler secret put <NAME> writes to the default environment, but the deployment and secret docs require separate development, staging, and production keys. Add the chosen environment selector to each Cloudflare secret write in docs/DEPLOYMENT.md; add explicit environment-specific secret handling in docs/SECRETS.md for production and staging instead of only wrangler secret put.

📍 Affects 2 files
  • docs/DEPLOYMENT.md#L52-L58 (this comment)
  • docs/SECRETS.md#L63-L65
🤖 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 `@docs/DEPLOYMENT.md` around lines 52 - 58, Scope every Cloudflare secret write
to the selected environment: update the commands in docs/DEPLOYMENT.md (lines
52-58) to include the environment selector, and revise the production and
staging guidance in docs/SECRETS.md (lines 63-65) to use explicit
environment-specific secret handling rather than bare wrangler secret put
commands.


### 4. Deploy
### 4. Validate without deploying

```bash
npm run build
npm run deploy
npm run ci
npm audit --audit-level=low
npx wrangler deploy --dry-run
```

### 5. Verify
### 5. Deploy through the approved environment

Production deployment must run from protected `main`, require the GitHub `production` environment approval, record the exact source SHA and migration state, and use environment-specific Wrangler configuration. Direct workstation deployment is not a production handoff procedure.

### 6. Verify

```bash
curl https://your-relay.example.com -H "Accept: application/nostr+json"
```

## Wrangler Configuration

```toml
name = "your-relay"
compatibility_date = "2025-01-04"
main = "worker.js"

[[durable_objects.bindings]]
name = "RELAY_WEBSOCKET"
class_name = "RelayWebSocket"

[[d1_databases]]
binding = "RELAY_DATABASE"
database_name = "nostr-relay"
database_id = "your-database-id"

[triggers]
crons = ["0 0 * * *"]

[limits]
cpu_ms = 30000 # 30s for free tier, 300000 for paid

[[migrations]]
tag = "v4"
new_sqlite_classes = ["RelayWebSocket"]
```
`wrangler.toml` is the current first-party configuration and binding inventory. Create explicit environment-specific configurations before staging deployment; never reuse production database, bucket, queue, KV, service keys, or encryption/index keys in development or staging.

## Post-Deployment

Expand All @@ -100,4 +87,7 @@ new_sqlite_classes = ["RelayWebSocket"]
3. Test EVENT publish + REQ
4. Test NIP-42 auth
5. Monitor Cloudflare analytics
6. Check D1 storage growth
6. Verify OpenDating capabilities and every advertised service identity

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Verify the complete required service-role set.

The identity loader skips missing roles and logs a warning. Therefore, “verify every advertised service identity” can pass with only a subset configured. Assert the seven required roles—system, profile, discovery, matcher, dm_policy, moderation, and deletion—and fail the release if any role is absent.

🤖 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 `@docs/DEPLOYMENT.md` at line 90, Update the deployment verification step for
OpenDating capabilities and advertised service identities to require all seven
roles: system, profile, discovery, matcher, dm_policy, moderation, and deletion.
Treat any missing role as a verification failure and block the release rather
than accepting the identity loader’s warning-only behavior.

7. Verify Queue, AI, media, cache, deletion, and moderation health explicitly
8. Record D1/R2/KV growth and queue age
9. Exercise rollback and restore procedures before public beta
Loading
Loading