|
|
@@ -56,8 +56,15 @@ namespace ClankerSaddle.Services {
|
|
|
*/
|
|
|
public async Vector<TimelineEvent> recent_window() throws Error {
|
|
|
var titles = new Dictionary<string, string>();
|
|
|
+ // Goal-agent runs are internal tasks: their own lifecycle,
|
|
|
+ // mirrored blocks and telemetry never surface as task
|
|
|
+ // events (the goal-keyed events below carry the story).
|
|
|
+ var run_tasks = new Invercargill.DataStructures.HashSet<string>();
|
|
|
foreach (var task in yield db.query<TaskEntity>().materialise_async()) {
|
|
|
titles.set(task.id.to_string(), task.title);
|
|
|
+ if (task.kind == TASK_KIND_GOAL_RUN) {
|
|
|
+ run_tasks.add(task.id.to_string());
|
|
|
+ }
|
|
|
}
|
|
|
var saddle_names = new Dictionary<string, string>();
|
|
|
foreach (var saddle in yield db.query<Saddle>().materialise_async()) {
|
|
|
@@ -73,6 +80,9 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
foreach (var task in yield db.query<TaskEntity>()
|
|
|
.order_by_desc(expr("id")).limit(WINDOW).materialise_async()) {
|
|
|
+ if (run_tasks.has(task.id.to_string())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
string title = titles.get_or_default(task.id.to_string()) ?? task.title;
|
|
|
if (task.created_at != null) {
|
|
|
events.add(new TimelineEvent() {
|
|
|
@@ -116,6 +126,9 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
foreach (var block in yield db.query<TaskBlock>()
|
|
|
.order_by_desc(expr("id")).limit(WINDOW).materialise_async()) {
|
|
|
+ if (run_tasks.has(block.task_id.to_string())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
if (block.created_at != null) {
|
|
|
events.add(new TimelineEvent() {
|
|
|
kind = "block-raised", at_epoch = ((!)block.created_at).to_unix(),
|
|
|
@@ -138,7 +151,7 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
foreach (var comment in yield db.query<TaskComment>()
|
|
|
.order_by_desc(expr("id")).limit(WINDOW).materialise_async()) {
|
|
|
- if (comment.created_at == null) {
|
|
|
+ if (comment.created_at == null || run_tasks.has(comment.task_id.to_string())) {
|
|
|
continue;
|
|
|
}
|
|
|
events.add(new TimelineEvent() {
|
|
|
@@ -152,7 +165,7 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
foreach (var progress in yield db.query<TaskProgress>()
|
|
|
.order_by_desc(expr("id")).limit(WINDOW).materialise_async()) {
|
|
|
- if (progress.created_at == null) {
|
|
|
+ if (progress.created_at == null || run_tasks.has(progress.task_id.to_string())) {
|
|
|
continue;
|
|
|
}
|
|
|
events.add(new TimelineEvent() {
|
|
|
@@ -165,7 +178,7 @@ namespace ClankerSaddle.Services {
|
|
|
|
|
|
foreach (var session in yield db.query<Session>()
|
|
|
.order_by_desc(expr("id")).limit(WINDOW).materialise_async()) {
|
|
|
- if (session.started_at == null) {
|
|
|
+ if (session.started_at == null || run_tasks.has(session.task_id.to_string())) {
|
|
|
continue;
|
|
|
}
|
|
|
string saddle = saddle_names.get_or_default(session.saddle_id.to_string())
|
|
|
@@ -194,7 +207,7 @@ namespace ClankerSaddle.Services {
|
|
|
continue;
|
|
|
}
|
|
|
string? task_key = session_tasks.get_or_default(entry.session_id.to_string());
|
|
|
- if (task_key == null) {
|
|
|
+ if (task_key == null || run_tasks.has((!)task_key)) {
|
|
|
continue;
|
|
|
}
|
|
|
string? lead = first_line(entry.output_text ?? entry.command_text);
|
|
|
@@ -217,11 +230,17 @@ namespace ClankerSaddle.Services {
|
|
|
if (goal_event.created_at == null) {
|
|
|
continue;
|
|
|
}
|
|
|
+ // A goal event may reference the goal agent's own run
|
|
|
+ // task — the row stays goal-keyed, but the internal
|
|
|
+ // task never becomes a clickable task reference.
|
|
|
+ int64 event_task_id = run_tasks.has(goal_event.task_id.to_string())
|
|
|
+ ? 0 : goal_event.task_id;
|
|
|
events.add(new TimelineEvent() {
|
|
|
kind = @"goal-$(goal_event.kind)",
|
|
|
at_epoch = ((!)goal_event.created_at).to_unix(),
|
|
|
- task_id = goal_event.task_id,
|
|
|
- task_title = titles.get_or_default(goal_event.task_id.to_string()) ?? "",
|
|
|
+ task_id = event_task_id,
|
|
|
+ task_title = event_task_id > 0
|
|
|
+ ? titles.get_or_default(event_task_id.to_string()) ?? "" : "",
|
|
|
goal_id = goal_event.goal_id,
|
|
|
goal_title = goal_titles.get_or_default(goal_event.goal_id.to_string()) ?? "",
|
|
|
text = snippet(goal_event.text), sequence = sequence++
|