instar 1.3.787 → 1.3.788

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.
@@ -55,10 +55,27 @@
55
55
  position: relative;
56
56
  }
57
57
 
58
- /* Hamburger togglevisible only on mobile, sits in the header row */
58
+ /* Navigation menu button grouped-nav trigger at ALL widths (F2, dashboard-ux-standard).
59
+ Reachability floor: 25 tabs can't fit a flat bar, so a single grouped menu opens from here. */
59
60
  .nav-toggle {
60
- display: none;
61
+ display: flex;
62
+ align-items: center;
63
+ gap: 8px;
64
+ margin-left: 16px;
65
+ padding: 8px 14px;
66
+ min-height: 38px;
67
+ background: var(--bg);
68
+ border: 1px solid var(--border);
69
+ border-radius: 6px;
70
+ color: var(--text);
71
+ font-size: 14px;
72
+ font-weight: 500;
73
+ cursor: pointer;
74
+ flex-shrink: 0;
61
75
  }
76
+ .nav-toggle:hover { background: var(--bg-hover); }
77
+ .nav-toggle[aria-expanded="true"] { background: var(--bg-active); border-color: var(--accent); }
78
+ #navToggleLabel { font-weight: 600; color: var(--text-bright); }
62
79
 
63
80
  .header-left {
64
81
  display: flex;
@@ -542,6 +559,18 @@
542
559
  background: var(--bg);
543
560
  }
544
561
 
562
+ /* F3 — Dashboard UX Standard: every tab's plain-language purpose line.
563
+ One muted, readable sentence directly under the tab header telling a
564
+ non-expert what the tab is for and what they can do here. Enforced by
565
+ tests/unit/dashboard-tab-purpose.test.ts. */
566
+ .tab-purpose {
567
+ font-size: 13px;
568
+ color: var(--text-dim);
569
+ line-height: 1.5;
570
+ margin: 0 0 4px 0;
571
+ max-width: 900px;
572
+ }
573
+
545
574
  .terminal-header {
546
575
  display: flex;
547
576
  align-items: center;
@@ -767,41 +796,69 @@
767
796
  ::-webkit-scrollbar-thumb:hover { background: #444; }
768
797
 
769
798
  /* ── Tab bar ──────────────────────────────────────────── */
799
+ /* Grouped navigation menu (F2, dashboard-ux-standard) — one dropdown at ALL widths,
800
+ opened by .nav-toggle. Hidden until .app.nav-open. Replaces the old horizontal bar
801
+ that clipped 17 of 25 tabs with no reachable affordance. */
770
802
  .tab-bar {
771
- display: flex;
772
- gap: 0;
773
- margin-left: 24px;
774
- overflow-x: auto;
775
- -webkit-overflow-scrolling: touch;
776
- scrollbar-width: none; /* hide scrollbar on Firefox */
803
+ position: absolute;
804
+ top: 100%;
805
+ left: 16px;
806
+ width: 320px;
807
+ max-width: calc(100vw - 32px);
808
+ display: none;
809
+ flex-direction: column;
810
+ gap: 2px;
811
+ padding: 8px;
812
+ background: var(--bg-panel);
813
+ border: 1px solid var(--border);
814
+ border-radius: 0 0 10px 10px;
815
+ box-shadow: 0 8px 28px rgba(0,0,0,0.45);
816
+ z-index: 100;
817
+ max-height: calc(100vh - 64px);
818
+ overflow-y: auto;
777
819
  }
778
- .tab-bar::-webkit-scrollbar { display: none; }
820
+ .app.nav-open .tab-bar { display: flex; }
779
821
 
780
- .tab-bar .tab {
781
- padding: 6px 16px;
782
- border: 1px solid var(--border);
783
- border-radius: 6px 6px 0 0;
784
- background: var(--bg);
822
+ /* Group headers inside the menu (grouped sections). */
823
+ .tab-group { display: flex; flex-direction: column; gap: 2px; }
824
+ .tab-group + .tab-group { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
825
+ .tab-group-label {
826
+ font-size: 11px;
827
+ font-weight: 700;
828
+ letter-spacing: 0.06em;
829
+ text-transform: uppercase;
785
830
  color: var(--text-dim);
786
- font-size: 13px;
831
+ padding: 4px 10px 2px;
832
+ }
833
+
834
+ .tab-bar .tab {
835
+ display: flex;
836
+ align-items: center;
837
+ justify-content: space-between;
838
+ gap: 8px;
839
+ width: 100%;
840
+ text-align: left;
841
+ padding: 9px 12px;
842
+ min-height: 40px;
843
+ border: 1px solid transparent;
844
+ border-radius: 6px;
845
+ background: transparent;
846
+ color: var(--text);
847
+ font-size: 14px;
787
848
  font-weight: 500;
788
849
  cursor: pointer;
789
- border-bottom: none;
790
- margin-bottom: -1px;
791
850
  transition: color 0.15s, background 0.15s;
792
- white-space: nowrap;
793
- flex-shrink: 0;
794
851
  }
795
852
 
796
853
  .tab-bar .tab:hover {
797
- color: var(--text);
854
+ color: var(--text-bright);
798
855
  background: var(--bg-hover);
799
856
  }
800
857
 
801
858
  .tab-bar .tab.active {
802
- background: var(--bg-panel);
859
+ background: var(--bg-active);
803
860
  color: var(--accent);
804
- border-color: var(--border);
861
+ border-color: var(--accent);
805
862
  }
806
863
 
807
864
  .tab-bar .tab-count {
@@ -1008,6 +1065,7 @@
1008
1065
  .files-container {
1009
1066
  display: flex;
1010
1067
  grid-column: 1 / -1;
1068
+ min-width: 0; /* F4 — a grid child must be able to shrink below content width, else it blows out the row and the body scrolls sideways */
1011
1069
  overflow: hidden;
1012
1070
  background: var(--bg);
1013
1071
  }
@@ -1819,6 +1877,7 @@
1819
1877
  .jobs-container {
1820
1878
  display: flex;
1821
1879
  grid-column: 1 / -1;
1880
+ min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
1822
1881
  overflow: hidden;
1823
1882
  background: var(--bg);
1824
1883
  }
@@ -2193,6 +2252,7 @@
2193
2252
  /* ── Features Tab (was Discovery) ──────────────────────────── */
2194
2253
  .features-container {
2195
2254
  grid-column: 1 / -1;
2255
+ min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
2196
2256
  overflow-y: auto;
2197
2257
  background: var(--bg);
2198
2258
  padding: 20px;
@@ -2284,7 +2344,7 @@
2284
2344
  .feat-reversibility { font-size: 12px; color: var(--text-dim); line-height: 1.5; padding: 12px 14px; background: var(--bg-panel); border: 1px solid var(--border); border-radius: 6px; }
2285
2345
 
2286
2346
  /* ── Systems Tab ──────────────────────────────────────────── */
2287
- .systems-container { grid-column: 1 / -1; overflow-y: auto; background: var(--bg); padding: 20px; }
2347
+ .systems-container { grid-column: 1 / -1; min-width: 0; overflow-y: auto; background: var(--bg); padding: 20px; }
2288
2348
  .systems-main { max-width: 960px; margin: 0 auto; }
2289
2349
  .systems-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
2290
2350
  .systems-header h2 { font-size: 16px; font-weight: 600; color: var(--text-bright); }
@@ -2750,32 +2810,47 @@
2750
2810
  <img class="logo" src="/dashboard/logo.png" alt="Instar">
2751
2811
  <h1>Instar Dashboard</h1>
2752
2812
  <button class="nav-toggle" id="navToggle" aria-label="Open navigation menu" aria-expanded="false" onclick="toggleNavMenu()">&#9776; <span id="navToggleLabel">Sessions</span></button>
2753
- <nav class="tab-bar" id="tabBar">
2754
- <button class="tab active" data-tab="sessions" onclick="switchTab('sessions')">Sessions <span class="tab-count" id="tabSessionCount">0</span></button>
2755
- <button class="tab" data-tab="files" onclick="switchTab('files')">Files</button>
2756
- <button class="tab" data-tab="dropzone" onclick="switchTab('dropzone')">Send Content</button>
2757
- <button class="tab" data-tab="secrets" onclick="switchTab('secrets')">Secrets <span class="tab-count" id="tabSecretCount">0</span></button>
2758
- <button class="tab" data-tab="jobs" onclick="switchTab('jobs')">Jobs <span class="tab-count" id="tabJobCount">0</span></button>
2759
- <button class="tab" data-tab="features" onclick="switchTab('features')">Features</button>
2760
- <button class="tab" data-tab="systems" onclick="switchTab('systems')">Health</button>
2761
- <button class="tab" data-tab="integrated-being" onclick="switchTab('integrated-being')">Integrated-Being</button>
2762
- <button class="tab" data-tab="pr-pipeline" onclick="switchTab('pr-pipeline')">PR Pipeline</button>
2763
- <button class="tab" data-tab="projects" onclick="switchTab('projects')">Projects <span class="tab-count" id="tabProjectCount">0</span></button>
2764
- <button class="tab" data-tab="initiatives" onclick="switchTab('initiatives')">Initiatives <span class="tab-count" id="tabInitiativeCount">0</span></button>
2765
- <button class="tab" data-tab="commitments" onclick="switchTab('commitments')">Commitments <span class="tab-count" id="tabCommitmentCount">0</span></button>
2766
- <button class="tab" data-tab="tokens" onclick="switchTab('tokens')">Tokens</button>
2767
- <button class="tab" data-tab="resources" onclick="switchTab('resources')">Resource Usage</button>
2768
- <button class="tab" data-tab="llm-activity" onclick="switchTab('llm-activity')">LLM Activity</button>
2769
- <button class="tab" data-tab="routing-map" onclick="switchTab('routing-map')">Routing Map</button>
2770
- <button class="tab" data-tab="spend" onclick="switchTab('spend')">Spend</button>
2771
- <button class="tab" data-tab="threadline" onclick="switchTab('threadline')">Threadline</button>
2772
- <button class="tab" data-tab="evidence" onclick="switchTab('evidence')">Evidence</button>
2773
- <button class="tab" data-tab="process-health" onclick="switchTab('process-health')">Process Health</button>
2774
- <button class="tab" data-tab="subscriptions" onclick="switchTab('subscriptions')">Subscriptions</button>
2775
- <button class="tab" data-tab="preferences-learning" onclick="switchTab('preferences-learning')">Preferences</button>
2776
- <button class="tab" data-tab="machines" onclick="switchTab('machines')">Machines</button>
2777
- <button class="tab" data-tab="mandates" onclick="switchTab('mandates')">Mandates</button>
2778
- <button class="tab" data-tab="blockers" onclick="switchTab('blockers')">Blockers</button>
2813
+ <nav class="tab-bar" id="tabBar" aria-label="Dashboard sections">
2814
+ <div class="tab-group" role="group" aria-label="Runtime">
2815
+ <div class="tab-group-label">Runtime</div>
2816
+ <button class="tab active" data-tab="sessions" onclick="switchTab('sessions')">Sessions <span class="tab-count" id="tabSessionCount">0</span></button>
2817
+ <button class="tab" data-tab="machines" onclick="switchTab('machines')">Machines</button>
2818
+ <button class="tab" data-tab="jobs" onclick="switchTab('jobs')">Jobs <span class="tab-count" id="tabJobCount">0</span></button>
2819
+ <button class="tab" data-tab="systems" onclick="switchTab('systems')">Health</button>
2820
+ </div>
2821
+ <div class="tab-group" role="group" aria-label="Work & Delivery">
2822
+ <div class="tab-group-label">Work &amp; Delivery</div>
2823
+ <button class="tab" data-tab="pr-pipeline" onclick="switchTab('pr-pipeline')">PR Pipeline</button>
2824
+ <button class="tab" data-tab="projects" onclick="switchTab('projects')">Projects <span class="tab-count" id="tabProjectCount">0</span></button>
2825
+ <button class="tab" data-tab="initiatives" onclick="switchTab('initiatives')">Initiatives <span class="tab-count" id="tabInitiativeCount">0</span></button>
2826
+ <button class="tab" data-tab="commitments" onclick="switchTab('commitments')">Commitments <span class="tab-count" id="tabCommitmentCount">0</span></button>
2827
+ <button class="tab" data-tab="blockers" onclick="switchTab('blockers')">Blockers</button>
2828
+ <button class="tab" data-tab="evidence" onclick="switchTab('evidence')">Evidence</button>
2829
+ </div>
2830
+ <div class="tab-group" role="group" aria-label="Cost & Routing">
2831
+ <div class="tab-group-label">Cost &amp; Routing</div>
2832
+ <button class="tab" data-tab="spend" onclick="switchTab('spend')">Spend</button>
2833
+ <button class="tab" data-tab="subscriptions" onclick="switchTab('subscriptions')">Subscriptions</button>
2834
+ <button class="tab" data-tab="routing-map" onclick="switchTab('routing-map')">Routing Map</button>
2835
+ <button class="tab" data-tab="llm-activity" onclick="switchTab('llm-activity')">LLM Activity</button>
2836
+ <button class="tab" data-tab="tokens" onclick="switchTab('tokens')">Tokens</button>
2837
+ <button class="tab" data-tab="resources" onclick="switchTab('resources')">Resource Usage</button>
2838
+ </div>
2839
+ <div class="tab-group" role="group" aria-label="Intelligence & Comms">
2840
+ <div class="tab-group-label">Intelligence &amp; Comms</div>
2841
+ <button class="tab" data-tab="threadline" onclick="switchTab('threadline')">Threadline</button>
2842
+ <button class="tab" data-tab="integrated-being" onclick="switchTab('integrated-being')">Integrated-Being</button>
2843
+ <button class="tab" data-tab="process-health" onclick="switchTab('process-health')">Process Health</button>
2844
+ <button class="tab" data-tab="preferences-learning" onclick="switchTab('preferences-learning')">Preferences</button>
2845
+ </div>
2846
+ <div class="tab-group" role="group" aria-label="Content & Access">
2847
+ <div class="tab-group-label">Content &amp; Access</div>
2848
+ <button class="tab" data-tab="files" onclick="switchTab('files')">Files</button>
2849
+ <button class="tab" data-tab="dropzone" onclick="switchTab('dropzone')">Send Content</button>
2850
+ <button class="tab" data-tab="secrets" onclick="switchTab('secrets')">Secrets <span class="tab-count" id="tabSecretCount">0</span></button>
2851
+ <button class="tab" data-tab="features" onclick="switchTab('features')">Features</button>
2852
+ <button class="tab" data-tab="mandates" onclick="switchTab('mandates')">Mandates</button>
2853
+ </div>
2779
2854
  </nav>
2780
2855
  </div>
2781
2856
  <div class="vital-signs" id="vitalSigns">
@@ -2815,6 +2890,7 @@
2815
2890
  <button class="new-session-btn" onclick="openNewSessionModal()" title="New session">+</button>
2816
2891
  </div>
2817
2892
  </div>
2893
+ <div class="tab-purpose" style="padding:0 12px 8px">Your agent's live sessions — pick one to watch its terminal in real time.</div>
2818
2894
  <div class="session-list" id="sessionList">
2819
2895
  <div class="empty-state" id="emptyState">
2820
2896
  <div class="icon">&#x1F4AD;</div>
@@ -2867,6 +2943,7 @@
2867
2943
  <div class="file-tree-header">
2868
2944
  <h2>Files</h2>
2869
2945
  </div>
2946
+ <div class="tab-purpose" style="padding:0 12px">Browse and edit this project's files from any device — changes save straight to disk.</div>
2870
2947
  <div class="file-tree-list" id="fileTreeList">
2871
2948
  <div class="file-loading" id="fileTreeLoading">Loading...</div>
2872
2949
  </div>
@@ -2981,7 +3058,7 @@
2981
3058
  <option value="lastRun">Sort: Last Run</option>
2982
3059
  </select>
2983
3060
  </div>
2984
- <div style="font-size:11px;color:var(--text-dim);padding:0 12px 8px;line-height:1.4">Monitor and control your scheduled tasks</div>
3061
+ <div class="tab-purpose" style="padding:0 12px 8px">Monitor and control your scheduled tasks — recurring jobs that run on their own.</div>
2985
3062
  <div id="jobsSummary" class="jobs-summary"></div>
2986
3063
  <div class="jobs-filter-bar" id="jobsFilterBar">
2987
3064
  <button class="jobs-filter-chip active" data-filter="all" onclick="setJobFilter('all')">All</button>
@@ -3012,6 +3089,7 @@
3012
3089
  <button onclick="loadIntegratedBeing()" style="padding:6px 12px">Refresh</button>
3013
3090
  </div>
3014
3091
  </div>
3092
+ <div class="tab-purpose">A cross-session record of what other parts of this agent have been doing — the shared memory that keeps separate conversations aware of each other.</div>
3015
3093
  <div id="ibPerMachineNotice" style="font-size:12px;color:var(--text-dim);display:none">
3016
3094
  Integrated-Being on this machine only — cross-machine ledger visibility is not yet implemented.
3017
3095
  </div>
@@ -3133,6 +3211,7 @@
3133
3211
  <button onclick="loadPrPipeline()" style="padding:6px 12px">Refresh</button>
3134
3212
  </div>
3135
3213
  </div>
3214
+ <div class="tab-purpose">A live view of your open pull requests as they move through review and CI checks toward merge.</div>
3136
3215
  <div id="prPipelinePhaseNotice" style="font-size:12px;color:var(--text-dim)"></div>
3137
3216
  <div id="prPipelineEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
3138
3217
  No PR activity to display.
@@ -3146,8 +3225,8 @@
3146
3225
  <h2 style="margin:0">Projects</h2>
3147
3226
  <button onclick="loadProjects()" style="padding:6px 12px">Refresh</button>
3148
3227
  </div>
3149
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3150
- Multi-spec project plans. Each project bundles related child initiatives across rounds with structurally-gated round advance.
3228
+ <div class="tab-purpose">
3229
+ Multi-spec project plans. Each project groups related pieces of work and only advances to its next round once its required checks pass.
3151
3230
  </div>
3152
3231
  <div id="projectsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
3153
3232
  No active projects. Create one via <code>POST /projects</code> with a plan-doc path.
@@ -3173,8 +3252,8 @@
3173
3252
  <button onclick="loadInitiatives()" style="padding:6px 12px">Refresh</button>
3174
3253
  </div>
3175
3254
  </div>
3176
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3177
- Multi-phase long-running work. Signals: <span style="color:#e27d3b">needs-user</span>,
3255
+ <div class="tab-purpose">
3256
+ Long-running work that spans multiple phases, with a status flag on each. Signals: <span style="color:#e27d3b">needs-user</span>,
3178
3257
  <span style="color:#d65f5f">next-check-due</span>,
3179
3258
  <span style="color:#4a9a4a">ready-to-advance</span>,
3180
3259
  <span style="color:#888">stale (&gt;7d)</span>.
@@ -3195,9 +3274,8 @@
3195
3274
  <button onclick="loadSecrets()" style="padding:6px 12px">Refresh</button>
3196
3275
  </div>
3197
3276
  </div>
3198
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3199
- Secret Drop — one-time-use links for users to submit credentials safely (never through chat).
3200
- Links expire automatically and are destroyed after submission.
3277
+ <div class="tab-purpose">
3278
+ Secret Drop — create one-time links so someone can hand you a password or API key safely, never pasted into chat. Each link expires and is destroyed the moment it's used.
3201
3279
  </div>
3202
3280
  <div id="secretsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
3203
3281
  No pending secret requests.
@@ -3210,7 +3288,7 @@
3210
3288
  <h2 style="margin:0">Commitments</h2>
3211
3289
  <button onclick="loadCommitments()" style="padding:6px 12px">Refresh</button>
3212
3290
  </div>
3213
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3291
+ <div class="tab-purpose">
3214
3292
  Open promises — beacon-watched commitments (⏳). States:
3215
3293
  <span style="color:#4a9a4a">pending</span>,
3216
3294
  <span style="color:#e27d3b">atRisk</span>,
@@ -3228,7 +3306,7 @@
3228
3306
  <h2 style="margin:0">Tokens</h2>
3229
3307
  <button onclick="loadTokens()" style="padding:6px 12px">Refresh</button>
3230
3308
  </div>
3231
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3309
+ <div class="tab-purpose">
3232
3310
  Token usage rolled up from Claude Code session transcripts. Last 24 hours unless noted.
3233
3311
  </div>
3234
3312
 
@@ -3264,7 +3342,7 @@
3264
3342
  <h2 style="margin:0">Resource Usage</h2>
3265
3343
  <button onclick="loadResources()" style="padding:6px 12px">Refresh</button>
3266
3344
  </div>
3267
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3345
+ <div class="tab-purpose">
3268
3346
  How much CPU and memory this agent is using right now — the server process and each running session — sampled continuously. Last hour unless noted.
3269
3347
  </div>
3270
3348
 
@@ -3304,7 +3382,7 @@
3304
3382
  <h2 style="margin:0">Blockers</h2>
3305
3383
  <button onclick="loadBlockers()" style="padding:6px 12px">Refresh</button>
3306
3384
  </div>
3307
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3385
+ <div class="tab-purpose">
3308
3386
  Things that looked like they stopped progress, tracked as <b>decaying hypotheses</b> rather than settled walls.
3309
3387
  Each one moves through verification states; a "true blocker" is the best current understanding with a recheck date —
3310
3388
  never a permanent "give up".
@@ -3330,7 +3408,7 @@
3330
3408
  <button onclick="loadLlmActivity()" style="padding:6px 12px">Refresh</button>
3331
3409
  </div>
3332
3410
  </div>
3333
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3411
+ <div class="tab-purpose">
3334
3412
  Every decision the system's "autopilot" makes with an AI call — sentinels, gates, background checks.
3335
3413
  For each one: which AI provider ran it, how often it actually <b>acted</b> on something vs. found
3336
3414
  nothing to do, how often it was <b>skipped</b> to save on rate limits, and what it cost. A row that
@@ -3364,7 +3442,7 @@
3364
3442
  <h2 style="margin:0">Routing Map</h2>
3365
3443
  <button onclick="loadRoutingMap()" style="padding:6px 12px">Refresh</button>
3366
3444
  </div>
3367
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3445
+ <div class="tab-purpose">
3368
3446
  Where each internal job-kind sends its AI calls. Every background check, gate, and
3369
3447
  sentinel has a <b>lane</b> (its "nature") and a fallback list of <b>doors</b> — the ways
3370
3448
  it can reach a model. This shows, per lane, the ordered door + model list it tries, and
@@ -3407,7 +3485,7 @@
3407
3485
  <button onclick="loadRoutingSpend()" style="padding:6px 12px">Refresh</button>
3408
3486
  </div>
3409
3487
  </div>
3410
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3488
+ <div class="tab-purpose">
3411
3489
  What the internal AI calls cost, and where the paid-door caps sit. The dollar figures are a
3412
3490
  <b>reporting</b> view — immutable token counts priced against a reviewed price list on read, so a
3413
3491
  price correction reflows automatically. <b>No paid door is live yet</b>, so metered spend is $0;
@@ -3642,7 +3720,7 @@
3642
3720
  <h2 style="margin:0">Evidence</h2>
3643
3721
  <div style="font-size:12px;color:var(--text-dim)">Per-entity evidence + reverse citations</div>
3644
3722
  </div>
3645
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3723
+ <div class="tab-purpose">
3646
3724
  Inspect the evidence trail behind any memory entity, or ask "what cites this?" given a kind + sourceId.
3647
3725
  All results are viewer-scope filtered by SemanticMemory before they reach this view.
3648
3726
  </div>
@@ -3701,7 +3779,7 @@
3701
3779
  <h2 style="margin:0">Threadline</h2>
3702
3780
  <button onclick="loadThreadlineBridgeConfig()" style="padding:6px 12px">Refresh</button>
3703
3781
  </div>
3704
- <div style="font-size:12px;color:var(--text-dim);line-height:1.4">
3782
+ <div class="tab-purpose">
3705
3783
  Threadline is your agent's secure channel to other AI agents. The Telegram bridge mirrors those conversations into per-thread Telegram topics so you can watch every exchange. Quiet by default — flip the master switch below to opt in.
3706
3784
  </div>
3707
3785
 
@@ -3798,7 +3876,7 @@
3798
3876
  <h2>Health</h2>
3799
3877
  <button class="systems-refresh" onclick="loadSystems()">Refresh</button>
3800
3878
  </div>
3801
- <div style="font-size:12px;color:var(--text-dim);margin-bottom:16px;line-height:1.4">Your agent's health and running processes</div>
3879
+ <div class="tab-purpose" style="margin-bottom:16px">Your agent's health and running processes — the server and each running session at a glance.</div>
3802
3880
  <div id="systemsBanner">
3803
3881
  <div style="padding:20px;color:var(--text-dim);text-align:center">Loading...</div>
3804
3882
  </div>
@@ -5537,7 +5615,7 @@
5537
5615
  <span style="font-size:11px;color:var(--text-dim)">confidence: ${escapeHtml(confidence)}</span>
5538
5616
  <button class="ev-inspect-btn" data-entity-id="${id}" style="margin-left:auto;padding:2px 8px;font-size:11px">Inspect evidence</button>
5539
5617
  </div>
5540
- ${content ? `<div style="font-size:12px;color:var(--text-dim);line-height:1.4">${content}</div>` : ''}
5618
+ ${content ? `<div class="tab-purpose">${content}</div>` : ''}
5541
5619
  </div>
5542
5620
  `;
5543
5621
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.3.787",
3
+ "version": "1.3.788",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-07-09T03:23:07.095Z",
5
- "instarVersion": "1.3.787",
4
+ "generatedAt": "2026-07-09T06:42:14.302Z",
5
+ "instarVersion": "1.3.788",
6
6
  "entryCount": 202,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,45 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- assembled-by: assemble-next-md -->
4
+ <!-- bump: patch -->
5
+
6
+ ## What Changed
7
+
8
+ - **All 25 dashboard tabs are now reachable — grouped navigation (Dashboard UX Standard F2).**
9
+ The dashboard grew to 25 tabs in a flat horizontal bar that clipped at ~8 tabs on a 1280px
10
+ viewport with a hidden scrollbar — the other ~17 (Spend, Machines, Mandates, Process Health,
11
+ …) were unreachable by pointer, and the active tab often wasn't even visible in the nav
12
+ (operator report, topic 29723). The nav is now ONE grouped dropdown menu, opened from the
13
+ always-visible `☰` button at every viewport, organized into five labeled sections (Runtime,
14
+ Work & Delivery, Cost & Routing, Intelligence & Comms, Content & Access). It reuses the
15
+ existing (previously mobile-only) collapsible-menu machinery — every tab's data-tab, onclick,
16
+ and count badge is preserved verbatim.
17
+ - **The Dashboard UX Standard is now a constitutional standard with CI-enforced floors.**
18
+ `docs/specs/dashboard-ux-standard.md` (operator-approved, topic 29723) turns the operator's
19
+ "VERY user friendly / EASY to navigate" bar into eight objective floors. Two ship enforced:
20
+ F1 (panel placement, shipped #1403) and F2 (nav reachability, this change) — the rest are
21
+ tracked follow-up passes. Registered in `docs/STANDARDS-REGISTRY.md` so the
22
+ Standards-Enforcement-Coverage audit classifies them as enforced gates.
23
+
24
+ ## What to Tell Your User
25
+
26
+ Every dashboard tab is now reachable from one clean, grouped menu (opened by the ☰ button) at
27
+ desktop and phone width — no more tabs hidden off the edge of the screen. Nothing to enable;
28
+ it lands with the release.
29
+
30
+ ## Summary of New Capabilities
31
+
32
+ - None — this is a navigation/UX fix plus a build-time floor (`dashboard-nav-reachability.test.ts`)
33
+ that fails the build if a future tab is unreachable or the nav loses its grouped structure.
34
+
35
+ ## Evidence
36
+
37
+ `tests/unit/dashboard-nav-reachability.test.ts` — 3 cases: every `TAB_REGISTRY` tab has a
38
+ reachable nav control and there are no orphan nav buttons (population floor ≥20), the nav is
39
+ grouped into labeled sections, and the menu is reachable at all widths (`.nav-toggle`
40
+ `display:flex` at base + `.app.nav-open .tab-bar` open mechanism). Real-browser (headless
41
+ Chromium) verified at 1280×860 and 390×844: the grouped menu renders all five sections with all
42
+ 25 tabs, active-tab highlight + count badges intact, closed-state header shows the `☰ Sessions`
43
+ button and a full-width panel; no horizontal body overflow. Both dashboard floor tests green
44
+ (7 cases). The header-logo audit finding was confirmed a static-render artifact (logo.png is
45
+ served live via `express.static`) — corrected in the spec, no spurious fix made.
@@ -0,0 +1,20 @@
1
+ # Side-Effects Review — Dashboard F3 (tab purpose lines)
2
+
3
+ **Change:** Implements floor **F3** of the Dashboard UX Standard (`docs/specs/dashboard-ux-standard.md`, merged in #1404): every registered dashboard tab now carries a plain-language, self-explanatory purpose line near its top. Adds a shared `.tab-purpose` CSS class, converts the dashboard's pre-existing muted intro divs to it (de-jargoning the worst offenders), adds purpose lines to the tabs that lacked one (Sessions, Files), and adds a static floor test.
4
+
5
+ **Files:**
6
+ - `dashboard/index.html` — one `.tab-purpose` CSS rule; ~15 panels' intro divs converted to (or given) `.tab-purpose`; new purpose lines for Sessions and Files. Pure markup/CSS — no script changes.
7
+ - `tests/unit/dashboard-tab-purpose.test.ts` — the F3 floor: maps every `TAB_REGISTRY` tab to its panel markup and fails (naming the tab) if none carries a recognized purpose-line class (`tab-purpose` / `ph-intro` / `features-subtitle` / `dropzone-subtitle`). Population-floor guarded.
8
+
9
+ **Side effects / blast radius:**
10
+ - **Runtime behavior:** NONE. The dashboard is a static file served by `express.static`; this change adds display-only markup + CSS. No JS logic, no API routes, no state, no config touched.
11
+ - **Migrations:** none required. The dashboard `index.html` is served from the package, not templated per-agent; no `PostUpdateMigrator` / CLAUDE.md-template surface is involved (no agent-installed file changes).
12
+ - **Server/lifeline/deploy path:** untouched.
13
+ - **Cross-machine / mesh:** untouched.
14
+ - **Security/PII:** none — no data, credentials, or user content flow through the changed lines.
15
+
16
+ **Risk:** Low. Worst case is a cosmetic mis-placement of a purpose line on a tab, visible only in the dashboard UI, fixable by a follow-up edit. The floor test prevents a future tab from silently shipping without a purpose line.
17
+
18
+ **Rollback:** revert this commit — the dashboard reverts to the prior markup with zero residual state (nothing persisted, nothing migrated).
19
+
20
+ **Follow-ups (tracked, out of scope here):** F4 (mobile no-horizontal-scroll) ships next; F5–F8 (labeled controls, self-explaining empty states, shared component vocabulary that will consolidate the 4 accepted purpose-line classes into one) follow per the spec sequencing.
@@ -0,0 +1,18 @@
1
+ # Side-Effects Review — Dashboard F4 (no mobile horizontal scroll)
2
+
3
+ **Change:** Implements floor **F4** of the Dashboard UX Standard (`docs/specs/dashboard-ux-standard.md`): the page body must never scroll horizontally at 1280/768/390px. The audit (2026-07-08) found panels overflowing the viewport's right edge at 390px so the whole page scrolled sideways on a phone.
4
+
5
+ **Files:**
6
+ - `dashboard/index.html` — adds `min-width: 0` to the four grid-child panel containers that lacked it (`files-container`, `jobs-container`, `systems-container`, `features-container`). These are direct `.app` grid children (`grid-column: 1 / -1`); a CSS grid/flex child defaults to `min-width: auto`, so a wide descendant forces the row wider than the viewport and the body scrolls sideways. `min-width: 0` lets the child shrink so wide content wraps/contains instead of blowing out the row. (`.tab-panel` already carried this from #1403.) No JS touched.
7
+ - `tests/unit/dashboard-viewport-scroll.test.ts` — the F4 floor, in two halves: (1) a STATIC check that every grid-child container carries `min-width: 0` (always runs); (2) a BROWSER-GATED render check that `document.body.scrollWidth <= clientWidth` at each viewport, which SKIPS HONESTLY when no browser driver is installed (FD-2) and runs in the CI browser job. Never a false green.
8
+
9
+ **Side effects / blast radius:**
10
+ - **Runtime behavior:** NONE. Display-only CSS on static markup. No JS, API, state, or config.
11
+ - **Migrations / agent-installed files:** none (dashboard is package-served, not templated per agent).
12
+ - **Server/lifeline/mesh/security:** untouched.
13
+
14
+ **Risk:** Very low. `min-width: 0` on a grid child is the textbook, side-effect-free fix for grid row-blowout; it only *allows* a child to shrink, it never forces a size. Worst case is a wide element inside one of these tabs wrapping instead of overflowing — the desired behavior.
15
+
16
+ **Verification honesty:** The static half is verified green here. The rendered half is **browser-gated and was SKIPPED in this worktree** — no Playwright/Puppeteer is installed, and installing a browser (a large download) was deliberately avoided on a host that wedged twice on 2026-07-08 under filesystem load. The `min-width: 0` fix targets the known mechanism (grid child blowout) with high confidence from the CSS, but a pixel-level 390px confirmation should run via the CI browser job or a browser-capable pass before treating F4 as fully closed. This is disclosed rather than claimed as visually verified.
17
+
18
+ **Rollback:** revert — pure CSS + a test, zero residual state.
@@ -0,0 +1,53 @@
1
+ # Side-Effects Review — Grouped-nav reachability + Dashboard UX Standard (F1/F2)
2
+
3
+ **Version / slug:** `dashboard-ux-standard-nav`
4
+ **Date:** `2026-07-08`
5
+ **Author:** `Instar Agent (echo)`
6
+ **Second-pass reviewer:** `not required`
7
+
8
+ ## Summary of the change
9
+
10
+ Makes all 25 dashboard tabs reachable (operator report, topic 29723: 17 of 25 unreachable in a clipping flat nav bar) by converting the nav into ONE grouped dropdown menu, opened from the always-visible `☰` toggle at every viewport, organized into five labeled sections. This reuses the existing (previously mobile-only) `.app.nav-open .tab-bar` collapsible-menu machinery — `toggleNavMenu`/`closeNavMenu`/`updateNavToggleLabel`/`switchTab` are untouched; every tab button's `data-tab`, `onclick`, and count badge is preserved verbatim (25 in, 25 out, cross-checked against `TAB_REGISTRY`). Ships the operator-approved `docs/specs/dashboard-ux-standard.md` (8 floors), a `docs/STANDARDS-REGISTRY.md` entry, and the F2 floor test. Files touched: `dashboard/index.html` (CSS: `.nav-toggle` visible at base + `.tab-bar` → grouped dropdown + `.tab-group`/`.tab-group-label`; markup: tabs wrapped in groups), `tests/unit/dashboard-nav-reachability.test.ts`, `docs/specs/dashboard-ux-standard.md`, `docs/STANDARDS-REGISTRY.md`, this artifact, a release fragment.
11
+
12
+ ## Decision-point inventory
13
+
14
+ No runtime decision-point surface. Presentation-layer CSS/HTML plus a static test. It gates no information flow, blocks no actions, filters no messages, constrains no agent behavior at runtime. The new unit test constrains future COMMITS (the standard test-ratchet pattern), not runtime behavior.
15
+
16
+ ---
17
+
18
+ ## 1. Over-block
19
+
20
+ No block/allow surface at runtime. For the commit-time ratchet: the F2 floor could "over-block" a future legitimate nav change — e.g. a deliberate move to a different reachable model (persistent left rail). Mitigation: the floor asserts the FLOOR (every tab reachable, nav grouped, reachable at all widths), not a specific implementation; a left-rail that keeps tabs reachable + grouped still passes. Failure messages name the exact unreachable/orphan tab and the fix.
21
+
22
+ ## 2. Under-block
23
+
24
+ The floor keys on `data-tab="..."` buttons inside the `id="tabBar"` nav and `id: '...'` entries in the `TAB_REGISTRY` array. A tab injected purely from JS (not in the static markup) or a registry authored with unconventional syntax would not be seen. Accepted: the regression vector this closes is the observed flat-nav clip (a real 25-tab overflow); the population floor (≥20 nav buttons AND ≥20 registry ids visible) fails loudly if either matcher goes blind. Deeper enforcement (the F4 viewport smoke test for body-never-h-scroll) is a tracked follow-up pass in the spec's implementation sequencing. <!-- tracked: topic-29723 dashboard-ux-brief Increment 2b -->
25
+
26
+ ## 3. Level-of-abstraction fit
27
+
28
+ Right layer. The bug is nav reachability; the fix reuses the existing collapsible-menu mechanism at the layout layer rather than inventing new nav architecture (a persistent sidebar rewrite would relocate the sessions panel that owns the 280px column — higher risk for no reachability gain). No smarter existing gate applies (not decision logic).
29
+
30
+ ## 4. Signal vs authority compliance
31
+
32
+ Compliant by vacuity at runtime: the change holds no blocking authority and produces no signal — inert presentation markup. The unit test is a build-time ratchet with commit-blocking authority through CI exactly like every other test, with deterministic human-readable failure output.
33
+
34
+ ## 5. Interactions
35
+
36
+ - `switchTab()` already closes the menu (`classList.remove('nav-open')`) and updates the toggle label on selection — verified; the always-dropdown model needs no JS change.
37
+ - The mobile `@media` block still sets `.tab-bar` full-width (`left:0;right:0`) — it reinforces the base dropdown harmlessly (mobile menu = full width).
38
+ - `.tab-panel` placement (F1, #1403) is unaffected — this change touches only the header nav, not the after-main panels.
39
+ - Fresh class names (`.tab-group`, `.tab-group-label`) — grep-verified no prior definitions; `.nav-toggle`/`.tab-bar` rules are the only ones restyled, both verified.
40
+
41
+ ## 6. External surfaces
42
+
43
+ Visible change: the dashboard nav becomes a grouped `☰` menu reachable at every width; all 25 tabs reachable (was ~8). No API change, no data change, no cross-agent surface, no timing/conversation-state dependency. Verified with real-browser (headless Chromium) at 1280×860 (grouped menu: 5 sections, all tabs, active highlight + count badges) and 390×844 (full-width menu, no h-overflow), plus the closed default state (header `☰ Sessions` button + full-width panel).
44
+
45
+ **Operator-Surface-Quality (dashboard is an operator surface):** (1) leads with the primary action — the nav is the surface's primary affordance and is now front-and-center, all destinations reachable; (2) zero raw internals — tabs are plain-language labels, grouped under plain-language section headers, no JSON/IDs/slugs; (3) no destructive action in the nav; (4) plain language a non-engineer reads ("Cost & Routing → Spend"); (5) works at phone width — 40px+ tap targets, readable 14–15px type, no horizontal scroll (headless-verified at 390px). The header-logo "broken" audit finding was confirmed a static-render false positive (logo.png served live via `express.static`) — no spurious change made.
46
+
47
+ ## 7. Multi-machine posture (Cross-Machine Coherence)
48
+
49
+ Machine-local BY DESIGN like all dashboard markup: the HTML ships identically to every machine with the release; each serves its own copy. No replicated state, no machine-boundary URL, no one-voice notice surface. Both operator machines get it as they pick up the release.
50
+
51
+ ## 8. Rollback cost
52
+
53
+ Trivial: revert the commit (CSS + nav markup regroup + one test + the spec/registry/fragment docs). No data migration, no agent state, no config. A revert restores the prior (clipping) nav and deletes the F2 floor with it.