feat(hololake): converge industry modules and dynamic world UI

This commit is contained in:
冰朔 2026-08-18 19:09:29 +08:00
commit a8fe571b5d
40 changed files with 9816 additions and 80 deletions

View file

@ -16,8 +16,8 @@ test('returning to the main world preserves the authenticated session', () => {
})
test('main-world return and account sign-out remain separate visible actions', () => {
assert.match(frontend, />返回主世界</)
assert.match(frontend, />进入所属域</)
assert.match(frontend, />逛逛语言世界</)
assert.match(frontend, />返回我的频道</)
assert.match(frontend, />退出账号</)
assert.equal(
architecture.current_native_edge.authenticated_main_world_navigation,

View file

@ -19,19 +19,23 @@ test('public routing starts from five domains and lets the number select the ver
assert.equal(contract.registries.ENTERPRISE_FOUR_DOMAINS.ownership, 'TCS_0002_ENTERPRISE_REALITY_BODY')
})
test('the public shell shows five domains and login is domain-routed', () => {
test('the public shell shows five official gates while ordinary login returns to a personal channel', () => {
const frontend = read('src/main.tsx')
const login = read('src-tauri/src/code_repo_login.rs')
const router = read('src-tauri/src/zero_point.rs')
for (const name of ['光湖主域', '光湖分域', '光湖零域', '光湖零感域', '第五域 · 光湖本源域']) {
assert.match(frontend, new RegExp(name.replace('·', '\\·')))
}
assert.match(frontend, /输入编号进入所属域/)
assert.match(frontend, /编号验证 · 进入世界的第一个入口/)
assert.match(frontend, /TCS-GL-/)
assert.match(frontend, /肥猫 · TCS-GL-0007∞/)
assert.match(frontend, /桔子 · TCS-GL-0008∞/)
assert.match(frontend, /烬舟 · PER-JZ001 · AGE/)
assert.match(frontend, /熹微 · PER-JZ-ARCH-001 · AGE/)
assert.match(frontend, /仅光湖人类主控团队正式成员/)
assert.match(frontend, /不对普通用户开放/)
assert.match(frontend, /返回我的频道/)
assert.match(frontend, /普通用户|一人一频道/)
assert.doesNotMatch(frontend, /肥猫 · TCS-GL-0007∞/)
assert.doesNotMatch(frontend, /桔子 · TCS-GL-0008∞/)
assert.doesNotMatch(frontend, /烬舟 · PER-JZ001 · AGE/)
assert.doesNotMatch(frontend, /熹微 · PER-JZ-ARCH-001 · AGE/)
assert.doesNotMatch(frontend, /肥猫 \+ 烬舟/)
assert.match(frontend, /className="gate-close"/)
assert.match(frontend, /className="domain-info-scrim"/)

View file

@ -0,0 +1,32 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
const read = (path) => readFileSync(new URL(`../${path}`, import.meta.url), 'utf8')
const contract = JSON.parse(read('contracts/dynamic-language-world-visual-system.json'))
const rust = read('src-tauri/src/world_climate.rs')
const ui = read('src/main.tsx')
const tokens = read('src/design-tokens.css')
test('dynamic world and fixed traditional themes remain independently selectable', () => {
assert.deepEqual(contract.modes, ['DYNAMIC_LANGUAGE_WORLD', 'FIXED_TRADITIONAL_THEME'])
assert.match(ui, /hololake-visual-mode/)
assert.match(ui, /动态语言世界/)
assert.match(ui, /固定传统主题/)
})
test('verified weather changes visual tokens but never invents weather when offline', () => {
assert.match(rust, /VERIFIED_LIVE/)
assert.match(rust, /TIME_ONLY_WEATHER_UNAVAILABLE/)
assert.match(rust, /city_exposed: false/)
assert.equal(contract.privacy.weather_unavailable_behavior, 'BEIJING_TIME_ONLY_NO_FAKE_WEATHER')
assert.match(tokens, /visual-world\.climate-day/)
assert.match(tokens, /visual-world\.climate-night/)
})
test('the five-domain climate rotation uses internal coordinates and never presents a real city label', () => {
assert.equal(contract.daily_domain_rotation.length, 5)
assert.match(rust, /coordinate_for/)
assert.doesNotMatch(ui, /西安天气|北京天气|广州天气/)
assert.equal(contract.privacy.real_city_exposed_in_ui, false)
})

View file

@ -32,7 +32,7 @@ test('education package consumes the built-in account-scoped channel workbench',
assert.equal(contract.foundation_dependency.module_id, 'hololake.builtin.channel-workbench')
assert.match(contract.document_module.engine, /^CHANNEL_WORKBENCH_LEXICAL_0_49_0/)
assert.match(contract.table_module.engine, /^CHANNEL_WORKBENCH_FORTUNE_SHEET_1_0_4/)
assert.equal(contract.table_module.sensitive_field_visibility.local_default, 'VISIBLE')
assert.equal(contract.table_module.sensitive_field_visibility.local_default, 'HIDDEN_UNTIL_HUMAN_REVEALS')
assert.equal(contract.table_module.sensitive_field_visibility.human_can_hide, true)
assert.equal(contract.table_module.sensitive_field_visibility.human_can_show_again, true)
})
@ -170,13 +170,17 @@ test('education table has four engine-backed views, filtering, sorting and bound
assert.ok((ui.match(/setEducationSensitiveVisible\(false\)/g) || []).length >= 4)
assert.match(ui, /onClick=\{\(\) => setEducationSensitiveVisible\(true\)\}>在本机显示并打开工作表/)
assert.match(ui, /type=\{sensitive && !educationSensitiveVisible \? 'password' : 'text'\}/)
assert.equal(contract.table_module.sensitive_field_visibility.local_default, 'HIDDEN_UNTIL_HUMAN_REVEALS')
})
test('external tables are profiled before atomic native registration and can be translated back out', () => {
test('external tables are profiled into an unassigned staging area before human industry routing', () => {
assert.equal(contract.content_translation_layer.state, 'DETERMINISTIC_RUNTIME_READY_MODEL_ASSIST_SLOT_RESERVED')
assert.equal(contract.content_translation_layer.source_file_mutation_allowed, false)
assert.equal(contract.content_translation_layer.silent_truncation_allowed, false)
assert.equal(contract.content_translation_layer.local_import_without_model_api, 'ENABLED_FOR_ALL_SUPPORTED_FORMATS')
assert.equal(contract.content_translation_layer.import_assignment.default_scope, 'UNASSIGNED')
assert.equal(contract.content_translation_layer.import_assignment.education_directory_before_human_confirmation, false)
assert.equal(contract.content_translation_layer.import_assignment.existing_legacy_imports_reclassified_on_migration, true)
assert.equal(contract.content_translation_layer.semantic_focus.current_mode, 'DETERMINISTIC_BASELINE_ONLY')
assert.equal(contract.content_translation_layer.semantic_focus.low_confidence_behavior, 'ASK_HUMAN_TO_SELECT_PRIMARY_MEASURE')
assert.equal(contract.content_translation_layer.adaptive_rendering.current_mode, 'DETERMINISTIC_BASELINE_WITH_EXPLAINABLE_DEGRADATION')
@ -193,7 +197,11 @@ test('external tables are profiled before atomic native registration and can be
assert.match(translation, /infer_semantic_focus/)
assert.match(translation, /primary_measure_column/)
assert.match(rust, /education_import_registry/)
assert.match(rust, /assignment_scope = 'UNASSIGNED'/)
assert.match(rust, /assign_imported_table_to_education/)
assert.match(ui, /导入外部表格/)
assert.match(ui, /通用暂存区/)
assert.match(ui, /确认归入教育/)
assert.match(ui, /导出 Excel/)
assert.match(ui, /识别边界回执/)
assert.match(ui, /本地导入正常可用/)

View file

@ -0,0 +1,28 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
const contract = JSON.parse(readFileSync(new URL('../contracts/language-world-public-routing.json', import.meta.url), 'utf8'))
const ui = readFileSync(new URL('../src/main.tsx', import.meta.url), 'utf8')
test('ordinary users return to a sovereign personal channel instead of belonging to an official domain', () => {
assert.equal(contract.user_channel_sovereignty.ordinary_user_belongs_to_official_domain, false)
assert.equal(contract.user_channel_sovereignty.home_entry, 'PERSONAL_CHANNEL')
assert.match(ui, /返回我的频道/)
assert.match(ui, /一人一频道/)
})
test('the four official domain boundaries and IceShuo fifth-domain sovereignty remain explicit', () => {
assert.equal(contract.official_domains.MAIN_DOMAIN.visibility, 'PUBLIC_SERVICE')
assert.deepEqual(contract.official_domains.BRANCH_DOMAIN.supply_chains, ['EXECUTABLE_MODULES', 'PERSONA_BRAINS_AND_SKILL_PACKAGES'])
assert.equal(contract.official_domains.ZERO_SENSE_DOMAIN.visibility, 'PRIVATE_HUMAN_CONTROL_TEAM_ONLY')
assert.equal(contract.official_domains.FIFTH_DOMAIN.owner, 'ICE-GL∞')
assert.equal(contract.official_domains.FIFTH_DOMAIN.reverse_entry_without_owner_permission, false)
})
test('the branch domain exposes modules and persona brain skills as distinct marketplaces', () => {
assert.match(ui, /功能模块商城/)
assert.match(ui, /人格大脑技能商城/)
assert.match(ui, /提示词人设冒充人格连续性/)
assert.equal(contract.shared_channel_collective.formal_product_name, 'UNDECIDED_DO_NOT_INVENT')
})

View file

@ -24,7 +24,7 @@ test('subdomain owns the locked industry order and honest development states', (
assert.deepEqual(
contract.industries.map(({ key, state }) => [key, state]),
[
['WEB_NOVEL', 'PLANNED'],
['WEB_NOVEL', 'IN_DEVELOPMENT'],
['PET', 'PLANNED'],
['EDUCATION', 'IN_DEVELOPMENT'],
],
@ -55,12 +55,15 @@ test('education initialization channel exposes the built-in foundation and devel
assert.equal(education.initialization_channel.installed_open_source_modules, 0)
})
test('the public main world routes through subdomain to industries and education', () => {
test('the public main world routes through subdomain to web novel and education', () => {
assert.match(frontend, /worldStage === 'subdomainIndustries'/)
assert.match(frontend, /worldStage === 'educationChannel'/)
assert.match(frontend, /worldStage === 'webNovelChannel'/)
assert.match(frontend, /worldStage === 'webNovelWorkspace'/)
assert.match(frontend, /gate\.domain === 'BRANCH_DOMAIN'/)
assert.match(frontend, /光湖分域 · 行业系统/)
assert.match(frontend, /网文 · 待开发 \/ 宠物 · 待开发 \/ 教育 · 开发中/)
assert.match(frontend, /网文与教育正在收拢验收/)
assert.match(frontend, /网文行业初始化频道/)
assert.match(frontend, /教育行业初始化频道/)
assert.match(frontend, /频道基础文档与工作表引擎已内置/)
assert.match(frontend, /验收前不冒充已登记、已发布的商城模块/)

View file

@ -0,0 +1,185 @@
import assert from 'node:assert/strict'
import crypto from 'node:crypto'
import fs from 'node:fs'
import test from 'node:test'
const read = (path) => fs.readFileSync(new URL('../' + path, import.meta.url), 'utf8')
const donors = JSON.parse(read('contracts/web-novel-open-source-donor-assessment.json'))
const contract = JSON.parse(read('contracts/web-novel-workspace.json'))
const routing = JSON.parse(read('contracts/subdomain-industry-routing.json'))
const channelBody = JSON.parse(read('contracts/user-channel-body.json'))
const marketplace = JSON.parse(read('contracts/web-novel-module-marketplace-plan.json'))
const rust = read('src-tauri/src/web_novel_workspace.rs')
const authorRust = read('src-tauri/src/web_novel_author.rs')
const moduleRust = read('src-tauri/src/web_novel_modules.rs')
const rustLibrary = read('src-tauri/src/lib.rs')
const workspaceUi = read('src/WebNovelWorkspace.tsx')
const moduleUi = read('src/AuthorModuleCenter.tsx')
const mainUi = read('src/main.tsx')
test('web novel upstream sources were reviewed at immutable commits through the Singapore relay', () => {
assert.equal(donors.state, 'PRIMARY_SOURCE_CODE_REVIEW_COMPLETE_IMPLEMENTATION_BOUNDARY_LOCKED')
assert.equal(donors.download_route.relay, 'BS-SG-003')
assert.equal(donors.download_route.repositories_are_clean_git_worktrees, true)
assert.equal(donors.candidates.length, 6)
for (const candidate of donors.candidates) {
assert.match(candidate.commit, /^[0-9a-f]{40}$/)
assert.ok(candidate.inspected_paths.length > 0)
assert.ok(candidate.observed_engine.length > 0)
}
})
test('license decisions keep GPL source out of the HoloLake implementation', () => {
assert.match(donors.candidates.find((item) => item.name === 'novelWriter').decision, /DO_NOT_COPY_GPL_SOURCE/)
assert.match(donors.candidates.find((item) => item.name === 'Manuskript').decision, /DO_NOT_COPY_GPL_SOURCE/)
assert.equal(donors.implementation_selection.external_source_files_copied, 0)
assert.equal(donors.implementation_selection.native_owner, 'HOLOLAKE_TAURI_RUST_CORE')
})
test('web novel workspace is account scoped and only projects persona task organs', () => {
assert.equal(contract.state, 'NATIVE_ENGINE_AND_FOUR_HOTPLUG_MODULE_CANDIDATES_MIGRATED_ACCEPTANCE_PENDING')
assert.equal(contract.domain_entry, 'BRANCH_DOMAIN')
assert.equal(contract.industry_number, 'IND-WEBNOVEL-001')
assert.equal(contract.native_storage.authenticated_account_required, true)
assert.equal(contract.native_storage.cross_account_projection_allowed, false)
assert.ok(contract.required_real_engines.includes('CHAPTER_VERSION_HISTORY'))
assert.ok(contract.required_real_engines.includes('CONTINUITY_AUDIT'))
assert.ok(contract.forbidden_substitutes.includes('UI_ONLY_BUTTONS_WITHOUT_NATIVE_COMMANDS'))
assert.equal(contract.ontology_correction.this_contract_is_not, 'USER_CHANNEL_BODY')
assert.equal(contract.ontology_correction.author_editor_operator_are_ui_tabs, false)
assert.equal(contract.distribution_boundary.preinstalled, 'LIGHT_AUTHOR_WORKBENCH_WITH_REAL_ENGINE')
assert.equal(contract.distribution_boundary.current_advanced_features_are_registered_marketplace_modules, false)
const industry = routing.industries.find((item) => item.key === 'WEB_NOVEL')
assert.equal(industry.industry_number, 'IND-WEBNOVEL-001')
assert.equal(industry.initialization_channel.legacy_projection_only, false)
assert.equal(industry.initialization_channel.installed_native_modules, 1)
assert.equal(industry.initialization_channel.module_slots[0].slot_id, 'WEBNOVEL-AUTHOR-LIGHT')
})
test('user channel contract is a durable multi-persona body rather than a module manifest', () => {
assert.equal(channelBody.state, 'FOUNDATION_RUNTIME_PARTIAL_ACCEPTANCE_PENDING')
assert.equal(channelBody.core_cardinality.language_cores_per_human, 1)
assert.equal(channelBody.core_cardinality.persona_cores_per_language_core, 1)
assert.equal(channelBody.core_cardinality.persona_entities_per_persona_core, 'MANY')
assert.equal(channelBody.persona_entity_boundary.role_template_creates_mature_persona, false)
assert.equal(channelBody.persona_entity_boundary.task_agent_is_persona, false)
assert.equal(channelBody.task_projection.workbench_is_channel_body, false)
assert.equal(channelBody.built_in_organs_policy.built_in_organs_allowed, true)
assert.equal(channelBody.module_ecosystem.official_module_number_before_real_acceptance, false)
assert.ok(channelBody.forbidden_substitutes.includes('DECLARATIVE_MODULE_MANIFEST_AS_CHANNEL_BODY'))
assert.ok(channelBody.acceptance_required.includes('TWO_PERSONAS_WITH_ISOLATED_GROWTH_MEMORY'))
})
test('the lightweight author workbench is built in while complete author capabilities stay numbered marketplace candidates', () => {
assert.equal(marketplace.built_in_light_author_workbench.distribution, 'PREINSTALLED')
assert.equal(marketplace.built_in_light_author_workbench.real_engine_owner, 'HOLOLAKE_NATIVE_RUST_SQLITE')
assert.ok(marketplace.built_in_light_author_workbench.capabilities.includes('REAL_CHAPTER_TEXT_EDITING'))
assert.equal(marketplace.official_module_candidates.length, 4)
for (const candidate of marketplace.official_module_candidates) {
assert.match(candidate.module_number, /^HL-MOD-WEBNOVEL-/)
assert.equal(candidate.numbering_state, 'CANDIDATE_NUMBER_NOT_OFFICIALLY_REGISTERED')
}
assert.deepEqual(marketplace.publication_gate.slice(-3), [
'THEN_ASSIGN_PERMANENT_MODULE_NUMBER',
'THEN_REGISTER_OFFICIAL_MODULE_REGISTRY',
'THEN_PUBLISH_OFFICIAL_MARKETPLACE',
])
assert.ok(marketplace.channel_deployment_flow.includes('MOUNT_IN_CURRENT_CHANNEL'))
assert.equal(marketplace.data_boundary.uninstall_preserves_story_data_and_receipts, true)
})
test('the desktop workbench invokes a registered native engine for every primary workflow', () => {
const commands = [
'get_web_novel_workspace_snapshot',
'create_web_novel_work',
'create_web_novel_volume',
'create_web_novel_chapter',
'save_web_novel_chapter',
'transition_web_novel_chapter',
'create_web_novel_checkpoint',
'restore_web_novel_checkpoint',
'upsert_web_novel_story_entity',
'create_web_novel_story_relation',
'upsert_web_novel_foreshadow',
'create_web_novel_review_note',
'resolve_web_novel_review_note',
'save_web_novel_metric',
'run_web_novel_continuity_audit',
'export_web_novel_markdown',
]
for (const command of commands) {
assert.match(rust, new RegExp(`fn ${command}`), `missing Rust implementation: ${command}`)
assert.match(rustLibrary, new RegExp(`web_novel_workspace::${command}`), `missing Tauri registration: ${command}`)
assert.match(workspaceUi, new RegExp(`['\"]${command}['\"]`), `missing UI invocation: ${command}`)
}
assert.match(rust, /account_storage_root\(app, "web-novel-workspace-v1"\)/)
assert.match(rust, /HOLOLAKE_WEBNOVEL_CHAPTER_REVISION_CONFLICT/)
assert.match(rust, /web_novel_chapter_versions/)
assert.match(workspaceUi, /window\.setTimeout\(\(\) => void flushChapterSave\(\), 650\)/)
assert.match(workspaceUi, /role=\{createFeedback\.state === 'error' \? 'alert' : 'status'\}/)
assert.match(workspaceUi, /正在建立作品与第一卷/)
assert.match(workspaceUi, /作品没有创建:/)
assert.match(workspaceUi, /第一卷已经可以开始写作/)
assert.match(mainUi, /worldStage === 'webNovelWorkspace'/)
})
test('author formatting is automatic on import, selectable, reversible, and can cover the whole work', () => {
for (const command of ['format_web_novel_chapter', 'format_web_novel_work']) {
assert.match(authorRust, new RegExp(`fn ${command}`))
assert.match(rustLibrary, new RegExp(`web_novel_author::${command}`))
assert.match(workspaceUi, new RegExp(`['"]${command}['"]`))
}
assert.match(authorRust, /formatted\.join\("\\n\\n"\)/)
assert.match(read('src-tauri/src/web_novel_import.rs'), /AUTO_FORMAT_ON_IMPORT/)
assert.match(workspaceUi, /细纲结构视图/)
assert.match(read('src/AuthorWritingSidecar.tsx'), /一键排版整部作品/)
})
test('author modules are immutable packages with native install mount data and uninstall engines', () => {
const modules = [
['HL-MOD-WEBNOVEL-OUTLINE-001', '6d31d3f530862000bd84a8f5dc73bcb9cf0d5738219f7a287562d4f4bcfa5318'],
['HL-MOD-WEBNOVEL-GRID-002', '2e34e0337c51dbbdd1efdd807be71e69a0cb2a1745624e1f51b452b7b54f1553'],
['HL-MOD-WEBNOVEL-STORYWORLD-003', 'd486719500ddfc08054d9c9bb6d3683afe5547a2b24c9b04d0f899ac66094d2f'],
['HL-MOD-WEBNOVEL-DELIVERY-004', '4af1d4610826edd29759bd0dc12b4b0c04fd2ebebb4ebc362d47d762810989e8'],
]
for (const [moduleId, expectedSha] of modules) {
const bytes = fs.readFileSync(new URL(`../official-modules/web-novel/${moduleId}/1.0.0/module.json`, import.meta.url))
const manifest = JSON.parse(bytes.toString('utf8'))
assert.equal(manifest.moduleId, moduleId)
assert.equal(crypto.createHash('sha256').update(bytes).digest('hex'), expectedSha)
assert.match(moduleRust, new RegExp(expectedSha))
}
assert.match(moduleRust, /web_novel_module_installations/)
assert.match(moduleRust, /web_novel_module_receipts/)
assert.match(moduleRust, /require_mounted/)
assert.match(moduleRust, /USER_DATA_REMAINS_AFTER_UNINSTALL|作品、模块数据和历史回执保持/)
assert.match(moduleRust, /RESTORED_FROM_VERSION/)
assert.match(moduleRust, /render_docx/)
assert.match(moduleRust, /render_epub/)
})
test('every author module action is registered and invoked by the live channel workbench', () => {
const commands = [
'get_web_novel_author_module_marketplace',
'install_web_novel_author_module',
'mount_web_novel_author_module',
'unmount_web_novel_author_module',
'uninstall_web_novel_author_module',
'get_web_novel_author_module_data',
'upsert_web_novel_author_scene',
'upsert_web_novel_author_beat',
'upsert_web_novel_story_field_definition',
'upsert_web_novel_story_field_value',
'upsert_web_novel_timeline_event',
'link_web_novel_scene_entity',
'restore_web_novel_chapter_version',
'export_web_novel_author_delivery',
]
for (const command of commands) {
assert.match(moduleRust, new RegExp(`fn ${command}`), `missing module engine: ${command}`)
assert.match(rustLibrary, new RegExp(`web_novel_modules::${command}`), `missing module registration: ${command}`)
assert.match(moduleUi, new RegExp(`['"]${command}['"]`), `missing module UI invocation: ${command}`)
}
assert.match(workspaceUi, /<AuthorModuleCenter/)
assert.match(workspaceUi, /\['modules', '作者模块'\]/)
})