Skip to content

g1t/services/work/src/rows.rs

373 lines12,496 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Work service in Rust, with RFC 3339 timestamps1//! Rows as they come out of D1, and their conversion to contract types.
2
3use g1t_contracts::User;
4use g1t_contracts::repos::RepoPath;
5use g1t_contracts::work::{
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar6 CheckStatus, Comment, CommentKind, Issue, IssueReason, MilestoneRef, Pull, PullStatus, Runtime, SessionEntry,
Acceptance checks in sandboxes, line comments and review verdicts7 SessionEntryKind, State, Verdict,
Work service in Rust, with RFC 3339 timestamps8};
9use serde::Deserialize;
10
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily11/// An author or actor as stored: g1t itself when the id is its own (a
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights12/// security update it opened, a merge its settings made), g1t's agent by
13/// its id (what it made or filed), a person otherwise.
Agents as a team: lifecycle, merge queue, billing and a new shell14pub(crate) fn user(id: String, username: String) -> User {
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily15 let kind = if g1t_contracts::system::is_system_id(&id) {
16 g1t_contracts::PrincipalKind::System
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights17 } else if id == g1t_contracts::identity::AGENT_ID {
18 g1t_contracts::PrincipalKind::Agent
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily19 } else {
20 g1t_contracts::PrincipalKind::User
21 };
Issues and pull requests replace intents and attempts22 User {
23 id,
24 username,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily25 kind,
Issues and pull requests replace intents and attempts26 ..User::default()
27 }
28}
29
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights30/// Who asked g1t for the work, as stored beside its author: both columns,
31/// or nobody.
32pub(crate) fn requester(id: Option<String>, username: Option<String>) -> Option<User> {
33 Some(user(id?, username?))
34}
35
Work service in Rust, with RFC 3339 timestamps36#[derive(Deserialize)]
Issues and pull requests replace intents and attempts37pub struct IssueRow {
Work service in Rust, with RFC 3339 timestamps38 pub id: String,
39 pub repo_id: String,
40 pub number: u32,
41 pub title: String,
Issues and pull requests replace intents and attempts42 pub body: String,
43 /// JSON array of label names.
44 pub labels: String,
45 pub state: State,
46 pub reason: Option<IssueReason>,
47 pub resolved_by: Option<u32>,
Work service in Rust, with RFC 3339 timestamps48 pub author_id: String,
49 pub author_name: String,
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights50 #[serde(default)]
51 pub requested_by_id: Option<String>,
52 #[serde(default)]
53 pub requested_by_name: Option<String>,
Work service in Rust, with RFC 3339 timestamps54 pub created_at: String,
Issues and pull requests replace intents and attempts55 pub updated_at: String,
56 pub closed_at: Option<String>,
57 pub pull_count: u32,
58 pub comment_count: u32,
Agents as a team: lifecycle, merge queue, billing and a new shell59 /// JSON array of usernames.
60 pub assignees: String,
61 /// JSON array of issue numbers.
62 pub blocked_by: String,
63 /// JSON of who queued it for a g1t agent, if anyone has.
64 pub queued_by: Option<String>,
65 pub agent: Option<String>,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar66 /// The number of its milestone, and that milestone's title.
67 #[serde(default)]
68 pub milestone: Option<u32>,
69 #[serde(default)]
70 pub milestone_title: Option<String>,
Work service in Rust, with RFC 3339 timestamps71}
72
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar73/// A milestone as an issue or pull request names it, from its number and
74/// title as read beside it.
75pub(crate) fn milestone_ref(number: Option<u32>, title: Option<String>) -> Option<MilestoneRef> {
76 Some(MilestoneRef { number: number?, title: title? })
77}
78
Issues and pull requests replace intents and attempts79impl From<IssueRow> for Issue {
80 fn from(row: IssueRow) -> Self {
81 Issue {
Work service in Rust, with RFC 3339 timestamps82 id: row.id,
83 repo_id: row.repo_id,
84 number: row.number,
85 title: row.title,
Issues and pull requests replace intents and attempts86 body: row.body,
87 labels: serde_json::from_str(&row.labels).unwrap_or_default(),
88 state: row.state,
89 reason: row.reason,
90 resolved_by: row.resolved_by,
91 author: user(row.author_id, row.author_name),
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights92 requested_by: requester(row.requested_by_id, row.requested_by_name),
Work service in Rust, with RFC 3339 timestamps93 created_at: row.created_at,
Issues and pull requests replace intents and attempts94 updated_at: row.updated_at,
95 closed_at: row.closed_at,
96 pull_count: row.pull_count,
97 comment_count: row.comment_count,
Agents as a team: lifecycle, merge queue, billing and a new shell98 assignees: serde_json::from_str(&row.assignees).unwrap_or_default(),
99 blocked_by: serde_json::from_str(&row.blocked_by).unwrap_or_default(),
100 queued: row.queued_by.is_some(),
101 agent: row.agent,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar102 milestone: milestone_ref(row.milestone, row.milestone_title),
Work service in Rust, with RFC 3339 timestamps103 }
104 }
105}
106
Agents as a team: lifecycle, merge queue, billing and a new shell107/// The remembered assessment of a pull request, read beside its row.
Work service in Rust, with RFC 3339 timestamps108#[derive(Deserialize)]
Agents as a team: lifecycle, merge queue, billing and a new shell109pub struct Snapshot {
110 pub stage: Option<g1t_contracts::work::Stage>,
111 pub stage_detail: Option<String>,
112 #[serde(default)]
113 pub revisions: u32,
114 /// Whether g1t is seeing it through at all.
115 #[serde(default)]
116 pub managed: u32,
117}
118
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step119/// A pull request's columns, with its confidence (confidence.rs) beside
120/// them: what every read of a [`PullRow`] selects.
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar121pub const PULL_COLUMNS: &str = "pulls.*,
122 (SELECT detail FROM pull_confidence WHERE pull_confidence.pull_id = pulls.id) AS confidence,
123 (SELECT title FROM milestones
124 WHERE milestones.repo_id = pulls.repo_id AND milestones.number = pulls.milestone) AS milestone_title";
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step125
Agents as a team: lifecycle, merge queue, billing and a new shell126#[derive(Deserialize)]
Issues and pull requests replace intents and attempts127pub struct PullRow {
Work service in Rust, with RFC 3339 timestamps128 pub id: String,
129 pub repo_id: String,
130 pub number: u32,
Issues and pull requests replace intents and attempts131 pub issue_number: Option<u32>,
132 pub title: String,
133 pub body: Option<String>,
Work service in Rust, with RFC 3339 timestamps134 pub agent: String,
Issues and pull requests replace intents and attempts135 pub runtime: Runtime,
136 pub status: PullStatus,
Pull requests from branches137 pub fork_repo_id: Option<String>,
138 pub fork_namespace: Option<String>,
139 pub fork_name: Option<String>,
140 pub source_branch: Option<String>,
Work service in Rust, with RFC 3339 timestamps141 pub head_commit: Option<String>,
Issues and pull requests replace intents and attempts142 pub merge_base: Option<String>,
143 pub merged_by: Option<String>,
144 pub merged_at: Option<String>,
145 pub superseded_by: Option<u32>,
Acceptance checks in sandboxes, line comments and review verdicts146 pub check_status: Option<CheckStatus>,
Agents as a team: lifecycle, merge queue, billing and a new shell147 /// JSON array of changed files; `None` until first worked out.
148 pub files: Option<String>,
149 /// JSON arrays of usernames.
150 pub assignees: String,
151 pub reviewers: String,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar152 /// JSON array of `workspace/team`.
153 #[serde(default)]
154 pub team_reviewers: Option<String>,
Issues and pull requests replace intents and attempts155 pub author_id: String,
156 pub author_name: String,
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights157 #[serde(default)]
158 pub requested_by_id: Option<String>,
159 #[serde(default)]
160 pub requested_by_name: Option<String>,
Work service in Rust, with RFC 3339 timestamps161 pub created_at: String,
162 pub updated_at: String,
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step163 /// JSON of its confidence, once worked out.
164 #[serde(default)]
165 pub confidence: Option<String>,
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar166 /// JSON array of label names.
167 #[serde(default)]
168 pub labels: Option<String>,
169 #[serde(default)]
170 pub milestone: Option<u32>,
171 #[serde(default)]
172 pub milestone_title: Option<String>,
173 /// The branch it merges into; NULL for the default branch.
174 #[serde(default)]
175 pub base_branch: Option<String>,
Work service in Rust, with RFC 3339 timestamps176}
177
Issues and pull requests replace intents and attempts178impl From<PullRow> for Pull {
179 fn from(row: PullRow) -> Self {
180 Pull {
Work service in Rust, with RFC 3339 timestamps181 id: row.id,
182 repo_id: row.repo_id,
183 number: row.number,
Issues and pull requests replace intents and attempts184 issue: row.issue_number,
185 title: row.title,
186 body: row.body,
Work service in Rust, with RFC 3339 timestamps187 agent: row.agent,
188 runtime: row.runtime,
189 status: row.status,
Pull requests from branches190 fork: row
191 .fork_namespace
192 .zip(row.fork_name)
193 .map(|(namespace, name)| RepoPath { namespace, name }),
Work service in Rust, with RFC 3339 timestamps194 fork_repo_id: row.fork_repo_id,
Pull requests from branches195 branch: row.source_branch,
Work service in Rust, with RFC 3339 timestamps196 head_commit: row.head_commit,
Issues and pull requests replace intents and attempts197 merge_base: row.merge_base,
198 merged_by: row.merged_by,
199 merged_at: row.merged_at,
200 superseded_by: row.superseded_by,
Acceptance checks in sandboxes, line comments and review verdicts201 check_status: row.check_status,
Agents as a team: lifecycle, merge queue, billing and a new shell202 files: row
203 .files
204 .as_deref()
205 .and_then(|files| serde_json::from_str(files).ok())
206 .unwrap_or_default(),
207 assignees: serde_json::from_str(&row.assignees).unwrap_or_default(),
208 reviewers: serde_json::from_str(&row.reviewers).unwrap_or_default(),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar209 team_reviewers: row
210 .team_reviewers
211 .as_deref()
212 .and_then(|teams| serde_json::from_str(teams).ok())
213 .unwrap_or_default(),
Issues and pull requests replace intents and attempts214 author: user(row.author_id, row.author_name),
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights215 requested_by: requester(row.requested_by_id, row.requested_by_name),
Work service in Rust, with RFC 3339 timestamps216 created_at: row.created_at,
217 updated_at: row.updated_at,
Thirteen MCP tools and classic token scopes; agents rate their confidence and can be put on an issue in one step218 confidence: row
219 .confidence
220 .as_deref()
221 .and_then(|detail| serde_json::from_str(detail).ok()),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar222 labels: row
223 .labels
224 .as_deref()
225 .and_then(|labels| serde_json::from_str(labels).ok())
226 .unwrap_or_default(),
227 milestone: milestone_ref(row.milestone, row.milestone_title),
228 base: row.base_branch,
Work service in Rust, with RFC 3339 timestamps229 }
230 }
231}
232
233#[derive(Deserialize)]
Issues and pull requests replace intents and attempts234pub struct CommentRow {
235 pub id: String,
Agents as a team: lifecycle, merge queue, billing and a new shell236 pub kind: CommentKind,
Issues and pull requests replace intents and attempts237 pub author_id: String,
238 pub author_name: String,
239 pub body: String,
Acceptance checks in sandboxes, line comments and review verdicts240 pub path: Option<String>,
241 pub line: Option<u32>,
242 pub verdict: Option<Verdict>,
Issues and pull requests replace intents and attempts243 pub created_at: String,
244}
245
246impl From<CommentRow> for Comment {
247 fn from(row: CommentRow) -> Self {
248 Comment {
249 id: row.id,
Agents as a team: lifecycle, merge queue, billing and a new shell250 kind: row.kind,
Issues and pull requests replace intents and attempts251 author: user(row.author_id, row.author_name),
252 body: row.body,
Acceptance checks in sandboxes, line comments and review verdicts253 path: row.path,
254 line: row.line,
255 verdict: row.verdict,
Issues and pull requests replace intents and attempts256 created_at: row.created_at,
257 }
258 }
259}
260
261#[derive(Deserialize)]
Work service in Rust, with RFC 3339 timestamps262pub struct SessionRow {
263 pub seq: u32,
264 pub kind: SessionEntryKind,
265 pub text: String,
266 pub tool: Option<String>,
267 pub commit: Option<String>,
268 pub at: String,
269}
270
271impl From<SessionRow> for SessionEntry {
272 fn from(row: SessionRow) -> Self {
273 SessionEntry {
274 seq: row.seq,
275 kind: row.kind,
276 text: row.text,
277 tool: row.tool,
278 commit: row.commit,
279 at: row.at,
280 }
281 }
282}
Issues and pull requests replace intents and attempts283
Acceptance checks in sandboxes, line comments and review verdicts284/// A pull request whose head a push moved.
285#[derive(Deserialize)]
286pub struct MovedRow {
287 pub id: String,
288 pub repo_id: String,
289 pub number: u32,
290 pub issue_number: Option<u32>,
291 pub status: PullStatus,
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights292 pub author_id: String,
293 pub author_name: String,
294 #[serde(default)]
295 pub requested_by_id: Option<String>,
296 #[serde(default)]
297 pub requested_by_name: Option<String>,
Acceptance checks in sandboxes, line comments and review verdicts298}
299
Issues and pull requests replace intents and attempts300/// A single number selected as `n`.
301#[derive(Deserialize)]
302pub struct NumberRow {
303 pub n: u32,
304}
305
306/// A single string selected as `value`.
307#[derive(Deserialize)]
308pub struct ValueRow {
309 pub value: String,
310}
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights311
312/// Rows as the database holds them, for tests of the rules that read them.
313#[cfg(test)]
314pub(crate) mod stored {
315 use super::*;
316
317 /// A pull request g1t made in a fork, read back as stored: g1t as its
318 /// author, and `requested_by` the person who asked, if anyone did.
319 pub(crate) fn pull(author: (&str, &str), requested_by: Option<(&str, &str)>) -> Pull {
320 let row: PullRow = serde_json::from_value(serde_json::json!({
321 "id": "pr_1", "repo_id": "rep_1", "number": 14, "issue_number": 12, "title": "Fix it",
322 "body": null, "agent": "g1t", "runtime": "hosted", "status": "open",
323 "fork_repo_id": "rep_f", "fork_namespace": "pulls", "fork_name": "pr_1",
324 "source_branch": null, "head_commit": null, "merge_base": null, "merged_by": null,
325 "merged_at": null, "superseded_by": null, "check_status": null, "files": null,
326 "assignees": "[]", "reviewers": "[]",
327 "author_id": author.0, "author_name": author.1,
328 "requested_by_id": requested_by.map(|(id, _)| id),
329 "requested_by_name": requested_by.map(|(_, name)| name),
330 "created_at": "", "updated_at": ""
331 }))
332 .unwrap();
333 row.into()
334 }
335
336 /// g1t's agent, as an author is stored.
337 pub(crate) const G1T: (&str, &str) = (g1t_contracts::identity::AGENT_ID, "g1t");
338 /// The person who asked g1t for the work.
339 pub(crate) const ASKER: (&str, &str) = ("usr_1", "syntaqx");
340}
341
342#[cfg(test)]
343mod tests {
344 use super::stored::{ASKER, G1T, pull};
345 use super::*;
346 use g1t_contracts::PrincipalKind;
347
348 #[test]
349 fn g1t_s_pull_request_reads_back_as_g1t_s_requested_by_the_person() {
350 let made = pull(G1T, Some(ASKER));
351 assert_eq!((made.author.username.as_str(), made.author.kind), ("g1t", PrincipalKind::Agent));
352 let asked = made.requested_by.as_ref().expect("who asked is kept");
353 assert_eq!((asked.id.as_str(), asked.username.as_str(), asked.kind), ("usr_1", "syntaqx", PrincipalKind::User));
354 assert_eq!(made.owner().id, "usr_1");
355 }
356
357 #[test]
358 fn anyone_else_s_reads_back_as_theirs_alone() {
359 let own = pull(ASKER, None);
360 assert_eq!(own.author.kind, PrincipalKind::User);
361 assert!(own.requested_by.is_none());
362 assert_eq!(own.owner().id, "usr_1");
363 // Half a requester is nobody.
364 assert!(requester(Some("usr_1".into()), None).is_none());
365 }
366
367 #[test]
368 fn g1t_s_own_work_reads_back_as_g1t_itself() {
369 let own = pull(("g1t", "g1t"), None);
370 assert_eq!(own.author.kind, PrincipalKind::System);
371 assert!(own.requested_by.is_none());
372 }
373}