Skip to content

fold: CEG-native build manifests on the shared Engine (POST/GET /v1/builds) - #143

Open
emooreatx wants to merge 4 commits into
mainfrom
fold/builds-ceg-native
Open

emooreatx wants to merge 4 commits into
mainfrom
fold/builds-ceg-native

Conversation

@emooreatx

Copy link
Copy Markdown
Contributor

FSD-004 §6.2 settled: a build is a pipeline-signed Contribution on provenance:build_manifest:{target}:v1 plus the manifest bytes as a commons blob the Contribution names in evidence_refs. fold_builds is the persist-native surface for it.

What changes

  • POST /v1/builds (submit), GET /v1/builds/{version}, GET /v1/builds/hash/{manifest_hash}, GET /v1/builds/manifest/{manifest_hash} on fold::router, which is what CIRISServer mounts. The standalone binary is unchanged and keeps its Postgres build table.
  • Authority is the pipeline's infra:attest from a trust root the node accepts: a live delegates_to(root → pipeline, infra:attest) grant, checked with capability_roots_to_trusted_root. No bearer, no registry signature. The door refuses an unblessed pipeline and stores nothing; the read re-checks on every request.
  • The submit body carries the pipeline's key record and grant beside the Contribution, so a node that has never seen the pipeline can check it in one request.
  • The standalone Manifests are stranded between two mechanisms — and /v1/builds synthesizes provenance it never verified #138 walk matched provenance:build_manifest:{target} with no version segment, which no admissible row can carry. It now uses the versioned spelling. This is the only change to the deployed binary.

The wire shape is persist's, not verify v18's

Measured against a live Engine and pinned by a test: verify's producer emits a dimension without the :v1 CC 3.1.7 R3 requires (persist refuses it, missing_version_segment) and an envelope with no signed row mirror. Filed as CIRISVerify#299.

Verification

  • tests/build_manifest_fold.rs: nine tests, every refusal plus the two verify mismatches. Runs in the no-default-features build.
  • Lib 117, fold build 65/9/26/19/16/3; sqlx, tonic and tokio-postgres still absent from the fold graph.
  • End to end on CIRISServer's harness/mesh-repro manifest scenario (synthetic trust root, three docker nodes): all 11 rungs green. A blessed pipeline publishes to one registry node, the Contribution, its key and its grant replicate to the second, the second pulls the manifest blob and serves the build with provenance it re-verified; the unblessed pipeline is refused at the door and served nowhere. The blessed admission path has no in-process test here, because it needs a trust root the node accepts.

Not in this PR

  • No version bump or tag. CIRISServer#442 needs a tag to pin; cutting one from main would redeploy the standalone registry, so that is left as a decision.
  • The read walks every node key's attestations. Fine while builds are read rarely; it wants an index before that stops being true.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VhhR4ntuczmABtdh6RifqF

emooreatx and others added 2 commits October 1, 2026 09:54
…uilds)

FSD-004 §6.2, settled: a build is a pipeline-signed Contribution on
provenance:build_manifest:{target}:v1 plus the manifest bytes as a commons blob
the Contribution names in evidence_refs. `fold_builds` is the persist-native
surface for it, mounted by `fold::router` (the server's path) and not by the
standalone binary, which keeps its Postgres build table.

Authority is the pipeline's infra:attest from a trust root this node accepts
(`capability_roots_to_trusted_root`). The submit door refuses an unblessed
pipeline and stores nothing; the read re-checks, because rows also arrive by
anti-entropy and a blessing can be withdrawn after a row was admitted.

The wire shape is persist's stamped envelope, not verify v18's. Measured against
a live Engine: verify's producer emits a dimension without the version segment
CC 3.1.7 R3 requires (persist refuses it, `missing_version_segment`) and an
envelope with no signed `row` mirror (CIRISPersist#643). Filed as
CIRISVerify#299; a test pins both so the day verify changes it says so.

The standalone #138 walk matched the unversioned dimension, which no admissible
row can carry. It now uses the same spelling.

Not shown here: a blessed pipeline being admitted. That needs a trust root the
node accepts, and is exercised by CIRISServer's `manifest` mesh scenario.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VhhR4ntuczmABtdh6RifqF
…ribution

Measured on CIRISServer's `manifest` mesh scenario: persist's capability walk
confers infra:attest through a live `delegates_to(root → pipeline, infra:attest)`
grant. A role on the pipeline's co-scrubbed key record does not confer it; the
walk reads such a record as "this key is itself a root", and a pipeline is not.

So the submit door takes the grant alongside the key record (`pipeline_grant`),
checks its signature against the granter's key in this node's directory, and
stores it. Storing it confers nothing by itself: whether the granter is a root
this node accepts is still the walk's question, asked afterwards.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VhhR4ntuczmABtdh6RifqF
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

emooreatx and others added 2 commits October 1, 2026 19:14
…he size

Two changes agreed with CIRISVerify's FSD-006 (the build-manifest lifecycle).

The read door returned facts and a provenance summary, so an agent could only
take them on the serving node's word, which CC 5.3.4 forbids. It now returns the
Contribution exactly as the pipeline signed it, plus `standing`: the root and
grant this node's walk found, and whose walk it was. A reader re-verifies the
signature and shape locally and can fetch the grant to run its own walk.

`BuildFacts` gains `manifest_size` (CC 5.3.2.5: every blob carries its size).
The submit door checks the length before it hashes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VhhR4ntuczmABtdh6RifqF
…n its record

The door asked only persist's capability walk, which would have refused every
production pipeline. The accord's CI-key ceremony blesses a pipeline by
co-scrubbing infra:attest onto its key record and writes no delegates_to row;
the walk's co-scrub arm then treats that key as a root in its own right and
wants a charter and a heartbeat a pipeline does not have.

persist's designed authority for this case is `is_infra_attest_effective`
(CIRISPersist#422/#424): the role on the stored record, which the admission gate
lets through only on an accord co-scrub, minus any withdrawal tombstone. The
door now asks the walk first and that second, and refuses only when both say no.

`Blessing` names which one answered (`delegation`, `family_quorum`,
`accord_role`), in the shape verify 19's `PipelineBlessing` takes, and the read
response carries it with the pipeline's key record, which under `accord_role` is
the evidence itself.

New test: a key that writes infra:attest onto its own record is not blessed.

Raised by CIRISVerify's FSD-006 review; confirmed against persist v52.0.1 source.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VhhR4ntuczmABtdh6RifqF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant