feat: implement ISSUE-WP-0005 connector mapping and scope alignment
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Build and Publish Container Image / build-and-push (push) Successful in 1m22s

Add MappingService (work_record_uuid ↔ external id), project/map CLI with
outward push-status, optional TaskSpec work_record fields, boundary-sync
policy, and packaging/capability framing cleanup. Mark WP-0005 finished.
This commit is contained in:
tegwick 2026-07-22 00:25:06 +02:00
parent 6855fb2a32
commit f88e9a28fe
16 changed files with 1300 additions and 179 deletions

View file

@ -54,14 +54,26 @@ declared in `pyproject.toml`; no backend package under `issue_core/backends/`).
| Group | Commands (shipped) |
| --- | --- |
| Issues | `list`, `show`, `create`, `edit`, `close`, `reopen`, `comment` |
| Project / map | `project`, `map link`, `map show`, `map detach`, `map list`, `map push-status` |
| Backend | `backend list`, `add`, `remove`, `test`, `set-default` |
| Sync | `sync status`, `pull`, `push`, `bidirectional` |
| Server | `serve` — FastAPI process (requires `[api]` extra) |
- JSON-friendly output for agents (`--format=json` on list/show paths).
- Backend configs: `~/.config/issue-core/` (default backend + named configs).
- Backend configs: `~/.config/issue-tracker/` (default backend + named configs).
- Mapping store: `~/.config/issue-tracker/mappings.db` (independent of CRUD backend).
- Gitea token typically from env (`GITEA_API_TOKEN` / config); never commit secrets.
### 1.4b Work-record mapping (shipped v0.2.x)
| Piece | Notes |
| --- | --- |
| `MappingService` | `issue_core/core/mapping.py` — SQLite `work_record_issue_map` |
| Keys | Work-record **UUIDv7**`(backend, external_id)`; optional canonical id denorm |
| Uniqueness | One active mapping per `(uuid, backend)` and per `(backend, external_id)` |
| Outward status | `map push-status` uses `docs/boundary-sync-and-status-mapping.md` |
| TaskSpec | Optional `work_record_uuid` / `work_record_id` / `work_record_kind` on `POST /issues/` upserts mapping; idempotent reuse |
### 1.5 REST API (optional install: `pip install 'issue-core[api]'`)
Auth: shared secret `ISSUE_CORE_API_KEY` via `Authorization: Bearer …` or
@ -105,7 +117,8 @@ optional `due_at` derived from `due_in_days`.
| Item | Status |
| --- | --- |
| Work-record UUID ↔ external-id **mapping store/API** | Design only — `docs/uuid-external-id-mapping.md` |
| Inward boundary sync (tracker → work-record file write) | Not shipped — v1 is outward-only |
| REST `/mappings/` resource | CLI primary; REST mapping is via optional fields on `POST /issues/` |
| NATS subscriber | Design stub — `docs/nats-task-ingestion.md` |
| Runtime calls to state-hub (`add_progress_event`, etc.) | **Not in `issue_core` package**; repo participates as a normal ADR-001 workplan host only |
| Auto-detect backend from git remote | Roadmap / Makefile hints; not a reliable product path yet |
@ -114,6 +127,7 @@ optional `due_at` derived from `due_in_days`.
| Per-`target_repo` backend routing on REST | Planned only |
| Issue claiming locks beyond assignee + state | Convention only |
| First-class due-date field on `Issue` | `due_in_days` → ingestion metadata only |
| Canon work-record YAML back-reference field | Field name TBD in the-custodian; mapping authority is issue-core |
---
@ -131,12 +145,14 @@ Things this repo **owns** and may grow, consistent with the connector role.
### 2.2 Connector / mapping (owned direction)
- Durable **work-record UUID ↔ (backend, external issue id)** mapping
(design agreed; implementation stage-3 work-record architecture).
- Optional two-way **boundary sync** when an integration is switched on;
**zero load** when not configured.
- Keep `triggering_event_id` as emitter lineage; **extend** with
`work_record_uuid` rather than overloading it (see mapping design).
- Durable **work-record UUID ↔ (backend, external issue id)** mapping —
**store + CLI shipped** (ISSUE-WP-0005); REST `/mappings/` and file
back-references remain optional growth.
- **Outward** status projection shipped; **inward** boundary sync later,
never silent ADR-001 mutation; **zero load** when no mapping is used.
- Keep `triggering_event_id` as emitter lineage; optional
**`work_record_uuid` on TaskSpec** is shipped (do not overload
`triggering_event_id`).
### 2.3 Surfaces
@ -242,12 +258,17 @@ Retained for intentional emits and backward compatibility:
"source_type": "rule | instruction",
"source_id": "string",
"triggering_event_id": "event uuid or stable source key",
"activity_definition_id": "string"
"activity_definition_id": "string",
"work_record_uuid": "optional UUIDv7",
"work_record_id": "optional canonical id",
"work_record_kind": "optional kind"
}
```
- `triggering_event_id`: non-empty string; activity event UUID or stable key
such as `scheduled`. Stored in ingestion metadata — **not** a work-record UUID.
- `work_record_uuid` (optional): when set, upserts mapping and makes re-POST
idempotent for that UUID + backend.
- Response:
```json