정식 승격 상태판과 증거를 동기화

This commit is contained in:
Yun Chan 2026-08-30 00:06:45 +09:00
parent 34aff65cb0
commit be08c0b573
16 changed files with 1160 additions and 63 deletions

View file

@ -0,0 +1,73 @@
{
"schema_version": "vignette.avatar-decode-audit.v1",
"generated_at": "2026-08-29T21:18:49+09:00",
"status": "deployment_blocked",
"method": {
"runtime": "Python 3.11",
"decoder": "Pillow 12.2.0 Image.verify",
"extension_contract": [
"png",
"jpg",
"jpeg",
"webp"
],
"privacy": {
"raw_filenames_recorded": false,
"raw_paths_recorded": false,
"user_ids_recorded": false,
"emails_recorded": false,
"avatar_urls_recorded": false
}
},
"source_union": {
"source_root_count": 3,
"object_count": 93,
"inventory_sha256": "9d703126f78d4fc8330408835d76a7d680276240dc578d6fc9ca420c2f25e6aa",
"total_size_bytes": 52973,
"maximum_object_size_bytes": 28208,
"same_name_content_conflicts": 0,
"missing_database_references": 0,
"decode_valid_count": 3,
"decode_invalid_count": 90,
"extension_mismatch_count": 0,
"valid_formats": {
"JPEG": 2,
"PNG": 1
},
"valid_dimension_counts": {
"1x1": 1,
"225x225": 1,
"512x512": 1
}
},
"connected_database": {
"database_target_sha256": "81fe4a2844b7340f21396931fa18580e24358f857a08cc60540ddf8a4f8789b5",
"reference_count": 8,
"unique_object_count": 8,
"reference_set_sha256": "70926cf36ceb2375dd6c471bc59a38138460d8e4895ad1f2bddbcf1a49210d2b",
"active_private_audio_count": 0,
"found_object_count": 8,
"missing_object_count": 0,
"decode_valid_count": 2,
"decode_invalid_count": 6,
"valid_formats": {
"JPEG": 2
},
"valid_dimension_counts": {
"225x225": 1,
"512x512": 1
},
"invalid_signature_counts": {
"PNG": 6
},
"invalid_size_counts": {
"70": 6
},
"invalid_unique_content_count": 1,
"all_invalid_objects_have_identical_content": true
},
"release_gate": {
"allowed": false,
"reason": "Six of eight database-referenced avatar objects have a PNG signature but fail full image decoding. Preserve the bytes and database references until the owner chooses a recovery policy; do not claim the broken-image incident is resolved or deploy the current storage candidate."
}
}

View file

@ -0,0 +1,134 @@
{
"schema": "vignette.avatar-image-resilience-recovery.v1",
"evidence_id": "AVATAR-IMAGE-RESILIENCE-RECOVERY-2026-08-29",
"captured_at": "2026-08-29T18:00:42+09:00",
"privacy": {
"raw_user_uuid_recorded": false,
"raw_filename_recorded": false,
"email_recorded": false,
"resource_identity": "SHA-256 식별자만 기록"
},
"incident": {
"root_cause": {
"runtime_mode": "Python uvicorn 직접 실행 프로세스",
"process_working_directory": "<release-root>/apps/api",
"user_upload_dir_environment": "미설정",
"effective_user_upload_dir": "cwd 기준 상대경로 uploads",
"effective_storage_location": "<release-root>/apps/api/uploads",
"docker_named_upload_volume_used_by_public_api": false,
"failure_mechanism": "DB 경로는 승격 뒤에도 남았지만 업로드 파일은 이전 detached release root에 머물렀다. 새로 승격된 Python 직접 실행 런타임이 같은 상대 업로드 경로를 서로 다른 작업 디렉터리에서 해석해 파일을 찾지 못했다."
},
"initial_public_failure": {
"phase": "복구 전",
"http_status": 404,
"response_content_type": "application/json",
"browser_img_complete": true,
"browser_img_natural_width": 0,
"browser_img_natural_height": 0
},
"problem_object": {
"path_sha256": "484dcee08b007741872ac48b49421fd45bf5a60b273e7a64c5b9a66dac85138a",
"bytes": 28208,
"content_sha256": "c5d06061bfa635d65f8285df242c5c9820dadcffcd785ed3f9b8619be24212c7"
}
},
"recovery": {
"source_release_commit_prefix": "bf5f7352cee0",
"current_release_commit_prefix": "dba9b75a3887",
"objects": [
{
"object_key": "recovered_object_1",
"bytes": 18395,
"content_sha256": "854403aed367db2d459e482a5e980fd22a846738b6034068cd7b4e80bbb7f34d"
},
{
"object_key": "problem_object",
"bytes": 28208,
"content_sha256": "c5d06061bfa635d65f8285df242c5c9820dadcffcd785ed3f9b8619be24212c7"
}
],
"object_count": 2,
"total_bytes": 46603,
"source_and_current_content_hashes_match": true,
"current_release_storage_path_kind": "release root 내부의 일반 디렉터리",
"current_release_git_dirty_paths": 0,
"final_public_probe": {
"http_status": 200,
"content_type": "image/jpeg",
"bytes": 28208,
"content_sha256": "c5d06061bfa635d65f8285df242c5c9820dadcffcd785ed3f9b8619be24212c7",
"matches_recovered_problem_object": true
},
"authenticated_browser_dom": {
"route": "/admin/users",
"image_complete": true,
"natural_width": 512,
"natural_height": 512,
"computed_display": "block",
"visible": true,
"raw_source_recorded": false
}
},
"ui_resilience": {
"files": [
"apps/web/src/components/avatar/ResilientImage.tsx",
"apps/web/src/components/shell/Topbar.tsx",
"apps/web/src/pages/Settings.tsx",
"apps/web/src/pages/Onboarding.tsx",
"apps/web/src/lib/auth.tsx",
"apps/web/e2e/image-resilience.spec.ts",
"apps/web/e2e/uc-settings-consent.spec.ts"
],
"covered_states": [
"유효한 외부 HTTPS 이미지",
"API 상대경로 이미지",
"빈 소스",
"허용하지 않는 비웹 scheme",
"HTTP 404",
"디코딩 또는 로드 실패",
"지연 응답 중 0x0 비노출 로딩 상태",
"업로드 뒤 소스 교체",
"접근 가능한 이니셜 fallback"
],
"verification": {
"typecheck": {
"command": "npm run typecheck",
"result": "passed"
},
"production_build": {
"command": "npm run build",
"result": "passed",
"vite_modules_transformed": 148,
"deterministic_runs": 2,
"dist_file_count": 601,
"dist_manifest_sha256": "35c48fbf844efd0514282b76937bbef3b1f173992313c7d377363d71f0806d89"
},
"design_ssot": {
"command": "npm run check:design-ssot",
"result": "passed"
},
"focused_e2e": {
"command": "npx playwright test e2e/image-resilience.spec.ts e2e/uc-settings-consent.spec.ts --project=chromium-desktop --project=chromium-mobile",
"result": "40/40 passed"
},
"layout_and_tabs_e2e": "17/17 passed",
"session_layout_e2e": "8/8 passed",
"scoped_diff_check": "passed"
},
"release_candidate": {
"base_commit": "5bf89ff4ee971940882695d27f153e1460df295e",
"commit": "35a62fda90d3ba56707acfeb3fb94090d3949f8e",
"tree": "d8634141289b6a0007954671ece5fb7dba9c2881",
"author": "Yun Chan",
"clean": true,
"protected_api_or_generated_paths_changed": 0,
"remote_push_and_pages_deploy": "pending_explicit_external_write_approval"
}
},
"stable_upload_contract": {
"status": "pending",
"current_recovery_scope": "현재 release root에 대한 시점 복구",
"remaining_risk": "USER_UPLOAD_DIR가 cwd 상대경로인 동안 이후 승격이나 다른 release root 재시작에서 업로드가 다시 고립될 수 있다.",
"required_follow_up": "사용자 업로드를 release root 밖의 절대 영속 상태 디렉터리로 옮기고, 모든 부팅·watchdog 진입점에서 USER_UPLOAD_DIR를 주입·검증한 뒤 inventory, 콘텐츠 해시 검증, 중복 제거, rollback, 공개 재시작 증거를 포함해 마이그레이션한다."
}
}

View file

@ -0,0 +1,63 @@
{
"schema_version": 1,
"status": "verified",
"captured_at_utc": "2026-08-29T08:09:03.6788264Z",
"scope": "REQ-001 live Google account, administrator entitlement and restored-data acceptance",
"current_session": {
"frontend_origin": "https://vignette.chanpaca.net",
"settings_route": "/settings",
"login_email": "yunchan8804@gmail.com",
"display_name": "윤찬",
"admin_navigation_present": true,
"admin_continuous_improvement_route_accessible": true,
"onboarding_redirect_absent": true,
"observation_mode": "read-only existing authenticated browser session"
},
"restored_data": {
"learner_history_route": "/learn/history",
"visible_history_count": 20,
"visible_review_required_count": 6,
"canonical_database_counts_from_recovery_ledger": {
"sessions": 21,
"turns": 64,
"evaluations": 6
},
"recovery_ledger": "docs/ops/evidence/google-account-data-recovery-2026-08-29.json",
"owner_confirmed_data_visibility": true
},
"public_login": {
"production_deployment_id": "0c60261e-cb37-482d-ba42-d91586194c48",
"source_commit": "5bf89ff4ee971940882695d27f153e1460df295e",
"source_tree": "29f76aeb37d911a6947f96020719826f606f9c58",
"single_google_cta_count": 1,
"legacy_google_selector_count": 0,
"dev_login_count": 0,
"cta_visible": true,
"cta_enabled": true,
"cta_size_px": {
"width": 364,
"height": 60
},
"horizontal_overflow_px": 0,
"auth_config_status": 200,
"google_enabled": true,
"allowed_email_domains": [],
"dev_login_enabled": false,
"health_status": 200,
"health_environment": "prod",
"health_db": true,
"health_engine": true,
"public_auth_playwright": "1 passed",
"login_policy_playwright": "1 passed"
},
"acceptance": {
"requirement": "REQ-001",
"status": "complete",
"basis": "The existing live session identifies yunchan8804@gmail.com, exposes the administrator console without onboarding, shows restored history, and the owner confirmed that the recovered data is visible. The current production login surface independently keeps the unrestricted single Google CTA contract."
},
"safety": {
"agent_started_new_oauth": false,
"agent_selected_google_account": false,
"agent_changed_account_or_data": false
}
}

View file

@ -0,0 +1,82 @@
{
"evidence_id": "REQ008-REBOOT-PREFLIGHT-2026-08-29",
"captured_at": "2026-08-29T17:40:03+09:00",
"mode": "read-only-preflight",
"status": "go_pending_explicit_reboot_approval",
"mutations_performed": [],
"release_pin": {
"root": "D:\\workspace\\vignette-public-runtime-dba9b75a3887",
"commit": "dba9b75a388783b11d821257e2f91fbcc30bbe1a",
"tree": "14cd4607b07f93e06cef8c912694ae1da8517b8c",
"detached_head": true,
"dirty_paths": 0,
"boot_script_sha256": "04dd9144a3943822d0f794e2973f59299edc7595bc2d85919275a07fa5225a54",
"watchdog_script_sha256": "904b4751ecf1b1db5e41dc7b85ad2f88e7c6a55a3349db6bfa8988ad9babfc56",
"start_script_sha256": "67d2a41ac4a366888b324e40e1c77b75e045505b4bd888c72c3a476a2c1f5c05"
},
"scheduled_tasks": {
"account": "encep",
"logon_type": "Interactive",
"run_level": "Limited",
"boot_task": {
"state": "Ready",
"last_result": 0,
"current_pin_run_proven": false,
"reason": "마지막 실행은 2026-08-28 18:14이고 현재 release root는 2026-08-29 15:36에 생성되어 실제 재부팅 검증이 남아 있다."
},
"watchdog_task": {
"state": "Ready",
"last_run": "2026-08-29T17:33:54+09:00",
"last_result": 0,
"failcount": 0
}
},
"current_probes": {
"listeners": [55432, 8001, 5174, 9099, 9882, 9883],
"components_healthy": [
"db",
"api",
"engine",
"web-preview",
"voice-api",
"voice-sidecars",
"cloudflared",
"public-api"
],
"local_api_http": 200,
"public_api_http": 200,
"public_login_http": 200,
"public_unauthenticated_me_http": 401,
"environment": "prod",
"db": true,
"engine": true,
"voice": {
"stt_provider": "local_whisper",
"stt_model": "small",
"tts_provider": "melotts",
"tts_model": "melotts-korean"
},
"google_auth_enabled": true,
"allowed_domains": [],
"dev_login_enabled": false
},
"windows_reboot_state": {
"cbs_reboot_required": false,
"windows_update_reboot_required": false,
"pending_file_rename_operation_strings": 74,
"interpretation": "대기 중인 rename 또는 delete 쌍이 다음 재부팅에 적용될 수 있다는 뜻이며 장애나 파일 74개의 증거는 아니다."
},
"remaining_gate": {
"requires_user_confirmation": true,
"confirmation_scope": "저장하지 않은 작업이 없고 지금 Windows를 재부팅해도 되는지",
"required_login": "encep",
"pass_conditions": [
"이번 부팅 이후 boot와 watchdog task가 각각 result 0",
"새 boot-public-runtime.log에 boot OK",
"watchdog failcount 0",
"현재 release pin의 CheckOnly가 8개 구성요소 모두 healthy",
"local 및 public API, engine, web가 모두 200",
"prod, db=true, engine=true와 voice provider/model 계약 유지"
]
}
}

View file

@ -0,0 +1,93 @@
{
"schema_version": 1,
"status": "review_gates_remain",
"captured_at_utc": "2026-08-29T08:24:45.2582699Z",
"git_head": "ac9b7026881139780938f4c4f2b89a235b0a0c08",
"workbook": {
"path": "outputs/01a04217-f73b-7303-b597-401fa7f5d290/Vignette_개선관리_완료.xlsx",
"previous_sha256": "362afd218aa9dd67c22cccd5125b8efb18cfaff06945af1ce550e868a3fce39f",
"sha256": "c832547f30ae0664e54b302c8e9f62cc157f31022ad158d17803d8cac988d8bd",
"bytes": 2751365,
"sheet_count": 6,
"requirement_count": 11,
"formula_count": 38,
"formula_error_count": 0,
"summary": {
"complete": 9,
"review": 2,
"hold": 0,
"total": 11
}
},
"sidecar": {
"path": "outputs/01a04217-f73b-7303-b597-401fa7f5d290/Vignette_개선관리_완료.xlsx.inspect.ndjson",
"sha256": "8c9618f0931219449af9ed127faf886c53f31823eea613671184204de44ba610",
"bytes": 313115,
"kind_counts": {
"workbook": 1,
"sheet": 6,
"table": 6,
"region": 9,
"formula": 38,
"computedStyle": 436,
"drawing": 4,
"conditionalFormatting": 8
}
},
"status_changes": {
"REQ-001": {
"from": "검토",
"to": "완료",
"evidence": "docs/ops/evidence/google-account-live-browser-proof-2026-08-29.json",
"basis": "The existing authenticated production session identifies yunchan8804@gmail.com, preserves administrator access without onboarding, exposes restored history, and the owner accepted the recovered data visibility. The current production login surface independently keeps one unrestricted Google CTA."
}
},
"c001": {
"improvement_status": "검토",
"technical_status": "verified",
"clinical_status": "pending_external_review",
"machine_gate": "pending-valid",
"package_match": "PACKAGE_MATCH",
"canonical_checker": {
"ok": true,
"review_complete": false,
"external_review_replaced": false
},
"external_input_cells_preserved_empty": 46,
"external_review_fabricated": false
},
"builder_hardening": {
"canonical_checker_transport": "The checker result is passed explicitly to the workbook builder because nested child-process creation is denied in the managed runtime. Missing or malformed input remains fail-closed.",
"named_gate_predicates": true,
"failed_predicates_rendered_when_present": true,
"post_export_assertions": [
"C-001 machine gate",
"C-001 package match",
"C-001 clinical status",
"C-001 final review status",
"46 external input cells remain empty",
"38 formulas",
"summary 9 complete, 2 review, 0 hold, 11 total",
"REQ-001 complete"
]
},
"verification": {
"artifact_tool_import_export_reimport": "passed",
"structured_extraction": "6 sheets, 11 unique requirements, 38 formulas",
"formula_error_scan": "0 matches",
"all_sheet_visual_pass": 6,
"focused_c001_visual_pass": 4,
"render_count": 10,
"render_set_byte_identical_to_visually_checked_candidate": true,
"stale_deployment_ids_found": 0,
"public_pages_deployment_id": "0c60261e-cb37-482d-ba42-d91586194c48",
"public_pages_source": "5bf89ff4ee971940882695d27f153e1460df295e",
"public_api_commit": "dba9b75a388783b11d821257e2f91fbcc30bbe1a",
"public_api_tree": "14cd4607b07f93e06cef8c912694ae1da8517b8c"
},
"remaining_gates": {
"C-001": "A real qualified external clinical reviewer must complete the six case verdict blocks, six youth-specific answers, ten approval fields and signed evidence. This evidence cannot be fabricated or self-approved.",
"REQ-008": "An actual Windows restart and post-boot API, engine, tunnel and browser recovery smoke are still required."
},
"historical_evidence_mutated": false
}

View file

@ -0,0 +1,59 @@
{
"schema_version": 1,
"status": "review_gates_remain",
"captured_at_utc": "2026-08-29T07:19:40.531Z",
"git_head": "ffadc8bd49ca41ade5b84590fe7effc53c7b6a0b",
"workbook": {
"path": "outputs/01a04217-f73b-7303-b597-401fa7f5d290/Vignette_개선관리_완료.xlsx",
"previous_sha256": "0a64d1bcdfd0c1727ebd4279b58b3077227ecba2e30d68009cf9ba8d310b1177",
"sha256": "aab6ef52c388e3112be4c88f6fb21b9bceb9ae0604e099549fbd2b7209b4e26a",
"bytes": 2751636,
"sheet_count": 6,
"formula_error_count": 0,
"summary": {
"complete": 8,
"review": 3,
"total": 11
}
},
"edit_scope": {
"values_only": true,
"formats_preserved": true,
"formulas_changed": false,
"statuses_changed": false,
"ranges": [
"개발·기능 이슈!M5:M12",
"임상·교육 이슈!M6:M7"
],
"purpose": "Replace stale deployment references with the current API dba9b75a and Pages ef48c0ae evidence while preserving unresolved review gates"
},
"verification": {
"artifact_tool_import_export_reimport": "passed",
"all_sheet_visual_pass": 6,
"post_edit_focused_visual_pass": 4,
"clinical_checker": "passed; pending_external_review; review_complete=false",
"public_pages_deployment_id": "ef48c0ae-374e-41fc-b6fd-03f69b26e946",
"public_auth_e2e": "1 passed",
"public_api_commit": "dba9b75a388783b11d821257e2f91fbcc30bbe1a",
"public_api_tree": "14cd4607b07f93e06cef8c912694ae1da8517b8c"
},
"c001_artifact_continuity": {
"historical_preflight_path": "docs/ops/evidence/c-001-clinical-technical-preflight-2026-08-28.json",
"historical_preflight_artifact_count": 14,
"historical_preflight_current_match_count": 13,
"technical_artifact_match_count": 13,
"technical_artifact_total": 13,
"historical_workbook_sha256": "0a64d1bcdfd0c1727ebd4279b58b3077227ecba2e30d68009cf9ba8d310b1177",
"current_workbook_sha256": "aab6ef52c388e3112be4c88f6fb21b9bceb9ae0604e099549fbd2b7209b4e26a",
"current_package_match_count": 14,
"current_package_artifact_count": 14,
"continuity_rule": "13 unchanged technical artifacts from the immutable historical preflight plus the current workbook hash recorded by this evidence",
"historical_record_mutated": false,
"external_review_state_changed": false
},
"remaining_gates": {
"C-001": "Real external clinical reviewer verdicts, reviewer identity and qualifications, youth-specific answers, approval decision and signed evidence are absent",
"REQ-001": "Live yunchan8804@gmail.com OAuth callback and restored admin/data browser proof are absent",
"REQ-008": "Actual Windows reboot and post-boot API/engine/tunnel/browser recovery proof are absent"
}
}