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