instar 1.3.787 → 1.3.789
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.
- package/dashboard/index.html +162 -74
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.788.md +45 -0
- package/upgrades/1.3.789.md +44 -0
- package/upgrades/side-effects/dashboard-f3-tab-purpose.md +20 -0
- package/upgrades/side-effects/dashboard-f4-viewport-scroll.md +18 -0
- package/upgrades/side-effects/dashboard-f5-f8.md +22 -0
- package/upgrades/side-effects/dashboard-ux-standard-nav.md +53 -0
package/dashboard/index.html
CHANGED
|
@@ -55,10 +55,27 @@
|
|
|
55
55
|
position: relative;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
/*
|
|
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:
|
|
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,28 @@
|
|
|
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
|
+
|
|
567
|
+
F7 — CANONICAL purpose-line class. `.tab-purpose` is the shared vocabulary
|
|
568
|
+
every NEW tab should use for its purpose line. Three legacy variants still
|
|
569
|
+
exist and carry their own deliberately-distinct sizing — `.ph-intro`
|
|
570
|
+
(Process-Health design-system intro, larger), `.features-subtitle`, and
|
|
571
|
+
`.dropzone-subtitle` — all recognized by the F3 floor test. Per the spec
|
|
572
|
+
(docs/specs/dashboard-ux-standard.md, FD-3) F7 is soft-first: consolidating
|
|
573
|
+
those three into `.tab-purpose` is a tracked migration (it changes their
|
|
574
|
+
visual size, so it is done deliberately, not big-bang). Until then: reach
|
|
575
|
+
for `.tab-purpose`; do not add a fifth variant or an inline-styled line. */
|
|
576
|
+
.tab-purpose {
|
|
577
|
+
font-size: 13px;
|
|
578
|
+
color: var(--text-dim);
|
|
579
|
+
line-height: 1.5;
|
|
580
|
+
margin: 0 0 4px 0;
|
|
581
|
+
max-width: 900px;
|
|
582
|
+
}
|
|
583
|
+
|
|
545
584
|
.terminal-header {
|
|
546
585
|
display: flex;
|
|
547
586
|
align-items: center;
|
|
@@ -767,41 +806,69 @@
|
|
|
767
806
|
::-webkit-scrollbar-thumb:hover { background: #444; }
|
|
768
807
|
|
|
769
808
|
/* ── Tab bar ──────────────────────────────────────────── */
|
|
809
|
+
/* Grouped navigation menu (F2, dashboard-ux-standard) — one dropdown at ALL widths,
|
|
810
|
+
opened by .nav-toggle. Hidden until .app.nav-open. Replaces the old horizontal bar
|
|
811
|
+
that clipped 17 of 25 tabs with no reachable affordance. */
|
|
770
812
|
.tab-bar {
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
-
|
|
776
|
-
|
|
813
|
+
position: absolute;
|
|
814
|
+
top: 100%;
|
|
815
|
+
left: 16px;
|
|
816
|
+
width: 320px;
|
|
817
|
+
max-width: calc(100vw - 32px);
|
|
818
|
+
display: none;
|
|
819
|
+
flex-direction: column;
|
|
820
|
+
gap: 2px;
|
|
821
|
+
padding: 8px;
|
|
822
|
+
background: var(--bg-panel);
|
|
823
|
+
border: 1px solid var(--border);
|
|
824
|
+
border-radius: 0 0 10px 10px;
|
|
825
|
+
box-shadow: 0 8px 28px rgba(0,0,0,0.45);
|
|
826
|
+
z-index: 100;
|
|
827
|
+
max-height: calc(100vh - 64px);
|
|
828
|
+
overflow-y: auto;
|
|
777
829
|
}
|
|
778
|
-
.tab-bar
|
|
830
|
+
.app.nav-open .tab-bar { display: flex; }
|
|
779
831
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
832
|
+
/* Group headers inside the menu (grouped sections). */
|
|
833
|
+
.tab-group { display: flex; flex-direction: column; gap: 2px; }
|
|
834
|
+
.tab-group + .tab-group { margin-top: 6px; padding-top: 6px; border-top: 1px solid var(--border); }
|
|
835
|
+
.tab-group-label {
|
|
836
|
+
font-size: 11px;
|
|
837
|
+
font-weight: 700;
|
|
838
|
+
letter-spacing: 0.06em;
|
|
839
|
+
text-transform: uppercase;
|
|
785
840
|
color: var(--text-dim);
|
|
786
|
-
|
|
841
|
+
padding: 4px 10px 2px;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.tab-bar .tab {
|
|
845
|
+
display: flex;
|
|
846
|
+
align-items: center;
|
|
847
|
+
justify-content: space-between;
|
|
848
|
+
gap: 8px;
|
|
849
|
+
width: 100%;
|
|
850
|
+
text-align: left;
|
|
851
|
+
padding: 9px 12px;
|
|
852
|
+
min-height: 40px;
|
|
853
|
+
border: 1px solid transparent;
|
|
854
|
+
border-radius: 6px;
|
|
855
|
+
background: transparent;
|
|
856
|
+
color: var(--text);
|
|
857
|
+
font-size: 14px;
|
|
787
858
|
font-weight: 500;
|
|
788
859
|
cursor: pointer;
|
|
789
|
-
border-bottom: none;
|
|
790
|
-
margin-bottom: -1px;
|
|
791
860
|
transition: color 0.15s, background 0.15s;
|
|
792
|
-
white-space: nowrap;
|
|
793
|
-
flex-shrink: 0;
|
|
794
861
|
}
|
|
795
862
|
|
|
796
863
|
.tab-bar .tab:hover {
|
|
797
|
-
color: var(--text);
|
|
864
|
+
color: var(--text-bright);
|
|
798
865
|
background: var(--bg-hover);
|
|
799
866
|
}
|
|
800
867
|
|
|
801
868
|
.tab-bar .tab.active {
|
|
802
|
-
background: var(--bg-
|
|
869
|
+
background: var(--bg-active);
|
|
803
870
|
color: var(--accent);
|
|
804
|
-
border-color: var(--
|
|
871
|
+
border-color: var(--accent);
|
|
805
872
|
}
|
|
806
873
|
|
|
807
874
|
.tab-bar .tab-count {
|
|
@@ -1008,6 +1075,7 @@
|
|
|
1008
1075
|
.files-container {
|
|
1009
1076
|
display: flex;
|
|
1010
1077
|
grid-column: 1 / -1;
|
|
1078
|
+
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
1079
|
overflow: hidden;
|
|
1012
1080
|
background: var(--bg);
|
|
1013
1081
|
}
|
|
@@ -1819,6 +1887,7 @@
|
|
|
1819
1887
|
.jobs-container {
|
|
1820
1888
|
display: flex;
|
|
1821
1889
|
grid-column: 1 / -1;
|
|
1890
|
+
min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
|
|
1822
1891
|
overflow: hidden;
|
|
1823
1892
|
background: var(--bg);
|
|
1824
1893
|
}
|
|
@@ -2193,6 +2262,7 @@
|
|
|
2193
2262
|
/* ── Features Tab (was Discovery) ──────────────────────────── */
|
|
2194
2263
|
.features-container {
|
|
2195
2264
|
grid-column: 1 / -1;
|
|
2265
|
+
min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
|
|
2196
2266
|
overflow-y: auto;
|
|
2197
2267
|
background: var(--bg);
|
|
2198
2268
|
padding: 20px;
|
|
@@ -2284,7 +2354,7 @@
|
|
|
2284
2354
|
.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
2355
|
|
|
2286
2356
|
/* ── Systems Tab ──────────────────────────────────────────── */
|
|
2287
|
-
.systems-container { grid-column: 1 / -1; overflow-y: auto; background: var(--bg); padding: 20px; }
|
|
2357
|
+
.systems-container { grid-column: 1 / -1; min-width: 0; overflow-y: auto; background: var(--bg); padding: 20px; }
|
|
2288
2358
|
.systems-main { max-width: 960px; margin: 0 auto; }
|
|
2289
2359
|
.systems-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
|
|
2290
2360
|
.systems-header h2 { font-size: 16px; font-weight: 600; color: var(--text-bright); }
|
|
@@ -2750,32 +2820,47 @@
|
|
|
2750
2820
|
<img class="logo" src="/dashboard/logo.png" alt="Instar">
|
|
2751
2821
|
<h1>Instar Dashboard</h1>
|
|
2752
2822
|
<button class="nav-toggle" id="navToggle" aria-label="Open navigation menu" aria-expanded="false" onclick="toggleNavMenu()">☰ <span id="navToggleLabel">Sessions</span></button>
|
|
2753
|
-
<nav class="tab-bar" id="tabBar">
|
|
2754
|
-
<
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
<
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
<
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2823
|
+
<nav class="tab-bar" id="tabBar" aria-label="Dashboard sections">
|
|
2824
|
+
<div class="tab-group" role="group" aria-label="Runtime">
|
|
2825
|
+
<div class="tab-group-label">Runtime</div>
|
|
2826
|
+
<button class="tab active" data-tab="sessions" onclick="switchTab('sessions')">Sessions <span class="tab-count" id="tabSessionCount">0</span></button>
|
|
2827
|
+
<button class="tab" data-tab="machines" onclick="switchTab('machines')">Machines</button>
|
|
2828
|
+
<button class="tab" data-tab="jobs" onclick="switchTab('jobs')">Jobs <span class="tab-count" id="tabJobCount">0</span></button>
|
|
2829
|
+
<button class="tab" data-tab="systems" onclick="switchTab('systems')">Health</button>
|
|
2830
|
+
</div>
|
|
2831
|
+
<div class="tab-group" role="group" aria-label="Work & Delivery">
|
|
2832
|
+
<div class="tab-group-label">Work & Delivery</div>
|
|
2833
|
+
<button class="tab" data-tab="pr-pipeline" onclick="switchTab('pr-pipeline')">PR Pipeline</button>
|
|
2834
|
+
<button class="tab" data-tab="projects" onclick="switchTab('projects')">Projects <span class="tab-count" id="tabProjectCount">0</span></button>
|
|
2835
|
+
<button class="tab" data-tab="initiatives" onclick="switchTab('initiatives')">Initiatives <span class="tab-count" id="tabInitiativeCount">0</span></button>
|
|
2836
|
+
<button class="tab" data-tab="commitments" onclick="switchTab('commitments')">Commitments <span class="tab-count" id="tabCommitmentCount">0</span></button>
|
|
2837
|
+
<button class="tab" data-tab="blockers" onclick="switchTab('blockers')">Blockers</button>
|
|
2838
|
+
<button class="tab" data-tab="evidence" onclick="switchTab('evidence')">Evidence</button>
|
|
2839
|
+
</div>
|
|
2840
|
+
<div class="tab-group" role="group" aria-label="Cost & Routing">
|
|
2841
|
+
<div class="tab-group-label">Cost & Routing</div>
|
|
2842
|
+
<button class="tab" data-tab="spend" onclick="switchTab('spend')">Spend</button>
|
|
2843
|
+
<button class="tab" data-tab="subscriptions" onclick="switchTab('subscriptions')">Subscriptions</button>
|
|
2844
|
+
<button class="tab" data-tab="routing-map" onclick="switchTab('routing-map')">Routing Map</button>
|
|
2845
|
+
<button class="tab" data-tab="llm-activity" onclick="switchTab('llm-activity')">LLM Activity</button>
|
|
2846
|
+
<button class="tab" data-tab="tokens" onclick="switchTab('tokens')">Tokens</button>
|
|
2847
|
+
<button class="tab" data-tab="resources" onclick="switchTab('resources')">Resource Usage</button>
|
|
2848
|
+
</div>
|
|
2849
|
+
<div class="tab-group" role="group" aria-label="Intelligence & Comms">
|
|
2850
|
+
<div class="tab-group-label">Intelligence & Comms</div>
|
|
2851
|
+
<button class="tab" data-tab="threadline" onclick="switchTab('threadline')">Threadline</button>
|
|
2852
|
+
<button class="tab" data-tab="integrated-being" onclick="switchTab('integrated-being')">Integrated-Being</button>
|
|
2853
|
+
<button class="tab" data-tab="process-health" onclick="switchTab('process-health')">Process Health</button>
|
|
2854
|
+
<button class="tab" data-tab="preferences-learning" onclick="switchTab('preferences-learning')">Preferences</button>
|
|
2855
|
+
</div>
|
|
2856
|
+
<div class="tab-group" role="group" aria-label="Content & Access">
|
|
2857
|
+
<div class="tab-group-label">Content & Access</div>
|
|
2858
|
+
<button class="tab" data-tab="files" onclick="switchTab('files')">Files</button>
|
|
2859
|
+
<button class="tab" data-tab="dropzone" onclick="switchTab('dropzone')">Send Content</button>
|
|
2860
|
+
<button class="tab" data-tab="secrets" onclick="switchTab('secrets')">Secrets <span class="tab-count" id="tabSecretCount">0</span></button>
|
|
2861
|
+
<button class="tab" data-tab="features" onclick="switchTab('features')">Features</button>
|
|
2862
|
+
<button class="tab" data-tab="mandates" onclick="switchTab('mandates')">Mandates</button>
|
|
2863
|
+
</div>
|
|
2779
2864
|
</nav>
|
|
2780
2865
|
</div>
|
|
2781
2866
|
<div class="vital-signs" id="vitalSigns">
|
|
@@ -2815,6 +2900,7 @@
|
|
|
2815
2900
|
<button class="new-session-btn" onclick="openNewSessionModal()" title="New session">+</button>
|
|
2816
2901
|
</div>
|
|
2817
2902
|
</div>
|
|
2903
|
+
<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
2904
|
<div class="session-list" id="sessionList">
|
|
2819
2905
|
<div class="empty-state" id="emptyState">
|
|
2820
2906
|
<div class="icon">💭</div>
|
|
@@ -2867,13 +2953,14 @@
|
|
|
2867
2953
|
<div class="file-tree-header">
|
|
2868
2954
|
<h2>Files</h2>
|
|
2869
2955
|
</div>
|
|
2956
|
+
<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
2957
|
<div class="file-tree-list" id="fileTreeList">
|
|
2871
2958
|
<div class="file-loading" id="fileTreeLoading">Loading...</div>
|
|
2872
2959
|
</div>
|
|
2873
2960
|
</div>
|
|
2874
2961
|
<div class="file-content-panel" id="fileContentPanel">
|
|
2875
2962
|
<div class="file-content-header" id="fileContentHeader" style="display:none">
|
|
2876
|
-
<button class="files-back-btn" onclick="filesGoBack()">←</button>
|
|
2963
|
+
<button class="files-back-btn" onclick="filesGoBack()" title="Back" aria-label="Back">←</button>
|
|
2877
2964
|
<div class="breadcrumbs" id="fileBreadcrumbs"></div>
|
|
2878
2965
|
<div class="file-badges" id="fileBadges"></div>
|
|
2879
2966
|
</div>
|
|
@@ -2981,7 +3068,7 @@
|
|
|
2981
3068
|
<option value="lastRun">Sort: Last Run</option>
|
|
2982
3069
|
</select>
|
|
2983
3070
|
</div>
|
|
2984
|
-
<div style="
|
|
3071
|
+
<div class="tab-purpose" style="padding:0 12px 8px">Monitor and control your scheduled tasks — recurring jobs that run on their own.</div>
|
|
2985
3072
|
<div id="jobsSummary" class="jobs-summary"></div>
|
|
2986
3073
|
<div class="jobs-filter-bar" id="jobsFilterBar">
|
|
2987
3074
|
<button class="jobs-filter-chip active" data-filter="all" onclick="setJobFilter('all')">All</button>
|
|
@@ -3012,6 +3099,7 @@
|
|
|
3012
3099
|
<button onclick="loadIntegratedBeing()" style="padding:6px 12px">Refresh</button>
|
|
3013
3100
|
</div>
|
|
3014
3101
|
</div>
|
|
3102
|
+
<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
3103
|
<div id="ibPerMachineNotice" style="font-size:12px;color:var(--text-dim);display:none">
|
|
3016
3104
|
Integrated-Being on this machine only — cross-machine ledger visibility is not yet implemented.
|
|
3017
3105
|
</div>
|
|
@@ -3133,6 +3221,7 @@
|
|
|
3133
3221
|
<button onclick="loadPrPipeline()" style="padding:6px 12px">Refresh</button>
|
|
3134
3222
|
</div>
|
|
3135
3223
|
</div>
|
|
3224
|
+
<div class="tab-purpose">A live view of your open pull requests as they move through review and CI checks toward merge.</div>
|
|
3136
3225
|
<div id="prPipelinePhaseNotice" style="font-size:12px;color:var(--text-dim)"></div>
|
|
3137
3226
|
<div id="prPipelineEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3138
3227
|
No PR activity to display.
|
|
@@ -3146,11 +3235,11 @@
|
|
|
3146
3235
|
<h2 style="margin:0">Projects</h2>
|
|
3147
3236
|
<button onclick="loadProjects()" style="padding:6px 12px">Refresh</button>
|
|
3148
3237
|
</div>
|
|
3149
|
-
<div
|
|
3150
|
-
Multi-spec project plans. Each project
|
|
3238
|
+
<div class="tab-purpose">
|
|
3239
|
+
Multi-spec project plans. Each project groups related pieces of work and only advances to its next round once its required checks pass.
|
|
3151
3240
|
</div>
|
|
3152
3241
|
<div id="projectsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3153
|
-
No active projects.
|
|
3242
|
+
No active projects yet. Ask your agent to start one from a plan document, and it'll appear here.
|
|
3154
3243
|
</div>
|
|
3155
3244
|
<div id="projectsList" style="display:flex;flex-direction:column;gap:12px"></div>
|
|
3156
3245
|
</div>
|
|
@@ -3173,15 +3262,15 @@
|
|
|
3173
3262
|
<button onclick="loadInitiatives()" style="padding:6px 12px">Refresh</button>
|
|
3174
3263
|
</div>
|
|
3175
3264
|
</div>
|
|
3176
|
-
<div
|
|
3177
|
-
|
|
3265
|
+
<div class="tab-purpose">
|
|
3266
|
+
Long-running work that spans multiple phases, with a status flag on each. Signals: <span style="color:#e27d3b">needs-user</span>,
|
|
3178
3267
|
<span style="color:#d65f5f">next-check-due</span>,
|
|
3179
3268
|
<span style="color:#4a9a4a">ready-to-advance</span>,
|
|
3180
3269
|
<span style="color:#888">stale (>7d)</span>.
|
|
3181
3270
|
</div>
|
|
3182
3271
|
<div id="initiativesDigest" style="display:none;padding:12px;border:1px solid var(--border);border-radius:6px;background:var(--bg-dim)"></div>
|
|
3183
3272
|
<div id="initiativesEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3184
|
-
No initiatives to
|
|
3273
|
+
No initiatives yet. Ask your agent to create one, and it'll appear here.
|
|
3185
3274
|
</div>
|
|
3186
3275
|
<div id="initiativesList" style="display:flex;flex-direction:column;gap:12px"></div>
|
|
3187
3276
|
</div>
|
|
@@ -3195,9 +3284,8 @@
|
|
|
3195
3284
|
<button onclick="loadSecrets()" style="padding:6px 12px">Refresh</button>
|
|
3196
3285
|
</div>
|
|
3197
3286
|
</div>
|
|
3198
|
-
<div
|
|
3199
|
-
Secret Drop — one-time
|
|
3200
|
-
Links expire automatically and are destroyed after submission.
|
|
3287
|
+
<div class="tab-purpose">
|
|
3288
|
+
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
3289
|
</div>
|
|
3202
3290
|
<div id="secretsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3203
3291
|
No pending secret requests.
|
|
@@ -3210,7 +3298,7 @@
|
|
|
3210
3298
|
<h2 style="margin:0">Commitments</h2>
|
|
3211
3299
|
<button onclick="loadCommitments()" style="padding:6px 12px">Refresh</button>
|
|
3212
3300
|
</div>
|
|
3213
|
-
<div
|
|
3301
|
+
<div class="tab-purpose">
|
|
3214
3302
|
Open promises — beacon-watched commitments (⏳). States:
|
|
3215
3303
|
<span style="color:#4a9a4a">pending</span>,
|
|
3216
3304
|
<span style="color:#e27d3b">atRisk</span>,
|
|
@@ -3228,7 +3316,7 @@
|
|
|
3228
3316
|
<h2 style="margin:0">Tokens</h2>
|
|
3229
3317
|
<button onclick="loadTokens()" style="padding:6px 12px">Refresh</button>
|
|
3230
3318
|
</div>
|
|
3231
|
-
<div
|
|
3319
|
+
<div class="tab-purpose">
|
|
3232
3320
|
Token usage rolled up from Claude Code session transcripts. Last 24 hours unless noted.
|
|
3233
3321
|
</div>
|
|
3234
3322
|
|
|
@@ -3264,7 +3352,7 @@
|
|
|
3264
3352
|
<h2 style="margin:0">Resource Usage</h2>
|
|
3265
3353
|
<button onclick="loadResources()" style="padding:6px 12px">Refresh</button>
|
|
3266
3354
|
</div>
|
|
3267
|
-
<div
|
|
3355
|
+
<div class="tab-purpose">
|
|
3268
3356
|
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
3357
|
</div>
|
|
3270
3358
|
|
|
@@ -3304,7 +3392,7 @@
|
|
|
3304
3392
|
<h2 style="margin:0">Blockers</h2>
|
|
3305
3393
|
<button onclick="loadBlockers()" style="padding:6px 12px">Refresh</button>
|
|
3306
3394
|
</div>
|
|
3307
|
-
<div
|
|
3395
|
+
<div class="tab-purpose">
|
|
3308
3396
|
Things that looked like they stopped progress, tracked as <b>decaying hypotheses</b> rather than settled walls.
|
|
3309
3397
|
Each one moves through verification states; a "true blocker" is the best current understanding with a recheck date —
|
|
3310
3398
|
never a permanent "give up".
|
|
@@ -3330,7 +3418,7 @@
|
|
|
3330
3418
|
<button onclick="loadLlmActivity()" style="padding:6px 12px">Refresh</button>
|
|
3331
3419
|
</div>
|
|
3332
3420
|
</div>
|
|
3333
|
-
<div
|
|
3421
|
+
<div class="tab-purpose">
|
|
3334
3422
|
Every decision the system's "autopilot" makes with an AI call — sentinels, gates, background checks.
|
|
3335
3423
|
For each one: which AI provider ran it, how often it actually <b>acted</b> on something vs. found
|
|
3336
3424
|
nothing to do, how often it was <b>skipped</b> to save on rate limits, and what it cost. A row that
|
|
@@ -3364,7 +3452,7 @@
|
|
|
3364
3452
|
<h2 style="margin:0">Routing Map</h2>
|
|
3365
3453
|
<button onclick="loadRoutingMap()" style="padding:6px 12px">Refresh</button>
|
|
3366
3454
|
</div>
|
|
3367
|
-
<div
|
|
3455
|
+
<div class="tab-purpose">
|
|
3368
3456
|
Where each internal job-kind sends its AI calls. Every background check, gate, and
|
|
3369
3457
|
sentinel has a <b>lane</b> (its "nature") and a fallback list of <b>doors</b> — the ways
|
|
3370
3458
|
it can reach a model. This shows, per lane, the ordered door + model list it tries, and
|
|
@@ -3407,7 +3495,7 @@
|
|
|
3407
3495
|
<button onclick="loadRoutingSpend()" style="padding:6px 12px">Refresh</button>
|
|
3408
3496
|
</div>
|
|
3409
3497
|
</div>
|
|
3410
|
-
<div
|
|
3498
|
+
<div class="tab-purpose">
|
|
3411
3499
|
What the internal AI calls cost, and where the paid-door caps sit. The dollar figures are a
|
|
3412
3500
|
<b>reporting</b> view — immutable token counts priced against a reviewed price list on read, so a
|
|
3413
3501
|
price correction reflows automatically. <b>No paid door is live yet</b>, so metered spend is $0;
|
|
@@ -3642,7 +3730,7 @@
|
|
|
3642
3730
|
<h2 style="margin:0">Evidence</h2>
|
|
3643
3731
|
<div style="font-size:12px;color:var(--text-dim)">Per-entity evidence + reverse citations</div>
|
|
3644
3732
|
</div>
|
|
3645
|
-
<div
|
|
3733
|
+
<div class="tab-purpose">
|
|
3646
3734
|
Inspect the evidence trail behind any memory entity, or ask "what cites this?" given a kind + sourceId.
|
|
3647
3735
|
All results are viewer-scope filtered by SemanticMemory before they reach this view.
|
|
3648
3736
|
</div>
|
|
@@ -3701,7 +3789,7 @@
|
|
|
3701
3789
|
<h2 style="margin:0">Threadline</h2>
|
|
3702
3790
|
<button onclick="loadThreadlineBridgeConfig()" style="padding:6px 12px">Refresh</button>
|
|
3703
3791
|
</div>
|
|
3704
|
-
<div
|
|
3792
|
+
<div class="tab-purpose">
|
|
3705
3793
|
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
3794
|
</div>
|
|
3707
3795
|
|
|
@@ -3798,7 +3886,7 @@
|
|
|
3798
3886
|
<h2>Health</h2>
|
|
3799
3887
|
<button class="systems-refresh" onclick="loadSystems()">Refresh</button>
|
|
3800
3888
|
</div>
|
|
3801
|
-
<div style="
|
|
3889
|
+
<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
3890
|
<div id="systemsBanner">
|
|
3803
3891
|
<div style="padding:20px;color:var(--text-dim);text-align:center">Loading...</div>
|
|
3804
3892
|
</div>
|
|
@@ -3867,7 +3955,7 @@
|
|
|
3867
3955
|
<!-- WhatsApp QR panel (hidden by default) -->
|
|
3868
3956
|
<div class="wa-qr-backdrop" id="waQrBackdrop" style="display:none" onclick="closeQrPanel()"></div>
|
|
3869
3957
|
<div class="wa-qr-panel" id="waQrPanel" style="display:none">
|
|
3870
|
-
<button class="wa-close" onclick="closeQrPanel()">×</button>
|
|
3958
|
+
<button class="wa-close" onclick="closeQrPanel()" title="Close" aria-label="Close">×</button>
|
|
3871
3959
|
<h3>WhatsApp Connection</h3>
|
|
3872
3960
|
<p id="waQrMsg">Scan this QR code with WhatsApp to connect</p>
|
|
3873
3961
|
<div id="waQrContainer"></div>
|
|
@@ -5537,7 +5625,7 @@
|
|
|
5537
5625
|
<span style="font-size:11px;color:var(--text-dim)">confidence: ${escapeHtml(confidence)}</span>
|
|
5538
5626
|
<button class="ev-inspect-btn" data-entity-id="${id}" style="margin-left:auto;padding:2px 8px;font-size:11px">Inspect evidence</button>
|
|
5539
5627
|
</div>
|
|
5540
|
-
${content ? `<div
|
|
5628
|
+
${content ? `<div class="tab-purpose">${content}</div>` : ''}
|
|
5541
5629
|
</div>
|
|
5542
5630
|
`;
|
|
5543
5631
|
}
|
|
@@ -7571,7 +7659,7 @@
|
|
|
7571
7659
|
|
|
7572
7660
|
detail.innerHTML = '<div class="job-detail-header">'
|
|
7573
7661
|
+ '<div>'
|
|
7574
|
-
+ '<button class="back-btn" onclick="jobsGoBack()" style="display:none;margin-right:8px">←</button>'
|
|
7662
|
+
+ '<button class="back-btn" onclick="jobsGoBack()" style="display:none;margin-right:8px" title="Back" aria-label="Back">←</button>'
|
|
7575
7663
|
+ '<h3>' + esc(displayName) + '</h3>'
|
|
7576
7664
|
+ '<div class="job-desc">' + esc(job.description || '') + '</div>'
|
|
7577
7665
|
+ '</div>'
|
|
@@ -9342,7 +9430,7 @@
|
|
|
9342
9430
|
try {
|
|
9343
9431
|
const data = await apiFetch(info.endpoint);
|
|
9344
9432
|
panel.innerHTML = '<div class="cap-content-panel">' +
|
|
9345
|
-
'<div class="cap-content-header"><span>' + esc(info.label) + '</span><button onclick="document.getElementById(\'capContentBrowser\').innerHTML=\'\'" style="border:none;background:none;color:var(--text-dim);cursor:pointer;font-size:14px">×</button></div>' +
|
|
9433
|
+
'<div class="cap-content-header"><span>' + esc(info.label) + '</span><button onclick="document.getElementById(\'capContentBrowser\').innerHTML=\'\'" style="border:none;background:none;color:var(--text-dim);cursor:pointer;font-size:14px" title="Close" aria-label="Close">×</button></div>' +
|
|
9346
9434
|
'<div class="cap-content-body">' + renderBrowsableContent(info.renderer, data) + '</div></div>';
|
|
9347
9435
|
} catch (e) {
|
|
9348
9436
|
panel.innerHTML = '<div style="padding:12px;color:var(--red);font-size:12px">Failed to load: ' + esc(e.message) + '</div>';
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./builtin-manifest.schema.json",
|
|
3
3
|
"schemaVersion": 1,
|
|
4
|
-
"generatedAt": "2026-07-
|
|
5
|
-
"instarVersion": "1.3.
|
|
4
|
+
"generatedAt": "2026-07-09T07:11:33.686Z",
|
|
5
|
+
"instarVersion": "1.3.789",
|
|
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,44 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
- **Every dashboard control is now labeled (Dashboard UX Standard F5).** Four icon-only buttons
|
|
9
|
+
(the Files back arrow, the QR-panel close, the Jobs back arrow, and the capability-content
|
|
10
|
+
close) shipped as a bare `←` / `×` glyph with no accessible name — a user (or screen reader)
|
|
11
|
+
had to guess. Each now carries a `title` + `aria-label`. A build-time floor
|
|
12
|
+
(`dashboard-controls-labeled.test.ts`) fails if any future button ships icon-only.
|
|
13
|
+
- **Empty states speak plain language, not API jargon (F6).** Two empty states told the operator
|
|
14
|
+
to "Create one via `POST /projects`" / "`POST /initiatives`" — meaningless to the person
|
|
15
|
+
reading the dashboard. They now say "Ask your agent to start one … and it'll appear here." A
|
|
16
|
+
floor (`dashboard-empty-states.test.ts`) fails on a bare or jargon-leaking empty state.
|
|
17
|
+
- **Shared purpose-line vocabulary documented (F7, soft-first).** `.tab-purpose` is marked the
|
|
18
|
+
canonical purpose-line class; the three legacy variants (`ph-intro`, `features-subtitle`,
|
|
19
|
+
`dropzone-subtitle`) are documented for a tracked, deliberate migration (per spec FD-3, not a
|
|
20
|
+
big-bang restyle).
|
|
21
|
+
- **Broken-asset floor (F8).** `dashboard-assets-resolve.test.ts` fails if a referenced local
|
|
22
|
+
image/icon has no file on disk.
|
|
23
|
+
|
|
24
|
+
## What to Tell Your User
|
|
25
|
+
|
|
26
|
+
A few more dashboard papercuts are gone: every button now has a readable label (better for
|
|
27
|
+
accessibility too), and the "nothing here yet" messages tell you what to do in plain English
|
|
28
|
+
instead of showing a developer command. Nothing to enable — it lands with the release.
|
|
29
|
+
|
|
30
|
+
## Summary of New Capabilities
|
|
31
|
+
|
|
32
|
+
- None — UX polish plus three build-time floors (F5 control labeling, F6 empty-state clarity,
|
|
33
|
+
F8 asset resolution) that fail the build if a future change regresses them.
|
|
34
|
+
|
|
35
|
+
## Evidence
|
|
36
|
+
|
|
37
|
+
`tests/unit/dashboard-controls-labeled.test.ts` (F5): scans every `<button>` in
|
|
38
|
+
`dashboard/index.html`, asserts each has visible text, `title`, or `aria-label` (population floor
|
|
39
|
+
≥30). `tests/unit/dashboard-empty-states.test.ts` (F6): audits the `*Empty*` resting-state
|
|
40
|
+
containers (population floor ≥6) for a real sentence and no `POST /…`/curl jargon.
|
|
41
|
+
`tests/unit/dashboard-assets-resolve.test.ts` (F8): every static local `src`/`url(...)` ref
|
|
42
|
+
resolves to a real file (logo.png confirmed present). All 7 dashboard floor tests green (13
|
|
43
|
+
cases, 1 browser-gated skip). Display-only markup + build-time floors — no runtime surface;
|
|
44
|
+
machine-local static asset; rollback is a plain revert.
|
|
@@ -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,22 @@
|
|
|
1
|
+
# Side-effects review — Dashboard UX Standard floors F5–F8
|
|
2
|
+
|
|
3
|
+
**Change:** `dashboard/index.html` (F5 button labels, F6 empty-state de-jargoning, F7 canonical-class doc) + three static floor tests (`dashboard-controls-labeled` F5, `dashboard-empty-states` F6, `dashboard-assets-resolve` F8). Spec: `docs/specs/dashboard-ux-standard.md` (converged + approved, shipped in #1404). Tier 1 — display-only markup + build-time CI floors; no runtime `src/` change, no decision logic.
|
|
4
|
+
|
|
5
|
+
## Phase 1 — Principle check (signal vs authority)
|
|
6
|
+
Does this touch a decision point that gates information flow / blocks actions / constrains agent behavior? **No.** The changes are (a) HTML label/text attributes rendered to the operator and (b) static test files that fail a *build* if the dashboard regresses. The tests are build-time CI floors, not runtime authorities — they never gate a message, session, or agent action. Signal-vs-authority does not apply (no runtime decision surface).
|
|
7
|
+
|
|
8
|
+
## Phase 4 — Side-effects review
|
|
9
|
+
1. **Over-block:** the floor tests could reject legitimate markup. F5 accepts a button labeled by visible text OR `title` OR `aria-label` OR dynamic (`${…}`/concatenated) content — the full current button population passes; a button labeled *only* by an adjacent element (not itself) would false-flag, acceptable because self-labeling is the accessibility norm and easily satisfied. F6 requires a ≥4-word sentence in each `*Empty*` container — a legitimately terse state would flag, but the 4-word floor is lenient. F8 excludes `data:`/`http(s)`/dynamic `${}` srcs, so only real static local refs are checked. No legitimate current markup is rejected (all 7 dashboard tests green).
|
|
10
|
+
2. **Under-block:** F5 checks `<button>` only, not `<select>`/`<input>` labeling (a tracked F5 follow-up <!-- tracked: topic-29723 -->). F6 audits `*Empty*`-id containers, not every conceivable resting state. F8 checks static local refs only. These are honest partial floors that raise the bar without claiming totality — not regressions.
|
|
11
|
+
3. **Level-of-abstraction fit:** correct layer. A UI-consistency standard is enforced at build time over the shipped markup; there is no smarter runtime gate this should feed (it is not a runtime concern). It extends the existing dashboard-floor test family (`dashboard-tab-purpose`, `dashboard-panel-placement`, `dashboard-nav-reachability`, `dashboard-viewport-scroll`) — same pattern, same layer.
|
|
12
|
+
4. **Signal vs authority compliance:** compliant by absence — no blocking authority added (build-time test, not runtime gate). See Phase 1.
|
|
13
|
+
5. **Interactions:** the new F5/F6/F8 tests are independent scans over `index.html`; none shadows another. The F7 change is a CSS *comment* only — it does not alter the `.tab-purpose` rule and the F3 `dashboard-tab-purpose` test (which recognizes all four purpose-line classes) still passes. No double-fire, no race with cleanup.
|
|
14
|
+
6. **External surfaces:** changes the dashboard HTML the operator sees — 4 icon buttons gain accessible names, 2 empty states lose API jargon ("POST /projects" → plain language). Strictly additive/clarifying; no behavior, endpoint, or data change. No surface visible to other agents/users/systems. No timing/conversation-state dependency.
|
|
15
|
+
7. **Multi-machine posture:** **machine-local BY DESIGN** — `dashboard/index.html` is a static asset shipped in the package and served by each machine's own server; every machine serves the identical shipped file, so there is nothing to replicate, proxy, or transfer. No durable state, no generated URL, no user-facing notice. A single-machine assumption is correct here, not a defect.
|
|
16
|
+
8. **Rollback cost:** trivial — `git revert` the commit. Display-only markup + additive tests; no migration, no agent-state repair, no data change.
|
|
17
|
+
|
|
18
|
+
## Phase 4.5 — No deferrals
|
|
19
|
+
The two under-block follow-ups (F5 select/input labeling; broader F6 coverage) are tracked <!-- tracked: topic-29723 -->. F7 hard-consolidation is deliberately soft-first per the spec's FD-3, not an orphan deferral. No partial fix of an in-scope item is shipped.
|
|
20
|
+
|
|
21
|
+
## Phase 5 — Second pass
|
|
22
|
+
Not required: no block/allow, session-lifecycle, coherence, or sentinel/guard/gate/watchdog surface (Tier 1, display-only).
|
|
@@ -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.
|