use pql --with-context for ticket detail loading
test / unit + widget + golden + a11y (push) Failing after 26s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped

Replaces the N+1 parent-chain walk (one IPC call per ancestor, one
per decision ref) with a single pql ticket show --with-context call.
pql now returns ancestors and decisions arrays inline.

Updates PqlClient.ticketShow to accept withContext/withChildren flags,
removes the obsolete withDecision flag.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-04-24 10:54:17 +02:00
co-authored by Claude
parent 77c2f25eaf
commit b8c8826b9e
3 changed files with 10 additions and 32 deletions
@@ -49,7 +49,7 @@ class TicketDetailController extends ChangeNotifier {
_loading = true;
notifyListeners();
final resp = await ipc.request('pql.tickets.show', args: {'id': id});
final resp = await ipc.request('pql.tickets.show', args: {'id': id, 'withContext': true});
if (!resp.ok) {
_loading = false;
notifyListeners();
@@ -57,33 +57,10 @@ class TicketDetailController extends ChangeNotifier {
}
final ticket = resp.data;
final parents = <Map<String, Object?>>[];
final decisions = <Map<String, Object?>>[];
final ancestors = (ticket['ancestors'] as List?)?.cast<Map<String, Object?>>() ?? const [];
final decisions = (ticket['decisions'] as List?)?.cast<Map<String, Object?>>() ?? const [];
// Walk parent chain
var pid = ticket['parent_id'] as String?;
while (pid != null) {
final pr = await ipc.request('pql.tickets.show', args: {'id': pid});
if (!pr.ok) break;
parents.add(pr.data);
pid = pr.data['parent_id'] as String?;
}
// Collect decision refs from ticket and parents
final refs = <String>{};
final dr = ticket['decision_ref'] as String?;
if (dr != null) refs.add(dr);
for (final p in parents) {
final pdr = p['decision_ref'] as String?;
if (pdr != null) refs.add(pdr);
}
for (final ref in refs) {
final dr = await ipc.request('pql.decisions.show', args: {'id': ref});
if (dr.ok) decisions.add(dr.data);
}
_detail = TicketDetail(ticket: ticket, parents: parents, decisions: decisions);
_detail = TicketDetail(ticket: ticket, parents: ancestors, decisions: decisions);
_loading = false;
messages.publish('builtin.tickets', 'focus', {'id': id});
notifyListeners();
+2 -1
View File
@@ -200,8 +200,9 @@ void registerPqlCommands(DaemonDispatcher d, PqlClient pql) {
try {
final result = await pql.ticketShow(
id,
withDecision: req.args['withDecision'] as bool? ?? false,
withContext: req.args['withContext'] as bool? ?? false,
withBlockers: req.args['withBlockers'] as bool? ?? false,
withChildren: req.args['withChildren'] as bool? ?? false,
);
return IpcResponse.ok(id: req.id, data: result);
} on PqlException catch (e) {
+4 -4
View File
@@ -8,8 +8,6 @@ library;
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
class PqlException implements Exception {
const PqlException(this.message, {this.exitCode = 1, this.stderr = ''});
final String message;
@@ -126,12 +124,14 @@ class PqlClient {
Future<Map<String, Object?>> ticketShow(
String id, {
bool withDecision = false,
bool withContext = false,
bool withBlockers = false,
bool withChildren = false,
}) async {
final args = ['ticket', 'show', id];
if (withDecision) args.add('--with-decision');
if (withContext) args.add('--with-context');
if (withBlockers) args.add('--with-blockers');
if (withChildren) args.add('--with-children');
return _runObject(args);
}