DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path foray-reference/foray-protocol-deep-read-v0_1.md

FORAY Protocol Deep-Read v0.1

Produced 2026-05-24 by CC against the canonical FORAY documentation in /Users/dunin7/foray-kaspathon at commit 18727b4 (branch main, pull-first verified).

This document fills specific gaps in Claude.ai's understanding of FORAY that the substrate-review primer summarized but did not enumerate. Read alongside the primer (foray-protocol-primer-for-loomworks-substrate-v0_1.md); not a replacement for it.


Source material read

| Path (relative to /Users/dunin7/foray-kaspathon/) | Size | Date | Purpose in this deep-read | |---|---|---|---| | FORAY_Protocol_v4_1_Specification.md | 1,561 lines / 48 KB | 2026-02-14 | Topics 1, 7 (Attestation rules and framing) | | guides/FORAY_Attestation_Trust_Model.md | 304 lines / ~13 KB | 2026-01-31 | Topic 4 (Type 1 / Type 2 trust model) | | docs/DUNIN7_FORAY_Schema_Reference.md | 621 lines / ~31 KB | 2026-03-26 | Topics 5, 6, 7 (submission envelope, edge cases, framing) | | docs/DUNIN7_FORAY_Schema_Reference_2026-03-26.md | 448 lines | 2026-03-26 | Earlier snapshot of the same doc; cross-reference | | examples/manuka-honey-provenance-v41.json | 330 lines | 2026-02-14 | Topic 3 (worked transaction) | | integration-guide.html | ~28 KB | 2026-02-14 | Topic 5 (anchor service operational description) | | README.md | 18 KB | 2026-05-24 | Topic 5 (anchor service framing) | | foray-api-server.js | 40 KB | 2026-02-14 | Topic 5 (cross-check — generation server, not anchor) | | quickbooks-adapter.js | 19 KB | 2026-02-14 | Topic 5 (cross-check — SDK call shape) | | proxy-server.js | 3 KB | 2026-02-14 | Topic 5 (cross-check — CORS proxy only) |

Documents named by the kickoff but not present in the repository:


Section 1 — Attestation validation rules ATT-001 through ATT-006

Source: FORAY_Protocol_v4_1_Specification.md §9.6 (Validation Rules).

The v4.1 spec presents the rules as a single short table, not as numbered prose with examples. The rules and their descriptions, reproduced verbatim:

| Rule | Description | |------|-------------| | ATT-001 | id must be unique and begin with ATT_ | | ATT-002 | subject_refs must reference valid component IDs | | ATT-003 | attestation_date must not be in the future | | ATT-004 | If validity_period.end < current date, outcome should be expired | | ATT-005 | attestor_hash must be valid SHA-256 | | ATT-006 | Circular attestation references are prohibited |

Interpretation and observations:

Examples in the spec: none. The rules table is presented without per-rule examples. §9.7 (Trust Model) gives the higher-level "what attestations prove / do not prove" framing but no concrete validation-failure walkthrough.

What violating each rule produces: the spec does not assign error severity, error codes, or remediation guidance. It says only that these are "Validation Rules." Treat all six as validation errors by default, with the noted caveat that ATT-004 uses should.


Section 2 — Audit data extension and audit profiles

Source asked for: FORAY_Protocol_v4_0_Specification.md §3 (Audit Data Extension). Status: The v4.0 spec is not present in the repository. The v4.1 spec, the Schema Reference, the guides, and the example transactions do not define audit_data structurally either. Only the audit_data_anchor field on the top-level envelope is defined, and only the four enum values for audit_profile are stated by name (without per-profile field requirements).

What is present in the v4.1 spec (Top-Level Schema, §2.1):


"audit_data_anchor": {
  "audit_data_hash": "sha256:...",
  "audit_profile": "standard|dcaa_full|big4|minimal",
  "storage_locations": [...]
}

This is the only structural definition in the v4.1 spec. The four audit_profile values are standard, dcaa_full, big4, minimal. The spec also marks audit_data_anchor itself as optional in §2.2 ("Required: No").

The v4.1 spec defers four times: in §§4.2, 4.3, 4.4, 4.5 (examples for cash sale, depreciation, payment, RMBS), the audit_data block is consistently shown as:


"audit_data": {
  "...see audit_data specification..."
}

This placeholder appears in all four worked examples in the spec body. There is no audit_data specification document in the repository to follow that pointer to.

What the examples show in practice:

In examples/manuka-honey-provenance-v41.json, the audit_data_anchor carries only the three documented fields:


"audit_data_anchor": {
  "audit_data_hash": "sha256:manuka_audit_data...",
  "audit_profile": "standard",
  "storage_locations": ["s3://foray-audit/2026/Q1/PROV_2026_Q1_MANUKA_HONEY_BATCH_001"]
}

The actual audit_data payload is not inlinestorage_locations points to off-chain storage (here an S3 prefix). None of the 12 example files inline an audit_data block; all use the anchor-only pattern.

Profile differences: not documented in this repository. The four enum values are mentioned by name in:

…but nowhere is it stated what each profile contains, what the field-level differences are, whether minimal is a strict subset of standard, or whether profiles can be mixed within a transaction.

Relationship between foray_core and audit_data (what the spec does say):

The v4.1 spec's design rationale and the Schema Reference both emphasize the layered architecture:

> "Audit Data Extension — 3-layer architecture, sealed archive" — v4.0 release notes summary in FORAY_Protocol_v4_1_Specification.md §Version History

> "The core never grows. The mandatory dataset is the minimum required to describe any business transaction. Adding fields to accommodate edge cases breaks the universality that makes FORAY valuable." — Schema Reference §1 Principle 2

The architecture is: (a) foray_core is on-chain — the minimum to identify the transaction; (b) the four (or five with attestations) component arrays carry the deal structure — hashed individually into component_hashes; (c) audit_data is off-chain detail referenced by a single hash in audit_data_anchor. The primer's "hashed separately" claim is consistent with this layering — the on-chain anchor commits to merkle_root (over component_hashes) and separately to audit_data_hash. But the spec does not enumerate exactly what is in audit_data at each profile level.

Transaction-wide vs mixable: not documented. audit_profile is a single string on the transaction-level audit_data_anchor. There is no per-component audit_profile field anywhere in the schema. The natural reading is that the profile is transaction-wide, but the spec does not state this explicitly.

Things asked for that aren't in the source:

If Claude.ai needs these details, the v4.0 spec (which the kickoff names as the source) appears to be the only document that would carry them, and it is not in the local repository. The Operator may have it elsewhere.


Section 3 — A worked transaction — complete example with all components

Source: examples/manuka-honey-provenance-v41.json (330 lines).

This is the canonical complex v4.1 example. It is a Type 2 (attestation) provenance transaction with all five component arrays populated (ARR×2 + ACC×2 + ANT×2 + ACT×2 + ATT×3) and explicit dependency / _refs[] chains throughout.

Reproduced in full:


{
  "transaction_id": "PROV_2026_Q1_MANUKA_HONEY_BATCH_001",
  "schema_version": "4.1",
  "timestamp": "2026-01-15T09:00:00Z",

  "foray_core": {
    "entity": "Waikato Apiaries Ltd",
    "entity_hash": "sha256:wal_2026_abc123...",
    "transaction_type": "product_provenance",
    "total_value": 185000.00,
    "currency": "NZD",
    "status": "completed",
    "compliance_flags": ["MPI_Export_Certified", "UMF_Licensed", "ISO_22000"]
  },

  "component_hashes": {
    "arrangements": "sha256:arr_manuka_a1b2c3...",
    "accruals": "sha256:acc_manuka_d4e5f6...",
    "anticipations": "sha256:ant_manuka_g7h8i9...",
    "actions": "sha256:act_manuka_j0k1l2...",
    "attestations": "sha256:att_manuka_m3n4o5..."
  },

  "arrangements": [
    {
      "id": "ARR_UMF_LICENSE_2026",
      "foray_core": {
        "type": "origin_certification",
        "effective_date": "2026-01-01T00:00:00Z",
        "parties": [
          { "role": "producer", "name": "Waikato Apiaries Ltd", "jurisdiction": "NZ" },
          { "role": "certifier", "name": "UMF Honey Association", "jurisdiction": "NZ" },
          { "role": "laboratory", "name": "Analytica Laboratories", "jurisdiction": "NZ" }
        ],
        "description": "UMF certification license for authentic New Zealand Manuka Honey",
        "total_value": 185000.00,
        "currency": "NZD",
        "terms": {
          "certification_type": "UMF_Licensed_Producer",
          "license_number": "UMF-2026-0847",
          "valid_until": "2026-12-31",
          "annual_audit_required": true
        },
        "dependencies": []
      }
    },
    {
      "id": "ARR_BATCH_DEFINITION_2026_001",
      "foray_core": {
        "type": "production_batch",
        "effective_date": "2026-01-10T00:00:00Z",
        "parties": [
          { "role": "producer", "name": "Waikato Apiaries Ltd", "jurisdiction": "NZ" }
        ],
        "description": "Production batch MH-2026-001 - 500kg UMF 15+ Manuka Honey",
        "total_value": 185000.00,
        "currency": "NZD",
        "terms": {
          "batch_id": "MH-2026-001",
          "weight_kg": 500,
          "jar_count": 1000,
          "jar_size_g": 500,
          "harvest_date": "2025-12-20",
          "extraction_date": "2025-12-22",
          "apiary_region": "Waikato, North Island",
          "hive_source_ids": ["HIVE-W-042", "HIVE-W-043", "HIVE-W-044"]
        },
        "dependencies": ["ARR_UMF_LICENSE_2026"]
      }
    }
  ],

  "accruals": [
    {
      "id": "ACC_LABORATORY_ANALYSIS_001",
      "foray_core": {
        "arrangement_refs": ["ARR_BATCH_DEFINITION_2026_001", "ARR_UMF_LICENSE_2026"],
        "type": "product_analysis",
        "description": "Laboratory analysis results for batch MH-2026-001",
        "computation_method": "Valuation",
        "formula_id": "sha256:umf_analysis_protocol_v2...",
        "inputs": {
          "sample_id": "SAMPLE-MH-2026-001-A",
          "analysis_date": "2026-01-12",
          "methodology": "UMF_Grading_Standard_v4"
        },
        "output": 185000.00,
        "currency": "NZD",
        "analysis_results": {
          "mgo_mg_kg": 514,
          "dha_mg_kg": 1250,
          "hmo_mg_kg": 42,
          "leptosperin_mg_kg": 185,
          "umf_rating": 15,
          "umf_grade": "UMF 15+",
          "npa_equivalent": 15.2,
          "moisture_percent": 17.8,
          "hmf_mg_kg": 12,
          "diastase_number": 18,
          "authenticity_markers": {
            "c4_sugar_percent": 0.8,
            "pollen_analysis": "Leptospermum scoparium dominant",
            "dna_verified": true
          },
          "classification": "Authentic Monofloral Manuka",
          "grade_confirmed": true
        },
        "dependencies": ["ARR_BATCH_DEFINITION_2026_001"]
      }
    },
    {
      "id": "ACC_BATCH_VALUATION_001",
      "foray_core": {
        "arrangement_refs": ["ARR_BATCH_DEFINITION_2026_001"],
        "type": "inventory_valuation",
        "description": "Batch valuation at export wholesale price",
        "computation_method": "Calculated",
        "formula_id": "sha256:valuation_weight_x_grade_price...",
        "inputs": {
          "weight_kg": 500,
          "umf_grade": "UMF 15+",
          "price_per_kg_nzd": 370.00
        },
        "output": 185000.00,
        "currency": "NZD",
        "dependencies": ["ARR_BATCH_DEFINITION_2026_001"]
      }
    }
  ],

  "anticipations": [
    {
      "id": "ANT_EXPORT_DISTRIBUTION_2026_001",
      "foray_core": {
        "accrual_refs": ["ACC_BATCH_VALUATION_001"],
        "arrangement_refs": ["ARR_BATCH_DEFINITION_2026_001"],
        "type": "scheduled_distribution",
        "description": "Expected export distribution to international partners",
        "expected_amount": 185000.00,
        "currency": "NZD",
        "expected_date": "2026-02-15",
        "probability_factor": 0.95,
        "distribution_plan": {
          "export_markets": ["China", "UK", "USA", "Japan"],
          "jars_per_market": { "china": 400, "uk": 250, "usa": 200, "japan": 150 },
          "mpi_export_certificate_required": true
        },
        "dependencies": ["ACC_BATCH_VALUATION_001"]
      }
    },
    {
      "id": "ANT_SHELF_LIFE_WINDOW_001",
      "foray_core": {
        "accrual_refs": ["ACC_LABORATORY_ANALYSIS_001"],
        "arrangement_refs": ["ARR_BATCH_DEFINITION_2026_001"],
        "type": "quality_validity_window",
        "description": "Expected shelf life based on analysis results",
        "expected_amount": 0,
        "currency": "NZD",
        "expected_date": "2031-01-15",
        "probability_factor": 0.95,
        "quality_parameters": {
          "best_before_date": "2031-01-15",
          "optimal_storage_temp_c": "below 25",
          "light_exposure": "protected",
          "note": "Honey does not spoil; UMF activity may decrease over time"
        },
        "dependencies": ["ACC_LABORATORY_ANALYSIS_001"]
      }
    }
  ],

  "actions": [
    {
      "id": "ACT_JARRING_COMPLETE_001",
      "foray_core": {
        "anticipation_refs": ["ANT_EXPORT_DISTRIBUTION_2026_001"],
        "accrual_refs": ["ACC_LABORATORY_ANALYSIS_001", "ACC_BATCH_VALUATION_001"],
        "arrangement_refs": ["ARR_BATCH_DEFINITION_2026_001"],
        "type": "production_completion",
        "description": "Jarring completed for batch MH-2026-001",
        "amount_settled": 185000.00,
        "currency": "NZD",
        "settlement_date": "2026-01-15T09:00:00Z",
        "settlement_status": "completed",
        "payment_method": "other",
        "counterparty": "Internal",
        "production_details": {
          "jars_produced": 1000,
          "jars_passed_qc": 998,
          "jars_rejected": 2,
          "rejection_rate_percent": 0.2,
          "tamper_seal_applied": true,
          "umf_label_applied": true
        },
        "dependencies": ["ANT_EXPORT_DISTRIBUTION_2026_001"]
      }
    },
    {
      "id": "ACT_UMF_CERTIFICATION_ISSUED_001",
      "foray_core": {
        "anticipation_refs": [],
        "accrual_refs": ["ACC_LABORATORY_ANALYSIS_001"],
        "arrangement_refs": ["ARR_UMF_LICENSE_2026", "ARR_BATCH_DEFINITION_2026_001"],
        "type": "certification_issuance",
        "description": "UMF certificate issued for batch MH-2026-001",
        "amount_settled": 0,
        "currency": "NZD",
        "settlement_date": "2026-01-14T14:00:00Z",
        "settlement_status": "completed",
        "payment_method": "other",
        "counterparty": "UMF Honey Association",
        "certificate_details": {
          "certificate_number": "UMF-BATCH-2026-00847",
          "issued_by": "UMF Honey Association",
          "valid_for_batch": "MH-2026-001",
          "umf_grade_certified": "UMF 15+",
          "mgo_verified_mg_kg": 514,
          "qr_verification_url": "https://umf.org.nz/verify/UMF-BATCH-2026-00847"
        },
        "dependencies": ["ACC_LABORATORY_ANALYSIS_001"]
      }
    }
  ],

  "attestations": [
    {
      "id": "ATT_LAB_ANALYSIS_001",
      "foray_core": {
        "attestor": "Analytica Laboratories",
        "attestor_hash": "sha256:analytica_nz_2026...",
        "attestor_type": "laboratory",
        "attestor_credentials": ["IANZ_Accredited", "MPI_Recognized", "ISO_17025"],
        "subject_refs": ["ACC_LABORATORY_ANALYSIS_001"],
        "attestation_type": "analysis",
        "attestation_date": "2026-01-12T16:30:00Z",
        "validity_period": { "start": "2026-01-12", "end": "2027-01-12" },
        "outcome": "certified",
        "evidence_hash": "sha256:lab_report_mh2026001...",
        "evidence_location": "off-chain",
        "analysis_summary": {
          "mgo_result_mg_kg": 514,
          "leptosperin_result_mg_kg": 185,
          "dna_verified": true,
          "methodology": "UMF_Grading_Standard_v4"
        },
        "dependencies": []
      }
    },
    {
      "id": "ATT_UMF_CERTIFICATION_001",
      "foray_core": {
        "attestor": "UMF Honey Association",
        "attestor_hash": "sha256:umf_assoc_nz_2026...",
        "attestor_type": "certification_body",
        "attestor_credentials": ["NZ_Govt_Recognized", "Trademark_Owner_UMF", "MPI_Partner"],
        "subject_refs": ["ARR_UMF_LICENSE_2026", "ARR_BATCH_DEFINITION_2026_001", "ATT_LAB_ANALYSIS_001"],
        "attestation_type": "certification",
        "attestation_date": "2026-01-14T14:00:00Z",
        "validity_period": { "start": "2026-01-14", "end": "2026-12-31" },
        "outcome": "certified",
        "evidence_hash": "sha256:umf_certificate_mh2026001...",
        "evidence_location": "off-chain",
        "certificate_details": {
          "certificate_number": "UMF-BATCH-2026-00847",
          "umf_grade": "UMF 15+",
          "qr_verification_url": "https://umf.org.nz/verify/UMF-BATCH-2026-00847"
        },
        "dependencies": ["ATT_LAB_ANALYSIS_001"]
      }
    },
    {
      "id": "ATT_MPI_EXPORT_001",
      "foray_core": {
        "attestor": "Ministry for Primary Industries",
        "attestor_hash": "sha256:mpi_nz_govt_2026...",
        "attestor_type": "regulator",
        "attestor_credentials": ["NZ_Government_Authority", "Food_Safety_Regulator", "Export_Certification_Authority"],
        "subject_refs": ["ARR_BATCH_DEFINITION_2026_001", "ATT_UMF_CERTIFICATION_001"],
        "attestation_type": "approval",
        "attestation_date": "2026-01-15T08:00:00Z",
        "validity_period": { "start": "2026-01-15", "end": "2026-07-15" },
        "outcome": "approved",
        "evidence_hash": "sha256:mpi_export_cert_mh2026001...",
        "evidence_location": "off-chain",
        "export_details": {
          "export_certificate_number": "MPI-EXP-2026-NZ-00847",
          "approved_markets": ["China", "UK", "USA", "Japan"],
          "health_certificate_included": true
        },
        "dependencies": ["ATT_UMF_CERTIFICATION_001"]
      }
    }
  ],

  "merkle_root": "sha256:manuka_batch_001_merkle_root...",

  "blockchain_anchor": {
    "kaspa_tx_id": "kaspa:qr_manuka_batch_001...",
    "block_height": 2950000,
    "confirmation_time_ms": 1100,
    "anchored_at": "2026-01-15T09:00:02Z"
  },

  "audit_data_anchor": {
    "audit_data_hash": "sha256:manuka_audit_data...",
    "audit_profile": "standard",
    "storage_locations": ["s3://foray-audit/2026/Q1/PROV_2026_Q1_MANUKA_HONEY_BATCH_001"]
  },

  "privacy_metadata": {
    "formulas_obfuscated": 2,
    "instance_pools": 3,
    "attack_complexity": "2^96 operations"
  }
}

Commentary — how the references compose, where attestations attach, what the hashes commit to

The reference structure forms a directed acyclic graph. There are two distinct reference fabrics:

  1. The intra-DAG _refs[] fabric — every component except Arrangements carries arrangement_refs[], every component below Accruals carries accrual_refs[], every component below Anticipations carries anticipation_refs[]. These are upstream references — an Action declares which Anticipations it resolves, which Accruals it satisfies, and which Arrangements authorized it. They form chains:

This is the "DAG" the primer names: nodes are typed components; edges are typed upward references; the topology is built by the submitter.

  1. The attestation fabric — structurally separate. Attestations do not appear in any _refs[] array on any component. They reach into the DAG via subject_refs[] on the attestation itself — a one-way pointer. In the example:

This is the structural reason the primer calls attestation "cross-cutting": the DAG components have no knowledge of which attestations point at them. The reference is always from attestation into subject, never back.

Where attestations attach. Three distinct attachment patterns in this example:

The chain primitive uses the same subject_refs[] field — there is no separate chain_refs[]. An attestation that references prior attestations is structurally identical to one that references components.

What the hashes commit to. Four hash-bearing fields commit at different layers:

The Type 2 framing in this example. The transaction is anchored against three independent attestors (laboratory, certification body, regulator) with progressive chain dependency (lab → certifier → regulator). FORAY does not certify the honey is Manuka — it certifies that the lab analyzed it, that UMF certified the lab's analysis, and that MPI approved the certification for export. This is the canonical "attestation transaction" shape: identified parties making sequential claims under specific credentials, with the chain itself anchored.


Section 4 — Type 1 / Type 2 trust model — what attestations prove and don't

Source: guides/FORAY_Attestation_Trust_Model.md (304 lines), authored 2026-01-31, modified 2026-02-01.

The distinction

The trust model document is explicit:

> "FORAY transactions fall into two broad categories with different trust characteristics:"

Type 1: System-of-Record Transactions — "These transactions record events within authoritative business systems where the system itself is the source of truth."

> "Examples: ERP journal entries (SAP, Oracle, QuickBooks), Bank payment confirmations, Manufacturing work orders, Payroll processing." > > "Trust Model: The ERP/financial system is authoritative. When QuickBooks records a payment, the payment occurred. FORAY anchors this fact with external, tamper-evident proof." > > "FORAY Value: Proves the record existed at a point in time and hasn't been altered — even by system administrators."

Type 2: Attestation Transactions — "These transactions record claims about external reality made by identified parties."

> "Examples: Product provenance (Manuka honey origin, watch authenticity), Laboratory certifications (spectroscopic analysis), Third-party inspections, Compliance attestations." > > "Trust Model: FORAY anchors a chain of attestations, not independent truth. The value depends entirely on trusting the attestors." > > "FORAY Value: Creates a tamper-evident record of who claimed what, when — enabling accountability and dispute resolution."

How a transaction's type is determined

The trust model does NOT declare Type as a typed field. Type 1 / Type 2 is a categorisation imposed by the framing document, not a transaction-level field present in the schema. The distinction is inferred from structure:

There is no transaction_kind or trust_model field in foray_core. The trust-model document treats this as a conceptual taxonomy, not a typed dimension.

Important nuance: the v4.1 spec (§9.1 "When to Use Attestations") lists transaction types where attestations are appropriate vs not — but this is a usage guide, not a structural constraint. A "product provenance" transaction can in principle ship without attestations (lossy, but valid); a "cash sale" can in principle ship with attestations (over-the-top, but valid). The structural rule is the validation rules; the Type 1 / Type 2 label is editorial.

What attestations prove

From §9.7 of the v4.1 spec (Trust Model), reproduced exactly:

> What Attestations Prove: > - A specific party made a specific claim at a specific time > - The claim has not been altered since anchoring > - The attestor's credentials are recorded

From the trust model document, the equivalent framing:

> "Temporal proof — A specific claim was recorded at a specific point in time" > "Integrity proof — The recorded data has not been altered since anchoring" > "Consistency proof — Multiple parties can verify they hold identical records" > "Sequence proof — Events occurred in a verifiable order"

What attestations do NOT prove

From v4.1 spec §9.7, reproduced exactly:

> What Attestations Do NOT Prove: > - The claim is true > - The attestor is competent > - Physical reality matches the digital record

The trust model document expands this into a four-row table (reproduced exactly):

> | Limitation | Explanation | > | Truth of claims | FORAY anchors assertions, not facts — if a party claims "this honey is authentic Manuka from New Zealand," FORAY proves they made that claim, not that it's true | > | Physical reality | Digital records cannot independently verify physical world states | > | Attestor competence | A laboratory's certification is only as reliable as the laboratory | > | Data accuracy at source | "Garbage in, garbage out" — FORAY trusts validated source system data |

The exact wording around boundary

From the trust model document, the key sentence — reproduced exactly:

> This is not a weakness to hide — it is a boundary to understand. Every audit system shares these limitations. FORAY's contribution is making the recorded claims tamper-evident and the claimants accountable.

And the closing summary table (reproduced exactly):

> | Transaction Type | Source of Truth | FORAY Proves | Trust Assumption | > | System-of-Record | ERP/Financial System | Record integrity + timestamp | System is authoritative | > | Attestation | Identified Parties | Claims were made + timestamp | Attestors are trustworthy |

Substrate implications

The trust-model document does not directly address the question "does the substrate need a Type 1 / Type 2 discriminator?". Reading the protocol material:

Honest reading of the source: the trust model is editorial categorisation, not a structural feature of the schema. The substrate can implement a discriminator if it makes substrate-side queries cleaner, but doing so is a substrate decision, not a protocol mandate.


Section 5 — The FORAY anchor service — operational interface

Status: The "FORAY anchor service" as a separately defined operational interface is not documented in the local repository as an HTTP API, library, or service contract. The repository contains:

  1. The protocol description — what anchoring conceptually means.
  2. Per-source adapters (quickbooks-adapter.js, salesforce-adapter.js) that call into an ForaySDK module.
  3. The submission envelope in the Schema Reference — the closest thing to a service-interface contract.

The SDK module is referenced but absent. quickbooks-adapter.js:24 reads:


const ForaySDK = require('./foray-sdk');

— and the file foray-sdk.js is not in the repository. The adapter calls into this.sdk.anchorToBlockchain(transaction) (line 309, 389, 457 of quickbooks-adapter.js) and this.sdk.createArrangement(...) etc. for component construction. These are the only points where the calling code touches the anchor surface. The SDK implementation is private to this repo's local clone or has been pruned from public distribution.

The two API servers in this repo are not the anchor service. foray-api-server.js exposes three endpoints — /api/generate-foray, /api/analyze-business, /api/describe-transaction. All three are Claude-powered demo endpoints for constructing FORAY JSON from natural-language input, not for anchoring it. proxy-server.js is a CORS proxy in front of those. Neither submits to a blockchain.

What can be reconstructed from the repository

From the integration guide (integration-guide.html):

> "The universal FORAY integration pattern follows five steps, regardless of source system: > 1. Extract — Pull transaction data from ERP via API, webhook, or scheduled export > 2. Transform — Map to FORAY's 4-component model (Arrangements, Accruals, Anticipations, Actions) > 3. Hash — Generate component hashes, compute merkle root, apply privacy obfuscation > 4. Anchor — Submit merkle root to Kaspa blockchain > 5. Store — Archive full transaction JSON with blockchain anchor reference"

> "Phase 3: Anchor > - Submit merkle root to Kaspa blockchain > - Receive transaction ID and block confirmation > - Store full FORAY JSON with anchor reference > - Return confirmation to source system (optional)"

> "Kaspa's sub-second block times and minimal transaction costs (approximately \$0.0001 per anchor) make real-time anchoring economically feasible even for high-volume enterprises."

This is the operational outline. The "service" is functionally: a process that takes a constructed FORAY JSON, computes (or accepts) the merkle root, broadcasts it to Kaspa, and writes back the blockchain_anchor block (kaspa_tx_id, block_height, confirmation_time_ms, anchored_at). The repo does not state whether this runs in-process (library), out-of-process (CLI), or as a service.

From the README:

> "FORAY anchors cryptographic fingerprints of your transactions and agent actions to Kaspa's blockchain in real-time. The data stays in your systems. Only the proof goes on-chain."

> "Kaspa's 1-second blocks enable real-time anchoring as transactions happen — not batch processing hours later. GHOSTDAG consensus provides high throughput without sacrificing decentralisation."

From the foray-api-server.js generation prompt (note: this is the generator service, not the anchor service):

> "IMPORTANT: The 'blockchain_anchor' fields (kaspa_tx_id, block_height, confirmation_time_ms, anchored_at) MUST all be null when generating transactions. Blockchain anchoring happens AFTER generation when the user clicks 'Anchor'. Never generate fake values for these fields."

This confirms the temporal sequence: construct → submit to anchor → receive blockchain_anchor block back. It does not document the anchor-submission interface itself.

The closest thing to a service contract — the Submission Envelope

The Schema Reference (2026-03-26) §4.1 defines a "submission envelope" that is the most service-interface-like artifact in the repository:


{
  "foray_submission": {
    "schema_version": "1.0",
    "transaction_id": "<SHA-256 hash>",
    "parent_reference": { "type": null, "id": null },
    "submission_type": "",
    "submission_timestamp": "",
    "persistence": [],
    "boundaries": { ... },
    "arrangement": {},
    "accruals": [],
    "anticipations": [],
    "actions": []
  }
}

| Field | Description (from §4.1) | |---|---| | submission_type | "new" / "amendment" / "component" — first submission for this transaction_id, append-only correction, or addition to an existing transaction | | persistence[] | Persistence layer declarations (see below) | | parent_reference | Null if originating; otherwise points to parent Transaction or Accrual |

Critically, §4.2 (Persistence Layer Declaration) clarifies the anchor relationship:

> "FORAY is persistence-layer agnostic. The submitting party declares which persistence layer or layers to use. FORAY executes the anchoring according to the declaration. The cost is borne by the initiator."


"persistence": [
  {
    "layer": "",
    "layer_version": null,
    "layer_parameters": {}
  }
]

> "Required persistence layer properties for FORAY compatibility: Tamper-evident · Independently verifiable · Append-only · Timestamped · Durable · Accessible"

This makes the anchor "service" architecturally clearer:

Synchronous vs asynchronous

The repo does not state whether anchor submission is synchronous (the caller blocks until the anchor confirmation comes back) or asynchronous (the caller submits and polls or receives a callback). The adapter code uses await this.sdk.anchorToBlockchain(transaction) which is consistent with synchronous-via-async — the call returns once the blockchain has confirmed.

Kaspa's 1-second block times make a synchronous flow feasible (a 1-2 second wait is the documented latency, per integration-guide.html: "Real-time (immediate anchoring) < 2 seconds"). The bigger picture from the integration guide:

| Scenario | Strategy | Latency | |---|---|---| | High-value individual transactions | Real-time (immediate anchoring) | < 2 seconds | | Routine daily transactions | Batch (end-of-day) | Hours | | Month-end adjustments | Batch (period close) | End of period | | Regulatory filings | Real-time (regulatory timing) | < 2 seconds | | High-volume POS | Micro-batch (every 15 minutes) | Minutes |

— so the operating model supports both real-time and batched/micro-batched submission. The choice is per-deployment.

Honest summary

There is enough material in the local repository to know the conceptual shape: the submitting system constructs a FORAY envelope with a declared persistence layer, submits it to a layer-specific service (probably via the absent foray-sdk.js), receives a blockchain_anchor block with kaspa_tx_id and block_height once the persistence layer confirms, and stores the resulting full transaction JSON with the anchor reference. There is not enough material to know the exact wire interface — endpoint URL, request body shape, response shape, error codes, auth model — because the foray-sdk.js and any HTTP API contract are not present in the local clone.

If Loomworks' substrate-side design needs to integrate against an anchor service, the substrate is currently designing against an under-documented surface. The protocol-level abstraction (the persistence layer declaration) is documented; the operational interface is not. This is worth flagging to the Operator.


Section 6 — Transaction boundary edge cases

Source asked for: FORAY_Transaction_Boundary_Analysis.md. Status: A file by that name is not in the repository. The closest material is in docs/DUNIN7_FORAY_Schema_Reference.md (2026-03-26), specifically §5 (Asset Behaviour Taxonomy), §6 (Transaction Record Configurations), §7 (Multi-Behaviour Combination Rules), §10.3 (Edge Cases & Unusual Transactions), §11 (Schema Additions from Second Validation Pass), and §12 (Initial Transaction Validation Reference — Set Two). I treat that material as the canonical boundary analysis available.

What an edge case is, in FORAY's terms

The Schema Reference frames edge cases not as "anomalies that break the protocol" but as transactions where the asset's behaviour reveals a corner of the four-component model that simpler transactions don't exercise. §5 identifies nine asset behaviour types — extensively investigated; no tenth has emerged. The behaviours, with the boundary structure each one tests:

| # | Behaviour | Boundary feature exercised | |---|---|---| | 1 | Complete Transfer | Baseline — ARR + ACC + ANT + ACT, single asset moving one direction | | 2 | Conditional Transfer | Two competing Anticipations exist simultaneously; one resolves with an Action, the other is retired without generating an Action. The retired Anticipation is the reversal-path artifact. | | 3 | Transformation | Input asset is consumed, output asset is created — they are related but not the same asset. Two Actions in one Arrangement. | | 4 | Consumption | The asset ceases to exist with no output. Action records disappearance, not transfer. | | 5 | Governing Reference | The asset never moves — only its derivative obligation does. The reference asset appears in Accrual Properties, never in an Action. | | 6 | Creation | The asset did not exist before the transaction. It is brought into existence by the Arrangement itself. | | 7 | External Destruction | An external event destroys the primary asset. Destruction Action has no recipient. Cause is observable in record but outside the protocol's scope. | | 8 | Right | Right-grant and right-exercise are separate transactions linked by lineage. The right's existence is one Arrangement; each exercise is a child transaction. | | 9 | Perceived Value | The valuation oracle is the only source of value. The transaction is real; the value is agreed, not derived. |

Specific edge cases the kickoff names

System-generated transactions. The Schema Reference does not name this term explicitly. The closest material is in §10.3 (Edge Cases & Unusual Transactions):

— and the Action component definition (§2.4): Action Type admits two values — Transfer and State Change. State Change is "condition confirmed without asset movement — From Party and To Party are the same party." This is the structural admission of system-generated transactions: the protocol accepts state changes as Actions even when no asset moved.

Date-range transactions instead of point-in-time. The Schema Reference does not use the term "date-range transaction" directly. Several edge cases imply continuous-time behaviour:

The protocol does not require timestamps to be point-in-time; ranges and distributions are first-class.

Reversal patterns. Three distinct treatments appear in the Schema Reference:

  1. Reversal as a retired Anticipation (Conditional Transfer, §5):

> "Two possible outcomes exist simultaneously — completion or reversal." > "Action: Resolves to one path only. The other Anticipation is retired without generating an Action."

  1. Reversal as an Accrual that reverses direction (§12.5 Government and Public Sector):

> "Tax Payment & Refund Cycle | Formula-based Accrual | Accrual obligation can reverse direction between parties." > "Government Grant with Clawback | Conditional Transfer | Clawback is conditional transfer in reverse — asset already transferred may return."

  1. Reversal as a non-monotonic Accrual (§10.3 Carried Interest):

> "Accrual is non-monotonic — reverses and rebuilds. Anticipation is awareness until liquidity event."

The protocol expresses reversal through the component lifecycle, not through a reversed flag on the transaction. There is a status: "reversed" value on the top-level envelope in the v4.1 spec's §2.1 schema ("status": "active|completed|reversed"), but the Schema Reference's framing is that reversal is a structural lifecycle event, not a status flip — the underlying components carry the reversal mechanics.

The Amendment Protocol — boundary case for any transaction

§4.4 of the Schema Reference is the most precise statement of the substrate-relevant boundary:

> "Amendments are append-only. The original record is immutable. Every amendment is a new anchored record that references the original transaction_id. The full history — original plus all amendments — is always visible. Deletion is structurally impossible."


{
  "submission_type": "amendment",
  "transaction_id": "<hash of this amendment>",
  "parent_reference": { "type": "transaction", "id": "<hash of original transaction>" }
}

> "An amendment may add or clarify. It may never delete. Any attempt to submit an amendment that removes a previously anchored field is rejected."

This is structurally identical to Loomworks' Memory non-erasure rule (Loomworks' R-A28). Both substrates enforce append-only correction. The mapping is direct.

Other edge cases worth surfacing for substrate design

From §10.3 and §12 of the Schema Reference, three more cases that imply substrate structure:

| Edge case | Boundary feature | |---|---| | Open source bounty (§12.4) | Recipient is genuinely unknown at Arrangement creation. Resolved by an Open Recipient placeholder party type at the Arrangement, with the resolving Action carrying the actual party identifier. | | Divorce asset settlement (§12.7) | A Directing Authority (court) shapes the Arrangement without participating in asset flows. Added as a party role in the optional schema; appears in the Arrangement only. | | Organ procurement chain (§12.3) | Time-critical viability window in the Anticipation. Breach is structurally visible as a timestamp anomaly. | | Revenue-based financing (§12.7) | Self-terminating Accrual — the Accrual carries a cumulative cap value. Ceases when the cap is reached. | | Letter of Credit (§10.1) | "Attestation gates drawdown but is not mandatory for recording" — attestation is a real-world prerequisite for an Action, but FORAY records the transaction structure regardless. The gating is editorial, not structural. |

Substrate implications

The Schema Reference is explicit (§11): all edge-case resolutions land in the optional schema layer, never in the core. The substrate guidance is implicit:

The substrate design that absorbs all of this with minimum core impact is the layered one the primer recommends — four polymorphic component tables plus an attestations table plus JSONB for optional schema additions.


Section 7 — Spec drift — Attestation framing in v4.1 vs the primer

Three positions on Attestation exist in the canonical material, not two. The primer named the v4.1 spec's framing and contrasted it with its own. The Schema Reference (2026-03-26) holds a third position. Reproduced verbatim:

Position 1 — FORAY_Protocol_v4_1_Specification.md §9.1 (the v4.1 spec)

Section header: "9. Attestations Extension (Optional)"

Opening paragraph: > "The Attestations extension provides a fifth component type for transactions requiring third-party validation. This is optional — the core 4A model (Arrangements, Accruals, Anticipations, Actions) remains sufficient for most enterprise transactions."

"When to Use Attestations" table heads the section: a use-case-by-use-case admission of when ATT belongs. Most enterprise transactions (invoice payments, payroll, loans, manufacturing work orders) have a check in Core 4A but a dash in Attestations Extension. Provenance / luxury authentication / regulatory certifications / inspections / audit sign-offs have checks in both.

§9.5 ("Schema Extension") frames the schema position structurally:

> "When using attestations, add to component_hashes: ... Add attestations array to transaction:"

— that is, attestations are added to the schema if used. The default top-level schema in §2.1 has component_hashes with four entries (arrangements, accruals, anticipations, actions). Attestations are not in component_hashes unless added. The component arrays section in §2.1 lists arrangements, accruals, anticipations, actions — no attestations array.

Position 2 — docs/DUNIN7_FORAY_Schema_Reference.md §2 and §3.1 (2026-03-26, the more recent doc)

Section §2 (Core Schema), opening:

> "The core schema consists of four components — Arrangements, Accruals, Anticipations, and Actions (4A). Attestations are available as a FORAY capability but are not part of the core schema. A transaction is complete without them."

But §3.1 (Optional Schema Layer — Attestations) immediately reframes:

> "Attestations are the event layer of the FORAY protocol. They are not business transactions. They are claims — made by an identified, credentialed party, at a defined point in time, anchored tamper-evidently alongside the transaction they reference."

> "An Attestation establishes: who claimed what, under what credentials, at what time. The tamper-evident anchor makes the claim permanently attributable. Whether the claim was honest, accurate, or complete is outside the boundary of the protocol. A false Attestation is permanently attributable to its author. FORAY does not prevent false claims. It makes them impossible to deny."

> "This is the layer where AI agent observability connects to business transaction accountability."

This position is mid-way between Position 1 and Position 3. The Schema Reference holds (a) "not part of the core schema" (Position 1's framing) and (b) "the event layer of the FORAY protocol" — which is a structurally distinct framing from "optional extension."

Position 3 — the primer (foray-protocol-primer-for-loomworks-substrate-v0_1.md)

Reproduced from the primer's framing:

> "The refined position this primer uses is that FORAY is a five-component model in which Attestation is a native cross-cutting capability, not a downstream extension. Both framings produce the same JSON output; the difference is conceptual:"

> "Current framing (five components, cross-cutting fifth): Four component types (ARR, ACC, ANT, ACT) are peers in the transaction DAG; Attestation (ATT) is a fifth, structurally distinct kind — it does not sit in the DAG, it annotates it."

> "This is the deepest structural reason attestation is 'cross-cutting': no DAG component has an attestation_refs[] field. The reference always goes from the attestation into the thing being attested to, never the reverse."

Wording difference vs structural difference

The three positions produce identical JSON output. A v4.1-compliant transaction looks the same whether attestations are "an extension," "the event layer," or "a cross-cutting fifth." The transaction validates against the same rules under all three framings.

The difference is conceptual and substrate-shaping:

The structural one-way reference is the same in all three positions — every reading of the spec has the same answer: attestations point at components, components do not point at attestations. The structural fact is not contested. What is contested is the conceptual posture (optional / layered / native), which informs substrate-level decisions like:

What changed between the v4.1 spec and the Schema Reference 2026-03-26

The v4.1 spec is dated 2026-02-14 (last commit in repo). The Schema Reference is dated 2026-03-26 — six weeks later. The Schema Reference is the more recent document and shows the conceptual evolution:

The primer goes one further step — past "event layer" to "native cross-cutting capability." That step is unambiguously not in either spec document; it's the primer's synthesis.

Honest reading

The drift is real but uniformly in one direction: each successive document strengthens attestation's structural standing relative to the v4.1 spec. There is no document anywhere in the repo that retracts the v4.1 spec's framing — it remains the canonical wire-format reference — but every document written after it positions attestations as more central than the v4.1 spec's "Extension (Optional)" language suggests.

For substrate design: the primer's framing (native cross-cutting) is the strongest of the three and is consistent with the trajectory of the documentation. A substrate that builds attestations in from v1 — with a peer table and the one-way reference fabric — is consistent with all three positions even though only Position 3 demands it.


Things found that weren't on the list but seem relevant

1. The Submission Envelope is the most service-interface-like artifact in the repository.

docs/DUNIN7_FORAY_Schema_Reference.md §4 (Submission Schema) defines a wrapper around the transaction (foray_submission) with three submission types: new, amendment, component. This is structurally distinct from the v4.1 spec's top-level transaction object — the submission envelope is the outer shape that goes over the wire; the transaction-as-JSON is the inner shape. The substrate may want to model this layering: a foray_submissions table records every submission attempt (with parent references for amendments), and the foray_transactions row is the materialized result of one or more submissions for a given transaction_id.

The three submission types map to substrate operations:

This is the operational extension of the four-component-table design the primer recommends.

2. The Transaction ID is generated by the submitter, not by FORAY.

§4.3 of the Schema Reference: > "transaction_id = SHA-256( namespace + timestamp + entropy )" > "The pre-image is retained by the submitting agent's key management implementation. The submission agent never stores it in plaintext."

This has direct substrate implications for Loomworks: the substrate would either generate the transaction_id (and retain the pre-image for the proving-ownership story) or accept it from upstream. The substrate cannot synthesize a transaction_id on demand without also synthesizing the namespace/entropy/timestamp triple.

3. Persistence layer is plural and declared per-submission.

§4.2 makes explicit that a transaction may be anchored to multiple persistence layers simultaneously: > "Multiple layers may be declared simultaneously. A party that anchors to a credible, independently verifiable layer carries more weight in the execution fidelity model than one that anchors to an unverified private log."

A substrate that stores blockchain_anchor as a single embedded object on the transaction row is structurally one-layer-only. If the protocol is to be honoured, the substrate needs transaction_anchors (plural) — one row per (transaction_id, persistence_layer).

4. The execution fidelity weighting model (§8) is a substrate-shaping concept the primer does not surface.

> "At transaction inception, a completeness weight is calculated based on the data supplied relative to what the transaction type requires. This weight can be recalculated at any subsequent point as Actions resolve against Anticipations."

The substrate would need to record the inception-time weight, the recomputed weights, and the cumulative party-level weight derived from many transactions. The primer's four-table design does not allow for this without an additional layer — a transaction_fidelity_weights table or per-transaction weight column.

5. AI agent observability is named as the canonical Attestation use case for FORAY's near future.

Schema Reference §3.1: > "This is the layer where AI agent observability connects to business transaction accountability. An AI agent's decision cycle — authorisation check, reasoning, projection, execution — is a sequence of events, not a business transaction. Each event is a claim made by the agent about what it did and why."

This is directly relevant to the substrate review: Loomworks itself is an AI-agent-operated substrate. The Schema Reference's framing suggests that Loomworks-as-a-FORAY-system would have its substrate's actor decisions (Companion turns, classifier outputs, agent dispatch records) modelled as Attestations against the engagement-as-Transaction. This is a deeper substrate implication than the primer states.

6. The protocol explicitly anticipates multiple deployment models — including hosted services.

> "The FORAY protocol is deployment-model neutral. Compliant implementations may be self-hosted, embedded in connectors, or offered as commercial services. The protocol does not mandate or prohibit any deployment model."

> "Commercial implementations of the FORAY protocol — including hosted services offered to third parties — require a commercial license from DUNIN7."

For Loomworks, this means the substrate's relationship to FORAY can be: embedded (calls into a local SDK), federated (each tenant declares its own persistence layer), or hosted (Loomworks operates the anchor service). The protocol doesn't pick one.


Things asked for but not found

| Topic | What's missing | Where the answer might live | |---|---|---| | Topic 2 — Audit data extension | The structural definition of audit_data; the field-level differences between standard, dcaa_full, big4, minimal; whether profiles can be mixed within a transaction | FORAY_Protocol_v4_0_Specification.md (not in this clone); possibly in DUNIN7's private documentation | | Topic 5 — Anchor service interface | The wire-level interface for submitting a transaction to be anchored: endpoint URL, request body, response shape, error codes, auth model, sync-vs-async semantics | foray-sdk.js (referenced by adapters but not in repo); possibly in DUNIN7's private documentation | | Topic 6 — Boundary edge cases (the named document) | FORAY_Transaction_Boundary_Analysis.md as a discrete document | Substituted with DUNIN7_FORAY_Schema_Reference.md §5/§6/§7/§10.3/§11/§12, which covers the same conceptual ground organised by asset behaviour and transaction validation set | | ATT-* validation rules — examples | The §9.6 table gives the rule statements but no per-rule example of violation or accepted outcome | Possibly in test fixtures (not searched exhaustively); no obvious test directory in the repo |

The substrate-review work can proceed against everything in the seven topics that was found, with the gaps above flagged. Topics 2 and 5 are the most consequential gaps — Topic 2 because audit-profile differences may shape a substrate-side audit_data table, and Topic 5 because the substrate will need to integrate against some anchor surface whose interface is not documented in the local clone.


End of deep-read.