diff --git a/AGENT_INTEGRATION.md b/AGENT_INTEGRATION.md index 3839ffd..7313553 100644 --- a/AGENT_INTEGRATION.md +++ b/AGENT_INTEGRATION.md @@ -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? diff --git a/INTENT.md b/INTENT.md index c2a7eb3..9afd85a 100644 --- a/INTENT.md +++ b/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,56 +109,72 @@ 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 | | | | | -+------------+ +-------+--------+ +-----------------+ - | - +---------+----------+ - | Backend router | - +---+------+------+--+ - | | | - v v v - +------+ +-----+ +------+ - |Gitea | |SQLite| |GitHub| - +------+ +-----+ +------+ + 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 | + +---+------+------+--+ + | | | + 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). diff --git a/README.md b/README.md index e3a9a58..7d64c83 100644 --- a/README.md +++ b/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. diff --git a/ROADMAP.md b/ROADMAP.md index 46d8c5a..23635b6 100644 --- a/ROADMAP.md +++ b/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 --- -## 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 --- diff --git a/SCOPE.md b/SCOPE.md index b6efa26..6f4938d 100644 --- a/SCOPE.md +++ b/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. | +| 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 (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). diff --git a/WORK-RECORDS.md b/WORK-RECORDS.md new file mode 100644 index 0000000..8925230 --- /dev/null +++ b/WORK-RECORDS.md @@ -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 | diff --git a/docs/uuid-external-id-mapping.md b/docs/uuid-external-id-mapping.md new file mode 100644 index 0000000..8bc525d --- /dev/null +++ b/docs/uuid-external-id-mapping.md @@ -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: # optional row id + work_record_uuid: # 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 [--backend gitea] [--title …] + +# Link an existing external issue to a work record (no create) +issue map link + +# Resolve +issue map show --uuid +issue map show --external [--backend gitea] + +# Detach +issue map detach +``` + +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) diff --git a/integration/gitea-backend.integration.yaml b/integration/gitea-backend.integration.yaml index b26b6cb..991795c 100644 --- a/integration/gitea-backend.integration.yaml +++ b/integration/gitea-backend.integration.yaml @@ -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 diff --git a/workplans/ISSUE-WP-0004-align-with-work-record-canon.md b/workplans/ISSUE-WP-0004-align-with-work-record-canon.md index a8ce802..f087d58 100644 --- a/workplans/ISSUE-WP-0004-align-with-work-record-canon.md +++ b/workplans/ISSUE-WP-0004-align-with-work-record-canon.md @@ -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.