@reinconsole/graph 0.1.1 → 0.3.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/index.d.ts +57 -4
- package/dist/index.js +726 -165
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Phase 3 of **[Rein](https://github.com/bugiiiii11/rein)** — the reputation graph. Guard receipts say what agents tried to spend; gate receipts say what vendors actually earned. The graph listens to both, scores every vendor and payer it has evidence on, and feeds the scores back into enforcement on both sides of the wire.
|
|
4
4
|
|
|
5
|
-
> **Status: v0.
|
|
5
|
+
> **Status: v0.2 — early open-source infrastructure, live on testnet.** APIs may change before 1.0. See the live scoreboard: [Rein console](https://app.reinconsole.com).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -31,7 +31,7 @@ createGate({ screen: { check: payerCheck(graph, { denyBelow: 40 }) }, /* ... */
|
|
|
31
31
|
- **Unknown is not bad.** The evaluator never fires `vendorReputationLt` without data, `syncVendors` withholds scores under the confidence floor, and `payerCheck` passes wallets it knows nothing about. A newcomer is served; a *confidently* bad actor is refused.
|
|
32
32
|
- **No-fault refusals carry no evidence.** Rate limits, velocity caps, and rails outages at one vendor's gate never bleed into a payer's global score.
|
|
33
33
|
- **One identity, one history.** `graph.link(canonical, alias)` merges subjects across id spaces — an agent's engine ULID, its paying wallets, its on-chain [ERC-8004](https://www.npmjs.com/package/@reinconsole/erc8004) identity — so evidence follows the party, not the key. Key rotation never splits a score.
|
|
34
|
-
- **Run it as a service.** `buildGraphServer()` — remote producers `POST /v1/events`, anyone reads `GET /v1/scores/:kind/:subject` and gets the score *and* the evidence behind it. The durable variant (evidence survives restarts) lives in the [monorepo](https://github.com/bugiiiii11/rein) (`@reinconsole/store`).
|
|
34
|
+
- **Run it as a service.** `buildGraphServer()` — remote producers `POST /v1/events`, anyone reads `GET /v1/scores/:kind/:subject` and gets the score *and* the evidence behind it. Pass `{ auth }` (an `ApiKeyAuth` from `@reinconsole/core/auth`, or set `REIN_GRAPH_API_KEY`) and the write routes demand a key holding the `report` scope while reads stay open; without one the server binds loopback and refuses a public bind. The durable variant (evidence survives restarts) lives in the [monorepo](https://github.com/bugiiiii11/rein) (`@reinconsole/store`).
|
|
35
35
|
|
|
36
36
|
Scoring weights are deliberately transparent v0.1 heuristics (`DEFAULT_WEIGHTS`, overridable) — scores are pure functions of the evidence ledger, so the model can evolve without migrations.
|
|
37
37
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReputationSubject, ReputationComponents, ReinEvent, ReputationScore, Receipt } from '@reinconsole/core';
|
|
2
2
|
import { FastifyInstance } from 'fastify';
|
|
3
|
+
import { ApiKeyAuth } from '@reinconsole/core/auth';
|
|
3
4
|
|
|
4
5
|
/** A value that may be produced synchronously or awaited (durable writes). */
|
|
5
6
|
type MaybePromise<T> = T | Promise<T>;
|
|
@@ -186,8 +187,21 @@ declare function reliabilityComponent(ev: SubjectEvidence): number;
|
|
|
186
187
|
* Confidence is first-class (see core ReputationScore): a thin or brand-new
|
|
187
188
|
* history yields LOW confidence rather than a misleading score, so consumers
|
|
188
189
|
* (engine sync, gate screening) can refuse to act on it. Depth of evidence
|
|
189
|
-
* saturates around 10 observations; age
|
|
190
|
-
*
|
|
190
|
+
* saturates around 10 observations; age stops mattering after a week.
|
|
191
|
+
*
|
|
192
|
+
* The 0.1 age floor is load-bearing for fairness. Both consumers act at a 0.3
|
|
193
|
+
* confidence floor (`syncVendors`, `payerCheck`), so capping a day-0 subject at
|
|
194
|
+
* 0.1 makes first-day enforcement impossible BY CONSTRUCTION rather than by
|
|
195
|
+
* arithmetic luck. It used to be 0.4, which left day-0 subjects enforceable
|
|
196
|
+
* after only 14 observations — `depth` saturates so fast that a busy vendor
|
|
197
|
+
* cleared that in seconds, and the console's own vendor sat at 0.30136 against
|
|
198
|
+
* the 0.3 floor, i.e. inside the newcomer grace period by 0.0014. Enforcement
|
|
199
|
+
* now needs roughly 1.6 days (high volume) to 2.3 days (moderate) of history:
|
|
200
|
+
* a grace period measured in time, which is what "newcomer" means.
|
|
201
|
+
*
|
|
202
|
+
* Note the constant only ever applies to subjects younger than a week — past
|
|
203
|
+
* 7 days `min(1, d/7)` saturates and age is 1.0 under any floor — so lowering
|
|
204
|
+
* it leaves every mature score bit-for-bit unchanged.
|
|
191
205
|
*/
|
|
192
206
|
declare function confidence(ev: SubjectEvidence, nowMs: number): number;
|
|
193
207
|
/** Blend all five components into the headline 0–100 score. */
|
|
@@ -364,11 +378,50 @@ interface PayerCheckOptions {
|
|
|
364
378
|
*/
|
|
365
379
|
declare function payerCheck(graph: ReputationGraph, options?: PayerCheckOptions): (payer: string) => string | undefined;
|
|
366
380
|
|
|
381
|
+
interface GraphServerOptions {
|
|
382
|
+
/**
|
|
383
|
+
* API-key authentication for the WRITE routes. Omit for embedded use (the
|
|
384
|
+
* console world holds the graph object directly) or for a loopback-only
|
|
385
|
+
* process; pass an {@link ApiKeyAuth} and every write demands a `report`
|
|
386
|
+
* scope while reads stay open.
|
|
387
|
+
*/
|
|
388
|
+
auth?: ApiKeyAuth;
|
|
389
|
+
}
|
|
367
390
|
/**
|
|
368
391
|
* Build the graph HTTP API. Remote producers POST their events here; anyone
|
|
369
392
|
* can read scores with the evidence behind them. Pass a graph for tests, or
|
|
370
393
|
* let it create a fresh in-memory one.
|
|
394
|
+
*
|
|
395
|
+
* READS ARE OPEN BY DESIGN and that is the whole point of a reputation graph:
|
|
396
|
+
* a score nobody can read governs nothing. WRITES are the asymmetry — an event
|
|
397
|
+
* posted here becomes evidence about a subject that did not post it — so when
|
|
398
|
+
* `auth` is supplied they require the `report` scope. Without `auth` the server
|
|
399
|
+
* is exactly as open as it always was, which is why the bins that expose it
|
|
400
|
+
* refuse a public bind unless a key exists or the operator says otherwise.
|
|
371
401
|
*/
|
|
372
|
-
declare function buildGraphServer(graph?: ReputationGraph): FastifyInstance;
|
|
402
|
+
declare function buildGraphServer(graph?: ReputationGraph, options?: GraphServerOptions): FastifyInstance;
|
|
403
|
+
/**
|
|
404
|
+
* Build the graph's auth layer from the environment, or explain why there is
|
|
405
|
+
* none. `REIN_GRAPH_API_KEY` seeds one or more comma-separated secrets.
|
|
406
|
+
*
|
|
407
|
+
* They are seeded with `report` and nothing else: the graph has no key-issuing
|
|
408
|
+
* routes to bootstrap (unlike the engine, which seeds `admin` so `/v1/keys` is
|
|
409
|
+
* reachable), so an `admin` secret here would grant authority no route needs.
|
|
410
|
+
*/
|
|
411
|
+
declare function graphAuthFromEnv(env: NodeJS.ProcessEnv): Promise<ApiKeyAuth | undefined>;
|
|
412
|
+
/**
|
|
413
|
+
* Where a graph process binds, given whether auth exists.
|
|
414
|
+
*
|
|
415
|
+
* Until D1(a) the graph had no key to trade, so the only trade available was a
|
|
416
|
+
* statement: `REIN_GRAPH_PUBLIC=1`. Now that writes can demand a `report` key,
|
|
417
|
+
* the rule matches the engine's — a key buys a public bind, and asking for one
|
|
418
|
+
* without a key is a startup ERROR rather than a warning. `REIN_GRAPH_PUBLIC=1`
|
|
419
|
+
* survives as the deliberate override for an open graph, because a read-only
|
|
420
|
+
* showcase is a real deployment and reads were never the exposure.
|
|
421
|
+
*/
|
|
422
|
+
declare function resolveGraphHost(env: NodeJS.ProcessEnv, hasAuth?: boolean): {
|
|
423
|
+
host: string;
|
|
424
|
+
warning?: string;
|
|
425
|
+
};
|
|
373
426
|
|
|
374
|
-
export { type CounterpartyLine, DEFAULT_CORRELATION_LIMIT, DEFAULT_WEIGHTS, type EventSource, EvidenceLedger, type EvidenceLedgerPort, InMemoryIntentStore, type IntentCorrelationPort, type IntentFacts, type ManualReport, type MaybePromise, type PayerCheckOptions, type ReputationExplanation, ReputationGraph, type ReputationGraphOptions, type ScoreWeights, type SubjectEvidence, type SyncOptions, type SyncedVendorScore, type VendorReputationSink, blend, blendBase, buildGraphServer, confidence, disputeComponent, longevityComponent, normalizeSubject, payerCheck, reliabilityComponent, subjectKey, volumeComponent };
|
|
427
|
+
export { type CounterpartyLine, DEFAULT_CORRELATION_LIMIT, DEFAULT_WEIGHTS, type EventSource, EvidenceLedger, type EvidenceLedgerPort, type GraphServerOptions, InMemoryIntentStore, type IntentCorrelationPort, type IntentFacts, type ManualReport, type MaybePromise, type PayerCheckOptions, type ReputationExplanation, ReputationGraph, type ReputationGraphOptions, type ScoreWeights, type SubjectEvidence, type SyncOptions, type SyncedVendorScore, type VendorReputationSink, blend, blendBase, buildGraphServer, confidence, disputeComponent, graphAuthFromEnv, longevityComponent, normalizeSubject, payerCheck, reliabilityComponent, resolveGraphHost, subjectKey, volumeComponent };
|