Handbook
Outlook People read strategies (OWA)
Read-only harvest for Outlook Web People (/people/). Cockpit orchestrates; LCDL provides governed tasks. Outlook People is the sole OWA org-directory surface — the legacy Org Explorer (Delve iframe) crawl has been…
Updated
Entry
- OWA left nav → People.
- Host URL:
https://outlook.office.com/people/ - No Delve iframe — all reads are host-page evaluate.
CDP policy
- Reuse the operator's existing People tab (
pick_outlook_people_cdp_page_target). - Attach with selective CDP (
connect_owa_page_via_selective_cdp) — focus emulation on connect. - Read-only clicks: contact rows, tree items, search suggest options, profile panel dismiss (Escape).
- Keep
FORGE_LCDL_CDP_BRING_TO_FRONT=0(default) for unattended harvest. - Tab lifecycle — external LinkedIn profile tabs opened during LPC harvest must be closed after URL capture; see TAB-LIFECYCLE-POLICY.md.
Tasks
| Task | Purpose |
|---|---|
outlook_probe_people_health |
/people/ URL, Search contacts and directory combobox, left [role=tree] |
outlook_people_home_snapshot |
Visible [role=row] contacts (+ scroll rounds) |
outlook_people_focus_search |
Type query → CDP Enter → capture suggest API → open LPC via quick-action |
outlook_people_focus_tree |
Click row or treeitem by display_name / mail |
outlook_people_snapshot_person |
Focus (tree, else search) + read_profile_panel |
outlook_people_read_profile_panel |
Parse flyout text (email, phone, org fields) |
outlook_people_dismiss_profile_panel |
Escape dismiss |
Input: { "session_ref": "…", "operator_graph_id": "…", "operator_mail": "…" } on a People host tab.
Task inputs for focus/search also accept query, display_name, mail, graph_id.
Data sources (priority)
- Directory suggest API —
POST /search/api/v1/suggestions?domain=People(network capture inOutlookPeopleReader) - Contact list —
[role=row]innerText (parse_people_row_text) - Left tree — operator email from treeitem text
- Profile panel — shared parsers from
owa_lpc_reader(parse_profile_card_text,parse_contact_panel_fields)
Identity: List rows often lack Azure AD GUID. Wire uses pending_mail:{email} unless operator_graph_id / env supplies operator GUID. Cockpit resolves mail against person table before ingest.
Not identity: Suggest PersonId when absent — prefer mail match in consumer.
Wire shape
{
"ok": true,
"focused_graph_id": "5af741ae-…",
"upn": "operator@contoso.com",
"people": [{ "graph_id": "pending_mail:user@example.com", "display_name": "…", "mail": "…" }],
"edges": []
}
v1 home scan does not emit reports_to / peer_of edges — hierarchy comes from the per-person Organization tab (parse_organization_panel_fields), resolved to graph_id consumer-side.
Consumer
forge-cockpit-web — cockpit_server/org/people_harvest.py, ingest.py (harvest_source="outlook_people"). Operator flow: org-people-harvest.md. Dual architecture: OUTLOOK-PEOPLE-DUAL-ARCHITECTURE.md ↔ org-people-dual-architecture.md.