# Link an existing external issue to a work record (no create)
issue map link <work_record_uuid><external_id>
# Resolve
issue map show --uuid <work_record_uuid>
issue map show --external <external_id> [--backend gitea]
# Detach
issue map detach <work_record_uuid>
```
REST sketch:
```text
POST /mappings/ { work_record_uuid, kind?, create_issue? | external_id? }
GET /mappings/?work_record_uuid=…
GET /mappings/?backend=gitea&external_id=…
DELETE /mappings/{id} # or POST detach
```
`POST /issues/` remains for **intentional** issue creation without a work
record. When a work record is known, prefer `POST /mappings/` (or
`POST /issues/` with required `work_record_uuid` in a later schema version).
## Intersection with `TaskSpec` / ingestion
### Today
```json
{
"title": "…",
"triggering_event_id": "…",
"activity_definition_id": "…",
…
}
```
### Proposed extension (backward compatible)
```json
{
"title": "…",
"triggering_event_id": "…",
"work_record_uuid": "optional-uuidv7",
"work_record_id": "optional-canonical-name",
"work_record_kind": "optional-kind",
…
}
```
Rules:
| Case | Behavior |
| --- | --- |
| No `work_record_uuid` | Current behavior: create issue; store ingestion meta; **no mapping row** |
| With `work_record_uuid` | Create or reuse issue; **upsert mapping row**; echo UUID in `sync_metadata` |
| Same UUID + active mapping | Idempotent: return existing `issue_id`, do not create duplicate |
| `triggering_event_id` only | Unchanged meaning (activity lineage) |
**Supersede vs extend:** **extend**. `triggering_event_id` stays for
activity-core. Work-record identity is additive. Long term, emitters that
only need fleet work should not call issue-core at all; emitters that
project a known work record pass `work_record_uuid`.
### activity-core implications (out of band)
- Default sink must not always POST for internal findings (see follow-up
workplan filed under ISSUE-WP-0004-T05).
- When a rule *does* intentionally project, pass the work-record UUID once
intake/task promotion exists — not only the activity event id.
## Sync semantics (boundary only)
| Direction | Trigger | Writes |
| --- | --- | --- |
| Outward | `project` / status change on work record when sync enabled | Update external issue state/labels/comment |
| Inward | Tracker webhook or poll when enabled | Update mapping cursors; **optionally** suggest work-record status change via hub/file write tools — never silent mutation of ADR-001 files without a defined writer |
v1 can implement outward-only + mapping durability; inward sync is a later
increment. Until enabled, connector load is zero beyond idle process cost.
## Failure and edge cases
- **Unknown UUID:** reject project with 4xx; do not create orphan mapping.
- **Backend down:** no mapping row until create succeeds (or store
`pending` if a queue is introduced later — not required for v1).
- **Issue deleted remotely:** mark mapping `detached`; leave work record
intact.
- **Multiple backends:** one active mapping per `(uuid, backend)`;
documenting multi-tracker projection is future work.
- **SQLite-only offline:** mapping table lives with local DB; sync of
issues and mappings to remote is coordinated (mapping rows are not