Files
issue-core/SCOPE.md
tegwick b605d970e3 feat: rename to issue-core and add task ingestion endpoint
Renames the package, distribution, CLI alias, Makefile targets, and
working directory from issue-facade to issue-core, signalling its
role as the authoritative task lifecycle manager for the Coulomb org
(peer to activity-core, rules-core, project-core).

Adds POST /issues/ ingestion endpoint for activity-core's IssueSink,
under a new optional [api] extra. The endpoint is served by `issue
serve`, authenticates via the ISSUE_CORE_API_KEY env var (Bearer or
X-API-Key header), and routes the TaskSpec payload to the configured
default backend with full traceability metadata embedded in
sync_metadata.

- T01: Python package issue_tracker -> issue_core, dir rename
- T02: registered in state hub under custodian domain
- T03: INTENT.md (what it is, what it isn't, how it fits)
- T04: SCOPE.md (in/out-of-scope, integration boundaries)
- T05: POST /issues/ via FastAPI + Uvicorn, 9 unit tests
- T06: docs/nats-task-ingestion.md design stub

Closes ISSC-WP-0001.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 05:16:27 +02:00

165 lines
5.8 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*.
## In scope
### Task CRUD across backends
- **Create** issues with title, description, labels, priority, type, milestone,
assignee, due date.
- **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 source of truth.
- **Gitea** — REST API integration.
### Backends planned
- **GitHub** — Issues + PRs.
- **GitLab** — Issues.
- **JIRA** — issues with story-points.
### Ingestion surfaces
- **CLI** (`issue` / `issue-core`) for humans and agents on a shell.
- **REST** (`POST /issues/`) for automation — primarily activity-core's
`IssueSink`, but open to any well-authenticated client.
- **NATS subscriber** (design stub only — implementation deferred until
activity-core migrates from REST to NATS, see `docs/nats-task-ingestion.md`).
### 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 repo.
- Emits `add_progress_event()` calls on significant task lifecycle moments.
- Surfaces blocked tasks via the hub's `list_blocked_tasks()` view.
## Out of scope
### Project management
Phases, campaigns, milestones-as-plans, dependency graphs between tasks,
gantt-style scheduling, OKR linkage. **That is `project-core` (planned).**
issue-core operates on individual tasks. A milestone field exists for
flat grouping, not for multi-stage plans.
### Spawn audit trail
When activity-core's IssueSink files a task here, the *spawn event* (who fired
the rule, against which activity definition, on which triggering event) is
recorded in **activity-core's `task_spawn_log`**. issue-core stores the resulting
task and a back-reference (`triggering_event_id`) — nothing more.
Symmetrically: issue-core does not push status updates back to activity-core.
Lifecycle updates stay here; activity-core does not care what happens to a task
it spawned.
### 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. issue-core emits progress
events; downstream consumers decide what to do with them.
### 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 ingestion endpoint. issue-core is not a
user directory.
## Integration boundaries
### Upstream emitters
| Emitter | Transport | Payload | Notes |
|----------------|----------------------|--------------------------|-------|
| Human CLI | local process call | CLI args | The classic path. |
| activity-core | REST `POST /issues/` | `TaskSpec` (see below) | Primary integration; planned NATS migration. |
| Agents | REST or CLI | `TaskSpec` or CLI args | Same surfaces as humans/automation. |
### Downstream consumers
| Consumer | Mechanism | Notes |
|----------------------|------------------------------------|-------|
| Humans / agents | `issue list`, web UI, backend UI | Standard task pickup. |
| state-hub | `add_progress_event()` calls | Lifecycle visibility. |
| Backend remote (e.g. Gitea) | direct backend write | Pass-through for the storage layer. |
### `TaskSpec` payload (from activity-core's IssueSink)
```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": "uuid",
"activity_definition_id": "string"
}
```
### `POST /issues/` response
```json
{
"issue_id": "string",
"issue_url": "string or null",
"backend": "gitea | sqlite | github"
}
```
The `issue_id` is the canonical back-reference activity-core stores in its
`task_spawn_log`. It is owned and managed by issue-core; activity-core does not
mutate it.
## See also
- `INTENT.md` — why issue-core exists and how it fits in the Coulomb org.
- `ROADMAP.md` — feature trajectory.
- `workplans/ISSC-WP-0001-rename-and-task-ingestion.md` — current rename +
ingestion workstream.
- activity-core `docs/adr/adr-001-event-bridge-architecture.md` — the upstream
side of the IssueSink contract.