# Company Navigator

One machine-readable interface over Company OS capabilities for agents. It is a
projection plus a receipt-backed action lifecycle; it owns no table, no
dashboard, and no execution path. Everything lands in the canonical ledger:
tenant admission, `SCOPE_TASKS` authority, `create_task_tx`, and
`governance_events`.

Source: `src/company_os/company_navigator/` (`mod.rs` catalogue and router,
`context.rs` entity resolver, `lifecycle.rs` action lifecycle and gaps,
`coverage.rs` freshness map, `tests.rs` database-backed contracts). Outcome
Radar integration lives in `src/company_os/outcome_radar.rs`; Capability Home
embeds the coverage map in `src/company_os/capability_home.rs`.

All routes sit under `/api/company/companies/{company_id}/navigator` and
require a company-bound principal token. POST routes additionally pass the
standard mutation admission (`SCOPE_TASKS`).

## Routes

| Method | Path | Purpose |
| --- | --- | --- |
| GET | `/capabilities` | Catalogue: input/output schemas, effect, risk, approval, prerequisites, entity types, idempotency, examples, readiness, expected receipts, lowering. |
| GET | `/capabilities/{id}/explain` | `explain` step: what a capability does, what it needs, who approves, which receipts prove it ran. Records nothing. |
| GET | `/context?ref=<domain>:<selector>` or `?q=<text>` | Cross-domain entity context with aliases, related entities, and store coverage. |
| GET | `/coverage` | Coverage and freshness map: domains, connectors, business sources, mail queue, open capability gaps, what cannot be performed and why. |
| GET | `/actions` | Recent actions with derived status and next action. |
| POST | `/actions/plan` | `plan` step. Body: `{capability_id?, input, owner_persona?, priority?, due_at?, business_impact?}`. |
| GET | `/actions/{action_id}` | Current envelope of one action. |
| POST | `/actions/{action_id}/preview` | `preview` step: the exact task that would be created. |
| POST | `/actions/{action_id}/approve` | `approve` step. Body: `{decision: approve\|reject, note?}`. |
| POST | `/actions/{action_id}/execute` | `execute` step: one canonical task through `create_task_tx`. |
| POST | `/actions/{action_id}/verify` | `verify` step: proves task and receipts are bound. |

## Action lifecycle

`explain → plan → preview → approve → execute → verify`

- The `action_id` is the SHA-256 of the canonical plan input (company,
  capability, intent, sorted entity bindings, sorted evidence refs). Same
  input, same action; re-planning never writes a second receipt.
- Every step is a `governance_events` row with `subject_type =
  navigator_action` and `subject_id = action_id`. Receipt actions:
  `company_navigator_action_planned`, `_previewed`, `_approved` or
  `_rejected`, `_executed`, `_verified`. Task creation adds `task_created`.
- Approval requires an active owner/admin who is not the planning principal
  (separation of duties). Rejected actions cannot execute.
- Execute is idempotent: the executed receipt carries the task id, and the task
  is deduplicated by `navigator:<action_id>`. Outcome Radar's acceptance of a
  `navigator:` proposal calls the same `execute_action_tx`.
- Global safe mode returns the plan as a `blocked_safe_mode` envelope without
  writing anything.

Every step returns one envelope (`hsm.company_os.navigator_action.v1`):
`action_id`, `capability_id`, `step`, `status`, `entity_bindings`,
`changed_state` (task id, display number, state, task preview), `evidence`
(evidence refs, receipts, verification checks), `receipt_ids`, `approval`, and
`next_action`.

## Entity references

`<domain>:<selector>`. Selectors: a UUID, `#<display_number>` for tasks,
`email:<address>`, `external:<id>`, or a bare natural key.

Domains with a canonical store: `client` (company_customers), `request`
(customer_requests), `task` (tasks), `message` and `thread`
(company_email_operator_queue), `order`, `ticket`, `invoice` (company_*),
`action` (navigator receipts). `opportunity` is computed by Outcome Radar.

Domains with no store in Company OS: `property`, `unit`, `lease`, `resident`,
`vendor`, `inspection`, `incident`, `compliance`, `deal`, `visit`, `document`,
`case`. These bind by reference. The lowered task carries
`{"kind":"label","ref":"entity:<domain>:<selector>"}` in `capability_refs`, so
`/context?ref=property:velora-12` still joins to its tasks and actions through
the ledger.

## Capability gaps

When `plan` receives no capability id (or an unknown one), the navigator
records `company_navigator_capability_gap` with `subject_type =
capability_gap` and `subject_id = fingerprint`. The fingerprint hashes the
requested capability, the entity kinds, and the normalized intent terms, so
rewordings of the same ask collapse. Frequency is the receipt count per
fingerprint. Each receipt keeps the attempted intent, the missing tool or
data, business impact, DRI, and suggested catalogue capabilities.

Open gaps appear in `/coverage` and in Outcome Radar as `gap:<first receipt
id>`. Accepting one creates the deduplicated missing-capability task
(dedupe key `capability-gap:<fingerprint>`).

## Outcome Radar sources added

Proposal ids keep the `<prefix>:<uuid>` convention:

| Prefix | Source | Proposal |
| --- | --- | --- |
| `connector` | company_connectors in error/degraded or failed after last success | Repair connector |
| `source` | company_business_sources degraded/error or non-manual and stale over 7 days | Refresh source |
| `mail` | company_email_operator_queue pending over 24 hours | Answer waiting email |
| `navigator` | planned actions with an approval and no execution/rejection | Execute approved action (accept executes it) |
| `gap` | capability gaps grouped by fingerprint | Close capability gap |

## Property operations pack

Nine capabilities under `company_os_property_operations_pack`:
`property.portfolio.context`, `property.lease.renewal`,
`property.resident.followup`, `property.maintenance.triage`,
`property.vendor.coordinate`, `property.inspection.schedule`,
`property.finance.review`, `property.compliance.deadline`,
`property.incident.respond`. Each lowers to one canonical task through the
lifecycle with approval required; property entities bind by reference.

## Verification

`cargo test --lib -- company_navigator:: outcome_radar:: capability_home::`
with `DATABASE_URL` set. The database-backed tests cover the read gate, the
full lifecycle, the Radar hand-off, gap deduplication, safe mode, and the
entity resolver.
