ζ Decision Trail — Algorithm Extraction

⚠ HERITAGE EXTRACTION — donor AMS ζ Decision Trail (Wave 8 quarantine)

This file extracts the donor AMS thought-record hash-chain from src/controllers/thought.js and src/domains/thought/ (deleted R53). The 7-thought-tool donor surface and the 9-tool donor audit family are donor accretion. Phase 0 Colibri ships exactly 6 ζ/η tools total (3 audit + 3 merkle per ADR-004 R74.5) targeting src/domains/thought/ (P0.7). The hash-chain algorithm itself is preserved as canonical and forms the basis of the Phase 0 implementation. The Phase 0 truth lives in ../../concepts/ζ-decision-trail.md.

Read this file as donor genealogy for the algorithm; the tool surface is in ../mcp-tools-phase-0.md.

Algorithmic content extracted from AMS src/controllers/thought.js and src/domains/thought/ for Colibri implementation reference.

Hash-Chain Algorithm

Each thought record is cryptographically linked to its parent. The chain is tamper-evident: modifying any record breaks all subsequent chain hashes.

For each new thought record:

  content_hash = SHA256(record.content)

  if record.parent_id == null:
    parent_chain_hash = "0000...0000"  (64-char zero hash)
  else:
    parent_chain_hash = parent_record.chain_hash

  chain_hash = SHA256(content_hash + parent_chain_hash)
               (string concatenation before hashing)

Implementation detail: The concatenation is string concatenation of two hex-encoded SHA-256 digests (128 hex chars total), then SHA-256 of that string. Both hashes are lowercase hex without separator.

4 Valid Record Types

Defined in src/controllers/thought.js as the accepted enum:

Type When to use Example content
plan Before starting work “I will implement X by doing Y, then Z”
analysis During work — examining facts, code, options “The root cause is X because Y. Evidence: …”
decision At a choice point “Chose approach A over B because of performance constraint C”
reflection After work — lessons, outcomes “Completed successfully. Blocker was X, resolved by Y. Tests: green”

Note: observation and hypothesis are NOT valid types in the current implementation. Use analysis for recording discovered facts during work.

Record Schema

Full schema for mcp_thought table:

{
  id:           string    — UUID, unique record identifier
  session_id:   string    — groups records belonging to same work session
  parent_id:    string | null  — links to previous record's id (null = chain root)
  type:         enum      — "plan" | "analysis" | "decision" | "reflection"
  content:      string    — the actual thought text (the content that gets hashed)
  content_hash: string    — SHA-256 hex digest of content field
  chain_hash:   string    — SHA-256 hex digest of (content_hash + parent.chain_hash)
  metadata:     JSON      — { task_id, agent_id, tool_calls: [...], branch, commit_sha }
  created_at:   ISO 8601  — UTC timestamp of record creation
}

The metadata.tool_calls array lists the MCP tool names called during the work session up to this record, providing execution context alongside the thought content.

Verification Algorithm

thought_verify(session_id) — O(n) walk over all records in the session:

def verify_chain(session_id):
  records = db.query(
    "SELECT * FROM mcp_thought WHERE session_id = ? ORDER BY created_at ASC",
    session_id
  )

  for record in records:
    # Step 1: verify content hash
    computed_content_hash = SHA256(record.content)
    if computed_content_hash != record.content_hash:
      return {
        valid: False,
        broken_at: record.id,
        reason: "content_hash_mismatch",
        expected: computed_content_hash,
        actual: record.content_hash
      }

    # Step 2: verify chain hash
    if record.parent_id is None:
      parent_chain_hash = "0" * 64
    else:
      parent = records[record.parent_id]
      parent_chain_hash = parent.chain_hash

    computed_chain_hash = SHA256(record.content_hash + parent_chain_hash)
    if computed_chain_hash != record.chain_hash:
      return {
        valid: False,
        broken_at: record.id,
        reason: "chain_hash_mismatch",
        expected: computed_chain_hash,
        actual: record.chain_hash
      }

  return { valid: True, records: len(records), chain_length: len(records) }

Time complexity: O(n) where n = number of records in session. Space complexity: O(n) to hold all records in memory during walk.

FTS5 Full-Text Search Integration

The mcp_thought table has a companion FTS5 virtual table for full-text search:

-- FTS5 virtual table (one of the 4 FTS5 tables in the schema)
CREATE VIRTUAL TABLE mcp_thought_fts USING fts5(
  content,
  metadata,
  content=mcp_thought,
  content_rowid=rowid
);

-- Trigger to keep FTS5 in sync
CREATE TRIGGER mcp_thought_ai AFTER INSERT ON mcp_thought BEGIN
  INSERT INTO mcp_thought_fts(rowid, content, metadata)
  VALUES (new.rowid, new.content, new.metadata);
END;

thought_search(query, session_id?, limit?) uses mcp_thought_fts MATCH ? with optional session filter. Results include BM25 relevance rank.

Branching: Thought Trees

Multiple records can share the same parent_id, creating a tree structure rather than a strict linear chain:

root (parent_id = null)
  ├── analysis_1 (parent_id = root.id)
  │     ├── decision_A (parent_id = analysis_1.id)
  │     └── decision_B (parent_id = analysis_1.id)  ← branch
  └── analysis_2 (parent_id = root.id)              ← branch

thought_tree(session_id) returns the full tree as a nested JSON structure. thought_trail(session_id, record_id) returns the linear path from root to the specified record (single ancestry branch).

Verification note: thought_verify walks all records but branches mean a record can have only one parent. The chain_hash for each record still ties it uniquely to its parent — divergent branches cannot be grafted onto each other without breaking the chain.

Tool Surface (src/controllers/thought.js)

Tool Parameters Returns
thought_record session_id, type, content, parent_id?, metadata? New record with content_hash, chain_hash
thought_get id Single record
thought_tree session_id Nested tree JSON
thought_trail session_id, record_id Linear path from root to record
thought_verify session_id Verification result (valid/broken)
thought_search query, session_id?, limit? FTS5 matched records

See Also

  • [[concepts/ζ-decision-trail ζ Decision Trail]] — concept overview
  • [[extractions/eta-proof-store-extraction η Proof Store Extraction]] — Merkle tree that consumes thought chains
  • [[extractions/beta-task-pipeline-extraction β Pipeline Extraction]] — writeback contract requires thought_record
  • [[architecture/database Database Architecture]] — mcp_thought table schema
  • [[guides/tutorials/merkle-audit Merkle Audit Tutorial]] — end-to-end thought + merkle workflow

Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.