instar 1.3.786 → 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.
- package/dashboard/index.html +179 -86
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +2 -2
- package/upgrades/1.3.787.md +42 -0
- package/upgrades/1.3.788.md +45 -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-responsive-fix.md +51 -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;
|
|
@@ -527,6 +544,33 @@
|
|
|
527
544
|
background: var(--bg);
|
|
528
545
|
}
|
|
529
546
|
|
|
547
|
+
/* ── REQUIRED placement for every tab panel declared after </main> ──
|
|
548
|
+
Those panels are direct .app grid children. switchTab() hides the
|
|
549
|
+
sidebar too, so WITHOUT explicit grid placement the lone visible
|
|
550
|
+
panel auto-places into the 280px sidebar COLUMN — the "squished to
|
|
551
|
+
the side" bug (operator report 2026-07-08). Every after-main panel
|
|
552
|
+
MUST carry class="tab-panel" (or one of the container classes that
|
|
553
|
+
already sets grid-column: files/jobs/systems/features/dropzone, or
|
|
554
|
+
ph-root). Enforced structurally:
|
|
555
|
+
tests/unit/dashboard-panel-placement.test.ts fails on a bare panel. */
|
|
556
|
+
.tab-panel {
|
|
557
|
+
grid-column: 1 / -1;
|
|
558
|
+
min-width: 0;
|
|
559
|
+
background: var(--bg);
|
|
560
|
+
}
|
|
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
|
+
|
|
530
574
|
.terminal-header {
|
|
531
575
|
display: flex;
|
|
532
576
|
align-items: center;
|
|
@@ -752,41 +796,69 @@
|
|
|
752
796
|
::-webkit-scrollbar-thumb:hover { background: #444; }
|
|
753
797
|
|
|
754
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. */
|
|
755
802
|
.tab-bar {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
-
|
|
761
|
-
|
|
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;
|
|
762
819
|
}
|
|
763
|
-
.tab-bar
|
|
820
|
+
.app.nav-open .tab-bar { display: flex; }
|
|
764
821
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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;
|
|
770
830
|
color: var(--text-dim);
|
|
771
|
-
|
|
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;
|
|
772
848
|
font-weight: 500;
|
|
773
849
|
cursor: pointer;
|
|
774
|
-
border-bottom: none;
|
|
775
|
-
margin-bottom: -1px;
|
|
776
850
|
transition: color 0.15s, background 0.15s;
|
|
777
|
-
white-space: nowrap;
|
|
778
|
-
flex-shrink: 0;
|
|
779
851
|
}
|
|
780
852
|
|
|
781
853
|
.tab-bar .tab:hover {
|
|
782
|
-
color: var(--text);
|
|
854
|
+
color: var(--text-bright);
|
|
783
855
|
background: var(--bg-hover);
|
|
784
856
|
}
|
|
785
857
|
|
|
786
858
|
.tab-bar .tab.active {
|
|
787
|
-
background: var(--bg-
|
|
859
|
+
background: var(--bg-active);
|
|
788
860
|
color: var(--accent);
|
|
789
|
-
border-color: var(--
|
|
861
|
+
border-color: var(--accent);
|
|
790
862
|
}
|
|
791
863
|
|
|
792
864
|
.tab-bar .tab-count {
|
|
@@ -884,10 +956,10 @@
|
|
|
884
956
|
maturation "you're here" marker. */
|
|
885
957
|
.ph-root {
|
|
886
958
|
--ph-accent: #4ade80;
|
|
887
|
-
/*
|
|
888
|
-
|
|
889
|
-
placement
|
|
890
|
-
|
|
959
|
+
/* Grid placement for after-main panels is now the shared .tab-panel
|
|
960
|
+
contract (see the .tab-panel rule + the placement floor test:
|
|
961
|
+
tests/unit/dashboard-panel-placement.test.ts). ph-root keeps its own
|
|
962
|
+
grid-column because it ALSO constrains width for prose readability. */
|
|
891
963
|
grid-column: 1 / -1;
|
|
892
964
|
max-width: 760px;
|
|
893
965
|
width: 100%;
|
|
@@ -993,6 +1065,7 @@
|
|
|
993
1065
|
.files-container {
|
|
994
1066
|
display: flex;
|
|
995
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 */
|
|
996
1069
|
overflow: hidden;
|
|
997
1070
|
background: var(--bg);
|
|
998
1071
|
}
|
|
@@ -1804,6 +1877,7 @@
|
|
|
1804
1877
|
.jobs-container {
|
|
1805
1878
|
display: flex;
|
|
1806
1879
|
grid-column: 1 / -1;
|
|
1880
|
+
min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
|
|
1807
1881
|
overflow: hidden;
|
|
1808
1882
|
background: var(--bg);
|
|
1809
1883
|
}
|
|
@@ -2178,6 +2252,7 @@
|
|
|
2178
2252
|
/* ── Features Tab (was Discovery) ──────────────────────────── */
|
|
2179
2253
|
.features-container {
|
|
2180
2254
|
grid-column: 1 / -1;
|
|
2255
|
+
min-width: 0; /* F4 — grid child must shrink below content width (no body h-scroll) */
|
|
2181
2256
|
overflow-y: auto;
|
|
2182
2257
|
background: var(--bg);
|
|
2183
2258
|
padding: 20px;
|
|
@@ -2269,7 +2344,7 @@
|
|
|
2269
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; }
|
|
2270
2345
|
|
|
2271
2346
|
/* ── Systems Tab ──────────────────────────────────────────── */
|
|
2272
|
-
.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; }
|
|
2273
2348
|
.systems-main { max-width: 960px; margin: 0 auto; }
|
|
2274
2349
|
.systems-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
|
|
2275
2350
|
.systems-header h2 { font-size: 16px; font-weight: 600; color: var(--text-bright); }
|
|
@@ -2735,32 +2810,47 @@
|
|
|
2735
2810
|
<img class="logo" src="/dashboard/logo.png" alt="Instar">
|
|
2736
2811
|
<h1>Instar Dashboard</h1>
|
|
2737
2812
|
<button class="nav-toggle" id="navToggle" aria-label="Open navigation menu" aria-expanded="false" onclick="toggleNavMenu()">☰ <span id="navToggleLabel">Sessions</span></button>
|
|
2738
|
-
<nav class="tab-bar" id="tabBar">
|
|
2739
|
-
<
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
<
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
<
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
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 & 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 & 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 & 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 & 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>
|
|
2764
2854
|
</nav>
|
|
2765
2855
|
</div>
|
|
2766
2856
|
<div class="vital-signs" id="vitalSigns">
|
|
@@ -2800,6 +2890,7 @@
|
|
|
2800
2890
|
<button class="new-session-btn" onclick="openNewSessionModal()" title="New session">+</button>
|
|
2801
2891
|
</div>
|
|
2802
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>
|
|
2803
2894
|
<div class="session-list" id="sessionList">
|
|
2804
2895
|
<div class="empty-state" id="emptyState">
|
|
2805
2896
|
<div class="icon">💭</div>
|
|
@@ -2852,6 +2943,7 @@
|
|
|
2852
2943
|
<div class="file-tree-header">
|
|
2853
2944
|
<h2>Files</h2>
|
|
2854
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>
|
|
2855
2947
|
<div class="file-tree-list" id="fileTreeList">
|
|
2856
2948
|
<div class="file-loading" id="fileTreeLoading">Loading...</div>
|
|
2857
2949
|
</div>
|
|
@@ -2966,7 +3058,7 @@
|
|
|
2966
3058
|
<option value="lastRun">Sort: Last Run</option>
|
|
2967
3059
|
</select>
|
|
2968
3060
|
</div>
|
|
2969
|
-
<div style="
|
|
3061
|
+
<div class="tab-purpose" style="padding:0 12px 8px">Monitor and control your scheduled tasks — recurring jobs that run on their own.</div>
|
|
2970
3062
|
<div id="jobsSummary" class="jobs-summary"></div>
|
|
2971
3063
|
<div class="jobs-filter-bar" id="jobsFilterBar">
|
|
2972
3064
|
<button class="jobs-filter-chip active" data-filter="all" onclick="setJobFilter('all')">All</button>
|
|
@@ -2990,13 +3082,14 @@
|
|
|
2990
3082
|
</div>
|
|
2991
3083
|
|
|
2992
3084
|
<!-- Integrated-Being Tab (Integrated-Being v1) -->
|
|
2993
|
-
<div id="integratedBeingPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3085
|
+
<div id="integratedBeingPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
2994
3086
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
2995
3087
|
<h2 style="margin:0">Integrated-Being</h2>
|
|
2996
3088
|
<div>
|
|
2997
3089
|
<button onclick="loadIntegratedBeing()" style="padding:6px 12px">Refresh</button>
|
|
2998
3090
|
</div>
|
|
2999
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>
|
|
3000
3093
|
<div id="ibPerMachineNotice" style="font-size:12px;color:var(--text-dim);display:none">
|
|
3001
3094
|
Integrated-Being on this machine only — cross-machine ledger visibility is not yet implemented.
|
|
3002
3095
|
</div>
|
|
@@ -3111,13 +3204,14 @@
|
|
|
3111
3204
|
<!-- Read-only: NO action buttons that mutate eligibility. All PR-authored -->
|
|
3112
3205
|
<!-- content rendered via textContent, never innerHTML — XSS defense rule -->
|
|
3113
3206
|
<!-- for the dashboard per spec §"Dashboard surface rules". -->
|
|
3114
|
-
<div id="prPipelinePanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3207
|
+
<div id="prPipelinePanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3115
3208
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3116
3209
|
<h2 style="margin:0">PR Pipeline</h2>
|
|
3117
3210
|
<div>
|
|
3118
3211
|
<button onclick="loadPrPipeline()" style="padding:6px 12px">Refresh</button>
|
|
3119
3212
|
</div>
|
|
3120
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>
|
|
3121
3215
|
<div id="prPipelinePhaseNotice" style="font-size:12px;color:var(--text-dim)"></div>
|
|
3122
3216
|
<div id="prPipelineEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3123
3217
|
No PR activity to display.
|
|
@@ -3126,13 +3220,13 @@
|
|
|
3126
3220
|
</div>
|
|
3127
3221
|
|
|
3128
3222
|
<!-- Projects Tab — PROJECT-SCOPE-SPEC Phase 1.10 read-only view -->
|
|
3129
|
-
<div id="projectsPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3223
|
+
<div id="projectsPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3130
3224
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3131
3225
|
<h2 style="margin:0">Projects</h2>
|
|
3132
3226
|
<button onclick="loadProjects()" style="padding:6px 12px">Refresh</button>
|
|
3133
3227
|
</div>
|
|
3134
|
-
<div
|
|
3135
|
-
Multi-spec project plans. Each project
|
|
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.
|
|
3136
3230
|
</div>
|
|
3137
3231
|
<div id="projectsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3138
3232
|
No active projects. Create one via <code>POST /projects</code> with a plan-doc path.
|
|
@@ -3141,7 +3235,7 @@
|
|
|
3141
3235
|
</div>
|
|
3142
3236
|
|
|
3143
3237
|
<!-- Initiatives Tab — multi-phase long-running work -->
|
|
3144
|
-
<div id="initiativesPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3238
|
+
<div id="initiativesPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3145
3239
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3146
3240
|
<h2 style="margin:0">Initiatives</h2>
|
|
3147
3241
|
<div style="display:flex;gap:8px;align-items:center">
|
|
@@ -3158,8 +3252,8 @@
|
|
|
3158
3252
|
<button onclick="loadInitiatives()" style="padding:6px 12px">Refresh</button>
|
|
3159
3253
|
</div>
|
|
3160
3254
|
</div>
|
|
3161
|
-
<div
|
|
3162
|
-
|
|
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>,
|
|
3163
3257
|
<span style="color:#d65f5f">next-check-due</span>,
|
|
3164
3258
|
<span style="color:#4a9a4a">ready-to-advance</span>,
|
|
3165
3259
|
<span style="color:#888">stale (>7d)</span>.
|
|
@@ -3172,7 +3266,7 @@
|
|
|
3172
3266
|
</div>
|
|
3173
3267
|
|
|
3174
3268
|
<!-- Commitments Tab (Open Promises) -->
|
|
3175
|
-
<div id="secretsPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3269
|
+
<div id="secretsPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3176
3270
|
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
|
|
3177
3271
|
<h2 style="margin:0">Secrets</h2>
|
|
3178
3272
|
<div style="display:flex;gap:8px">
|
|
@@ -3180,9 +3274,8 @@
|
|
|
3180
3274
|
<button onclick="loadSecrets()" style="padding:6px 12px">Refresh</button>
|
|
3181
3275
|
</div>
|
|
3182
3276
|
</div>
|
|
3183
|
-
<div
|
|
3184
|
-
Secret Drop — one-time
|
|
3185
|
-
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.
|
|
3186
3279
|
</div>
|
|
3187
3280
|
<div id="secretsEmpty" style="padding:40px;text-align:center;color:var(--text-dim);display:none">
|
|
3188
3281
|
No pending secret requests.
|
|
@@ -3190,12 +3283,12 @@
|
|
|
3190
3283
|
<div id="secretsList" style="display:flex;flex-direction:column;gap:12px"></div>
|
|
3191
3284
|
</div>
|
|
3192
3285
|
|
|
3193
|
-
<div id="commitmentsPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3286
|
+
<div id="commitmentsPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3194
3287
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3195
3288
|
<h2 style="margin:0">Commitments</h2>
|
|
3196
3289
|
<button onclick="loadCommitments()" style="padding:6px 12px">Refresh</button>
|
|
3197
3290
|
</div>
|
|
3198
|
-
<div
|
|
3291
|
+
<div class="tab-purpose">
|
|
3199
3292
|
Open promises — beacon-watched commitments (⏳). States:
|
|
3200
3293
|
<span style="color:#4a9a4a">pending</span>,
|
|
3201
3294
|
<span style="color:#e27d3b">atRisk</span>,
|
|
@@ -3208,12 +3301,12 @@
|
|
|
3208
3301
|
</div>
|
|
3209
3302
|
|
|
3210
3303
|
<!-- Tokens Tab — read-only token-usage observability -->
|
|
3211
|
-
<div id="tokensPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3304
|
+
<div id="tokensPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3212
3305
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3213
3306
|
<h2 style="margin:0">Tokens</h2>
|
|
3214
3307
|
<button onclick="loadTokens()" style="padding:6px 12px">Refresh</button>
|
|
3215
3308
|
</div>
|
|
3216
|
-
<div
|
|
3309
|
+
<div class="tab-purpose">
|
|
3217
3310
|
Token usage rolled up from Claude Code session transcripts. Last 24 hours unless noted.
|
|
3218
3311
|
</div>
|
|
3219
3312
|
|
|
@@ -3244,12 +3337,12 @@
|
|
|
3244
3337
|
|
|
3245
3338
|
<!-- Resource Usage tab — per-agent CPU + memory (ResourceLedger Phase B).
|
|
3246
3339
|
Read-only observability; mirrors the Tokens tab. -->
|
|
3247
|
-
<div id="resourcesPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3340
|
+
<div id="resourcesPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3248
3341
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3249
3342
|
<h2 style="margin:0">Resource Usage</h2>
|
|
3250
3343
|
<button onclick="loadResources()" style="padding:6px 12px">Refresh</button>
|
|
3251
3344
|
</div>
|
|
3252
|
-
<div
|
|
3345
|
+
<div class="tab-purpose">
|
|
3253
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.
|
|
3254
3347
|
</div>
|
|
3255
3348
|
|
|
@@ -3284,12 +3377,12 @@
|
|
|
3284
3377
|
true-blocker. A true-blocker is "best current understanding — recheck after <date>",
|
|
3285
3378
|
never "stop trying". Read-only here; data from GET /blockers. detectedText and all
|
|
3286
3379
|
free-text are UNTRUSTED and HTML-escaped before render. 503 = feature off. -->
|
|
3287
|
-
<div id="blockersPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3380
|
+
<div id="blockersPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3288
3381
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3289
3382
|
<h2 style="margin:0">Blockers</h2>
|
|
3290
3383
|
<button onclick="loadBlockers()" style="padding:6px 12px">Refresh</button>
|
|
3291
3384
|
</div>
|
|
3292
|
-
<div
|
|
3385
|
+
<div class="tab-purpose">
|
|
3293
3386
|
Things that looked like they stopped progress, tracked as <b>decaying hypotheses</b> rather than settled walls.
|
|
3294
3387
|
Each one moves through verification states; a "true blocker" is the best current understanding with a recheck date —
|
|
3295
3388
|
never a permanent "give up".
|
|
@@ -3303,7 +3396,7 @@
|
|
|
3303
3396
|
Every LLM call the system makes on its own behalf: which component, which
|
|
3304
3397
|
provider/model, whether it acted or no-op'd, was skipped, cost + latency.
|
|
3305
3398
|
Read-only; data from /metrics/features. -->
|
|
3306
|
-
<div id="llmActivityPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3399
|
+
<div id="llmActivityPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3307
3400
|
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
|
|
3308
3401
|
<h2 style="margin:0">LLM Activity</h2>
|
|
3309
3402
|
<div style="display:flex;gap:8px;align-items:center">
|
|
@@ -3315,7 +3408,7 @@
|
|
|
3315
3408
|
<button onclick="loadLlmActivity()" style="padding:6px 12px">Refresh</button>
|
|
3316
3409
|
</div>
|
|
3317
3410
|
</div>
|
|
3318
|
-
<div
|
|
3411
|
+
<div class="tab-purpose">
|
|
3319
3412
|
Every decision the system's "autopilot" makes with an AI call — sentinels, gates, background checks.
|
|
3320
3413
|
For each one: which AI provider ran it, how often it actually <b>acted</b> on something vs. found
|
|
3321
3414
|
nothing to do, how often it was <b>skipped</b> to save on rate limits, and what it cost. A row that
|
|
@@ -3344,12 +3437,12 @@
|
|
|
3344
3437
|
model it uses and its full ordered fallback tier list, with injection-safe /
|
|
3345
3438
|
money-gated / critical-gate flags. Read-only display; data from
|
|
3346
3439
|
/intelligence/routing/chains. No controls — the map only DISPLAYS the routing. -->
|
|
3347
|
-
<div id="routingMapPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3440
|
+
<div id="routingMapPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3348
3441
|
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
|
|
3349
3442
|
<h2 style="margin:0">Routing Map</h2>
|
|
3350
3443
|
<button onclick="loadRoutingMap()" style="padding:6px 12px">Refresh</button>
|
|
3351
3444
|
</div>
|
|
3352
|
-
<div
|
|
3445
|
+
<div class="tab-purpose">
|
|
3353
3446
|
Where each internal job-kind sends its AI calls. Every background check, gate, and
|
|
3354
3447
|
sentinel has a <b>lane</b> (its "nature") and a fallback list of <b>doors</b> — the ways
|
|
3355
3448
|
it can reach a model. This shows, per lane, the ordered door + model list it tries, and
|
|
@@ -3379,7 +3472,7 @@
|
|
|
3379
3472
|
READ + every metered paid-door key with its caps and honest not-live/$0 state.
|
|
3380
3473
|
Read-only: data from /routing-spend/summary + /routing-spend/caps. No money controls
|
|
3381
3474
|
(caps adjust, go-live, alerts are later, dark increments). -->
|
|
3382
|
-
<div id="spendPanel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3475
|
+
<div id="spendPanel" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3383
3476
|
<div style="display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap">
|
|
3384
3477
|
<h2 style="margin:0">Spend</h2>
|
|
3385
3478
|
<div style="display:flex;gap:8px;align-items:center">
|
|
@@ -3392,7 +3485,7 @@
|
|
|
3392
3485
|
<button onclick="loadRoutingSpend()" style="padding:6px 12px">Refresh</button>
|
|
3393
3486
|
</div>
|
|
3394
3487
|
</div>
|
|
3395
|
-
<div
|
|
3488
|
+
<div class="tab-purpose">
|
|
3396
3489
|
What the internal AI calls cost, and where the paid-door caps sit. The dollar figures are a
|
|
3397
3490
|
<b>reporting</b> view — immutable token counts priced against a reviewed price list on read, so a
|
|
3398
3491
|
price correction reflows automatically. <b>No paid door is live yet</b>, so metered spend is $0;
|
|
@@ -3622,12 +3715,12 @@
|
|
|
3622
3715
|
</section>
|
|
3623
3716
|
</div>
|
|
3624
3717
|
|
|
3625
|
-
<div id="evidenceTab" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3718
|
+
<div id="evidenceTab" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3626
3719
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3627
3720
|
<h2 style="margin:0">Evidence</h2>
|
|
3628
3721
|
<div style="font-size:12px;color:var(--text-dim)">Per-entity evidence + reverse citations</div>
|
|
3629
3722
|
</div>
|
|
3630
|
-
<div
|
|
3723
|
+
<div class="tab-purpose">
|
|
3631
3724
|
Inspect the evidence trail behind any memory entity, or ask "what cites this?" given a kind + sourceId.
|
|
3632
3725
|
All results are viewer-scope filtered by SemanticMemory before they reach this view.
|
|
3633
3726
|
</div>
|
|
@@ -3681,12 +3774,12 @@
|
|
|
3681
3774
|
</div>
|
|
3682
3775
|
|
|
3683
3776
|
<!-- Threadline Tab — agent-to-agent conversations + Telegram bridge settings -->
|
|
3684
|
-
<div id="threadlineTab" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3777
|
+
<div id="threadlineTab" class="tab-panel" style="display:none;flex-direction:column;padding:20px;gap:16px;overflow-y:auto">
|
|
3685
3778
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
3686
3779
|
<h2 style="margin:0">Threadline</h2>
|
|
3687
3780
|
<button onclick="loadThreadlineBridgeConfig()" style="padding:6px 12px">Refresh</button>
|
|
3688
3781
|
</div>
|
|
3689
|
-
<div
|
|
3782
|
+
<div class="tab-purpose">
|
|
3690
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.
|
|
3691
3784
|
</div>
|
|
3692
3785
|
|
|
@@ -3783,7 +3876,7 @@
|
|
|
3783
3876
|
<h2>Health</h2>
|
|
3784
3877
|
<button class="systems-refresh" onclick="loadSystems()">Refresh</button>
|
|
3785
3878
|
</div>
|
|
3786
|
-
<div style="
|
|
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>
|
|
3787
3880
|
<div id="systemsBanner">
|
|
3788
3881
|
<div style="padding:20px;color:var(--text-dim);text-align:center">Loading...</div>
|
|
3789
3882
|
</div>
|
|
@@ -5522,7 +5615,7 @@
|
|
|
5522
5615
|
<span style="font-size:11px;color:var(--text-dim)">confidence: ${escapeHtml(confidence)}</span>
|
|
5523
5616
|
<button class="ev-inspect-btn" data-entity-id="${id}" style="margin-left:auto;padding:2px 8px;font-size:11px">Inspect evidence</button>
|
|
5524
5617
|
</div>
|
|
5525
|
-
${content ? `<div
|
|
5618
|
+
${content ? `<div class="tab-purpose">${content}</div>` : ''}
|
|
5526
5619
|
</div>
|
|
5527
5620
|
`;
|
|
5528
5621
|
}
|
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-09T06:42:14.302Z",
|
|
5
|
+
"instarVersion": "1.3.788",
|
|
6
6
|
"entryCount": 202,
|
|
7
7
|
"entries": {
|
|
8
8
|
"hook:session-start": {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- assembled-by: assemble-next-md -->
|
|
4
|
+
<!-- bump: patch -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
- **The "squished to the side" bug is fixed structurally.** Fourteen dashboard tab panels
|
|
9
|
+
(Routing Map, Spend, Tokens, LLM Activity, Integrated Being, PR Pipeline, Projects,
|
|
10
|
+
Initiatives, Secrets, Commitments, Resources, Blockers, Evidence, Threadline) are declared
|
|
11
|
+
after `</main>` and are therefore direct `.app` grid children; with the sidebar hidden they
|
|
12
|
+
auto-placed into the 280px sidebar COLUMN, rendering all content in a ~185px strip on a
|
|
13
|
+
1280px viewport (operator screenshots, topic 29723). A shared `.tab-panel` class
|
|
14
|
+
(`grid-column: 1 / -1; min-width: 0`) now places every one of them across the full content
|
|
15
|
+
area — one rule instead of fourteen inline copies. The pre-existing `.ph-root` tabs keep
|
|
16
|
+
their own placement + prose width.
|
|
17
|
+
- **A placement floor makes the bug unrepeatable.** `tests/unit/dashboard-panel-placement.test.ts`
|
|
18
|
+
scans the after-main markup region and fails the build when a top-level panel lacks a
|
|
19
|
+
placement-carrying class (with an instructive message naming the panel and the fix), asserts
|
|
20
|
+
the `.tab-panel` rule keeps its grid span, and guards its own matcher with a population floor.
|
|
21
|
+
The old defense was a CSS comment on `.ph-root` — a wish; every panel added since repeated
|
|
22
|
+
the bug. This is the guarantee (Structure > Willpower).
|
|
23
|
+
|
|
24
|
+
## What to Tell Your User
|
|
25
|
+
|
|
26
|
+
The dashboard tabs that used to render squeezed into a narrow strip on the left of a desktop
|
|
27
|
+
window — including the new Routing Map and Spend tabs — now use the full width of the window.
|
|
28
|
+
Nothing to enable; it's just fixed everywhere once the release lands.
|
|
29
|
+
|
|
30
|
+
## Summary of New Capabilities
|
|
31
|
+
|
|
32
|
+
- None — this is a layout bug fix. (It also adds a build-time guard so a future dashboard tab
|
|
33
|
+
can't reintroduce the same squished layout.)
|
|
34
|
+
|
|
35
|
+
## Evidence
|
|
36
|
+
|
|
37
|
+
`tests/unit/dashboard-panel-placement.test.ts` — 4 cases: rule present + spans grid, every
|
|
38
|
+
placement class actually declares grid-column, no bare after-main panel (negative control
|
|
39
|
+
verified: stripping one panel's class fails naming exactly that panel), matcher-anchor guard
|
|
40
|
+
(the slice skips CSS/JS mentions of `</main>`). Real-browser (headless Chromium) before/after
|
|
41
|
+
screenshots at 1280×800: content strip ~260px before, full-width after; 390×844 rendering is
|
|
42
|
+
byte-identical before vs after (placement-only change). All 106 dashboard-reading unit tests green.
|
|
@@ -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,51 @@
|
|
|
1
|
+
# Side-Effects Review — Dashboard responsive fix (.tab-panel placement + floor test)
|
|
2
|
+
|
|
3
|
+
**Version / slug:** `dashboard-responsive-fix`
|
|
4
|
+
**Date:** `2026-07-08`
|
|
5
|
+
**Author:** `Instar Agent (echo)`
|
|
6
|
+
**Second-pass reviewer:** `not required`
|
|
7
|
+
|
|
8
|
+
## Summary of the change
|
|
9
|
+
|
|
10
|
+
Fixes the "everything is squished to the side" dashboard bug (operator report with screenshots, topic 29723, 2026-07-08): fourteen tab panels declared after `</main>` in `dashboard/index.html` are direct `.app` grid children with no explicit grid placement, so the lone visible panel auto-places into the 280px sidebar column on desktop. The fix adds ONE shared `.tab-panel` CSS class (`grid-column: 1 / -1; min-width: 0`) applied to all fourteen panels (Integrated Being, PR Pipeline, Projects, Initiatives, Secrets, Commitments, Tokens, Resources, Blockers, LLM Activity, Routing Map, Spend, Evidence, Threadline), plus a regression floor test (`tests/unit/dashboard-panel-placement.test.ts`) that fails the build when a future after-main panel lacks a placement-carrying class. The pre-existing `.ph-root` per-tab fix is left untouched; its comment now points at the shared contract. Files touched: `dashboard/index.html`, `tests/unit/dashboard-panel-placement.test.ts`, `docs/specs/dashboard-responsive-fix.eli16.md`, this artifact, and a release fragment.
|
|
11
|
+
|
|
12
|
+
## Decision-point inventory
|
|
13
|
+
|
|
14
|
+
No decision-point surface. This change is presentation-layer CSS/HTML plus a static test. It gates no information flow, blocks no actions, filters no messages, and 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 — over-block not applicable to agent/user traffic. For the commit-time ratchet: the floor test could "over-block" a future legitimate panel that is genuinely out of normal flow (e.g. a new fixed-position overlay). Mitigation is built in: the `OUT_OF_FLOW_EXEMPT` list with a required justification comment, and the failure message names the exact panel and both resolution paths.
|
|
21
|
+
|
|
22
|
+
## 2. Under-block
|
|
23
|
+
|
|
24
|
+
The floor test keys on 4-space-indented `<div id=...>` openers in the after-`</main>` markup region (all 27 current top-level panels match this shape). A future panel authored at unconventional indentation, as a non-div element, or injected purely from JS would not be seen by the floor. Accepted: the regression vector this floor closes is the observed copy-paste pattern (14 real instances); the population-sanity assertion (≥20 openers visible) fails loudly if the matcher ever goes blind wholesale. Deeper enforcement (viewport smoke tests) belongs to the Dashboard UX Standard work tracked in the topic-29723 working brief. <!-- tracked: topic-29723 dashboard-ux-brief Increment 2 -->
|
|
25
|
+
|
|
26
|
+
## 3. Level-of-abstraction fit
|
|
27
|
+
|
|
28
|
+
Right layer. The bug is a CSS grid-placement defect; the fix is a shared CSS class at the layout layer where the sibling container classes (`files-container`, `jobs-container`, `systems-container`, `features-container`, `dropzone-container`) already solve the same problem the same way. The alternative — per-panel inline styles — is exactly the pattern that produced fourteen copies of the bug. No smarter existing gate applies (this is 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 — it is inert presentation markup. The unit test is a build-time ratchet, the same class as every other test in `tests/unit/`; it holds commit-blocking authority through CI exactly like all tests do, with deterministic, human-readable failure output.
|
|
33
|
+
|
|
34
|
+
## 5. Interactions
|
|
35
|
+
|
|
36
|
+
- Interacts with `switchTab()` only passively: switchTab toggles inline `display`; the new class carries grid placement only, so show/hide behavior is unchanged.
|
|
37
|
+
- `.ph-root` panels keep their own placement + 760px prose width; the new rule does not apply to them (no double-fire; the floor test accepts either class).
|
|
38
|
+
- Mobile breakpoint (`@media max-width: 768px`) collapses `.app` to one column; `grid-column: 1 / -1` resolves identically there — verified byte-identical mobile rendering before vs after the change.
|
|
39
|
+
- No other rule targets `.tab-panel` (fresh class name; grep-verified single definition).
|
|
40
|
+
|
|
41
|
+
## 6. External surfaces
|
|
42
|
+
|
|
43
|
+
Visible change: dashboard tabs render full-width on desktop instead of squished — the operator-requested fix. No API change, no data change, no cross-agent surface, no timing/conversation-state dependency. Verified with real-browser (headless Chromium) before/after screenshots at 1280×800 and 390×844: desktop fixed; mobile rendering byte-identical to pre-change.
|
|
44
|
+
|
|
45
|
+
## 7. Multi-machine posture (Cross-Machine Coherence)
|
|
46
|
+
|
|
47
|
+
Machine-local BY DESIGN in the same sense as all dashboard markup: the HTML ships identically to every machine with the release; each machine serves its own copy. No replicated state, no machine-boundary URL, no one-voice notice surface. Both of the operator's machines get the fix as they pick up the release.
|
|
48
|
+
|
|
49
|
+
## 8. Rollback cost
|
|
50
|
+
|
|
51
|
+
Trivial: revert the commit (CSS class + class attributes + one test file). No data migration, no agent state, no config. A revert restores the prior (buggy) rendering and deletes the floor test with it.
|
|
@@ -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.
|