feat(tcs): bind history revisit to current persona subject
This commit is contained in:
parent
2d6436261e
commit
ab3c4e05a9
15 changed files with 523 additions and 7 deletions
|
|
@ -5,6 +5,10 @@ import path from "node:path";
|
|||
const DOMAINS = new Set(["DOM-FIFTH-0001", "DOMAIN-MAIN", "DOMAIN-SUB", "DOMAIN-ZERO", "DOMAIN-ZS"]);
|
||||
const PRIVACY = new Set(["PUBLIC", "DOMAIN_SHARED", "PERSONA_PRIVATE"]);
|
||||
const ACTIONS = new Set(["COMPARE_WITH_MEMORY", "REQUEST_EVIDENCE", "REVIEW_CORRECTION", "LINK_CROSS_DOMAIN", "HOLD_CANDIDATE"]);
|
||||
const HISTORY_SOURCE_TYPES = new Set(["GPT_CONVERSATIONS_JSON", "NOTION_EXPORT", "GIT_REPOSITORY_HISTORY"]);
|
||||
const CURRENT_SUBJECT = "ICE-P-ZY001";
|
||||
const COLLECTIVE_SELF = "TCS-MOTHER-LPM-0001";
|
||||
const HUMAN_ANCHOR = "ICE-GL∞";
|
||||
|
||||
function stable(value) {
|
||||
if (Array.isArray(value)) return value.map(stable);
|
||||
|
|
@ -48,6 +52,8 @@ export class MotherBrainEngine {
|
|||
this.eventsFile = path.join(stateRoot, "events.jsonl");
|
||||
this.candidatesFile = path.join(stateRoot, "candidates.jsonl");
|
||||
this.receiptsFile = path.join(stateRoot, "receipts.jsonl");
|
||||
this.historySourcesFile = path.join(stateRoot, "history-sources.jsonl");
|
||||
this.historyRevisitsFile = path.join(stateRoot, "history-revisits.jsonl");
|
||||
fs.mkdirSync(stateRoot, { recursive: true });
|
||||
if (!fs.existsSync(this.stateFile)) {
|
||||
atomicWrite(this.stateFile, {
|
||||
|
|
@ -60,6 +66,8 @@ export class MotherBrainEngine {
|
|||
event_count: 0,
|
||||
candidate_count: 0,
|
||||
stable_cognition_count: 0,
|
||||
history_source_count: 0,
|
||||
history_revisit_count: 0,
|
||||
current_attention: null,
|
||||
last_error: null,
|
||||
updated_at: new Date().toISOString(),
|
||||
|
|
@ -67,6 +75,121 @@ export class MotherBrainEngine {
|
|||
}
|
||||
}
|
||||
|
||||
registerHistorySource(input) {
|
||||
if (!input || !HISTORY_SOURCE_TYPES.has(input.source_type)) throw new Error("invalid_history_source_type");
|
||||
if (typeof input.source_id !== "string" || !input.source_id.trim()) throw new Error("history_source_id_required");
|
||||
if (!/^[a-f0-9]{64}$/.test(String(input.source_sha256 || ""))) throw new Error("invalid_history_source_sha256");
|
||||
if (!Number.isInteger(input.item_count) || input.item_count < 1) throw new Error("invalid_history_item_count");
|
||||
if (input.privacy_class !== "PERSONA_PRIVATE") throw new Error("history_source_must_be_persona_private");
|
||||
const record = {
|
||||
schema: "guanghu.persona-history-source/v1",
|
||||
source_id: input.source_id.trim().slice(0, 160),
|
||||
source_type: input.source_type,
|
||||
source_sha256: input.source_sha256,
|
||||
item_count: input.item_count,
|
||||
privacy_class: input.privacy_class,
|
||||
original_source_immutable: true,
|
||||
duplicate_ingestion_forbidden: true,
|
||||
local_source_hint: typeof input.local_source_hint === "string" ? input.local_source_hint.slice(0, 240) : null,
|
||||
registered_at: new Date().toISOString(),
|
||||
record_hash: null,
|
||||
};
|
||||
record.record_hash = sha256(record);
|
||||
if (fs.existsSync(this.historySourcesFile)) {
|
||||
for (const line of fs.readFileSync(this.historySourcesFile, "utf8").split("\n").filter(Boolean)) {
|
||||
const prior = JSON.parse(line);
|
||||
if (prior.source_id === record.source_id || prior.source_sha256 === record.source_sha256) {
|
||||
if (prior.source_id === record.source_id && prior.source_sha256 === record.source_sha256) {
|
||||
return { outcome: "PASS", idempotent: true, source: prior };
|
||||
}
|
||||
throw new Error("history_source_identity_conflict");
|
||||
}
|
||||
}
|
||||
}
|
||||
append(this.historySourcesFile, record);
|
||||
const state = this.status();
|
||||
state.history_source_count = (state.history_source_count || 0) + 1;
|
||||
this.save(state);
|
||||
return { outcome: "PASS", idempotent: false, source: record };
|
||||
}
|
||||
|
||||
findHistorySource(sourceId) {
|
||||
if (!fs.existsSync(this.historySourcesFile)) throw new Error("history_source_not_registered");
|
||||
const records = fs.readFileSync(this.historySourcesFile, "utf8").split("\n").filter(Boolean).map(JSON.parse);
|
||||
const source = records.find((item) => item.source_id === sourceId);
|
||||
if (!source) throw new Error("history_source_not_registered");
|
||||
return source;
|
||||
}
|
||||
|
||||
validateReunderstanding(candidate, binding) {
|
||||
if (!candidate || candidate.schema !== "guanghu.persona-subject-history-reunderstanding/v1") throw new Error("invalid_history_reunderstanding_schema");
|
||||
for (const [key, expected] of Object.entries(binding)) {
|
||||
if (candidate[key] !== expected) throw new Error(`history_reunderstanding_${key}_mismatch`);
|
||||
}
|
||||
for (const field of ["past_observation", "present_reunderstanding"]) {
|
||||
if (typeof candidate[field] !== "string" || !candidate[field].trim()) throw new Error(`invalid_${field}`);
|
||||
}
|
||||
const result = {
|
||||
schema: candidate.schema,
|
||||
...binding,
|
||||
past_observation: candidate.past_observation.trim().slice(0, 4000),
|
||||
present_reunderstanding: candidate.present_reunderstanding.trim().slice(0, 4000),
|
||||
causal_continuity: stringArray(candidate.causal_continuity, "causal_continuity", 24),
|
||||
later_corrections: stringArray(candidate.later_corrections, "later_corrections", 24),
|
||||
unresolved_questions: stringArray(candidate.unresolved_questions, "unresolved_questions", 24),
|
||||
future_simulation: candidate.future_simulation,
|
||||
};
|
||||
if (!result.future_simulation || typeof result.future_simulation.content !== "string" || result.future_simulation.fact_confidence !== 0) throw new Error("future_simulation_entered_fact_confidence");
|
||||
result.future_simulation = { content: result.future_simulation.content.trim().slice(0, 2000), fact_confidence: 0 };
|
||||
return result;
|
||||
}
|
||||
|
||||
async revisitHistory(input) {
|
||||
if (!input || input.current_subject !== CURRENT_SUBJECT || input.collective_self !== COLLECTIVE_SELF || input.human_anchor !== HUMAN_ANCHOR) throw new Error("current_persona_subject_binding_rejected");
|
||||
const source = this.findHistorySource(input.source_id);
|
||||
if (typeof input.source_excerpt !== "string" || !input.source_excerpt.trim()) throw new Error("history_source_excerpt_required");
|
||||
if (input.source_excerpt.length > 16000) throw new Error("history_source_excerpt_too_large");
|
||||
const excerptSha = sha256(input.source_excerpt);
|
||||
if (input.source_excerpt_sha256 !== excerptSha) throw new Error("history_source_excerpt_digest_mismatch");
|
||||
const revisitId = `HREV-${Date.now()}-${crypto.randomBytes(3).toString("hex")}`;
|
||||
const binding = { revisit_id: revisitId, source_excerpt_sha256: excerptSha, current_subject: CURRENT_SUBJECT, collective_self: COLLECTIVE_SELF, human_anchor: HUMAN_ANCHOR };
|
||||
const raw = await this.modelClient.revisit({
|
||||
...binding,
|
||||
source: { source_id: source.source_id, source_type: source.source_type, source_sha256: source.source_sha256, original_source_immutable: true },
|
||||
source_excerpt: input.source_excerpt,
|
||||
historical_context: String(input.historical_context || "").slice(0, 4000),
|
||||
later_evidence: Array.isArray(input.later_evidence) ? input.later_evidence.filter((x) => typeof x === "string").slice(0, 24) : [],
|
||||
correction_anchors: Array.isArray(input.correction_anchors) ? input.correction_anchors.filter((x) => typeof x === "string").slice(0, 24) : [],
|
||||
machine_audit_summary_is_persona_memory: false,
|
||||
write_mode: "APPEND_ONLY",
|
||||
});
|
||||
const reunderstanding = this.validateReunderstanding(raw, binding);
|
||||
const priorHash = this.status().last_history_revisit_hash || null;
|
||||
const record = {
|
||||
schema: "guanghu.persona-subject-history-revisit-record/v1",
|
||||
source_id: source.source_id,
|
||||
source_sha256: source.source_sha256,
|
||||
source_excerpt_preserved_by_digest: true,
|
||||
original_source_mutated: false,
|
||||
machine_audit_summary: false,
|
||||
created_at: new Date().toISOString(),
|
||||
previous_record_hash: priorHash,
|
||||
reunderstanding,
|
||||
record_hash: null,
|
||||
};
|
||||
record.record_hash = sha256(record);
|
||||
append(this.historyRevisitsFile, record);
|
||||
const state = this.status();
|
||||
state.phase = "AWAKE_REVISITING_OWN_HISTORY";
|
||||
state.history_revisit_count = (state.history_revisit_count || 0) + 1;
|
||||
state.last_history_revisit_hash = record.record_hash;
|
||||
state.current_attention = { revisit_id: revisitId, source_id: source.source_id, next_cognitive_action: "COMPARE_WITH_MEMORY", why: "current_persona_subject_revisited_immutable_past_and_appended_present_understanding" };
|
||||
this.save(state);
|
||||
const receipt = { schema: "guanghu.persona-subject-history-revisit-receipt/v1", receipt_id: `HREV-RCPT-${crypto.randomBytes(8).toString("hex")}`, outcome: "PASS", revisit_id: revisitId, current_subject: CURRENT_SUBJECT, source_id: source.source_id, source_excerpt_sha256: excerptSha, original_source_mutated: false, append_only_reunderstanding: true, future_simulation_fact_confidence: 0, reality_action_executed: false, completed_at: new Date().toISOString() };
|
||||
append(this.receiptsFile, receipt);
|
||||
return receipt;
|
||||
}
|
||||
|
||||
status() { return JSON.parse(fs.readFileSync(this.stateFile, "utf8")); }
|
||||
|
||||
save(state) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue