@principal-ai/subsystems-react 0.53.6 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/index.d.ts +8 -2
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +3 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/pierre/PierreTrailCodeView.d.ts.map +1 -1
  6. package/dist/pierre/PierreTrailCodeView.js +7 -5
  7. package/dist/pierre/PierreTrailCodeView.js.map +1 -1
  8. package/dist/stories/Subsystem/ComponentGraph/fixtures.d.ts.map +1 -1
  9. package/dist/stories/Subsystem/ComponentGraph/fixtures.js +1 -2
  10. package/dist/stories/Subsystem/ComponentGraph/fixtures.js.map +1 -1
  11. package/dist/subsystem/C4Graph.d.ts +144 -9
  12. package/dist/subsystem/C4Graph.d.ts.map +1 -1
  13. package/dist/subsystem/C4Graph.js +924 -148
  14. package/dist/subsystem/C4Graph.js.map +1 -1
  15. package/dist/subsystem/C4NodeCard.d.ts +22 -1
  16. package/dist/subsystem/C4NodeCard.d.ts.map +1 -1
  17. package/dist/subsystem/C4NodeCard.js +10 -2
  18. package/dist/subsystem/C4NodeCard.js.map +1 -1
  19. package/dist/subsystem/ComponentDeclaration.d.ts +5 -4
  20. package/dist/subsystem/ComponentDeclaration.d.ts.map +1 -1
  21. package/dist/subsystem/ComponentDeclaration.js +12 -4
  22. package/dist/subsystem/ComponentDeclaration.js.map +1 -1
  23. package/dist/subsystem/ConstructsCatalog.d.ts.map +1 -1
  24. package/dist/subsystem/ConstructsCatalog.js +10 -7
  25. package/dist/subsystem/ConstructsCatalog.js.map +1 -1
  26. package/dist/subsystem/GraphSidebar.d.ts +71 -0
  27. package/dist/subsystem/GraphSidebar.d.ts.map +1 -0
  28. package/dist/subsystem/GraphSidebar.js +145 -0
  29. package/dist/subsystem/GraphSidebar.js.map +1 -0
  30. package/dist/subsystem/GraphWithSidebar.d.ts +24 -0
  31. package/dist/subsystem/GraphWithSidebar.d.ts.map +1 -0
  32. package/dist/subsystem/GraphWithSidebar.js +25 -0
  33. package/dist/subsystem/GraphWithSidebar.js.map +1 -0
  34. package/dist/subsystem/IssueList.d.ts +4 -5
  35. package/dist/subsystem/IssueList.d.ts.map +1 -1
  36. package/dist/subsystem/IssueList.js +33 -28
  37. package/dist/subsystem/IssueList.js.map +1 -1
  38. package/dist/subsystem/SubsystemComponentGraph.d.ts +33 -0
  39. package/dist/subsystem/SubsystemComponentGraph.d.ts.map +1 -1
  40. package/dist/subsystem/SubsystemComponentGraph.js +367 -414
  41. package/dist/subsystem/SubsystemComponentGraph.js.map +1 -1
  42. package/dist/subsystem/TrailStepsNav.d.ts +48 -0
  43. package/dist/subsystem/TrailStepsNav.d.ts.map +1 -0
  44. package/dist/subsystem/TrailStepsNav.js +189 -0
  45. package/dist/subsystem/TrailStepsNav.js.map +1 -0
  46. package/dist/subsystem/TrailsPanel.d.ts.map +1 -1
  47. package/dist/subsystem/TrailsPanel.js +3 -4
  48. package/dist/subsystem/TrailsPanel.js.map +1 -1
  49. package/dist/subsystem/__fixtures__/c4Drilldown.d.ts +151 -0
  50. package/dist/subsystem/__fixtures__/c4Drilldown.d.ts.map +1 -0
  51. package/dist/subsystem/__fixtures__/c4Drilldown.js +783 -0
  52. package/dist/subsystem/__fixtures__/c4Drilldown.js.map +1 -0
  53. package/dist/subsystem/c4.d.ts +39 -8
  54. package/dist/subsystem/c4.d.ts.map +1 -1
  55. package/dist/subsystem/c4.js.map +1 -1
  56. package/dist/subsystem/declarationRef.d.ts +26 -18
  57. package/dist/subsystem/declarationRef.d.ts.map +1 -1
  58. package/dist/subsystem/declarationRef.js +9 -4
  59. package/dist/subsystem/declarationRef.js.map +1 -1
  60. package/dist/subsystem/model.d.ts +19 -1
  61. package/dist/subsystem/model.d.ts.map +1 -1
  62. package/dist/subsystem/model.js +12 -2
  63. package/dist/subsystem/model.js.map +1 -1
  64. package/dist/subsystem/nodes.d.ts.map +1 -1
  65. package/dist/subsystem/nodes.js +24 -4
  66. package/dist/subsystem/nodes.js.map +1 -1
  67. package/dist/subsystem/trailBrief.d.ts.map +1 -1
  68. package/dist/subsystem/trailBrief.js +6 -1
  69. package/dist/subsystem/trailBrief.js.map +1 -1
  70. package/package.json +3 -3
  71. package/src/index.ts +9 -2
  72. package/src/pierre/PierreTrailCodeView.tsx +9 -13
  73. package/src/stories/Subsystem/C4Graph/C4ToComponentDrill.stories.tsx +496 -0
  74. package/src/stories/Subsystem/ComponentGraph/AnimatedProgression.stories.tsx +7 -7
  75. package/src/stories/Subsystem/ComponentGraph/Constructs.stories.tsx +19 -25
  76. package/src/stories/Subsystem/ComponentGraph/DetailPanel.stories.tsx +8 -10
  77. package/src/stories/Subsystem/ComponentGraph/Issues.stories.tsx +40 -33
  78. package/src/stories/Subsystem/ComponentGraph/ProposedTrails.stories.tsx +6 -6
  79. package/src/stories/Subsystem/ComponentGraph/TrailAutoplay.stories.tsx +7 -7
  80. package/src/stories/Subsystem/ComponentGraph/Trails.stories.tsx +27 -30
  81. package/src/stories/Subsystem/ComponentGraph/fixtures.ts +1 -2
  82. package/src/stories/Subsystem/ConstructsCatalog.stories.tsx +10 -13
  83. package/src/stories/Subsystem/EgoGraph/EgoGraph.stories.tsx +3 -4
  84. package/src/stories/Subsystem/IssueIcons.stories.tsx +65 -0
  85. package/src/stories/Subsystem/Sidebar/GraphSidebar.stories.tsx +206 -0
  86. package/src/subsystem/C4Graph.groups.test.ts +96 -2
  87. package/src/subsystem/C4Graph.tsx +1377 -165
  88. package/src/subsystem/C4NodeCard.test.ts +1 -2
  89. package/src/subsystem/C4NodeCard.tsx +24 -2
  90. package/src/subsystem/ComponentDeclaration.tsx +18 -8
  91. package/src/subsystem/ConstructsCatalog.tsx +23 -8
  92. package/src/subsystem/GraphSidebar.test.tsx +152 -0
  93. package/src/subsystem/GraphSidebar.tsx +300 -0
  94. package/src/subsystem/GraphWithSidebar.test.tsx +78 -0
  95. package/src/subsystem/GraphWithSidebar.tsx +60 -0
  96. package/src/subsystem/IssueList.tsx +34 -29
  97. package/src/subsystem/SubsystemComponentGraph.tsx +290 -376
  98. package/src/subsystem/TrailStepsNav.test.tsx +179 -0
  99. package/src/subsystem/TrailStepsNav.tsx +372 -0
  100. package/src/subsystem/TrailsPanel.tsx +3 -4
  101. package/src/subsystem/__fixtures__/c4Drilldown.test.ts +338 -0
  102. package/src/subsystem/__fixtures__/c4Drilldown.ts +847 -0
  103. package/src/subsystem/c4.ts +41 -8
  104. package/src/subsystem/declarationRef.ts +28 -19
  105. package/src/subsystem/model.test.ts +32 -12
  106. package/src/subsystem/model.ts +30 -1
  107. package/src/subsystem/nodes.group.test.tsx +82 -0
  108. package/src/subsystem/nodes.tsx +30 -2
  109. package/src/subsystem/trailBrief.test.ts +2 -2
  110. package/src/subsystem/trailBrief.ts +6 -1
@@ -72,9 +72,9 @@ const ISSUES: SubsystemIssue[] = [
72
72
  },
73
73
  {
74
74
  id: 'i20',
75
- severity: 'info',
76
- kind: 'step_unconfirmed',
77
- message: 'Trail "Story steps" step 1: call site not verified (entry → store via writes)',
75
+ severity: 'error',
76
+ kind: 'step_span_unconfirmed',
77
+ message: 'Trail "Story steps" step 1: step span not captured (entry → store via writes)',
78
78
  target: {
79
79
  kind: 'step',
80
80
  id: 'story-steps',
@@ -86,8 +86,8 @@ const ISSUES: SubsystemIssue[] = [
86
86
  {
87
87
  id: 'i21',
88
88
  severity: 'info',
89
- kind: 'step_stale',
90
- message: 'Trail "Story steps" step 2: call site changed since verification (lines 42-44 in src/checkout/api.ts)',
89
+ kind: 'step_span_stale',
90
+ message: 'Trail "Story steps" step 2: step span changed since verification (lines 42-44 in src/checkout/api.ts)',
91
91
  target: {
92
92
  kind: 'step',
93
93
  id: 'story-steps',
@@ -120,8 +120,8 @@ const ISSUES: SubsystemIssue[] = [
120
120
  },
121
121
  {
122
122
  id: 'i9',
123
- severity: 'error',
124
- kind: 'stale_declaration',
123
+ severity: 'info',
124
+ kind: 'construct_span_stale',
125
125
  message: 'Declaration moved since capture — recorded start line 42, now 57.',
126
126
  target: { kind: 'component', id: 'session-store', label: 'SessionStore' },
127
127
  fix: { label: 'Re-pin declaration' },
@@ -133,6 +133,13 @@ const ISSUES: SubsystemIssue[] = [
133
133
  message: 'Graphify anchored the node but left the construct unclassified (interface vs type alias).',
134
134
  target: { kind: 'component', id: 'host-info', label: 'HostInfo' },
135
135
  },
136
+ {
137
+ id: 'i22',
138
+ severity: 'error',
139
+ kind: 'construct_span_unconfirmed',
140
+ message: 'HostInfo has no captured source span — its declaration extent is unpinned until an agent proposes start/end lines.',
141
+ target: { kind: 'component', id: 'host-info', label: 'HostInfo' },
142
+ },
136
143
  {
137
144
  id: 'i11',
138
145
  severity: 'error',
@@ -216,7 +223,7 @@ const TRAIL_STEP_ISSUES: SubsystemIssue[] = [
216
223
  {
217
224
  id: 'ts1',
218
225
  severity: 'info',
219
- kind: 'step_unconfirmed',
226
+ kind: 'step_span_unconfirmed',
220
227
  message: 'Trail "Add to Cart" step 1: call site not verified (addToCart → cartStore via writes)',
221
228
  target: {
222
229
  kind: 'step',
@@ -229,7 +236,7 @@ const TRAIL_STEP_ISSUES: SubsystemIssue[] = [
229
236
  {
230
237
  id: 'ts2',
231
238
  severity: 'info',
232
- kind: 'step_unconfirmed',
239
+ kind: 'step_span_unconfirmed',
233
240
  message: 'Trail "Add to Cart" step 2: call site not verified (cartStore → inventoryService via calls)',
234
241
  target: {
235
242
  kind: 'step',
@@ -242,7 +249,7 @@ const TRAIL_STEP_ISSUES: SubsystemIssue[] = [
242
249
  {
243
250
  id: 'ts3',
244
251
  severity: 'info',
245
- kind: 'step_stale',
252
+ kind: 'step_span_stale',
246
253
  message: 'Trail "Checkout" step 1: call site changed since verification (lines 42-44 in src/checkout/api.ts)',
247
254
  target: {
248
255
  kind: 'step',
@@ -255,7 +262,7 @@ const TRAIL_STEP_ISSUES: SubsystemIssue[] = [
255
262
  {
256
263
  id: 'ts4',
257
264
  severity: 'info',
258
- kind: 'step_stale',
265
+ kind: 'step_span_stale',
259
266
  message: 'Trail "Checkout" step 3: call site changed since verification (lines 78-82 in src/checkout/api.ts)',
260
267
  target: {
261
268
  kind: 'step',
@@ -302,7 +309,7 @@ const stepVerificationIssues: SubsystemIssue[] = [
302
309
  {
303
310
  id: 'sv1',
304
311
  severity: 'info',
305
- kind: 'step_unconfirmed',
312
+ kind: 'step_span_unconfirmed',
306
313
  message: 'Trail "Checkout" step 1: call site not verified (checkoutApi → cartStore via writes)',
307
314
  target: {
308
315
  kind: 'step',
@@ -315,7 +322,7 @@ const stepVerificationIssues: SubsystemIssue[] = [
315
322
  {
316
323
  id: 'sv2',
317
324
  severity: 'info',
318
- kind: 'step_stale',
325
+ kind: 'step_span_stale',
319
326
  message: 'Trail "Checkout" step 2: call site changed since verification (lines 42-44 in src/checkout/api.ts)',
320
327
  target: {
321
328
  kind: 'step',
@@ -646,7 +653,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
646
653
  to: 'maintain-rpc-handler',
647
654
  mechanism: 'calls',
648
655
  file: 'packages/subsystems-studio/src/mainview/components/MaintainModelPickerModal.tsx',
649
- line: 116,
656
+ span: { startLine: 116, endLine: 116, contentHash: 'fixture' },
650
657
  symbol: 'MaintainModelPickerModal',
651
658
  purl: `${PURL}#packages/subsystems-studio/src/mainview/components/MaintainModelPickerModal.tsx`,
652
659
  annotation: 'Fire the maintainSubsystemModel RPC with the selected model.',
@@ -656,7 +663,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
656
663
  to: 'maintain-background-runner',
657
664
  mechanism: 'calls',
658
665
  file: 'packages/subsystems-studio/src/bun/index.ts',
659
- line: 2522,
666
+ span: { startLine: 2522, endLine: 2522, contentHash: 'fixture' },
660
667
  symbol: 'maintainSubsystemModelInBackground',
661
668
  purl: `${PURL}#packages/subsystems-studio/src/bun/index.ts`,
662
669
  annotation: 'RPC returns started:true immediately and hands off to the guarded runner.',
@@ -666,7 +673,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
666
673
  to: 'maintain-orchestrator',
667
674
  mechanism: 'calls',
668
675
  file: 'packages/subsystems-studio/src/bun/index.ts',
669
- line: 3160,
676
+ span: { startLine: 3160, endLine: 3160, contentHash: 'fixture' },
670
677
  symbol: 'maintainSubsystemModelInBackground',
671
678
  purl: `${PURL}#packages/subsystems-studio/src/bun/index.ts`,
672
679
  annotation: 'Run the full install → audit → route-by-verdict → brief pipeline.',
@@ -676,7 +683,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
676
683
  to: 'maintain-agent-launcher',
677
684
  mechanism: 'calls',
678
685
  file: 'packages/subsystems-studio/src/bun/maintain-model.ts',
679
- line: 854,
686
+ span: { startLine: 854, endLine: 854, contentHash: 'fixture' },
680
687
  symbol: 'runMaintainAgent',
681
688
  purl: `${PURL}#packages/subsystems-studio/src/bun/maintain-model.ts`,
682
689
  annotation: 'Resolve the model then launch the agent run, retrying once on the credentialed fallback if unusable.',
@@ -686,7 +693,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
686
693
  to: 'session-runner',
687
694
  mechanism: 'calls',
688
695
  file: 'packages/subsystems-studio/src/bun/maintain-model.ts',
689
- line: 742,
696
+ span: { startLine: 742, endLine: 742, contentHash: 'fixture' },
690
697
  symbol: 'runOpencodeV2AgentSession',
691
698
  purl: `${PURL}#packages/subsystems-studio/src/bun/maintain-model.ts`,
692
699
  annotation: 'Hand the brief, agent, and directory to the V2 session runner.',
@@ -696,7 +703,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
696
703
  to: 'events-tab',
697
704
  mechanism: 'calls',
698
705
  file: 'packages/subsystems-studio/src/bun/index.ts',
699
- line: 3164,
706
+ span: { startLine: 3164, endLine: 3164, contentHash: 'fixture' },
700
707
  symbol: 'maintainSubsystemModelInBackground',
701
708
  purl: `${PURL}#packages/subsystems-studio/src/bun/index.ts`,
702
709
  annotation: 'Open the live feed tab the instant the session id exists.',
@@ -712,7 +719,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
712
719
  to: 'sse-feed-reader',
713
720
  mechanism: 'calls',
714
721
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
715
- line: 355,
722
+ span: { startLine: 355, endLine: 355, contentHash: 'fixture' },
716
723
  symbol: 'runOpencodeV2AgentSession',
717
724
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
718
725
  annotation: 'Open the /api/event subscription before creating the session.',
@@ -722,7 +729,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
722
729
  to: 'opencode-v2-server',
723
730
  mechanism: 'watches',
724
731
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
725
- line: 222,
732
+ span: { startLine: 222, endLine: 222, contentHash: 'fixture' },
726
733
  symbol: 'readSse',
727
734
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
728
735
  annotation: "Stream the single SSE feed that carries every session's events.",
@@ -732,7 +739,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
732
739
  to: 'service-ensurer',
733
740
  mechanism: 'calls',
734
741
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
735
- line: 326,
742
+ span: { startLine: 326, endLine: 326, contentHash: 'fixture' },
736
743
  symbol: 'runOpencodeV2AgentSession',
737
744
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
738
745
  annotation: 'Ensure the opencode2 daemon is healthy, starting the service if it is not.',
@@ -742,7 +749,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
742
749
  to: 'opencode-v2-server',
743
750
  mechanism: 'calls',
744
751
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
745
- line: 384,
752
+ span: { startLine: 384, endLine: 384, contentHash: 'fixture' },
746
753
  symbol: 'runOpencodeV2AgentSession',
747
754
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
748
755
  annotation: 'POST /api/session creates the session with a 15s HTTP timeout.',
@@ -752,7 +759,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
752
759
  to: 'opencode-v2-server',
753
760
  mechanism: 'calls',
754
761
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
755
- line: 428,
762
+ span: { startLine: 428, endLine: 428, contentHash: 'fixture' },
756
763
  symbol: 'runOpencodeV2AgentSession',
757
764
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
758
765
  annotation: 'POST /api/session/{id}/prompt feeds the maintain brief with a 15s HTTP timeout.',
@@ -762,7 +769,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
762
769
  to: 'terminal-matcher',
763
770
  mechanism: 'calls',
764
771
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
765
- line: 365,
772
+ span: { startLine: 365, endLine: 365, contentHash: 'fixture' },
766
773
  symbol: 'readSse',
767
774
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
768
775
  annotation: 'Flag sawTerminal when the event is an execution finish or session idle.',
@@ -772,7 +779,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
772
779
  to: 'session-runner',
773
780
  mechanism: 'feeds',
774
781
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
775
- line: 469,
782
+ span: { startLine: 469, endLine: 469, contentHash: 'fixture' },
776
783
  symbol: 'runOpencodeV2AgentSession',
777
784
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
778
785
  annotation: 'Wait loop polls every 400ms until sawTerminal or the 15-minute deadline.',
@@ -782,7 +789,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
782
789
  to: 'maintain-probe-registry',
783
790
  mechanism: 'reads',
784
791
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
785
- line: 484,
792
+ span: { startLine: 484, endLine: 484, contentHash: 'fixture' },
786
793
  symbol: 'runOpencodeV2AgentSession',
787
794
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
788
795
  annotation: "Confirm the model's first tool call landed the liveness probe; abort as unusable on timeout.",
@@ -792,7 +799,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
792
799
  to: 'live-feed-store',
793
800
  mechanism: 'writes',
794
801
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
795
- line: 529,
802
+ span: { startLine: 529, endLine: 529, contentHash: 'fixture' },
796
803
  symbol: 'runOpencodeV2AgentSession',
797
804
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
798
805
  annotation: 'Stamp the feed done (or error) when the wait loop exits.',
@@ -802,7 +809,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
802
809
  to: 'maintain-picker',
803
810
  mechanism: 'feeds',
804
811
  file: 'packages/subsystems-studio/src/bun/index.ts',
805
- line: 3187,
812
+ span: { startLine: 3187, endLine: 3187, contentHash: 'fixture' },
806
813
  symbol: 'maintainSubsystemModelInBackground',
807
814
  purl: `${PURL}#packages/subsystems-studio/src/bun/index.ts`,
808
815
  annotation: 'Broadcast done/error so the Maintain row flips off Running.',
@@ -818,7 +825,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
818
825
  to: 'probe-route',
819
826
  mechanism: 'calls',
820
827
  file: 'packages/subsystems-studio/src/bun/http-server.ts',
821
- line: 314,
828
+ span: { startLine: 314, endLine: 314, contentHash: 'fixture' },
822
829
  symbol: 'handleSubsystemModelRequest',
823
830
  purl: `${PURL}#packages/subsystems-studio/src/bun/http-server.ts`,
824
831
  annotation: "The agent's step-0 tool call curls POST /api/maintainer/probe with the run token.",
@@ -828,7 +835,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
828
835
  to: 'maintain-probe-registry',
829
836
  mechanism: 'writes',
830
837
  file: 'packages/subsystems-studio/src/bun/http-server.ts',
831
- line: 318,
838
+ span: { startLine: 318, endLine: 318, contentHash: 'fixture' },
832
839
  symbol: 'getMaintainerProbeRegistry',
833
840
  purl: `${PURL}#packages/subsystems-studio/src/bun/http-server.ts`,
834
841
  annotation: 'mark(runId) records when the probe landed.',
@@ -838,7 +845,7 @@ const MAINTAIN_TRAILS: SubsystemTrail[] = [
838
845
  to: 'maintain-probe-registry',
839
846
  mechanism: 'reads',
840
847
  file: 'packages/subsystems-studio/src/bun/opencode-v2-live.ts',
841
- line: 484,
848
+ span: { startLine: 484, endLine: 484, contentHash: 'fixture' },
842
849
  symbol: 'runOpencodeV2AgentSession',
843
850
  purl: `${PURL}#packages/subsystems-studio/src/bun/opencode-v2-live.ts`,
844
851
  annotation: 'Each loop tick checks whether the token landed before the probe deadline.',
@@ -875,7 +882,7 @@ const MAINTAIN_ISSUES: SubsystemIssue[] = [
875
882
  {
876
883
  id: 'mr-decl',
877
884
  severity: 'error',
878
- kind: 'stale_declaration',
885
+ kind: 'construct_span_stale',
879
886
  message: 'Declaration moved since capture — recorded start line 2522, now 2588.',
880
887
  target: {
881
888
  kind: 'component',
@@ -92,7 +92,7 @@ const trails: SubsystemTrail[] = [
92
92
  to: 'maintain',
93
93
  mechanism: 'calls',
94
94
  file: 'src/bun/verify-subsystem-component.ts',
95
- line: 1,
95
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
96
96
  symbol: 'auditSubsystemModel',
97
97
  annotation: 'Live-only trail — no proposed badge.',
98
98
  },
@@ -107,7 +107,7 @@ const trails: SubsystemTrail[] = [
107
107
  to: 'maintain',
108
108
  mechanism: 'calls',
109
109
  file: 'src/bun/verify-subsystem-component.ts',
110
- line: 1,
110
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
111
111
  symbol: 'auditSubsystemModel',
112
112
  },
113
113
  {
@@ -115,7 +115,7 @@ const trails: SubsystemTrail[] = [
115
115
  to: 'lifecycle',
116
116
  mechanism: 'uses',
117
117
  file: 'src/bun/maintain-model.ts',
118
- line: 1,
118
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
119
119
  symbol: 'runMaintainModel',
120
120
  annotation: 'Step onto the proposed lifecycle — step index is tinted.',
121
121
  },
@@ -124,7 +124,7 @@ const trails: SubsystemTrail[] = [
124
124
  to: 'cli',
125
125
  mechanism: 'calls',
126
126
  file: 'src/bun/maintain-model.ts',
127
- line: 1,
127
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
128
128
  symbol: 'OpenCodeV2Lifecycle.ensure',
129
129
  },
130
130
  ],
@@ -138,7 +138,7 @@ const trails: SubsystemTrail[] = [
138
138
  to: 'cache',
139
139
  mechanism: 'writes',
140
140
  file: 'src/bun/maintain-model.ts',
141
- line: 1,
141
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
142
142
  symbol: 'LifecycleProbeCache.set',
143
143
  annotation: 'Both endpoints are proposed.',
144
144
  },
@@ -153,7 +153,7 @@ const trails: SubsystemTrail[] = [
153
153
  to: 'cli',
154
154
  mechanism: 'uses',
155
155
  file: 'src/bun/verify-subsystem-component.ts',
156
- line: 1,
156
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
157
157
  symbol: 'probeCliVersion',
158
158
  // Step-level proposed: BOTH endpoints are real components — the
159
159
  // seam itself is what is planned. The edge label draws dashed on
@@ -87,7 +87,7 @@ const trails: SubsystemTrail[] = [
87
87
  to: 'api',
88
88
  mechanism: 'calls',
89
89
  file: 'src/ui/BookingPage.tsx',
90
- line: 42,
90
+ span: { startLine: 42, endLine: 42, contentHash: 'fixture' },
91
91
  purl: stepPurl('src/ui/BookingPage.tsx'),
92
92
  symbol: 'BookingPage.submit',
93
93
  annotation: 'Submit hands the picked slot to the API.',
@@ -97,7 +97,7 @@ const trails: SubsystemTrail[] = [
97
97
  to: 'store',
98
98
  mechanism: 'writes',
99
99
  file: 'src/api/checkout.ts',
100
- line: 18,
100
+ span: { startLine: 18, endLine: 18, contentHash: 'fixture' },
101
101
  purl: stepPurl('src/api/checkout.ts'),
102
102
  symbol: 'checkoutApi.book',
103
103
  annotation: 'API writes the booking into the store.',
@@ -107,7 +107,7 @@ const trails: SubsystemTrail[] = [
107
107
  to: 'db',
108
108
  mechanism: 'writes',
109
109
  file: 'src/store/bookingStore.ts',
110
- line: 27,
110
+ span: { startLine: 27, endLine: 27, contentHash: 'fixture' },
111
111
  purl: stepPurl('src/store/bookingStore.ts'),
112
112
  symbol: 'BookingStore.commit',
113
113
  annotation: 'Store commits the row.',
@@ -117,7 +117,7 @@ const trails: SubsystemTrail[] = [
117
117
  to: 'ui',
118
118
  mechanism: 'produces',
119
119
  file: 'src/api/checkout.ts',
120
- line: 24,
120
+ span: { startLine: 24, endLine: 24, contentHash: 'fixture' },
121
121
  purl: stepPurl('src/api/checkout.ts'),
122
122
  symbol: 'checkoutApi.respond',
123
123
  annotation: 'API returns the confirmed booking.',
@@ -133,7 +133,7 @@ const trails: SubsystemTrail[] = [
133
133
  to: 'api',
134
134
  mechanism: 'calls',
135
135
  file: 'src/ui/BookingPage.tsx',
136
- line: 61,
136
+ span: { startLine: 61, endLine: 61, contentHash: 'fixture' },
137
137
  purl: stepPurl('src/ui/BookingPage.tsx'),
138
138
  symbol: 'BookingPage.cancel',
139
139
  },
@@ -142,7 +142,7 @@ const trails: SubsystemTrail[] = [
142
142
  to: 'store',
143
143
  mechanism: 'writes',
144
144
  file: 'src/api/checkout.ts',
145
- line: 33,
145
+ span: { startLine: 33, endLine: 33, contentHash: 'fixture' },
146
146
  purl: stepPurl('src/api/checkout.ts'),
147
147
  symbol: 'checkoutApi.cancel',
148
148
  },
@@ -151,7 +151,7 @@ const trails: SubsystemTrail[] = [
151
151
  to: 'db',
152
152
  mechanism: 'writes',
153
153
  file: 'src/store/bookingStore.ts',
154
- line: 41,
154
+ span: { startLine: 41, endLine: 41, contentHash: 'fixture' },
155
155
  purl: stepPurl('src/store/bookingStore.ts'),
156
156
  symbol: 'BookingStore.remove',
157
157
  },
@@ -134,32 +134,32 @@ const drawingTrails: SubsystemTrail[] = [
134
134
  id: 'tl-open-drawing',
135
135
  title: 'Open drawing',
136
136
  steps: [
137
- { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', line: 56, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan', annotation: 'Lists the drawings directory; each row feeds an open intent.' },
138
- { from: 'panel', to: 'host', mechanism: 'produces', file: 'src/panels/DrawingsLeftPanel.tsx', line: 85, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.openDrawing', annotation: 'Emits the open intent up to the host.' },
139
- { from: 'host', to: 'storage', mechanism: 'calls', file: 'src/hooks/useDrawingsHost.ts', line: 45, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.openDrawing', annotation: 'Host resolves the path and delegates to storage.' },
140
- { from: 'host', to: 'shell', mechanism: 'produces', file: 'src/workspace/WorkspaceShell.tsx', line: 369, purl: stepPurl('src/workspace/WorkspaceShell.tsx'), symbol: 'WorkspaceShell.openTab', annotation: 'Asks the shell to surface the drawing as a tab.' },
141
- { from: 'shell', to: 'tab', mechanism: 'feeds', file: 'src/workspace/WorkspaceShell.tsx', line: 372, purl: stepPurl('src/workspace/WorkspaceShell.tsx'), symbol: 'WorkspaceShell.mountTab' },
142
- { from: 'storage', to: 'fs', mechanism: 'calls', file: 'src/storage/drawingsStorage.ts', line: 90, purl: stepPurl('src/storage/drawingsStorage.ts'), symbol: 'DrawingsStorage.read', annotation: 'Reads the file through the sandboxed fs service.' },
143
- { from: 'tab', to: 'fs', mechanism: 'calls', file: 'src/components/DrawingTabContent.tsx', line: 83, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.load' },
137
+ { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', span: { startLine: 56, endLine: 56, contentHash: 'fixture' }, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan', annotation: 'Lists the drawings directory; each row feeds an open intent.' },
138
+ { from: 'panel', to: 'host', mechanism: 'produces', file: 'src/panels/DrawingsLeftPanel.tsx', span: { startLine: 85, endLine: 85, contentHash: 'fixture' }, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.openDrawing', annotation: 'Emits the open intent up to the host.' },
139
+ { from: 'host', to: 'storage', mechanism: 'calls', file: 'src/hooks/useDrawingsHost.ts', span: { startLine: 45, endLine: 45, contentHash: 'fixture' }, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.openDrawing', annotation: 'Host resolves the path and delegates to storage.' },
140
+ { from: 'host', to: 'shell', mechanism: 'produces', file: 'src/workspace/WorkspaceShell.tsx', span: { startLine: 369, endLine: 369, contentHash: 'fixture' }, purl: stepPurl('src/workspace/WorkspaceShell.tsx'), symbol: 'WorkspaceShell.openTab', annotation: 'Asks the shell to surface the drawing as a tab.' },
141
+ { from: 'shell', to: 'tab', mechanism: 'feeds', file: 'src/workspace/WorkspaceShell.tsx', span: { startLine: 372, endLine: 372, contentHash: 'fixture' }, purl: stepPurl('src/workspace/WorkspaceShell.tsx'), symbol: 'WorkspaceShell.mountTab' },
142
+ { from: 'storage', to: 'fs', mechanism: 'calls', file: 'src/storage/drawingsStorage.ts', span: { startLine: 90, endLine: 90, contentHash: 'fixture' }, purl: stepPurl('src/storage/drawingsStorage.ts'), symbol: 'DrawingsStorage.read', annotation: 'Reads the file through the sandboxed fs service.' },
143
+ { from: 'tab', to: 'fs', mechanism: 'calls', file: 'src/components/DrawingTabContent.tsx', span: { startLine: 83, endLine: 83, contentHash: 'fixture' }, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.load' },
144
144
  ],
145
145
  },
146
146
  {
147
147
  id: 'tl-save-drawing',
148
148
  title: 'Save drawing',
149
149
  steps: [
150
- { from: 'tab', to: 'fs', mechanism: 'calls', file: 'src/components/DrawingTabContent.tsx', line: 112, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.save' },
151
- { from: 'tab', to: 'host', mechanism: 'produces', file: 'src/components/DrawingTabContent.tsx', line: 121, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.emitSaved' },
152
- { from: 'host', to: 'panel', mechanism: 'produces', file: 'src/hooks/useDrawingsHost.ts', line: 64, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.onSaved' },
153
- { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', line: 56, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan' },
150
+ { from: 'tab', to: 'fs', mechanism: 'calls', file: 'src/components/DrawingTabContent.tsx', span: { startLine: 112, endLine: 112, contentHash: 'fixture' }, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.save' },
151
+ { from: 'tab', to: 'host', mechanism: 'produces', file: 'src/components/DrawingTabContent.tsx', span: { startLine: 121, endLine: 121, contentHash: 'fixture' }, purl: stepPurl('src/components/DrawingTabContent.tsx'), symbol: 'DrawingTabContent.emitSaved' },
152
+ { from: 'host', to: 'panel', mechanism: 'produces', file: 'src/hooks/useDrawingsHost.ts', span: { startLine: 64, endLine: 64, contentHash: 'fixture' }, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.onSaved' },
153
+ { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', span: { startLine: 56, endLine: 56, contentHash: 'fixture' }, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan' },
154
154
  ],
155
155
  },
156
156
  {
157
157
  id: 'tl-delete-drawing',
158
158
  title: 'Delete drawing',
159
159
  steps: [
160
- { from: 'host', to: 'fs', mechanism: 'calls', file: 'src/hooks/useDrawingsHost.ts', line: 64, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.deleteDrawing' },
161
- { from: 'host', to: 'panel', mechanism: 'produces', file: 'src/hooks/useDrawingsHost.ts', line: 66, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.refreshList' },
162
- { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', line: 56, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan' },
160
+ { from: 'host', to: 'fs', mechanism: 'calls', file: 'src/hooks/useDrawingsHost.ts', span: { startLine: 64, endLine: 64, contentHash: 'fixture' }, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.deleteDrawing' },
161
+ { from: 'host', to: 'panel', mechanism: 'produces', file: 'src/hooks/useDrawingsHost.ts', span: { startLine: 66, endLine: 66, contentHash: 'fixture' }, purl: stepPurl('src/hooks/useDrawingsHost.ts'), symbol: 'useDrawingsHost.refreshList' },
162
+ { from: 'panel', to: 'storage', mechanism: 'calls', file: 'src/panels/DrawingsLeftPanel.tsx', span: { startLine: 56, endLine: 56, contentHash: 'fixture' }, purl: stepPurl('src/panels/DrawingsLeftPanel.tsx'), symbol: 'DrawingsLeftPanel.scan' },
163
163
  ],
164
164
  },
165
165
  ];
@@ -255,7 +255,7 @@ const proposedTrails: SubsystemTrail[] = [
255
255
  to: 'storage',
256
256
  mechanism: 'calls',
257
257
  file: 'src/hooks/useDrawingsHost.ts',
258
- line: 45,
258
+ span: { startLine: 45, endLine: 45, contentHash: 'fixture' },
259
259
  purl: stepPurl('src/hooks/useDrawingsHost.ts'),
260
260
  symbol: 'useDrawingsHost.openDrawing',
261
261
  annotation: 'Live step — its snippet still renders.',
@@ -265,7 +265,7 @@ const proposedTrails: SubsystemTrail[] = [
265
265
  to: 'runs',
266
266
  mechanism: 'writes',
267
267
  file: 'src/runs/subsystemModelRuns.ts',
268
- line: 1,
268
+ span: { startLine: 1, endLine: 1, contentHash: 'fixture' },
269
269
  purl: stepPurl('src/runs/subsystemModelRuns.ts'),
270
270
  symbol: 'SubsystemModelRunStore.write',
271
271
  annotation: 'Proposed seam — the file is not in the checkout yet.',
@@ -350,11 +350,10 @@ const clickableComponents: SubsystemComponent[] = [
350
350
  symbol: 'LoadPanel',
351
351
  purpose: 'loads the drawing list and hands rows to the render surface',
352
352
  process: 'draw-list',
353
- declarationRef: {
354
- file: 'src/load/LoadPanel.tsx',
353
+ declarationSpan: {
355
354
  startLine: 3,
356
- lineHash: 'story',
357
- capturedAt: '2026-01-01T00:00:00.000Z',
355
+ endLine: 3,
356
+ contentHash: 'story',
358
357
  },
359
358
  declaration: {
360
359
  kind: 'function',
@@ -374,11 +373,10 @@ const clickableComponents: SubsystemComponent[] = [
374
373
  symbol: 'DrawingStore.list',
375
374
  purpose: 'lists stored drawings for the panel',
376
375
  process: 'draw-list',
377
- declarationRef: {
378
- file: 'src/store/DrawingStore.ts',
376
+ declarationSpan: {
379
377
  startLine: 4,
380
- lineHash: 'story',
381
- capturedAt: '2026-01-01T00:00:00.000Z',
378
+ endLine: 4,
379
+ contentHash: 'story',
382
380
  },
383
381
  declaration: {
384
382
  kind: 'method',
@@ -397,11 +395,10 @@ const clickableComponents: SubsystemComponent[] = [
397
395
  symbol: 'RenderSurface',
398
396
  purpose: 'paints a drawing into a surface',
399
397
  process: 'draw-host',
400
- declarationRef: {
401
- file: 'src/render/RenderSurface.ts',
398
+ declarationSpan: {
402
399
  startLine: 3,
403
- lineHash: 'story',
404
- capturedAt: '2026-01-01T00:00:00.000Z',
400
+ endLine: 3,
401
+ contentHash: 'story',
405
402
  },
406
403
  declaration: {
407
404
  kind: 'class',
@@ -454,7 +451,7 @@ const clickableTrails: SubsystemTrail[] = [
454
451
  to: 'drawing-store-list',
455
452
  mechanism: 'calls',
456
453
  file: 'src/load/LoadPanel.tsx',
457
- line: 4,
454
+ span: { startLine: 4, endLine: 4, contentHash: 'fixture' },
458
455
  purl: stepPurl('src/load/LoadPanel.tsx'),
459
456
  symbol: 'LoadPanel.load',
460
457
  annotation:
@@ -465,7 +462,7 @@ const clickableTrails: SubsystemTrail[] = [
465
462
  to: 'render-surface',
466
463
  mechanism: 'calls',
467
464
  file: 'src/store/DrawingStore.ts',
468
- line: 5,
465
+ span: { startLine: 5, endLine: 5, contentHash: 'fixture' },
469
466
  purl: stepPurl('src/store/DrawingStore.ts'),
470
467
  symbol: 'DrawingStore.list',
471
468
  annotation: 'list reads through RenderSurface — click RenderSurface.',
@@ -38,7 +38,7 @@ export function trailFromSteps(
38
38
  to,
39
39
  mechanism,
40
40
  file,
41
- line,
41
+ span: { startLine: line, endLine: line, contentHash: 'fixture' },
42
42
  purl: `pkg:github/storybook/fixture#${file}`,
43
43
  symbol: symbol ?? from,
44
44
  })),
@@ -54,7 +54,6 @@ export function graphSpecFromSteps(
54
54
  to,
55
55
  mechanism: mechanism as SubsystemTrailMechanism,
56
56
  file: 'story-placeholder.ts',
57
- line: 1,
58
57
  purl: 'pkg:github/storybook/fixture#story-placeholder.ts',
59
58
  symbol: from,
60
59
  }));
@@ -43,11 +43,10 @@ const components: SubsystemComponent[] = [
43
43
  process: 'notes-api/server',
44
44
  file: 'src/api/submitNote.ts',
45
45
  purpose: 'HTTP/handler entry — validates and hands off to the service.',
46
- declarationRef: {
47
- file: 'src/api/submitNote.ts',
46
+ declarationSpan: {
48
47
  startLine: 7,
49
- lineHash: 'storybook-placeholder',
50
- capturedAt: new Date(0).toISOString(),
48
+ endLine: 7,
49
+ contentHash: 'storybook-placeholder',
51
50
  },
52
51
  declaration: {
53
52
  kind: 'function',
@@ -69,11 +68,10 @@ const components: SubsystemComponent[] = [
69
68
  process: 'notes-api/server',
70
69
  file: 'src/NoteService.ts',
71
70
  purpose: 'Owns intake rules; methods are separate nodes when they matter.',
72
- declarationRef: {
73
- file: 'src/NoteService.ts',
71
+ declarationSpan: {
74
72
  startLine: 3,
75
- lineHash: 'storybook-placeholder',
76
- capturedAt: new Date(0).toISOString(),
73
+ endLine: 3,
74
+ contentHash: 'storybook-placeholder',
77
75
  },
78
76
  declaration: {
79
77
  kind: 'class',
@@ -101,11 +99,10 @@ const components: SubsystemComponent[] = [
101
99
  process: 'notes-api/server',
102
100
  file: 'src/NoteService.ts',
103
101
  purpose: 'Instance method on NoteService — written as its own construct.',
104
- declarationRef: {
105
- file: 'src/NoteService.ts',
102
+ declarationSpan: {
106
103
  startLine: 14,
107
- lineHash: 'storybook-placeholder',
108
- capturedAt: new Date(0).toISOString(),
104
+ endLine: 14,
105
+ contentHash: 'storybook-placeholder',
109
106
  },
110
107
  declaration: {
111
108
  kind: 'method',
@@ -337,7 +334,7 @@ function renderFileViewer(file: string, opts?: SubsystemOpenFileOptions) {
337
334
  filePath={file}
338
335
  fileName={file.split('/').pop() ?? file}
339
336
  startLine={startLine}
340
- endLine={startLine}
337
+ endLine={opts?.endLine ?? startLine}
341
338
  focusLine={startLine}
342
339
  contextLines={12}
343
340
  readFile={readStoryFile}
@@ -151,11 +151,10 @@ function toComponent(
151
151
  ...(line != null ? { line } : {}),
152
152
  ...(line != null
153
153
  ? {
154
- declarationRef: {
155
- file: node.source_file ?? '',
154
+ declarationSpan: {
156
155
  startLine: line,
157
- lineHash: 'ego-fixture',
158
- capturedAt: new Date(0).toISOString(),
156
+ endLine: line,
157
+ contentHash: 'ego-fixture',
159
158
  },
160
159
  }
161
160
  : {}),