issue-core/SCOPE.md
tegwick d60175c354
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
docs: align issue-core with work-record connector role (ISSUE-WP-0004)
Retarget INTENT, SCOPE, README, ROADMAP, and agent docs from "task landing
zone" to external-tracker connector per work-record canon and architecture
draft §4.2. Add UUID↔external-id mapping design; mark ISSUE-WP-0004 finished
and cross-file activity-core ACTIVITY-WP-0022 for IssueSink policy.
2026-07-21 04:22:12 +02:00

234 lines
9.2 KiB
Markdown

# SCOPE — issue-core
Concrete in-scope / out-of-scope decisions for issue-core. Paired with `INTENT.md`,
which explains *why*; this file states *what* and *what not*.
**Fleet framing (2026-07-20):** issue-core is a **connector** to external
issue trackers and the home of the **UUID ↔ external-id mapping** concept.
Work records originate as repo files (ADR-001 / work-record canon). See
`INTENT.md` and `docs/uuid-external-id-mapping.md`.
## In scope
### External-issue CRUD across backends
- **Create** issues with title, description, labels, priority, type, milestone,
assignee, due date — when a tracker projection or direct tracker use is
intentional.
- **Read** individual issues and lists with filters (state, labels, priority,
assignee, text search).
- **Update** any mutable field on existing issues.
- **Close / reopen** with state transitions enforced at the domain layer.
- **Delete** where the backend allows (local SQLite; soft-archive elsewhere).
- **Comment** threads on issues.
### Backend abstraction
- A single `IssueBackend` ABC contract that every backend implements.
- `BackendCapabilities` declares which optional features a backend supports
(bulk update, search, milestones, etc.).
- A `BackendFactory` registry that maps config to backend instances.
### Backends shipped today
- **Local SQLite** — offline cache / source of truth for disconnected work.
- **Gitea** — REST API integration (Forgejo-compatible in deployment).
### Backends planned
- **GitHub** — Issues + PRs.
- **GitLab** — Issues.
- **JIRA** — issues with story-points.
### UUID ↔ external-id mapping (target shape)
Primary *fleet* responsibility of issue-core going forward — design only in
this repo until stage-3 work-record architecture lands; see
`docs/uuid-external-id-mapping.md`.
| Concept | Meaning |
| --- | --- |
| Internal id | Work-record UUID (UUIDv7, hub-assigned / written back to source file as `state_hub_*_id`-style fields) |
| External id | Backend issue id / number + backend identity (`gitea`, `github`, …) |
| Mapping row | Durable association: which work record projects to which external issue |
| Direction | Create projection outward; optional two-way sync of status/comments at the boundary |
Named here so scope and design agree before implementation.
### Operator / automation surfaces
- **CLI** (`issue` / `issue-core`) for humans and agents on a shell — direct
backend use.
- **REST** (`POST /issues/`) for **intentional** external-issue creation by
authenticated clients. Remains useful; is **not** the primary fleet path for
originating work.
- **REST worker surface** (`GET/PATCH /issues/`) for executors that operate on
external issues when a tracker is in the loop: list, claim
(`in_progress` + assignee), close.
- **NATS subscriber** (design stub only — see `docs/nats-task-ingestion.md`).
Any NATS path must respect the same rule: external projection only when
explicitly configured, never silent origin of fleet work.
### Synchronization
- Local SQLite ↔ remote backends, bidirectional.
- `get_issues_modified_since()` on `SyncableBackend` for incremental sync.
- Conflict resolution via `SyncableBackend.resolve_sync_conflict()`.
- Sync metadata (last-synced timestamps, remote IDs) stored on `Issue.sync_metadata`.
### State Hub integration
- Registered as a custodian-domain / infotech repo.
- May emit `add_progress_event()` on significant *connector* lifecycle moments
(e.g. projection created, mapping updated) when wired.
- Does **not** replace work-record indexing; state-hub remains the fleet read
model for work records.
## Out of scope
### Origin of fleet work
Creating workplans, tasks, intake items, decisions, or engagements. Those
originate as repo files (or schema-valid blocks in context) and are indexed by
`fix-consistency` / state-hub. issue-core may **project** an existing work
record to a tracker; it does not birth the work record.
### Default sink for internal automation findings
activity-core (and similar) must not treat `POST /issues/` as the always-on
default for every matched rule. That product decision lives in the emitter;
issue-core will keep accepting authenticated POSTs but will not redefine itself
as the landing zone. Follow-up: activity-core IssueSink policy (filed from
ISSUE-WP-0004-T05).
### Project management
Phases, campaigns, milestones-as-plans, dependency graphs between tasks,
gantt-style scheduling, OKR linkage. **That is workplan / project tooling.**
issue-core operates on individual external issues. A milestone field exists for
flat grouping, not for multi-stage plans.
### Spawn audit trail
When an emitter files an issue here, the *spawn event* (who fired, which rule,
which triggering event) is recorded by the **emitter** (e.g. activity-core's
`task_spawn_log`). issue-core stores the resulting issue and traceability
fields (`triggering_event_id` today; work-record UUID in the mapping design) —
nothing more.
Symmetrically: issue-core does not push fleet work-record status updates back
to activity-core. Lifecycle of external issues stays here; lifecycle of work
records stays in repo files + hub.
### Event bus / message broker
Inter-service communication runs on NATS managed elsewhere. issue-core consumes
specific subjects (future) and exposes a REST surface; it does not relay events
between other services.
### Notifications
Telling a human "your task changed" is the job of the relevant UI, digest,
chatbot, or notification service — not issue-core.
### Workflow / approval engine
State machine is intentionally small (OPEN, CLOSED, IN_PROGRESS, BLOCKED).
Conditional routing, approval chains, multi-step workflows, SLA timers — all
out of scope.
### UI
issue-core is CLI + REST first. Each backend brings its own native UI
(Gitea web, GitHub web, etc.) and that is enough. A web UI for issue-core
itself is not on the roadmap.
### Identity / access management
Authentication relies on backend credentials (Gitea tokens, GitHub tokens) and
on a service-level API key for the REST endpoint. issue-core is not a
user directory.
## Integration boundaries
### Fleet primary path (work records)
| Step | Owner | Notes |
| --- | --- | --- |
| Author / promote work record | Repo files + tools | ADR-001 / work-record canon |
| Index + UUID write-back | state-hub `fix-consistency` | Hub is read model |
| Claim / execute | Humans, agents, harness | On work records, not on Forgejo by default |
| Optional external projection | **issue-core** | Mapping table + backend CRUD |
### Surfaces into issue-core
| Client | Transport | Payload | Role |
| --- | --- | --- | --- |
| Human CLI | local process | CLI args | Direct tracker use / admin |
| Agents | REST or CLI | issue fields or CLI args | Tracker ops when in the loop |
| activity-core IssueSink | REST `POST /issues/` | `TaskSpec` | **Optional, intentional** external issues only — not default for internal findings |
| Future mapping API | REST/CLI (TBD) | work_record_uuid + project request | Primary fleet connector path once designed |
### Downstream consumers
| Consumer | Mechanism | Notes |
| --- | --- | --- |
| Humans / external collab | backend UI, `issue list` | Third-party tracker collaboration |
| state-hub | work-record index; optional progress events | Fleet orientation |
| Backend remote (e.g. Gitea) | direct backend write | Storage / projection layer |
### `TaskSpec` payload (activity-core IssueSink — retained contract)
Still accepted for backward compatibility and intentional emits:
```json
{
"title": "string",
"description": "string",
"target_repo": "string",
"priority": "high | medium | low",
"labels": ["string"],
"due_in_days": 7,
"source_type": "rule | instruction",
"source_id": "string",
"triggering_event_id": "event uuid or stable source key",
"activity_definition_id": "string"
}
```
`triggering_event_id` is accepted as a non-empty string. Event-driven
emissions should send the upstream activity event UUID. Scheduled or cron
emissions that do not have a concrete event row may send a stable source key
such as `scheduled`; issue-core stores the value verbatim in ingestion
metadata for traceability.
**Relation to mapping design:** `triggering_event_id` is emitter-side
traceability, not a work-record UUID. The mapping surface will add an explicit
work-record identity field (and durable mapping rows). See
`docs/uuid-external-id-mapping.md` — extend rather than overload
`triggering_event_id`.
### `POST /issues/` response
```json
{
"issue_id": "string",
"issue_url": "string or null",
"backend": "gitea | sqlite | github"
}
```
The `issue_id` is the external-issue back-reference an intentional emitter may
store (e.g. activity-core `task_spawn_log`). It is owned by issue-core's
backend; it is not a work-record UUID.
## See also
- `INTENT.md` — why issue-core exists and the connector pivot.
- `ROADMAP.md` — feature trajectory.
- `docs/uuid-external-id-mapping.md` — mapping design (not yet implemented).
- `workplans/ISSUE-WP-0004-align-with-work-record-canon.md` — alignment work.
- `the-custodian/canon/standards/work-record-types_v0.1.md` — work-record kinds;
task kind notes that issue-core issues are external projections only.
- activity-core `docs/adr/adr-001-event-bridge-architecture.md` — IssueSink
contract (emitter side; policy follow-up separate).