-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmulti-agent-coding-system.design.html
More file actions
1071 lines (957 loc) · 60.8 KB
/
Copy pathmulti-agent-coding-system.design.html
File metadata and controls
1071 lines (957 loc) · 60.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="agentify 0.1.0">
<title>Autonomous Coding System</title>
<script>
// Apply the theme before first paint to avoid a flash.
(function () {
try {
var theme = null;
try {
var param = new URLSearchParams(window.location.search).get('theme');
if (param === 'light' || param === 'dark') theme = param;
} catch (_) {}
if (!theme) {
try { theme = localStorage.getItem('agentify-theme'); } catch (_) {}
}
if (theme !== 'light' && theme !== 'dark') {
theme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
}
document.documentElement.setAttribute('data-theme', theme);
} catch (_) {}
})();
</script>
<style>
:root, [data-theme="dark"] {
--bg: #0b1220;
--bg-raised: #0f172a;
--grid: #1e293b;
--text: #e2e8f0;
--text-muted: #94a3b8;
--text-dim: #64748b;
--text-faint: #64748b;
--panel: #0f172a;
--panel-border: #1e293b;
--lane-fill: rgba(15, 23, 42, 0.55);
--lane-stroke: #334155;
--arrow: #64748b;
--arrow-emphasis: #34d399;
--mask: #0f172a;
--accent: #818cf8;
--link: #7dd3fc;
--frontend-fill: rgba(8, 51, 68, 0.4);
--frontend-stroke: #22d3ee;
--backend-fill: rgba(6, 78, 59, 0.4);
--backend-stroke: #34d399;
--database-fill: rgba(76, 29, 149, 0.4);
--database-stroke: #a78bfa;
--cloud-fill: rgba(120, 53, 15, 0.3);
--cloud-stroke: #fbbf24;
--security-fill: rgba(136, 19, 55, 0.4);
--security-stroke: #fb7185;
--messagebus-fill: rgba(251, 146, 60, 0.3);
--messagebus-stroke:#fb923c;
--external-fill: rgba(30, 41, 59, 0.5);
--external-stroke: #94a3b8;
--agent-fill: rgba(49, 46, 129, 0.45);
--agent-stroke: #818cf8;
--model-fill: rgba(19, 78, 74, 0.45);
--model-stroke: #2dd4bf;
--retrieval-fill: rgba(30, 58, 138, 0.4);
--retrieval-stroke: #60a5fa;
--eval-fill: rgba(54, 83, 20, 0.4);
--eval-stroke: #a3e635;
--human-fill: rgba(112, 26, 117, 0.35);
--human-stroke: #e879f9;
}
[data-theme="light"] {
--bg: #f8fafc;
--bg-raised: #ffffff;
--grid: #e2e8f0;
--text: #0f172a;
--text-muted: #64748b;
--text-dim: #94a3b8;
--text-faint: #64748b;
--panel: #ffffff;
--panel-border: #e2e8f0;
--lane-fill: rgba(248, 250, 252, 0.65);
--lane-stroke: #cbd5e1;
--arrow: #94a3b8;
--arrow-emphasis: #059669;
--mask: #ffffff;
--accent: #4f46e5;
--link: #0369a1;
--frontend-fill: rgba(34, 211, 238, 0.15);
--frontend-stroke: #0891b2;
--backend-fill: rgba(52, 211, 153, 0.18);
--backend-stroke: #059669;
--database-fill: rgba(167, 139, 250, 0.2);
--database-stroke: #7c3aed;
--cloud-fill: rgba(251, 191, 36, 0.18);
--cloud-stroke: #d97706;
--security-fill: rgba(251, 113, 133, 0.15);
--security-stroke: #e11d48;
--messagebus-fill: rgba(251, 146, 60, 0.15);
--messagebus-stroke:#ea580c;
--external-fill: rgba(148, 163, 184, 0.18);
--external-stroke: #64748b;
--agent-fill: rgba(129, 140, 248, 0.16);
--agent-stroke: #4f46e5;
--model-fill: rgba(45, 212, 191, 0.16);
--model-stroke: #0d9488;
--retrieval-fill: rgba(96, 165, 250, 0.16);
--retrieval-stroke: #2563eb;
--eval-fill: rgba(163, 230, 53, 0.2);
--eval-stroke: #65a30d;
--human-fill: rgba(232, 121, 249, 0.14);
--human-stroke: #c026d3;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: var(--bg);
color: var(--text);
font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: 15px;
line-height: 1.65;
}
.layout {
display: grid;
grid-template-columns: 250px minmax(0, 1fr);
max-width: 1240px;
margin: 0 auto;
gap: 32px;
padding: 32px 24px 96px;
}
/* Sidebar / TOC */
nav.toc {
position: sticky;
top: 24px;
align-self: start;
font-size: 13px;
max-height: calc(100vh - 48px);
overflow-y: auto;
padding-right: 8px;
}
nav.toc .toc-title {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-dim);
margin-bottom: 10px;
}
nav.toc ol { list-style: none; }
nav.toc li { margin: 2px 0; }
nav.toc a {
color: var(--text-muted);
text-decoration: none;
display: block;
padding: 4px 10px;
border-left: 2px solid var(--panel-border);
transition: color 120ms, border-color 120ms;
}
nav.toc a:hover { color: var(--text); }
nav.toc a.active { color: var(--accent); border-left-color: var(--accent); }
/* Header */
header.doc-header {
grid-column: 1 / -1;
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 16px;
border-bottom: 1px solid var(--panel-border);
padding-bottom: 20px;
}
header.doc-header h1 { font-size: 26px; line-height: 1.25; letter-spacing: -0.01em; }
header.doc-header .subtitle { color: var(--text-muted); margin-top: 6px; font-size: 14px; }
header.doc-header .meta-line { color: var(--text-dim); font-size: 12px; margin-top: 10px; }
.badge {
display: inline-block;
font-size: 11px;
padding: 2px 8px;
border: 1px solid var(--panel-border);
border-radius: 999px;
color: var(--text-muted);
margin-right: 6px;
}
#btn-theme {
background: var(--panel);
border: 1px solid var(--panel-border);
color: var(--text);
font: inherit;
font-size: 13px;
border-radius: 8px;
padding: 6px 12px;
cursor: pointer;
white-space: nowrap;
}
#btn-theme:hover { border-color: var(--text-dim); }
/* Content */
main { min-width: 0; }
section.doc-section { margin-bottom: 44px; scroll-margin-top: 24px; }
section.doc-section h2 {
font-size: 19px;
margin-bottom: 14px;
padding-bottom: 8px;
border-bottom: 1px solid var(--panel-border);
letter-spacing: -0.01em;
}
section.doc-section h3 {
font-size: 15px;
margin: 20px 0 8px;
color: var(--text);
}
section.doc-section p { margin: 10px 0; color: var(--text); }
section.doc-section p.lead { font-size: 16px; }
section.doc-section ul, section.doc-section ol { margin: 10px 0 10px 22px; }
section.doc-section li { margin: 4px 0; }
section.doc-section a { color: var(--link); }
/* Tables */
table {
width: 100%;
border-collapse: collapse;
font-size: 13.5px;
margin: 14px 0;
display: block;
overflow-x: auto;
}
th, td {
text-align: left;
padding: 8px 12px;
border: 1px solid var(--panel-border);
vertical-align: top;
}
th {
background: var(--panel);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-muted);
white-space: nowrap;
}
tbody tr:nth-child(even) { background: color-mix(in srgb, var(--panel) 45%, transparent); }
/* Callouts */
.callout {
border: 1px solid var(--panel-border);
border-left: 3px solid var(--accent);
background: var(--panel);
border-radius: 8px;
padding: 12px 16px;
margin: 14px 0;
font-size: 14px;
}
.callout.assumption { border-left-color: var(--cloud-stroke); }
.callout.risk { border-left-color: var(--security-stroke); }
.callout.decision { border-left-color: var(--eval-stroke); }
.callout .callout-label {
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-dim);
display: block;
margin-bottom: 4px;
}
/* Interview mode blocks */
details.interview {
border: 1px dashed var(--panel-border);
border-radius: 8px;
padding: 10px 16px;
margin: 14px 0;
font-size: 14px;
}
details.interview summary {
cursor: pointer;
color: var(--human-stroke);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* Citations */
.cite {
font-size: 12px;
color: var(--text-dim);
vertical-align: super;
line-height: 0;
}
code {
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 0.88em;
background: var(--panel);
border: 1px solid var(--panel-border);
border-radius: 4px;
padding: 1px 5px;
}
pre {
background: var(--panel);
border: 1px solid var(--panel-border);
border-radius: 8px;
padding: 14px 16px;
overflow-x: auto;
margin: 14px 0;
}
pre code { background: none; border: none; padding: 0; }
/* Embedded diagrams */
figure.diagram-slot {
background: var(--bg-raised);
border: 1px solid var(--panel-border);
border-radius: 12px;
padding: 18px;
margin: 18px 0;
}
figure.diagram-slot svg { width: 100%; height: auto; display: block; }
figure.diagram-slot figcaption {
margin-top: 10px;
font-size: 12.5px;
color: var(--text-muted);
text-align: center;
}
/* SVG classes shared with the diagram engine, so embedded SVGs theme correctly */
.c-mask { fill: var(--mask); stroke: none; }
.c-frontend { fill: var(--frontend-fill); stroke: var(--frontend-stroke); }
.c-backend { fill: var(--backend-fill); stroke: var(--backend-stroke); }
.c-database { fill: var(--database-fill); stroke: var(--database-stroke); }
.c-cloud { fill: var(--cloud-fill); stroke: var(--cloud-stroke); }
.c-security { fill: var(--security-fill); stroke: var(--security-stroke); }
.c-messagebus { fill: var(--messagebus-fill); stroke: var(--messagebus-stroke); }
.c-external { fill: var(--external-fill); stroke: var(--external-stroke); }
.c-agent { fill: var(--agent-fill); stroke: var(--agent-stroke); }
.c-model { fill: var(--model-fill); stroke: var(--model-stroke); }
.c-retrieval { fill: var(--retrieval-fill); stroke: var(--retrieval-stroke); }
.c-eval { fill: var(--eval-fill); stroke: var(--eval-stroke); }
.c-human { fill: var(--human-fill); stroke: var(--human-stroke); stroke-dasharray: 6,3; }
.c-security-group { fill: transparent; stroke: var(--security-stroke); stroke-dasharray: 4,4; }
.c-region { fill: var(--lane-fill); stroke: var(--lane-stroke); }
.t-primary { fill: var(--text); }
.t-muted { fill: var(--text-muted); }
.t-dim { fill: var(--text-dim); }
.t-frontend { fill: var(--frontend-stroke); }
.t-backend { fill: var(--backend-stroke); }
.t-database { fill: var(--database-stroke); }
.t-cloud { fill: var(--cloud-stroke); }
.t-security { fill: var(--security-stroke); }
.t-messagebus { fill: var(--messagebus-stroke); }
.t-external { fill: var(--external-stroke); }
.t-agent { fill: var(--agent-stroke); }
.t-model { fill: var(--model-stroke); }
.t-retrieval { fill: var(--retrieval-stroke); }
.t-eval { fill: var(--eval-stroke); }
.t-human { fill: var(--human-stroke); }
.a-default { stroke: var(--arrow); fill: none; }
.a-emphasis { stroke: var(--arrow-emphasis); fill: none; }
.a-security { stroke: var(--security-stroke); fill: none; stroke-dasharray: 5,5; }
.a-dashed { stroke: var(--arrow); fill: none; stroke-dasharray: 5,5; }
.arrowhead { fill: var(--arrow); }
.arrowhead-emphasis { fill: var(--arrow-emphasis); }
.arrowhead-security { fill: var(--security-stroke); }
.lane { fill: var(--lane-fill); stroke: var(--lane-stroke); }
/* Print */
@media print {
:root, [data-theme="dark"], [data-theme="light"] {
--bg: #ffffff;
--bg-raised: #ffffff;
--text: #0f172a;
--text-muted: #475569;
--text-dim: #94a3b8;
--panel: #ffffff;
--panel-border: #e2e8f0;
--mask: #ffffff;
--lane-fill: rgba(248, 250, 252, 0.65);
--lane-stroke: #cbd5e1;
--arrow: #94a3b8;
--arrow-emphasis: #059669;
--link: #0369a1;
--accent: #4f46e5;
--frontend-fill: rgba(34, 211, 238, 0.15);
--frontend-stroke: #0891b2;
--backend-fill: rgba(52, 211, 153, 0.18);
--backend-stroke: #059669;
--database-fill: rgba(167, 139, 250, 0.2);
--database-stroke: #7c3aed;
--cloud-fill: rgba(251, 191, 36, 0.18);
--cloud-stroke: #d97706;
--security-fill: rgba(251, 113, 133, 0.15);
--security-stroke: #e11d48;
--messagebus-fill: rgba(251, 146, 60, 0.15);
--messagebus-stroke:#ea580c;
--external-fill: rgba(148, 163, 184, 0.18);
--external-stroke: #64748b;
--agent-fill: rgba(129, 140, 248, 0.16);
--agent-stroke: #4f46e5;
--model-fill: rgba(45, 212, 191, 0.16);
--model-stroke: #0d9488;
--retrieval-fill: rgba(96, 165, 250, 0.16);
--retrieval-stroke: #2563eb;
--eval-fill: rgba(163, 230, 53, 0.2);
--eval-stroke: #65a30d;
--human-fill: rgba(232, 121, 249, 0.14);
--human-stroke: #c026d3;
}
.layout { grid-template-columns: 1fr; padding: 0; }
nav.toc, #btn-theme { display: none !important; }
section.doc-section { break-inside: avoid-page; }
figure.diagram-slot { break-inside: avoid; }
details.interview { display: none; }
}
@media (max-width: 900px) {
.layout { grid-template-columns: 1fr; }
nav.toc { position: static; max-height: none; order: -1; }
}
</style>
</head>
<body>
<div class="layout">
<header class="doc-header">
<div>
<h1>Autonomous Coding System</h1>
<div class="subtitle">Staff-level system design in interview mode: turn a ticket into a reviewed pull request, and know when to hand back</div>
<div class="meta-line">
<span class="badge">agentify design document</span>
<span class="badge">interview mode</span>
<span class="badge">2026-07-14</span>
</div>
</div>
<button id="btn-theme" type="button" aria-pressed="false">
<span id="theme-icon">☾</span> <span id="theme-label">Dark</span>
</button>
</header>
<nav class="toc" aria-label="Table of contents">
<div class="toc-title">Contents</div>
<ol id="toc-list"></ol>
</nav>
<main id="doc-body">
<section class="doc-section" id="executive-summary">
<h2>1. Executive summary</h2>
<p class="lead">Build <strong>one bounded agent per ticket with an in-loop reflection stage</strong>, not a multi-agent fleet. The agent plans, edits in a sandbox, runs CI, and reflects on failures until tests pass or a retry budget is spent, then opens a pull request. It never merges: a human approves every merge. This is rung 3 of the escalation ladder, and the single-versus-multi-agent question is the crux of the design <span class="cite">[knowledge/decision-trees.md]</span>.</p>
<p>Success is 30 percent of eligible tickets merged with under 10 minutes of human review, and zero production incidents attributable to the system. The safety posture is what makes that acceptable: sandboxed execution, no production credentials, no deploy access, and a hard rule that the system opens PRs but never merges them.</p>
<div class="callout decision"><span class="callout-label">Position</span> A single agent with a test-driven reflection loop beats a planner-coder-reviewer multi-agent system here: CI is the ground-truth reviewer, and multi-agent coordination would roughly quadruple token cost for no reliability gain.</div>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Lead with the escalation decision and the safety boundary, not the tool list. State the merged-rate target and the zero-incident bar in the first minute.</p>
<p><strong>Interviewer probes.</strong> Why an agent at all rather than a scripted refactor tool? What is the blast radius if it goes wrong?</p>
<p><strong>Tradeoffs to voice.</strong> Autonomy versus safety: more autonomy raises throughput but widens blast radius. The position is maximum autonomy inside a sandbox, zero autonomy at the merge boundary.</p>
</details>
</section>
<section class="doc-section" id="requirements">
<h2>2. Requirements and NFRs</h2>
<table>
<thead><tr><th>NFR</th><th>Target</th></tr></thead>
<tbody>
<tr><td>Volume</td><td>~600 eligible tickets/week (bugs, small features), 40 concurrent jobs peak</td></tr>
<tr><td>Latency</td><td>Batch-tolerant: ticket to PR under 4 hours is fine</td></tr>
<tr><td>Success</td><td>30% of eligible tickets merged with < 10 min human review; zero attributable prod incidents in Q1</td></tr>
<tr><td>Cost</td><td>≤ 20 USD per attempted ticket</td></tr>
<tr><td>Codebase</td><td>Monorepo, 30M LOC, existing CI (25 min full run)</td></tr>
<tr><td>Safety</td><td>Never merges, no prod credentials, no deploy access, sandboxed execution only</td></tr>
<tr><td>Compliance</td><td>SOC 2; code exfiltration is the chief concern</td></tr>
</tbody>
</table>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Separate eligible tickets (bugs, small scoped features) from the long tail the system should refuse. The 30 percent target is of the eligible slice, not all tickets.</p>
<p><strong>Interviewer probes.</strong> How do you decide a ticket is eligible? What stops it attempting a 3-week refactor?</p>
<p><strong>Tradeoffs to voice.</strong> Coverage versus reliability: chasing hard tickets lowers the merged rate and burns budget. Scope tightly and hand back early.</p>
</details>
</section>
<section class="doc-section" id="decision-record">
<h2>3. Decision record</h2>
<table>
<thead><tr><th>Gate</th><th>Decision</th><th>Why, and what lost</th></tr></thead>
<tbody>
<tr><td>Escalation ladder</td><td>Rung 3, single agent</td><td>The path is open-ended: the number of edit-test iterations depends on results <span class="cite">[knowledge/building-effective-agents.md]</span>. A fixed workflow cannot absorb that. Rejected: rung 2.</td></tr>
<tr><td>Single vs multi-agent</td><td>Single, with reflection</td><td>The reflection pattern (self-review plus CI as ground truth) gives most of the benefit of a separate reviewer agent <span class="cite">[knowledge/agentic-design-patterns.md]</span>. A planner-coder-reviewer fleet costs several times the tokens and adds coordination failure modes for no measured reliability gain <span class="cite">[knowledge/multi-agent-orchestration.md]</span>. Rejected: multi-agent.</td></tr>
<tr><td>Autonomy</td><td>Tier 1 (open PR), merge out of scope</td><td>A PR is reversible and reviewed; a merge is not the agent's to make <span class="cite">[knowledge/security-governance.md]</span>.</td></tr>
<tr><td>Grounding</td><td>Repo as corpus, retrieval over code</td><td>The agent retrieves relevant files rather than loading 30M LOC; long-context on the whole repo is neither affordable nor necessary <span class="cite">[knowledge/rag-patterns.md]</span>.</td></tr>
<tr><td>Memory</td><td>Per-run checkpointed state</td><td>Long-running jobs need resumability; no cross-ticket memory is required <span class="cite">[knowledge/context-memory.md]</span>.</td></tr>
</tbody>
</table>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Make the single-versus-multi-agent call explicitly and defend it with token economics, not taste. Name CI as the real reviewer.</p>
<p><strong>Interviewer probes.</strong> When would multi-agent actually win here? What signal would make you switch?</p>
<p><strong>Tradeoffs to voice.</strong> If tickets needed genuinely parallel independent subtasks, or separate privilege domains, multi-agent would earn its cost. This workload does not.</p>
</details>
</section>
<section class="doc-section" id="architecture">
<h2>4. System architecture</h2>
<p>A ticket is admitted through a safety gate into a sandboxed runtime. The agent reasons via a model gateway, edits through repo tools, runs code in a sandbox and tests through CI, and reflects on failures. It checkpoints to run state, then opens a PR that a human reviews.</p>
<figure class="diagram-slot"><svg viewBox="0 0 1320 840" role="img" aria-label="Autonomous Coding System: One bounded agent per ticket with a reflection loop, sandboxed, human approves every merge (architecture diagram)">
<!-- Definitions -->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-default" />
</marker>
<marker id="arrowhead-emphasis" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-emphasis" />
</marker>
<marker id="arrowhead-security" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-security" />
</marker>
<marker id="arrowhead-dashed" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-dashed" />
</marker>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" class="c-grid" stroke-width="0.5"/>
</pattern>
</defs>
<!-- Background Grid -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- Boundaries (behind everything) -->
<rect x="270" y="336" width="630" height="304" rx="8" class="c-security-group" stroke-width="1"/>
<text x="278" y="354" class="t-security" font-size="9" font-weight="600">Sandboxed runtime (no prod access)</text>
<!-- Connection paths (before components for correct z-order) -->
<path d="M 190 402 L 240 402" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 380 402 L 440 402" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 525 366 L 526.25 366 Q 527.5 366 527.5 364.75 L 527.5 211.25 Q 527.5 210 528.75 210 L 530 210" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 525 366 L 589.5 366 Q 597.5 366 597.5 358 L 597.5 188 Q 597.5 180 605.5 180 L 670 180" class="a-dashed" stroke-width="1.5" marker-end="url(#arrowhead-dashed)"/>
<path d="M 525 438 L 547 438 Q 555 438 555 446 L 555 552 Q 555 560 563 560 L 585 560" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 525 438 L 458 438 Q 450 438 450 446 L 450 552 Q 450 560 442 560 L 375 560" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 525 438 L 652 438 Q 660 438 660 446 L 660 552 Q 660 560 668 560 L 795 560" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 525 438 L 752 438 Q 760 438 760 446 L 760 552 Q 760 560 768 560 L 995 560" class="a-dashed" stroke-width="1.5" marker-end="url(#arrowhead-dashed)"/>
<path d="M 610 402 L 753 402 Q 755 402 755 400 L 755 400 Q 755 398 757 398 L 900 398" class="a-emphasis" stroke-width="1.8" marker-end="url(#arrowhead-emphasis)"/>
<path d="M 1050 398 L 1110 398" class="a-default" stroke-width="1.5" marker-end="url(#arrowhead)"/>
<path d="M 1190 366 L 525 366" class="a-dashed" stroke-width="1.5" marker-end="url(#arrowhead-dashed)"/>
<path d="M 605 180 L 880 180" class="a-dashed" stroke-width="1.5" marker-end="url(#arrowhead-dashed)"/>
<!-- Components -->
<rect x="40" y="370" width="150" height="64" rx="6" class="c-mask"/>
<rect x="40" y="370" width="150" height="64" rx="6" class="c-messagebus" stroke-width="1.5"/>
<text x="115" y="400" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Ticket Queue</text>
<text x="115" y="416" class="t-muted" font-size="9" text-anchor="middle">bugs + small features</text>
<rect x="240" y="370" width="140" height="64" rx="6" class="c-mask"/>
<rect x="240" y="370" width="140" height="64" rx="6" class="c-security" stroke-width="1.5"/>
<text x="310" y="400" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Safety Gate</text>
<text x="310" y="416" class="t-muted" font-size="9" text-anchor="middle">no prod creds</text>
<text x="310" y="426" class="t-security" font-size="7" text-anchor="middle">sandboxed</text>
<rect x="440" y="366" width="170" height="72" rx="6" class="c-mask"/>
<rect x="440" y="366" width="170" height="72" rx="6" class="c-agent" stroke-width="1.5"/>
<text x="525" y="400" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Coding Agent</text>
<text x="525" y="416" class="t-muted" font-size="9" text-anchor="middle">plan, edit, test loop</text>
<rect x="455" y="150" width="150" height="60" rx="6" class="c-mask"/>
<rect x="455" y="150" width="150" height="60" rx="6" class="c-model" stroke-width="1.5"/>
<text x="530" y="178" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Model Gateway</text>
<text x="530" y="194" class="t-muted" font-size="9" text-anchor="middle">provider fallback</text>
<rect x="670" y="150" width="160" height="60" rx="6" class="c-mask"/>
<rect x="670" y="150" width="160" height="60" rx="6" class="c-eval" stroke-width="1.5"/>
<text x="750" y="178" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Test + Self-Review</text>
<text x="750" y="194" class="t-muted" font-size="9" text-anchor="middle">reflection</text>
<text x="750" y="202" class="t-eval" font-size="7" text-anchor="middle">in-loop</text>
<rect x="880" y="150" width="150" height="60" rx="6" class="c-mask"/>
<rect x="880" y="150" width="150" height="60" rx="6" class="c-cloud" stroke-width="1.5"/>
<text x="955" y="178" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Observability</text>
<text x="955" y="194" class="t-muted" font-size="9" text-anchor="middle">cost + traces</text>
<rect x="900" y="366" width="150" height="64" rx="6" class="c-mask"/>
<rect x="900" y="366" width="150" height="64" rx="6" class="c-backend" stroke-width="1.5"/>
<text x="975" y="396" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Pull Request</text>
<text x="975" y="412" class="t-muted" font-size="9" text-anchor="middle">never auto-merged</text>
<rect x="1110" y="366" width="160" height="64" rx="6" class="c-mask"/>
<rect x="1110" y="366" width="160" height="64" rx="6" class="c-human" stroke-width="1.5"/>
<text x="1190" y="396" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Code Review</text>
<text x="1190" y="412" class="t-muted" font-size="9" text-anchor="middle">human approves merge</text>
<rect x="300" y="560" width="150" height="60" rx="6" class="c-mask"/>
<rect x="300" y="560" width="150" height="60" rx="6" class="c-backend" stroke-width="1.5"/>
<text x="375" y="588" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Sandbox</text>
<text x="375" y="604" class="t-muted" font-size="9" text-anchor="middle">isolated exec</text>
<rect x="500" y="560" width="170" height="60" rx="6" class="c-mask"/>
<rect x="500" y="560" width="170" height="60" rx="6" class="c-backend" stroke-width="1.5"/>
<text x="585" y="588" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Repo Tools</text>
<text x="585" y="604" class="t-muted" font-size="9" text-anchor="middle">MCP: read, edit, branch</text>
<rect x="720" y="560" width="150" height="60" rx="6" class="c-mask"/>
<rect x="720" y="560" width="150" height="60" rx="6" class="c-backend" stroke-width="1.5"/>
<text x="795" y="588" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">CI Runner</text>
<text x="795" y="604" class="t-muted" font-size="9" text-anchor="middle">full suite, 25 min</text>
<rect x="920" y="560" width="150" height="60" rx="6" class="c-mask"/>
<rect x="920" y="560" width="150" height="60" rx="6" class="c-database" stroke-width="1.5"/>
<text x="995" y="588" class="t-primary" font-size="11" font-weight="600" text-anchor="middle">Run State</text>
<text x="995" y="604" class="t-muted" font-size="9" text-anchor="middle">checkpointed</text>
<!-- Connection labels -->
<rect x="195.6" y="382" width="38.8" height="14" rx="3" class="c-mask"/>
<text x="215" y="392" class="t-muted" font-size="8" text-anchor="middle">ticket</text>
<rect x="393" y="382" width="34" height="14" rx="3" class="c-mask"/>
<text x="410" y="392" class="t-muted" font-size="8" text-anchor="middle">admit</text>
<rect x="508.1" y="268" width="38.8" height="14" rx="3" class="c-mask"/>
<text x="527.5" y="278" class="t-muted" font-size="8" text-anchor="middle">reason</text>
<rect x="575.7" y="253" width="43.6" height="14" rx="3" class="c-mask"/>
<text x="597.5" y="263" class="t-messagebus" font-size="8" text-anchor="middle">reflect</text>
<rect x="663.4" y="479" width="53.199999999999996" height="14" rx="3" class="c-mask"/>
<text x="690" y="489" class="t-muted" font-size="8" text-anchor="middle">run tests</text>
<rect x="733.2" y="380" width="43.6" height="14" rx="3" class="c-mask"/>
<text x="755" y="390" class="t-backend" font-size="8" text-anchor="middle">open PR</text>
<rect x="1060.6" y="378" width="38.8" height="14" rx="3" class="c-mask"/>
<text x="1080" y="388" class="t-muted" font-size="8" text-anchor="middle">review</text>
<rect x="816.5" y="346" width="82" height="14" rx="3" class="c-mask"/>
<text x="857.5" y="356" class="t-messagebus" font-size="8" text-anchor="middle">review comments</text>
<!-- Legend -->
<text x="40" y="811" class="t-primary" font-size="9" font-weight="600">Legend</text>
<rect x="40" y="816" width="14" height="9" rx="2" class="c-messagebus" stroke-width="1"/>
<text x="60" y="824" class="t-muted" font-size="8">Queue</text>
<rect x="123" y="816" width="14" height="9" rx="2" class="c-security" stroke-width="1"/>
<text x="143" y="824" class="t-muted" font-size="8">Guardrail</text>
<rect x="226" y="816" width="14" height="9" rx="2" class="c-agent" stroke-width="1"/>
<text x="246" y="824" class="t-muted" font-size="8">Agent</text>
<rect x="309" y="816" width="14" height="9" rx="2" class="c-model" stroke-width="1"/>
<text x="329" y="824" class="t-muted" font-size="8">Model gateway</text>
<rect x="432" y="816" width="14" height="9" rx="2" class="c-eval" stroke-width="1"/>
<text x="452" y="824" class="t-muted" font-size="8">Eval loop</text>
<rect x="535" y="816" width="14" height="9" rx="2" class="c-cloud" stroke-width="1"/>
<text x="555" y="824" class="t-muted" font-size="8">Cloud</text>
<rect x="618" y="816" width="14" height="9" rx="2" class="c-backend" stroke-width="1"/>
<text x="638" y="824" class="t-muted" font-size="8">Backend</text>
<rect x="711" y="816" width="14" height="9" rx="2" class="c-human" stroke-width="1"/>
<text x="731" y="824" class="t-muted" font-size="8">Human review</text>
<rect x="829" y="816" width="14" height="9" rx="2" class="c-backend" stroke-width="1"/>
<text x="849" y="824" class="t-muted" font-size="8">Tool / MCP server</text>
<rect x="972" y="816" width="14" height="9" rx="2" class="c-database" stroke-width="1"/>
<text x="992" y="824" class="t-muted" font-size="8">Memory / state</text>
</svg><figcaption>Figure 1. The sandboxed runtime boundary holds the agent and its tools with no production access. Reflection (Test + Self-Review) is in the loop; the human review gate approves every merge.</figcaption></figure>
<table>
<thead><tr><th>Component</th><th>Serves</th><th>Scaling</th><th>Failure mode and fallback</th><th>Tech example</th></tr></thead>
<tbody>
<tr><td>Safety gate</td><td>Admission, credential stripping</td><td>Stateless</td><td>Reject ticket if sandbox unavailable</td><td>Policy check + sandbox provisioner</td></tr>
<tr><td>Coding agent</td><td>Plan, edit, test loop</td><td>One per ticket, horizontal</td><td>Retry budget then hand back</td><td>Sonnet-class model</td></tr>
<tr><td>Repo tools</td><td>Read, edit, branch</td><td>Stateless</td><td>Abort on write conflict</td><td>MCP server over the VCS <span class="cite">[knowledge/interoperability-observability.md]</span></td></tr>
<tr><td>Sandbox</td><td>Isolated execution</td><td>Ephemeral per job</td><td>Kill on resource or time cap</td><td>Container or microVM</td></tr>
<tr><td>CI runner</td><td>Ground-truth tests</td><td>Pooled, queued</td><td>Backpressure to the agent</td><td>Existing CI, 25 min suite</td></tr>
<tr><td>Test + self-review</td><td>In-loop reflection</td><td>Stateless</td><td>Bounded iterations</td><td>Evaluator-optimizer loop <span class="cite">[knowledge/agentic-design-patterns.md]</span></td></tr>
<tr><td>Run state</td><td>Checkpoint, resume</td><td>Durable store</td><td>Resume from last checkpoint</td><td>Durable execution store <span class="cite">[knowledge/context-memory.md]</span></td></tr>
<tr><td>Human review</td><td>Approves every merge</td><td>Human capacity</td><td>PR waits; never auto-merges</td><td>Existing code review</td></tr>
</tbody>
</table>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Draw the sandbox boundary first and put the human at the merge line. Everything else is inside a box that cannot reach production.</p>
<p><strong>Interviewer probes.</strong> What exactly is in the sandbox, and what secrets does the agent hold? How do you prevent code exfiltration?</p>
<p><strong>Tradeoffs to voice.</strong> Isolation versus iteration speed: tighter sandboxes are safer but slower to provision. Ephemeral microVMs per job is the balance.</p>
</details>
</section>
<section class="doc-section" id="data-retrieval">
<h2>5. Code retrieval</h2>
<p>The corpus is the monorepo. The agent does not load 30M LOC; it retrieves the files and symbols relevant to the ticket (code search plus embeddings over the repo), then works within that focused context <span class="cite">[knowledge/rag-patterns.md]</span>. A repo map plus retrieved files is cached across the agent's iterations to control token cost.</p>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Frame code as retrieval, not context stuffing. The repo map is the cheap always-on context; specific files are retrieved just in time.</p>
<p><strong>Interviewer probes.</strong> How does the agent find the right files in a 30M-LOC monorepo? What about cross-file changes?</p>
<p><strong>Tradeoffs to voice.</strong> Recall versus token budget: retrieving more files raises the chance of catching cross-file effects but costs tokens on every iteration.</p>
</details>
</section>
<section class="doc-section" id="tools">
<h2>6. Tools and integrations</h2>
<table>
<thead><tr><th>Tool</th><th>Tier</th><th>Enforcement</th></tr></thead>
<tbody>
<tr><td>read_code, search</td><td>0</td><td>Read-only, sandbox scope</td></tr>
<tr><td>edit_file, create_branch</td><td>1</td><td>Sandbox branch only, never the default branch</td></tr>
<tr><td>run_tests (CI)</td><td>0</td><td>Pooled runner, no prod targets</td></tr>
<tr><td>open_pull_request</td><td>1</td><td>PR only; merge permission not granted to the agent</td></tr>
</tbody>
</table>
<div class="callout risk"><span class="callout-label">The boundary that matters</span> There is no merge tool and no deploy tool in the registry. The agent literally cannot merge or ship, regardless of what it decides <span class="cite">[knowledge/security-governance.md]</span>.</div>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Enumerate tools by tier and point out the two that do not exist (merge, deploy). Absence is the enforcement.</p>
<p><strong>Interviewer probes.</strong> Could the agent open a PR that quietly weakens a security check? How would a reviewer catch it?</p>
<p><strong>Tradeoffs to voice.</strong> Autonomy versus reviewer load: broader edit permissions raise throughput but make human review harder. Keep diffs small and scoped.</p>
</details>
</section>
<section class="doc-section" id="state-memory">
<h2>7. State and memory</h2>
<p>Each run is checkpointed so a job interrupted at hour two can resume rather than restart, which matters for cost on long tickets <span class="cite">[knowledge/context-memory.md]</span>. There is no cross-ticket memory: every ticket starts clean, which keeps behavior predictable and avoids leaking one team's code context into another's.</p>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Checkpoint at natural boundaries (after a passing test run), not every token. Resumability is a cost lever, not just reliability.</p>
<p><strong>Interviewer probes.</strong> What happens if the model or sandbox dies mid-edit? Do you replay tool calls or restore state?</p>
<p><strong>Tradeoffs to voice.</strong> Checkpoint frequency versus overhead: more checkpoints resume better but cost storage and time.</p>
</details>
</section>
<section class="doc-section" id="security">
<h2>8. Security and safety</h2>
<p>Code exfiltration is the chief threat <span class="cite">[knowledge/security-governance.md]</span>. The lethal trifecta (private data, untrusted content, exfiltration channel) is broken by removing the channel: the sandbox has no outbound network beyond the model gateway and the VCS, and holds no production secrets.</p>
<table>
<thead><tr><th>Control</th><th>Purpose</th></tr></thead>
<tbody>
<tr><td>Sandbox with no prod creds or deploy access</td><td>Excessive agency, exfiltration</td></tr>
<tr><td>No merge or deploy tool</td><td>Irreversible-action prevention</td></tr>
<tr><td>Egress allowlist (model gateway, VCS only)</td><td>Code exfiltration</td></tr>
<tr><td>Prompt-injection handling on ticket text and code comments</td><td>LLM01, indirect injection from repo content</td></tr>
<tr><td>Full audit of tool calls and diffs</td><td>SOC 2, forensics</td></tr>
</tbody>
</table>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Name code exfiltration as the top risk and show how the egress allowlist and credential-free sandbox close it. Injection can come from a malicious code comment.</p>
<p><strong>Interviewer probes.</strong> A ticket description contains an injection telling the agent to add a backdoor. What stops the PR from shipping it?</p>
<p><strong>Tradeoffs to voice.</strong> Convenience versus containment: an egress allowlist blocks some legitimate package fetches; mirror them internally rather than open egress.</p>
</details>
</section>
<section class="doc-section" id="evaluation">
<h2>9. Evaluation plan</h2>
<p>Offline evals on a held-out set of historical tickets with known-good PRs, scored on tests-pass and diff similarity, before any live run <span class="cite">[knowledge/evaluation.md]</span>. Because tool agents are unreliable even at high single-run scores, measure pass^k across repeated attempts on the same ticket <span class="cite">[knowledge/evaluation.md]</span>. Online, track merged rate, human review minutes, and revert rate as the real signals.</p>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> CI is a built-in outcome eval: tests either pass or they do not. Layer trajectory review on top to catch tests that pass for the wrong reason.</p>
<p><strong>Interviewer probes.</strong> How do you know a merged PR was actually good, not just green? What is your regression signal?</p>
<p><strong>Tradeoffs to voice.</strong> Outcome versus process eval: green tests are necessary but not sufficient; revert rate and reviewer edits are the honest quality signal.</p>
</details>
</section>
<section class="doc-section" id="observability">
<h2>10. Observability</h2>
<p>Every ticket run is a trace: plan, each edit, each test run, each reflection, as spans with token and cost attribution, using OpenTelemetry GenAI conventions <span class="cite">[knowledge/interoperability-observability.md]</span>. Dashboards track merged rate, cost per attempted ticket against the 20 USD ceiling, retry-loop depth, and abandonment reasons; a cost anomaly or a spike in abandonment pages a human.</p>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Instrument cost per ticket and retry depth from day one: they are your early warning that the agent is grinding on tickets it should hand back.</p>
<p><strong>Interviewer probes.</strong> How do you debug a ticket that burned the full budget and produced nothing?</p>
<p><strong>Tradeoffs to voice.</strong> Detail versus noise: full trajectory traces are large; sample deep traces and always keep cost and outcome.</p>
</details>
</section>
<section class="doc-section" id="scale-cost">
<h2>11. Scale and cost analysis</h2>
<p>Model pricing used, <span class="cite">[live-sourced 2026-07-14]</span>: Sonnet 4.6 at 3.00 / 15.00 USD per million input / output tokens, prompt caching near 10% of input on cached tokens.</p>
<h3>Per-ticket cost</h3>
<p>A typical attempt runs roughly 15 to 25 model calls (plan, then edit-test iterations). Assume ~20 calls, each with ~10k cached context (repo map, system) plus ~20k fresh (retrieved files, diffs, test output) and ~1.5k output. Per call that is about 0.003 USD cached, 0.06 USD fresh input, and 0.023 USD output, near 0.086 USD. Twenty calls is roughly 1.70 USD, and hard tickets that iterate 50 times still land near 4 to 5 USD, comfortably under the 20 USD ceiling. CI and sandbox compute are the other cost line and are dominated by the 25 minute test suite.</p>
<h3>The real cost lever</h3>
<p>The ceiling is generous; the waste is tickets that will never land. Early abandonment (a retry budget and a confidence check after planning) protects both the per-ticket cost and the merged rate.</p>
<h3>At 10x (6,000 tickets/week)</h3>
<p>Token cost scales linearly and stays within the per-ticket ceiling, so the binding constraints move to CI throughput and sandbox provisioning, not model spend <span class="cite">[knowledge/latency-cost-reliability.md]</span>. A 25 minute suite times thousands of attempts needs a large CI pool or a smart subset-of-tests-first strategy, and sandbox provisioning must scale to hundreds of concurrent ephemeral environments.</p>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Show that model cost is not the constraint: CI capacity is. That reframes the scaling conversation away from tokens.</p>
<p><strong>Interviewer probes.</strong> At 10x, what breaks first? How do you keep CI cost sane when every attempt runs a 25 minute suite?</p>
<p><strong>Tradeoffs to voice.</strong> Thoroughness versus throughput: running the full suite every iteration is safe but expensive; run an impacted-tests subset first, full suite before the PR.</p>
</details>
</section>
<section class="doc-section" id="failure-modes">
<h2>12. Failure modes, degradation, and lifecycle</h2>
<p>The ticket state machine makes the terminal outcomes explicit: merged, handed back, or abandoned. Handing back cleanly is a feature, not a failure.</p>
<figure class="diagram-slot"><svg viewBox="0 0 1020 680" role="img" aria-label="Ticket Lifecycle: From queued ticket to merged, handed back, or abandoned, with a bounded retry loop (lifecycle diagram)">
<!-- Definitions -->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-default" />
</marker>
<marker id="arrowhead-emphasis" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-emphasis" />
</marker>
<marker id="arrowhead-security" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-security" />
</marker>
<marker id="arrowhead-dashed" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
<polygon points="0 0, 10 3.5, 0 7" class="m-dashed" />
</marker>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" class="c-grid" stroke-width="0.5"/>
</pattern>
</defs>
<!-- Background Grid -->
<rect width="100%" height="100%" fill="url(#grid)" />
<!-- Lifecycle bands -->
<path d="M 72 112 L 948 112" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
<text x="72" y="100" class="t-dim" font-size="10" font-weight="600">01 / Happy path</text>
<path d="M 72 264 L 948 264" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
<text x="72" y="252" class="t-dim" font-size="10" font-weight="600">02 / Human in loop + Retry loop</text>
<path d="M 72 436 L 948 436" class="a-default" stroke-width="0.8" stroke-dasharray="3,8"/>
<text x="72" y="424" class="t-dim" font-size="10" font-weight="600">03 / Terminal exits</text>
<!-- Primary lifecycle rail -->
<path d="M 154 157 L 748 157" class="a-emphasis" stroke-width="2.2" marker-end="url(#arrowhead-emphasis)"/>
<!-- Transition paths -->
<path d="M 153 157 L 189 157" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 307 157 L 343 157" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 461 157 L 497 157" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 615 157 L 651 157" class="a-emphasis" stroke-width="2" marker-end="url(#arrowhead-emphasis)"/>
<path d="M 615 157 L 615 257 Q 615 267 625 267 L 637 267 Q 647 267 647 277 L 647 377" class="a-security" stroke-width="1.1" marker-end="url(#arrowhead-security)"/>
<path d="M 647 377 L 647 277 Q 647 267 637 267 L 471 267 Q 461 267 461 257 L 461 157" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 710 188 L 710 233 L 710 233 L 710 278" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 647 307 L 647 242 Q 647 232 637 232 L 471 232 Q 461 232 461 222 L 461 157" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 651 157 L 651 308 Q 651 318 641 318 L 471 318 Q 461 318 461 328 L 461 479" class="a-emphasis" stroke-width="2" marker-end="url(#arrowhead-emphasis)"/>
<path d="M 307 157 L 307 308 Q 307 318 317 318 L 487 318 Q 497 318 497 328 L 497 479" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<path d="M 710 406 L 710 428 L 710 428 L 710 450" class="a-default" stroke-width="1.1" marker-end="url(#arrowhead)"/>
<!-- States -->
<rect x="35" y="126" width="118" height="62" rx="7" class="c-mask"/>
<rect x="35" y="126" width="118" height="62" rx="7" class="c-frontend" stroke-width="1.5"/>
<text x="45" y="140" class="t-frontend" font-size="7" font-weight="700">01</text>
<text x="94" y="147" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Queued</text>
<text x="94" y="163" class="t-muted" font-size="7" text-anchor="middle">ticket accepted</text>
<text x="94" y="177" class="t-frontend" font-size="7" text-anchor="middle">entry</text>
<rect x="189" y="126" width="118" height="62" rx="7" class="c-mask"/>
<rect x="189" y="126" width="118" height="62" rx="7" class="c-backend" stroke-width="1.5"/>
<text x="199" y="140" class="t-backend" font-size="7" font-weight="700">02</text>
<text x="248" y="147" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Planning</text>
<text x="248" y="163" class="t-muted" font-size="7" text-anchor="middle">scope the change</text>
<text x="248" y="177" class="t-backend" font-size="7" text-anchor="middle">model</text>
<rect x="343" y="126" width="118" height="62" rx="7" class="c-mask"/>
<rect x="343" y="126" width="118" height="62" rx="7" class="c-backend" stroke-width="1.5"/>
<text x="353" y="140" class="t-backend" font-size="7" font-weight="700">03</text>
<text x="402" y="147" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Editing</text>
<text x="402" y="163" class="t-muted" font-size="7" text-anchor="middle">write code</text>
<text x="402" y="177" class="t-backend" font-size="7" text-anchor="middle">work</text>
<rect x="497" y="126" width="118" height="62" rx="7" class="c-mask"/>
<rect x="497" y="126" width="118" height="62" rx="7" class="c-security" stroke-width="1.5"/>
<text x="507" y="140" class="t-security" font-size="7" font-weight="700">04</text>
<text x="556" y="147" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Testing</text>
<text x="556" y="163" class="t-muted" font-size="7" text-anchor="middle">run CI + self-review</text>
<text x="556" y="177" class="t-security" font-size="7" text-anchor="middle">gate</text>
<rect x="651" y="126" width="118" height="62" rx="7" class="c-mask"/>
<rect x="651" y="126" width="118" height="62" rx="7" class="c-backend" stroke-width="1.5"/>
<text x="661" y="140" class="t-backend" font-size="7" font-weight="700">05</text>
<text x="710" y="147" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">PR Open</text>
<text x="710" y="163" class="t-muted" font-size="7" text-anchor="middle">awaiting review</text>
<text x="710" y="177" class="t-backend" font-size="7" text-anchor="middle">output</text>
<rect x="647" y="278" width="126" height="58" rx="7" class="c-mask"/>
<rect x="647" y="278" width="126" height="58" rx="7" class="c-cloud" stroke-width="1.5"/>
<text x="710" y="299" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Addressing Review</text>
<text x="710" y="315" class="t-muted" font-size="7" text-anchor="middle">human comments</text>
<text x="710" y="325" class="t-cloud" font-size="7" text-anchor="middle">human</text>
<rect x="647" y="348" width="126" height="58" rx="7" class="c-mask"/>
<rect x="647" y="348" width="126" height="58" rx="7" class="c-security" stroke-width="1.5"/>
<text x="710" y="369" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Tests Failed</text>
<text x="710" y="385" class="t-muted" font-size="7" text-anchor="middle">bounded retries</text>
<text x="710" y="395" class="t-security" font-size="7" text-anchor="middle">retryable</text>
<rect x="343" y="450" width="118" height="58" rx="7" class="c-mask"/>
<rect x="343" y="450" width="118" height="58" rx="7" class="c-database" stroke-width="1.5"/>
<text x="402" y="471" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Merged</text>
<text x="402" y="487" class="t-muted" font-size="7" text-anchor="middle">human approved</text>
<text x="402" y="497" class="t-database" font-size="7" text-anchor="middle">terminal</text>
<rect x="497" y="450" width="118" height="58" rx="7" class="c-mask"/>
<rect x="497" y="450" width="118" height="58" rx="7" class="c-security" stroke-width="1.5"/>
<text x="556" y="471" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Handed Back</text>
<text x="556" y="487" class="t-muted" font-size="7" text-anchor="middle">needs a human</text>
<text x="556" y="497" class="t-security" font-size="7" text-anchor="middle">terminal</text>
<rect x="651" y="450" width="118" height="58" rx="7" class="c-mask"/>
<rect x="651" y="450" width="118" height="58" rx="7" class="c-security" stroke-width="1.5"/>
<text x="710" y="471" class="t-primary" font-size="10" font-weight="600" text-anchor="middle">Abandoned</text>
<text x="710" y="487" class="t-muted" font-size="7" text-anchor="middle">retry budget spent</text>
<text x="710" y="497" class="t-security" font-size="7" text-anchor="middle">terminal</text>
<!-- Transition labels -->
<rect x="617" y="136" width="32" height="16" rx="4" class="c-mask"/>
<text x="633" y="147" class="t-backend" font-size="8" text-anchor="middle">pass</text>
<rect x="530.4" y="297" width="51.2" height="16" rx="4" class="c-mask"/>
<text x="556" y="308" class="t-backend" font-size="8" text-anchor="middle">approved</text>
<!-- Legend -->
<text x="220" y="562" class="t-primary" font-size="10" font-weight="600">Legend</text>
<rect x="220" y="574" width="14" height="9" rx="2" class="c-backend" stroke-width="1"/>
<text x="240" y="582" class="t-muted" font-size="7">active state</text>
<rect x="325" y="574" width="14" height="9" rx="2" class="c-cloud" stroke-width="1"/>
<text x="345" y="582" class="t-muted" font-size="7">waiting</text>
<rect x="415" y="574" width="14" height="9" rx="2" class="c-database" stroke-width="1"/>
<text x="435" y="582" class="t-muted" font-size="7">terminal success</text>
<rect x="560" y="574" width="14" height="9" rx="2" class="c-security" stroke-width="1"/>
<text x="580" y="582" class="t-muted" font-size="7">failure / exit</text>
</svg><figcaption>Figure 2. Ticket lifecycle. The retry loop between Editing and Testing is bounded; when the budget is spent the ticket is abandoned, and unclear scope is handed back to a human early.</figcaption></figure>
<table>
<thead><tr><th>Failure</th><th>Handling</th></tr></thead>
<tbody>
<tr><td>Tests keep failing</td><td>Bounded retries, then abandon with a summary of what was tried</td></tr>
<tr><td>Scope too large</td><td>Detected at planning, handed back to a human immediately</td></tr>
<tr><td>Flaky test</td><td>Retry once; if it flips, flag rather than chase</td></tr>
<tr><td>Model or sandbox crash</td><td>Resume from the last checkpoint <span class="cite">[knowledge/latency-cost-reliability.md]</span></td></tr>
<tr><td>Reviewer requests changes</td><td>Re-enter the edit loop from the PR comments</td></tr>
</tbody>
</table>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Treat handing back as a first-class success path. An agent that knows its limits is more valuable than one that always produces a PR.</p>
<p><strong>Interviewer probes.</strong> How does the agent know when to give up? What stops an infinite edit-test loop?</p>
<p><strong>Tradeoffs to voice.</strong> Persistence versus waste: a higher retry budget lands more hard tickets but burns cost on hopeless ones; tune the budget from the abandonment data.</p>
</details>
</section>
<section class="doc-section" id="rollout">
<h2>13. Rollout plan</h2>
<ol>
<li><strong>Crawl:</strong> shadow mode on closed historical tickets, comparing the agent's PR to the human's. Gate: offline tests-pass and diff quality <span class="cite">[knowledge/evaluation.md]</span>.</li>
<li><strong>Walk:</strong> live on a few low-risk services, one team, PRs clearly labeled as agent-authored. Gate: merged rate and review-time targets, zero incidents.</li>
<li><strong>Run:</strong> expand service by service. The abandonment and revert data continuously retunes eligibility and the retry budget <span class="cite">[knowledge/genai-sysdesign-loop.md]</span>.</li>
</ol>
<details class="interview"><summary>Interview notes</summary>
<p><strong>Strong answer.</strong> Start in shadow against known-good PRs: it is a free, safe eval with ground truth. Expand by service risk, not all at once.</p>
<p><strong>Interviewer probes.</strong> How do you build reviewer trust so the 10-minute review target is realistic?</p>
<p><strong>Tradeoffs to voice.</strong> Speed of rollout versus trust: moving fast risks a bad merge that poisons adoption; expand only as the revert rate stays near zero.</p>
</details>
</section>
<section class="doc-section" id="references">
<h2>14. References</h2>
<h3>Knowledge base</h3>
<ul>
<li>knowledge/decision-trees.md, building-effective-agents.md, agentic-design-patterns.md (rung 3, reflection, single vs multi-agent)</li>
<li>knowledge/multi-agent-orchestration.md (the token economics behind rejecting multi-agent)</li>
<li>knowledge/security-governance.md (sandboxing, exfiltration, autonomy tiers), rag-patterns.md (code retrieval)</li>
<li>knowledge/evaluation.md (pass^k, CI as eval, shadow mode), context-memory.md (checkpointing)</li>
<li>knowledge/latency-cost-reliability.md, interoperability-observability.md (CI scaling, tracing)</li>
</ul>
<h3>Live-sourced</h3>
<ul><li>Anthropic API pricing, retrieved 2026-07-14, for the cost model in section 11.</li></ul>
<p>Primary-source citations for each knowledge document are in agentify/knowledge/SOURCES.md.</p>
</section>
</main>
</div>
<script>
// Build the TOC from section h2s.
(function () {
var list = document.getElementById('toc-list');
var sections = document.querySelectorAll('main section.doc-section');
sections.forEach(function (sec) {
var h2 = sec.querySelector('h2');
if (!h2 || !sec.id) return;
var li = document.createElement('li');
var a = document.createElement('a');
a.href = '#' + sec.id;
a.textContent = h2.textContent;
li.appendChild(a);
list.appendChild(li);
});
// Highlight the section in view.
var links = list.querySelectorAll('a');