From f0de33442134062392b3bcfb7c7d40b99c54962a Mon Sep 17 00:00:00 2001 From: Henrythefoodie <13022037121@163.com> Date: Sat, 29 Aug 2026 23:49:05 +0800 Subject: [PATCH 1/4] fix(programs): remove redundant tuition warning --- src/app/[locale]/programs/[slug]/page.tsx | 4 ++-- src/i18n/messages.ts | 13 ++++++------- .../application-decision-experience.test.tsx | 17 +++++++++++++++-- tests/unit/favorites-view.test.tsx | 2 +- 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/app/[locale]/programs/[slug]/page.tsx b/src/app/[locale]/programs/[slug]/page.tsx index 74519f6..31af2c9 100644 --- a/src/app/[locale]/programs/[slug]/page.tsx +++ b/src/app/[locale]/programs/[slug]/page.tsx @@ -107,7 +107,7 @@ export default async function ProgramDetailPage({ params }: { params: Promise<{ : `${program.durationMonths} ${messages.common.months}` const partialTuition = cycle?.tuitionCny == null ? messages.common.unknown - : `${formatCny(cycle.tuitionCny, locale, messages.common.unknown)} / ${partialTuitionPeriodLabels[cycle.tuitionPeriod || 'other']}${cycle.tuitionStatus === 'reference' ? ` · ${messages.programs.tuitionReference}` : ''}` + : `${formatCny(cycle.tuitionCny, locale, messages.common.unknown)} / ${partialTuitionPeriodLabels[cycle.tuitionPeriod || 'other']}` const partialApplicationFee = cycle?.applicationFeeCny == null ? messages.common.unknown : formatCny(cycle.applicationFeeCny, locale, messages.common.unknown) @@ -242,7 +242,7 @@ export default async function ProgramDetailPage({ params }: { params: Promise<{ } const tuition = cycle.tuitionCny === null ? messages.common.unknown - : `${formatCny(cycle.tuitionCny, locale, messages.common.unknown)} / ${tuitionPeriodLabels[cycle.tuitionPeriod || 'other']}${cycle.tuitionStatus === 'reference' ? ` · ${messages.programs.tuitionReference}` : ''}` + : `${formatCny(cycle.tuitionCny, locale, messages.common.unknown)} / ${tuitionPeriodLabels[cycle.tuitionPeriod || 'other']}` const duration = program.durationMonthsMax && program.durationMonthsMax !== program.durationMonths ? `${program.durationMonths}–${program.durationMonthsMax} ${messages.common.months}` : `${program.durationMonths} ${messages.common.months}` diff --git a/src/i18n/messages.ts b/src/i18n/messages.ts index a1619cb..906d51c 100644 --- a/src/i18n/messages.ts +++ b/src/i18n/messages.ts @@ -47,7 +47,6 @@ const en = { type BaseMessages = typeof en type ProgramExtraMessages = { viewApplicationPortal: string - tuitionReference: string evidenceBasis: string cycleSpecific: string recurringRule: string @@ -250,12 +249,12 @@ const es: BaseMessages = { const baseDictionaries = { en, zh, ru, de, fr, es } satisfies Record const programExtraMessages: Record = { - en: { viewApplicationPortal: 'View official application portal', tuitionReference: 'Reference amount—confirm with university', evidenceBasis: 'Evidence basis', cycleSpecific: 'Cycle-specific official notice', recurringRule: 'Official recurring annual rule' }, - zh: { viewApplicationPortal: '查看官方申请系统', tuitionReference: '参考金额——请向大学确认', evidenceBasis: '信息依据', cycleSpecific: '当期官方通知', recurringRule: '官方年度常规规则' }, - ru: { viewApplicationPortal: 'Открыть официальную систему подачи заявлений', tuitionReference: 'Ориентировочная сумма — уточните в университете', evidenceBasis: 'Основание данных', cycleSpecific: 'Официальное уведомление для конкретного цикла', recurringRule: 'Официальное ежегодно действующее правило' }, - de: { viewApplicationPortal: 'Offizielles Bewerbungsportal öffnen', tuitionReference: 'Referenzbetrag – bitte bei der Universität bestätigen', evidenceBasis: 'Datengrundlage', cycleSpecific: 'Offizielle Mitteilung für den jeweiligen Zulassungszeitraum', recurringRule: 'Offizielle jährlich wiederkehrende Regelung' }, - fr: { viewApplicationPortal: 'Accéder au portail officiel de candidature', tuitionReference: 'Montant indicatif — à confirmer auprès de l’université', evidenceBasis: 'Base documentaire', cycleSpecific: 'Avis officiel propre au cycle', recurringRule: 'Règle officielle renouvelée chaque année' }, - es: { viewApplicationPortal: 'Abrir el portal oficial de solicitudes', tuitionReference: 'Importe de referencia: confírmalo con la universidad', evidenceBasis: 'Base documental', cycleSpecific: 'Aviso oficial específico del ciclo', recurringRule: 'Norma oficial recurrente anual' }, + en: { viewApplicationPortal: 'View official application portal', evidenceBasis: 'Evidence basis', cycleSpecific: 'Cycle-specific official notice', recurringRule: 'Official recurring annual rule' }, + zh: { viewApplicationPortal: '查看官方申请系统', evidenceBasis: '信息依据', cycleSpecific: '当期官方通知', recurringRule: '官方年度常规规则' }, + ru: { viewApplicationPortal: 'Открыть официальную систему подачи заявлений', evidenceBasis: 'Основание данных', cycleSpecific: 'Официальное уведомление для конкретного цикла', recurringRule: 'Официальное ежегодно действующее правило' }, + de: { viewApplicationPortal: 'Offizielles Bewerbungsportal öffnen', evidenceBasis: 'Datengrundlage', cycleSpecific: 'Offizielle Mitteilung für den jeweiligen Zulassungszeitraum', recurringRule: 'Offizielle jährlich wiederkehrende Regelung' }, + fr: { viewApplicationPortal: 'Accéder au portail officiel de candidature', evidenceBasis: 'Base documentaire', cycleSpecific: 'Avis officiel propre au cycle', recurringRule: 'Règle officielle renouvelée chaque année' }, + es: { viewApplicationPortal: 'Abrir el portal oficial de solicitudes', evidenceBasis: 'Base documental', cycleSpecific: 'Aviso oficial específico del ciclo', recurringRule: 'Norma oficial recurrente anual' }, } export const dictionaries = Object.fromEntries( diff --git a/tests/unit/application-decision-experience.test.tsx b/tests/unit/application-decision-experience.test.tsx index 731a89f..24a8f47 100644 --- a/tests/unit/application-decision-experience.test.tsx +++ b/tests/unit/application-decision-experience.test.tsx @@ -12,6 +12,15 @@ import { import { getMessages } from '@/i18n/messages' import type { AdmissionCycle, Program, Scholarship } from '@/lib/data/types' +const obsoleteTuitionReferenceLabels = [ + 'Reference amount—confirm with university', + '参考金额——请向大学确认', + 'Ориентировочная сумма — уточните в университете', + 'Referenzbetrag – bitte bei der Universität bestätigen', + 'Montant indicatif — à confirmer auprès de l’université', + 'Importe de referencia: confírmalo con la universidad', +] + const auditMeta = { sourceIds: ['source-official'], verifiedAt: '2026-08-08', @@ -169,7 +178,9 @@ describe('decision-oriented cards', () => { ) const reference = container.querySelector('[data-fact-status="reference"]') expect(reference).toHaveTextContent('2025-2026') - expect(reference).not.toHaveTextContent(messages.programs.tuitionReference) + for (const obsoleteLabel of obsoleteTuitionReferenceLabels) { + expect(reference).not.toHaveTextContent(obsoleteLabel) + } unmount() } @@ -186,7 +197,9 @@ describe('decision-oriented cards', () => { ) expect(container.querySelector('[data-fact-status="reference"]')).not.toBeInTheDocument() expect(screen.getByText(/28,000/)).toBeVisible() - expect(screen.queryByText(messages.programs.tuitionReference)).not.toBeInTheDocument() + for (const obsoleteLabel of obsoleteTuitionReferenceLabels) { + expect(screen.queryByText(obsoleteLabel)).not.toBeInTheDocument() + } }) it('puts scholarship deadline and funding first and localizes its university scope', () => { diff --git a/tests/unit/favorites-view.test.tsx b/tests/unit/favorites-view.test.tsx index 7e64e88..b75fec5 100644 --- a/tests/unit/favorites-view.test.tsx +++ b/tests/unit/favorites-view.test.tsx @@ -187,6 +187,6 @@ describe('favorites comparison workspace', () => { await user.click(await screen.findByRole('checkbox')) expect(screen.getByText(/CN¥\s*30,000/)).toBeVisible() - expect(screen.queryByText(messages.programs.tuitionReference)).not.toBeInTheDocument() + expect(screen.queryByText('Reference amount—confirm with university')).not.toBeInTheDocument() }) }) From d5ef9e4aa3c4fb0b59e7f66f82ee2485e2cf50db Mon Sep 17 00:00:00 2001 From: Henrythefoodie <13022037121@163.com> Date: Sun, 30 Aug 2026 00:09:35 +0800 Subject: [PATCH 2/4] feat(data): classify official source purposes --- .../pilot/fudan-university.json | 12 ++ .../pilot/harbin-institute-of-technology.json | 11 ++ .../pilot/nanjing-university.json | 11 ++ .../pilot/peking-university.json | 14 ++ .../pilot/shanghai-jiao-tong-university.json | 11 ++ .../pilot/sun-yat-sen-university.json | 12 ++ .../pilot/tsinghua-university.json | 16 +++ content/source-manifests/pilot/ustc.json | 13 ++ .../pilot/wuhan-university.json | 7 + .../pilot/zhejiang-university.json | 13 ++ .../ingestion/build-source-manifest-cohort.ts | 3 + .../sync-source-manifest-bindings.ts | 76 +++++++++++ scripts/source-manifest-contract.ts | 124 +++++++++++++++++- scripts/source-manifest-registry.ts | 12 ++ tests/unit/source-manifests.test.ts | 59 +++++++++ 15 files changed, 393 insertions(+), 1 deletion(-) create mode 100644 scripts/ingestion/sync-source-manifest-bindings.ts diff --git a/content/source-manifests/pilot/fudan-university.json b/content/source-manifests/pilot/fudan-university.json index 881c855..7856098 100644 --- a/content/source-manifests/pilot/fudan-university.json +++ b/content/source-manifests/pilot/fudan-university.json @@ -5,6 +5,18 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["iso.fudan.edu.cn","istudent.fudan.edu.cn"], + "sourceBindings": [ + {"sourceId":"fudan-intl-admissions-home","purpose":"discovery","resourceKey":"resource:5104c08f3939209a00f465b31eb8e58bf2c9777123ff74418f294907b3ca31a6"}, + {"sourceId":"fudan-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:d15909bce77e3dd89cc61a9b5e4273fe77674c7442a65d269af0bc7a0b1089aa"}, + {"sourceId":"fudan-masters-catalog","purpose":"entity_index","resourceKey":"resource:7f05269a50e2b48fc730764bab37bcc966e088c00c055bdcf6bfccf5a8469cf7"}, + {"sourceId":"fudan-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:7f05269a50e2b48fc730764bab37bcc966e088c00c055bdcf6bfccf5a8469cf7"}, + {"sourceId":"fudan-non-degree-catalog","purpose":"entity_index","resourceKey":"resource:83cd3f9035af430d9de7141efb03ebe60e9ef16cd3537fdde23fd62e12f49962"}, + {"sourceId":"fudan-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:2ddc0ac62d5fdf84dcaf786a086dbb0c9958f75d838352616927c5554448750b"}, + {"sourceId":"fudan-application-portal","purpose":"application_endpoint","resourceKey":"resource:cdbb6e1afdc88a9adb0b3b818fa5c676d1a84e148b53c5eadc489030ef05126a"}, + {"sourceId":"fudan-university-scholarship-index","purpose":"entity_index","resourceKey":"resource:e3f2b2e9a3909fc5bf6de58fa175c452c655603f57cd109abba6f13bbdf295fe"}, + {"sourceId":"fudan-government-scholarship-index","purpose":"entity_index","resourceKey":"resource:f65f13d8834993039b3e8f2dcc759d8f33bfdab6ee4382b755455fb8153252ec"}, + {"sourceId":"fudan-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:5104c08f3939209a00f465b31eb8e58bf2c9777123ff74418f294907b3ca31a6"} + ], "sources": [ { "version": 1, "id": "fudan-intl-admissions-home", "institutionId": "uni-fudan-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/harbin-institute-of-technology.json b/content/source-manifests/pilot/harbin-institute-of-technology.json index 7809011..bb01385 100644 --- a/content/source-manifests/pilot/harbin-institute-of-technology.json +++ b/content/source-manifests/pilot/harbin-institute-of-technology.json @@ -5,6 +5,17 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["hit.at0086.cn","studyathit.hit.edu.cn"], + "sourceBindings": [ + {"sourceId":"hit-intl-admissions-home","purpose":"discovery","resourceKey":"resource:4f527beffda183b5ddeec6c4fed6a28dc05560835db23570dcd919e0ecf56878"}, + {"sourceId":"hit-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:80630dd461183aa717ffb882155263aa9eabf15bc9fb882d8099d2744e61d28d"}, + {"sourceId":"hit-masters-catalog","purpose":"entity_index","resourceKey":"resource:f74f3a0bb65321790408ce867fbbf219e46e1644000e35da95ab0d78a722c2c7"}, + {"sourceId":"hit-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:6396f3e75d0e7201ee1a3263b568fe11a62a8cc207cc917e6ae7e0de15448035"}, + {"sourceId":"hit-non-degree-catalog","purpose":"entity_index","resourceKey":"resource:ab49892abd42b9ee5fe2f24a7392f9c6fb09d22173a50e5475bd3ccc01ab36a7"}, + {"sourceId":"hit-application-portal","purpose":"application_endpoint","resourceKey":"resource:18cf253f230d6264c8dabd1b5b77a3a5ade6632be3fc4ffad43798a58307105f"}, + {"sourceId":"hit-university-scholarship-index","purpose":"entity_index","resourceKey":"resource:9a3d4a1454c778881e10648e3ad10abbe6fff06b78479ca7717ccb2ee65961ee"}, + {"sourceId":"hit-government-scholarship-index","purpose":"entity_index","resourceKey":"resource:c782e669e3f68b02b79ca28051b7305e786501ca87ccdfa2d5dd76b43dc867f6"}, + {"sourceId":"hit-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:4f527beffda183b5ddeec6c4fed6a28dc05560835db23570dcd919e0ecf56878"} + ], "sources": [ { "version": 1, "id": "hit-intl-admissions-home", "institutionId": "uni-harbin-institute-of-technology", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/nanjing-university.json b/content/source-manifests/pilot/nanjing-university.json index 0826680..75047d7 100644 --- a/content/source-manifests/pilot/nanjing-university.json +++ b/content/source-manifests/pilot/nanjing-university.json @@ -5,6 +5,17 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["hwxy.nju.edu.cn","nju.17gz.org"], + "sourceBindings": [ + {"sourceId":"nju-intl-admissions-home","purpose":"discovery","resourceKey":"resource:b6e81557c096975e9c7e42bbbccbd03fd1f7e83e93d581355247459d4b97255e"}, + {"sourceId":"nju-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:e63633625f864e715dd1d243da5dd96d0c91aef2ca1537444a7ee947c8b03779"}, + {"sourceId":"nju-masters-catalog","purpose":"entity_index","resourceKey":"resource:0089d2b1fd782989cc4680b8d70ae31c93388ae35aff5735c98aa82b57f7cba6"}, + {"sourceId":"nju-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:2a381f3db40e224c125191cf5bdc00a632102ee369b19cafd88f1f73610a6f6d"}, + {"sourceId":"nju-official-tuition","purpose":"fact_sheet","resourceKey":"resource:2bbfc503c9aa0ba962d8e1ed4bef03f99c0215e6339b28014759b9408c0472c6"}, + {"sourceId":"nju-application-portal","purpose":"application_endpoint","resourceKey":"resource:a3ad673bda486fc1d9a53e093882d14f64fc95c3d95c25dc70392c665324f905"}, + {"sourceId":"nju-university-scholarship","purpose":"entity_detail","resourceKey":"resource:49595d763f78f2e402ea4f22c8d9eb6d85bc0f9d9a0372f4ffaafae75dd29f0a"}, + {"sourceId":"nju-2026-chinese-government-scholarship","purpose":"entity_detail","resourceKey":"resource:dcce784eef5ce1a97eeb93c74af000d108e973f2cc774d93bf6fc553749a7c72"}, + {"sourceId":"nju-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:b6e81557c096975e9c7e42bbbccbd03fd1f7e83e93d581355247459d4b97255e"} + ], "sources": [ { "version": 1, "id": "nju-intl-admissions-home", "institutionId": "uni-nanjing-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/peking-university.json b/content/source-manifests/pilot/peking-university.json index f799964..070672e 100644 --- a/content/source-manifests/pilot/peking-university.json +++ b/content/source-manifests/pilot/peking-university.json @@ -5,6 +5,20 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["isd.pku.edu.cn","www.isd.pku.edu.cn","www.studyatpku.com"], + "sourceBindings": [ + {"sourceId":"pku-intl-admissions-home","purpose":"discovery","resourceKey":"resource:d28c9eca73a147e62470163b3ee78340e0db70f71a9ae81c6472cd9302285eac"}, + {"sourceId":"pku-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:547ae78b5c311c5d6fd73ab51eb15b60c9219015b7fcb8abdf4547429f2cbdad"}, + {"sourceId":"pku-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:aa779495e4e212162637df9bac91f768379b7f07a722d61cef65da751619dad9"}, + {"sourceId":"pku-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:aa779495e4e212162637df9bac91f768379b7f07a722d61cef65da751619dad9"}, + {"sourceId":"pku-non-degree-downloads","purpose":"entity_index","resourceKey":"resource:ff93562f15613925181652508059cca52fc97f4418e19fb137c0d8777840aa1f"}, + {"sourceId":"pku-2026-graduate-guide","purpose":"fact_sheet","resourceKey":"resource:aa779495e4e212162637df9bac91f768379b7f07a722d61cef65da751619dad9"}, + {"sourceId":"pku-2026-graduate-fees","purpose":"fact_sheet","resourceKey":"resource:6c4c484213ce13e682f77692958d78e9d4c51aa18fda8e658f8664953bdd6560"}, + {"sourceId":"pku-application-portal","purpose":"application_endpoint","resourceKey":"resource:57b2f3d41cb7ee5435270cd31ab73a42e8e3498032541bf93a73bed53298b898"}, + {"sourceId":"pku-2026-university-scholarships","purpose":"entity_detail","resourceKey":"resource:ae668f4047b064ad6dc11faae2546a6583d8141a6a2bc0165f5607a28280bdb2"}, + {"sourceId":"pku-2026-government-scholarships","purpose":"entity_detail","resourceKey":"resource:ae668f4047b064ad6dc11faae2546a6583d8141a6a2bc0165f5607a28280bdb2"}, + {"sourceId":"pku-admissions-contacts","purpose":"fact_sheet","resourceKey":"resource:355bacac6a613e76ad252217b6634e4e7bc4f5f6eac275410a3d1c2ba5c01315"}, + {"sourceId":"pku-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:422550177e222eda47c3c98ae19da623ca8fac4afadc73dc353cc320cb0607b9"} + ], "sources": [ { "version": 1, "id": "pku-intl-admissions-home", "institutionId": "uni-peking-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/shanghai-jiao-tong-university.json b/content/source-manifests/pilot/shanghai-jiao-tong-university.json index 1ab9332..1154ebe 100644 --- a/content/source-manifests/pilot/shanghai-jiao-tong-university.json +++ b/content/source-manifests/pilot/shanghai-jiao-tong-university.json @@ -5,6 +5,17 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["apply.sjtu.edu.cn","isc.sjtu.edu.cn"], + "sourceBindings": [ + {"sourceId":"sjtu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:fa14388f2690a70111e1cfdefb4fac2c551232bd6632be7d4b0e2b18b42872d6"}, + {"sourceId":"sjtu-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:b9e8f8b5edd4ba9be7ea63cf8470586dde53d093b420f0844f0fd33d0eeb753c"}, + {"sourceId":"sjtu-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:ecd26ba40b12df2ddfcc1bcb290ccddc8670bb0655b09196a4fdf01b1237d06b"}, + {"sourceId":"sjtu-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:ecd26ba40b12df2ddfcc1bcb290ccddc8670bb0655b09196a4fdf01b1237d06b"}, + {"sourceId":"sjtu-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:ecd26ba40b12df2ddfcc1bcb290ccddc8670bb0655b09196a4fdf01b1237d06b"}, + {"sourceId":"sjtu-application-portal","purpose":"application_endpoint","resourceKey":"resource:dfa5a6f13325c7877e567fe62b28a036f30e9b6fd2aab7e273c15c83e0594d80"}, + {"sourceId":"sjtu-graduate-university-scholarships","purpose":"entity_index","resourceKey":"resource:419eb9863e1ea949cb4c95826740b84bebcb70dc0958f3108a3748b66e2380c7"}, + {"sourceId":"sjtu-shanghai-government-scholarship","purpose":"entity_index","resourceKey":"resource:871be5edf120e0c285b7e342341139c8212673aaab2e6551d47bf8172b1ba332"}, + {"sourceId":"sjtu-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:226e0556d4e7dc299dec97f59bff3d60dfd78b73690b349dc161ab29ac7d958f"} + ], "sources": [ { "version": 1, "id": "sjtu-intl-admissions-home", "institutionId": "uni-shanghai-jiao-tong-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/sun-yat-sen-university.json b/content/source-manifests/pilot/sun-yat-sen-university.json index d392286..0a150c8 100644 --- a/content/source-manifests/pilot/sun-yat-sen-university.json +++ b/content/source-manifests/pilot/sun-yat-sen-university.json @@ -5,6 +5,18 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["apply.sysu.edu.cn","iso.sysu.edu.cn"], + "sourceBindings": [ + {"sourceId":"sysu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:7eda8f54938a084ad427676b859f9ccd10562e101e4f190eabbf24ec6d076592"}, + {"sourceId":"sysu-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:3db37f6da7ebcb7bbef2c07fb988290b331b583574ec46ca0a9d006f44a757b9"}, + {"sourceId":"sysu-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:29e4d148a952baf7521cbe26eb025e72bce11d7d34a7b650bdb5c0b9aa3ee9b0"}, + {"sourceId":"sysu-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:674a0d712c3170ab245ad8e3fd1c80fe1306fe46ae980dd580bd09cba5429c7f"}, + {"sourceId":"sysu-2026-non-degree-program","purpose":"entity_index","resourceKey":"resource:37a51cad1848d1341fd42253e0abf19fa3c9defba76cd1dc3da4da5a788aebc2"}, + {"sourceId":"sysu-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:0725732d77da09422c2a20b85af37abf633ff84dddb9849a368cdf55303c9812"}, + {"sourceId":"sysu-application-portal","purpose":"application_endpoint","resourceKey":"resource:1a75af43fab2eaaf5809289ec9fa6fa8481715a1cd6ef5f561325db8ad5b4df9"}, + {"sourceId":"sysu-2026-university-scholarship","purpose":"entity_detail","resourceKey":"resource:6c8f95b6d2fb212dfdd2f901e436308e8d4e236e647175f9e6662c6f8e00fae3"}, + {"sourceId":"sysu-2026-government-scholarship","purpose":"entity_detail","resourceKey":"resource:53e855f5ab9633c5dcff10d89e60d7bd2d69da54456ccd9a2974db925ff65cca"}, + {"sourceId":"sysu-application-guide-anchor","purpose":"discovery","resourceKey":"resource:1ad167e7b39333fcaf2ec2bbfc80a12cd9aa508f8f54dd008751f22c97a88cb0"} + ], "sources": [ { "version": 1, "id": "sysu-intl-admissions-home", "institutionId": "uni-sun-yat-sen-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/tsinghua-university.json b/content/source-manifests/pilot/tsinghua-university.json index a9d15fb..085c8c9 100644 --- a/content/source-manifests/pilot/tsinghua-university.json +++ b/content/source-manifests/pilot/tsinghua-university.json @@ -5,6 +5,22 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["apply.join-tsinghua.edu.cn","international.join-tsinghua.edu.cn","yz.tsinghua.edu.cn","yzbm.tsinghua.edu.cn"], + "sourceBindings": [ + {"sourceId":"thu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:e872584236e4b1275368af09724801d29b8c97ad15e669bcf9e337744f58f749"}, + {"sourceId":"thu-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:d5624a838aba1a1b6b709191b57a76c0b334b031e837f43a48694c9e8ace7174"}, + {"sourceId":"thu-masters-catalog","purpose":"entity_index","resourceKey":"resource:312cc36bef11cd4261be74631c659505eb5353b7033b8117d31c10f5e2844203"}, + {"sourceId":"thu-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:c7348269581c8472e8029cc0c2503c5244f64dff85bbff62b708472a00dc076f"}, + {"sourceId":"thu-2026-graduate-guide","purpose":"fact_sheet","resourceKey":"resource:cd0554f261335e7e7602168bda5c8d095fa5097ce280d24c09dffabad49dcf72"}, + {"sourceId":"thu-2026-undergraduate-dates","purpose":"fact_sheet","resourceKey":"resource:48f8bd014e7feb3b6251e77e06c495635cb9b908a761ffb7da19f9b8f6eee4ef"}, + {"sourceId":"thu-undergraduate-fees","purpose":"fact_sheet","resourceKey":"resource:49b2313753b605dc0f72fde87b25fae8314d0b06687ca5c16d173c04c0bab518"}, + {"sourceId":"thu-undergraduate-eligibility-language","purpose":"fact_sheet","resourceKey":"resource:cd0df0ef10f6606f4d26405a3a0ac439968d5417eb39f0605e96382ce104c376"}, + {"sourceId":"thu-undergraduate-application-portal","purpose":"application_endpoint","resourceKey":"resource:2d9ef9ec2849320424c33d544c1eb5d331b75131997d720813592ad061994479"}, + {"sourceId":"thu-graduate-application-portal","purpose":"application_endpoint","resourceKey":"resource:c489ec057a5ecb623599c200ffcc90c7bd8aa239327266141926e66e42cf0161"}, + {"sourceId":"thu-freshmen-university-scholarships","purpose":"entity_index","resourceKey":"resource:1e64d0c21bdf1d66618d346d657ce11677307a5d05d3869b91191d2900790321"}, + {"sourceId":"thu-freshmen-government-scholarship","purpose":"entity_detail","resourceKey":"resource:1e64d0c21bdf1d66618d346d657ce11677307a5d05d3869b91191d2900790321"}, + {"sourceId":"thu-graduate-admissions-contacts","purpose":"fact_sheet","resourceKey":"resource:e6c604d1a51797d5693ac55b94663c09e37231b01d9c46c8e3f023bf2fdfcf4d"}, + {"sourceId":"thu-graduate-catalog-anchor","purpose":"discovery","resourceKey":"resource:14179ac278915ea779fe5d9fc5497c6f48388310e91b3ef5deecb8935bbf79c6"} + ], "sources": [ { "version": 1, diff --git a/content/source-manifests/pilot/ustc.json b/content/source-manifests/pilot/ustc.json index 307681a..e482dce 100644 --- a/content/source-manifests/pilot/ustc.json +++ b/content/source-manifests/pilot/ustc.json @@ -5,6 +5,19 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["ic.ustc.edu.cn","isa.ustc.edu.cn"], + "sourceBindings": [ + {"sourceId":"ustc-intl-admissions-home","purpose":"discovery","resourceKey":"resource:1e6351b56daddf5b763e0d349f1d18210caab0e85f22aa6fd7f60a8d0a38fb63"}, + {"sourceId":"ustc-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:f45400f49b315e1c317555829c4513430556fde3ec8a424adef696bc64972322"}, + {"sourceId":"ustc-masters-catalog","purpose":"entity_index","resourceKey":"resource:01ef6abe15f3f677c43bec33be20ff5589db95f72ad47cf27a7b36c2051f3c8e"}, + {"sourceId":"ustc-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:01ef6abe15f3f677c43bec33be20ff5589db95f72ad47cf27a7b36c2051f3c8e"}, + {"sourceId":"ustc-non-degree-summer-program","purpose":"entity_index","resourceKey":"resource:33262a140d40b7af767f5296e2ce2c921e3b2d9adfb9fb72b58edd972b2791f6"}, + {"sourceId":"ustc-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:3e645b82a8aa481b71f163cba3ff3b7f23d8579e39e25e3c2fa6e314b70add26"}, + {"sourceId":"ustc-application-portal","purpose":"application_endpoint","resourceKey":"resource:d71e3b89792da12c336b5d471561d672fe0322610bc71ce373b1c904b54ed490"}, + {"sourceId":"ustc-university-fellowship","purpose":"entity_index","resourceKey":"resource:9e7a42ddb4a9286de15e003743a85ec2bc669504e238fd1f07991c1dfd726b20"}, + {"sourceId":"ustc-government-scholarship","purpose":"entity_detail","resourceKey":"resource:881bb961435eaefcabe8078eaf6a0298cf0123602641a5fcb145148b7afd4296"}, + {"sourceId":"ustc-admissions-contacts","purpose":"fact_sheet","resourceKey":"resource:f29e0e97adf22290598c831992d11ceb6759c052990dac4fb8d0fd1f2dccd37c"}, + {"sourceId":"ustc-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:1e6351b56daddf5b763e0d349f1d18210caab0e85f22aa6fd7f60a8d0a38fb63"} + ], "sources": [ { "version": 1, "id": "ustc-intl-admissions-home", "institutionId": "uni-university-of-science-and-technology-of-china", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/wuhan-university.json b/content/source-manifests/pilot/wuhan-university.json index 02075a8..334365f 100644 --- a/content/source-manifests/pilot/wuhan-university.json +++ b/content/source-manifests/pilot/wuhan-university.json @@ -5,6 +5,13 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["admission.whu.edu.cn","en.whu.edu.cn"], + "sourceBindings": [ + {"sourceId":"whu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:d3a04b4704de79e57671b98345b4bda7843049cf1d0d8a43ea878387791b36e2"}, + {"sourceId":"whu-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:d8668b1e250353a53beef776e7abe903e9a4b53980feae5f5b26899cffb6b869"}, + {"sourceId":"whu-application-portal","purpose":"application_endpoint","resourceKey":"resource:de757f9f86bcff730e58cfc735e7e67e2fff240ac5f419b716fdbfa6e0b04546"}, + {"sourceId":"whu-admissions-contacts","purpose":"fact_sheet","resourceKey":"resource:54d277b41004a2636d7a7b6a4eacbb13ceb60f41c0c7b1d3f70e34feebbf3bed"}, + {"sourceId":"whu-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:c76845742ee591e73e2adac3b87242abde132a361eb22debcf76af664d0f4c85"} + ], "sources": [ { "version": 1, "id": "whu-intl-admissions-home", "institutionId": "uni-wuhan-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/content/source-manifests/pilot/zhejiang-university.json b/content/source-manifests/pilot/zhejiang-university.json index d9ce5d6..d8bebdf 100644 --- a/content/source-manifests/pilot/zhejiang-university.json +++ b/content/source-manifests/pilot/zhejiang-university.json @@ -5,6 +5,19 @@ "manifestStatus": "in_progress", "checkedAt": "2026-07-20", "officialHosts": ["iczu.zju.edu.cn","intlstudent.zju.edu.cn"], + "sourceBindings": [ + {"sourceId":"zju-intl-admissions-home","purpose":"discovery","resourceKey":"resource:3da6e2a4c3c47dd8ee8a3a27ad94a7ec0280031b76bb391746b0ed075e616e12"}, + {"sourceId":"zju-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:c420ac4489fd9e2fba623ec9f3b923dcf5940a26913fb774f1ff1df0987152cd"}, + {"sourceId":"zju-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:a1f91cd9373d52d491d0621f7a6adebda4d997a077e8ef3ef0975cba816cdf05"}, + {"sourceId":"zju-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:2247fd8dcfa0f5b1064c859ef0e2e1cbf7ab7a714150c23313f6fcc6adc2a234"}, + {"sourceId":"zju-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:a1f91cd9373d52d491d0621f7a6adebda4d997a077e8ef3ef0975cba816cdf05"}, + {"sourceId":"zju-official-fees","purpose":"fact_sheet","resourceKey":"resource:805ee3189494db6af3082ab838f6ed396c243ce27150f7a180660a21654501b7"}, + {"sourceId":"zju-application-portal","purpose":"application_endpoint","resourceKey":"resource:b055e14054d1a1542129f87c82eeb0b252494e7f43049a42bac6241846059ee1"}, + {"sourceId":"zju-university-scholarship-index","purpose":"entity_index","resourceKey":"resource:e672f664fbd47088be1229a3d51c4f657dd642ed807d545a24597d73c17b7046"}, + {"sourceId":"zju-2026-zhejiang-government-scholarship","purpose":"entity_detail","resourceKey":"resource:4736726a019d516a54899e0e106d9bc1a8922f6fe65934abe8bd930f7857fcc5"}, + {"sourceId":"zju-admissions-contacts","purpose":"fact_sheet","resourceKey":"resource:2b1ee30104553c83679e227f698b4bfbace2a8a7b94c9dcd2de9eb1188614aac"}, + {"sourceId":"zju-application-guide-anchor","purpose":"discovery","resourceKey":"resource:a784ace1e20d4fd6511022d449ec9bb285258cf8b8c0d43952caaae1b808a8df"} + ], "sources": [ { "version": 1, "id": "zju-intl-admissions-home", "institutionId": "uni-zhejiang-university", "entityType": "university", "sourceCategory": "international_admissions_home", diff --git a/scripts/ingestion/build-source-manifest-cohort.ts b/scripts/ingestion/build-source-manifest-cohort.ts index 9ab4cb4..9ea9051 100644 --- a/scripts/ingestion/build-source-manifest-cohort.ts +++ b/scripts/ingestion/build-source-manifest-cohort.ts @@ -17,6 +17,7 @@ import type { SourceManifestV1, } from '../../workers/ingestion/src/types' import { + sourceBindingsForSources, sourceManifestV2Schema, type SourceManifestV2, } from '../source-manifest-registry' @@ -537,6 +538,7 @@ function buildReconciliationFallbackManifest( checkedAt, officialHosts: [...new Set(sources.flatMap((source) => source.allowedHosts))].sort(), sources, + sourceBindings: sourceBindingsForSources(sources), coverage, catalogReconciliation: { scope: 'limited_official_catalog', @@ -846,6 +848,7 @@ export function buildSourceManifestCohort( checkedAt: input.checkedAt, officialHosts: [...new Set(safeSources.map((source) => source.host))].sort(), sources: manifestSources, + sourceBindings: sourceBindingsForSources(manifestSources), coverage, catalogReconciliation: { scope: 'representative_international_programs', diff --git a/scripts/ingestion/sync-source-manifest-bindings.ts b/scripts/ingestion/sync-source-manifest-bindings.ts new file mode 100644 index 0000000..9d4baa0 --- /dev/null +++ b/scripts/ingestion/sync-source-manifest-bindings.ts @@ -0,0 +1,76 @@ +import { + lstatSync, + readFileSync, + readdirSync, + realpathSync, + writeFileSync, +} from 'node:fs' +import { resolve, sep } from 'node:path' + +import { sourceManifestSchema } from '../../workers/ingestion/src/manifest-schema' +import { sourceBindingsForSources } from '../source-manifest-contract' + +function jsonFiles(directory: string): string[] { + return readdirSync(directory, { withFileTypes: true }) + .flatMap((entry) => { + const path = resolve(directory, entry.name) + if (entry.isDirectory()) return jsonFiles(path) + if (!entry.isFile() || !entry.name.endsWith('.json')) return [] + if (/^targets(?:\.|-).*\.json$/i.test(entry.name)) return [] + return [path] + }) + .sort((left, right) => left.localeCompare(right, 'en')) +} + +function assertInsideRepository(path: string): void { + const repositoryRoot = realpathSync(process.cwd()) + const resolved = realpathSync(path) + if (resolved !== repositoryRoot && !resolved.startsWith(`${repositoryRoot}${sep}`)) { + throw new Error(`Source manifest directory is outside the repository: ${resolved}`) + } + if (!lstatSync(resolved).isDirectory()) { + throw new Error(`Source manifest path is not a directory: ${resolved}`) + } +} + +function synchronizeFile(filePath: string): 'updated' | 'unchanged' | 'skipped' { + const text = readFileSync(filePath, 'utf8') + const document = JSON.parse(text) as Record + if (document.version !== 2 || !Array.isArray(document.sources)) return 'skipped' + + const sources = document.sources.map((source) => sourceManifestSchema.parse(source)) + const expectedBindings = sourceBindingsForSources(sources) + if (document.sourceBindings !== undefined) { + if (JSON.stringify(document.sourceBindings) !== JSON.stringify(expectedBindings)) { + throw new Error(`Existing sourceBindings differ from the locked derivation: ${filePath}`) + } + return 'unchanged' + } + + const newline = text.includes('\r\n') ? '\r\n' : '\n' + const marker = /^ "officialHosts": [^\r\n]+,$/m + const match = text.match(marker) + if (!match) throw new Error(`Could not locate compact officialHosts field: ${filePath}`) + const bindingLines = [ + ' "sourceBindings": [', + ...expectedBindings.map((binding, index) => ( + ` ${JSON.stringify(binding)}${index === expectedBindings.length - 1 ? '' : ','}` + )), + ' ],', + ].join(newline) + const updated = text.replace(marker, `${match[0]}${newline}${bindingLines}`) + writeFileSync(filePath, updated, 'utf8') + return 'updated' +} + +const targetDirectory = resolve( + process.argv[2] ?? 'content/source-manifests/pilot', +) +assertInsideRepository(targetDirectory) + +const summary = { updated: 0, unchanged: 0, skipped: 0 } +for (const filePath of jsonFiles(targetDirectory)) { + summary[synchronizeFile(filePath)] += 1 +} + +console.log(JSON.stringify({ directory: targetDirectory, ...summary })) diff --git a/scripts/source-manifest-contract.ts b/scripts/source-manifest-contract.ts index 6347f8a..d65f6b2 100644 --- a/scripts/source-manifest-contract.ts +++ b/scripts/source-manifest-contract.ts @@ -1,9 +1,74 @@ +import { createHash } from 'node:crypto' import { z } from 'zod' import { SOURCE_CATEGORIES, sourceManifestSchema, } from '../workers/ingestion/src/manifest-schema' +import type { SourceManifestV1 } from '../workers/ingestion/src/types' + +export const SOURCE_PURPOSES = [ + 'discovery', + 'entity_index', + 'entity_detail', + 'fact_sheet', + 'application_endpoint', +] as const + +export type SourcePurpose = (typeof SOURCE_PURPOSES)[number] + +export type SourceBinding = { + sourceId: string + purpose: SourcePurpose + resourceKey: string +} + +export function normalizeSourceResourceUrl(value: string): string { + const url = new URL(value) + url.hash = '' + url.protocol = url.protocol.toLowerCase() + url.hostname = url.hostname.toLowerCase() + if (url.pathname !== '/') url.pathname = url.pathname.replace(/\/+$/, '') + return url.toString() +} + +export function sourceResourceKey(officialUrl: string): string { + const digest = createHash('sha256') + .update(normalizeSourceResourceUrl(officialUrl), 'utf8') + .digest('hex') + return `resource:${digest}` +} + +export function sourcePurposeFor(source: SourceManifestV1): SourcePurpose { + switch (source.sourceCategory) { + case 'international_admissions_home': + case 'catalog_anchor': + return 'discovery' + case 'application_portal': + return 'application_endpoint' + case 'undergraduate_catalog': + case 'masters_catalog': + case 'doctoral_catalog': + case 'non_degree_catalog': + return 'entity_index' + case 'university_scholarship': + case 'faculty_scholarship': + case 'government_scholarship': + return source.entityType === 'scholarship-cycle' ? 'entity_detail' : 'entity_index' + case 'program_detail': + return 'entity_detail' + default: + return 'fact_sheet' + } +} + +export function sourceBindingsForSources(sources: SourceManifestV1[]): SourceBinding[] { + return sources.map((source) => ({ + sourceId: source.id, + purpose: sourcePurposeFor(source), + resourceKey: sourceResourceKey(source.officialUrl), + })) +} export const CATALOG_RECONCILIATION_STATUSES = [ 'published', @@ -79,6 +144,12 @@ const catalogReconciliationSchema = z.object({ } }) +const sourceBindingSchema = z.object({ + sourceId: z.string().min(1), + purpose: z.enum(SOURCE_PURPOSES), + resourceKey: z.string().regex(/^resource:[0-9a-f]{64}$/), +}).strict() + export const sourceManifestV2Schema = z.object({ version: z.literal(2), institutionId: z.string().min(1), @@ -89,9 +160,60 @@ export const sourceManifestV2Schema = z.object({ // Fetch workers still consume the strict V1 source contract. V2 is the // institution-level trust envelope around those source manifests. sources: z.array(sourceManifestSchema).min(1), + sourceBindings: z.array(sourceBindingSchema).min(1), coverage: z.array(coverageSchema).length(SOURCE_CATEGORIES.length), catalogReconciliation: catalogReconciliationSchema, -}).strict() +}).strict().superRefine((manifest, context) => { + const sources = new Map(manifest.sources.map((source) => [source.id, source])) + const seen = new Set() + + for (const [index, binding] of manifest.sourceBindings.entries()) { + if (seen.has(binding.sourceId)) { + context.addIssue({ + code: 'custom', + path: ['sourceBindings', index, 'sourceId'], + message: `duplicate source binding: ${binding.sourceId}`, + }) + continue + } + seen.add(binding.sourceId) + const source = sources.get(binding.sourceId) + if (!source) { + context.addIssue({ + code: 'custom', + path: ['sourceBindings', index, 'sourceId'], + message: `source binding references unknown source: ${binding.sourceId}`, + }) + continue + } + const expectedPurpose = sourcePurposeFor(source) + if (binding.purpose !== expectedPurpose) { + context.addIssue({ + code: 'custom', + path: ['sourceBindings', index, 'purpose'], + message: `source binding purpose must be ${expectedPurpose} for ${binding.sourceId}`, + }) + } + const expectedResourceKey = sourceResourceKey(source.officialUrl) + if (binding.resourceKey !== expectedResourceKey) { + context.addIssue({ + code: 'custom', + path: ['sourceBindings', index, 'resourceKey'], + message: `source binding resourceKey does not match officialUrl for ${binding.sourceId}`, + }) + } + } + + for (const source of manifest.sources) { + if (!seen.has(source.id)) { + context.addIssue({ + code: 'custom', + path: ['sourceBindings'], + message: `source binding is missing for ${source.id}`, + }) + } + } +}) export type SourceManifestV2 = z.infer export type SourceManifestRecord = PilotSourceManifest | SourceManifestV2 diff --git a/scripts/source-manifest-registry.ts b/scripts/source-manifest-registry.ts index 874fa55..4159736 100644 --- a/scripts/source-manifest-registry.ts +++ b/scripts/source-manifest-registry.ts @@ -15,20 +15,32 @@ import { import { CATALOG_RECONCILIATION_STATUSES, pilotSourceManifestSchema, + sourceBindingsForSources, sourceManifestV2Schema, + sourcePurposeFor, + sourceResourceKey, + SOURCE_PURPOSES, type CatalogReconciliationStatus, + type SourceBinding, type SourceManifestRecord, type SourceManifestV2, + type SourcePurpose, } from './source-manifest-contract' export { CATALOG_RECONCILIATION_STATUSES, + SOURCE_PURPOSES, + sourceBindingsForSources, sourceManifestV2Schema, + sourcePurposeFor, + sourceResourceKey, } export type { CatalogReconciliationStatus, + SourceBinding, SourceManifestRecord, SourceManifestV2, + SourcePurpose, } export type LoadedSourceManifest = { diff --git a/tests/unit/source-manifests.test.ts b/tests/unit/source-manifests.test.ts index adce05a..899eecf 100644 --- a/tests/unit/source-manifests.test.ts +++ b/tests/unit/source-manifests.test.ts @@ -4,6 +4,8 @@ import { describe, expect, it } from 'vitest' import { isCatalogReconciliationComplete, loadSourceManifestFiles, + SOURCE_PURPOSES, + sourceResourceKey, validateSourceManifests, type LoadedSourceManifest, type SourceManifestV2, @@ -104,11 +106,67 @@ describe('pilot source manifests', () => { expect(new Set(ids).size).toBe(ids.length) }) + it('maps every source to a locked purpose and shared official resource key', () => { + const records = validateSourceManifests(clonedInputs()) + const purposeCounts = Object.fromEntries( + SOURCE_PURPOSES.map((purpose) => [purpose, 0]), + ) as Record<(typeof SOURCE_PURPOSES)[number], number> + const sourcesByResource = new Map() + + for (const record of records) { + expect(record.version).toBe(2) + if (record.version !== 2) throw new Error('Expected a V2 pilot manifest') + expect(record.sourceBindings).toHaveLength(record.sources.length) + expect(new Set(record.sourceBindings.map((binding) => binding.sourceId)).size) + .toBe(record.sources.length) + for (const binding of record.sourceBindings) { + purposeCounts[binding.purpose] += 1 + expect(binding.resourceKey).toMatch(/^resource:[0-9a-f]{64}$/) + const sourceIds = sourcesByResource.get(binding.resourceKey) ?? [] + sourceIds.push(binding.sourceId) + sourcesByResource.set(binding.resourceKey, sourceIds) + } + } + + expect(purposeCounts).toEqual({ + discovery: 20, + entity_index: 42, + entity_detail: 9, + fact_sheet: 18, + application_endpoint: 11, + }) + expect( + [...sourcesByResource.values()] + .filter((sourceIds) => sourceIds.length > 1) + .map((sourceIds) => sourceIds.length) + .sort((left, right) => left - right), + ).toEqual([2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3]) + }) + + it('rejects missing, mismatched, or forged source bindings', () => { + const missing = clonedInputs() + recordOf(missing[0]!).sourceBindings.pop() + expect(() => validateSourceManifests(missing)).toThrow(/source binding is missing/) + + const mismatched = clonedInputs() + recordOf(mismatched[0]!).sourceBindings[0]!.purpose = 'fact_sheet' + expect(() => validateSourceManifests(mismatched)).toThrow(/source binding purpose must be/) + + const forged = clonedInputs() + recordOf(forged[0]!).sourceBindings[0]!.resourceKey = `resource:${'0'.repeat(64)}` + expect(() => validateSourceManifests(forged)).toThrow( + /source binding resourceKey does not match officialUrl/, + ) + }) + it('rejects an official URL and allowlist moved to an unapproved host', () => { const inputs = clonedInputs() const record = recordOf(inputs[0]!) record.sources[0]!.officialUrl = 'https://attacker.example/admissions' record.sources[0]!.allowedHosts = ['attacker.example'] + record.sourceBindings[0]!.resourceKey = sourceResourceKey( + record.sources[0]!.officialUrl, + ) expect(() => validateSourceManifests(inputs)).toThrow( /uses undeclared official host attacker\.example/, @@ -120,6 +178,7 @@ describe('pilot source manifests', () => { const first = recordOf(inputs[0]!) const second = recordOf(inputs[1]!) second.sources[0]!.id = first.sources[0]!.id + second.sourceBindings[0]!.sourceId = first.sources[0]!.id expect(() => validateSourceManifests(inputs)).toThrow( /duplicate source id/, From 5dbcdfaa0fc1788867aaf4f81cdfc978b60b7d03 Mon Sep 17 00:00:00 2001 From: Henrythefoodie <13022037121@163.com> Date: Sun, 30 Aug 2026 09:15:45 +0800 Subject: [PATCH 3/4] fix(data): preserve official resource URL semantics --- .../pilot/fudan-university.json | 6 ++--- .../pilot/peking-university.json | 2 +- .../pilot/shanghai-jiao-tong-university.json | 2 +- .../pilot/zhejiang-university.json | 2 +- scripts/source-manifest-contract.ts | 5 ++-- tests/unit/source-manifests.test.ts | 23 +++++++++++++++++++ 6 files changed, 31 insertions(+), 9 deletions(-) diff --git a/content/source-manifests/pilot/fudan-university.json b/content/source-manifests/pilot/fudan-university.json index 7856098..b660fd3 100644 --- a/content/source-manifests/pilot/fudan-university.json +++ b/content/source-manifests/pilot/fudan-university.json @@ -6,16 +6,16 @@ "checkedAt": "2026-07-20", "officialHosts": ["iso.fudan.edu.cn","istudent.fudan.edu.cn"], "sourceBindings": [ - {"sourceId":"fudan-intl-admissions-home","purpose":"discovery","resourceKey":"resource:5104c08f3939209a00f465b31eb8e58bf2c9777123ff74418f294907b3ca31a6"}, + {"sourceId":"fudan-intl-admissions-home","purpose":"discovery","resourceKey":"resource:697dd47b825698da54d9434464a8345440536d6da2dc2bf6612d36668ad80a3e"}, {"sourceId":"fudan-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:d15909bce77e3dd89cc61a9b5e4273fe77674c7442a65d269af0bc7a0b1089aa"}, {"sourceId":"fudan-masters-catalog","purpose":"entity_index","resourceKey":"resource:7f05269a50e2b48fc730764bab37bcc966e088c00c055bdcf6bfccf5a8469cf7"}, {"sourceId":"fudan-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:7f05269a50e2b48fc730764bab37bcc966e088c00c055bdcf6bfccf5a8469cf7"}, {"sourceId":"fudan-non-degree-catalog","purpose":"entity_index","resourceKey":"resource:83cd3f9035af430d9de7141efb03ebe60e9ef16cd3537fdde23fd62e12f49962"}, {"sourceId":"fudan-2026-current-guide","purpose":"fact_sheet","resourceKey":"resource:2ddc0ac62d5fdf84dcaf786a086dbb0c9958f75d838352616927c5554448750b"}, - {"sourceId":"fudan-application-portal","purpose":"application_endpoint","resourceKey":"resource:cdbb6e1afdc88a9adb0b3b818fa5c676d1a84e148b53c5eadc489030ef05126a"}, + {"sourceId":"fudan-application-portal","purpose":"application_endpoint","resourceKey":"resource:7b3f66e0c297fec42ae5104f8dc13891c4ace36fa035778eb7c2239c17b8df15"}, {"sourceId":"fudan-university-scholarship-index","purpose":"entity_index","resourceKey":"resource:e3f2b2e9a3909fc5bf6de58fa175c452c655603f57cd109abba6f13bbdf295fe"}, {"sourceId":"fudan-government-scholarship-index","purpose":"entity_index","resourceKey":"resource:f65f13d8834993039b3e8f2dcc759d8f33bfdab6ee4382b755455fb8153252ec"}, - {"sourceId":"fudan-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:5104c08f3939209a00f465b31eb8e58bf2c9777123ff74418f294907b3ca31a6"} + {"sourceId":"fudan-admissions-catalog-anchor","purpose":"discovery","resourceKey":"resource:697dd47b825698da54d9434464a8345440536d6da2dc2bf6612d36668ad80a3e"} ], "sources": [ { diff --git a/content/source-manifests/pilot/peking-university.json b/content/source-manifests/pilot/peking-university.json index 070672e..d923e86 100644 --- a/content/source-manifests/pilot/peking-university.json +++ b/content/source-manifests/pilot/peking-university.json @@ -6,7 +6,7 @@ "checkedAt": "2026-07-20", "officialHosts": ["isd.pku.edu.cn","www.isd.pku.edu.cn","www.studyatpku.com"], "sourceBindings": [ - {"sourceId":"pku-intl-admissions-home","purpose":"discovery","resourceKey":"resource:d28c9eca73a147e62470163b3ee78340e0db70f71a9ae81c6472cd9302285eac"}, + {"sourceId":"pku-intl-admissions-home","purpose":"discovery","resourceKey":"resource:46eec5776405abb252eb1c2a4a6dcf6a21b2d8b4ed247b08803b50fe6ffe1303"}, {"sourceId":"pku-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:547ae78b5c311c5d6fd73ab51eb15b60c9219015b7fcb8abdf4547429f2cbdad"}, {"sourceId":"pku-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:aa779495e4e212162637df9bac91f768379b7f07a722d61cef65da751619dad9"}, {"sourceId":"pku-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:aa779495e4e212162637df9bac91f768379b7f07a722d61cef65da751619dad9"}, diff --git a/content/source-manifests/pilot/shanghai-jiao-tong-university.json b/content/source-manifests/pilot/shanghai-jiao-tong-university.json index 1154ebe..0a99f81 100644 --- a/content/source-manifests/pilot/shanghai-jiao-tong-university.json +++ b/content/source-manifests/pilot/shanghai-jiao-tong-university.json @@ -6,7 +6,7 @@ "checkedAt": "2026-07-20", "officialHosts": ["apply.sjtu.edu.cn","isc.sjtu.edu.cn"], "sourceBindings": [ - {"sourceId":"sjtu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:fa14388f2690a70111e1cfdefb4fac2c551232bd6632be7d4b0e2b18b42872d6"}, + {"sourceId":"sjtu-intl-admissions-home","purpose":"discovery","resourceKey":"resource:2f73b4a857aa1819e3c881ff8bf06aaa812850575c9f85c834f8a0d0bc8e8c20"}, {"sourceId":"sjtu-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:b9e8f8b5edd4ba9be7ea63cf8470586dde53d093b420f0844f0fd33d0eeb753c"}, {"sourceId":"sjtu-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:ecd26ba40b12df2ddfcc1bcb290ccddc8670bb0655b09196a4fdf01b1237d06b"}, {"sourceId":"sjtu-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:ecd26ba40b12df2ddfcc1bcb290ccddc8670bb0655b09196a4fdf01b1237d06b"}, diff --git a/content/source-manifests/pilot/zhejiang-university.json b/content/source-manifests/pilot/zhejiang-university.json index d8bebdf..e1ba152 100644 --- a/content/source-manifests/pilot/zhejiang-university.json +++ b/content/source-manifests/pilot/zhejiang-university.json @@ -6,7 +6,7 @@ "checkedAt": "2026-07-20", "officialHosts": ["iczu.zju.edu.cn","intlstudent.zju.edu.cn"], "sourceBindings": [ - {"sourceId":"zju-intl-admissions-home","purpose":"discovery","resourceKey":"resource:3da6e2a4c3c47dd8ee8a3a27ad94a7ec0280031b76bb391746b0ed075e616e12"}, + {"sourceId":"zju-intl-admissions-home","purpose":"discovery","resourceKey":"resource:7401c9501715ab530ef88823e0d96b86c2d54d7921b14c90af2eb7f0f245251b"}, {"sourceId":"zju-2026-undergraduate-catalog","purpose":"entity_index","resourceKey":"resource:c420ac4489fd9e2fba623ec9f3b923dcf5940a26913fb774f1ff1df0987152cd"}, {"sourceId":"zju-2026-masters-catalog","purpose":"entity_index","resourceKey":"resource:a1f91cd9373d52d491d0621f7a6adebda4d997a077e8ef3ef0975cba816cdf05"}, {"sourceId":"zju-2026-doctoral-catalog","purpose":"entity_index","resourceKey":"resource:2247fd8dcfa0f5b1064c859ef0e2e1cbf7ab7a714150c23313f6fcc6adc2a234"}, diff --git a/scripts/source-manifest-contract.ts b/scripts/source-manifest-contract.ts index d65f6b2..dba5ad5 100644 --- a/scripts/source-manifest-contract.ts +++ b/scripts/source-manifest-contract.ts @@ -26,9 +26,8 @@ export type SourceBinding = { export function normalizeSourceResourceUrl(value: string): string { const url = new URL(value) url.hash = '' - url.protocol = url.protocol.toLowerCase() - url.hostname = url.hostname.toLowerCase() - if (url.pathname !== '/') url.pathname = url.pathname.replace(/\/+$/, '') + // Keep the request path and query intact: a trailing slash or query order can + // identify a different official resource. URL already normalizes host/port. return url.toString() } diff --git a/tests/unit/source-manifests.test.ts b/tests/unit/source-manifests.test.ts index 899eecf..b7c4a8d 100644 --- a/tests/unit/source-manifests.test.ts +++ b/tests/unit/source-manifests.test.ts @@ -143,6 +143,29 @@ describe('pilot source manifests', () => { ).toEqual([2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3]) }) + it('preserves distinct request paths and query strings in resource keys', () => { + expect(sourceResourceKey('https://example.edu/catalog')).not.toBe( + sourceResourceKey('https://example.edu/catalog/'), + ) + expect(sourceResourceKey('https://example.edu/catalog?level=masters&lang=en')) + .not.toBe(sourceResourceKey('https://example.edu/catalog?lang=en&level=masters')) + expect(sourceResourceKey('https://example.edu/catalog?year=2026')).not.toBe( + sourceResourceKey('https://example.edu/catalog?year=2027'), + ) + expect(sourceResourceKey('https://example.edu/catalog?name=Chinese')).not.toBe( + sourceResourceKey('https://example.edu/catalog?name=chinese'), + ) + }) + + it('ignores fragments and uses standard host and default-port normalization', () => { + expect(sourceResourceKey('https://example.edu/catalog?year=2026#masters')).toBe( + sourceResourceKey('https://example.edu/catalog?year=2026#doctoral'), + ) + expect(sourceResourceKey('https://EXAMPLE.edu:443/catalog?year=2026')).toBe( + sourceResourceKey('https://example.edu/catalog?year=2026'), + ) + }) + it('rejects missing, mismatched, or forged source bindings', () => { const missing = clonedInputs() recordOf(missing[0]!).sourceBindings.pop() From 58d2b3f106a3592bb93b7fe60c1dfd3e0d07bb04 Mon Sep 17 00:00:00 2001 From: Henrythefoodie <13022037121@163.com> Date: Sun, 30 Aug 2026 09:21:01 +0800 Subject: [PATCH 4/4] fix(data): expire overdue verification states for August 30 --- content/data/admission-cycles.json | 2 +- content/data/programs.json | 458 ++++++++++++++--------------- content/data/scholarships.json | 172 +++++------ content/data/universities.json | 14 +- 4 files changed, 323 insertions(+), 323 deletions(-) diff --git a/content/data/admission-cycles.json b/content/data/admission-cycles.json index 28ea232..66afce1 100644 --- a/content/data/admission-cycles.json +++ b/content/data/admission-cycles.json @@ -19698,7 +19698,7 @@ ], "verifiedAt": "2026-08-26", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "cycle-thu-visiting-student-spring-2027", diff --git a/content/data/programs.json b/content/data/programs.json index ff3cf01..8edf72b 100644 --- a/content/data/programs.json +++ b/content/data/programs.json @@ -83,7 +83,7 @@ ], "verifiedAt": "2026-08-26", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "durationMonthsMax": null, "details": { "faculty": { @@ -13793,7 +13793,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-ahmu-d-clinical-pharmacy", @@ -13817,7 +13817,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecs-ahmu-epidemiology-master", @@ -14071,7 +14071,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-bjfu-international-economics-trade-bachelor", @@ -14097,7 +14097,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-bjfu-landscape-architecture-bachelor", @@ -14123,7 +14123,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-bipt-biological-pharmacy-bachelor", @@ -14175,7 +14175,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-bipt-chinese-language-program", @@ -15273,7 +15273,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave6-cueb-chinese-language", @@ -15431,7 +15431,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-cafa-art-theory-doctorate", @@ -15505,7 +15505,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-csw-ccnu-chinese-literature-icl-bachelor", @@ -15766,7 +15766,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-cust-m-mba-en", @@ -15792,7 +15792,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-cust-b-software-engineering-en", @@ -15819,7 +15819,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-csust-architecture-master", @@ -16111,7 +16111,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-cdut-b-mechanical-engineering", @@ -16137,7 +16137,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-cdut-b-resource-exploration-engineering", @@ -16163,7 +16163,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-cdutcm-acupuncture-tuina-master", @@ -16241,7 +16241,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-cdutcm-nursing-master", @@ -16527,7 +16527,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave6-cjlu-electronic-information-engineering-bachelor", @@ -16685,7 +16685,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-cugb-environmental-science-engineering-doctorate-english", @@ -16712,7 +16712,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-cugb-geology-master", @@ -16739,7 +16739,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-cugb-geology-bachelor", @@ -16766,7 +16766,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-cugb-geology-master-english", @@ -16793,7 +16793,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecs-cumt-electrical-engineering-master", @@ -16955,7 +16955,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave5-depth-cumtb-mining-engineering-bachelor", @@ -17278,7 +17278,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-cqmu-b-medical-imaging", @@ -17304,7 +17304,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-cqmu-b-rehabilitation-science", @@ -17330,7 +17330,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-cqmu-b-stomatology", @@ -17356,7 +17356,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-cqnu-language-chinese", @@ -17382,7 +17382,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-ctbu-d-big-data-statistics-intelligent-computing", @@ -17408,7 +17408,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-ctbu-m-business-administration-en", @@ -17434,7 +17434,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-ctbu-d-digital-economy", @@ -17461,7 +17461,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-ctbu-b-international-economics-and-trade", @@ -17487,7 +17487,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-cqupt-computer-science-technology-doctorate", @@ -17617,7 +17617,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-cqupt-management-science-engineering-master", @@ -17930,7 +17930,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dmu-b-mbbs", @@ -17955,7 +17955,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dmu-pre-medical", @@ -17980,7 +17980,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dmu-b-stomatology", @@ -18004,7 +18004,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dlufl-b-chinese-culture", @@ -18030,7 +18030,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dlufl-b-chinese-international-trade", @@ -18056,7 +18056,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dlufl-b-tcsol", @@ -18082,7 +18082,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-nss-dut-international-chinese-education-master", @@ -18216,7 +18216,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dufe-m-international-trade-en", @@ -18244,7 +18244,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-dufe-m-tourism-management-en", @@ -18272,7 +18272,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-dgut-food-and-nutrition-master", @@ -18350,7 +18350,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-dgut-social-work-master", @@ -18403,7 +18403,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-chinese-degree-ecnu-business-chinese-bachelor", @@ -18873,7 +18873,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-fjmu-mbbs-english-bachelor", @@ -18899,7 +18899,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecma-fjmu-pharmacology-master", @@ -19136,7 +19136,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gdmu-clinical-medicine-bachelor", @@ -19162,7 +19162,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gdmu-pharmacy-bachelor", @@ -19188,7 +19188,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gdmu-stomatology-bachelor", @@ -19214,7 +19214,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-0805-scw-gdou-aquaculture-bachelor", @@ -19579,7 +19579,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-csw-gdufe-international-chinese-education-master", @@ -19639,7 +19639,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-csw-gdufe-international-trade-master", @@ -19950,7 +19950,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-gxmu-clinical-medicine-mbbs-2026", @@ -20003,7 +20003,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-0805-scw-gxmzu-iclt-bachelor", @@ -20105,7 +20105,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-csw-gxnu-chinese-language-literature-master", @@ -20210,7 +20210,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-sparse-depth-0808-gxu-chinese-language-major-bachelor", @@ -20284,7 +20284,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gxtcmu-chinese-internal-medicine-master", @@ -20310,7 +20310,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gxtcmu-chinese-medicine-bachelor", @@ -20336,7 +20336,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-gxtcmu-history-literature-chinese-medicine-doctorate", @@ -20362,7 +20362,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecma-gafa-art-studies-doctorate", @@ -20648,7 +20648,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-glmu-administrative-management-master", @@ -20700,7 +20700,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-glmu-epidemiology-health-statistics-master", @@ -20806,7 +20806,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-glmu-stomatology-bachelor", @@ -20858,7 +20858,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-guet-chinese-language-program", @@ -20885,7 +20885,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-guet-cs-bilingual-master", @@ -20912,7 +20912,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-guet-cs-english-bachelor", @@ -20938,7 +20938,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-0805-scw-glut-civil-engineering-master-chinese", @@ -21099,7 +21099,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-gzmu-b-stomatology", @@ -21125,7 +21125,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-gznu-chinese-language", @@ -21335,7 +21335,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-hmu-nursing-bachelor-chinese", @@ -22033,7 +22033,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-hmu-d-international-postgraduate-programs", @@ -22058,7 +22058,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-hmu-m-international-postgraduate-programs", @@ -22083,7 +22083,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-hrbnu-chinese-language-bachelor", @@ -22110,7 +22110,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-hrbnu-long-term-international-course", @@ -22186,7 +22186,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-hebmu-d-doctoral", @@ -22214,7 +22214,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-hebmu-b-international-undergraduate", @@ -22242,7 +22242,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-nnw-hebtu-chinese-language-literature-bachelor", @@ -22376,7 +22376,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-hbu-tcsol-master", @@ -22611,7 +22611,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-hlju-chinese-language", @@ -22662,7 +22662,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-htu-chinese-language-program", @@ -22871,7 +22871,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-haut-nondegree-chinese-language", @@ -22898,7 +22898,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-haut-m-computer-science-and-technology", @@ -22922,7 +22922,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-haut-b-food-science-and-engineering", @@ -22947,7 +22947,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecs-hhu-computer-science-doctorate", @@ -23610,7 +23610,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-just-b-computer-science-en", @@ -23636,7 +23636,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-jzh-just-energy-power-master", @@ -24208,7 +24208,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-jnmc-m-clinical-medicine-cn", @@ -24235,7 +24235,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-jnmc-m-pharmacy", @@ -24261,7 +24261,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-jnmc-m-public-health", @@ -24287,7 +24287,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-kmmu-chinese-language", @@ -24313,7 +24313,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-kmmu-mbbs-preparatory", @@ -24340,7 +24340,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-kmmu-medical-advanced-training", @@ -24364,7 +24364,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-kust-b-civil-engineering-en", @@ -24391,7 +24391,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-sparse-depth-0808-kust-energy-and-power-engineering-bachelor", @@ -24445,7 +24445,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-sparse-depth-0808-kust-mechanical-engineering-bachelor", @@ -24708,7 +24708,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-lnu-international-business-master-english", @@ -24735,7 +24735,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-mnnu-iclt-year-chinese-language-literature", @@ -25816,7 +25816,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-ntu-b-computer-science-en", @@ -25842,7 +25842,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecs-ntu-stomatology-bachelor", @@ -25948,7 +25948,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave5-nbu-general-scholar", @@ -26347,7 +26347,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-ncut-b-electronic-information-engineering-en", @@ -26373,7 +26373,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-ncut-b-mechatronics-engineering-en", @@ -26399,7 +26399,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-ne-neau-animal-husbandry-doctorate", @@ -26667,7 +26667,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-nenu-environmental-engineering-doctorate-english", @@ -26694,7 +26694,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-nenu-finance-bachelor", @@ -26721,7 +26721,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-nenu-international-chinese-education-master", @@ -26748,7 +26748,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-nenu-2026-one-year-chinese-literature", @@ -26801,7 +26801,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-nwnu-chinese-philology-master", @@ -26934,7 +26934,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave6-nwu-international-law-master", @@ -27197,7 +27197,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-cs-doctorate-english", @@ -27224,7 +27224,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-gvs-chinese-language", @@ -27251,7 +27251,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-gvs-credit-courses", @@ -27276,7 +27276,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-chinese-degree-pku-international-chinese-education-master", @@ -27329,7 +27329,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-llm-chinese-law", @@ -27356,7 +27356,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-chinese-language-summer-school", @@ -27383,7 +27383,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-yuke-pre-university", @@ -27410,7 +27410,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-lse-environmental-double-master", @@ -27436,7 +27436,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-research-scholar", @@ -27461,7 +27461,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-senior-visiting-student", @@ -27485,7 +27485,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-spring-four-week-chinese", @@ -27511,7 +27511,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-undergraduate-international-degree-entry", @@ -27539,7 +27539,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-pku-depth-yenching-china-studies-master", @@ -27563,7 +27563,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-remaining-qdu-nondegree-chinese-language-fall-2025", @@ -27590,7 +27590,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-qdu-international-chinese-education-master", @@ -27616,7 +27616,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-qdu-textile-science-engineering-doctorate-english", @@ -27643,7 +27643,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-qdu-textile-science-engineering-master-english", @@ -27670,7 +27670,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-qust-b-artificial-intelligence-en", @@ -27698,7 +27698,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-ne-qust-chinese-language-literature-bachelor", @@ -27752,7 +27752,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-ne-qust-chinese-language-semester", @@ -28064,7 +28064,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-sdjzu-b-civil-engineering-en", @@ -28092,7 +28092,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-sdnu-chinese-language-bachelor", @@ -28146,7 +28146,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-sdnu-tcsol-bachelor", @@ -28298,7 +28298,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sdufe-international-economics-trade-english-bachelor", @@ -28324,7 +28324,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sdufe-management-science-engineering-english-master", @@ -28350,7 +28350,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sdufe-international-business-english-master", @@ -28376,7 +28376,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecma-sdutcm-acupuncture-master", @@ -28809,7 +28809,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-shmtu-b-materials-science-engineering-en", @@ -28836,7 +28836,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-shmtu-b-mechatronic-engineering-bilingual", @@ -28864,7 +28864,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-shmtu-traffic-engineering-bachelor-2026", @@ -28918,7 +28918,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-shnu-2026-master-icle", @@ -29462,7 +29462,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave6-suibe-international-finance-master", @@ -29772,7 +29772,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-medicine-sxtcm-acupuncture-tuina-master", @@ -29797,7 +29797,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-medicine-sxtcm-pharmacy-bachelor", @@ -29822,7 +29822,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-sxtcm-b-traditional-chinese-medicine-cn", @@ -29848,7 +29848,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sau-b-aeronautical-engineering", @@ -29873,7 +29873,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sau-b-computer-science-and-technology", @@ -29898,7 +29898,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sau-b-international-economics-and-trade", @@ -29923,7 +29923,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-mew-nss-synu-four-week-chinese-study", @@ -30055,7 +30055,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-medicine-syphu-pharmaceutics-master", @@ -30081,7 +30081,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-remaining-syphu-b-pharmacy", @@ -30106,7 +30106,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sztu-ai-english-bachelor", @@ -30133,7 +30133,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sztu-cs-chinese-bachelor", @@ -30160,7 +30160,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sztu-international-business-english-bachelor", @@ -30187,7 +30187,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-sztu-pharmacy-english-bachelor", @@ -30214,7 +30214,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-szu-chinese-language-literature-bachelor-2026", @@ -30408,7 +30408,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-sicau-chinese-language-program", @@ -30434,7 +30434,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-sicau-international-doctoral-programs-2026", @@ -30458,7 +30458,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-sicau-international-master-programs-2026", @@ -30482,7 +30482,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-0805-scw-scfai-art-studies-doctorate", @@ -30580,7 +30580,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-sisu-chinese-language-2026-2027", @@ -30631,7 +30631,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-sisu-b-tcsol-cn", @@ -30655,7 +30655,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-sicnu-chinese-refresher-course", @@ -30785,7 +30785,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-clw-sw-scu-chinese-language-bachelor", @@ -31445,7 +31445,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-swpu-b-mechanical-engineering", @@ -31471,7 +31471,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-swpu-m-petroleum-and-natural-gas-engineering", @@ -31497,7 +31497,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-swpu-petroleum-engineering-bachelor", @@ -31523,7 +31523,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-clw-sw-swu-icl-bachelor", @@ -32090,7 +32090,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-tjfsu-b-international-business-ecommerce-cn", @@ -32116,7 +32116,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-tjfsu-b-tcsol-cn", @@ -32142,7 +32142,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-tjfsu-b-translation-en", @@ -32168,7 +32168,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-tjnu-computer-science-bachelor", @@ -32192,7 +32192,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-tjnu-2026-doctor-icle", @@ -32242,7 +32242,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-tjnu-long-term-chinese-language", @@ -32269,7 +32269,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-tjnu-2026-master-icle", @@ -32322,7 +32322,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-chinese-degree-tju-chinese-cross-border-ecommerce-bachelor", @@ -32375,7 +32375,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-chinese-degree-tju-international-chinese-education-master", @@ -32426,7 +32426,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-tju-b-pharmacy-en", @@ -32453,7 +32453,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-tjufe-business-administration-bachelor", @@ -32525,7 +32525,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-tjufe-theoretical-economics-master", @@ -32655,7 +32655,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave6-ucas-biology-master", @@ -32760,7 +32760,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-ujn-b-big-data-management-and-application", @@ -32787,7 +32787,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-ujn-chinese-language-culture", @@ -32841,7 +32841,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-ujn-m-computer-science-and-technology", @@ -32868,7 +32868,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-ustc-scientific-management-leaders-mba", @@ -32920,7 +32920,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-usst-chinese-language-preparatory-2026", @@ -32973,7 +32973,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-usst-m-software-engineering-en", @@ -32999,7 +32999,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-wzu-chinese-language-literature-bachelor", @@ -33025,7 +33025,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-wzu-computer-science-technology-bachelor", @@ -33051,7 +33051,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-wzu-international-economics-trade-bachelor", @@ -33077,7 +33077,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave8-2-wtu-design-doctorate", @@ -33462,7 +33462,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xisu-b-international-economics-and-trade", @@ -33487,7 +33487,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xisu-foundation-pre-university", @@ -33513,7 +33513,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xisu-b-russian", @@ -33538,7 +33538,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xaut-d-international-doctoral", @@ -33565,7 +33565,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xaut-m-international-postgraduate", @@ -33592,7 +33592,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-xaut-b-international-undergraduate", @@ -33619,7 +33619,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-csw-xtu-artificial-intelligence-bachelor", @@ -33752,7 +33752,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-xjau-animal-science-bachelor", @@ -33851,7 +33851,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-xjnu-chinese-language-nondegree", @@ -34063,7 +34063,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-xzmu-b-mbbs", @@ -34087,7 +34087,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-breadth-xzhmu-b-stomatology", @@ -34111,7 +34111,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-yangtzeu-b-clinical-medicine-cn", @@ -34137,7 +34137,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mew-scws-yangtze-computer-science-bachelor", @@ -34241,7 +34241,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-jzh-yzu-animal-science-master", @@ -34350,7 +34350,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-yzu-m-software-engineering-en", @@ -34376,7 +34376,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-jzh-yzu-tcsol-bachelor", @@ -34534,7 +34534,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-ynnu-b-business-administration-cn", @@ -34560,7 +34560,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-ynnu-b-chinese-education-overseas", @@ -34586,7 +34586,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-clw-sw-ynnu-chinese-language-year", @@ -34665,7 +34665,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-clw-sw-ynu-chinese-language-2026", @@ -34716,7 +34716,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-ynu-finance-bachelor", @@ -34743,7 +34743,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-ynu-international-chinese-education-master", @@ -34768,7 +34768,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave3-depth-ynu-software-engineering-bachelor-english", @@ -34795,7 +34795,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-strong-ynufe-language-chinese", @@ -34821,7 +34821,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-ynufe-international-business-bachelor", @@ -34999,7 +34999,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-ecma-zcmu-pharmacy-bachelor", @@ -35050,7 +35050,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-zjgsu-chinese-language-culture-2026", @@ -35104,7 +35104,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-zjgsu-b-international-business-en", @@ -35131,7 +35131,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-local-zjgsu-b-international-law-en", @@ -35158,7 +35158,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-zjnu-chinese-language-culture", @@ -35184,7 +35184,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave4-depth-zjnu-computer-science-master-english", @@ -35211,7 +35211,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-chinese-degree-zjnu-international-chinese-education-bachelor", @@ -35316,7 +35316,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-prog-zstu-chinese-language-literature-bachelor", @@ -35394,7 +35394,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-confirmed-zju-chinese-language", @@ -35468,7 +35468,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-wave7-zufe-international-law-master", @@ -35573,7 +35573,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-jzh-zust-intelligent-manufacturing-master", @@ -35657,7 +35657,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "prog-gap-mve-jzh-zust-iclt-master", diff --git a/content/data/scholarships.json b/content/data/scholarships.json index 887aa3d..84d3e24 100644 --- a/content/data/scholarships.json +++ b/content/data/scholarships.json @@ -2671,7 +2671,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-ecs-ahmu-anhui-government-scholarship", @@ -2741,7 +2741,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-chinese-scholarship-bfsu-iclt-degree-programs-2026", @@ -2810,7 +2810,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-strong-bipt-beijing-government-scholarship", @@ -2843,7 +2843,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave7-bipt-beijing-government-scholarship", @@ -3512,7 +3512,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-cust-jilin-provincial", @@ -3545,7 +3545,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-cust-software-engineering-partial", @@ -3580,7 +3580,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-csust-outstanding-international-student-scholarship", @@ -3829,7 +3829,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave4-sch-cdut-sichuan-government", @@ -3862,7 +3862,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-final-cdutcm-chengdu-government-freshman-scholarship", @@ -4072,7 +4072,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-scws-cug-china-link-2026", @@ -4418,7 +4418,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-ctbu-moe-chongqing-joint", @@ -4451,7 +4451,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-jzh-cuz-postgraduate-scholarship", @@ -4765,7 +4765,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-dgut-international-master-freshman-scholarship", @@ -4801,7 +4801,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-dgut-international-master-living-stipend", @@ -4837,7 +4837,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-chinese-scholarship-ecnu-iclt-degree-programs-2026", @@ -5013,7 +5013,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-fjmu-fujian-government-scholarship-graduate", @@ -5046,7 +5046,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-csw-fzu-fujian-government-scholarship", @@ -5162,7 +5162,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-0805-scw-gdou-outstanding-new-students-scholarship", @@ -5343,7 +5343,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-gdut-guangdong-government-new-student-scholarship-2026", @@ -5475,7 +5475,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-gxmu-president-freshmen-scholarship", @@ -5507,7 +5507,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-scws-gxmzu-guangxi-asean-scholarship-2025", @@ -5641,7 +5641,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-csw-gxnu-university-postgraduate-scholarship", @@ -5714,7 +5714,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-scws-gxu-cgs-high-level-postgraduate-2026", @@ -5785,7 +5785,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-gxtcmu-moe-guangxi-asean-scholarship", @@ -5818,7 +5818,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-ecma-gafa-guangdong-government-scholarship", @@ -6029,7 +6029,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-gzucm-silk-road-csc-scholarship-2026", @@ -6096,7 +6096,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-0805-scw-glut-guangxi-asean-scholarship", @@ -6205,7 +6205,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-gznu-chinese-language-scholarship-fall-2026", @@ -6309,7 +6309,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-strong-muhn-hainan-government-scholarship", @@ -6342,7 +6342,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-scws-hainnu-iclt-scholarship-2026", @@ -6533,7 +6533,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-hmu-csc-silk-road", @@ -6566,7 +6566,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-hmu-moe-heilongjiang-eurasia", @@ -6599,7 +6599,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-hrbnu-chinese-government-scholarship", @@ -6698,7 +6698,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-mew-nnw-hebtu-csc-high-level-postgraduate", @@ -6949,7 +6949,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-haut-promotion", @@ -6982,7 +6982,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-ecs-hhu-csc-high-level-2026", @@ -7446,7 +7446,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-ecs-jxnu-iclt-scholarship-2026", @@ -7651,7 +7651,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-strong-jnmc-shandong-government-scholarship", @@ -7684,7 +7684,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-jnmc-shandong-government", @@ -7717,7 +7717,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-kmmu-freshmen-aid", @@ -7749,7 +7749,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-kmmu-academic-scholarship", @@ -7781,7 +7781,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-strong-kust-scholarship-information", @@ -7814,7 +7814,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-mew-nnw-lnnu-international-chinese-language-teachers", @@ -8809,7 +8809,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-mew-ne-neau-csc-high-level-postgraduate", @@ -8983,7 +8983,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-nenu-2026-iclts-bachelor-language-coverage", @@ -9054,7 +9054,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-2-nwupl-belt-road-scholarship", @@ -9198,7 +9198,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-pku-depth-cgs-advanced-graduate", @@ -9231,7 +9231,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-pku-depth-international-chinese-language-teachers-scholarship", @@ -9303,7 +9303,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-pku-depth-cs-international-phd-full-support", @@ -9338,7 +9338,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-pku-depth-yenching-fellowship", @@ -9373,7 +9373,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave4-depth-qdu-csc-silk-road-2026", @@ -9410,7 +9410,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-strong-qust-chinese-government-scholarship", @@ -9443,7 +9443,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-mew-ne-qust-csc-high-level-postgraduate", @@ -9552,7 +9552,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-sdjzu-shandong-provincial", @@ -9585,7 +9585,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-sdnu-international-chinese-language-teachers-scholarship-2026", @@ -9758,7 +9758,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sdufe-shandong-government-scholarship", @@ -9792,7 +9792,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-ecma-sdutcm-president-scholarship-2026", @@ -10387,7 +10387,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-sau-liaoning-government", @@ -10420,7 +10420,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-sau-university-outstanding", @@ -10453,7 +10453,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-mew-nss-synu-csc-high-level", @@ -10557,7 +10557,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sztu-freshman-scholarship", @@ -10595,7 +10595,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-szu-guangdong-government-2026", @@ -10802,7 +10802,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-depth-sicau-master-university-scholarship-2026", @@ -10837,7 +10837,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-depth-sicau-undergraduate-university-scholarship-2026", @@ -10872,7 +10872,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-0805-scw-scfai-chongqing-mayor-scholarship", @@ -11436,7 +11436,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave4-sch-swpu-sichuan-government", @@ -11469,7 +11469,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave5-west-swu-csc-silk-road-excellence-education-2026", @@ -11862,7 +11862,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-tju-silk-road-2026", @@ -11895,7 +11895,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-tju-international-chinese-language-teachers", @@ -11931,7 +11931,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-tju-tianjin-government", @@ -11964,7 +11964,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-breadth-sch-tju-growth-steel-indonesia-2026", @@ -11997,7 +11997,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave7-tjufe-cgs-high-level-graduate-2026", @@ -12135,7 +12135,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-sch-ujn-undergraduate-international", @@ -12233,7 +12233,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave8-whut-csc-type-b-university-program", @@ -12299,7 +12299,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xisu-international-chinese-language-teachers", @@ -12333,7 +12333,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xisu-university", @@ -12366,7 +12366,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xaut-shaanxi-sanqin", @@ -12399,7 +12399,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xaut-international-students", @@ -12432,7 +12432,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xaut-xian-belt-and-road", @@ -12465,7 +12465,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave3-sch-xaut-central-asian-countries", @@ -12498,7 +12498,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mew-csw-xtu-belt-road-language-scholarship-2026", @@ -12598,7 +12598,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-jzh-yzu-iclt-scholarship-2026", @@ -12667,7 +12667,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-mve-jzh-yzu-csc-high-level-2026", @@ -12869,7 +12869,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-wave7-ynufe-da-yi-scholarship", @@ -13041,7 +13041,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-local-zjgsu-general-scholarship", @@ -13074,7 +13074,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified" + "status": "stale" }, { "id": "sch-gap-chinese-scholarship-zjnu-iclt-degree-programs-2026", diff --git a/content/data/universities.json b/content/data/universities.json index e9a770e..391bdad 100644 --- a/content/data/universities.json +++ b/content/data/universities.json @@ -5563,7 +5563,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-changchun-university-of-science-and-technology", "slug": "changchun-university-of-science-and-technology", "name": { @@ -5588,7 +5588,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-chongqing-technology-and-business-university", "slug": "chongqing-technology-and-business-university", "name": { @@ -5763,7 +5763,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-harbin-medical-university", "slug": "harbin-medical-university", "name": { @@ -5788,7 +5788,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-hebei-medical-university", "slug": "hebei-medical-university", "name": { @@ -5813,7 +5813,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-henan-university-of-technology", "slug": "henan-university-of-technology", "name": { @@ -5863,7 +5863,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-shenyang-aerospace-university", "slug": "shenyang-aerospace-university", "name": { @@ -5913,7 +5913,7 @@ ], "verifiedAt": "2026-07-30", "reviewAfter": "2026-08-29", - "status": "verified", + "status": "stale", "id": "uni-xian-university-of-technology", "slug": "xian-university-of-technology", "name": {