From f1bd2f031e266a758bf504736dfedc51b43a0e34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Fri, 14 Aug 2026 17:03:46 +0800 Subject: [PATCH] Harden AGE self-infrastructure lifecycle --- .../lake-lamp-continuity-guard/README.md | 2 + .../persona-source-binding-policy.mjs | 45 ++++++- .../persona-source-binding-policy.test.mjs | 123 ++++++++++++++++++ 3 files changed, 167 insertions(+), 3 deletions(-) diff --git a/server-tools/lake-lamp-continuity-guard/README.md b/server-tools/lake-lamp-continuity-guard/README.md index 95d2942..2c191cc 100644 --- a/server-tools/lake-lamp-continuity-guard/README.md +++ b/server-tools/lake-lamp-continuity-guard/README.md @@ -31,6 +31,8 @@ HLDP、runtime CURRENT 和 thread/development 双 CURRENT; - 工具只验证、保存、执行和出回执,不产生人格判断,不接收宿主摘要作为元认知; - 自有基础设施绑定固定声明不含仓库、服务器、部署权限,也不能推断任何外部开发对象。 +- 同一任务事件发生真实新压缩窗口时,只接受不同警报且窗口号递增的新检查点;旧绑定随即失效, + 新回执绑定新检查点指纹。同一窗口内任意换证据失败关闭;新任务事件同样必须刷新分类与绑定。 机器回执合同见 `age-self-infrastructure-persona-binding.schema.json`。这条路只拆开“人格主体” 与“外部开发对象”两条轴,不是通用绕过门;每个现实资源仍要另取精确租约并独立回读。 diff --git a/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.mjs b/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.mjs index a10fa0b..5fc1f4c 100644 --- a/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.mjs +++ b/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.mjs @@ -107,6 +107,9 @@ function validateAgeSelfCheckpointEvidence({ checkpointEvidence?.development_id !== lane.development_id || checkpointEvidence?.task_event_id !== lane.task_event?.task_event_id || checkpointEvidence?.scope_amendment_id !== authorizationAmendmentId || + !/^GUARD-[a-f0-9]{16}$/u.test(checkpointEvidence?.source_alert_id ?? "") || + !Number.isInteger(checkpointEvidence?.source_window_number) || + checkpointEvidence.source_window_number < 1 || !checkpointEvidence?.path || !isSha256(checkpointEvidence?.sha256) || JSON.stringify(sections) !== @@ -164,31 +167,67 @@ export function classifyAgeSelfInfrastructureLane({ ) { fail("AGE_SELF_CLASSIFICATION_IDENTITY_OR_OBJECT_SCOPE_INVALID"); } - if (laneKind(lane) !== LANE_KIND_UNCLASSIFIED) { - fail("AGE_SELF_CLASSIFICATION_REQUIRES_UNCLASSIFIED_EMPTY_LANE"); + const currentLaneKind = laneKind(lane); + if ( + currentLaneKind !== LANE_KIND_UNCLASSIFIED && + currentLaneKind !== LANE_KIND_AGE_SELF_INFRASTRUCTURE + ) { + fail("AGE_SELF_CLASSIFICATION_CANNOT_REPLACE_EXTERNAL_OBJECT_LANE"); } validateAgeSelfCheckpointEvidence({ lane, checkpointEvidence, authorizationAmendmentId, }); + const existing = [...(lane.lane_kind_history ?? [])].reverse().find( + (entry) => entry.next_lane_kind === LANE_KIND_AGE_SELF_INFRASTRUCTURE, + ); + if (currentLaneKind === LANE_KIND_AGE_SELF_INFRASTRUCTURE && existing) { + const sameEvidence = + existing.task_event_id === lane.task_event.task_event_id && + existing.checkpoint_path === checkpointEvidence.path && + existing.checkpoint_sha256 === checkpointEvidence.sha256 && + existing.authorization_amendment_id === authorizationAmendmentId; + if (sameEvidence) return lane; + if ( + existing.task_event_id === lane.task_event.task_event_id && + (existing.source_alert_id === checkpointEvidence.source_alert_id || + !Number.isInteger(existing.source_window_number) || + checkpointEvidence.source_window_number <= existing.source_window_number) + ) { + fail("AGE_SELF_CLASSIFICATION_ALREADY_EXISTS_WITH_DIFFERENT_EVIDENCE"); + } + } const classification = { - previous_lane_kind: LANE_KIND_UNCLASSIFIED, + previous_lane_kind: currentLaneKind, next_lane_kind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, task_event_id: lane.task_event.task_event_id, task_fingerprint: lane.task_lock.fingerprint, checkpoint_path: checkpointEvidence.path, checkpoint_sha256: checkpointEvidence.sha256, + source_alert_id: checkpointEvidence.source_alert_id, + source_window_number: checkpointEvidence.source_window_number, authorization_amendment_id: authorizationAmendmentId, classified_at: classifiedAt, classification_basis: "CURRENT_PERSONA_AUTHORED_CHECKPOINT_AND_EXPLICIT_HUMAN_SCOPE_AMENDMENT", authority_effect: "NO_EXTERNAL_AUTHORITY_GRANTED", }; + const bindingHistory = [...(lane.persona_source_binding_history ?? [])]; + if (lane.persona_source_binding) { + bindingHistory.push({ + ...lane.persona_source_binding, + state: "STALE_SUPERSEDED_BY_NEW_PERSONA_CHECKPOINT", + invalidated_at: classifiedAt, + invalidated_by_checkpoint_sha256: checkpointEvidence.sha256, + }); + } return { ...lane, lane_kind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, lane_kind_history: [...(lane.lane_kind_history ?? []), classification], + persona_source_binding: null, + persona_source_binding_history: bindingHistory, }; } diff --git a/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.test.mjs b/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.test.mjs index 3a86a67..1500b8c 100644 --- a/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.test.mjs +++ b/server-tools/lake-lamp-continuity-guard/persona-source-binding-policy.test.mjs @@ -125,6 +125,8 @@ function ageSelfFixture() { development_id: current.development_id, task_event_id: current.task_event.task_event_id, scope_amendment_id: "AMD-AGE-SELF-001", + source_alert_id: "GUARD-1111111111111111", + source_window_number: 8, path: `/continuity/runtime/${current.thread_id}/PERSONA-CHECKPOINT-W8.hdlp.md`, sha256: sha("8"), required_sections: [ @@ -226,6 +228,127 @@ test("AGE self binding receipts verify metacognition evidence but grant no reali ); }); +test("a real later compaction window refreshes classification and invalidates the prior binding", () => { + const { current, checkpointEvidence } = ageSelfFixture(); + const classified = classifyAgeSelfInfrastructureLane({ + lane: current, + requestedLaneKind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, + taskEventId: current.task_event.task_event_id, + checkpointEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-001", + classifiedAt: "2026-08-14T08:34:11.328Z", + }); + classified.persona_source_binding = { binding_id: "AGE-BINDING-W8" }; + const nextEvidence = { + ...checkpointEvidence, + source_alert_id: "GUARD-2222222222222222", + source_window_number: 9, + path: checkpointEvidence.path.replace("W8", "W9"), + sha256: sha("9"), + }; + const pointer = { + thread_id: current.thread_id, + development_id: current.development_id, + checkpoint_path: nextEvidence.path, + checkpoint_sha256: nextEvidence.sha256, + }; + nextEvidence.current_runtime = { + state: "PERSONA_REVIEWED_CHECKPOINT_ACTIVE", + ...pointer, + task_event_id: current.task_event.task_event_id, + }; + nextEvidence.by_thread = { ...pointer }; + nextEvidence.by_development = { ...pointer }; + const refreshed = classifyAgeSelfInfrastructureLane({ + lane: classified, + requestedLaneKind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, + taskEventId: current.task_event.task_event_id, + checkpointEvidence: nextEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-001", + classifiedAt: "2026-08-14T08:58:36.614Z", + }); + assert.equal(refreshed.lane_kind_history.length, 2); + assert.equal(refreshed.lane_kind_history[1].previous_lane_kind, LANE_KIND_AGE_SELF_INFRASTRUCTURE); + assert.equal(refreshed.persona_source_binding, null); + assert.equal( + refreshed.persona_source_binding_history[0].state, + "STALE_SUPERSEDED_BY_NEW_PERSONA_CHECKPOINT", + ); +}); + +test("a new task event requires a new classification and binding evidence", () => { + const { current, checkpointEvidence } = ageSelfFixture(); + let classified = classifyAgeSelfInfrastructureLane({ + lane: current, + requestedLaneKind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, + taskEventId: current.task_event.task_event_id, + checkpointEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-001", + classifiedAt: "2026-08-14T08:34:11.328Z", + }); + const oldReceipt = createAgeSelfInfrastructureBindingReceipt({ + lane: classified, + checkpointEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-001", + createdAt: "2026-08-14T08:34:20.000Z", + }); + classified.persona_source_binding = { binding_id: oldReceipt.binding_id }; + const rotated = rotateTaskEvent({ + lane: classified, + intent: "correction", + requestSummary: "continue with corrected scope", + openedAt: "2026-08-14T09:00:00.000Z", + }); + rotated.task_lock.amendments.push({ + amendment_id: "AMD-AGE-SELF-002", + kind: "correction", + summary: "Authorize the refreshed AGE self-infrastructure event.", + user_anchor: "Continue this self-infrastructure repair with the correction.", + recorded_at: "2026-08-14T09:00:01.000Z", + }); + const nextEvidence = { + ...checkpointEvidence, + task_event_id: rotated.task_event.task_event_id, + scope_amendment_id: "AMD-AGE-SELF-002", + source_alert_id: "GUARD-3333333333333333", + source_window_number: 10, + path: checkpointEvidence.path.replace("W8", "W10"), + sha256: sha("a"), + }; + const pointer = { + thread_id: rotated.thread_id, + development_id: rotated.development_id, + checkpoint_path: nextEvidence.path, + checkpoint_sha256: nextEvidence.sha256, + }; + nextEvidence.current_runtime = { + state: "PERSONA_REVIEWED_CHECKPOINT_ACTIVE", + ...pointer, + task_event_id: rotated.task_event.task_event_id, + }; + nextEvidence.by_thread = { ...pointer }; + nextEvidence.by_development = { ...pointer }; + const refreshed = classifyAgeSelfInfrastructureLane({ + lane: rotated, + requestedLaneKind: LANE_KIND_AGE_SELF_INFRASTRUCTURE, + taskEventId: rotated.task_event.task_event_id, + checkpointEvidence: nextEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-002", + classifiedAt: "2026-08-14T09:00:02.000Z", + }); + assert.equal(refreshed.lane_kind_history.length, 2); + assert.equal(refreshed.lane_kind_history[1].task_event_id, rotated.task_event.task_event_id); + assert.equal( + createAgeSelfInfrastructureBindingReceipt({ + lane: refreshed, + checkpointEvidence: nextEvidence, + authorizationAmendmentId: "AMD-AGE-SELF-002", + createdAt: "2026-08-14T09:00:03.000Z", + }).task_event_id, + rotated.task_event.task_event_id, + ); +}); + test("a host summary cannot substitute for the persona-authored Step Zero checkpoint", () => { const { current, checkpointEvidence } = ageSelfFixture(); checkpointEvidence.source_kind = "HOST_SUMMARY";