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 @@
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();
}
}