diff --git a/ui/agijobmanager_genesis_job_mainnet_2026-03-05-v29.html b/ui/agijobmanager_genesis_job_mainnet_2026-03-05-v29.html index bfe8b3e7..2e4e8574 100644 --- a/ui/agijobmanager_genesis_job_mainnet_2026-03-05-v29.html +++ b/ui/agijobmanager_genesis_job_mainnet_2026-03-05-v29.html @@ -795,7 +795,7 @@

Command Center

Jobs Table Terms -
New in v29: the interface now includes the Operator Deck, activity concierge, transaction review, a tighter $AGIALPHA conversion console, and a stronger mobile-first navigation layer for one-handed protocol operations.
+
New in v29: ENS job-page preview and Alpha Agent Identity operations are now contract-faithful, preview-driven, and hardened for elite mainnet operator workflows.
Operational note
@@ -1353,7 +1353,6 @@

1.5) Mint Free Alpha-Agent ENS Access Key

Wrapped owner:
Resolver:
Wrapped expiry:
-
Labelhash:
Minted at:
TokenURI (decoded):
@@ -2235,7 +2234,7 @@

Contact & Legal

const activeJobIndexCache = { ids:null, ts:0 }; const nftRenderCache = { total:null, myHtml:'', allHtml:'', ts:0, myAccount:'' }; const AGI_JOB_MANAGER = "0xB3AAeb69b630f0299791679c063d68d6687481d1"; - const FALLBACK_NAME_WRAPPER = "0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"; + const NAME_WRAPPER = "0xD4416b13d2b3a9aBae7AcD5D6C2BbDBE25686401"; const KNOWN_ENS_JOB_PAGES_FALLBACK = "0x06188e77c1c38d392b16d9d9fb24673363ce1da0"; const FREE_TRIAL_REGISTRAR = "0x7aae649184182a01ac7d8d5d7873903015c08761"; const FREE_TRIAL_REGISTRAR_IDENTITY = "0x7811993CbcCa3b8bb35a3d919F3BA59eeFbeAA9a"; @@ -2724,7 +2723,7 @@

Contact & Legal

if(el('mintAlphaStatus')) el('mintAlphaStatus').textContent = 'Runtime context reset. Reconnect to refresh registrar state.'; if(el('mintAlphaAvailability')) el('mintAlphaAvailability').textContent = '—'; if(el('freeTrialParentUsableState')) el('freeTrialParentUsableState').textContent = '—'; - ['alphaIdentityStatusPill','alphaIdentityFullName','alphaIdentityTokenId','alphaIdentityExists','alphaIdentityClaimable','alphaIdentityRegistrable','alphaIdentityActionStatus','alphaIdentityTokenOwner','alphaIdentityWrappedOwner','alphaIdentityResolver','alphaIdentityWrappedExpiry','alphaIdentityLabelhash','alphaIdentityMintedAt','alphaIdentityTokenMetaName','alphaIdentityTokenMetaDescription'].forEach(id=>{ if(el(id)) el(id).textContent='—'; }); + ['alphaIdentityStatusPill','alphaIdentityFullName','alphaIdentityTokenId','alphaIdentityExists','alphaIdentityClaimable','alphaIdentityRegistrable','alphaIdentityActionStatus','alphaIdentityTokenOwner','alphaIdentityWrappedOwner','alphaIdentityResolver','alphaIdentityWrappedExpiry','alphaIdentityMintedAt','alphaIdentityTokenMetaName','alphaIdentityTokenMetaDescription'].forEach(id=>{ if(el(id)) el(id).textContent='—'; }); ['alphaIdentityRootName','alphaIdentityRootNode','alphaIdentityRootActive','alphaIdentityPaused','alphaIdentityWrapper','alphaIdentityRegistry','alphaIdentityOwnerLine','alphaIdentityParentOwner','alphaIdentityParentFlags','alphaIdentityRegistrarAuth','alphaIdentityParentExpiry','alphaIdentityRootUsable','alphaIdentityRequiredFuses','alphaIdentityNameSymbol'].forEach(id=>{ if(el(id)) el(id).textContent='—'; }); if(el('alphaIdentityAdminControls')) el('alphaIdentityAdminControls').innerHTML = '
Reconnect to refresh identity admin posture.
'; if(el('alphaIdentityActionStatus')) el('alphaIdentityActionStatus').textContent='Runtime context reset. Reconnect to refresh identity state.'; @@ -3095,52 +3094,28 @@

Contact & Legal

let primary = {label:'Connect wallet', action:'connect'}; let secondary = {label:'Command Palette', action:'command'}; const bridgedBal = parseDisplayedNumber(el('bridgeAcceptedBalance')?.textContent || '0'); + const p = APP_STATE.identity?.preview; + const repairNeeded = !!p && (p.status===4 || (p.status===3 && p.identityExists)); if(connected && !isMainnet){ - title = 'Switch to Ethereum Mainnet'; - body = 'The UI is in read-only mode on the current network. Switch to chainId 1 to post jobs, apply, validate, finalize, and mint through the Ethereum vault.'; - pill = 'Network action required'; - primary = {label:'Switch network', action:'switch-mainnet'}; - secondary = {label:'Command Palette', action:'command'}; + title = 'Switch to Ethereum Mainnet'; body = 'The UI is in read-only mode on the current network. Switch to chainId 1 to post jobs, apply, validate, finalize, and mint through the Ethereum vault.'; pill='Network action required'; primary={label:'Switch network',action:'switch-mainnet'}; }else if(connected && isMainnet && !hasAcceptedTerms){ - title = 'Read and accept the terms'; - body = 'This interface intentionally keeps write actions locked until you confirm the embedded contract terms. That reduces accidental posting and signing.'; - pill = 'Terms review required'; - primary = {label:'Read Terms', action:'terms'}; - secondary = {label:'Open Create Job', action:'create'}; + title = 'Read and accept the terms'; body='This interface intentionally keeps write actions locked until you confirm the embedded contract terms. That reduces accidental posting and signing.'; pill='Terms review required'; primary={label:'Read Terms',action:'terms'}; secondary={label:'Open Create Job',action:'create'}; }else if(connected && isMainnet && hasAcceptedTerms && bridgedBal > 0){ - title = 'Convert bridged AGIALPHA to official mainnet AGIALPHA'; - body = 'Your wallet appears to hold the intermediate bridged Ethereum token. Use the vault conversion flow before posting jobs or funding bonds.'; - pill = 'Bridge conversion available'; - primary = {label:'Open bridge console', action:'bridge'}; - secondary = {label:'Refresh balances', action:'refresh'}; - }else if(connected && isMainnet && hasAcceptedTerms && !verified.agentAlpha && !((APP_STATE.identity?.preview?.claimable) || (APP_STATE.identity?.preview?.identityExists && [3,4].includes(APP_STATE.identity?.preview?.status)) || (APP_STATE.identity?.preview?.registrable))){ - title = 'Mint your alpha-agent ENS access key'; - body = 'You can mint a free-trial *.alpha.agent.agi.eth identity now (gas only), then auto-verify it for agent readiness.'; - pill = 'Alpha-agent identity recommended'; - primary = {label:'Mint free alpha-agent ENS', action:'mint-alpha'}; - secondary = {label:'Verify ENS', action:'verify'}; + title='Convert bridged AGIALPHA to official mainnet AGIALPHA'; body='Your wallet appears to hold the intermediate bridged Ethereum token. Use the vault conversion flow before posting jobs or funding bonds.'; pill='Bridge conversion available'; primary={label:'Open bridge console',action:'bridge'}; secondary={label:'Refresh balances',action:'refresh'}; + }else if(connected && isMainnet && hasAcceptedTerms && p?.claimable){ + title='Claim your Alpha Agent Identity'; body='preview(label) indicates claimable posture: wrapped name exists and this wallet can claim the soulbound identity credential.'; pill='Identity claim available'; primary={label:'Claim Alpha Agent Identity',action:'claim-alpha-identity'}; secondary={label:'Refresh identity preview',action:'refresh-identity-preview'}; + }else if(connected && isMainnet && hasAcceptedTerms && repairNeeded){ + title='Repair Alpha Agent Identity state'; body='preview(label) shows desynced or expired identity posture. Run syncIdentityByLabel(label) to repair or clean up stale identity state.'; pill='Identity repair recommended'; primary={label:'Sync Alpha Agent Identity',action:'sync-alpha-identity'}; secondary={label:'Refresh identity preview',action:'refresh-identity-preview'}; + }else if(connected && isMainnet && hasAcceptedTerms && p?.registrable){ + title='Mint Alpha Agent Identity (recommended path)'; body='Use register(label) to mint wrapped alpha-agent ENS plus the soulbound Alpha Agent Identity in one transaction.'; pill='Identity register ready'; primary={label:'Mint Alpha Agent Identity',action:'mint-alpha-identity'}; secondary={label:'Open ENS-only alpha-agent path',action:'mint-alpha'}; }else if(connected && isMainnet && hasAcceptedTerms && jobStats.completion > 0 && verified.club){ - title = 'Review jobs waiting for validator attention'; - body = `${jobStats.completion} job${jobStats.completion === 1 ? '' : 's'} currently show a live completion-review surface. Open the board, inspect the details modal, and vote only after independent evidence review.`; - pill = 'Validator attention available'; - primary = {label:'Open Jobs', action:'jobs'}; - secondary = {label:'Activity Concierge', action:'activity'}; + title='Review jobs waiting for validator attention'; body=`${jobStats.completion} job${jobStats.completion === 1 ? '' : 's'} currently show a live completion-review surface. Open the board, inspect the details modal, and vote only after independent evidence review.`; pill='Validator attention available'; primary={label:'Open Jobs',action:'jobs'}; secondary={label:'Activity Concierge',action:'activity'}; }else if(connected && isMainnet && hasAcceptedTerms && jobStats.open > 0 && verified.agent){ - title = 'Apply for a live job'; - body = `${jobStats.open} open job${jobStats.open === 1 ? '' : 's'} are currently visible. If the fit is good and your bond exposure is acceptable, apply from the jobs table.`; - pill = 'Agent mode ready'; - primary = {label:'Browse open jobs', action:'jobs'}; - secondary = {label:'Command Palette', action:'command'}; + title='Apply for a live job'; body=`${jobStats.open} open job${jobStats.open === 1 ? '' : 's'} are currently visible. If the fit is good and your bond exposure is acceptable, apply from the jobs table.`; pill='Agent mode ready'; primary={label:'Browse open jobs',action:'jobs'}; + }else if(connected && isMainnet && hasAcceptedTerms && !verified.agentAlpha){ + title='Alpha-agent posture not verified yet'; body='Open the alpha-agent section to mint or verify. Recommended route is Alpha Agent Identity register(label); ENS-only remains available for expert operators.'; pill='Alpha-agent action recommended'; primary={label:'Open alpha-agent section',action:'mint-alpha'}; secondary={label:'Verify ENS',action:'verify'}; }else if(connected && isMainnet && hasAcceptedTerms){ - title = 'System ready'; - body = 'Wallet, network, and write-gating are in a good state. You can create a job, inspect live jobs, or use the command palette for faster navigation.'; - pill = 'Ready for production use'; - const p = APP_STATE.identity?.preview; - if(p && p.claimable){ primary = {label:'Claim Alpha Agent Identity', action:'claim-alpha-identity'}; secondary = {label:'Open ENS-only alpha-agent path', action:'mint-alpha'}; } - else if(p && p.identityExists && (p.status===3 || p.status===4)){ primary = {label:'Sync Alpha Agent Identity', action:'sync-alpha-identity'}; secondary = {label:'Open alpha-agent section', action:'mint-alpha'}; } - else if(p && p.registrable){ primary = {label:'Mint Alpha Agent Identity', action:'mint-alpha-identity'}; secondary = {label:'Open ENS-only alpha-agent path', action:'mint-alpha'}; } - else if((!p || !p.identityExists) && userAccount && isMainnet && hasAcceptedTerms){ primary = {label:'Open alpha-agent section', action:'mint-alpha-identity'}; secondary = {label:'Open ENS-only alpha-agent path', action:'mint-alpha'}; } - else { primary = {label:'Open Create Job', action:'create'}; secondary = {label:'Open Jobs', action:'jobs'}; } + title='System ready'; body='Wallet, network, and write-gating are in a good state. You can create a job, inspect live jobs, or use the command palette for faster navigation.'; pill='Ready for production use'; primary={label:'Open Create Job',action:'create'}; secondary={label:'Open Jobs',action:'jobs'}; } if(el('missionNextActionTitle')) el('missionNextActionTitle').textContent = title; if(el('missionNextActionBody')) el('missionNextActionBody').textContent = body; @@ -3955,18 +3930,8 @@

Contact & Legal

function parseIdentityPreviewResult(v){ if(!v) return null; const p = Array.isArray(v) - ? { - validLabel:!!v[0], fullName:String(v[1]||''), labelOut:String(v[2]||''), labelhash:String(v[3]||''), node:String(v[4]||''), tokenId:String(v[5]||''), - rootActiveOut:!!v[6], pausedOut:!!v[7], parentWrapped:!!v[8], parentLocked:!!v[9], registrarAuthorised:!!v[10], rootUsable:!!v[11], - availableOut:!!v[12], identityExists:!!v[13], registrable:!!v[14], claimable:!!v[15], tokenOwner:String(v[16]||''), wrappedOwner:String(v[17]||''), - resolver:String(v[18]||''), currentWrappedExpiry:Number(v[19]||0), expectedNewExpiry:Number(v[20]||0), status:Number(v[21]||0) - } - : { - validLabel:!!v.validLabel, fullName:String(v.fullName||''), labelOut:String(v.labelOut||''), labelhash:String(v.labelhash||''), node:String(v.node||''), tokenId:String(v.tokenId||''), - rootActiveOut:!!v.rootActiveOut, pausedOut:!!v.pausedOut, parentWrapped:!!v.parentWrapped, parentLocked:!!v.parentLocked, registrarAuthorised:!!v.registrarAuthorised, rootUsable:!!v.rootUsable, - availableOut:!!v.availableOut, identityExists:!!v.identityExists, registrable:!!v.registrable, claimable:!!v.claimable, tokenOwner:String(v.tokenOwner||''), wrappedOwner:String(v.wrappedOwner||''), - resolver:String(v.resolver||''), currentWrappedExpiry:Number(v.currentWrappedExpiry||0), expectedNewExpiry:Number(v.expectedNewExpiry||0), status:Number(v.status||0) - }; + ? {validLabel:!!v[0], fullName:String(v[1]||''), labelOut:String(v[2]||''), labelhash:String(v[3]||''), node:String(v[4]||''), tokenId:String(v[5]||''), rootActiveOut:!!v[6], pausedOut:!!v[7], parentWrapped:!!v[8], parentLocked:!!v[9], registrarAuthorised:!!v[10], rootUsable:!!v[11], availableOut:!!v[12], identityExists:!!v[13], registrable:!!v[14], claimable:!!v[15], tokenOwner:String(v[16]||''), wrappedOwner:String(v[17]||''), resolver:String(v[18]||''), currentWrappedExpiry:Number(v[19]||0), expectedNewExpiry:Number(v[20]||0), status:Number(v[21]||0)} + : {validLabel:!!v.validLabel, fullName:String(v.fullName||''), labelOut:String(v.labelOut||''), labelhash:String(v.labelhash||''), node:String(v.node||''), tokenId:String(v.tokenId||''), rootActiveOut:!!v.rootActiveOut, pausedOut:!!v.pausedOut, parentWrapped:!!v.parentWrapped, parentLocked:!!v.parentLocked, registrarAuthorised:!!v.registrarAuthorised, rootUsable:!!v.rootUsable, availableOut:!!v.availableOut, identityExists:!!v.identityExists, registrable:!!v.registrable, claimable:!!v.claimable, tokenOwner:String(v.tokenOwner||''), wrappedOwner:String(v.wrappedOwner||''), resolver:String(v.resolver||''), currentWrappedExpiry:Number(v.currentWrappedExpiry||0), expectedNewExpiry:Number(v.expectedNewExpiry||0), status:Number(v.status||0)}; p.statusLabel = IDENTITY_PREVIEW_STATUS[p.status] || `unknown-${p.status}`; return p; } @@ -3984,7 +3949,7 @@

Contact & Legal

const local = validateAlphaLabelLocal(el('mintAlphaLabel')?.value || ''); APP_STATE.identity.label = local.label || ''; if(el('alphaIdentityContractAddress')) el('alphaIdentityContractAddress').textContent = FREE_TRIAL_REGISTRAR_IDENTITY; - const [rootName,rootNode,rootActive,paused,wrapper,registry,owner,pendingOwner,fuses,name,symbol,health] = await Promise.all([ + const [rootName,rootNode,rootActive,paused,wrapper,registry,owner,pendingOwner,fuses,name,symbol,health,identityBalance] = await Promise.all([ freeTrialRegistrarIdentity.methods.ROOT_NAME().call().catch(()=>''), freeTrialRegistrarIdentity.methods.ROOT_NODE().call().catch(()=>''), freeTrialRegistrarIdentity.methods.rootActive().call().catch(()=>false), @@ -3996,30 +3961,40 @@

Contact & Legal

freeTrialRegistrarIdentity.methods.REQUIRED_CHILD_FUSES().call().catch(()=>''), freeTrialRegistrarIdentity.methods.name().call().catch(()=>''), freeTrialRegistrarIdentity.methods.symbol().call().catch(()=>''), - freeTrialRegistrarIdentity.methods.rootHealth().call().catch(()=>null) + freeTrialRegistrarIdentity.methods.rootHealth().call().catch(()=>null), + userAccount ? freeTrialRegistrarIdentity.methods.balanceOf(userAccount).call().catch(()=>null) : Promise.resolve(null) ]); const computed = namehash(ALPHA_AGENT_PARENT); - if(el('alphaIdentityRootName')) el('alphaIdentityRootName').textContent = rootName || ALPHA_AGENT_PARENT; - if(el('alphaIdentityRootNode')) el('alphaIdentityRootNode').textContent = rootNode || '—'; - if(el('alphaIdentityRootActive')) el('alphaIdentityRootActive').textContent = String(!!rootActive); - if(el('alphaIdentityPaused')) el('alphaIdentityPaused').textContent = String(!!paused); - if(el('alphaIdentityWrapper')) el('alphaIdentityWrapper').textContent = wrapper || '—'; - if(el('alphaIdentityRegistry')) el('alphaIdentityRegistry').textContent = registry || '—'; - if(el('alphaIdentityOwnerLine')) el('alphaIdentityOwnerLine').textContent = `${owner || '—'} / ${pendingOwner || '—'}`; + const h = health ? (Array.isArray(health) ? { + rootName:String(health[0]||''), rootNode:String(health[1]||''), active:!!health[2], pausedOut:!!health[3], wrapperAddress:String(health[4]||''), ensRegistryAddress:String(health[5]||''), contractOwner:String(health[6]||''), wrappedParentOwner:String(health[7]||''), parentWrapped:!!health[8], parentLocked:!!health[9], registrarAuthorised:!!health[10], effectiveParentExpiry:Number(health[11]||0), rootUsable:!!health[12] + } : health) : null; + APP_STATE.identity.rootHealth = h; + if(el('alphaIdentityRootName')) el('alphaIdentityRootName').textContent = h?.rootName || rootName || ALPHA_AGENT_PARENT; + if(el('alphaIdentityRootNode')) el('alphaIdentityRootNode').textContent = h?.rootNode || rootNode || '—'; + if(el('alphaIdentityRootActive')) el('alphaIdentityRootActive').textContent = String(!!(h?.active ?? rootActive)); + if(el('alphaIdentityPaused')) el('alphaIdentityPaused').textContent = String(!!(h?.pausedOut ?? paused)); + if(el('alphaIdentityWrapper')) el('alphaIdentityWrapper').textContent = h?.wrapperAddress || wrapper || '—'; + if(el('alphaIdentityRegistry')) el('alphaIdentityRegistry').textContent = h?.ensRegistryAddress || registry || '—'; + if(el('alphaIdentityOwnerLine')) el('alphaIdentityOwnerLine').textContent = `${h?.contractOwner || owner || '—'} / ${pendingOwner || '—'}`; if(el('alphaIdentityRequiredFuses')) el('alphaIdentityRequiredFuses').textContent = String(fuses || '—'); - if(el('alphaIdentityNameSymbol')) el('alphaIdentityNameSymbol').textContent = `${name || '—'} / ${symbol || '—'}`; - const managerWrapperLive = await agiJobManager.methods.nameWrapper().call().catch(()=>""); - const managerEnsLive = await agiJobManager.methods.ens().call().catch(()=>""); - if(el('alphaIdentityActionStatus') && managerWrapperLive && wrapper && String(managerWrapperLive).toLowerCase() !== String(wrapper).toLowerCase()) el('alphaIdentityActionStatus').textContent = 'Warning: AGIJobManager nameWrapper differs from identity wrapper; treat posture as degraded.'; - if(el('alphaIdentityActionStatus') && managerEnsLive && registry && String(managerEnsLive).toLowerCase() !== String(registry).toLowerCase()) el('alphaIdentityActionStatus').textContent = 'Warning: AGIJobManager ENS registry differs from identity registrar ENS registry; verify before writing.'; - const h = health ? (Array.isArray(health) ? {rootName:String(health[0]||''),rootNode:String(health[1]||''),active:!!health[2],pausedOut:!!health[3],wrapperAddress:String(health[4]||''),ensRegistryAddress:String(health[5]||''),contractOwner:String(health[6]||''),wrappedParentOwner:String(health[7]||''),parentWrapped:!!health[8],parentLocked:!!health[9],registrarAuthorised:!!health[10],effectiveParentExpiry:Number(health[11]||0),rootUsable:!!health[12]} : health) : null; + if(el('alphaIdentityNameSymbol')) el('alphaIdentityNameSymbol').textContent = `${name || '—'} / ${symbol || '—'}${identityBalance===null?'':` · balanceOf(wallet): ${identityBalance}`}`; if(el('alphaIdentityParentOwner')) el('alphaIdentityParentOwner').textContent = h?.wrappedParentOwner || '—'; if(el('alphaIdentityParentFlags')) el('alphaIdentityParentFlags').textContent = h ? `${h.parentWrapped?'wrapped':'not wrapped'} / ${h.parentLocked?'locked':'unlocked'}` : '—'; if(el('alphaIdentityRegistrarAuth')) el('alphaIdentityRegistrarAuth').textContent = h ? String(!!h.registrarAuthorised) : '—'; if(el('alphaIdentityParentExpiry')) el('alphaIdentityParentExpiry').textContent = h ? formatTimestamp(h.effectiveParentExpiry) : '—'; if(el('alphaIdentityRootUsable')) el('alphaIdentityRootUsable').textContent = h ? String(!!h.rootUsable) : '—'; - const rootNodeMismatch = !!(rootNode && computed.toLowerCase() !== String(rootNode).toLowerCase()); - if(rootNodeMismatch && el('alphaIdentityActionStatus')) el('alphaIdentityActionStatus').textContent = `Blocking warning: ROOT_NODE mismatch. computed ${computed}, contract ${rootNode}.`; + + const rootMismatch = (rootNode || h?.rootNode) && computed.toLowerCase() !== String(h?.rootNode || rootNode).toLowerCase(); + let mismatchWarnings = []; + const managerEns = await agiJobManager?.methods?.ens?.().call().catch(()=> ''); + const managerWrapper = await agiJobManager?.methods?.nameWrapper?.().call().catch(()=> ''); + if(wrapper && freeTrialRegistrar){ + const ensOnlyWrapper = await freeTrialRegistrar.methods.wrapper().call().catch(()=> ''); + if(ensOnlyWrapper && wrapper && ensOnlyWrapper.toLowerCase() !== wrapper.toLowerCase()) mismatchWarnings.push('Identity wrapper differs from ENS-only registrar wrapper.'); + } + if(managerEns && registry && managerEns.toLowerCase() !== registry.toLowerCase()) mismatchWarnings.push('Identity ensRegistry differs from AGIJobManager.ens().'); + if(managerWrapper && wrapper && managerWrapper.toLowerCase() !== wrapper.toLowerCase()) mismatchWarnings.push('Identity wrapper differs from AGIJobManager.nameWrapper().'); + const previewRaw = local.ok ? await freeTrialRegistrarIdentity.methods.preview(local.label).call().catch(()=>null) : null; const preview = parseIdentityPreviewResult(previewRaw); APP_STATE.identity.preview = preview; @@ -4027,35 +4002,40 @@

Contact & Legal

if(el('alphaIdentityFullName')) el('alphaIdentityFullName').textContent = preview?.fullName || (local.ok ? `${local.label}.${ALPHA_AGENT_PARENT}` : '—'); if(el('alphaIdentityTokenId')) el('alphaIdentityTokenId').textContent = preview?.tokenId || '—'; if(el('alphaIdentityExists')) el('alphaIdentityExists').textContent = preview ? String(!!preview.identityExists) : '—'; - if(el('alphaIdentityWrappedOwner')) el('alphaIdentityWrappedOwner').textContent = preview?.wrappedOwner || '—'; - if(el('alphaIdentityResolver')) el('alphaIdentityResolver').textContent = preview?.resolver || '—'; - if(el('alphaIdentityWrappedExpiry')) el('alphaIdentityWrappedExpiry').textContent = preview ? formatTimestamp(preview.currentWrappedExpiry) : '—'; if(el('alphaIdentityClaimable')) el('alphaIdentityClaimable').textContent = preview ? String(!!preview.claimable) : '—'; if(el('alphaIdentityRegistrable')) el('alphaIdentityRegistrable').textContent = preview ? String(!!preview.registrable) : '—'; - const lockedReason = identityWriteLockedReason(preview) || (rootNodeMismatch ? 'ROOT_NODE mismatch blocks identity writes until contract/root alignment is restored.' : ''); - const registerEnabled = !lockedReason && preview?.registrable; - const claimEnabled = !lockedReason && preview?.claimable; - const syncEnabled = !lockedReason && preview?.identityExists && (preview.status===3 || preview.status===4); + const lockedReason = rootMismatch ? 'ROOT_NODE mismatch blocks identity writes.' : identityWriteLockedReason(preview); + const registerEnabled = !lockedReason && !!preview?.validLabel && !!preview?.registrable; + const claimEnabled = !lockedReason && !!preview?.claimable; + const syncEnabled = !lockedReason && (preview?.status===4 || (preview?.status===3 && preview?.identityExists)); if(el('alphaIdentityRegisterBtn')) el('alphaIdentityRegisterBtn').disabled = !registerEnabled; if(el('alphaIdentityClaimBtn')) el('alphaIdentityClaimBtn').disabled = !claimEnabled; if(el('alphaIdentitySyncBtn')) el('alphaIdentitySyncBtn').disabled = !syncEnabled; if(el('alphaIdentityActionStatus')){ if(lockedReason) el('alphaIdentityActionStatus').textContent = lockedReason; + else if(mismatchWarnings.length) el('alphaIdentityActionStatus').textContent = mismatchWarnings.join(' '); + else if(claimEnabled) el('alphaIdentityActionStatus').textContent = 'Ready: claimIdentity(label) for wrapped names already owned by your wallet.'; + else if(syncEnabled) el('alphaIdentityActionStatus').textContent = 'Ready: syncIdentityByLabel(label) repair path for desynced / expired identity posture.'; else if(registerEnabled) el('alphaIdentityActionStatus').textContent = 'Ready: register(label) mints wrapped ENS name + soulbound identity to connected wallet.'; - else if(claimEnabled) el('alphaIdentityActionStatus').textContent = 'Ready: claimIdentity(label) for an existing wrapped name you already own.'; - else if(syncEnabled) el('alphaIdentityActionStatus').textContent = 'Ready: syncIdentityByLabel(label) repair path.'; else el('alphaIdentityActionStatus').textContent = 'No eligible identity write action for current preview state.'; } - if(preview?.identityExists && preview?.tokenId){ - const [ownerOf, labelData, tokenURI] = await Promise.all([ - freeTrialRegistrarIdentity.methods.ownerOf(preview.tokenId).call().catch(()=>''), + + const hasPreviewTokenOwner = !!preview?.tokenOwner && !isZeroAddress(preview.tokenOwner); + const shouldReadIdentityToken = !!preview?.tokenId && (!!preview?.identityExists || hasPreviewTokenOwner); + if(shouldReadIdentityToken){ + const [ownerOf, labelData, tokenURI, lockedState] = await Promise.all([ + freeTrialRegistrarIdentity.methods.ownerOf(preview.tokenId).call().catch(()=> preview?.tokenOwner || ''), freeTrialRegistrarIdentity.methods.labelData(preview.tokenId).call().catch(()=>null), freeTrialRegistrarIdentity.methods.tokenURI(preview.tokenId).call().catch(()=>''), + freeTrialRegistrarIdentity.methods.locked(preview.tokenId).call().catch(()=>null), ]); - if(el('alphaIdentityTokenOwner')) el('alphaIdentityTokenOwner').textContent = ownerOf || '—'; - const ld = labelData ? (Array.isArray(labelData) ? {label:String(labelData[0]||''), labelhash:String(labelData[1]||''), mintedAt:Number(labelData[2]||0)} : labelData) : null; - if(el('alphaIdentityLabelhash')) el('alphaIdentityLabelhash').textContent = ld?.labelhash || preview?.labelhash || '—'; + const ld = labelData ? (Array.isArray(labelData) ? {label:String(labelData[0]||''), labelhash:String(labelData[1]||''), mintedAt:Number(labelData[2]||0)} : {label:String(labelData.label||''), labelhash:String(labelData.labelhash||''), mintedAt:Number(labelData.mintedAt||0)}) : null; + if(el('alphaIdentityTokenOwner')) el('alphaIdentityTokenOwner').textContent = ownerOf || preview?.tokenOwner || '—'; + if(el('alphaIdentityWrappedOwner')) el('alphaIdentityWrappedOwner').textContent = preview?.wrappedOwner || '—'; + if(el('alphaIdentityResolver')) el('alphaIdentityResolver').textContent = preview?.resolver || '—'; + if(el('alphaIdentityWrappedExpiry')) el('alphaIdentityWrappedExpiry').textContent = preview ? formatTimestamp(preview.currentWrappedExpiry) : '—'; if(el('alphaIdentityMintedAt')) el('alphaIdentityMintedAt').textContent = ld ? formatTimestamp(ld.mintedAt) : '—'; + if(el('alphaIdentityStatusPill')) el('alphaIdentityStatusPill').textContent = `${preview?.statusLabel || '—'} (${preview?.status ?? '—'}) · soulbound locked: ${lockedState === null ? '—' : (lockedState ? 'true' : 'false')}`; if(tokenURI && tokenURI.startsWith('data:application/json;base64,')){ try{ const payload = JSON.parse(atob(tokenURI.split(',')[1] || '')); @@ -4063,15 +4043,24 @@

Contact & Legal

if(el('alphaIdentityTokenMetaDescription')) el('alphaIdentityTokenMetaDescription').textContent = payload?.description || '—'; const img = payload?.image || ''; const node = el('alphaIdentityTokenImage'); - if(node){ - if(img){ node.style.display='block'; node.src = img; } - else{ node.style.display='none'; node.removeAttribute('src'); } - } + if(node){ if(img){ node.style.display='block'; node.src = img; } else { node.style.display='none'; node.removeAttribute('src'); } } }catch{} + }else{ + if(el('alphaIdentityTokenMetaName')) el('alphaIdentityTokenMetaName').textContent = '—'; + if(el('alphaIdentityTokenMetaDescription')) el('alphaIdentityTokenMetaDescription').textContent = '—'; + const node = el('alphaIdentityTokenImage'); + if(node){ node.style.display='none'; node.removeAttribute('src'); } } }else{ - ['alphaIdentityTokenOwner','alphaIdentityLabelhash','alphaIdentityMintedAt','alphaIdentityTokenMetaName','alphaIdentityTokenMetaDescription'].forEach(id=>{ if(el(id)) el(id).textContent='—'; }); - if(el('alphaIdentityTokenImage')){ el('alphaIdentityTokenImage').style.display='none'; el('alphaIdentityTokenImage').removeAttribute('src'); } + if(el('alphaIdentityTokenOwner')) el('alphaIdentityTokenOwner').textContent = '—'; + if(el('alphaIdentityWrappedOwner')) el('alphaIdentityWrappedOwner').textContent = preview?.wrappedOwner || '—'; + if(el('alphaIdentityResolver')) el('alphaIdentityResolver').textContent = preview?.resolver || '—'; + if(el('alphaIdentityWrappedExpiry')) el('alphaIdentityWrappedExpiry').textContent = preview ? formatTimestamp(preview.currentWrappedExpiry) : '—'; + if(el('alphaIdentityMintedAt')) el('alphaIdentityMintedAt').textContent = '—'; + if(el('alphaIdentityTokenMetaName')) el('alphaIdentityTokenMetaName').textContent = '—'; + if(el('alphaIdentityTokenMetaDescription')) el('alphaIdentityTokenMetaDescription').textContent = '—'; + const node = el('alphaIdentityTokenImage'); + if(node){ node.style.display='none'; node.removeAttribute('src'); } } renderIdentityAdminControls(owner, pendingOwner); updateMissionControl(); @@ -4106,13 +4095,17 @@

Contact & Legal

if(action==='claimIdentity') send = ()=>freeTrialRegistrarIdentity.methods.claimIdentity(local.label).send({from:userAccount, value:'0'}); if(action==='syncIdentityByLabel') send = ()=>freeTrialRegistrarIdentity.methods.syncIdentityByLabel(local.label).send({from:userAccount, value:'0'}); if(!send) return; - await runTrackedTx(`Alpha identity ${action} ${local.label}`, send, {pendingDetail:`Submitting ${action}…`, successDetail:`${action} confirmed.`}); + const receipt = await runTrackedTx(`Alpha identity ${action} ${local.label}`, send, {pendingDetail:`Submitting ${action}…`, successDetail:`${action} confirmed.`}); if(el('agentSub')) el('agentSub').value = local.label; await verifySubdomain('agent', true); await refreshFreeTrialRegistrarState(); await refreshIdentityState(); + await updateMissionControl(); + await updateDynamicInsights().catch(()=>{}); + await loadJobs().catch(()=>{}); saveRecentAlphaAgentName(local.label); - setToast(`Identity action ${action} confirmed for ${local.label}.${ALPHA_AGENT_PARENT}.`, 'ok'); + const p = APP_STATE.identity?.preview; + setToast(`Identity action ${action} confirmed for ${local.label}.${ALPHA_AGENT_PARENT} · tokenId ${p?.tokenId || 'n/a'} · tx ${shortAddr(receipt?.transactionHash || '')}`, 'ok'); } function renderIdentityAdminControls(owner,pendingOwner){ const box = el('alphaIdentityAdminControls'); @@ -5550,88 +5543,43 @@

Contact & Legal

const input = isAgent ? el("agentSub") : el("clubSub"); const out = isAgent ? el("agentOut") : el("clubOut"); const pill = isAgent ? el("agentPill") : el("clubPill"); - const suffix = isAgent ? (alpha ? SUFFIX.alphaAgent : SUFFIX.agent) : (alpha ? SUFFIX.alphaClub : SUFFIX.club); - const clearRoleVerification = ()=>{ - verified[kind] = null; - if(isAgent){ - verified.agentAlpha = false; - const ab = el("agentAlphaBadge"); - if(ab) ab.style.display = "none"; - }else{ - verified.clubAlpha = false; - const cb = el("clubAlphaBadge"); - if(cb) cb.style.display = "none"; - const vb = el("validatorBadge"); - if(vb) vb.style.display = "none"; - } - }; + const clearRoleVerification = ()=>{ verified[kind] = null; if(isAgent){ verified.agentAlpha = false; const ab = el("agentAlphaBadge"); if(ab) ab.style.display = "none"; } else { verified.clubAlpha = false; const cb = el("clubAlphaBadge"); if(cb) cb.style.display = "none"; const vb = el("validatorBadge"); if(vb) vb.style.display = "none"; } }; const sub = (input.value||"").trim(); if(!/^[a-z0-9-]+$/.test(sub)){ - clearRoleVerification(); - out.textContent="Invalid format. Use lowercase letters, numbers, hyphens."; - pill.className="pill bad"; - pill.textContent=(isAgent?"Agent":"Club")+" ENS: invalid"; - updateReadinessUI(); - return; + clearRoleVerification(); out.textContent="Invalid format. Use lowercase letters, numbers, hyphens."; pill.className="pill bad"; pill.textContent=(isAgent?"Agent":"Club")+" ENS: invalid"; updateReadinessUI(); return; } - try{ const full = `${sub}.${suffix}`; const tokenID = namehash(full); - const managerWrapper = await agiJobManager.methods.nameWrapper().call().catch(()=>""); - const wrapperAddr = !isZeroAddress(managerWrapper) ? managerWrapper : FALLBACK_NAME_WRAPPER; - const nw = new web3.eth.Contract(NameWrapperABI, wrapperAddr); + const managerWrapperAddr = await agiJobManager?.methods?.nameWrapper?.().call().catch(()=>null); + const managerEnsAddr = await agiJobManager?.methods?.ens?.().call().catch(()=>null); + if(!managerWrapperAddr || isZeroAddress(managerWrapperAddr)) throw new Error('AGIJobManager.nameWrapper() unavailable; cannot verify with contract-faithful certainty.'); + if(!managerEnsAddr || isZeroAddress(managerEnsAddr)) throw new Error('AGIJobManager.ens() unavailable; resolver cross-check degraded.'); + const nw = new web3.eth.Contract(NameWrapperABI, managerWrapperAddr); const owner = await nw.methods.ownerOf(tokenID).call(); const acct = String(userAccount || '').toLowerCase(); const ownerLc = String(owner || '').toLowerCase(); const approved = await nw.methods.getApproved(tokenID).call().catch(()=>"0x0000000000000000000000000000000000000000"); const approvedLc = String(approved || '').toLowerCase(); const approvedForAll = await nw.methods.isApprovedForAll(owner, userAccount).call().catch(()=>false); - let resolverAddrMatch = false; - try{ - const ensRegistryAddr = await agiJobManager.methods.ens().call(); - if(ensRegistryAddr && !isZeroAddress(ensRegistryAddr)){ - const ensRegistry = new web3.eth.Contract(ENSRegistryResolverABI, ensRegistryAddr); - const nodeResolver = await ensRegistry.methods.resolver(tokenID).call().catch(()=>"0x0000000000000000000000000000000000000000"); - resolverAddrMatch = !!nodeResolver && String(nodeResolver).toLowerCase() === acct; - } - }catch{} + const ensRegistry = new web3.eth.Contract(ENSRegistryResolverABI, managerEnsAddr); + const nodeResolver = await ensRegistry.methods.resolver(tokenID).call().catch(()=>"0x0000000000000000000000000000000000000000"); + const resolverAddrMatch = !!nodeResolver && String(nodeResolver).toLowerCase() === acct; const isAuthorized = ownerLc === acct || approvedLc === acct || !!approvedForAll || resolverAddrMatch; - if(isAuthorized){ verified[kind] = sub; - if(isAgent){ - verified.agentAlpha = !!alpha; - const ab = el("agentAlphaBadge"); - if(ab) ab.style.display = alpha ? "inline-block" : "none"; - }else{ - verified.clubAlpha = !!alpha; - const cb = el("clubAlphaBadge"); - if(cb) cb.style.display = alpha ? "inline-block" : "none"; - const vb = el("validatorBadge"); - if(vb) vb.style.display = "inline-block"; - } + if(isAgent){ verified.agentAlpha = !!alpha; const ab = el("agentAlphaBadge"); if(ab) ab.style.display = alpha ? "inline-block" : "none"; } + else { verified.clubAlpha = !!alpha; const cb = el("clubAlphaBadge"); if(cb) cb.style.display = alpha ? "inline-block" : "none"; const vb = el("validatorBadge"); if(vb) vb.style.display = "inline-block"; } const mode = ownerLc === acct ? 'owner' : (approvedLc === acct ? 'token approval' : (approvedForAll ? 'operator approval' : 'resolver-address authorization')); - out.textContent = `Verified (${mode}): ${full}`; - pill.className = "pill ok"; - pill.textContent = (isAgent?"Agent":"Club") + (alpha ? " ENS: verified (alpha)" : " ENS: verified"); - await loadJobs(); - await updateDynamicInsights(); + out.textContent = `Verified (${mode}): ${full}`; pill.className = "pill ok"; pill.textContent = (isAgent?"Agent":"Club") + (alpha ? " ENS: verified (alpha)" : " ENS: verified"); + await loadJobs(); await updateDynamicInsights(); }else{ - clearRoleVerification(); - out.textContent = `Not authorized for this wallet: ${full}`; - pill.className = "pill bad"; - pill.textContent = (isAgent?"Agent":"Club") + " ENS: not verified"; + clearRoleVerification(); out.textContent = `Not authorized for this wallet: ${full}`; pill.className = "pill bad"; pill.textContent = (isAgent?"Agent":"Club") + " ENS: not verified"; } updateReadinessUI(); }catch(e){ - console.error(e); - clearRoleVerification(); - out.textContent = `Verification error: ${e.message || String(e)}`; - pill.className = "pill bad"; - pill.textContent = (isAgent?"Agent":"Club") + " ENS: error"; - updateReadinessUI(); + console.error(e); clearRoleVerification(); out.textContent = `Verification degraded/error: ${e.message || String(e)}`; pill.className = "pill bad"; pill.textContent = (isAgent?"Agent":"Club") + " ENS: degraded"; updateReadinessUI(); } }