|
| 1 | +# Identity companion service |
| 2 | + |
| 3 | +This opt-in package supplies `engine.TopicManager` for `tm_identity` and |
| 4 | +`engine.LookupService` for `ls_identity`. It does not register either service, |
| 5 | +start HTTP, or supply a database adapter. The generic engine must independently |
| 6 | +verify transactions, scripts and chain proofs before topic admission. |
| 7 | + |
| 8 | +`NewTopicManager` evaluates outputs independently. It verifies the exact |
| 9 | +concatenation of PushDrop fields using the subject's `[1, "identity"]`, key |
| 10 | +ID `"1"` signature, then verifies the certificate and decrypts public fields. |
| 11 | +The certificate subject need not equal the derived script locking key. |
| 12 | +Retention is always empty. Admission alone does not establish SPV validity, |
| 13 | +unspentness, certificate revocation status, freshness or trusted-certifier policy. |
| 14 | + |
| 15 | +`NewLookupService(projection)` indexes admitted outputs and removes them on |
| 16 | +spend or legal eviction. History-retention and block-height notifications do |
| 17 | +not change the current-output index. Lookup results are actual outpoint |
| 18 | +formulas for engine BEEF hydration. `ProjectOutput` exposes the same validated |
| 19 | +public record derivation without a storage write for future atomic admission |
| 20 | +and projection-intent integration. |
| 21 | + |
| 22 | +## Projection contract |
| 23 | + |
| 24 | +Implement `Projection` with a durable adapter and explicitly inject the topic |
| 25 | +and lookup service into the engine's configuration. `Upsert` must use the |
| 26 | +outpoint as a unique key, and repeated `Delete` calls must succeed. Public |
| 27 | +decrypted fields remain in `Record.Certificate.Fields`; searchable text excludes |
| 28 | +`profilePhoto` and `icon`. Its concatenation preserves TS keyring property |
| 29 | +enumeration, including numeric field names. |
| 30 | + |
| 31 | +`Find` must honor `Query.Kind`, including an empty-string identity key, all |
| 32 | +selected exact filters, attribute predicates, offset and limit. Attribute |
| 33 | +predicates combine with AND. Empty optional certifier filters are unrestricted; |
| 34 | +an empty certifier-only query is empty. No new ordering guarantee is implied. |
| 35 | +`Field == ""` selects `SearchableAttributes`; otherwise it names a literal |
| 36 | +certificate field. Adapters must use server-owned operators and must not splice |
| 37 | +query values into database operators or regular expressions. |
| 38 | + |
| 39 | +Preserved TS query semantics: |
| 40 | + |
| 41 | +- Precedence: serial number; attributes; identity key with certificate types; |
| 42 | + identity key; certifiers. Serial number ignores lower-priority filters. |
| 43 | +- Attribute whitespace follows ECMAScript trimming/collapsing. `userName` is an |
| 44 | + exact, case-sensitive normalized match; other attributes use escaped tokens |
| 45 | + joined by `.*` with case-insensitive matching. |
| 46 | +- `attributes.any` takes precedence within attributes. After normalization, |
| 47 | + fewer than two UTF-16 code units yields empty; two uses a fuzzy text regex; |
| 48 | + more than two requires the native Mongo text-search semantics/index used by |
| 49 | + the TS service. It must not be approximated by substring or fuzzy matching. |
| 50 | +- Empty/blank attribute searches are empty. Native Mongo text language, |
| 51 | + stemming, stop words, phrases and index behavior need real adapter tests. |
| 52 | + |
| 53 | +The adapter and host own admission/projection atomicity, ordered replay, |
| 54 | +tombstones or equivalent fencing, outbox retries, read-your-write boundaries, |
| 55 | +rebuilds, migration and readiness. An old admission replay must not resurrect |
| 56 | +an output after spend/eviction. Callback idempotency alone cannot guarantee |
| 57 | +this. The legacy engine callbacks are not an atomic transaction merely because |
| 58 | +this interface exists. Use the separately reviewed engine persistence/outbox |
| 59 | +capability when integrating; this package adds no competing operation ledger. |
| 60 | + |
| 61 | +## Budgets and narrow compatibility limits |
| 62 | + |
| 63 | +`DefaultAdmissionPolicy()` limits one output script to 1 MiB, certificate and |
| 64 | +PushDrop fields to 128, selected outputs to 10,000, total selected transaction |
| 65 | +locking-script bytes to 32 MiB, and engine notification BEEF to 64 MiB. |
| 66 | +`NewTopicManagerWithPolicy` and `NewLookupServiceWithPolicies` accept explicit |
| 67 | +positive policy values. These are application budgets; the host separately |
| 68 | +needs bounded transport and BEEF/transaction/proof parsing. Notification BEEF |
| 69 | +is an already admitted engine payload, not an independent network ingress API. |
| 70 | + |
| 71 | +`DefaultQueryPolicy()` permits at most 10,000 results and offset 100,000. |
| 72 | +The policy may lower those operational ceilings. Explicit positive limits |
| 73 | +within the cap retain limit/offset behavior. Omitted or zero legacy limits |
| 74 | +fetch `cap + 1`: results within the cap succeed; overflow returns `ErrQueryBudget` |
| 75 | +and requires explicit bounded pagination. No truncated success or new wire |
| 76 | +metadata is invented. Large offsets remain workload-dependent scans, not a |
| 77 | +promise of cheap access. |
| 78 | + |
| 79 | +Queries are capped at 64 KiB, 4 KiB per string, 64 attributes and 128 certifiers |
| 80 | +or certificate types. Pagination accepts finite integral JSON numbers and |
| 81 | +rejects negative, fractional, quoted or over-budget values before projection |
| 82 | +work. Attribute selectors must be nonempty and exclude `.`, `$` and NUL to |
| 83 | +prevent unsafe Mongo path construction; certificate data is not normalized or |
| 84 | +renamed. Those selectors and resource ceilings are explicit restrictions on |
| 85 | +the otherwise permissive TS input shape. |
| 86 | + |
| 87 | +## Certificate serialization checkpoint |
| 88 | + |
| 89 | +This component deliberately uses the existing Go SDK v1.4.1 certificate |
| 90 | +verification profile. Its serializer orders UTF-8 field names with Go byte |
| 91 | +ordering. Pinned TS `2bc799a8d8e535242e6de2d305f426ce3975ea7b` reconstructs |
| 92 | +the certificate preimage with `localeCompare`; even mixed ASCII case can |
| 93 | +differ. Collation ties preserve JSON insertion order. The PushDrop envelope |
| 94 | +carries JSON and the subject signature, not a separate signed binary preimage. |
| 95 | + |
| 96 | +The common-compatible real TS fixtures pass. Other legitimate TS certificates |
| 97 | +may not verify under this profile. `ErrCertificateVerification` describes a |
| 98 | +failure to verify under the Go profile, not a diagnosis of forgery. There is |
| 99 | +no alternate-order retry, arbitrary permutation search, ambient locale |
| 100 | +dependency or normalization of signed data. Full TS certificate interoperability |
| 101 | +remains open pending explicit deterministic profile/migration review. The |
| 102 | +[portable fixture provenance](testdata/data/provenance.md) records mixed ASCII, |
| 103 | +accent/combining ties, astral/BMP and searchable-field cases with exact bytes. |
| 104 | + |
| 105 | +## Verification and integration gates |
| 106 | + |
| 107 | +Package tests consume actual TS signed certificate/PushDrop/transaction/BEEF |
| 108 | +bytes. They exercise independently admitted/rejected outputs, exact signature |
| 109 | +and decryption checks, replay/upsert and deletion seams, query behavior and |
| 110 | +budgets, and malformed scripts. In-memory projections exist only in tests; |
| 111 | +they do not claim Mongo text-search or persistent-server acceptance. |
| 112 | + |
| 113 | +Run package tests with `GOTOOLCHAIN=go1.26.8 go test ./pkg/topics/identity`. |
| 114 | +The fixture generator requires the pinned TS sources and built artifacts; |
| 115 | +committed fixture bytes make ordinary Go checks independent of Node or a |
| 116 | +database. Regeneration uses SDK randomness, producing new signed bytes with |
| 117 | +the same tested behavior, and records their SHA-256 digests. |
| 118 | + |
| 119 | +Remaining acceptance includes the durable Mongo adapter/indexes, atomic engine |
| 120 | +admission/projection/outbox integration, actual engine+HTTP lookup consumed by |
| 121 | +the real TS IdentityClient/wallet, restart/spend/eviction, independent chain |
| 122 | +validation and identity-history integration. SDK v1.4.1 also misserializes |
| 123 | +parsed V1 BEEF through `AtomicBytes`; the generic SDK repair is a separate |
| 124 | +primary-profile dependency. Tests here consume exact TS `toAtomicBEEF()` bytes |
| 125 | +and do not conceal that unresolved engine interoperability dependency. |
0 commit comments