diff --git a/apps/web/messages/en.json b/apps/web/messages/en.json
index 9e78c36e..8bad2517 100644
--- a/apps/web/messages/en.json
+++ b/apps/web/messages/en.json
@@ -2198,6 +2198,54 @@
"field": "not authorization; action buttons=false"
}
}
+ },
+ "hostOwnerDecisionRecordFormalRecordQueueReview": {
+ "title": "Host Owner Decision Record Formal Record Queue Review Checklist",
+ "subtitle": "The formal record queue review checklist only confirms whether queue packets are readable for a future human formal-record review. It does not mark review passed, enqueue, create decision records, create approval records, or open runtime gates.",
+ "checkLabel": "Queue review",
+ "guardLabel": "Guardrail",
+ "items": {
+ "queueIdentityTraceable": {
+ "title": "Queue identity traceable",
+ "body": "Confirms queue identity can trace candidate record, version, owner, review scope, and source without treating traceability as formal enqueue.",
+ "guard": "trace only; queue enqueued=0"
+ },
+ "queueDecisionSummaryReadable": {
+ "title": "Queue decision summary readable",
+ "body": "Confirms the decision summary and no-execution statement are readable without creating a formal decision record.",
+ "guard": "summary only; record created=false"
+ },
+ "queueScopeExpiryFresh": {
+ "title": "Queue scope and expiry fresh",
+ "body": "Confirms host, network, service, exclusion, observation intent, and expiry are not stale or outside the original scope.",
+ "guard": "scope check only; finalized=0"
+ },
+ "queueScanLimitsNotAuthorization": {
+ "title": "Queue scan limits not authorization",
+ "body": "Confirms observe-only, future active scan, and credentialed scan limits remain constraints, not scan approval.",
+ "guard": "scan authorized=false"
+ },
+ "queueCredentialBoundaryMetadataOnly": {
+ "title": "Queue credential boundary metadata-only",
+ "body": "Confirms credential boundary keeps only metadata, owner, retention, and masking boundary without requesting sensitive material.",
+ "guard": "secret collection=false"
+ },
+ "queueMaintenanceRollbackLinked": {
+ "title": "Queue maintenance and rollback linked",
+ "body": "Confirms maintenance window, constraints, rollback owner, recovery path, and human contact have pointers without allowing host package changes or tuning.",
+ "guard": "host change=false"
+ },
+ "queueValidationGateSeparate": {
+ "title": "Queue validation gate separate",
+ "body": "Confirms validation evidence, post-check metrics, and baseline pointer still route to a separate runtime gate.",
+ "guard": "active gates=0"
+ },
+ "queueNoExecutionAttestationPresent": {
+ "title": "Queue no-execution attestation present",
+ "body": "Confirms the no-execution, no-approval, and no-runtime-gate statement remains present so the checklist cannot become an action entry.",
+ "guard": "action buttons=false"
+ }
+ }
}
},
"tickets": {
diff --git a/apps/web/messages/zh-TW.json b/apps/web/messages/zh-TW.json
index 353649f4..cb591531 100644
--- a/apps/web/messages/zh-TW.json
+++ b/apps/web/messages/zh-TW.json
@@ -2199,6 +2199,54 @@
"field": "not authorization;action buttons=false"
}
}
+ },
+ "hostOwnerDecisionRecordFormalRecordQueueReview": {
+ "title": "主機 Owner Decision Record Formal Record Queue Review Checklist",
+ "subtitle": "Formal record queue review checklist 只確認佇列資料包是否可供未來人工正式紀錄審查。不標記 review passed、不 enqueue、不建立 decision record、不建立 approval record、不開 runtime gate。",
+ "checkLabel": "Queue review",
+ "guardLabel": "保護邊界",
+ "items": {
+ "queueIdentityTraceable": {
+ "title": "Queue identity traceable",
+ "body": "確認 queue identity 能回溯 candidate record、版本、owner、review scope 與來源,不把可追蹤性當成正式入列。",
+ "guard": "trace only;queue enqueued=0"
+ },
+ "queueDecisionSummaryReadable": {
+ "title": "Queue decision summary readable",
+ "body": "確認 decision summary 與 no-execution statement 可讀,但不產生正式 decision record。",
+ "guard": "summary only;record created=false"
+ },
+ "queueScopeExpiryFresh": {
+ "title": "Queue scope and expiry fresh",
+ "body": "確認 host、network、service、exclusion、觀察目的與 expiry 沒有過期或超出原始 scope。",
+ "guard": "scope check only;finalized=0"
+ },
+ "queueScanLimitsNotAuthorization": {
+ "title": "Queue scan limits not authorization",
+ "body": "確認 observe-only、future active scan 與 credentialed scan limits 仍只是限制描述,不是掃描批准。",
+ "guard": "scan authorized=false"
+ },
+ "queueCredentialBoundaryMetadataOnly": {
+ "title": "Queue credential boundary metadata-only",
+ "body": "確認 credential boundary 只保留 metadata、owner、retention 與 masking 邊界,不要求敏感素材。",
+ "guard": "secret collection=false"
+ },
+ "queueMaintenanceRollbackLinked": {
+ "title": "Queue maintenance and rollback linked",
+ "body": "確認維護窗口、限制條件、rollback owner、復原路徑與人工聯絡點都有 pointer,但不代表可以做主機套件變更或調校。",
+ "guard": "host change=false"
+ },
+ "queueValidationGateSeparate": {
+ "title": "Queue validation gate separate",
+ "body": "確認 validation evidence、post-check metrics 與 baseline pointer 仍導向獨立 runtime gate。",
+ "guard": "active gates=0"
+ },
+ "queueNoExecutionAttestationPresent": {
+ "title": "Queue no-execution attestation present",
+ "body": "確認 no-execution / no-approval / no-runtime-gate 聲明仍在,避免 checklist 被當成 action entry。",
+ "guard": "action buttons=false"
+ }
+ }
}
},
"tickets": {
diff --git a/apps/web/src/app/[locale]/iwooos/page.tsx b/apps/web/src/app/[locale]/iwooos/page.tsx
index c9fb1565..9d14b51c 100644
--- a/apps/web/src/app/[locale]/iwooos/page.tsx
+++ b/apps/web/src/app/[locale]/iwooos/page.tsx
@@ -229,6 +229,13 @@ type HostOwnerDecisionRecordFormalRecordQueuePacket = {
tone: 'steady' | 'warn' | 'locked'
}
+type HostOwnerDecisionRecordFormalRecordQueueReviewItem = {
+ key: string
+ check: string
+ icon: typeof ShieldCheck
+ tone: 'steady' | 'warn' | 'locked'
+}
+
const postureMetrics: PostureMetric[] = [
{ key: 'overall', value: '58%', tone: 'warn' },
{ key: 'framework', value: '80-85%', tone: 'steady' },
@@ -542,6 +549,17 @@ const hostOwnerDecisionRecordFormalRecordQueuePackets: HostOwnerDecisionRecordFo
{ key: 'queueNoExecutionAttestationPacket', packet: 'FQ8', icon: FileWarning, tone: 'locked' },
]
+const hostOwnerDecisionRecordFormalRecordQueueReviewItems: HostOwnerDecisionRecordFormalRecordQueueReviewItem[] = [
+ { key: 'queueIdentityTraceable', check: 'FQC1', icon: FileText, tone: 'warn' },
+ { key: 'queueDecisionSummaryReadable', check: 'FQC2', icon: ClipboardCheck, tone: 'warn' },
+ { key: 'queueScopeExpiryFresh', check: 'FQC3', icon: Radar, tone: 'warn' },
+ { key: 'queueScanLimitsNotAuthorization', check: 'FQC4', icon: Activity, tone: 'locked' },
+ { key: 'queueCredentialBoundaryMetadataOnly', check: 'FQC5', icon: Lock, tone: 'locked' },
+ { key: 'queueMaintenanceRollbackLinked', check: 'FQC6', icon: Clock3, tone: 'warn' },
+ { key: 'queueValidationGateSeparate', check: 'FQC7', icon: ShieldCheck, tone: 'locked' },
+ { key: 'queueNoExecutionAttestationPresent', check: 'FQC8', icon: FileWarning, tone: 'locked' },
+]
+
const evidenceItems = [
'iwooos-posture-projection.snapshot.json',
'security-rollout-policy.snapshot.json',
@@ -1428,6 +1446,38 @@ function HostOwnerDecisionRecordFormalRecordQueueCard({
)
}
+function HostOwnerDecisionRecordFormalRecordQueueReviewCard({
+ item,
+}: {
+ item: HostOwnerDecisionRecordFormalRecordQueueReviewItem
+}) {
+ const t = useTranslations('iwooos.hostOwnerDecisionRecordFormalRecordQueueReview')
+ const Icon = item.icon
+ return (
+
+
+
+
+ {t('checkLabel')}
+
+
{item.check}
+
+
+ {t(`items.${item.key}.title` as never)}
+
+
+ {t(`items.${item.key}.body` as never)}
+
+
+
{t('guardLabel')}
+
+ {t(`items.${item.key}.guard` as never)}
+
+
+
+ )
+}
+
export default function IwoooSPage({ params }: { params: { locale: string } }) {
const t = useTranslations('iwooos')
@@ -1940,6 +1990,26 @@ export default function IwoooSPage({ params }: { params: { locale: string } }) {
+
+
+
{t('hostOwnerDecisionRecordFormalRecordQueueReview.title')}
+
+ {t('hostOwnerDecisionRecordFormalRecordQueueReview.subtitle')}
+
+
+
+ {hostOwnerDecisionRecordFormalRecordQueueReviewItems.map(item => (
+
+ ))}
+
+
+
None:
"s2_33_iwooos_host_owner_decision_record_formal_candidate_review_checklist",
"s2_34_iwooos_host_owner_decision_record_formal_candidate_review_outcome_lanes",
"s2_35_iwooos_host_owner_decision_record_formal_record_queue_packets",
+ "s2_36_iwooos_host_owner_decision_record_formal_record_queue_review_checklist",
]
assert_equal(
"progress_delta_ledger.delta_ids",
@@ -550,6 +551,16 @@ def validate(root: Path) -> None:
"host_decision_record_formal_record_queue_validation_runtime_gate_packet",
"host_decision_record_formal_record_queue_no_execution_attestation_packet",
]
+ expected_iwooos_host_owner_decision_record_formal_record_queue_review_checklist_item_ids = [
+ "host_decision_record_formal_record_queue_review_identity_traceable_check",
+ "host_decision_record_formal_record_queue_review_decision_summary_readable_check",
+ "host_decision_record_formal_record_queue_review_scope_expiry_fresh_check",
+ "host_decision_record_formal_record_queue_review_scan_limits_not_authorization_check",
+ "host_decision_record_formal_record_queue_review_credential_boundary_metadata_only_check",
+ "host_decision_record_formal_record_queue_review_maintenance_rollback_linked_check",
+ "host_decision_record_formal_record_queue_review_validation_runtime_gate_separate_check",
+ "host_decision_record_formal_record_queue_review_no_execution_attestation_present_check",
+ ]
assert_equal(
"iwooos_projection.summary.frontend_surface_coverage_group_count",
iwooos_projection["summary"]["frontend_surface_coverage_group_count"],
@@ -680,6 +691,11 @@ def validate(root: Path) -> None:
iwooos_projection["summary"]["host_owner_decision_record_formal_record_queue_packet_count"],
len(expected_iwooos_host_owner_decision_record_formal_record_queue_packet_ids),
)
+ assert_equal(
+ "iwooos_projection.summary.host_owner_decision_record_formal_record_queue_review_checklist_item_count",
+ iwooos_projection["summary"]["host_owner_decision_record_formal_record_queue_review_checklist_item_count"],
+ len(expected_iwooos_host_owner_decision_record_formal_record_queue_review_checklist_item_ids),
+ )
iwooos_progress = iwooos_projection["progress"]
assert_equal("iwooos_projection.progress.overall_percent", iwooos_progress["overall_percent"], progress["overall_percent"])
assert_equal(
@@ -2454,6 +2470,97 @@ def validate(root: Path) -> None:
f"iwooos_projection.host_owner_decision_record_formal_record_queue_packets.{item['packet_id']}.not_authorization",
item["not_authorization"],
)
+ iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items = iwooos_projection[
+ "host_owner_decision_record_formal_record_queue_review_checklist_items"
+ ]
+ assert_equal(
+ "iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.ids",
+ [item["item_id"] for item in iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items],
+ expected_iwooos_host_owner_decision_record_formal_record_queue_review_checklist_item_ids,
+ )
+ assert_equal(
+ "iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.display_order",
+ [item["display_order"] for item in iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items],
+ list(range(1, len(expected_iwooos_host_owner_decision_record_formal_record_queue_review_checklist_item_ids) + 1)),
+ )
+ assert_equal(
+ "iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.source_packet_ids",
+ [item["source_packet_id"] for item in iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items],
+ expected_iwooos_host_owner_decision_record_formal_record_queue_packet_ids,
+ )
+ expected_iwooos_host_owner_decision_record_formal_record_queue_review_conditions = [
+ "identity_traceable_to_candidate_source",
+ "decision_summary_readable_without_approval_semantics",
+ "scope_expiry_current_and_bounded",
+ "scan_limits_not_authorization",
+ "credential_boundary_metadata_only",
+ "maintenance_rollback_pointer_linked",
+ "validation_runtime_gate_separate",
+ "no_execution_attestation_present",
+ ]
+ assert_equal(
+ "iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.review_conditions",
+ [item["review_condition"] for item in iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items],
+ expected_iwooos_host_owner_decision_record_formal_record_queue_review_conditions,
+ )
+ for item in iwooos_host_owner_decision_record_formal_record_queue_review_checklist_items:
+ assert_equal(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.display_mode",
+ item["display_mode"],
+ "owner_decision_record_formal_record_queue_review_checklist_only",
+ )
+ assert_equal(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.formal_record_queue_review_passed_count",
+ item["formal_record_queue_review_passed_count"],
+ 0,
+ )
+ assert_equal(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.formal_record_queue_enqueued_count",
+ item["formal_record_queue_enqueued_count"],
+ 0,
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.decision_record_created",
+ item["decision_record_created"],
+ )
+ assert_equal(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.owner_decision_received_count",
+ item["owner_decision_received_count"],
+ 0,
+ )
+ assert_equal(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.owner_decision_accepted_count",
+ item["owner_decision_accepted_count"],
+ 0,
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.owner_approval_record_created",
+ item["owner_approval_record_created"],
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.runtime_gate_opened",
+ item["runtime_gate_opened"],
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.raw_payload_allowed",
+ item["raw_payload_allowed"],
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.secret_value_collection_allowed",
+ item["secret_value_collection_allowed"],
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.runtime_execution_authorized",
+ item["runtime_execution_authorized"],
+ )
+ assert_false(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.action_buttons_allowed",
+ item["action_buttons_allowed"],
+ )
+ assert_true(
+ f"iwooos_projection.host_owner_decision_record_formal_record_queue_review_checklist_items.{item['item_id']}.not_authorization",
+ item["not_authorization"],
+ )
assert_equal(
"iwooos_projection.non_blocking_lane_ids",
iwooos_projection["non_blocking_lane_ids"],
@@ -2498,6 +2605,7 @@ def validate(root: Path) -> None:
"display_host_owner_decision_record_formal_candidate_review_checklist",
"display_host_owner_decision_record_formal_candidate_review_outcome_lanes",
"display_host_owner_decision_record_formal_record_queue_packets",
+ "display_host_owner_decision_record_formal_record_queue_review_checklist",
"display_evidence_refs",
"display_forbidden_actions",
]:
@@ -2593,6 +2701,11 @@ def validate(root: Path) -> None:
"create_host_owner_decision_record_from_formal_record_queue_packet",
"accept_host_owner_decision_record_from_formal_record_queue_packet",
"open_runtime_gate_from_owner_decision_record_formal_record_queue_packet",
+ "treat_host_owner_decision_record_formal_record_queue_review_as_approval",
+ "mark_host_owner_decision_record_formal_record_queue_review_passed",
+ "enqueue_host_owner_decision_record_from_formal_record_queue_review",
+ "create_host_owner_decision_record_from_formal_record_queue_review",
+ "open_runtime_gate_from_formal_record_queue_review",
"apply_runtime_blocking_control",
"switch_github_primary",
"production_deploy",