PageSourceSearch

https://tumitrust.com/docs/assets/js/316a83bc.e8270f6e.js

js tumitrust.com collected 2026-09-28 06:43:23 UTC 12,877 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocs_new=globalThis.webpackChunkdocs_new||[]).push([[4390],{27025:(e,i,n)=>{n.r(i),n.d(i,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>d,metadata:()=>s,toc:()=>o});const s=JSON.parse('{"id":"pti/implementation-guide/anti-patterns","title":"Anti-Patterns","description":"Common PTI integration mistakes and how to correct them.","source":"@site/docs/pti/implementation-guide/anti-patterns.md","sourceDirName":"pti/implementation-guide","slug":"/pti/implementation-guide/anti-patterns","permalink":"/docs/pti/implementation-guide/anti-patterns","draft":false,"unlisted":false,"tags":[],"version":"current","sidebarPosition":3,"frontMatter":{"title":"Anti-Patterns","description":"Common PTI integration mistakes and how to correct them.","sidebar_position":3},"sidebar":"ptiSidebar","previous":{"title":"Best Practices","permalink":"/docs/pti/implementation-guide/best-practices"},"next":{"title":"Migration Guide","permalink":"/docs/pti/implementation-guide/migration-guide"}}');var r=n(74848),t=n(28453);const d={title:"Anti-Patterns",description:"Common PTI integration mistakes and how to correct them.",sidebar_position:3},l="Anti-Patterns",c={},o=[{value:"Identity",id:"identity",level:2},{value:"Embedding PII in <code>pti_id</code>",id:"embedding-pii-in-pti_id",level:3},{value:"Ignoring merge webhooks",id:"ignoring-merge-webhooks",level:3},{value:"Treating low-confidence matches as certain",id:"treating-low-confidence-matches-as-certain",level:3},{value:"Ingest",id:"ingest",level:2},{value:"Random idempotency keys",id:"random-idempotency-keys",level:3},{value:"Using ingest time as <code>occurred_at</code>",id:"using-ingest-time-as-occurred_at",level:3},{value:"Oversized payloads",id:"oversized-payloads",level:3},{value:"Context sprawl",id:"context-sprawl",level:3},{value:"Consumer",id:"consumer",level:2},{value:"Single global score",id:"single-global-score",level:3},{value:"Thin data as approval",id:"thin-data-as-approval",level:3},{value:"Stale report reuse",id:"stale-report-reuse",level:3},{value:"Skipping verification",id:"skipping-verification",level:3},{value:"Security",id:"security",level:2},{value:"Shared producer and consumer credentials",id:"shared-producer-and-consumer-credentials",level:3},{value:"Disabled TLS verification",id:"disabled-tls-verification",level:3},{value:"Logging full PII",id:"logging-full-pii",level:3},{value:"Architecture",id:"architecture",level:2},{value:"Bypassing the exchange",id:"bypassing-the-exchange",level:3},{value:"Client-side scoring",id:"client-side-scoring",level:3},{value:"Silent schema drift",id:"silent-schema-drift",level:3},{value:"Corrections",id:"corrections",level:2},{value:"Deleting bad events",id:"deleting-bad-events",level:3},{value:"Detection checklist",id:"detection-checklist",level:2},{value:"Related pages",id:"related-pages",level:2}];function a(e){const i={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",header:"header",li:"li",p:"p",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,t.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(i.header,{children:(0,r.jsx)(i.h1,{id:"anti-patterns",children:"Anti-Patterns"})}),"\n",(0,r.jsx)(i.p,{children:"Common mistakes when implementing PTI, and the corrective patterns that avoid them."}),"\n",(0,r.jsx)(i.h2,{id:"identity",children:"Identity"}),"\n",(0,r.jsxs)(i.h3,{id:"embedding-pii-in-pti_id",children:["Embedding PII in ",(0,r.jsx)(i.code,{children:"pti_id"})]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Custom identifiers encode phone numbers or national IDs, creating leakage risk and merge failures."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Use registry-allocated opaque ",(0,r.jsx)(i.code,{children:"pti_id"})," values only."]}),"\n",(0,r.jsx)(i.h3,{id:"ignoring-merge-webhooks",children:"Ignoring merge webhooks"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Producer continues sending events to a merged (retired) ",(0,r.jsx)(i.co
1de,{children:"pti_id"}),"."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Subscribe to ",(0,r.jsx)(i.code,{children:"identity.merged"})," and update local mapping tables to the survivor ID."]}),"\n",(0,r.jsx)(i.h3,{id:"treating-low-confidence-matches-as-certain",children:"Treating low-confidence matches as certain"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Auto-decisioning on weak match confidence (for example 0.62)."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Apply confidence thresholds; require secondary verification for high-impact decisions."]}),"\n",(0,r.jsx)(i.h2,{id:"ingest",children:"Ingest"}),"\n",(0,r.jsx)(i.h3,{id:"random-idempotency-keys",children:"Random idempotency keys"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Every retry creates duplicate signals."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Use deterministic keys per business action (see ",(0,r.jsx)(i.a,{href:"/docs/pti/implementation-guide/best-practices",children:"Best Practices"}),")."]}),"\n",(0,r.jsxs)(i.h3,{id:"using-ingest-time-as-occurred_at",children:["Using ingest time as ",(0,r.jsx)(i.code,{children:"occurred_at"})]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Skews decay and misorders historical backfill."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Always send the true activity time; keep ",(0,r.jsx)(i.code,{children:"ingested_at"})," as a separate server-set field."]}),"\n",(0,r.jsx)(i.h3,{id:"oversized-payloads",children:"Oversized payloads"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Entire CRM records stuffed into ",(0,r.jsx)(i.code,{children:"payload"}),", violating minimization."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Emit schema-required fields only; keep additional data in your own systems."]}),"\n",(0,r.jsx)(i.h3,{id:"context-sprawl",children:"Context sprawl"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Producer enables every context \u201cjust in case.\u201d"]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Enable only entitled, observed contexts; request catalog additions when needed."]}),"\n",(0,r.jsx)(i.h2,{id:"consumer",children:"Consumer"}),"\n",(0,r.jsx)(i.h3,{id:"single-global-score",children:"Single global score"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," UI collapses lending, rental, and merchant into one number."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Present ",(0,r.jsx)(i.strong,{children:"context scores"})," separately with per-context drivers."]}),"\n",(0,r.jsx)(i.h3,{id:"thin-data-as-approval",children:"Thin data as approval"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," A high band is treated as \u201cno risk\u201d when ",(0,r.jsx)(i.code,{children:"coverage_gaps"})," is non-empty."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Surface gaps clearly; treat thin bands as inconclusive."]}),"\n",(0,r.jsx)(i.h3,{id:"stale-report-reuse",children:"Stale report reuse"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," A months-old report is used for a live decision without regeneration."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Check ",(0,r.jsx)(i.code,{children:"generated_at"}),"; regenerate or reject expired reports."]}),"\n",(0,r.jsx)(i.h3,{id:"skipping-verification",children:"Skipping verification"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," PDF or JSON accepted without a ",(0,r.jsx)(i.code,{children:"verify_uri"})," check."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Call the verify endpoint for audit-sensitive workflows."]}),"\n",(0,r.jsx)(i.h2,{id:"security",children:"Security"}),"\n",(0,r.jsx)(i.h3,{id:"shared-producer-and-consumer-credentials",children:"Shared producer and consumer credentials"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," One API key used for ingest and lookup, weak audit trail."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Separate credentials and scopes per role."]}),"\n",(0,r.jsx)(i.h3,{id:"disabled-tls-verification",children:"Disabled TLS verification"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," MITM exposure in partner integrations."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Always validate certificates in production; use mTLS for high-assurance profiles."]}),"\n",(0,r.jsx)(i.h3,{id:"logging-full-pii",children:"Logging full PII"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Request bodies with national IDs land in application logs."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"}
1)," Log ",(0,r.jsx)(i.code,{children:"correlation_id"}),", ",(0,r.jsx)(i.code,{children:"pti_id"}),", and hashed identifiers only."]}),"\n",(0,r.jsx)(i.h2,{id:"architecture",children:"Architecture"}),"\n",(0,r.jsx)(i.h3,{id:"bypassing-the-exchange",children:"Bypassing the exchange"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Producer writes directly to a consumer database or shared cache."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," All signals flow through the Exchange for policy, provenance, and audit."]}),"\n",(0,r.jsx)(i.h3,{id:"client-side-scoring",children:"Client-side scoring"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Consumer reimplements the intelligence engine locally."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Consume server-derived scores; use drivers for transparency only."]}),"\n",(0,r.jsx)(i.h3,{id:"silent-schema-drift",children:"Silent schema drift"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Client ignores unknown JSON fields and breaks when new required fields appear."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Pin ",(0,r.jsx)(i.code,{children:"X-PTI-Version"}),"; monitor ",(0,r.jsx)(i.code,{children:"/capabilities"})," deprecations."]}),"\n",(0,r.jsx)(i.h2,{id:"corrections",children:"Corrections"}),"\n",(0,r.jsx)(i.h3,{id:"deleting-bad-events",children:"Deleting bad events"}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Problem:"})," Hard delete without an audit trail."]}),"\n",(0,r.jsxs)(i.p,{children:[(0,r.jsx)(i.strong,{children:"Fix:"})," Issue ",(0,r.jsx)(i.code,{children:".corrected"})," or ",(0,r.jsx)(i.code,{children:".retracted"})," lifecycle events."]}),"\n",(0,r.jsx)(i.h2,{id:"detection-checklist",children:"Detection checklist"}),"\n",(0,r.jsxs)(i.table,{children:[(0,r.jsx)(i.thead,{children:(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.th,{children:"Symptom"}),(0,r.jsx)(i.th,{children:"Likely anti-pattern"})]})}),(0,r.jsxs)(i.tbody,{children:[(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:"Duplicate signals on retry"}),(0,r.jsx)(i.td,{children:"Random idempotency keys"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:"Score jumps after backfill"}),(0,r.jsxs)(i.td,{children:["Wrong ",(0,r.jsx)(i.code,{children:"occurred_at"})]})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:"Challenge on explainability"}),(0,r.jsx)(i.td,{children:"Global score UI"})]}),(0,r.jsxs)(i.tr,{children:[(0,r.jsx)(i.td,{children:"Cross-tenant data leak"}),(0,r.jsx)(i.td,{children:"Missing tenant filter"})]})]})]}),"\n",(0,r.jsx)(i.h2,{id:"related-pages",children:"Related pages"}),"\n",(0,r.jsxs)(i.ul,{children:["\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"/docs/pti/implementation-guide/best-practices",children:"Best Practices"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"/docs/pti/specification/v1.0/governance",children:"Governance Specification"})}),"\n",(0,r.jsx)(i.li,{children:(0,r.jsx)(i.a,{href:"/docs/pti/specification/v1.0/reference-error-codes",children:"Reference Error Codes"})}),"\n"]})]})}function h(e={}){const{wrapper:i}={...(0,t.R)(),...e.components};return i?(0,r.jsx)(i,{...e,children:(0,r.jsx)(a,{...e})}):a(e)}},28453:(e,i,n)=>{n.d(i,{R:()=>d,x:()=>l});var s=n(96540);const r={},t=s.createContext(r);function d(e){const i=s.useContext(t);return s.useMemo(function(){return"function"==typeof e?e(i):{...i,...e}},[i,e])}function l(e){let i;return i=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:d(e.components),s.createElement(t.Provider,{value:i},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.