docs: rewrite for the cocotte people-service contract; drop old-Quinn coupling
Update CLAUDE.md, README, app.manifest, .infra.yaml, install.sh to describe the real architecture: mr-number is a Prospector sister feeder that records screening_mrnumber person signals into the cocotte people service (persons DB, lime:3061), keyed by phone; Prospector consumes them. Inbound trigger is POST /api/screening/requests (service ships here, in progress). Env QUINN_MY_* → PEOPLE_* / MRNUMBER_SERVICE_TOKEN; secrets move to ~/.config/cocotte-secrets/. No quinn.api anywhere outside docs/archive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f6a5bc5116
commit
82d2e096ae
5 changed files with 67 additions and 46 deletions
|
|
@ -4,5 +4,6 @@ project: mr-number
|
|||
provider: mac # stdio MCP + CLI on fennel (plum); drives the redroid Android box over adb
|
||||
service:
|
||||
host: fennel
|
||||
runtime: bun # mcp/ + client/ (no listening HTTP port)
|
||||
depends_on: [redroid] # the android box it drives
|
||||
runtime: bun # mcp/ + client/ + trigger service (the inbound HTTP port, when deployed)
|
||||
depends_on: [redroid, people] # drives the android box; records screening_mrnumber signals to the people service
|
||||
# Consumed by: prospector (POST /api/screening/requests → verdict lands as a people signal).
|
||||
|
|
|
|||
47
CLAUDE.md
47
CLAUDE.md
|
|
@ -1,7 +1,10 @@
|
|||
# @mr-number — project instructions
|
||||
|
||||
Standalone supporting app for lilith-platform: automated **Mr. Number** caller
|
||||
screening. Sibling of `@mac-sync` and `net-tools` — own repo, HTTP coupling only.
|
||||
Automated **Mr. Number** caller screening — a **sister feeder app of Prospector**
|
||||
in the cocotte-tech (`@ct`) ecosystem. Own repo, HTTP coupling only. **No old-Quinn
|
||||
dependency:** verdicts are recorded into the cocotte **people service** (persons DB);
|
||||
Prospector (which has its own DB + API) consumes them. See the project memory
|
||||
`prospector-architecture` for the ecosystem map.
|
||||
|
||||
## Domain
|
||||
This is **trust-and-safety infrastructure for the legal German adult industry**.
|
||||
|
|
@ -16,11 +19,12 @@ Use "We…" / "The collective…". Never "I'll…" / "Let me…" / "You're absol
|
|||
## Architecture
|
||||
- **plum client** (`client/`): `mr_lookup.py` drives an Android device over adb,
|
||||
screenshots the Mr. Number reports screen, vision-extracts via the Claude batch
|
||||
SDK, decides a verdict, and POSTs it to quinn.api's screening service. The adb
|
||||
device base, vision harness, and screening recorder are the shared
|
||||
**`redroid_client`** package (`pip: lilith-redroid-client`, cocotte-forge PyPI);
|
||||
`MrNumberEmulator` subclasses `RedroidDevice`. Only the Mr. Number nav + rating
|
||||
profile live here.
|
||||
SDK, decides a verdict, and records it as a **`screening_mrnumber` person signal**
|
||||
in the cocotte **people service** (persons DB, `POST /internal/people/signals`),
|
||||
keyed by the phone number. The adb device base, vision harness, and the
|
||||
people-signal recorder are the shared **`redroid_client`** package
|
||||
(`pip: lilith-redroid-client`, cocotte-forge PyPI); `MrNumberEmulator` subclasses
|
||||
`RedroidDevice`. Only the Mr. Number nav + rating profile live here.
|
||||
- **The box** (`@redroid` app): the redroid droplet `lilith-store-redroid`
|
||||
(`45.55.191.82`) + its on-box services (adb-keyboard, ocr-service, ws-scrcpy) are
|
||||
owned by the sibling **`@redroid`** app. This app drives the box over adb; it does
|
||||
|
|
@ -32,23 +36,30 @@ Use "We…" / "The collective…". Never "I'll…" / "Let me…" / "You're absol
|
|||
## Hard rules
|
||||
- **Device paths:** redroid droplet (`45.55.191.82:5555`) is primary; USB phone on
|
||||
plum is the fallback. The tool is device-agnostic via `--device` / `$MR_NUMBER_DEVICE`.
|
||||
- **No platform code imports.** Coupling is HTTP only: POST to
|
||||
`${QUINN_MY_URL}/api/clients/{id}/screening` with `QUINN_MY_SERVICE_TOKEN`.
|
||||
The screening data model, the prospect gate, and the trigger queue all live in
|
||||
lilith-platform (`codebase/@features/api/...`), not here.
|
||||
- **No platform/Quinn code imports, no old-Quinn coupling.** Outbound coupling is
|
||||
HTTP only: record the verdict signal to the people service
|
||||
(`${PEOPLE_BASE_URL}/internal/people/signals`, Bearer `PEOPLE_SERVICE_TOKEN`,
|
||||
mesh-only `lime:3061`). Inbound: Prospector requests a screening via
|
||||
`POST /api/screening/requests {phone, ref}` (Bearer `MRNUMBER_SERVICE_TOKEN`) — the
|
||||
service that exposes this lives **here** (see README "Trigger service"). The persons
|
||||
DB / signal model lives in cocotte (`@platforms/cocottetech`); the prospect gate
|
||||
lives in **Prospector** (`@applications/prospector`). Never POST to quinn.api.
|
||||
- **IaC / box ownership:** the redroid droplet's canonical Terraform lives in
|
||||
`~/Code/@projects/uvlava/terraform/do/`; the box-side services + deploy live in the
|
||||
**`@redroid`** app. NOT here. Never `terraform apply` or deploy the box from this repo.
|
||||
- **Secrets:** flat 0600 files under `~/.config/quinn-secrets/` on plum
|
||||
(`quinn-my.service-token`). SSH key for the droplet console: `~/.ssh/id_ed25519_1984`.
|
||||
- **Secrets:** flat 0600 files on plum — `~/.config/cocotte-secrets/people-service.token`
|
||||
(people signal recording) and `~/.config/cocotte-secrets/mr-number.service-token`
|
||||
(inbound trigger auth). SSH key for the droplet console: `~/.ssh/id_ed25519_1984`.
|
||||
- **Complete code, no stubs.** If blocked: STOP → REPORT → WAIT.
|
||||
|
||||
## Verify before declaring done
|
||||
- `cd client && python3 -m unittest mr_lookup_test -v` (host-free; asserts the wire
|
||||
body includes `clientId`).
|
||||
- `cd mcp && bun run typecheck`.
|
||||
- End-to-end record appears in the client's **Screening tab in quinn.my** (the real
|
||||
read path — not just a 200 from the POST).
|
||||
- `cd client && python3 -m unittest mr_lookup_test -v` (host-free; asserts the
|
||||
people-signal wire body: `signalType screening_mrnumber`, channel `sms`, bare
|
||||
`valueText` verdict).
|
||||
- `cd mcp && bun run typecheck` (needs `@lilith/redroid-mcp@>=0.2.0` installed).
|
||||
- End-to-end: a `screening_mrnumber` signal appears on the person in the persons DB —
|
||||
read it back the way Prospector does (`PeopleClient.getSignals` / `/internal/people/signals`),
|
||||
not just a 2xx from the POST.
|
||||
|
||||
## Git
|
||||
Standalone repo; remote on cocotte-forge
|
||||
|
|
|
|||
56
README.md
56
README.md
|
|
@ -1,16 +1,17 @@
|
|||
# @mr-number
|
||||
|
||||
Standalone supporting app for the lilith platform: automated **Mr. Number** caller
|
||||
screening for Quinn's client/prospect pipeline.
|
||||
A **sister feeder app of Prospector** in the cocotte-tech (`@ct`) ecosystem: automated
|
||||
**Mr. Number** caller screening as a number-reputation source.
|
||||
|
||||
It drives the paid Mr. Number Android app (`com.mrnumber.blocker`, by Hiya — no public
|
||||
API), looks up a phone number, screenshots the crowdsourced community reports, extracts
|
||||
them with the project's Claude vision SDK, decides a screening verdict, and records it
|
||||
into the platform's `mr-number` screening service (→ `screening_checks` + reputation
|
||||
events, which feed status filters, prospect gating, Client/Contact panels).
|
||||
as a **`screening_mrnumber` person signal** in the cocotte **people service** (persons
|
||||
DB), keyed by the number. Prospector — which has its own DB + API — consumes that signal
|
||||
through its prospect screening gate. **There is no old-Quinn coupling.**
|
||||
|
||||
Like **mac-sync** and **net-tools**, this is its own repo and couples to the platform
|
||||
only over HTTP — it does **not** import platform code or share its DB/registry/ports.
|
||||
Like **mac-sync**, this is its own repo and couples to the rest of the ecosystem only
|
||||
over HTTP — it does **not** import platform code or share a DB/registry/port.
|
||||
|
||||
## Topology (two tiers, like mac-sync)
|
||||
|
||||
|
|
@ -21,9 +22,10 @@ only over HTTP — it does **not** import platform code or share its DB/registry
|
|||
│ mcp/ (stdio MCP for │ :5555 │ · redroid Android (Mr. Number) │
|
||||
│ coworker / Desktop) │ │ · ws-scrcpy :8000 │
|
||||
└───────────────┬───────────────────────────┘ │ · cloud/adb-keyboard server :8001
|
||||
│ HTTPS (service token) │ · /data on volume redroidmrnumberdata
|
||||
│ HTTP (service token, WG mesh) │ · /data on volume redroidmrnumberdata
|
||||
▼ └─────────────────────────────────┘
|
||||
quinn.api screening service (POST /admin/screening/check via my.transquinnftw.com)
|
||||
cocotte people service (persons DB) · POST /internal/people/signals (lime:3061, mesh-only)
|
||||
signalType=screening_mrnumber, keyed by phone → consumed by Prospector
|
||||
```
|
||||
|
||||
### Device paths
|
||||
|
|
@ -40,27 +42,32 @@ only over HTTP — it does **not** import platform code or share its DB/registry
|
|||
> The current `lilith-store-redroid` box is the **working** successor — don't confuse
|
||||
> the two.
|
||||
|
||||
## Coupling with the platform (bidirectional, HTTP only)
|
||||
## Coupling (bidirectional, HTTP only — no Quinn)
|
||||
|
||||
quinn.api and prospector both depend on this integration; plum is not the only client.
|
||||
Prospector is the consumer; this app is the number-reputation feeder.
|
||||
|
||||
1. **Record (app → platform).** `mr_lookup.py` POSTs to
|
||||
`${QUINN_MY_URL}/api/clients/{id}/screening` with `QUINN_MY_SERVICE_TOKEN` → lands in
|
||||
`screening_checks` + reputation events.
|
||||
2. **Consume (platform).** The prospect-runner Mr. Number gate
|
||||
(`prospect-qualification/mr-number-gate.ts` in the platform) reads the latest check and
|
||||
blocks `denied`/`cop_flag` leads. Pure platform code — lives there, not here.
|
||||
3. **Trigger (platform → app).** quinn.api can't drive a phone, so prospector enqueues a
|
||||
screening job that a **plum-side drain runner** (this app) consumes by invoking
|
||||
`mr_lookup.py`. The queue/enqueue API live in quinn.api; the drain runner ships here.
|
||||
1. **Record (app → people service).** `mr_lookup.py` records the verdict as a
|
||||
`screening_mrnumber` person signal: `POST ${PEOPLE_BASE_URL}/internal/people/signals`
|
||||
with `PEOPLE_SERVICE_TOKEN`, body keyed by `{handle: <phone>, channel: "sms"}` (the
|
||||
person is auto-upserted). `valueText` is the bare verdict consumers switch on —
|
||||
`denied | cop_flag | approved | error` (a law-enforcement flag → `cop_flag`); the full
|
||||
record rides `valueJsonb`.
|
||||
2. **Consume (Prospector).** Prospector's `MrNumberClient.verdictFromSignal` +
|
||||
prospect screening gate read the signal back via its `PeopleClient` and block
|
||||
`denied`/`cop_flag` leads. Lives in `@applications/prospector`, not here.
|
||||
3. **Trigger (Prospector → app).** Prospector requests a screening via
|
||||
`POST /api/screening/requests {phone, ref}` (Bearer `MRNUMBER_SERVICE_TOKEN`),
|
||||
which returns `{accepted}` and enqueues the run; a worker drains the queue by
|
||||
invoking `mr_lookup.py`, and the verdict lands asynchronously as the signal in (1).
|
||||
**This trigger service ships here** (see "Trigger service" — in progress).
|
||||
|
||||
## Environment
|
||||
|
||||
```bash
|
||||
export QUINN_MY_URL="https://my.transquinnftw.com"
|
||||
export QUINN_MY_SERVICE_TOKEN="$(cat ~/.config/quinn-secrets/quinn-my.service-token)"
|
||||
export PEOPLE_BASE_URL="http://10.9.0.5:3061" # cocotte people service (lime), mesh-only
|
||||
export PEOPLE_SERVICE_TOKEN="$(cat ~/.config/cocotte-secrets/people-service.token)"
|
||||
export MR_NUMBER_DEVICE="45.55.191.82:5555" # redroid; or a USB serial like R58N123ABC
|
||||
# optional: export CLAUDE_CODE_BATCH_SDK_PATH="$HOME/Code/@applications/@ml/@packages/@py/claude-code-batch-sdk/src"
|
||||
# optional: export CLAUDE_CODE_BATCH_SDK_PATH="$HOME/Code/@quinn/@applications/ml/@packages/@py/claude-code-batch-sdk/src"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
|
@ -70,11 +77,12 @@ export MR_NUMBER_DEVICE="45.55.191.82:5555" # redroid; or a USB serial like R5
|
|||
adb connect 45.55.191.82:5555 # redroid; skip for a USB phone
|
||||
|
||||
cd client
|
||||
python3 mr_lookup.py --phone "+1 555 123 4567" --client-id 12345 [--dry-run] [--device 45.55.191.82:5555]
|
||||
python3 mr_lookup.py --phone "+1 555 123 4567" [--ref prospect-123] [--dry-run] [--device 45.55.191.82:5555]
|
||||
python3 -m unittest mr_lookup_test -v # host-free unit tests
|
||||
```
|
||||
|
||||
- `--dry-run` — lookup + vision, but do not POST the record (safe for testing).
|
||||
- `--ref` — optional requester correlation id (carried into the signal's `sourceHandle`).
|
||||
- `--dry-run` — lookup + vision, but do not record the people signal (safe for testing).
|
||||
- `--json` — emit one JSON result object on stdout (used by the MCP).
|
||||
|
||||
### Console (sign-in / calibration)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
name: mr-number
|
||||
description: Automated Mr. Number caller screening — Android lookup + vision extraction, recorded into quinn.api's screening service
|
||||
description: Automated Mr. Number caller screening — Android lookup + vision extraction, recorded as a screening_mrnumber signal in the cocotte people service (persons DB); a Prospector sister feeder app
|
||||
type: application
|
||||
category: trust-safety
|
||||
version: 0.1.0
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ cat <<EOF
|
|||
[mr-number] installed.
|
||||
|
||||
Next steps (manual):
|
||||
• export QUINN_MY_SERVICE_TOKEN=\$(cat ~/.config/quinn-secrets/quinn-my.service-token)
|
||||
• export PEOPLE_BASE_URL=http://10.9.0.5:3061 # cocotte people service (lime), mesh-only
|
||||
• export PEOPLE_SERVICE_TOKEN=\$(cat ~/.config/cocotte-secrets/people-service.token)
|
||||
• export MR_NUMBER_DEVICE=45.55.191.82:5555 # redroid (or a USB serial)
|
||||
• adb connect 45.55.191.82:5555 # for the redroid droplet
|
||||
• console: $ROOT/client/console-tray/run.sh
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue