UI: Revamp Premium Participate studio, update continuity fields and UI text/CSS (2026-04-02)#220
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5b04eb9b22
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| } | ||
| }; | ||
| box.appendChild(img); | ||
| box.innerHTML = `<img src="${src}" alt="Job cover preview" onerror="this.parentNode.textContent='Image unavailable'">`; |
There was a problem hiding this comment.
Build cover preview image without unsafe innerHTML
The new box.innerHTML = ...${src}... interpolation places a user-controlled URI directly into HTML after only prefix validation in isValidUriLoose, so an input like https://x" onerror="... can break attribute context and execute script in the page. The previous element/property approach (img.src = ...) did not have this injection path; please switch back to DOM property assignment (or strict escaping) for the image preview.
Useful? React with 👍 / 👎.
| function pel(id){ return document.getElementById(id); } | ||
| function premiumRoundUnits(raw, bps){ return raw <= 0n ? 0n : (raw * BigInt(bps)) / 10000n; } | ||
| function premiumFormat(raw){ try{ return `${formatUnitsToAmount(raw)} $AGIALPHA`; }catch{ return '—'; } } | ||
| function formatNumber(value){ | ||
| const n = typeof value === 'bigint' ? Number(value) : Number(value); | ||
| if(!Number.isFinite(n)) return String(value ?? '—'); | ||
| return n.toLocaleString('en-US'); | ||
| } | ||
| async function copyText(value, okMessage='Copied.'){ | ||
| try{ | ||
| await navigator.clipboard.writeText(String(value ?? '')); | ||
| setToast(okMessage, 'ok'); | ||
| }catch(_){ | ||
| setToast('Clipboard unavailable in this environment.', 'warn'); | ||
| } | ||
| } | ||
| const PREMIUM_SETTLEMENT_DEFAULTS = {premiumReputationThreshold:10000,requiredValidatorApprovals:3,requiredValidatorDisapprovals:3,voteQuorum:3,validationRewardPercentage:8,completionReviewPeriod:7*86400,disputeReviewPeriod:14*86400,challengePeriodAfterApproval:86400,validatorBondBps:1500,validatorBondMin:1_0000000000000000000n*10n,validatorBondMax:88888888_000000000000000000n,validatorSlashBps:8000,agentBondBps:500,agentBondMin:1_0000000000000000000n,agentBondMax:88888888_000000000000000000n,jobDurationLimit:10000000,DISPUTE_BOND_BPS:50,DISPUTE_BOND_MIN:1_0000000000000000000n,DISPUTE_BOND_MAX:200_000000000000000000n}; |
There was a problem hiding this comment.
Reintroduce removed premium helper functions
This edit removed local helpers in this section, but later code still calls them: premiumRefresh() uses formatNumber(...) when building scenarioRows, and first-live copy handlers call copyText(...). As a result, running premiumRefresh() now throws ReferenceError: formatNumber is not defined (breaking create-panel refresh), and copy buttons throw copyText is not defined on click.
Useful? React with 👍 / 👎.
| document.querySelectorAll('[data-premium-role-action]').forEach(btn=>btn.addEventListener('click', ()=>setPanel('participate'))); | ||
| $('premiumParticipateLoadBtn')?.addEventListener('click', ()=>refreshParticipate()); |
There was a problem hiding this comment.
Sync inspector quick actions to new procurement field
The new inspector role-action binding only switches to the participate panel, but does not copy the inspector procurement id into the new premiumParticipateProcurementId input. The old auto-trigger path in boot() still targets the removed premiumActionProcurementId, so clicking inspector quick actions now commonly submits with an empty procurement id and shows the warning instead of opening a prefilled review flow.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
premiumRefresh() still references timelineMonotonic when composing Step 4 of wizardRail, but this commit removed the local const timelineMonotonic = ... definition. As soon as premiumRefresh() runs, the missing identifier throws ReferenceError, which interrupts the rest of the premium create refresh flow (wizard rail/status, validations, and related UI updates).
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const role = activeParticipateRole(); | ||
| const finalist = role === 'validator' ? (finalistSelect || finalistText) : (finalistText || finalistSelect); | ||
| return {pid:String($('premiumActionProcurementId')?.value||'').trim(), subdomain:normalizeSubdomainLabel($('premiumActionSubdomain')?.value), proof:parseProof($('premiumActionProof')?.value), commitment:String($('premiumActionCommitment')?.value||'').trim(), salt:String($('premiumActionSalt')?.value||'').trim(), uri:String($('premiumActionApplicationUri')?.value||'').trim(), finalist, score:String($('premiumActionScore')?.value||'').trim()}; | ||
| function actionInputs(){ return {pid:String($('premiumActionProcurementId')?.value||$('premiumParticipateProcurementId')?.value||'').trim(), subdomain:String($('premiumActionSubdomain')?.value||'').trim(), proof:parseProof($('premiumActionProof')?.value), commitment:String($('premiumActionCommitment')?.value||'').trim(), salt:String($('premiumActionSalt')?.value||'').trim(), uri:String($('premiumActionApplicationUri')?.value||'').trim(), finalist:String($('premiumActionFinalist')?.value||'').trim(), score:String($('premiumActionScore')?.value||'').trim()}; } |
There was a problem hiding this comment.
Use finalist trial URI field when building submitTrial payload
The new Finalist rail introduced premiumActionApplicationUriFinalist, but actionInputs() still sources uri only from premiumActionApplicationUri (the applicant field). Because the sync is one-way (finalist input writes into the hidden applicant field), stale applicant/continuity/import values can be submitted as trialURI even when the visible finalist input is empty or different, causing incorrect submitTrial review/transaction data.
Useful? React with 👍 / 👎.
Motivation
Description
premiumParticipateProcurementId,premiumParticipateSubdomain,premiumRoleChip,premiumApplicantRail,premiumFinalistRail,premiumValidatorRail,premiumClaimantRail).actionInputschanges,normalizeSubdomain,setRole,refreshParticipate, local packet save/download/import helpers, commitment/score generation adjustments, and bindings for new buttons and chips; switched some approval calls topremiumApprove(...)and updated packet storage keys.UI_CONTINUITY_FIELDS/portableFieldIds) so participate inputs persist across sessions and restored logic accordingly..premiumRoleChip.active,.premiumStickyCtaMobile, the advanced vault summary, renaming an inspector tab to "Procurement inspector", tweaking claims/notes copy, and bumping the console title and comment date to2026-04-02.Testing
Codex Task