Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions .github/scripts/downstream-canary-stella.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ fi

echo "CGP crates available to patch in: ${crates[*]}"

# A local patch must still satisfy the downstream's declared semver requirement.
# During a release-major canary, temporarily align exact workspace pins with
# this checkout so the canary tests source compatibility rather than stopping
# at dependency resolution. This only mutates the disposable downstream checkout.
cgp_version=$(sed -n 's/^version = "\([^"]*\)"/\1/p' "$CGP_DIR/Cargo.toml" | head -1)
for crate in "${crates[@]}"; do
sed -i -E "s|^(${crate}[[:space:]]*=[[:space:]]*)\"=?[0-9][^\"]*\"|\1\"=${cgp_version}\"|" "$STELLA_MANIFEST"
done

if grep -qF "$SENTINEL" "$STELLA_MANIFEST"; then
echo "stella's Cargo.toml already carries the local-CGP patch — leaving it as-is."
else
Expand All @@ -79,11 +88,16 @@ else
for crate in "${crates[@]}"; do
printf '%s = { path = "%s/%s" }\n' "$crate" "$CGP_DIR" "$crate"
done
echo ""
echo '[patch.crates-io]'
for crate in "${crates[@]}"; do
printf '%s = { path = "%s/%s" }\n' "$crate" "$CGP_DIR" "$crate"
done
} >>"$STELLA_MANIFEST"
fi

echo "--- patched Cargo.toml tail ---"
tail -n "$(( ${#crates[@]} + 3 ))" "$STELLA_MANIFEST"
tail -n "$(( 2 * ${#crates[@]} + 5 ))" "$STELLA_MANIFEST"
echo "-------------------------------"

# Discover which stella crates depend on a contextgraph-* crate at all, from
Expand All @@ -93,8 +107,8 @@ echo "-------------------------------"
dependents=()
while IFS= read -r manifest; do
dependents+=("$(basename "$(dirname "$manifest")")")
done < <(cd "$STELLA_DIR" && find . -mindepth 2 -maxdepth 2 -name Cargo.toml \
-exec grep -lE '^contextgraph-[a-z-]+ = ' {} \; | sort -u)
done < <(cd "$STELLA_DIR" && find . -mindepth 2 -maxdepth 3 -name Cargo.toml \
-exec grep -lE '^contextgraph-[a-z-]+([.]workspace)?[[:space:]]*=' {} \; | sort -u)

if [[ "${#dependents[@]}" -eq 0 ]]; then
echo "::error::no stella crate depends on contextgraph-* — is STELLA_DIR stale, or did the dependency move?"
Expand Down
14 changes: 9 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
name: Release

# Publishes the three publishable Context Graph Protocol crates to crates.io,
# Publishes the four public Context Graph Protocol crates to crates.io,
# in dependency order (see PUBLISHING.md): contextgraph-types -> contextgraph-host
# -> contextgraph-conformance. `contextgraph-trace` is deliberately excluded — it
# inherits the workspace's `publish = false` default (see its Cargo.toml).
# -> contextgraph-conformance -> contextgraph-trace.
#
# This workflow is inert by construction. A `contextgraph-v*` tag push alone
# can never publish anything:
Expand Down Expand Up @@ -54,7 +53,7 @@ jobs:
- run: cargo publish --dry-run -p contextgraph-types

publish:
name: publish crates.io (contextgraph-types -> contextgraph-host -> contextgraph-conformance)
name: publish crates.io (types -> host -> conformance -> trace)
needs: preflight
runs-on: ubuntu-latest
environment: crates-io
Expand All @@ -72,7 +71,7 @@ jobs:
run: ./.github/scripts/wait-for-crate.sh contextgraph-types "${GITHUB_REF_NAME#contextgraph-v}"

# contextgraph-host depends on contextgraph-types via a path dep with a
# ">=0.1.0" version requirement (see contextgraph-host/Cargo.toml) —
# ">=1.0.0" version requirement (see contextgraph-host/Cargo.toml) —
# crates.io strips the path and resolves the version req against the
# registry, so this step fails fast if the wait above returned too
# early.
Expand All @@ -88,3 +87,8 @@ jobs:
run: cargo publish -p contextgraph-conformance --locked
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

- name: Publish contextgraph-trace
run: cargo publish -p contextgraph-trace --locked
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
74 changes: 73 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ specification repository are documented in this file.

The Context Graph Protocol crates (`contextgraph-types`, `contextgraph-host`,
`contextgraph-conformance`, `contextgraph-trace`) track **crate
version** (`0.x` today) and **protocol version** (`contextgraph/1.0-draft`) as two
version** (`1.x` today) and **protocol version** (`contextgraph/1.0`) as two
independent axes — see [docs/stability.md](./docs/stability.md). This changelog
records crate releases and spec-repository milestones together, noting which is
which. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
Expand Down Expand Up @@ -47,6 +47,24 @@ this is a crate-version release only.

## [Unreleased]

## [1.0.0] — 2026-08-11 (stable protocol and crate release)

The `contextgraph/1.0` wire contract is now frozen. The four public Rust crates
move to 1.0.0 in lockstep, and the TypeScript and Python provider SDKs advertise
the stable protocol identifier. Existing `contextgraph/1.0-draft` peers remain
wire-compatible under the major-family negotiation rule.

### Changed
- Dropped the `-draft` suffix from `PROTOCOL_VERSION` and every reference wire
vector, SDK, example, badge, and conformance fixture.
- Renamed the attested fixture profile to `contextgraph-1.0`; its strict file
coverage and SHA-256 manifest remain the release witness downstreams can pin.
- Promoted workspace crates and published SDK manifests to version `1.0.0`.
- Integrated PR #76's schema/spec regression coverage before the freeze, so
documented JSONC examples and schema `$id` bytes are checked alongside the
existing wire, host, provider, and composition conformance suites.


### Added

- **First real crates.io publish** (2026-07-31) — `contextgraph-types`,
Expand Down Expand Up @@ -274,6 +292,60 @@ this is a crate-version release only.
- Recommended relation vocabulary `frame::rel` (#7).
- Embedding fingerprint format and exact-match rule (E1) (#11).

### Removed
- **Breaking:** `Capabilities.upsert`, `Capabilities.subscribe`, and
`QueryCapability.filters` — negotiable at handshake but unreachable by any
host. Wire-compatible; Rust API breaking (#5, #6, #11).

### Fixed
- **`SPEC.md` §9's `verify` example no longer fails the schema `SPEC.md` ships.**
Both envelopes carried `"id": "v1"`, but §3.2 grants an `id` only to
`query`/`frames`/`error`, the reference `Envelope::Verify`/`Verified` have no
such field, and the schema is `additionalProperties: false` — the example was
invalid against the protocol's own definition. The `id`s are removed;
`verify` correlates by full frame identity, not by envelope id. Root cause:
`schema/validate-examples.py` checked `examples/` but never `SPEC.md`, so the
one example surface with no machine check was the one that drifted. It now
validates every fenced `jsonc` block in `SPEC.md` too (comments and documented
placeholders normalized away, structure checked), and CI's existing `schema`
job therefore catches this class of drift.
- **Regression guard for the `ContextQuery` `required` fix.** The schema change
itself landed independently in #63; this adds the test that keeps it fixed —
an ordinary unfiltered, unanchored query must satisfy the schema's *own*
`required` array (read from the schema, so it cannot drift into a stale
snapshot). A cross-audit of all 16 shared types confirms no other type demands
a field its serializer elides — this bug class has now recurred twice
(`ContextFrame` in PR #44, `ContextQuery` in #63), so it is worth a standing
check rather than another one-off fix.
- **§G2 and §D1 are now actually verified, not merely asserted.** Both named
`frame-validity` as their verifier while neither `target_uri` nor the frame's
own `content_digest` was read by any check — the self-attestation §11.1
exists to rule out. `check_frames` now rejects a relation with an empty
`target_uri` (§G2) and a present-but-malformed `content_digest` (§D1); its
evidence string had claimed "well-formed digests" while accepting
`sha256:abc`. §D1 was found by auditing the other ten rules that cite
`frame-validity` after §G2 turned out to be unenforced; the remaining nine
were confirmed enforced.
- **`contextgraph-host::wire` docs no longer invert a MUST NOT.** The module
said concurrency is "negotiated by observation, not by a capability flag",
contradicting `SPEC.md` §3.2 and the shipped `Capabilities::correlation`: a
host **MUST NOT** send an `id` to a provider that did not declare correlation.
- JSON Schema: a `ContextFrame`'s `required` is now exactly what the reference
serializer always emits (`id`, `kind`, `title`, `score`, `token_cost`).
`provenance` and `relations` were listed as globally required but are
`skip_serializing_if = Vec::is_empty` in the reference type and required by no
frame-validity check, so a Rust-serialized frame with no edges failed schema
validation. Surfaced by ADR 0006's wire-conformance test — the first to
validate serialized frames (not just hand-authored examples) against the
schema. `content` remains governed per-representation by the existing `allOf`.

### Changed
- **Breaking:** `token_cost` MUST now equal the canonical count for its content.
Providers that under-declared cost were previously green (#8).
- Withdrew the incorrect claim that CGP rides JSON-RPC 2.0 (#4).
- Code comments cite `SPEC.md` anchors instead of a private repository (#3).

### Added
- [`schema/contextgraph-envelope.schema.json`](./schema/contextgraph-envelope.schema.json) — a
machine-readable JSON Schema (Draft 2020-12) for the Context Graph Protocol envelope and all wire
types. Validates in any language (`ajv`, Python `jsonschema`, Rust
Expand Down
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ members = [
]

[workspace.package]
version = "0.1.2"
version = "1.0.0"
edition = "2024"
rust-version = "1.90"
license = "MIT OR Apache-2.0"
Expand Down
36 changes: 14 additions & 22 deletions GOVERNANCE.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# Context Graph Protocol governance

This document describes how the Context Graph Protocol is maintained, how
it changes, and the path from `contextgraph/1.0-draft` to a frozen `contextgraph/1.0`. It exists
it changes, and the maintenance of the frozen `contextgraph/1.0` family. It exists
so adopters can trust that the protocol is maintained deliberately and that
"Context Graph Protocol conformant" is a stable, verifiable claim — not a maintainer's mood.

## Roles

- **Maintainer.** Mac Anderson (`@macanderson`) is the current maintainer. The
maintainer owns release decisions, approval of normative changes, and the
call on when `contextgraph/1.0-draft` freezes to `contextgraph/1.0`.
stewardship of the frozen `contextgraph/1.0` family.
- **Contributors.** Anyone. Contributions land via pull request under the
[DCO](./CONTRIBUTING.md) — no CLA, no copyright assignment.

Expand Down Expand Up @@ -51,26 +51,18 @@ version bump.
The bias is **additive, not breaking.** A new optional field is a minor change;
a removed or renamed field requires a new major family (`contextgraph/2`).

## The path to `contextgraph/1.0`

`contextgraph/1.0-draft` freezes to `contextgraph/1.0` when **all** of the following are true:

- **Independent implementations.** At least two independent Context Graph Protocol implementations
pass the conformance suite against the reference host. One reference
implementation plus one genuine third-party implementation is the minimum;
the point is to prove the spec is buildable without the reference code.
- **Stabilization window.** The wire surface has had no normative change for at
least 60 days.
- **No blocking normative issues.** There are no open normative issues the
maintainer considers blocking.
- **Complete enforcement.** The conformance suite's checks are agreed to fully
enforce the documented conformance requirements in [`SPEC.md`](./SPEC.md)
(indexed in [protocol-surface.md](./docs/protocol-surface.md#conformance-requirements)).

At the freeze, the `-draft` suffix is dropped, the crates move to `1.0.0` in
lockstep, and the major-family compatibility rule guarantees that
already-deployed `1.0-draft` providers keep handshaking successfully — no flag
day. See [stability.md](./docs/stability.md).
## The `contextgraph/1.0` freeze

The protocol froze on 2026-08-11 after the pre-freeze backlog and conformance
enforcement sweep. The release ships independent TypeScript, Python, Go, and
Rust provider implementations, an external-provider harness, host and custom
composition suites, and an attested fixture profile. Stella remains compatible
with both the former draft identifier and stable peers through major-family
negotiation.

Within `contextgraph/1`, normative evolution is additive-only. A removed,
renamed, or repurposed wire field requires `contextgraph/2`; conformance checks
may be strengthened when doing so enforces an already-normative requirement.

## Governance evolution

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ prompt. MCP tools do the work.
Green means it works with any CGP host. A broken provider is caught at CI time,
not at integration time. The suite ships a `--misbehave` mode that trips every
check on purpose, so you know the checks are real.
- **Stability you can pin.** The protocol version is `contextgraph/1.0-draft`. Two versions
- **Stability you can pin.** The protocol version is `contextgraph/1.0`. Two versions
interoperate when they share a major family, the part before the first dot. So
`contextgraph/1.0-draft` and `contextgraph/1.0` both belong to family `contextgraph/1` and interoperate.
`contextgraph/1.0` and `contextgraph/1.0` both belong to family `contextgraph/1` and interoperate.
When the draft freezes, every deployed provider keeps working. No flag day.

---
Expand All @@ -184,7 +184,7 @@ contributing you agree your contributions are licensed under the same terms.

## Status

CGP is `contextgraph/1.0-draft` today. The wire types are stable enough to build against,
CGP is `contextgraph/1.0` today. The wire types are stable enough to build against,
the host runtime enforces the guarantees, and the conformance suite verifies them.
The path from "open context as an idea" to "open context as a standard" is the
conformance suite: anyone can build a provider, anyone can verify it, and the
Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Include as much of the following as you can:
- A description of the issue and its security impact.
- The Context Graph Protocol crate(s) and version(s) affected (`contextgraph-types`, `contextgraph-host`,
`contextgraph-conformance`).
- The protocol version (e.g. `contextgraph/1.0-draft`).
- The protocol version (e.g. `contextgraph/1.0`).
- A minimal repro: a malformed envelope, a misbehaving provider, or a
bypassed consent gate.
- Any mitigations you have identified.
Expand Down Expand Up @@ -56,5 +56,5 @@ Advisory and, where applicable, a CVE.

## Supported versions

Context Graph Protocol is pre-1.0 (`contextgraph/1.0-draft`). Only the latest published crate release
Context Graph Protocol is pre-1.0 (`contextgraph/1.0`). Only the latest published crate release
receives security fixes until the `contextgraph/1.0` freeze.
4 changes: 2 additions & 2 deletions SPEC.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Context Graph Protocol (CGP) — normative specification

**Version:** `contextgraph/1.0-draft`
**Version:** `contextgraph/1.0`

This document is the **single normative home** of the Context Graph Protocol.
A provider or host can be implemented from this document, the
Expand Down Expand Up @@ -95,7 +95,7 @@ minor = 1*DIGIT

The **major family** is the substring up to (not including) the first `.`. Two
versions interoperate **if and only if** they share a major family.
`contextgraph/1.0-draft` and `contextgraph/1.0` both belong to `contextgraph/1`
`contextgraph/1.0` and `contextgraph/1.0` both belong to `contextgraph/1`
and interoperate; `contextgraph/2.0` does not.

This is what lets the freeze drop `-draft` without a flag day. An
Expand Down
8 changes: 4 additions & 4 deletions assets/badges/conformant.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading