Skip to content

Commit fd12233

Browse files
wip v28
1 parent 7128529 commit fd12233

22 files changed

Lines changed: 435 additions & 29 deletions

BITCODE_SPEC_V28_NOTES.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ The standalone `protocol-demonstration` runtime must not import UAPI or commerci
136136
V28 closes this as a boundary baseline; V29 must continue commercializing freshly ported protocol internals into cleaner packages and narrower APIs.
137137
Dual-lane setup smoke also found that the embedded demonstration witness could overwrite the commercial Terminal browser title with `Bitcode Demonstration`.
138138
That is a commercial/demonstration boundary leak, so V28 now requires the mounted witness bundle to guard document-title writes when hosted inside `/terminal`; standalone demonstration may keep its demonstration title.
139+
The same deployment-readiness pass found a Vercel production build failure in `lib/bitcode-app-context.ts` because the newly formalized `@bitcode/protocol` package was present as a workspace dependency but had not been added to the Next transpilation/webpack alias path.
140+
V28 treats this as a commercial MVP blocker: formal protocol package imports must resolve during local and Vercel `next build`.
141+
The UAPI Next configuration now transpiles `@bitcode/protocol`, aliases its root import to `packages/protocol/src/index.js`, and the commercial protocol boundary test asserts this resolver so the standalone demonstration separation remains deployable.
139142

140143
Manual QA was re-ordered on May 8, 2026 into two directionalities.
141144
The first is natural operator progression: connect wallet/GitHub/identity prerequisites, perform the fastest simple Need through Fit/settlement/delivery readback, then perform the fastest simple Give through measurement/earning/settlement readback.
@@ -148,6 +151,21 @@ The Mock lane runs first with deterministic mocks enabled so visual behavior, co
148151
The Testnet-readiness lane follows with public mock flags disabled and `NEXT_PUBLIC_BITCODE_ENV=testnet`, preserving Exchange/Auxillaries/Create Account entry while exposing real provider, signer, GitHub, database, BTC broadcaster, ledger observer, and interface readiness.
149152
V28 does not require that every live credential already be provisioned, but it does require that missing live/testnet dependencies fail closed with readable readiness rather than silent mocked success.
150153
This dual-lane process is intentionally earlier than V34 deployment deepening: it guards V28 MVP QA against mock-only confidence while leaving production deployment, host capabilities, distributed execution, CI/CD promotion, and operational rollback to V34.
154+
The first restarted 1A mock-lane pass showed a readiness/cache edge case: Auxillaries indicated mock mode, but the top chrome rendered zero BTC/BTD and an empty notification tray after prior mock values had been visible.
155+
V28 closes this as an MVP QA bug, not a user-data polish item.
156+
Master mock mode must activate auxillaries mock data consistently in client and server code, public mock flags must be visible to the Next client bundle, and shared user-data cache must revalidate on fresh mounts so environment-lane changes cannot preserve anonymous or zero-valued state.
157+
The same 1A verification also found that simultaneous mock and testnet-readiness dev servers must not share the same Next build artifact directory.
158+
V28 QA therefore requires lane-specific `NEXT_DIST_DIR` values for local dual-lane runs, because the client bundle compiles public env values while the server routes read process env at request time.
159+
Without isolated artifacts, the testnet-readiness lane can appear mock-authenticated even while its `/api/auxillaries/data` response correctly returns anonymous zero-state.
160+
161+
The next 1A Auxillaries/Profile/Connects slice exposed four MVP shell issues and closed them in source and tests.
162+
The active contained pane must own vertical scrolling; the overlay shell may constrain height, but it must not trap the operator above lower profile, wallet, or repository controls.
163+
Selector-card state must render as visual indicators rather than `laneactive` / `laneready` prose, while retaining accessible labels and machine-readable state for tests.
164+
Async profile props must hydrate into editable local fields after mock/live data arrives, so display name, bio, company, avatar, and team data do not remain blank after the email field has already loaded.
165+
The BTC/BTD widget must render a compact wallet-reading posture while fresh lane-specific data loads or while stale anonymous zero-state is being revalidated; zero BTC/BTD may be shown only as a settled data state, not as an unceremonious hydration flash.
166+
167+
These changes remain V28 scope because they are MVP-readiness and trust issues.
168+
The deeper Auxillaries version retains hierarchy, spacing, diagnostics, recovery, and provider-management expansion after V28 proves the contained shell, mocked prerequisite reads, fail-closed testnet-readiness, and no-console-error baseline.
151169

152170
## Promotion Review Basis
153171

BITCODE_V28_QA.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,33 @@ Implemented after Pass 2, pending next manual QA confirmation:
171171
| Testnet-readiness | `http://127.0.0.1:3001/terminal` | renders HTTP 200 after cold compile | Server runs with public mock flags disabled and `NEXT_PUBLIC_BITCODE_ENV=testnet`; missing live credentials/providers are expected to appear as blocked readiness, not success. |
172172
| Both | `/terminal` browser title | pass | Follow-up smoke confirms both lanes keep the commercial `Bitcode Terminal` document title after the embedded witness title guard. |
173173
| Both | 2026-05-08 dev-server restart for Pass 3A | pass | Mock server restarted on `3000`; testnet-readiness server restarted on `3001`; curl and Playwright smoke confirm `/terminal` HTTP 200, `Bitcode Terminal` title, no page errors, and no non-HMR internal 404s after reload. |
174+
| Vercel deployment build | pass after fix | Latest deployment failed because `lib/bitcode-app-context.ts` imported `@bitcode/protocol` before Next's workspace-package resolver knew how to transpile/alias the new formal protocol package. V28 now adds `@bitcode/protocol` to `transpilePackages`, aliases the root import to `packages/protocol/src/index.js`, and verifies the resolver in `tests/protocolCommercialBoundary.test.ts`. Local `pnpm run build` from `uapi` now passes. |
175+
| Mock top chrome during 1A | pass | Manual reconfirmation on 2026-05-08 accepted the fixed mock balance, notification, and profile posture. V28 now treats master mock mode as sufficient for auxillaries mock data in client and server code, explicitly exposes public mock flags through Next config, and revalidates stale module-level user data on new mount so lane transitions cannot keep anonymous/zero cached data. |
176+
| Dual-lane dev artifact isolation | pass | Manual reconfirmation on 2026-05-08 accepted the mock/testnet-readiness separation. V28 QA servers use lane-specific `NEXT_DIST_DIR` values so public mock env compilation is isolated per lane. |
177+
178+
### 2026-05-08 Pass 3A: Auxillaries Profile And Connects Readiness
179+
180+
| Check | Result | Notes |
181+
| --- | --- | --- |
182+
| Auxillaries overlay opens and pane selection works | pass | Manual QA confirmed the overlay opens and panes remain selectable. |
183+
| Inner pane scrolling | fixed | Manual QA found the contained pane could not scroll down. V28 now constrains the overlay shell height, keeps the pane as the scroll container, and verifies the active pane can advance `scrollTop` with `overflowY:auto`. |
184+
| Selector card state rendering | fixed | Manual QA found raw `laneactive` / `laneready` text. V28 replaces visible state prose with active/ready/locked visual indicators and keeps state available through `aria-label`, `title`, and `data-state` for accessibility and tests. |
185+
| Mock profile fields | fixed | Manual QA confirmed email but found display name and bio missing. V28 now hydrates async initial profile props into local editable state and mock data supplies display name, bio, and company posture. |
186+
| Connected repositories | pass | Manual QA confirmed mocked connected repos; browser verification confirms `Connected Repositories (3)` and `bitcode/economic-ledger` render in Connects. |
187+
| BTD/BTC first-load posture | fixed | Manual QA found the top-right widget flashing anonymous zero-state before hydrated values. V28 now surfaces a compact `Reading wallet` posture while fresh lane-specific user data is loading or revalidating stale cached zero-state. |
188+
| Console/page errors | pass | Manual QA reported none; focused browser verification reports no product console messages and no page errors. |
189+
190+
Automated verification for this slice:
191+
192+
- `pnpm -C uapi exec jest --runInBand tests/useUserDataHydration.test.tsx tests/btdTrackerLoading.test.tsx tests/auxillariesWorkspacePanels.test.tsx tests/featureFlagsMockMode.test.ts`: pass.
193+
- `pnpm -C uapi exec playwright test tests/e2e/commercial-mvp.auxillaries.spec.ts --project=laptop --workers=1`: 8 passed.
194+
- Focused browser verification on the mock lane: raw lane text count `0`, state indicator count `4`, Profile display name `Avery Mercer`, Profile bio `Reviewing the Bitcode commercial surface in deterministic mock mode.`, pane `scrollTop` advances, Connects repos present, no product console/page errors.
195+
196+
Deferred to V31 from this pass:
197+
198+
| Finding | V31 disposition |
199+
| --- | --- |
200+
| Auxillaries pane hierarchy, spacing, border polish, readiness recovery, and account/provider diagnostics can deepen beyond the V28 MVP shell. | V31 owns full Auxillaries deepening after V28 proves the contained shell, pane selectability, mocked prerequisites, and fail-closed readiness posture. |
174201

175202
Ignored during this setup smoke: Google Analytics network aborts in headless Playwright.
176203
They are external telemetry noise, not product readiness evidence.
@@ -187,6 +214,8 @@ Automated verification after this implementation pass:
187214
- `pnpm -C packages/protocol test`: 1 passed after the formal package split.
188215
- `pnpm -C packages/protocol run typecheck`: pass after adding the formal package typecheck config.
189216
- `pnpm -C uapi exec jest --runInBand tests/protocolCommercialBoundary.test.ts`: 3 passed after the formal package split.
217+
- `pnpm -C uapi exec jest --runInBand tests/useUserDataHydration.test.tsx tests/featureFlagsMockMode.test.ts tests/protocolCommercialBoundary.test.ts`: 11 passed after the mock top-chrome cache/flag fix, JavaScript companion parity check, and protocol package resolver check.
218+
- Playwright dual-lane browser verification after lane-specific `NEXT_DIST_DIR` restart: mock lane shows `0.042 BTC`, `1,200 BTD`, mock review state, reviewer profile, and populated notifications; testnet-readiness lane shows no mock balances, no mock review state, and the Connect Wallet prerequisite controls; both lanes have no product console/page errors.
190219

191220
Deferred to V29 from this pass:
192221

@@ -208,6 +237,7 @@ Mock lane dev server:
208237

209238
```sh
210239
NEXT_PUBLIC_MASTER_MOCK_MODE=true \
240+
NEXT_DIST_DIR=.next-v28-mock \
211241
NEXT_PUBLIC_ENABLE_MOCKS=true \
212242
NEXT_PUBLIC_MOCK_USER_AUXILLARIES=true \
213243
NEXT_PUBLIC_MOCK_USER_AUXILLARIES_SCENARIO=demo \
@@ -225,6 +255,7 @@ Testnet-readiness lane dev server:
225255

226256
```sh
227257
NEXT_PUBLIC_BITCODE_ENV=testnet \
258+
NEXT_DIST_DIR=.next-v28-testnet \
228259
NEXT_PUBLIC_MASTER_MOCK_MODE=false \
229260
NEXT_PUBLIC_ENABLE_MOCKS=false \
230261
NEXT_PUBLIC_MOCK_USER_AUXILLARIES=false \

uapi/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
# next.js
1313
/.next/
14+
/.next-*/
1415
/out/
1516

1617
# production

uapi/app/auxillaries/components/AuxillariesProfilePane.tsx

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,26 @@ export default function AuxillariesProfilePane({ onSave,
293293
const [selectedAvatar, setSelectedAvatar] = useState(0);
294294
const [showAvatarSelector, setShowAvatarSelector] = useState(false);
295295

296+
useEffect(() => {
297+
_setUsername(initialUsername);
298+
}, [initialUsername]);
299+
300+
useEffect(() => {
301+
setDisplayName(initialDisplayName);
302+
}, [initialDisplayName]);
303+
304+
useEffect(() => {
305+
setBio(initialBio);
306+
}, [initialBio]);
307+
308+
useEffect(() => {
309+
setCompanyName(initialCompanyName);
310+
}, [initialCompanyName]);
311+
312+
useEffect(() => {
313+
setAvatarUrl(initialAvatarUrl);
314+
}, [initialAvatarUrl]);
315+
296316
useEffect(() => {
297317
setWalletAddress(initialWalletAddress);
298318
setWalletProvider(initialWalletProvider || (initialWalletAddress ? 'manual' : ''));
@@ -321,6 +341,11 @@ export default function AuxillariesProfilePane({ onSave,
321341
);
322342
const [teamSectionExpanded, setTeamSectionExpanded] = useState(false);
323343

344+
useEffect(() => {
345+
if (initialTeamMembers.length === 0) return;
346+
setTeamMembers(initialTeamMembers);
347+
}, [initialTeamMembers]);
348+
324349
// Sample avatar options
325350
const avatarOptions = AVATAR_OPTIONS;
326351

uapi/app/auxillaries/components/shared/AuxillariesWorkspacePanels.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ export default function AuxillariesWorkspacePanels({
3333
const descriptor = getAuxillaryDescriptor(step);
3434
const isActive = currentStep === step;
3535
const isAvailable = availableSteps.includes(step);
36+
const state = isActive ? 'active' : isAvailable ? 'ready' : 'locked';
37+
const stateLabel =
38+
state === 'active'
39+
? 'Active auxillary'
40+
: state === 'ready'
41+
? 'Ready auxillary'
42+
: 'Locked auxillary';
3643

3744
return (
3845
<div key={step} role="listitem">
@@ -57,9 +64,12 @@ export default function AuxillariesWorkspacePanels({
5764
<span className="orbital-workspace-panel-layer auxillaries-bitcode-selector-card-layer">
5865
{getAuxillaryLayerLabel(step)}
5966
</span>
60-
<span className="orbital-workspace-panel-state auxillaries-bitcode-selector-card-state">
61-
{isActive ? 'active' : isAvailable ? 'ready' : 'locked'}
62-
</span>
67+
<span
68+
className={`orbital-workspace-panel-state auxillaries-bitcode-selector-card-state auxillaries-bitcode-selector-card-state-${state}`}
69+
aria-label={stateLabel}
70+
title={stateLabel}
71+
data-state={state}
72+
/>
6373
</div>
6474
<p className="orbital-workspace-panel-label auxillaries-bitcode-selector-card-label">
6575
{descriptor.label}

uapi/components/base/bitcode/btd/btd-tracker.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
'use client';
33

4-
import { useEffect, useState, useMemo, useRef, useLayoutEffect } from 'react';
4+
import React, { useEffect, useState, useMemo, useRef, useLayoutEffect } from 'react';
55
import { useAuth } from '@/components/base/bitcode/auth/AuthProvider';
66
import Logo from '@/components/base/bitcode/branding/logo';
77
import { motion, AnimatePresence } from 'framer-motion';
@@ -18,6 +18,7 @@ interface BTDTrackerProps {
1818
btdBalance: number;
1919
btcFeeBalance?: number | null;
2020
recentBtdAssetPacks?: BtdAssetPackSummary[];
21+
isLoading?: boolean;
2122
}
2223

2324
function formatBtcFeeBalance(balance: number | null | undefined) {
@@ -53,16 +54,18 @@ export function BTDTracker({
5354
btdBalance,
5455
btcFeeBalance = null,
5556
recentBtdAssetPacks = [],
57+
isLoading = false,
5658
}: BTDTrackerProps) {
5759
const [displayedBtdBalance, setDisplayedBtdBalance] = useState(btdBalance);
5860
const [displayedBtcFeeBalance, setDisplayedBtcFeeBalance] = useState<number | null>(btcFeeBalance);
5961
const [isHovered, setIsHovered] = useState(false);
6062
const [isAnimating, setIsAnimating] = useState(false);
6163
const [exchangeState, setExchangeState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
62-
const shouldShowExchangeNow = isHovered;
64+
const isBalanceLoading = isLoading && btdBalance === 0 && btcFeeBalance === null;
65+
const shouldShowExchangeNow = isHovered && !isBalanceLoading;
6366
const btcBalanceLabel = formatBtcFeeBalance(displayedBtcFeeBalance);
6467
const btdBalanceLabel = `${displayedBtdBalance.toLocaleString()} BTD`;
65-
const balanceLabel = `${btcBalanceLabel}; ${btdBalanceLabel}`;
68+
const balanceLabel = isBalanceLoading ? 'Reading BTC and BTD wallet posture' : `${btcBalanceLabel}; ${btdBalanceLabel}`;
6669
const recentAssetPackTitle = useMemo(() => {
6770
const labels = recentBtdAssetPacks
6871
.slice(0, 5)
@@ -76,14 +79,16 @@ export function BTDTracker({
7679
// Measure the widest hover/rest posture so the tracker does not resize on hover.
7780
const exchangeRef = useRef<HTMLSpanElement>(null);
7881
const btdRef = useRef<HTMLSpanElement>(null);
82+
const loadingRef = useRef<HTMLSpanElement>(null);
7983
const [textWidth, setTextWidth] = useState(0);
8084
useLayoutEffect(() => {
81-
if (exchangeRef.current && btdRef.current) {
85+
if (exchangeRef.current && btdRef.current && loadingRef.current) {
8286
const exchangeW = exchangeRef.current.offsetWidth;
8387
const btdW = btdRef.current.offsetWidth;
84-
setTextWidth(Math.ceil(Math.max(exchangeW, btdW)));
88+
const loadingW = loadingRef.current.offsetWidth;
89+
setTextWidth(Math.ceil(Math.max(exchangeW, btdW, loadingW)));
8590
}
86-
}, [displayedBtcFeeBalance, displayedBtdBalance]);
91+
}, [displayedBtcFeeBalance, displayedBtdBalance, isBalanceLoading]);
8792
// Compute static container min-width: icon + gap + text + horizontal paddings
8893
const paddingPx = 24; // px-6
8994
const iconWidthPx = 16; // w-4
@@ -318,6 +323,7 @@ export function BTDTracker({
318323
{/* Hidden measurement spans */}
319324
<div style={{ position: 'absolute', visibility: 'hidden', pointerEvents: 'none' }}>
320325
<span ref={exchangeRef} className="whitespace-nowrap font-normal tracking-wide text-sm">Exchange BTD</span>
326+
<span ref={loadingRef} className="whitespace-nowrap font-normal tracking-wide text-sm">Reading wallet</span>
321327
<span ref={btdRef} className="inline-flex items-center whitespace-nowrap font-medium tracking-wide text-sm">
322328
<span>{btcBalanceLabel}</span>
323329
<span
@@ -377,6 +383,21 @@ export function BTDTracker({
377383
exit={{ opacity: 0, rotateX: 90 }}
378384
transition={{ duration: 0.3, ease: 'easeInOut' }}
379385
>Opening Exchange...</motion.span>
386+
) : isBalanceLoading ? (
387+
<motion.span
388+
key="wallet-loading"
389+
className="inline-flex w-full items-center justify-center gap-2 whitespace-nowrap font-normal tracking-wide text-sm text-emerald-200/78"
390+
initial={{ opacity: 0, rotateX: -90 }}
391+
animate={{ opacity: 1, rotateX: 0 }}
392+
exit={{ opacity: 0, rotateX: 90 }}
393+
transition={{ duration: 0.3, ease: 'easeInOut' }}
394+
>
395+
<span
396+
aria-hidden="true"
397+
className="inline-block h-1.5 w-1.5 rounded-full bg-emerald-200/80 shadow-[0_0_10px_rgba(103,254,183,0.45)]"
398+
/>
399+
<span>Reading wallet</span>
400+
</motion.span>
380401
) : exchangeState === 'idle' && shouldShowExchangeNow ? (
381402
<motion.span
382403
key="exchange"

uapi/components/base/bitcode/layout/nav.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ export default function Nav() {
8484
const pathname = usePathname();
8585
const router = useRouter();
8686
const { user } = useAuth();
87-
const { btdBalance, btcFeeBalance, recentBtdAssetPacks } = useUserData();
87+
const {
88+
btdBalance,
89+
btcFeeBalance,
90+
recentBtdAssetPacks,
91+
isLoading: isUserDataLoading,
92+
isRevalidating: isUserDataRevalidating,
93+
} = useUserData();
8894

8995
const [showNavUse, setShowNavUse] = useState(false);
9096
const [showNavEntrance, setShowNavEntrance] = useState(navEntrancePlayedInRuntime);
@@ -489,6 +495,7 @@ export default function Nav() {
489495
btdBalance={btdBalance}
490496
btcFeeBalance={btcFeeBalance}
491497
recentBtdAssetPacks={recentBtdAssetPacks}
498+
isLoading={isUserDataLoading || isUserDataRevalidating}
492499
/>
493500
)}
494501

0 commit comments

Comments
 (0)