> ## Documentation Index
> Fetch the complete documentation index at: https://docs.codatta.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog 2026

> This changelog documents all updates, fixes, and new features for Codatta in 2026.

<div
  style={{
backgroundColor: '#ffffff',
border: '1px solid #e5e7eb',
borderRadius: '0.75rem',
padding: '0.875rem 1.25rem',
marginBottom: '2rem',
boxShadow: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)'
}}
>
  <div
    style={{
display: 'flex',
alignItems: 'center',
flexWrap: 'wrap',
gap: '1rem',
marginBottom: '0.1rem'
}}
  >
    <ChangelogFilter />

    <MonthFilter />
  </div>

  {(() => {
      const ShowResult = () => {
        const [num, setNum] = useState(0);
        useEffect(() => {
          if (typeof document === 'undefined') return;
          const update = () => {
            try {
              const items = document.querySelectorAll('.changelog-item');
              let count = 0;
              items.forEach(item => {
                if (item.style.display !== 'none') count++;
              });
              setNum(count);
            } catch {}
          };
          update();
          const id = setInterval(update, 2000);
          return () => clearInterval(id);
        }, []);
        return (
          <div style={{
            display: 'flex',
            alignItems: 'center',
            padding: '0.5rem 0.875rem',
            backgroundColor: '#f9fafb',
            borderRadius: '0.5rem',
            fontSize: '0.8125rem',
            color: '#6b7280',
            border: '1px solid #e5e7eb',
            display: 'inline-flex',
            fontWeight: '500',
            letterSpacing: '0.01em'
          }}>
            <span style={{
              display: 'inline-block',
              width: '6px',
              height: '6px',
              borderRadius: '50%',
              backgroundColor: '#10b981',
              marginRight: '0.5rem',
              flexShrink: 0
            }}></span>
            <strong style={{color:'#111827', fontWeight:'600', marginRight: '0.25rem'}}>{num}</strong>
            <span>result{num !== 1 ? 's' : ''}</span>
          </div>
        );
      };
      return <ShowResult />;
    })()}
</div>

<div className="changelog-item" data-type="core-feature" data-month="mar">
  ## Mar 22, 2026

  ***

  **Qualification System: Contributors Must Now Meet Requirements Before Claiming Gated Tasks**

  <br />

  <div style={{ marginTop: "1rem" }} />

  A full qualification framework is now live across the Frontier Platform and Task Engine, enabling task managers to gate access based on contributor credentials.

  * **Gate:** Task managers can define qualification requirements — education level, location, domain expertise — directly from the Frontier management interface.
  * **Visibility:** Contributors see qualification tags on task listings and can check their eligibility status at a glance.
  * **Profile:** A unified user profile page now includes education and location fields, a homepage check-in button, and a profile sidebar for quick access to qualification status.
  * **Backward compatible:** Existing certified users retain their credentials automatically — no re-verification required.
</div>

<div className="changelog-item" data-type="core-feature" data-month="mar">
  ## Mar 22, 2026

  ***

  **On-Chain Token Reward Claiming is Now Live**

  <br />

  <div style={{ marginTop: "1rem" }} />

  Contributors can now claim earned token rewards directly to their wallet through the Frontier Platform.

  * **Claim:** A new claim modal guides contributors through on-chain signature verification and gas fee estimation before submitting the transaction.
  * **Scope:** All task rewards accumulated across Frontier activities are claimable in a single transaction flow.
</div>

<div className="changelog-item" data-type="optimization" data-month="mar">
  ## Mar 22, 2026

  ***

  **CEX Deposit & Withdrawal Flow Added to Frontier Platform**

  <br />

  <div style={{ marginTop: "1rem" }} />

  Contributors can now move funds between CEX wallets and the Frontier Platform without leaving the app, with tighter platform access controls in place.

  * **Deposit & Withdraw:** Full CEX deposit and withdrawal flows are now accessible directly from the Frontier interface.
  * **Access control:** Invite-code enforcement is now active on restricted API endpoints — only contributors with a registered invite code can access these routes.
  * **Rate limiting:** The API Gateway now includes an upper bound on rate-limit duration, with message headers and status codes in every rate-limit response.
</div>

<div className="changelog-item" data-type="protocol" data-month="mar">
  ## Mar 17, 2026

  ***

  **Gas Payment Smoothing Contracts Deployed**

  <br />

  <div style={{ marginTop: "1rem" }} />

  On-chain transaction costs are now managed through an automated cost-smoothing mechanism, removing the gas burden from contributors.

  * **How:** The Gas Payment contracts automatically swap \$XNY to ETH via Uniswap to cover transaction fees on behalf of contributors.
  * **Deployment:** Scripts are fully automated and repeatable for future contract upgrades.
</div>

<div className="changelog-item" data-type="core-feature" data-month="mar">
  ## Mar 11, 2026

  ***

  **Codatta Mobile App Launched**

  <br />

  <div style={{ marginTop: "1rem" }} />

  The Codatta Mobile App is now available, bringing the full Frontier contributor experience to iOS and Android.

  * **Tasks on mobile:** Contributors can discover and complete Frontier tasks, track reputation, and manage their profile entirely from the app.
  * **App Bridge:** A native bridge layer connects Frontier tasks to device APIs, enabling camera, location, and sensor-based task flows.
</div>

<div className="changelog-item" data-type="core-feature" data-month="feb">
  ## Feb 14, 2026

  ***

  **App Bridge: Mobile-Native Task Flows and Audit Transparency**

  <br />

  <div style={{ marginTop: "1rem" }} />

  Frontier tasks can now access native device capabilities on mobile, and submission history is more transparent for contributors.

  * **Bridge:** The app bridge layer enables Frontier tasks to use native mobile APIs (camera, sensors, location) within the task flow.
  * **Audit visibility:** Task submission history now shows the audit reason for any rejected submission, so contributors understand exactly what to improve.
  * **Task control:** Task publishers can now toggle task visibility separately for app and web audiences.
</div>

<div className="changelog-item" data-type="optimization" data-month="feb">
  ## Feb 09, 2026

  ***

  **Task Feed: Device-Aware Filtering and Fairer Distribution**

  <br />

  <div style={{ marginTop: "1rem" }} />

  The Frontier task feed now intelligently serves tasks based on the contributor's device and refreshes more equitably across the contributor pool.

  * **Device filtering:** Tasks that require specific hardware (desktop, mobile, sensors) are matched to the appropriate device at the API level — no more irrelevant tasks in the feed.
  * **Fairer feed:** Task ranking now refreshes every 10 minutes with a randomized sort component, ensuring all contributors get exposure to high-value tasks over time.
</div>

<div className="changelog-item" data-type="core-feature" data-month="feb">
  ## Feb 02, 2026

  ***

  **Contributor Data Profile Page**

  <br />

  <div style={{ marginTop: "1rem" }} />

  A new Data Profile page gives contributors a full view of their platform activity in one place.

  * **Stats:** Access via User Info > Data Profile to see total submissions, earned rewards, and contribution history in a visual dashboard.
  * **Access control:** An invite code system has been added to the app — only contributors with a registered invite code can access restricted app endpoints, protecting the platform from unauthorized use.
</div>

<div className="changelog-item" data-type="optimization" data-month="jan">
  ## Jan 26, 2026

  ***

  **Reputation System Redesign**

  <br />

  <div style={{ marginTop: "1rem" }} />

  The reputation score visualization and underlying calculation have been updated for greater clarity and accuracy across the platform.

  * **Detail view:** A new reputation breakdown page shows contributors their score components, rank comparison, and historical trend.
  * **Feed alignment:** Task listings now show participant counts, and the feed prioritizes tasks aligned with contributor reputation levels.
  * **Performance:** The reputation API now returns baseline data enriched with ranking fields, improving query speed under high load.
</div>

<div className="changelog-item" data-type="core-feature" data-month="jan">
  ## Jan 12, 2026

  ***

  **New Frontier: CEX Hot Wallet Data Collection**

  <br />

  <div style={{ marginTop: "1rem" }} />

  A dedicated Frontier for CEX (centralized exchange) hot wallet data is now live, expanding the platform's on-chain data collection capabilities.

  * **Tasks:** Contributors can submit and annotate CEX hot wallet transaction records through structured Frontier tasks.
  * **Multi-exchange:** Exchange group configuration supports multiple CEX providers within a single frontier.
  * **Architecture:** Frontier V2 launched alongside this release — improved task runtime, history display, and cross-device API support.
</div>

<div className="changelog-item" data-type="core-feature" data-month="jan">
  ## Jan 05, 2026

  ***

  **New Frontier: Fashion Validation**

  <br />

  <div style={{ marginTop: "1rem" }} />

  A fashion image validation Frontier is now available for structured AI training dataset collection.

  * **Tasks:** Contributors validate and annotate fashion images across categories, providing labeled data for visual AI models.
  * **Configuration:** Task publishers can set difficulty levels and enable repeat submissions for ongoing data collection campaigns.
  * **Referral rewards:** Contributors who recruit new members automatically receive rewards when their invitees complete their first task.
</div>

<div className="changelog-item" data-type="core-feature" data-month="jan">
  ## Jan 01, 2026

  ***

  **Staking & Reputation System Overhaul**

  <br />

  <div style={{ marginTop: "1rem" }} />

  The staking and reputation systems have been completely redesigned as the foundation for the 2026 platform architecture.

  * **Staking conditions:** Staking condition queries and async reputation refresh on stake events are now supported end-to-end across the Task Engine, User service, and Asset service.
  * **Reputation checks:** Contributors who stake are subject to reputation checks before claiming high-value tasks, protecting ecosystem quality.
  * **Referral integration:** Referral rewards are issued automatically when an invited contributor completes their first task.
  * **Community:** Discord community group support has been integrated into the Campaign Engine for campaign-level distribution.
</div>

export const ChangelogFilter = () => {
  const [activeFilter, setActiveFilter] = useState('all');
  const [isOpen, setIsOpen] = useState(false);
  const [isMenuHovered, setIsMenuHovered] = useState(false);
  useEffect(() => {
    window.activeTypeFilter = activeFilter;
  }, [activeFilter]);
  useEffect(() => {
    const items = document.querySelectorAll('.changelog-item');
    const activeMonth = window.activeMonthFilter || 'all';
    items.forEach(item => {
      const itemType = item.getAttribute('data-type');
      const itemMonth = item.getAttribute('data-month');
      const typeMatch = activeFilter === 'all' || itemType === activeFilter;
      const monthMatch = activeMonth === 'all' || itemMonth === activeMonth;
      item.style.display = typeMatch && monthMatch ? '' : 'none';
    });
  }, [activeFilter]);
  const filterTypes = [{
    id: 'all',
    label: 'All',
    color: '#6b7280',
    count: 12
  }, {
    id: 'core-feature',
    label: 'Core Feature Release',
    color: '#16A34A',
    count: 8
  }, {
    id: 'optimization',
    label: 'Adjustments & Optimization',
    color: '#F59E0B',
    count: 3
  }, {
    id: 'protocol',
    label: 'Protocol & Blockchain',
    color: '#3B82F6',
    count: 1
  }];
  const activeType = filterTypes.find(type => type.id === activeFilter) || filterTypes[0];
  return <div style={{
    marginBottom: '2rem',
    position: 'relative'
  }}>
      <div onClick={() => setIsOpen(!isOpen)} style={{
    display: 'inline-flex',
    alignItems: 'center',
    gap: '0.5rem',
    padding: '0.625rem 1rem',
    border: '2px solid #e5e7eb',
    borderRadius: '0.5rem',
    background: 'white',
    cursor: 'pointer',
    fontSize: '0.875rem',
    fontWeight: '500',
    boxShadow: isOpen ? `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)` : '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
    transition: 'all 0.2s ease',
    userSelect: 'none',
    minWidth: '200px'
  }}>
        <span style={{
    width: '12px',
    height: '12px',
    borderRadius: '50%',
    backgroundColor: activeType.color,
    display: 'inline-block',
    flexShrink: 0
  }} />
        <span style={{
    flex: 1
  }}>
          {activeType.label} ({activeType.count})
        </span>
        <span style={{
    display: 'inline-block',
    width: '0',
    height: '0',
    borderLeft: '5px solid transparent',
    borderRight: '5px solid transparent',
    borderTop: '6px solid #6b7280',
    transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
    transition: 'transform 0.2s ease',
    flexShrink: 0
  }} />
      </div>

      {isOpen && <div onMouseEnter={() => setIsMenuHovered(true)} onMouseLeave={() => setIsMenuHovered(false)} style={{
    position: 'absolute',
    top: '100%',
    left: 0,
    marginTop: '0.5rem',
    backgroundColor: 'white',
    border: `2px solid ${isMenuHovered ? '#9ca3af' : '#e5e7eb'}`,
    borderRadius: '0.5rem',
    boxShadow: isMenuHovered ? '0 10px 15px -3px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.1)' : '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
    zIndex: 1000,
    minWidth: '280px',
    overflow: 'hidden',
    transition: 'border-color 0.2s ease, box-shadow 0.2s ease'
  }}>
          {filterTypes.map(type => <div key={type.id} onClick={() => {
    setActiveFilter(type.id);
    setIsOpen(false);
  }} style={{
    padding: '0.75rem 1rem',
    cursor: 'pointer',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    borderBottom: type.id !== filterTypes[filterTypes.length - 1].id ? '1px solid #f3f4f6' : 'none',
    backgroundColor: activeFilter === type.id ? '#f9fafb' : 'white',
    transition: 'background-color 0.15s ease'
  }} onMouseEnter={e => {
    if (activeFilter !== type.id) {
      e.currentTarget.style.backgroundColor = '#f3f4f6';
    }
  }} onMouseLeave={e => {
    if (activeFilter !== type.id) {
      e.currentTarget.style.backgroundColor = 'white';
    }
  }}>
              <span style={{
    flex: 1,
    fontSize: '0.875rem',
    fontWeight: activeFilter === type.id ? '600' : '400'
  }}>
                {type.label}
              </span>
              <span style={{
    fontSize: '0.75rem',
    color: '#6b7280',
    fontWeight: '500'
  }}>
                {type.count}
              </span>
            </div>)}
        </div>}

      {isOpen && <div onClick={() => setIsOpen(false)} style={{
    position: 'fixed',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    zIndex: 999,
    backgroundColor: 'transparent'
  }} />}
    </div>;
};

export const MonthFilter = () => {
  const [activeMonth, setActiveMonth] = useState('all');
  const [isOpen, setIsOpen] = useState(false);
  const [isMenuHovered, setIsMenuHovered] = useState(false);
  useEffect(() => {
    window.activeMonthFilter = activeMonth;
    const event = new Event('monthFilterChange');
    window.dispatchEvent(event);
  }, [activeMonth]);
  useEffect(() => {
    const handleMonthChange = () => {
      const items = document.querySelectorAll('.changelog-item');
      const activeType = window.activeTypeFilter || 'all';
      items.forEach(item => {
        const itemType = item.getAttribute('data-type');
        const itemMonth = item.getAttribute('data-month');
        const typeMatch = activeType === 'all' || itemType === activeType;
        const monthMatch = activeMonth === 'all' || itemMonth === activeMonth;
        item.style.display = typeMatch && monthMatch ? '' : 'none';
      });
    };
    window.addEventListener('monthFilterChange', handleMonthChange);
    handleMonthChange();
    return () => {
      window.removeEventListener('monthFilterChange', handleMonthChange);
    };
  }, [activeMonth]);
  const months = [{
    id: 'all',
    label: 'All Months',
    count: 12
  }, {
    id: 'mar',
    label: 'March',
    count: 5
  }, {
    id: 'feb',
    label: 'February',
    count: 3
  }, {
    id: 'jan',
    label: 'January',
    count: 4
  }];
  const activeMonthData = months.find(month => month.id === activeMonth) || months[0];
  return <div style={{
    marginBottom: '2rem',
    position: 'relative',
    marginLeft: '1rem'
  }}>
      <div onClick={() => setIsOpen(!isOpen)} style={{
    display: 'inline-flex',
    alignItems: 'center',
    gap: '0.5rem',
    padding: '0.625rem 1rem',
    border: '2px solid #e5e7eb',
    borderRadius: '0.5rem',
    background: 'white',
    cursor: 'pointer',
    fontSize: '0.875rem',
    fontWeight: '500',
    boxShadow: isOpen ? `0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)` : '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
    transition: 'all 0.2s ease',
    userSelect: 'none',
    minWidth: '200px'
  }}>
        <span style={{
    flex: 1
  }}>
          {activeMonthData.label} ({activeMonthData.count})
        </span>
        <span style={{
    display: 'inline-block',
    width: '0',
    height: '0',
    borderLeft: '5px solid transparent',
    borderRight: '5px solid transparent',
    borderTop: '6px solid #6b7280',
    transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)',
    transition: 'transform 0.2s ease',
    flexShrink: 0
  }} />
      </div>

      {isOpen && <div onMouseEnter={() => setIsMenuHovered(true)} onMouseLeave={() => setIsMenuHovered(false)} style={{
    position: 'absolute',
    top: '100%',
    left: 0,
    marginTop: '0.5rem',
    backgroundColor: 'white',
    border: `2px solid ${isMenuHovered ? '#9ca3af' : '#e5e7eb'}`,
    borderRadius: '0.5rem',
    boxShadow: isMenuHovered ? '0 10px 15px -3px rgba(0, 0, 0, 0.15), 0 4px 6px -2px rgba(0, 0, 0, 0.1)' : '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
    zIndex: 1000,
    minWidth: '280px',
    overflow: 'hidden',
    transition: 'border-color 0.2s ease, box-shadow 0.2s ease'
  }}>
          {months.map(month => <div key={month.id} onClick={() => {
    setActiveMonth(month.id);
    setIsOpen(false);
  }} style={{
    padding: '0.75rem 1rem',
    cursor: 'pointer',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    borderBottom: month.id !== months[months.length - 1].id ? '1px solid #f3f4f6' : 'none',
    backgroundColor: activeMonth === month.id ? '#f9fafb' : 'white',
    transition: 'background-color 0.15s ease'
  }} onMouseEnter={e => {
    if (activeMonth !== month.id) {
      e.currentTarget.style.backgroundColor = '#f3f4f6';
    }
  }} onMouseLeave={e => {
    if (activeMonth !== month.id) {
      e.currentTarget.style.backgroundColor = 'white';
    }
  }}>
              <span style={{
    flex: 1,
    fontSize: '0.875rem',
    fontWeight: activeMonth === month.id ? '600' : '400'
  }}>
                {month.label}
              </span>
              <span style={{
    fontSize: '0.75rem',
    color: '#6b7280',
    fontWeight: '500'
  }}>
                {month.count}
              </span>
            </div>)}
        </div>}

      {isOpen && <div onClick={() => setIsOpen(false)} style={{
    position: 'fixed',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    zIndex: 999,
    backgroundColor: 'transparent'
  }} />}
    </div>;
};
