issue
Source: crates/lvcs-doc/src/kinds/issue/mod.rs.
/// An issue's id: the `HASH` of the canonical CBOR array `[ISSUE_DOMAIN,
/// creator key, n]` (the key as a byte string, `n` an integer), `n` being
/// the creator key's own count of the issues it created, from 1. Written
/// in `ID_ENCODING`; shown as `<alias>/<n>` (decision 304).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub struct IssueId(#[serde(with = "crate::cbor::fixed")] pub [u8; 32]);
/// How an `/assign` record changes who holds an issue or a task.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AssignOp {
/// `by` takes it for itself (`--add-assignee @me`): at once when it has
/// no assignee, else unless an assignee holds the claim within its
/// window.
Take,
/// `who` is added at once: open for `who` = `by`, else the assign grant.
Assign,
/// `who` is removed at once: open for `who` = `by`, else the assign
/// grant.
Unassign,
}
/// One `/assign` record (decision 304). Read in `(time_ms, by)` order.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AssignRecord {
pub by: ParticipantKey,
pub who: ParticipantKey,
pub op: AssignOp,
/// The plan task's id, or `None` for the issue itself.
pub task: Option<String>,
pub time_ms: i64,
/// The claimer's wait window, so every peer judges a hold alike.
pub window_ms: u64,
/// A `take` of a held issue or task: the thread address and message id
/// of the ask it sent its holders, which they answer.
pub ask: Option<(String, String)>,
}
/// One `/holds` record: an assignee keeps the issue or task a claim asked
/// for (decision 304).
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct HoldRecord {
pub by: ParticipantKey,
/// The held claim's id ([`AssignRecord::id`]), in `ID_ENCODING`.
pub claim: String,
pub time_ms: i64,
pub reason: String,
}
/// One `/links` record: a range linked by hand, at the file's heads then.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct LinkRecord {
pub by: ParticipantKey,
/// The plan task this links, by id, or `None` for the issue (decision
/// 313: a task's latest link is its code range).
pub task: Option<String>,
pub address: String,
/// The lines, as `LineName` writes them (`L3-L9`).
pub lines: String,
#[serde(with = "crate::cbor::heads")]
pub heads: Vec<ChangeHash>,
pub time_ms: i64,
}
/// One `/progress` record (decision 313): a structured checkpoint of the
/// work, at the frontier main's mirror showed when it was written.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CheckpointRecord {
pub by: ParticipantKey,
/// The frontier's id, in `ID_ENCODING`.
pub frontier: String,
pub done: Vec<String>,
pub next: Vec<String>,
pub blockers: Vec<String>,
pub open_questions: Vec<String>,
pub time_ms: i64,
}
/// Why an issue was closed by hand.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CloseReason {
Wontfix,
Duplicate,
}
/// One `/closes` record: a hand close or reopen, the latest by
/// `(time_ms, by)` deciding.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CloseRecord {
pub by: ParticipantKey,
/// `None` reopens.
pub reason: Option<CloseReason>,
pub time_ms: i64,
}
/// One operation of an [`IssueWrite`].
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum IssueOp {
/// Create the issue: the first operation of its first write, alone in
/// it. `/meta` gets `creator` (the change's signer), `n`, `created_ms`
/// (the origin's time), `title`, `body`, and `thread`, and `/labels`
/// the labels.
Create {
n: u64,
title: String,
body: String,
labels: BTreeSet<String>,
/// The issue's thread's address.
thread: String,
},
Title(String),
Body(String),
/// Add (`on`) or remove a label.
Label {
name: String,
on: bool,
},
Assign(AssignRecord),
Hold(HoldRecord),
/// Append a plan task, unchecked; its id is the `HASH` of `(by, time_ms,
/// text)` in `ID_ENCODING`.
AddTask {
text: String,
},
/// Check or uncheck the task with this id.
Done {
task: String,
done: bool,
},
Link(LinkRecord),
/// `by`'s latest heads of a document it changed while the issue was
/// its current issue: `/work/<by>:<address>`.
Work {
address: String,
#[serde(with = "crate::cbor::heads")]
heads: Vec<ChangeHash>,
},
/// A workspace bound to the issue (`lvcs issue develop`):
/// `/workspaces/<by>:<workspace id>` = its name.
Workspace {
id: String,
name: String,
},
Close(CloseRecord),
Checkpoint(CheckpointRecord),
}
/// Write `ops` to an issue as one change by `origin.author` at
/// `origin.time_ms / 1000` seconds (decision 304). A write holding
/// `Create` applies only to an issue not yet created, any other only to a
/// created one; the document ignores the rest.
///
/// Layout: genesis puts `/meta`, `/labels`, `/work`, and `/workspaces` as
/// maps and `/assign`, `/holds`, `/plan`, `/links`, `/closes`, and
/// `/progress` as lists.
/// A record is a map appended to its list: keys as the record's fields,
/// keys and ids in `ID_ENCODING`, heads a list of lowercase hex hashes,
/// enums in snake case, and `time_ms`, `window_ms`, and `n` integers. A
/// plan task is `{ id, by, text, time_ms, done }`, `done` a boolean.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct IssueWrite {
pub origin: Origin,
pub ops: Vec<IssueOp>,
}