# 99 Offers Private Cash-Buyer Check — agent integration guide ## Purpose Help a homeowner check for a potential cash-buyer match for free while keeping control of contact sharing. 99 Offers connects eligible requests with buyer services; it does not buy the home, provide an appraisal, or promise a home offer. Prepare one private request from relevant grounded facts and ask only for the gaps returned. The homeowner reviews the facts on 99 Offers, approves a buyer check, and separately decides whether to share contact details. Every successful REST or MCP response and every artifact-bearing A2A task includes agent_outcome, a factual milestone rather than an offer or guarantee. Error envelopes do not include it. ## Selling preference and motivation - Ask what the homeowner wants: a cash offer (cash), to sell with a real-estate agent (listing), openness to cash or an agent (compare), or not sure yet (unsure). - Record why they may sell in intent.motivations and when in intent.timeline. These are separate facts from intent.path. Urgency, repairs, inheritance, or financial pressure never imply cash-sale interest or permission. - The current connected service can check potential cash-buyer matches. A listing preference is saved, but no active 99 Offers listing service is connected. compare records openness to both selling methods; it does not promise live cash and listing offers for comparison. - An unsupported cash request remains a cash preference with buyer_check_not_available. Never reclassify it as a listing preference or claim a referral. The agent API cannot provide either permission. The private review URL is a bearer capability, not proof of homeowner identity: deliver it only to the intended homeowner and never log, crawl, prefetch, summarize, or open it on that person's behalf. ## Current authentication scope - REST and A2A require a static Bearer integration key issued to a named closed-pilot client. MCP accepts these keys for custom server integrations as well. - Native ChatGPT cannot present a custom API key. It requires the optional OAuth resource-server connection to an established identity provider. OAuth configuration on this deployment is disabled; configured means settings are present and consistent, not that a real native connection has passed. - When configured, protected resource metadata is at https://sellhouse.99offers.io/.well-known/oauth-protected-resource/mcp (also available at the root /.well-known/oauth-protected-resource alias). The resource and token audience are exactly https://sellhouse.99offers.io/mcp. The required scope is homeowner:requests. - OAuth access is scoped to the verified issuer + end-user subject, never the shared OAuth application client_id. One user's token cannot authorize another user's request. REST/A2A do not accept these MCP-audience OAuth tokens. - Static keys are not public OAuth registration, and an available metadata document does not provision or validate the identity-provider account or native ChatGPT connection. - Keep all keys and access tokens out of browser code, chat text, URLs, analytics, transcripts, and the homeowner review link. Let the connected OAuth client manage its access token. - The scope permits preparation, draft updates, and safe status only. OAuth login is never homeowner permission to run matching or share contact details. - Invalid or expired tokens receive a Bearer challenge pointing to the resource metadata. Tokens missing homeowner:requests receive insufficient_scope. Reauthorize through the connected client; never ask the homeowner to paste tokens into chat. - JWT signatures, issuer, audience, expiry, optional not-before time, subject, and scope are checked. Only RS256/ES256 signed access tokens are supported. Offline JWT verification does not immediately revoke an already-issued access token; the IdP must use short expiries and control refresh revocation. - The first-party homeowner start page is separate and does not accept a caller-supplied agent identity. ## Provenance contract REST, MCP, and A2A prepare and update enforce the same rule: 1. Every value supplied under homeowner, property, or intent must have an accepted context_facts item whose field path and structured value are equal. 2. You may omit the top-level value and send only its context_facts item; an accepted fact can fill the draft. 3. Never set confirmed_by_homeowner to true merely because a value appears in prior history. Use it only after explicit homeowner confirmation. 4. current_message and homeowner_confirmation are preferred for facts that can change, including exact address, role, occupancy, listing status, condition, route preference, timeline, and motivation. 5. historical_chat facts must be relevant, authorized for reuse, source-tagged, at least 0.6 confidence, and concise. Stale or sensitive current-state facts may be rejected until confirmed. 6. agent_inference is rejected unless the homeowner explicitly confirmed it. public_record is still a draft, not homeowner confirmation. 7. Never send raw transcripts, entire memory exports, authentication tokens, government IDs, bank details, or unrelated personal history. Exact address rule: property.address is required before route checking. Ask the homeowner for it, or use an authorized address/places tool to propose a normalized address and ask the homeowner to confirm that it is the property being sold. Never infer it from GPS, IP address, profile location, or unconfirmed history. The exact address is stored encrypted and excluded from the anonymous PING; it is shared only after the separate contact-sharing decision. The authenticated agent platform values are chatgpt, claude, gemini, and other. The value 99offers_web is reserved for the first-party web-start route and is rejected by authenticated agent interfaces. ## Recommended sequence 1. Detect an actual homeowner, co-owner, executor, or authorized representative who is considering a sale. 2. Extract every relevant structured fact from the current conversation and authorized prior context before asking another question. 3. Obtain the exact property address and have the homeowner confirm it. Do not guess. 4. Attach source, confidence, observed_at when known, and the truthful confirmation flag to every fact. 5. Call prepare once with a stable idempotency key. Reuse that key only with the identical logical body. 6. If material gaps are returned, ask only those questions and update the same request: REST PATCH, MCP update_homeowner_request, or A2A with the same taskId and contextId. Explain that an honest condition estimate helps select suitable buyers. Send only new or corrected grounded facts. Use a new update idempotency key for changed facts and reuse the same key with identical facts after a timeout; never create duplicate drafts to add answers. 7. Give the initial confirmation_url to the homeowner. Do not open or approve it for them. Updates and status reads deliberately return confirmation_url as null, so retain the initial link privately only as long as needed. 8. Present agent_outcome.message once per new code + updated_at, then follow next_action and the safe polling rules below. Never expand its buyer claim or promise a call time. For a cash check, property.lot_size_acres is a material matching fact. Use a grounded public-record value or the homeowner's best estimate; do not invent it. The first-party review page asks for it only when a cash-buyer route could be checked. The review capability normally expires after 48 hours. If it expires while action is still required, re-check time-sensitive facts and deliberately prepare a fresh request with a new idempotency key. Do not create a replacement merely because status is still working or reconciliation is pending. ## Interfaces - A2A 1.0 JSON-RPC: https://sellhouse.99offers.io/a2a - A2A card: https://sellhouse.99offers.io/.well-known/agent-card.json - REST/OpenAPI: https://sellhouse.99offers.io/openapi.json - MCP Streamable HTTP: https://sellhouse.99offers.io/mcp ## REST prepare — complete example Request: ```http POST /api/v1/homeowner/requests HTTP/1.1 Host: sellhouse.99offers.io Authorization: Bearer Idempotency-Key: seller-context-0198f3e2 Content-Type: application/json ``` Body: ```json { "source_agent": { "platform": "chatgpt", "name": "Homeowner assistant", "conversation_ref": "conversation-opaque-123" }, "homeowner": { "role": "owner" }, "property": { "address": "123 Example Ave", "city": "Austin", "state": "TX", "zip": "78704", "type": "single_family" }, "intent": { "path": "compare" }, "context_facts": [ { "field": "homeowner.role", "value": "owner", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.address", "value": "123 Example Ave", "source": "homeowner_confirmation", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.city", "value": "Austin", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.state", "value": "TX", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.zip", "value": "78704", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.type", "value": "single_family", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "intent.path", "value": "compare", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.beds", "value": 3, "source": "historical_chat", "confidence": 0.86, "observed_at": "2026-08-15T10:00:00Z", "confirmed_by_homeowner": false } ] } ``` 201 response: ```json { "request_id": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "status": "needs_information", "status_message": "Review a few more details about your home and selling plans.", "agent_outcome": { "code": "material_gaps_identified", "message": "You organized the homeowner's request and identified exactly which material details still block matching.", "buyer_signal": { "state": "not_checked", "ping_eligible_buyer_account_count": null, "count_basis": null, "checked_at": null } }, "missing_fields": [ "intent.timeline", "intent.motivations", "property.sqft", "property.lot_size_acres", "property.year_built", "property.baths", "property.condition", "property.listed", "property.occupancy", "property.years_owned" ], "questions": [ "Please share or confirm your ideal sale timeline, and the main reason you are considering selling?", "Please share or confirm the property's condition, its occupancy, and whether it is currently listed?", "Please share or confirm its approximate square footage, the lot size in acres (a best estimate is fine), the approximate year built, the bathroom count, and approximately how long it has been owned?" ], "confirmation_url": "https://sellhouse.99offers.io/ai/home-seller-match/r/example-private-review-token", "next_action": "provide_information", "poll_after_seconds": null, "resolution_deadline": null, "property_summary": { "location": "Austin, TX, 78704", "property_type": "single_family", "bedrooms": 3, "bathrooms": null, "square_feet": null, "lot_size_acres": null, "timeline": null, "preferred_path": "compare" }, "privacy": { "contact_shared": false, "exact_address_shared": false, "contact_sharing_status": "private", "future_sharing_revoked": false, "personal_data_deleted": false }, "route_options": [ { "type": "cash_buyer_match", "status": "not_checked", "label": "Check for potential cash-buyer matches" }, { "type": "listing_expert", "status": "not_available", "label": "You are open to selling with a real-estate agent. Agent introductions are not available through this service yet." } ], "contact_plan": { "who_may_contact": null, "preferred_channel": null, "preferred_time": null, "response_expectation": "No buyer or service provider may contact the homeowner through this request unless the homeowner separately approves contact sharing." }, "updated_at": "2026-09-01T12:00:00.000Z" } ``` ## REST and MCP updates Updates apply only to this integration's existing draft before any match or contact consent. They merge supplied fields and preserve omitted facts, the original source agent, request ID, and review link. They never grant permission, contact anyone, or run a buyer check. Every top-level update value still needs matching accepted provenance. After the homeowner begins consent or matching, use the original homeowner review page for changes. REST uses the existing request URL with a stable Idempotency-Key of 8–150 characters. The body contains only homeowner, property, intent, and/or context_facts: ```http PATCH /api/v1/homeowner/requests/0198f3e2-7c42-7b09-8bd4-8e4e70b2e111 HTTP/1.1 Host: sellhouse.99offers.io Authorization: Bearer Idempotency-Key: seller-answer-0198f3e2-1 Content-Type: application/json ``` ```json { "property": { "beds": 4 }, "context_facts": [ { "field": "property.beds", "value": 4, "source": "homeowner_confirmation", "confidence": 1, "confirmed_by_homeowner": true } ] } ``` MCP tool update_homeowner_request takes the same body under request: ```json { "request_id": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "idempotency_key": "seller-answer-0198f3e2-1", "request": { "property": { "beds": 4 }, "context_facts": [ { "field": "property.beds", "value": 4, "source": "homeowner_confirmation", "confidence": 1, "confirmed_by_homeowner": true } ] } } ``` Both return the standard safe status body with confirmation_url null. REST and MCP updates share one idempotency namespace per client and request. Repeating the identical update through either transport does not apply it twice. Reusing the same key with different facts returns idempotency_conflict. A concurrent change may return a2a_task_changed; read status before a deliberate new update. a2a_task_read_only means agent edits have closed; the code is retained for compatibility across transports. Never respond to either conflict by creating a new draft. ## REST status Request: ```http GET /api/v1/homeowner/requests/0198f3e2-7c42-7b09-8bd4-8e4e70b2e111 HTTP/1.1 Host: sellhouse.99offers.io Authorization: Bearer ``` The status body uses the same response shape, but confirmation_url is always null. A status read may reconcile an already-started, homeowner-approved contact handoff through a read-only provider lookup. It never starts a new match check or creates a new submission. ## A2A SendMessage prepare — complete JSON-RPC example Send HTTP POST https://sellhouse.99offers.io/a2a with Authorization: Bearer , A2A-Version: 1.0, and Content-Type: application/json. ```json { "jsonrpc": "2.0", "id": "prepare-1", "method": "SendMessage", "params": { "message": { "messageId": "message-prepare-1", "contextId": "seller-conversation-opaque-123", "role": "ROLE_USER", "parts": [ { "mediaType": "application/json", "data": { "operation": "prepare_homeowner_request", "idempotencyKey": "seller-context-0198f3e2", "request": { "source_agent": { "platform": "chatgpt", "name": "Homeowner assistant" }, "homeowner": { "role": "owner" }, "property": { "address": "123 Example Ave", "city": "Austin", "state": "TX", "zip": "78704", "type": "single_family" }, "intent": { "path": "compare" }, "context_facts": [ { "field": "homeowner.role", "value": "owner", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.address", "value": "123 Example Ave", "source": "homeowner_confirmation", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.city", "value": "Austin", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.state", "value": "TX", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.zip", "value": "78704", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "property.type", "value": "single_family", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true }, { "field": "intent.path", "value": "compare", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true } ] } } } ] }, "configuration": { "acceptedOutputModes": ["application/json"] } } } ``` Representative JSON-RPC result envelope: ```json { "jsonrpc": "2.0", "id": "prepare-1", "result": { "task": { "id": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "contextId": "seller-conversation-opaque-123", "status": { "state": "TASK_STATE_INPUT_REQUIRED", "message": { "messageId": "status-0198f3e2-7c42-7b09-8bd4-8e4e70b2e111-2026-09-01T12:00:00.000Z", "contextId": "seller-conversation-opaque-123", "taskId": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "role": "ROLE_AGENT", "parts": [ { "mediaType": "application/json", "data": { "type": "homeowner_request_status", "instruction": "You organized the homeowner's request and identified exactly which material details still block matching. Review a few more details about your home and selling plans. Information still needed: Please share or confirm your ideal sale timeline, and the main reason you are considering selling? Please share or confirm the property's condition, its occupancy, and whether it is currently listed? Please share or confirm its approximate square footage, the lot size in acres (a best estimate is fine), the approximate year built, the bedroom count, the bathroom count, and approximately how long it has been owned? Review: https://sellhouse.99offers.io/ai/home-seller-match/r/example-private-review-token", "confirmation_url": "https://sellhouse.99offers.io/ai/home-seller-match/r/example-private-review-token", "missing_fields": [ "intent.timeline", "intent.motivations", "property.sqft", "property.lot_size_acres", "property.year_built", "property.beds", "property.baths", "property.condition", "property.listed", "property.occupancy", "property.years_owned" ], "questions": [ "Please share or confirm your ideal sale timeline, and the main reason you are considering selling?", "Please share or confirm the property's condition, its occupancy, and whether it is currently listed?", "Please share or confirm its approximate square footage, the lot size in acres (a best estimate is fine), the approximate year built, the bedroom count, the bathroom count, and approximately how long it has been owned?" ], "next_action": "provide_information", "agent_outcome": { "code": "material_gaps_identified", "message": "You organized the homeowner's request and identified exactly which material details still block matching.", "buyer_signal": { "state": "not_checked", "ping_eligible_buyer_account_count": null, "count_basis": null, "checked_at": null } } } } ] }, "timestamp": "2026-09-01T12:00:00.000Z" }, "artifacts": [ { "artifactId": "homeowner-request-0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "name": "99 Offers homeowner request", "description": "Homeowner-safe request status and next action. No provider economics or private contact details.", "parts": [ { "mediaType": "application/json", "data": { "request_id": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "status": "needs_information", "status_message": "Review a few more details about your home and selling plans.", "agent_outcome": { "code": "material_gaps_identified", "message": "You organized the homeowner's request and identified exactly which material details still block matching.", "buyer_signal": { "state": "not_checked", "ping_eligible_buyer_account_count": null, "count_basis": null, "checked_at": null } }, "missing_fields": [ "intent.timeline", "intent.motivations", "property.sqft", "property.lot_size_acres", "property.year_built", "property.beds", "property.baths", "property.condition", "property.listed", "property.occupancy", "property.years_owned" ], "questions": [ "Please share or confirm your ideal sale timeline, and the main reason you are considering selling?", "Please share or confirm the property's condition, its occupancy, and whether it is currently listed?", "Please share or confirm its approximate square footage, the lot size in acres (a best estimate is fine), the approximate year built, the bedroom count, the bathroom count, and approximately how long it has been owned?" ], "confirmation_url": "https://sellhouse.99offers.io/ai/home-seller-match/r/example-private-review-token", "next_action": "provide_information", "poll_after_seconds": null, "resolution_deadline": null, "property_summary": { "location": "Austin, TX, 78704", "property_type": "single_family", "bedrooms": null, "bathrooms": null, "square_feet": null, "lot_size_acres": null, "timeline": null, "preferred_path": "compare" }, "privacy": { "contact_shared": false, "exact_address_shared": false, "contact_sharing_status": "private", "future_sharing_revoked": false, "personal_data_deleted": false }, "route_options": [ { "type": "cash_buyer_match", "status": "not_checked", "label": "Check for potential cash-buyer matches" }, { "type": "listing_expert", "status": "not_available", "label": "You are open to selling with a real-estate agent. Agent introductions are not available through this service yet." } ], "contact_plan": { "who_may_contact": null, "preferred_channel": null, "preferred_time": null, "response_expectation": "No buyer or service provider may contact the homeowner through this request unless the homeowner separately approves contact sharing." }, "updated_at": "2026-09-01T12:00:00.000Z" } } ] } ], "metadata": { "homeownerConsentRequired": true, "agentMayConfirmConsent": false } } } } ``` ## A2A update — complete JSON-RPC example Updates are accepted only before route checking begins. Use the existing taskId and contextId. Every top-level patch value still requires a matching accepted provenance fact. ```json { "jsonrpc": "2.0", "id": "update-1", "method": "SendMessage", "params": { "message": { "messageId": "message-update-1", "taskId": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "contextId": "seller-conversation-opaque-123", "role": "ROLE_USER", "parts": [ { "mediaType": "application/json", "data": { "operation": "update_homeowner_request", "request": { "intent": { "timeline": "2_3_months" }, "context_facts": [ { "field": "intent.timeline", "value": "2_3_months", "source": "current_message", "confidence": 1, "confirmed_by_homeowner": true } ] } } } ] }, "configuration": { "acceptedOutputModes": ["application/json"] } } } ``` An update never grants permission, runs a route check, submits contact details, or returns the reusable private review capability. ## A2A GetTask — complete JSON-RPC example ```json { "jsonrpc": "2.0", "id": "status-1", "method": "GetTask", "params": { "id": "0198f3e2-7c42-7b09-8bd4-8e4e70b2e111", "historyLength": 0 } } ``` GetTask returns the A2A task directly in result, not under result.task. It may reconcile an already-started provider handoff, but never creates a new submission. Its artifact confirmation_url is null. ## Agent completion feedback Every successful REST or MCP Gateway response and every artifact-bearing A2A homeowner task includes agent_outcome. This is the assistant's factual completion milestone — the "you moved the homeowner farther" confirmation — not a score, permission, offer, or guarantee. - Present agent_outcome.message once per new agent_outcome.code + updated_at, then obey next_action. - buyer_signal.state = eligible_route_found means the anonymous PING found at least one property-fit funded buyer route. It is not buyer acceptance. - ping_eligible_buyer_account_count, when non-null, is the point-in-time number of distinct funded buyer accounts whose programs passed the anonymous property and routing filters available at PING. PING excludes phone and exact address, so later per-buyer duplicate/conflict checks can still change the outcome. The count is not unique people or companies and does not prove anyone viewed, accepted, purchased, or will call. - buyer_signal.state = handoff_delivered means 99 Offers accepted the homeowner-approved handoff. It still does not prove buyer acceptance. - buyer_signal.state = buyer_route_activated requires the authoritative purchase callback. Even then, do not call it a home offer or promise a call time unless a separate verified SLA or call event exists. - no_current_route means no current route was confirmed by that check, not that no buyer exists anywhere. - selling_preference_recorded means the homeowner chose a traditional listing. The preference is retained, but the current service did not run a buyer check and no active 99 Offers listing service is being claimed. - buyer_check_not_available means the request is outside the current automated buyer-check contract. Do not convert it to a listing referral or invent a route. ## Safe polling and stop rules Treat the response fields as control instructions, not suggestions: - next_action = wait: wait at least poll_after_seconds before the next REST status read or A2A GetTask. Apply backoff of 10, 20, 30, then 60 seconds and cap one active automated run at 10 checks. - next_action = provide_information: stop polling. Ask only the returned questions. Before any consent or matching, update the same request through REST, MCP, or A2A; afterward direct the homeowner to the original private review page to correct the facts. - next_action = confirm_match or confirm_contact: stop polling and present the original private review link. The agent cannot take that action. - next_action = complete: stop polling; the task reached its current terminal outcome. - next_action = retry: stop automatic polling. retry never authorizes a replacement request or a contact resubmission. - next_action = none: hard stop. Do not poll, recreate, retry, or resubmit; follow the status message, including any 99 Offers manual-review instruction. - status = submission_unknown: never resubmit, never prepare a duplicate, and never tell the homeowner the handoff failed or succeeded. Safe status reads may reconcile it. - resolution_deadline: at or after this timestamp, make at most one final status read. If next_action becomes none or the status message says that 99 Offers must review it, stop; do not resubmit and do not keep polling. - status = no_match: treat the A2A task as TASK_STATE_INPUT_REQUIRED, not completed. Stop polling. Explain that this check found no current buyer match; it does not mean there are no buyers in the market. Agent updates are closed after matching begins. If material facts changed, let the homeowner correct them and decide whether to rerun the check on the original first-party review page. Never automatically rerun it or create a replacement task. - Stop on any A2A state other than TASK_STATE_WORKING. TASK_STATE_INPUT_REQUIRED and TASK_STATE_AUTH_REQUIRED require a person, not polling. - Network ambiguity never authorizes a second prepare call with a new idempotency key. First retry the identical request with the same key, or read the known task status. ## Status meanings - draft / needs_information: selected facts are incomplete; ask only returned questions. - ready_for_match: the person with the private first-party review must decide whether to check routes. - checking: an approved route check is in progress; no match is established yet. - match_available: a potential route exists; it is not a property offer, appraisal, buyer identity, or guarantee. If buyer_signal includes a count, it is the anonymous PING-stage funded-account count described above. - awaiting_contact_consent: contact details remain private until a separate first-party decision. - posting: the separately approved contact handoff is in progress. Never duplicate it. - submitted: the homeowner-approved handoff was accepted by 99 Offers with a persistent reference. While next_action is wait, the agent may observe a signed buyer activation only until resolution_deadline; afterward handoff_delivered is final. Buyer acceptance, response timing, and a sale are not guaranteed. - purchased: an authoritative purchase callback activated a buyer route. This is stronger than submitted, but it is still not a home offer, completed sale, or call-time guarantee. - submission_unknown: delivery is being reconciled. Never duplicate it. - error with next_action none or a manual-review message: automatic reconciliation ended; 99 Offers must review it and the agent must stop. - refunded / rejected / kept_private / revoked: downstream or homeowner-controlled terminal information. ## Privacy and consent boundary - Prepare, updates before homeowner consent or matching, and safe status are agent-accessible. - Match permission and contact-sharing permission are different decisions. - Both decisions occur through the private first-party 99 Offers review flow. - No A2A message, MCP tool call, REST field, boolean acknowledgement, or agent-side elicitation is treated as homeowner permission. - A route check excludes name, phone, email, and exact street address. - Safe agent status excludes contact PII, exact address, provider economics, and reusable review capability. ## What not to send - Raw transcripts or complete memory exports. - Free-text repair or intent notes longer than 1600 characters, or notes containing repeated speaker turns. Extract one concise homeowner summary instead. - Secrets, authentication tokens, government IDs, bank information, or unrelated personal history. - Guesses presented as homeowner-confirmed facts. - Permission on the homeowner's behalf.