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.
This commit is contained in:
parent
5e556028ab
commit
d60175c354
9 changed files with 760 additions and 226 deletions
|
|
@ -4,7 +4,9 @@
|
|||
|
||||
## Purpose
|
||||
|
||||
The **Issue Core** capability provides a standardized interface for autonomous coding agents to coordinate project implementation through issue tracking. Instead of agents directly interfacing with platform-specific APIs (GitHub, GitLab, Gitea), they use a unified abstraction that works consistently across backends.
|
||||
The **Issue Core** capability provides a standardized interface for autonomous coding agents to operate on **external issue trackers** (GitHub, GitLab, Gitea/Forgejo). Instead of agents learning platform-specific APIs, they use a unified abstraction.
|
||||
|
||||
**Fleet note (2026-07-20):** Internal work originates as repo work records (ADR-001 / work-record canon), not as issue-core issues. Use this guide when an agent must project to or work inside a third-party tracker. See `INTENT.md` and `docs/uuid-external-id-mapping.md`.
|
||||
|
||||
### Why Issue Tracking for Agent Coordination?
|
||||
|
||||
|
|
|
|||
194
INTENT.md
194
INTENT.md
|
|
@ -2,57 +2,105 @@
|
|||
|
||||
## Why it exists
|
||||
|
||||
The Coulomb org needs a **single, observable place where tasks land** — regardless
|
||||
of whether they were created by a human typing a CLI command, by an automation
|
||||
like activity-core acting on a rule, or by an agent acting on instructions.
|
||||
The Coulomb org collaborates through **external issue trackers** (Forgejo /
|
||||
Gitea, GitHub, Jira, …) when a human counterparty, open-source workflow, or
|
||||
third-party process requires it. Those systems are not the fleet's internal
|
||||
coordination substrate — that role belongs to **work records** authored as
|
||||
repo files (ADR-001) and indexed by state-hub.
|
||||
|
||||
Without a single landing zone, task creation fragments across:
|
||||
- Per-repo Gitea issue trackers (siloed, no cross-repo view)
|
||||
- Ad hoc files and TODO comments (invisible, unaudited)
|
||||
- Agent-local memory and notebooks (lost when the agent ends)
|
||||
- External SaaS trackers (rate-limited, off-network)
|
||||
issue-core exists so that, **when an external tracker is actually in use**,
|
||||
every actor can project, query, and update issues through one backend-agnostic
|
||||
interface — and so the fleet can keep a stable **mapping** between internal
|
||||
work-record identity (UUIDs) and external issue ids.
|
||||
|
||||
issue-core gives every actor — human or machine — one stable, observable place
|
||||
to file work, and one stable surface to consume work from.
|
||||
Without a connector layer, external-tracker access fragments across:
|
||||
- Per-repo Gitea / Forgejo API clients (siloed, no shared mapping)
|
||||
- Ad hoc `gh` / `glab` / curl scripts (untyped, unaudited)
|
||||
- Agent-local integrations (lost when the agent ends)
|
||||
- Direct SaaS API calls (rate-limited, off-network, no UUID back-reference)
|
||||
|
||||
issue-core gives humans and machines one stable surface to talk to external
|
||||
trackers, and (target shape) one place that records which internal work record
|
||||
projects to which external issue.
|
||||
|
||||
## Honest history (pivot, 2026-07-20)
|
||||
|
||||
issue-core was originally built and documented as a **task landing zone**: a
|
||||
single observable place where humans, activity-core, and agents filed work via
|
||||
CLI / REST / future NATS, with Gitea as the default store. That framing
|
||||
contradicted the fleet decision that work originates as **repo files** and
|
||||
that Forgejo issues are not the coordination mechanism.
|
||||
|
||||
The pivot was ratified while reviewing a live incident: activity-core's
|
||||
`daily-todo-md-stale-review` ActivityDefinition routed findings through
|
||||
`IssueSink` → issue-core → Forgejo, producing issues nobody was meant to see
|
||||
as fleet work. Founder-reviewed architecture draft §4.2
|
||||
(`the-custodian/research/WorkOrchestrationArchitectureDraft.md` v0.2,
|
||||
2026-07-20) and the work-record canon
|
||||
(`the-custodian/canon/standards/work-record-types_v0.1.md`, CUST-WP-0060)
|
||||
settled the role below. Capability (CRUD, backends, REST, sync) stays; the
|
||||
*purpose* is retargeted to connector, not origin.
|
||||
|
||||
## What it is
|
||||
|
||||
A **task lifecycle manager** with a pluggable-backend architecture.
|
||||
A **connector framework to external issue-tracking systems**, with a
|
||||
pluggable-backend architecture.
|
||||
|
||||
Responsibilities:
|
||||
- **Ingestion**: accept new tasks via CLI, REST (`POST /issues/`), and — in the
|
||||
future — NATS subscriptions.
|
||||
- **Storage**: route each task to the configured backend (Gitea, SQLite, GitHub).
|
||||
- **Lifecycle**: create → assign → update → close, with state transitions that
|
||||
hold regardless of backend.
|
||||
- **Querying**: list, search, filter across the active backend.
|
||||
- **Synchronization**: bidirectional sync between local SQLite (source of truth
|
||||
for offline work) and remote backends.
|
||||
- **Projection / CRUD**: create, read, update, close, and comment on issues in
|
||||
the configured backend (Gitea/Forgejo, SQLite offline cache, planned GitHub /
|
||||
GitLab / Jira).
|
||||
- **Mapping (target)**: maintain internal work-record UUID ↔ external issue id
|
||||
so a work record can carry a back-reference to its tracker projection
|
||||
(design: `docs/uuid-external-id-mapping.md`).
|
||||
- **Boundary sync**: two-way, transclusion-like sync *at the boundary* when
|
||||
collaboration runs through a third-party tracker — not as the internal
|
||||
execution loop.
|
||||
- **CLI + REST**: human and automation surfaces for direct backend use when a
|
||||
tracker is intentionally switched on.
|
||||
- **Optional ingestion**: `POST /issues/` remains for authenticated clients that
|
||||
deliberately create tracker issues; it is **not** the primary fleet path for
|
||||
internal findings or work origin.
|
||||
|
||||
Backends today: **local SQLite**, **Gitea**. Planned: **GitHub**, **GitLab**, **JIRA**.
|
||||
|
||||
The CLI entry points are `issue` (primary) and `issue-core` (explicit alias).
|
||||
|
||||
Until an external integration is actually switched on for a given workflow, the
|
||||
connector layer should add **zero load** to the internal coordination loop.
|
||||
|
||||
## What it is NOT
|
||||
|
||||
issue-core is intentionally narrow. The following live elsewhere:
|
||||
|
||||
- **Not a project manager.** Phases, campaigns, milestones spanning multiple tasks,
|
||||
dependency graphs across tasks, gantt-style scheduling — that is the domain of
|
||||
`project-core` (planned). issue-core deals in individual tasks, not in plans
|
||||
composed of tasks.
|
||||
- **Not the origin of work records.** Work records originate as repo files per
|
||||
ADR-001 (`the-custodian/canon/architecture/adr-001-workplans-as-repo-artefacts.md`
|
||||
and the work-record types standard). issue-core provides the
|
||||
**external-tracker projection** when one is in use. Internal tasks, intake
|
||||
items, workplans, and decisions are not created here.
|
||||
|
||||
- **Not a spawn audit trail.** When activity-core fires a rule that creates a task,
|
||||
the *spawn event* (who fired, what rule, what triggering event) is recorded in
|
||||
activity-core's `task_spawn_log`. issue-core only stores the resulting task and
|
||||
its `triggering_event_id` reference back. The audit-of-creation belongs to the
|
||||
emitter.
|
||||
- **Not the internal execution / coordination loop.** Claiming and execution
|
||||
run on work records directly (harness intake via NATS/activity-core per its
|
||||
stated target). Fleet orientation is state-hub + repo files, not Forgejo
|
||||
issue lists.
|
||||
|
||||
- **Not a project manager.** Phases, campaigns, milestones spanning multiple
|
||||
tasks, dependency graphs across tasks, gantt-style scheduling — that is the
|
||||
domain of workplans / project tooling. issue-core deals in individual
|
||||
external issues, not in plans composed of tasks.
|
||||
|
||||
- **Not a spawn audit trail.** When an upstream service deliberately emits an
|
||||
issue here, the *spawn event* belongs to the emitter (e.g. activity-core's
|
||||
`task_spawn_log`). issue-core stores the resulting issue and optional
|
||||
traceability fields (`triggering_event_id`, future work-record UUID) — not
|
||||
the audit-of-creation.
|
||||
|
||||
- **Not an event bus.** Communication between services flows over NATS (and
|
||||
state-hub progress events). issue-core consumes events, but does not relay them.
|
||||
state-hub progress events). issue-core consumes or serves specific
|
||||
boundaries; it does not relay events between other services.
|
||||
|
||||
- **Not a notification system.** Surfacing "your task changed" to humans is the
|
||||
job of the relevant UI / digest / chatbot layer, not issue-core.
|
||||
- **Not a notification system.** Surfacing "your task changed" to humans is
|
||||
the job of the relevant UI / digest / chatbot layer, not issue-core.
|
||||
|
||||
- **Not a workflow engine.** State transitions are simple (open → closed, with
|
||||
a few in-between states). Conditional routing, approvals, multi-step
|
||||
|
|
@ -61,19 +109,17 @@ issue-core is intentionally narrow. The following live elsewhere:
|
|||
## How it fits
|
||||
|
||||
```
|
||||
+-------------------+
|
||||
| activity-core |
|
||||
| IssueSink (REST) |
|
||||
+---------+---------+
|
||||
|
|
||||
POST /issues/ (TaskSpec payload)
|
||||
|
|
||||
v
|
||||
+------------+ +-------+--------+ +-----------------+
|
||||
| Humans +----->| |<-----+ Agents |
|
||||
| CLI: | | issue-core | | (CLI or REST) |
|
||||
| $ issue | | | | |
|
||||
+------------+ +-------+--------+ +-----------------+
|
||||
Work records (repo files, ADR-001) External collaboration
|
||||
───────────────────────────────── ──────────────────────
|
||||
workplan / task / intake / … Counterparty, OSS, Jira, …
|
||||
│ │
|
||||
│ optional project when │
|
||||
│ a tracker is switched on │
|
||||
v v
|
||||
+------------------+ UUID ↔ issue id +------------------+
|
||||
| state-hub | <---- mapping ------> | issue-core |
|
||||
| (read model) | | (connector) |
|
||||
+------------------+ +--------+---------+
|
||||
|
|
||||
+---------+----------+
|
||||
| Backend router |
|
||||
|
|
@ -82,35 +128,53 @@ issue-core is intentionally narrow. The following live elsewhere:
|
|||
v v v
|
||||
+------+ +-----+ +------+
|
||||
|Gitea | |SQLite| |GitHub|
|
||||
|Forgejo| |cache| | … |
|
||||
+------+ +-----+ +------+
|
||||
|
||||
Direct use (human CLI / intentional REST) still goes to issue-core
|
||||
without creating a work-record origin — useful for tracker admin and
|
||||
collaboration, not for fleet task birth.
|
||||
```
|
||||
|
||||
**Upstream of issue-core (emitters):**
|
||||
- **activity-core** — emits tasks via `IssueSink` when a rule fires or an
|
||||
instruction declares one. Payload: `TaskSpec` over `POST /issues/`.
|
||||
- **Humans** — `$ issue create ...` from terminals; future web UI.
|
||||
- **Agents** — same REST surface or CLI.
|
||||
**Primary fleet path (coordination):**
|
||||
1. A work record exists in a repo file (or is registered from one).
|
||||
2. Humans/agents claim and execute against that record (and state-hub views).
|
||||
3. **Optionally**, issue-core projects the record to an external tracker and
|
||||
records the UUID ↔ external-id mapping.
|
||||
|
||||
**Downstream of issue-core (consumers):**
|
||||
- **Humans and agents** assigned tasks consume them via `$ issue list`, web UI,
|
||||
or per-backend native UIs (Gitea web, GitHub PR view, etc.).
|
||||
- **state-hub** receives progress events as tasks move through their lifecycle.
|
||||
- **Status updates** flow back to issue-core, not to the original emitter —
|
||||
activity-core does not track what happened to the task it spawned.
|
||||
**Secondary path (direct tracker use):**
|
||||
- **Humans** — `$ issue create ...` when deliberately working in a backend.
|
||||
- **Authenticated automation** — `POST /issues/` only when the product decision
|
||||
is "create an external issue," not "spawn fleet work."
|
||||
- **activity-core IssueSink** — must not be the default always-on path for
|
||||
internal findings (see ISSUE-WP-0004-T05 / activity-core follow-up).
|
||||
|
||||
**Downstream:**
|
||||
- Backend native UIs (Gitea web, GitHub, …) for external collaboration.
|
||||
- state-hub for fleet lifecycle visibility of *work records*, not of every
|
||||
issue-core row.
|
||||
|
||||
## Success looks like
|
||||
|
||||
- Every task in the Coulomb org is discoverable from one query surface.
|
||||
- activity-core can fire a rule and have the resulting task land in the right
|
||||
backend with the right metadata, with no human in the loop.
|
||||
- The CLI experience is identical across SQLite-only laptops and full Gitea-
|
||||
backed servers.
|
||||
- Offline work syncs back cleanly when connectivity returns.
|
||||
- External trackers are usable through one CLI/API without each agent learning
|
||||
platform-specific clients.
|
||||
- When a work record is projected outward, the UUID ↔ external-id mapping is
|
||||
durable and inspectable (once implemented per the design note).
|
||||
- Internal automation does **not** silently open Forgejo issues for findings
|
||||
that belong in repo work records.
|
||||
- Offline SQLite work syncs cleanly to a remote backend when connectivity
|
||||
returns.
|
||||
- With no external integration switched on, issue-core adds no load to the
|
||||
internal loop.
|
||||
|
||||
## See also
|
||||
|
||||
- `SCOPE.md` — concrete in/out-of-scope decisions and integration boundaries.
|
||||
- `ROADMAP.md` — feature trajectory.
|
||||
- `workplans/` — active workplans.
|
||||
- activity-core `docs/adr/adr-001-event-bridge-architecture.md` — the IssueSink
|
||||
contract that issue-core honors at `POST /issues/`.
|
||||
- `ROADMAP.md` — feature trajectory (connector-aligned).
|
||||
- `docs/uuid-external-id-mapping.md` — design for the mapping surface.
|
||||
- `workplans/ISSUE-WP-0004-align-with-work-record-canon.md` — this pivot.
|
||||
- `the-custodian/canon/standards/work-record-types_v0.1.md` — work-record canon.
|
||||
- `the-custodian/research/WorkOrchestrationArchitectureDraft.md` §4.2 —
|
||||
founder-reviewed connector role.
|
||||
- activity-core `docs/adr/adr-001-event-bridge-architecture.md` — IssueSink
|
||||
contract at `POST /issues/` (optional, intentional use only).
|
||||
|
|
|
|||
153
README.md
153
README.md
|
|
@ -1,20 +1,30 @@
|
|||
# Issue Core - Agent Coordination via Issue Tracking
|
||||
# Issue Core — External Tracker Connector
|
||||
|
||||
**A unified interface for autonomous coding agents to coordinate project implementation through issue tracking systems.**
|
||||
**A backend-agnostic connector to third-party issue trackers (Gitea/Forgejo, GitHub, …), not the fleet's internal work-origin or coordination substrate.**
|
||||
|
||||
## Purpose
|
||||
|
||||
The **Issue Core** provides a standardized abstraction layer for coding agents to interact with issue tracking backends (Gitea, GitHub, GitLab, local SQLite). Instead of each agent implementing platform-specific API integrations, they use one consistent interface that works across all backends.
|
||||
**issue-core** is a standardized abstraction layer for talking to external issue-tracking backends (Gitea, GitHub, GitLab, local SQLite cache). Instead of each agent or automation implementing platform-specific APIs, they use one consistent CLI and Python interface — and, going forward, a durable **work-record UUID ↔ external issue id** mapping when a tracker projection is switched on.
|
||||
|
||||
### Why Issue Tracking for Agent Coordination?
|
||||
### Fleet coordination vs external trackers
|
||||
|
||||
Issue tracking provides natural coordination primitives for multi-agent software development:
|
||||
Internal fleet work is **not** originated here. Work records (workplans, tasks, intake, decisions, …) live as **repo files** (ADR-001) and are indexed by state-hub under the work-record types canon — see `the-custodian/canon/standards/work-record-types_v0.1.md` and `the-custodian/research/WorkOrchestrationArchitectureDraft.md` §4.2.
|
||||
|
||||
- **Task Distribution**: Issues represent discrete work units agents can claim and execute
|
||||
- **Progress Tracking**: States (open → in_progress → closed) track work across the team
|
||||
- **Communication**: Comments enable agent-to-agent and agent-to-human communication
|
||||
- **Visibility**: Labels, assignees, and milestones provide real-time project status
|
||||
- **Human Integration**: Humans can seamlessly participate in agent-driven development
|
||||
issue-core's role (founder-reviewed, 2026-07-20):
|
||||
|
||||
- **Connector** to external issue-tracking systems when collaboration requires them
|
||||
- **Mapping** between internal work-record UUIDs and external issue ids (design: `docs/uuid-external-id-mapping.md`)
|
||||
- **Two-way boundary sync** when a third-party tracker is actually in use
|
||||
- **Zero load** on the internal loop until an external integration is switched on
|
||||
|
||||
External trackers remain useful for:
|
||||
|
||||
- **Human / open-source collaboration** on GitHub, Forgejo, Jira, etc.
|
||||
- **Communication** via comments when the counterparty lives in that UI
|
||||
- **Visibility** for people who only watch the tracker, not the fleet hub
|
||||
- **Optional projection** of a work record outward (not birth of the work record)
|
||||
|
||||
For agent coordination *inside* the Coulomb fleet, use work records + state-hub, not Forgejo as the default task board. See `INTENT.md` and `SCOPE.md`.
|
||||
|
||||
## Current Status
|
||||
|
||||
|
|
@ -45,10 +55,13 @@ pip install -e . # CLI only
|
|||
pip install -e ".[api]" # CLI + REST ingestion server
|
||||
```
|
||||
|
||||
### REST Ingestion Server
|
||||
### REST Server (intentional external issues)
|
||||
|
||||
issue-core exposes `POST /issues/` for upstream emitters (primarily
|
||||
activity-core's `IssueSink`). Launch with:
|
||||
issue-core exposes `POST /issues/` for **authenticated clients that deliberately
|
||||
create external tracker issues**. This is not the primary fleet path for
|
||||
originating work (work records start as repo files). activity-core's
|
||||
`IssueSink` may call this only when an external issue is intentional policy —
|
||||
not as an always-on landing zone for internal findings.
|
||||
|
||||
```bash
|
||||
export ISSUE_CORE_API_KEY="$(python -c 'import secrets; print(secrets.token_urlsafe(32))')"
|
||||
|
|
@ -109,14 +122,16 @@ issue close 42 --comment="Ready for review"
|
|||
|
||||
## Agent Integration
|
||||
|
||||
**For autonomous coding agents**, see **[AGENT_INTEGRATION.md](AGENT_INTEGRATION.md)** for:
|
||||
**Prefer work records + state-hub for fleet task lifecycle.** Use issue-core when
|
||||
an agent must operate on an **external tracker** (project a task, update a
|
||||
Forgejo/GitHub issue, sync comments at the boundary).
|
||||
|
||||
See **[AGENT_INTEGRATION.md](AGENT_INTEGRATION.md)** for:
|
||||
|
||||
- Programmatic Python API usage
|
||||
- Multi-agent coordination patterns
|
||||
- Agent workflow examples
|
||||
- Label-based role assignment
|
||||
- State machine workflows
|
||||
- Comment-based communication protocols
|
||||
- Multi-agent patterns **against tracker backends** (not as the fleet board)
|
||||
- Label-based filters and state machine workflows on external issues
|
||||
- Comment-based communication when the counterparty is in the tracker UI
|
||||
- Workarounds for current limitations
|
||||
- Performance optimization tips
|
||||
|
||||
|
|
@ -192,42 +207,31 @@ for issue in issues:
|
|||
|
||||
## Use Cases
|
||||
|
||||
### 1. Multi-Agent Project Implementation
|
||||
### 1. External tracker ops (when a backend is in use)
|
||||
|
||||
Multiple specialized agents coordinate via issues:
|
||||
Agents or humans work issues that already live in Gitea/GitHub (e.g. OSS
|
||||
inbound, customer Jira, or an intentional projection):
|
||||
|
||||
```bash
|
||||
# Agent 1 (Coder): Claims and implements features
|
||||
issue list --label=needs-implementation --format=json | \
|
||||
jq -r '.[0].number' | \
|
||||
xargs -I {} issue edit {} --assignee=agent-coder --state=in_progress
|
||||
# List open external issues for a label
|
||||
issue list --label=needs-implementation --format=json
|
||||
|
||||
# Agent 2 (Reviewer): Reviews completed work
|
||||
issue list --label=needs-review --format=json | \
|
||||
jq -r '.[0].number' | \
|
||||
xargs -I {} issue comment {} "Code review: Approved"
|
||||
|
||||
# Agent 3 (Tester): Runs tests
|
||||
issue list --label=reviewed --format=json | \
|
||||
jq -r '.[0].number' | \
|
||||
xargs -I {} issue comment {} "Tests passing: 100%"
|
||||
# Claim and update state on the tracker
|
||||
issue edit 42 --assignee=agent-coder --state=in_progress
|
||||
issue comment 42 "Implementation complete, tests passing"
|
||||
issue close 42 --comment="Ready for review"
|
||||
```
|
||||
|
||||
### 2. Agent-Human Collaboration
|
||||
Fleet-internal task claim/execute should use workplan task status in the repo
|
||||
+ state-hub, not Forgejo by default.
|
||||
|
||||
Agents propose implementations, humans approve:
|
||||
### 2. Human collaboration through a tracker UI
|
||||
|
||||
```python
|
||||
# Agent creates subtasks from human requirements
|
||||
feature = backend.get_issue_by_number(100)
|
||||
for subtask in agent.break_down_feature(feature):
|
||||
backend.create_issue(subtask)
|
||||
When the counterparty only uses GitHub/Gitea, project or update the external
|
||||
issue and keep comments there. Mapping design (UUID ↔ external id) will tie
|
||||
that projection back to the work record — see `docs/uuid-external-id-mapping.md`.
|
||||
|
||||
# Human reviews and approves via comments
|
||||
# Agent monitors and proceeds with implementation
|
||||
```
|
||||
|
||||
### 3. Offline Development with Sync
|
||||
### 3. Offline development with sync
|
||||
|
||||
Work offline with local backend, sync when online:
|
||||
|
||||
|
|
@ -238,7 +242,7 @@ issue sync pull gitea-production backup
|
|||
|
||||
# Work offline
|
||||
issue backend set-default backup
|
||||
issue create "Offline implementation" --label=offline
|
||||
issue create "Offline tracker note" --label=offline
|
||||
|
||||
# Sync back
|
||||
issue sync push backup gitea-production
|
||||
|
|
@ -329,40 +333,35 @@ issue-core/
|
|||
|
||||
## Documentation
|
||||
|
||||
- **[AGENT_INTEGRATION.md](AGENT_INTEGRATION.md)** - Comprehensive guide for autonomous agents
|
||||
- Programmatic API usage
|
||||
- Multi-agent coordination patterns
|
||||
- Workflow examples and strategies
|
||||
- Performance optimization
|
||||
- Current workarounds
|
||||
- **[INTENT.md](INTENT.md)** — why issue-core exists (connector, not landing zone)
|
||||
- **[SCOPE.md](SCOPE.md)** — in/out of scope and integration boundaries
|
||||
- **[docs/uuid-external-id-mapping.md](docs/uuid-external-id-mapping.md)** — mapping design (not implemented yet)
|
||||
- **[AGENT_INTEGRATION.md](AGENT_INTEGRATION.md)** — programmatic API for tracker backends
|
||||
- **[ROADMAP.md](ROADMAP.md)** — feature trajectory (connector-aligned)
|
||||
- Work-record canon: `the-custodian/canon/standards/work-record-types_v0.1.md`
|
||||
- Architecture §4.2: `the-custodian/research/WorkOrchestrationArchitectureDraft.md`
|
||||
|
||||
- **[CLAUDE.md](CLAUDE.md)** - Development guide for working on this codebase
|
||||
- Architecture deep-dive
|
||||
- Testing strategy
|
||||
- Adding new backends
|
||||
- Common development tasks
|
||||
## Roadmap (summary)
|
||||
|
||||
- **[ROADMAP.md](ROADMAP.md)** - Planned features and implementation timeline
|
||||
### Connector alignment (docs — ISSUE-WP-0004)
|
||||
- INTENT / SCOPE / README framing as external connector
|
||||
- UUID ↔ external-id mapping design
|
||||
|
||||
## Roadmap
|
||||
|
||||
### v1.1 - Auto-Configuration (Next)
|
||||
### v1.1 - Auto-Configuration
|
||||
- Automatic git remote detection
|
||||
- Environment-variable-only setup
|
||||
- Per-repository configuration files
|
||||
- `issue config detect` command
|
||||
|
||||
### v1.2 - Agent Features
|
||||
- Agent identity management
|
||||
- Issue claiming/locking API
|
||||
- Webhook support for reactive agents
|
||||
- Structured metadata for agent state
|
||||
### Mapping + boundary sync (stage-3 work-record architecture)
|
||||
- Persist work-record UUID ↔ backend issue id
|
||||
- Optional two-way sync when a tracker is switched on
|
||||
- No load when integrations are off
|
||||
|
||||
### v2.0 - Advanced Coordination
|
||||
- Issue dependency tracking
|
||||
- Query DSL for complex filters
|
||||
- Activity streams and event logs
|
||||
- Distributed locking for concurrent operations
|
||||
### Further backends / agent helpers
|
||||
- GitHub, GitLab, Jira backends
|
||||
- Claiming helpers for external issues
|
||||
- Webhooks for tracker-side events
|
||||
|
||||
## Comparison with Platform CLIs
|
||||
|
||||
|
|
@ -396,19 +395,15 @@ The Issue Core is designed to be extensible:
|
|||
|
||||
See existing backends (Gitea, Local) as reference implementations.
|
||||
|
||||
## Why "Facade"?
|
||||
## Why "Facade" / connector?
|
||||
|
||||
The **Facade Pattern** describes this tool's purpose:
|
||||
The **Facade Pattern** still describes the *implementation* style:
|
||||
|
||||
> *"Provide a unified interface to a set of interfaces in a subsystem."*
|
||||
> — Gang of Four, Design Patterns
|
||||
|
||||
Instead of coding agents learning different APIs for GitHub (`gh`), GitLab (`glab`), Gitea, JIRA, etc., they use one consistent interface. The facade doesn't replace issue trackers—it makes them easier to use uniformly.
|
||||
Instead of agents learning different APIs for GitHub (`gh`), GitLab (`glab`), Gitea, JIRA, etc., they use one consistent interface. The facade does not replace issue trackers — and it does **not** replace work records as the origin of fleet work. It connects the fleet to trackers at the boundary.
|
||||
|
||||
## License
|
||||
|
||||
MIT License - See LICENSE file
|
||||
|
||||
## Part of MarkiTect
|
||||
|
||||
This capability is part of the [MarkiTect Project](https://github.com/markitect), a collection of tools for agent-driven software development.
|
||||
|
|
|
|||
105
ROADMAP.md
105
ROADMAP.md
|
|
@ -1,8 +1,30 @@
|
|||
# Issue Core Roadmap
|
||||
|
||||
**Long-term vision and implementation plan for agent-driven software development coordination.**
|
||||
**Long-term vision for issue-core as an external issue-tracker connector** —
|
||||
not as the fleet's work-origin or internal coordination substrate.
|
||||
|
||||
## Current Status: v1.0 (Production-Ready Core)
|
||||
## Framing (updated 2026-07-20)
|
||||
|
||||
Fleet coordination runs on **work records** (repo files + state-hub), per:
|
||||
|
||||
- `the-custodian/canon/standards/work-record-types_v0.1.md`
|
||||
- `the-custodian/research/WorkOrchestrationArchitectureDraft.md` §4.2
|
||||
- `INTENT.md` / `SCOPE.md` / ISSUE-WP-0004
|
||||
|
||||
issue-core's trajectory is therefore:
|
||||
|
||||
1. **Keep** multi-backend CRUD, CLI, REST, and sync as a solid connector.
|
||||
2. **Add** durable **work-record UUID ↔ external issue id** mapping and
|
||||
boundary sync (design: `docs/uuid-external-id-mapping.md`).
|
||||
3. **Stop** treating "everything lands in issue-core" as the product north star.
|
||||
Agent claim/execute for *fleet* work belongs on work records; tracker
|
||||
claim/locking remains useful for *external* issues.
|
||||
|
||||
Phases below that talk about multi-agent coordination should be read as
|
||||
**coordination through an external tracker when one is in use**, not as
|
||||
replacing workplans/tasks.
|
||||
|
||||
## Current Status: v1.0 (Production-Ready Connector Core)
|
||||
|
||||
✅ **Complete:**
|
||||
- Core CRUD operations (100%)
|
||||
|
|
@ -11,19 +33,40 @@
|
|||
- CLI with JSON output
|
||||
- Python programmatic API
|
||||
- Basic synchronization
|
||||
- Comprehensive test suite (109 tests, 61% coverage)
|
||||
- REST `POST/GET/PATCH /issues/` (intentional external issues)
|
||||
- Comprehensive test suite
|
||||
|
||||
⚠️ **Limitations:**
|
||||
- Manual backend configuration
|
||||
- No auto-detection
|
||||
- Basic conflict resolution
|
||||
- Hardcoded user context
|
||||
- No work-record UUID mapping yet (design only)
|
||||
- Docs historically framed issue-core as a landing zone (corrected in ISSUE-WP-0004)
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Auto-Configuration (v1.1) - **Next Priority**
|
||||
## Phase 0: Work-record canon alignment (docs) — ISSUE-WP-0004
|
||||
|
||||
**Goal:** Enable agents to work in any repository without manual setup.
|
||||
**Goal:** Align product framing with the connector decision; design mapping.
|
||||
|
||||
| Item | Status |
|
||||
| --- | --- |
|
||||
| Rewrite INTENT.md | this workplan |
|
||||
| Rewrite SCOPE.md (mapping table concept) | this workplan |
|
||||
| README / ROADMAP framing | this workplan |
|
||||
| Design note: UUID ↔ external-id mapping | `docs/uuid-external-id-mapping.md` |
|
||||
| File activity-core IssueSink policy follow-up | cross-repo task |
|
||||
|
||||
**Implementation of the mapping store is stage-3 in the-custodian work-record
|
||||
architecture — not blocked on inventing a parallel coordination system here.**
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Auto-Configuration (v1.1) - **Next engineering priority**
|
||||
|
||||
**Goal:** Enable agents and operators to attach issue-core to any repo's
|
||||
external tracker without painful manual setup.
|
||||
|
||||
### 1.1.1 Git Remote Detection
|
||||
|
||||
|
|
@ -245,9 +288,26 @@ fi
|
|||
|
||||
---
|
||||
|
||||
## Phase 2: Agent Features (v1.2)
|
||||
## Phase 1.5: UUID ↔ external-id mapping (stage-3 work-record arch)
|
||||
|
||||
**Goal:** Native support for multi-agent coordination.
|
||||
**Goal:** Persist and query the association between internal work-record
|
||||
UUIDs and backend issue ids so projections are first-class.
|
||||
|
||||
See **`docs/uuid-external-id-mapping.md`** for the design (no code in
|
||||
ISSUE-WP-0004). Expected deliverables when scheduled:
|
||||
|
||||
- Mapping table / store (local SQLite + optional remote annotation)
|
||||
- API/CLI: project work record → create or link external issue; resolve either way
|
||||
- Optional fields on `TaskSpec` / project request for `work_record_uuid`
|
||||
- Two-way status/comment sync *at the boundary* only when enabled
|
||||
- Idle cost zero when no mapping/integration is configured
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Agent Features for external trackers (v1.2)
|
||||
|
||||
**Goal:** Native helpers when agents operate **on external issues** (not a
|
||||
replacement for work-record execution).
|
||||
|
||||
### 1.2.1 Agent Identity Management
|
||||
|
||||
|
|
@ -473,9 +533,12 @@ issue webhook remove <id>
|
|||
|
||||
---
|
||||
|
||||
## Phase 3: Advanced Coordination (v2.0)
|
||||
## Phase 3: Advanced tracker features (v2.0)
|
||||
|
||||
**Goal:** Enterprise-grade multi-agent system coordination.
|
||||
**Goal:** Richer connector behavior for large external-tracker deployments
|
||||
(dependencies between *external* issues, query DSL, webhooks already partly
|
||||
in Phase 2). Fleet dependency graphs for work records remain out of scope
|
||||
here (workplan tooling / hub).
|
||||
|
||||
### 2.0.1 Issue Dependency Tracking
|
||||
|
||||
|
|
@ -718,20 +781,30 @@ def sync_with_strategy(
|
|||
|
||||
## Success Metrics
|
||||
|
||||
### Phase 0 Success (canon alignment)
|
||||
- [x] INTENT/SCOPE/README describe connector, not landing zone
|
||||
- [x] Mapping surface designed (`docs/uuid-external-id-mapping.md`)
|
||||
- [ ] activity-core IssueSink default no longer dumps internal findings to Forgejo
|
||||
|
||||
### Phase 1 Success
|
||||
- [ ] Agent can work in any repo with zero manual config
|
||||
- [ ] Agent can attach to any repo's tracker with zero manual config
|
||||
- [ ] Environment-only setup works: `GITEA_TOKEN=xxx issue list`
|
||||
- [ ] Auto-detection accuracy: >95% for common platforms
|
||||
|
||||
### Phase 1.5 Success (mapping)
|
||||
- [ ] Project work-record UUID → external issue id is durable and queryable
|
||||
- [ ] Reverse lookup (external issue → UUID) works for linked issues
|
||||
- [ ] No mapping configured ⇒ no extra load / no accidental Forgejo spam
|
||||
|
||||
### Phase 2 Success
|
||||
- [ ] Multiple agents can coordinate without race conditions
|
||||
- [ ] Agent identity propagates to all operations
|
||||
- [ ] Claim/lock prevents concurrent work on same issue
|
||||
- [ ] Multiple agents can operate on external issues without race conditions
|
||||
- [ ] Agent identity propagates to tracker operations
|
||||
- [ ] Claim/lock prevents concurrent work on the same external issue
|
||||
|
||||
### Phase 3 Success
|
||||
- [ ] Complex dependency chains work correctly
|
||||
- [ ] Query DSL covers 90% of common queries
|
||||
- [ ] Real-time event processing with <1s latency
|
||||
- [ ] External-issue dependency helpers work where backends support them
|
||||
- [ ] Query DSL covers 90% of common tracker queries
|
||||
- [ ] Real-time tracker event processing with <1s latency when webhooks enabled
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
154
SCOPE.md
154
SCOPE.md
|
|
@ -3,12 +3,18 @@
|
|||
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
|
||||
|
||||
### Task CRUD across backends
|
||||
### External-issue CRUD across backends
|
||||
|
||||
- **Create** issues with title, description, labels, priority, type, milestone,
|
||||
assignee, due date.
|
||||
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.
|
||||
|
|
@ -25,8 +31,8 @@ which explains *why*; this file states *what* and *what not*.
|
|||
|
||||
### Backends shipped today
|
||||
|
||||
- **Local SQLite** — offline source of truth.
|
||||
- **Gitea** — REST API integration.
|
||||
- **Local SQLite** — offline cache / source of truth for disconnected work.
|
||||
- **Gitea** — REST API integration (Forgejo-compatible in deployment).
|
||||
|
||||
### Backends planned
|
||||
|
||||
|
|
@ -34,15 +40,34 @@ which explains *why*; this file states *what* and *what not*.
|
|||
- **GitLab** — Issues.
|
||||
- **JIRA** — issues with story-points.
|
||||
|
||||
### Ingestion surfaces
|
||||
### UUID ↔ external-id mapping (target shape)
|
||||
|
||||
- **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.
|
||||
- **REST worker surface** (`GET/PATCH /issues/`) for executors (agent-harness):
|
||||
list open issues by label/state, claim (`in_progress` + assignee), close.
|
||||
- **NATS subscriber** (design stub only — implementation deferred until
|
||||
activity-core migrates from REST to NATS, see `docs/nats-task-ingestion.md`).
|
||||
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
|
||||
|
||||
|
|
@ -53,29 +78,47 @@ which explains *why*; this file states *what* and *what not*.
|
|||
|
||||
### 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.
|
||||
- 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 `project-core` (planned).**
|
||||
issue-core operates on individual tasks. A milestone field exists for
|
||||
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 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.
|
||||
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 status updates back to activity-core.
|
||||
Lifecycle updates stay here; activity-core does not care what happens to a task
|
||||
it spawned.
|
||||
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
|
||||
|
||||
|
|
@ -86,8 +129,7 @@ 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.
|
||||
chatbot, or notification service — not issue-core.
|
||||
|
||||
### Workflow / approval engine
|
||||
|
||||
|
|
@ -104,28 +146,40 @@ 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
|
||||
on a service-level API key for the REST endpoint. issue-core is not a
|
||||
user directory.
|
||||
|
||||
## Integration boundaries
|
||||
|
||||
### Upstream emitters
|
||||
### Fleet primary path (work records)
|
||||
|
||||
| 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. |
|
||||
| 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 / 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. |
|
||||
| --- | --- | --- |
|
||||
| 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 (from activity-core's IssueSink)
|
||||
### `TaskSpec` payload (activity-core IssueSink — retained contract)
|
||||
|
||||
Still accepted for backward compatibility and intentional emits:
|
||||
|
||||
```json
|
||||
{
|
||||
|
|
@ -148,6 +202,12 @@ 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
|
||||
|
|
@ -158,15 +218,17 @@ metadata for traceability.
|
|||
}
|
||||
```
|
||||
|
||||
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.
|
||||
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 how it fits in the Coulomb org.
|
||||
- `INTENT.md` — why issue-core exists and the connector pivot.
|
||||
- `ROADMAP.md` — feature trajectory.
|
||||
- `workplans/ISSC-WP-0001-rename-and-task-ingestion.md` — current rename +
|
||||
ingestion workplan.
|
||||
- activity-core `docs/adr/adr-001-event-bridge-architecture.md` — the upstream
|
||||
side of the IssueSink contract.
|
||||
- `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).
|
||||
|
|
|
|||
33
WORK-RECORDS.md
Normal file
33
WORK-RECORDS.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
# Work Records — issue-core
|
||||
|
||||
> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record
|
||||
> stage 3). Do not edit by hand — edit the source file/block listed for
|
||||
> each record and re-run fix-consistency to refresh this index. Archived
|
||||
> workplans are omitted; closed decisions/intakes/engagements stay listed
|
||||
> so recently-resolved work is still visible. [auto]
|
||||
|
||||
| Kind | ID | Status | Lane | Source |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| workplan | ISSC-WP-0001 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| workplan | ISSUE-WP-0002 | finished | — | workplans/ISSUE-WP-0002-gitea-pypi-publication.md |
|
||||
| workplan | ISSUE-WP-0003 | finished | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| workplan | ISSUE-WP-0004 | finished | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
| task | T01 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | T02 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | T03 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | T04 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | T05 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | T06 | done | — | workplans/ISSC-WP-0001-rename-and-task-ingestion.md |
|
||||
| task | ISSUE-WP-0002-T01 | done | — | workplans/ISSUE-WP-0002-gitea-pypi-publication.md |
|
||||
| task | ISSUE-WP-0003-T01 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T02 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T03 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T04 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T05 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T06 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0003-T07 | done | — | workplans/ISSUE-WP-0003-railiance01-deployment.md |
|
||||
| task | ISSUE-WP-0004-T01 | done | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
| task | ISSUE-WP-0004-T02 | done | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
| task | ISSUE-WP-0004-T03 | done | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
| task | ISSUE-WP-0004-T04 | done | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
| task | ISSUE-WP-0004-T05 | done | — | workplans/ISSUE-WP-0004-align-with-work-record-canon.md |
|
||||
287
docs/uuid-external-id-mapping.md
Normal file
287
docs/uuid-external-id-mapping.md
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
# Design: UUID ↔ external-id mapping
|
||||
|
||||
**Status:** design only (ISSUE-WP-0004-T04)
|
||||
**Date:** 2026-07-21
|
||||
**Implementation:** deferred to stage-3 work-record architecture in
|
||||
the-custodian (not this workplan).
|
||||
**Normative product role:** `INTENT.md`, `SCOPE.md`; founder decision
|
||||
`the-custodian/research/WorkOrchestrationArchitectureDraft.md` §4.2;
|
||||
kinds in `the-custodian/canon/standards/work-record-types_v0.1.md`
|
||||
(task kind: *issue-core issues become external projections only*).
|
||||
|
||||
## Problem
|
||||
|
||||
When collaboration requires a third-party tracker (Forgejo/Gitea, GitHub,
|
||||
Jira, …), the fleet still needs a stable link between:
|
||||
|
||||
| Side | Identity today | Owner |
|
||||
| --- | --- | --- |
|
||||
| Internal work record | UUIDv7 written back as `state_hub_*_id` (workplan/task/intake/…) | repo file + state-hub |
|
||||
| External issue | Backend issue id / number (+ URL) | Gitea, GitHub, … via issue-core |
|
||||
|
||||
Without an explicit mapping:
|
||||
|
||||
1. Projections are fire-and-forget — no reverse lookup from issue → work record.
|
||||
2. Emitters invent ad hoc back-references (`task_spawn_log.external_id`,
|
||||
labels, description footers).
|
||||
3. `TaskSpec.triggering_event_id` is overloaded as "some upstream id" and
|
||||
cannot represent work-record identity cleanly.
|
||||
4. Two-way sync at the boundary has nothing durable to key on.
|
||||
|
||||
## Goals
|
||||
|
||||
1. **One mapping row per projection:** work-record UUID ↔ (backend, external id).
|
||||
2. **Mirror the hub write-back pattern:** optional field on the work-record
|
||||
source (or generated index) pointing at the external projection, similar
|
||||
to `state_hub_task_id`.
|
||||
3. **Extend, do not overload, `triggering_event_id`.**
|
||||
4. **Zero load** when no external integration / mapping is configured.
|
||||
5. **Idempotent project:** re-projecting the same UUID does not create
|
||||
duplicate issues.
|
||||
|
||||
## Non-goals (this design)
|
||||
|
||||
- Replacing work records as origin of work.
|
||||
- Making Forgejo the fleet task board.
|
||||
- Implementing the store, CLI, or API in ISSUE-WP-0004.
|
||||
- Full CRDT merge of comments/body (v1 can be status + simple comment
|
||||
push/pull; advanced merge is later).
|
||||
|
||||
## Current traceability (as-is)
|
||||
|
||||
### Ingestion metadata
|
||||
|
||||
`POST /issues/` stores emitter fields under `Issue.sync_metadata.ingestion`:
|
||||
|
||||
```text
|
||||
triggering_event_id # activity event UUID or stable key e.g. "scheduled"
|
||||
source_type # rule | instruction
|
||||
source_id
|
||||
activity_definition_id
|
||||
target_repo
|
||||
```
|
||||
|
||||
See `issue_core/api/ingest.py` and `issue_core/api/schemas.py`.
|
||||
|
||||
### What `triggering_event_id` is
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Purpose | Emitter-side traceability / idempotency key for **activity** spawns |
|
||||
| Type | non-empty string (UUID or stable key) |
|
||||
| Scope | Links to activity-core event or schedule, **not** to a work-record UUID |
|
||||
| Stored on | `sync_metadata.ingestion` of the created issue |
|
||||
|
||||
### What it is not
|
||||
|
||||
- Not a work-record UUID
|
||||
- Not a substitute for `state_hub_task_id` / intake UUID
|
||||
- Not sufficient for "this Forgejo issue projects task X"
|
||||
|
||||
**Decision:** keep `triggering_event_id` for activity-core emit lineage.
|
||||
Add a **separate** identity channel for work records (`work_record_uuid`
|
||||
and durable mapping rows). Do not overload the existing field.
|
||||
|
||||
## Target shape
|
||||
|
||||
### Mapping record
|
||||
|
||||
Conceptual schema (storage TBD — local SQLite table is the natural first
|
||||
home; remote backends may only get labels/footers):
|
||||
|
||||
```yaml
|
||||
mapping:
|
||||
id: <mapping-uuid> # optional row id
|
||||
work_record_uuid: <uuidv7> # primary internal key
|
||||
work_record_id: "ISSUE-WP-0004-T01" # canonical name, optional denorm
|
||||
work_record_kind: task # task | intake | workplan | …
|
||||
backend: gitea # gitea | github | gitlab | jira | sqlite
|
||||
external_id: "176" # backend-native issue id/number
|
||||
external_url: "https://…/issues/176"
|
||||
target_repo: "coulomb/example" # optional routing hint
|
||||
direction: outward # outward | linked (pre-existing issue)
|
||||
status: active # active | detached | superseded
|
||||
created_at: …
|
||||
updated_at: …
|
||||
# optional sync cursors
|
||||
last_pushed_at: …
|
||||
last_pulled_at: …
|
||||
```
|
||||
|
||||
Uniqueness:
|
||||
|
||||
- Unique on `(backend, external_id)` while `status=active`
|
||||
- Unique on `(work_record_uuid, backend)` while `status=active`
|
||||
(one active projection per tracker per work record; multi-tracker later
|
||||
can relax to one per backend type)
|
||||
|
||||
### Work-record side back-reference (optional denorm)
|
||||
|
||||
Mirror hub write-back style so humans/agents see the link without querying
|
||||
issue-core only:
|
||||
|
||||
```yaml
|
||||
# on a task / intake YAML block (illustrative — exact key names TBD with canon)
|
||||
external_tracker:
|
||||
backend: gitea
|
||||
issue_id: "176"
|
||||
issue_url: "https://…"
|
||||
mapped_by: issue-core
|
||||
```
|
||||
|
||||
Alternatively a single string field if canon prefers flat keys:
|
||||
|
||||
```text
|
||||
issue_core_external_ref: "gitea:coulomb/example#176"
|
||||
```
|
||||
|
||||
Canon PR owns the field name; issue-core owns the mapping authority.
|
||||
|
||||
### issue-core side storage
|
||||
|
||||
Recommended v1:
|
||||
|
||||
1. **Local SQLite** table `work_record_issue_map` (even when primary CRUD
|
||||
backend is Gitea) — mapping is fleet bookkeeping, not a Gitea concept.
|
||||
2. **Issue.sync_metadata.mapping** (or top-level) echo for convenience when
|
||||
the issue is loaded:
|
||||
```json
|
||||
{
|
||||
"mapping": {
|
||||
"work_record_uuid": "…",
|
||||
"work_record_id": "…",
|
||||
"work_record_kind": "task"
|
||||
}
|
||||
}
|
||||
```
|
||||
3. Optional Gitea label / body footer for human visibility in the tracker UI
|
||||
(non-authoritative).
|
||||
|
||||
### API / CLI (sketch only)
|
||||
|
||||
```text
|
||||
# Project an existing work record outward
|
||||
issue project <work_record_uuid> [--backend gitea] [--title …]
|
||||
|
||||
# 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
|
||||
pushed as Gitea native objects).
|
||||
|
||||
## Implementation sketch (later workplan)
|
||||
|
||||
1. Schema: `work_record_issue_map` in local backend (+ migration path).
|
||||
2. Domain service: `MappingService` independent of HTTP.
|
||||
3. Wire `project` / `map` CLI + REST.
|
||||
4. Extend `TaskIngestionRequest` with optional work-record fields; tests for
|
||||
idempotent mapping.
|
||||
5. Canon PR for optional back-reference field on work-record YAML.
|
||||
6. activity-core: only emit with UUID when intentional; default sink policy
|
||||
already fixed by its follow-up.
|
||||
|
||||
## Open questions (for implementers)
|
||||
|
||||
1. Exact work-record back-reference key names (canon vs issue-core-owned).
|
||||
2. Whether mapping table is *only* SQLite or also dual-written to state-hub.
|
||||
3. Inward sync writer: who may edit work-record files (agent harness vs
|
||||
fix-consistency-only).
|
||||
4. Whether `kind: intake` projections are allowed before promotion, or only
|
||||
after `intake → task|workplan`.
|
||||
|
||||
## See also
|
||||
|
||||
- `INTENT.md` — connector role
|
||||
- `SCOPE.md` — mapping in scope as target shape
|
||||
- `issue_core/api/schemas.py` — current TaskSpec fields
|
||||
- `issue_core/api/ingest.py` — current ingestion metadata storage
|
||||
- ISSUE-WP-0004 — alignment workplan
|
||||
- activity-core IssueSink follow-up (filed from ISSUE-WP-0004-T05)
|
||||
|
|
@ -2,8 +2,8 @@ schema_version: open-reuse.integration.v0.1
|
|||
id: issue-core-gitea
|
||||
name: issue-core Gitea Backend
|
||||
description: >
|
||||
Pluggable remote backend that maps the issue-core unified task model onto the
|
||||
Gitea issues API for cross-repo task landing and synchronization.
|
||||
Pluggable remote backend that maps the issue-core unified issue model onto the
|
||||
Gitea issues API for external-tracker projection and synchronization.
|
||||
status: registered
|
||||
owner: issue-core
|
||||
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ type: workplan
|
|||
title: "Align issue-core with the work-record canon (connector, not landing zone)"
|
||||
domain: infotech
|
||||
repo: issue-core
|
||||
status: ready
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: infotech
|
||||
created: "2026-07-20"
|
||||
updated: "2026-07-20"
|
||||
updated: "2026-07-21"
|
||||
state_hub_workstream_id: "ee47385f-aadb-4dba-b39f-148ac1444c3d"
|
||||
---
|
||||
|
||||
|
|
@ -64,11 +64,14 @@ external-tracker projection when one is in use.* Green lane (docs only).
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0004-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "ae1e2a1e-8127-46bb-b7d7-be5c647f61ef"
|
||||
```
|
||||
|
||||
**Done 2026-07-21:** `INTENT.md` rewritten with connector framing, dated
|
||||
pivot, and expanded "What it is NOT".
|
||||
|
||||
## Task: Rewrite SCOPE.md — mapping table, not ingestion primary path
|
||||
|
||||
Current SCOPE.md lists activity-core's `POST /issues/` `TaskSpec` path as
|
||||
|
|
@ -82,11 +85,14 @@ implemented — name the target shape before building it. Green lane.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0004-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "cd0422f6-6921-4ac6-a484-19b6777d99bc"
|
||||
```
|
||||
|
||||
**Done 2026-07-21:** `SCOPE.md` reframed; mapping table concept named;
|
||||
TaskSpec retained as optional intentional path.
|
||||
|
||||
## Task: Audit and update README / ROADMAP for the same framing
|
||||
|
||||
`README.md`'s "Why Issue Tracking for Agent Coordination?" section and
|
||||
|
|
@ -98,11 +104,14 @@ and the architecture draft. Green lane.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0004-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "746d090d-ebed-4328-bcd8-d531706ae795"
|
||||
```
|
||||
|
||||
**Done 2026-07-21:** README + ROADMAP updated; Phase 0 + Phase 1.5 mapping
|
||||
called out.
|
||||
|
||||
## Task: Design the UUID ↔ external-id mapping surface (design only)
|
||||
|
||||
Specify (not implement) how issue-core will record the internal work-record
|
||||
|
|
@ -118,11 +127,14 @@ Green lane.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0004-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "61ba9b84-a2cc-4b20-b8d3-9fc8487f7acf"
|
||||
```
|
||||
|
||||
**Done 2026-07-21:** `docs/uuid-external-id-mapping.md` — extend
|
||||
`triggering_event_id`, add `work_record_uuid` + mapping rows; no code.
|
||||
|
||||
## Task: Fix activity-core's IssueSink call site to match
|
||||
|
||||
`activity-core`'s `issue_sink.py` (`IssueCoreRestSink`) currently treats
|
||||
|
|
@ -136,7 +148,13 @@ implement the activity-core change itself. Green lane.
|
|||
|
||||
```task
|
||||
id: ISSUE-WP-0004-T05
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "944e0510-42c3-48f3-a7d2-86853468f816"
|
||||
```
|
||||
|
||||
**Done 2026-07-21:** Filed
|
||||
`activity-core/workplans/ACTIVITY-WP-0022-issuesink-no-default-forgejo.md`
|
||||
(`status: proposed`) with tasks for default sink policy, implementation,
|
||||
definition reroute, and deploy docs. Cross-links ISSUE-WP-0004 and
|
||||
CUST-WP-0060 item 6. Implementation remains in activity-core.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue