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.
9.2 KiB
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
IssueBackendABC contract that every backend implements. BackendCapabilitiesdeclares which optional features a backend supports (bulk update, search, milestones, etc.).- A
BackendFactoryregistry 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()onSyncableBackendfor 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:
{
"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
{
"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).