fix cross-repo path deps; remove el compiler from neuron-lang/
- neuron-runtime, neuron-store, neuron-migrate: fix path deps (products/engram/ → foundation/engram/engrams/, products/el/ → foundation/el/engrams/) - neuron-rs workspace: fix axon-events/axon-protocol paths (../../../platform/ → ../../platform/, paths were off by one level) - neuron-lang/compiler/ removed (el self-hosting compiler now lives in foundation/el/el-compiler/)
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
// backlog.el — Work item management subsystem.
|
||||
//
|
||||
// The backlog is Neuron's task queue and project roadmap in one. Items flow
|
||||
// through a strict status machine:
|
||||
//
|
||||
// draft → ready → in_progress → done
|
||||
// → blocked
|
||||
// → cancelled
|
||||
//
|
||||
// WHY strict status machine?
|
||||
// Without guardrails, backlogs become unactionable lists of wishes.
|
||||
// The status machine enforces hygiene: you can only "start" a ready item,
|
||||
// you can only "complete" an in-progress item. This keeps the backlog
|
||||
// trustworthy as a source of truth.
|
||||
//
|
||||
// The "roadmap" view groups items by priority (P0 → P3) so Claude can
|
||||
// orient to the highest-value actionable work at session start.
|
||||
|
||||
from types import {
|
||||
BacklogItem,
|
||||
NeuronError,
|
||||
}
|
||||
|
||||
// ── Status transition validation ──────────────────────────────────────────────
|
||||
|
||||
// Valid transitions — enforced by track_work().
|
||||
// Any other transition is a NeuronError::InvalidInput.
|
||||
//
|
||||
// start : ready → in_progress
|
||||
// complete: in_progress → done
|
||||
// block : in_progress → blocked
|
||||
// unblock : blocked → ready
|
||||
// cancel : * → cancelled (any status can be cancelled)
|
||||
// ready : draft → ready (promote from draft)
|
||||
|
||||
@accessor
|
||||
fn valid_transition(current_status: String, action: String) -> Result<String, NeuronError> {
|
||||
if action == "start" {
|
||||
if current_status == "ready" {
|
||||
return Ok("in_progress")
|
||||
}
|
||||
return Err(NeuronError::InvalidInput("can only start a ready item"))
|
||||
}
|
||||
if action == "complete" {
|
||||
if current_status == "in_progress" {
|
||||
return Ok("done")
|
||||
}
|
||||
return Err(NeuronError::InvalidInput("can only complete an in_progress item"))
|
||||
}
|
||||
if action == "block" {
|
||||
if current_status == "in_progress" {
|
||||
return Ok("blocked")
|
||||
}
|
||||
return Err(NeuronError::InvalidInput("can only block an in_progress item"))
|
||||
}
|
||||
if action == "unblock" {
|
||||
if current_status == "blocked" {
|
||||
return Ok("ready")
|
||||
}
|
||||
return Err(NeuronError::InvalidInput("can only unblock a blocked item"))
|
||||
}
|
||||
if action == "ready" {
|
||||
if current_status == "draft" {
|
||||
return Ok("ready")
|
||||
}
|
||||
return Err(NeuronError::InvalidInput("can only promote a draft to ready"))
|
||||
}
|
||||
if action == "cancel" {
|
||||
// Any status can be cancelled.
|
||||
return Ok("cancelled")
|
||||
}
|
||||
Err(NeuronError::InvalidInput("unknown action"))
|
||||
}
|
||||
|
||||
// ── Public API ────────────────────────────────────────────────────────────────
|
||||
|
||||
// plan_work — create a new backlog item.
|
||||
//
|
||||
// New items start in "draft" status. Use track_work(action="ready") to
|
||||
// promote them to the actionable queue. This two-step prevents half-baked
|
||||
// ideas from polluting the ready queue.
|
||||
@manager
|
||||
fn plan_work(
|
||||
title: String,
|
||||
description: String,
|
||||
item_type: String,
|
||||
priority: String,
|
||||
project: String,
|
||||
tags: [String],
|
||||
depends_on: [String],
|
||||
) -> Result<BacklogItem, NeuronError> {
|
||||
let id = native_uuid()
|
||||
let now = native_now()
|
||||
let item = BacklogItem {
|
||||
id: id,
|
||||
title: title,
|
||||
description: description,
|
||||
item_type: item_type,
|
||||
priority: priority,
|
||||
status: "draft",
|
||||
project: project,
|
||||
tags: tags,
|
||||
depends_on: depends_on,
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}
|
||||
native_store_backlog_item(item)?
|
||||
native_emit("backlog.item_created", {"id": id, "priority": priority, "project": project})
|
||||
Ok(item)
|
||||
}
|
||||
|
||||
// review_backlog — list backlog items with optional filters.
|
||||
//
|
||||
// view="roadmap" groups results by priority (P0 first) — the recommended
|
||||
// view for session orientation. Without a view, returns a flat list.
|
||||
@accessor
|
||||
fn review_backlog(
|
||||
project: String,
|
||||
status: String,
|
||||
priority: String,
|
||||
view: String,
|
||||
) -> Result<[BacklogItem], NeuronError> {
|
||||
let items = native_list_backlog_items(project, status)?
|
||||
// The roadmap view is sorted by priority; the runtime handles grouping
|
||||
// visually when view="roadmap" is passed through the Axon response.
|
||||
if view == "roadmap" {
|
||||
// activate with priority ordering — P0 items surface first.
|
||||
let ordered = activate BacklogItem where "project:{project} status:{status} priority:{priority} order:priority"
|
||||
return Ok(ordered)
|
||||
}
|
||||
Ok(items)
|
||||
}
|
||||
|
||||
// get_backlog_item — retrieve one backlog item by ID.
|
||||
@accessor
|
||||
fn get_backlog_item(id: String) -> Result<BacklogItem, NeuronError> {
|
||||
let item = native_get_backlog_item(id)?
|
||||
Ok(item)
|
||||
}
|
||||
|
||||
// track_work — transition a backlog item's status.
|
||||
//
|
||||
// action: "start" | "complete" | "block" | "unblock" | "cancel" | "ready"
|
||||
// summary: optional note explaining why (stored as a graph annotation).
|
||||
@manager
|
||||
fn track_work(
|
||||
item_id: String,
|
||||
action: String,
|
||||
summary: String,
|
||||
) -> Result<BacklogItem, NeuronError> {
|
||||
let item = native_get_backlog_item(item_id)?
|
||||
let new_status = valid_transition(item.status, action)?
|
||||
let now = native_now()
|
||||
let updated = BacklogItem {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
description: item.description,
|
||||
item_type: item.item_type,
|
||||
priority: item.priority,
|
||||
status: new_status,
|
||||
project: item.project,
|
||||
tags: item.tags,
|
||||
depends_on: item.depends_on,
|
||||
created_at: item.created_at,
|
||||
updated_at: now,
|
||||
}
|
||||
native_update_backlog_item(updated)?
|
||||
native_emit("backlog.item_transitioned", {
|
||||
"id": item_id,
|
||||
"action": action,
|
||||
"new_status": new_status,
|
||||
"summary": summary,
|
||||
})
|
||||
Ok(updated)
|
||||
}
|
||||
Reference in New Issue
Block a user