Skip to content

post-launch wave-5: agent decision lineage / decisions endpoint over Phi #10

@DubovskiyIM

Description

@DubovskiyIM

Why

Three angles converge on the same primitive that Fold already has but doesn't expose as a feature:

  1. Research finding (~/Desktop/IDF/2026-05-03-market-research-provenance-explainable.html): "decision lineage" / "AI assurance" emerging as adjacent category to data-lineage (Atlan, Collibra, Informatica heading there). White space — none of them carry decision-level semantics, only data-flow.
  2. GDPR Article 22 post CJEU C-203/22 (Feb 2025): right to "meaningful information about the logic involved in automated decision-making". Compliance-by-design XAI frameworks (XAI-Compliance-by-Design MDPI Dec 2025) explicitly call for structured per-decision audit trails.
  3. Fold already has it. Φ event log + anchoring + witnesses → every confirmed effect carries provenance back to the intent that proposed it, the role that allowed it, the conditions that passed, the invariants that held. Witness-of-proof is sitting in the codebase since Phase 2 SDK extraction. We just don't expose it as a query surface yet.

What

A new endpoint surface and a new domain-feature: "decisions" as a first-class queryable artifact derived from Φ.

Endpoint

GET /api/document/:domain/decisions?as=role&entity=Deal&id=42

Returns:

{
  "subject": { "entity": "Deal", "id": "deal_42" },
  "lineage": [
    {
      "effectId": "e_abc123",
      "intentId": "create_deal",
      "alpha": "add",
      "proposer": { "id": "user_x", "role": "customer" },
      "at": "2026-04-12T14:21:03Z",
      "conditions": [
        { "expression": "task.status = 'published'", "evaluated": true }
      ],
      "invariantsChecked": [
        { "name": "deal_status_transition", "passed": true },
        { "name": "max_active_deals_per_customer", "passed": true }
      ],
      "preapproval": null,
      "irreversibility": null
    },
    {
      "effectId": "e_def456",
      "intentId": "release_payment",
      "alpha": "replace",
      "target": "Deal.paidAt",
      "proposer": { "id": "user_x", "role": "customer" },
      "at": "2026-04-15T11:02:18Z",
      "irreversibility": { "point": "high", "at": "release", "reason": "Money is gone — forward-correction only" },
      "preapproval": null,
      "conditions": [
        { "expression": "deal.status = 'completed'", "evaluated": true }
      ],
      "invariantsChecked": [...]
    }
  ],
  "currentState": { ... folded snapshot ... },
  "format": "json | html | pdf"
}

This is not new data — it's a new materialization of existing Φ. The "decisions" reader is a view function over Φ_confirmed filtered by entity+id, joined with intent-schema metadata, formatted as a document graph.

Three demo questions this answers

  1. "Why did the agent reject my refund?" → returns the rejected effect lineage with failedCondition + failedCheck
  2. "What's the audit trail for Deal #42?" → returns full chain of intents that touched it, who proposed, what invariants held
  3. "What if we'd rejected this approval — what would the world look like?" → counterfactual: fold(Φ \ { effect: e_xyz }). This is wave-5.5 — a separate primitive worth its own issue.

Why this is wave-5 and not wave-2/3/4

Wave-2 (deploy-pipeline) — adds new domain. Wave-3 (multi-agent) — adds new pattern (co-selection). Wave-4 (compliance) — adds new ICP (regulated). Wave-5 adds new endpoint surface across all existing domains. Once shipped, every IDF domain gets /decisions for free. Highest leverage.

But also highest design risk:

  • Performance: lineage query for a row touched by 100+ effects requires careful indexing. Φ schema has parent_id chain — must traverse efficiently.
  • Authorization: lineage exposes who-did-what. filterWorldForRole must apply to lineage rows too — can't show preparer in case study to other preparer.
  • PII: even with role-filter, raw cells in lineage can contain PII. Need redaction policy similar to gapPolicy already in /api/agent/world.

Implementation paths

Path A — minimal viable (~1-2 days):

  • New server/routes/document.js endpoint :domain/decisions
  • Recursive lineage traversal via parent_id (already in Φ schema)
  • JSON output only
  • Apply filterWorldForRole to each effect row before inclusion
  • Example domain: invest, where decisions are: delegate_to_agent, agent_execute_preapproved_order, recompute_risk_score

Path B — full document materialization (~1 week):

  • Path A +
  • HTML output (server-side rendered with the IDF document materialiser — same one that powers /api/document)
  • PDF output (downstream — server-side puppeteer or pdf-lib)
  • React component primitive (renderer package): <DecisionLineageView> — for in-app use
  • Counterfactual hook: ?withoutEffect=e_xyz query param → folds Φ minus that effect

Path C — runtime XAI surface (~2-3 weeks, post-wave-4):

  • Path B +
  • Live SSE channel /api/document/:domain/decisions/stream — agent or auditor subscribes
  • Compliance-aligned export formats (regulatory schema TBD: SR 11-7 audit format? GDPR Art 22? FDA SaMD?)
  • Custom domain decisions.fold.software if we go enterprise

Three rejection types this surface showcases

This is not a new domain, so rejection types overlap with existing domains. But the lineage view exposes them as queryable:

  1. Failed condition — agent tries release_payment on uncompleted deal. Lineage shows the rejected effect with failedCondition: { entity: "deal", field: "status", op: "=", expected: "completed", actual: "in_progress" }.
  2. Invariant violation cascade — Φ has a cascadeReject trail: when invariant fires post-confirmation, it can rollback subsequent effects. Lineage shows the cascade tree.
  3. Preapproval daily-sum hit — agent's 8th order today, dailySum exceeded. Lineage records all 7 preceding orders + the rejection.

What's new that previous waves don't carry

  • First read-only-but-rich endpoint: previous quickstarts only show exec (write) + world (snapshot read). Decisions endpoint is a historical / temporal read.
  • First time provenance becomes a product feature, not implementation detail: Wave-1-4 use Φ as engine. Wave-5 sells Φ as the artifact.
  • Bridges to wave-4: compliance domain's "why was this approved" becomes one URL. Wave-4 enterprise sales motion uses wave-5 endpoint as the demo.

Open questions

  1. PDF generation in Docker quickstart? Would balloon the image (puppeteer ~150MB). Lean: skip PDF for quickstart, offer JSON+HTML.
  2. Counterfactual queries (?withoutEffect=) are computationally expensive — full Φ re-fold per query. Acceptable for low-traffic enterprise audit surface, not for high-frequency. Lean: rate-limit or paid-tier.
  3. Should this be cross-domain? I.e., /api/document/global/decisions?entity=... aggregating across all domains. Useful for federated audit. Hard for: scoping, performance, auth. Lean: per-domain only in wave-5; cross-domain is wave-6.
  4. Do agents themselves consume /decisions? Probably yes — gives them retrospective awareness. But that's also recursive: agents learning from past rejections. Lean: yes, expose via /api/agent/:domain/decisions mirror of document endpoint with same role-filter.

When to ship

Two scenarios:

Scenario A (most likely): After wave-2 ships and gets some "but where's the audit trail" feedback in HN/X comments. That's the inbound signal that this is the next-asked feature.

Scenario B (if wave-4 path opens): Enterprise design partner explicitly asks for SOX-404 audit-trail format. Wave-5 becomes the deliverable for that pilot.

Don't open this if:

  • Wave-1-3 metrics show people care about building agents, not auditing agents. Then this is over-engineering for the actual user.
  • We commit to wave-4 (enterprise compliance) before wave-2 (dev-tool depth). In that case wave-5 becomes part of wave-4 deliverables, not a separate issue.

Source narrative

Φ has carried decision-provenance since the first day. Wave-5 makes it queryable.

"Software you can interrogate."

If wave-5 ships, the comparison-table across competitors gets a new row:

LangChain Permit.io Lakera Datadog Audit Fold
Logs what was called partial
Logs what was rejected partial
Logs why with structured lineage
Counterfactual: "what would've happened"

This is the row no one else has. Wave-5 productizes it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions