Skip to content
433 linesCodeBlameRaw

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.

Fix a hydration mismatch in output that starts with a blank line1//! 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::{
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar6 AgentRef, AgentVerdict, CheckStatus, Comment, CommentKind, Issue, IssueReason, MilestoneRef, Pull, PullStatus, Runtime, SessionEntry,
Fix a hydration mismatch in output that starts with a blank line7 SessionEntryKind, State, Verdict,
8};
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.
Fix a hydration mismatch in output that starts with a blank line14pub(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 };
Fix a hydration mismatch in output that starts with a blank line22 User {
23 id,
24 username,
Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily25 kind,
Fix a hydration mismatch in output that starts with a blank line26 ..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
Fix a hydration mismatch in output that starts with a blank line36#[derive(Deserialize)]
37pub struct IssueRow {
38 pub id: String,
39 pub repo_id: String,
40 pub number: u32,
41 pub title: String,
42 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>,
48 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>,
Fix a hydration mismatch in output that starts with a blank line54 pub created_at: String,
55 pub updated_at: String,
56 pub closed_at: Option<String>,
57 pub pull_count: u32,
58 pub comment_count: u32,
59 /// 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>,
Fix a hydration mismatch in output that starts with a blank line71}
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
Fix a hydration mismatch in output that starts with a blank line79impl From<IssueRow> for Issue {
80 fn from(row: IssueRow) -> Self {
81 Issue {
82 id: row.id,
83 repo_id: row.repo_id,
84 number: row.number,
85 title: row.title,
86 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),
Fix a hydration mismatch in output that starts with a blank line93 created_at: row.created_at,
94 updated_at: row.updated_at,
95 closed_at: row.closed_at,
96 pull_count: row.pull_count,
97 comment_count: row.comment_count,
98 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),
Fix a hydration mismatch in output that starts with a blank line103 }
104 }
105}
106
107/// The remembered assessment of a pull request, read beside its row.
108#[derive(Deserialize)]
109pub 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
Fix a hydration mismatch in output that starts with a blank line126#[derive(Deserialize)]
127pub struct PullRow {
128 pub id: String,
129 pub repo_id: String,
130 pub number: u32,
131 pub issue_number: Option<u32>,
132 pub title: String,
133 pub body: Option<String>,
134 pub agent: String,
135 pub runtime: Runtime,
136 pub status: PullStatus,
137 pub fork_repo_id: Option<String>,
138 pub fork_namespace: Option<String>,
139 pub fork_name: Option<String>,
140 pub source_branch: Option<String>,
141 pub head_commit: Option<String>,
142 pub merge_base: Option<String>,
143 pub merged_by: Option<String>,
144 pub merged_at: Option<String>,
145 pub superseded_by: Option<u32>,
146 pub check_status: Option<CheckStatus>,
147 /// 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>,
Fix a hydration mismatch in output that starts with a blank line155 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>,
Fix a hydration mismatch in output that starts with a blank line161 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>,
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge176 #[serde(default)]
177 pub head_pushed_by: Option<String>,
178 #[serde(default)]
179 pub head_pushed_at: Option<String>,
Fix a hydration mismatch in output that starts with a blank line180}
181
182impl From<PullRow> for Pull {
183 fn from(row: PullRow) -> Self {
184 Pull {
185 id: row.id,
186 repo_id: row.repo_id,
187 number: row.number,
188 issue: row.issue_number,
189 title: row.title,
190 body: row.body,
191 agent: row.agent,
192 runtime: row.runtime,
193 status: row.status,
194 fork: row
195 .fork_namespace
196 .zip(row.fork_name)
197 .map(|(namespace, name)| RepoPath { namespace, name }),
198 fork_repo_id: row.fork_repo_id,
199 branch: row.source_branch,
200 head_commit: row.head_commit,
201 merge_base: row.merge_base,
202 merged_by: row.merged_by,
203 merged_at: row.merged_at,
204 superseded_by: row.superseded_by,
205 check_status: row.check_status,
206 files: row
207 .files
208 .as_deref()
209 .and_then(|files| serde_json::from_str(files).ok())
210 .unwrap_or_default(),
211 assignees: serde_json::from_str(&row.assignees).unwrap_or_default(),
212 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 bar213 team_reviewers: row
214 .team_reviewers
215 .as_deref()
216 .and_then(|teams| serde_json::from_str(teams).ok())
217 .unwrap_or_default(),
Fix a hydration mismatch in output that starts with a blank line218 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 rights219 requested_by: requester(row.requested_by_id, row.requested_by_name),
Fix a hydration mismatch in output that starts with a blank line220 created_at: row.created_at,
221 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 step222 confidence: row
223 .confidence
224 .as_deref()
225 .and_then(|detail| serde_json::from_str(detail).ok()),
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar226 labels: row
227 .labels
228 .as_deref()
229 .and_then(|labels| serde_json::from_str(labels).ok())
230 .unwrap_or_default(),
231 milestone: milestone_ref(row.milestone, row.milestone_title),
232 base: row.base_branch,
Merge rulesets: branch and tag rules, agent-first, enforced on push and merge233 head_pushed_by: row.head_pushed_by,
234 head_pushed_at: row.head_pushed_at,
Fix a hydration mismatch in output that starts with a blank line235 }
236 }
237}
238
239#[derive(Deserialize)]
240pub struct CommentRow {
241 pub id: String,
242 pub kind: CommentKind,
243 pub author_id: String,
244 pub author_name: String,
245 pub body: String,
246 pub path: Option<String>,
247 pub line: Option<u32>,
248 pub verdict: Option<Verdict>,
249 pub created_at: String,
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts250 #[serde(default)]
251 pub edited_at: Option<String>,
252 /// The issue or pull request it is on, where the query reads it.
253 #[serde(default)]
254 pub number: u32,
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar255 /// One of the workspace's agents that wrote it, as itself, and whom it
256 /// acted for (migrations/0033_agent_comments.sql).
257 #[serde(default)]
258 pub agent_id: Option<String>,
259 #[serde(default)]
260 pub agent_handle: Option<String>,
261 #[serde(default)]
262 pub agent_name: Option<String>,
263 #[serde(default)]
264 pub agent_avatar_seed: Option<String>,
265 #[serde(default)]
266 pub acting_for_id: Option<String>,
267 #[serde(default)]
268 pub acting_for_name: Option<String>,
269 /// An agent review's verdict, kept apart from `verdict`, which every
270 /// rule about approvals reads: so it is advisory.
271 #[serde(default)]
272 pub agent_verdict: Option<String>,
273}
274
275impl CommentRow {
276 /// Who answers for it: whoever an agent acted for, or its author.
277 pub fn answerable_id(&self) -> &str {
278 self.acting_for_id.as_deref().unwrap_or(&self.author_id)
279 }
280
281 /// Whether it carries a verdict, a person's or an agent's.
282 pub fn has_verdict(&self) -> bool {
283 self.verdict.is_some() || self.agent_verdict.is_some()
284 }
Fix a hydration mismatch in output that starts with a blank line285}
286
287impl From<CommentRow> for Comment {
288 fn from(row: CommentRow) -> Self {
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar289 let agent = match (row.agent_id, row.agent_handle) {
290 (Some(id), Some(handle)) => Some(AgentRef {
291 display_name: row.agent_name.unwrap_or_else(|| handle.clone()),
292 avatar_seed: row.agent_avatar_seed.unwrap_or_else(|| handle.clone()),
293 id,
294 handle,
295 }),
296 _ => None,
297 };
298 let advisory_verdict = row.agent_verdict.as_deref().and_then(AgentVerdict::parse);
299 let mut author = user(row.author_id, row.author_name);
300 if agent.is_some() {
301 author.kind = g1t_contracts::PrincipalKind::Agent;
302 }
Fix a hydration mismatch in output that starts with a blank line303 Comment {
304 id: row.id,
305 kind: row.kind,
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar306 author,
Fix a hydration mismatch in output that starts with a blank line307 body: row.body,
308 path: row.path,
309 line: row.line,
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar310 // A person's verdict, or for showing, an agent's advisory one.
311 verdict: row.verdict.or(advisory_verdict.and_then(AgentVerdict::verdict)),
Fix a hydration mismatch in output that starts with a blank line312 created_at: row.created_at,
Merge Actions: cross-repo workflows and actions, release and deployment triggers, step timeouts313 edited_at: row.edited_at,
Cards you act on in chat; agents comment and review as themselves; names shown cleanly; commits on the calendar314 acting_for: agent.as_ref().and(requester(row.acting_for_id, row.acting_for_name)),
315 advisory: agent.is_some() && advisory_verdict.is_some(),
316 agent,
Fix a hydration mismatch in output that starts with a blank line317 }
318 }
319}
320
321#[derive(Deserialize)]
322pub struct SessionRow {
323 pub seq: u32,
324 pub kind: SessionEntryKind,
325 pub text: String,
326 pub tool: Option<String>,
327 pub commit: Option<String>,
328 pub at: String,
329}
330
331impl From<SessionRow> for SessionEntry {
332 fn from(row: SessionRow) -> Self {
333 SessionEntry {
334 seq: row.seq,
335 kind: row.kind,
336 text: row.text,
337 tool: row.tool,
338 commit: row.commit,
339 at: row.at,
340 }
341 }
342}
343
344/// A pull request whose head a push moved.
345#[derive(Deserialize)]
346pub struct MovedRow {
347 pub id: String,
348 pub repo_id: String,
349 pub number: u32,
350 pub issue_number: Option<u32>,
351 pub status: PullStatus,
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights352 pub author_id: String,
353 pub author_name: String,
354 #[serde(default)]
355 pub requested_by_id: Option<String>,
356 #[serde(default)]
357 pub requested_by_name: Option<String>,
Fix a hydration mismatch in output that starts with a blank line358}
359
360/// A single number selected as `n`.
361#[derive(Deserialize)]
362pub struct NumberRow {
363 pub n: u32,
364}
365
366/// A single string selected as `value`.
367#[derive(Deserialize)]
368pub struct ValueRow {
369 pub value: String,
370}
g1t is the stored author of what it opens; the person who asked is requested_by and keeps the author's rights371
372/// Rows as the database holds them, for tests of the rules that read them.
373#[cfg(test)]
374pub(crate) mod stored {
375 use super::*;
376
377 /// A pull request g1t made in a fork, read back as stored: g1t as its
378 /// author, and `requested_by` the person who asked, if anyone did.
379 pub(crate) fn pull(author: (&str, &str), requested_by: Option<(&str, &str)>) -> Pull {
380 let row: PullRow = serde_json::from_value(serde_json::json!({
381 "id": "pr_1", "repo_id": "rep_1", "number": 14, "issue_number": 12, "title": "Fix it",
382 "body": null, "agent": "g1t", "runtime": "hosted", "status": "open",
383 "fork_repo_id": "rep_f", "fork_namespace": "pulls", "fork_name": "pr_1",
384 "source_branch": null, "head_commit": null, "merge_base": null, "merged_by": null,
385 "merged_at": null, "superseded_by": null, "check_status": null, "files": null,
386 "assignees": "[]", "reviewers": "[]",
387 "author_id": author.0, "author_name": author.1,
388 "requested_by_id": requested_by.map(|(id, _)| id),
389 "requested_by_name": requested_by.map(|(_, name)| name),
390 "created_at": "", "updated_at": ""
391 }))
392 .unwrap();
393 row.into()
394 }
395
396 /// g1t's agent, as an author is stored.
397 pub(crate) const G1T: (&str, &str) = (g1t_contracts::identity::AGENT_ID, "g1t");
398 /// The person who asked g1t for the work.
399 pub(crate) const ASKER: (&str, &str) = ("usr_1", "syntaqx");
400}
401
402#[cfg(test)]
403mod tests {
404 use super::stored::{ASKER, G1T, pull};
405 use super::*;
406 use g1t_contracts::PrincipalKind;
407
408 #[test]
409 fn g1t_s_pull_request_reads_back_as_g1t_s_requested_by_the_person() {
410 let made = pull(G1T, Some(ASKER));
411 assert_eq!((made.author.username.as_str(), made.author.kind), ("g1t", PrincipalKind::Agent));
412 let asked = made.requested_by.as_ref().expect("who asked is kept");
413 assert_eq!((asked.id.as_str(), asked.username.as_str(), asked.kind), ("usr_1", "syntaqx", PrincipalKind::User));
414 assert_eq!(made.owner().id, "usr_1");
415 }
416
417 #[test]
418 fn anyone_else_s_reads_back_as_theirs_alone() {
419 let own = pull(ASKER, None);
420 assert_eq!(own.author.kind, PrincipalKind::User);
421 assert!(own.requested_by.is_none());
422 assert_eq!(own.owner().id, "usr_1");
423 // Half a requester is nobody.
424 assert!(requester(Some("usr_1".into()), None).is_none());
425 }
426
427 #[test]
428 fn g1t_s_own_work_reads_back_as_g1t_itself() {
429 let own = pull(("g1t", "g1t"), None);
430 assert_eq!(own.author.kind, PrincipalKind::System);
431 assert!(own.requested_by.is_none());
432 }
433}

This file's history is long; its oldest lines are credited to the oldest commit read.