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 19c596da..dc06a8fa 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: ENS job-page preview and Alpha Agent Identity operations are now contract-faithful, preview-driven, and hardened for elite mainnet operator workflows.
+
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.
Operational note
@@ -2407,19 +2407,23 @@

Contact & Legal

{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"employer","type":"address"},{"indexed":false,"internalType":"string","name":"tokenURI","type":"string"}],"name":"NFTIssued","type":"event"}, {"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"hook","type":"uint8"},{"indexed":true,"internalType":"uint256","name":"jobId","type":"uint256"},{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"EnsHookAttempted","type":"event"} ]; - - const ENSJobPagesABI = [ + {"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"ens","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"nameWrapper","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"publicResolver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"jobsRootName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"jobsRootNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}, {"inputs":[],"name":"jobManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, - {"inputs":[],"name":"useEnsJobTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}, - {"inputs":[],"name":"configLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}, - {"inputs":[],"name":"publicResolver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"jobLabelPrefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"nextJobId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}, + {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobLabelSnapshot","outputs":[{"internalType":"bool","name":"isSet","type":"bool"},{"internalType":"string","name":"label","type":"string"}],"stateMutability":"view","type":"function"}, {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobEnsLabel","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobEnsName","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobEnsURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, - {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobEnsNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"} + {"inputs":[{"internalType":"uint256","name":"jobId","type":"uint256"}],"name":"jobEnsNode","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"useEnsJobTokenURI","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}, + {"inputs":[],"name":"configLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"} ]; @@ -3095,27 +3099,68 @@

Contact & Legal

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'}; + 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'}; }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 && 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'}; + 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 && p.claimable){ + title = 'Claim your Alpha Agent Identity'; + body = 'A wrapped alpha-agent ENS name is already present for this label and can be claimed into your soulbound identity credential now.'; + pill = 'Identity claim available'; + primary = {label:'Claim Alpha Agent Identity', action:'claim-alpha-identity'}; + secondary = {label:'Open ENS-only alpha-agent path', action:'mint-alpha'}; + }else if(connected && isMainnet && hasAcceptedTerms && p && p.identityExists && (p.status===3 || p.status===4)){ + title = 'Repair Alpha Agent Identity state'; + body = 'Your selected label indicates expired or desynced identity posture. Run sync to repair or clean up stale credential state.'; + pill = 'Identity sync 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 && p.registrable){ + title = 'Mint Alpha Agent Identity'; + body = 'Use the recommended register(label) path to mint wrapped ENS + soulbound identity (gas only, no recipient override).'; + pill = 'Identity register available'; + 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'}; + 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'}; }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'}; + 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:'Open alpha-agent section', action:'mint-alpha'}; + secondary = {label:'Refresh identity preview', action:'refresh-identity-preview'}; }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'; 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'; + 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){ primary = {label:'Open alpha-agent section', action:'mint-alpha'}; secondary = {label:'Refresh identity preview', action:'refresh-identity-preview'}; } + else { 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; @@ -3621,7 +3666,8 @@

Contact & Legal

if(el('ensHookReadiness')) el('ensHookReadiness').textContent = 'ENSJobPages unavailable. Degraded state: live preview is not fully available.'; return; } - const nextJobId = Number(await agiJobManager.methods.nextJobId().call()); + const nextJobIdRead = await ensContract.methods.nextJobId().call().catch(()=>agiJobManager.methods.nextJobId().call().catch(()=>0)); + const nextJobId = Number(nextJobIdRead || 0); const [owner, ensRegistry, nameWrapper, publicResolver, rootName, rootNode, jobManager, tokenUriMode, configLocked, prefix, snapshot, label, ensName, ensURI, ensNode] = await Promise.all([ ensContract.methods.owner().call().catch(()=>''), ensContract.methods.ens().call().catch(()=>''), @@ -3930,8 +3976,22 @@

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; } @@ -3949,7 +4009,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,identityBalance] = await Promise.all([ + const [rootName,rootNode,rootActive,paused,wrapper,registry,owner,pendingOwner,fuses,name,symbol,health] = await Promise.all([ freeTrialRegistrarIdentity.methods.ROOT_NAME().call().catch(()=>''), freeTrialRegistrarIdentity.methods.ROOT_NODE().call().catch(()=>''), freeTrialRegistrarIdentity.methods.rootActive().call().catch(()=>false), @@ -3961,40 +4021,34 @@

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), - userAccount ? freeTrialRegistrarIdentity.methods.balanceOf(userAccount).call().catch(()=>null) : Promise.resolve(null) + freeTrialRegistrarIdentity.methods.rootHealth().call().catch(()=>null) ]); const computed = namehash(ALPHA_AGENT_PARENT); - 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('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 || '—'}`; if(el('alphaIdentityRequiredFuses')) el('alphaIdentityRequiredFuses').textContent = String(fuses || '—'); - if(el('alphaIdentityNameSymbol')) el('alphaIdentityNameSymbol').textContent = `${name || '—'} / ${symbol || '—'}${identityBalance===null?'':` · balanceOf(wallet): ${identityBalance}`}`; + if(el('alphaIdentityNameSymbol')) el('alphaIdentityNameSymbol').textContent = `${name || '—'} / ${symbol || '—'}`; + 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('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 rootMismatch = (rootNode || h?.rootNode) && computed.toLowerCase() !== String(h?.rootNode || rootNode).toLowerCase(); - let mismatchWarnings = []; + const effectiveRootNode = String(rootNode || h?.rootNode || '').trim(); + const rootNodeMismatch = !!effectiveRootNode && computed.toLowerCase() !== effectiveRootNode.toLowerCase(); + if(rootNodeMismatch && el('alphaIdentityActionStatus')) el('alphaIdentityActionStatus').textContent = `Blocking warning: ROOT_NODE mismatch. computed ${computed}, contract ${effectiveRootNode}.`; + const 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 ensOnlyWrapper = await freeTrialRegistrar?.methods?.wrapper?.().call().catch(()=> ''); + if(wrapper && ensOnlyWrapper && String(wrapper).toLowerCase() !== String(ensOnlyWrapper).toLowerCase()) mismatchWarnings.push('Identity wrapper differs from ENS-only registrar wrapper.'); + if(managerEns && registry && String(managerEns).toLowerCase() !== String(registry).toLowerCase()) mismatchWarnings.push('Identity ensRegistry differs from AGIJobManager.ens().'); + if(managerWrapper && wrapper && String(managerWrapper).toLowerCase() !== String(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; @@ -4004,36 +4058,35 @@

Contact & Legal

if(el('alphaIdentityExists')) el('alphaIdentityExists').textContent = preview ? String(!!preview.identityExists) : '—'; if(el('alphaIdentityClaimable')) el('alphaIdentityClaimable').textContent = preview ? String(!!preview.claimable) : '—'; if(el('alphaIdentityRegistrable')) el('alphaIdentityRegistrable').textContent = preview ? String(!!preview.registrable) : '—'; - 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)); + const lockedReason = rootNodeMismatch ? 'ROOT_NODE mismatch blocks identity writes.' : identityWriteLockedReason(preview); + const registerEnabled = !lockedReason && preview?.registrable; + const claimEnabled = !lockedReason && preview?.claimable; + const syncEnabled = !lockedReason && preview?.identityExists && (preview.status===3 || preview.status===4); 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(mismatchWarnings.length) el('alphaIdentityActionStatus').textContent += ` Warning: ${mismatchWarnings.join(' ')}`; } - - if(preview?.tokenId && !!preview?.identityExists){ - const [ownerOf, labelData, tokenURI, lockedState] = await Promise.all([ - freeTrialRegistrarIdentity.methods.ownerOf(preview.tokenId).call().catch(()=> preview?.tokenOwner || ''), + if(preview?.identityExists && preview?.tokenId){ + const [ownerOf, isLocked, labelData, tokenURI] = await Promise.all([ + freeTrialRegistrarIdentity.methods.ownerOf(preview.tokenId).call().catch(()=>''), + freeTrialRegistrarIdentity.methods.locked(preview.tokenId).call().catch(()=>true), freeTrialRegistrarIdentity.methods.labelData(preview.tokenId).call().catch(()=>null), freeTrialRegistrarIdentity.methods.tokenURI(preview.tokenId).call().catch(()=>''), - freeTrialRegistrarIdentity.methods.locked(preview.tokenId).call().catch(()=>true), ]); - 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('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('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('alphaIdentityWrappedExpiry')) el('alphaIdentityWrappedExpiry').textContent = formatTimestamp(preview?.currentWrappedExpiry || 0); if(el('alphaIdentityMintedAt')) el('alphaIdentityMintedAt').textContent = ld ? formatTimestamp(ld.mintedAt) : '—'; - if(el('alphaIdentityStatusPill')) el('alphaIdentityStatusPill').textContent = `${preview?.statusLabel || '—'} (${preview?.status ?? '—'}) · soulbound locked: ${lockedState ? 'true' : 'false'}`; + if(el('alphaIdentityStatusPill') && isLocked===false) el('alphaIdentityStatusPill').textContent += ' · unlock anomaly'; if(tokenURI && tokenURI.startsWith('data:application/json;base64,')){ try{ const payload = JSON.parse(atob(tokenURI.split(',')[1] || '')); @@ -4041,8 +4094,16 @@

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'); } } - }catch{} + if(node){ + if(img){ node.style.display='block'; node.src = img; } + else{ node.style.display='none'; node.removeAttribute('src'); } + } + }catch{ + 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{ if(el('alphaIdentityTokenMetaName')) el('alphaIdentityTokenMetaName').textContent = '—'; if(el('alphaIdentityTokenMetaDescription')) el('alphaIdentityTokenMetaDescription').textContent = '—'; @@ -4051,9 +4112,9 @@

Contact & Legal

} }else{ 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('alphaIdentityWrappedOwner')) el('alphaIdentityWrappedOwner').textContent = '—'; + if(el('alphaIdentityResolver')) el('alphaIdentityResolver').textContent = '—'; + if(el('alphaIdentityWrappedExpiry')) el('alphaIdentityWrappedExpiry').textContent = '—'; if(el('alphaIdentityMintedAt')) el('alphaIdentityMintedAt').textContent = '—'; if(el('alphaIdentityTokenMetaName')) el('alphaIdentityTokenMetaName').textContent = '—'; if(el('alphaIdentityTokenMetaDescription')) el('alphaIdentityTokenMetaDescription').textContent = '—'; @@ -4093,17 +4154,13 @@

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; - const receipt = await runTrackedTx(`Alpha identity ${action} ${local.label}`, send, {pendingDetail:`Submitting ${action}…`, successDetail:`${action} confirmed.`}); + 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); - 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'); + setToast(`Identity action ${action} confirmed for ${local.label}.${ALPHA_AGENT_PARENT}.`, 'ok'); } function renderIdentityAdminControls(owner,pendingOwner){ const box = el('alphaIdentityAdminControls'); @@ -5541,21 +5598,39 @@

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 managerWrapperAddr = await agiJobManager?.methods?.nameWrapper?.().call().catch(()=>null); - const managerEnsAddr = await agiJobManager?.methods?.ens?.().call().catch(()=>null); + const managerWrapperAddr = await agiJobManager?.methods?.nameWrapper?.().call().catch(()=> ''); const wrapperCheckDegraded = !managerWrapperAddr || isZeroAddress(managerWrapperAddr); - const wrapperAddr = wrapperCheckDegraded ? NAME_WRAPPER : managerWrapperAddr; - if(!wrapperAddr || isZeroAddress(wrapperAddr)) throw new Error('No usable NameWrapper address available for verification.'); - const nw = new web3.eth.Contract(NameWrapperABI, wrapperAddr); + const runtimeNameWrapper = wrapperCheckDegraded ? NAME_WRAPPER : managerWrapperAddr; + const nw = new web3.eth.Contract(NameWrapperABI, runtimeNameWrapper); const owner = await nw.methods.ownerOf(tokenID).call(); const acct = String(userAccount || '').toLowerCase(); const ownerLc = String(owner || '').toLowerCase(); @@ -5563,26 +5638,49 @@

Contact & Legal

const approvedLc = String(approved || '').toLowerCase(); const approvedForAll = await nw.methods.isApprovedForAll(owner, userAccount).call().catch(()=>false); let resolverAddrMatch = false; - const resolverCheckDegraded = !managerEnsAddr || isZeroAddress(managerEnsAddr); - if(!resolverCheckDegraded){ - const ensRegistry = new web3.eth.Contract(ENSRegistryResolverABI, managerEnsAddr); - const nodeResolver = await ensRegistry.methods.resolver(tokenID).call().catch(()=>"0x0000000000000000000000000000000000000000"); - resolverAddrMatch = !!nodeResolver && String(nodeResolver).toLowerCase() === acct; - } + 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 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}${wrapperCheckDegraded ? '; wrapper source degraded' : ''}${resolverCheckDegraded ? '; resolver check degraded' : ''}): ${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 degraded/error: ${e.message || String(e)}`; pill.className = "pill bad"; pill.textContent = (isAgent?"Agent":"Club") + " ENS: degraded"; updateReadinessUI(); + console.error(e); + clearRoleVerification(); + out.textContent = `Verification error: ${e.message || String(e)}`; + pill.className = "pill bad"; + pill.textContent = (isAgent?"Agent":"Club") + " ENS: error"; + updateReadinessUI(); } }