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
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ cd site && npm run build
4. Add tests for new functionality
5. Open a PR against `main`

**Adding or changing a format field?** The models are not the source of truth for the *standard* — the schema is. Any new field on `Claim`, `Evidence`, the envelope, or a new sub-model must also be added to `spec/akf-v1.1.schema.json` and documented in `spec/akf-v1.0-spec.md`. `tests/test_schema_conformance.py` enforces this: it stamps a maximal unit and validates it against the schema, so a field that exists in code but not in the schema fails CI.

## Reporting Bugs

Open a GitHub issue with:
Expand Down
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ office = ["python-docx>=0.8", "openpyxl>=3.1", "python-pptx>=0.6"]
report = ["fpdf2>=2.7"]
crypto = ["cryptography>=42.0"]
all = ["python-docx>=0.8", "openpyxl>=3.1", "python-pptx>=0.6", "pypdf>=3.0", "Pillow>=10.0", "cryptography>=42.0", "fpdf2>=2.7"]
dev = ["pytest", "black", "ruff", "pyyaml"]
dev = ["pytest", "black", "ruff", "pyyaml", "jsonschema"]

[project.scripts]
akf = "akf.cli:main"
Expand Down
68 changes: 68 additions & 0 deletions python/tests/test_schema_conformance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"""Guard against schema drift: what the models emit must validate against the
canonical JSON schema (spec/akf-v1.1.schema.json).

This is the anti-drift mechanism — if a future field is added to the models
without being added to the schema, this test fails, so the published
"standard" can never silently fall behind the implementation again.
"""

import json
import os

import pytest

jsonschema = pytest.importorskip("jsonschema")

SCHEMA_PATH = os.path.join(
os.path.dirname(__file__), "..", "..", "spec", "akf-v1.1.schema.json"
)


@pytest.fixture(scope="module")
def schema():
with open(SCHEMA_PATH) as f:
return json.load(f)


def test_schema_is_valid(schema):
jsonschema.Draft202012Validator.check_schema(schema)


def test_maximal_stamp_validates(schema, tmp_path):
"""A stamp exercising every v1.6 field must validate against the schema."""
from akf.stamp import stamp_file
from akf import universal

dep = tmp_path / "helper.py"
dep.write_text("VALUE = 1\n")
src = tmp_path / "data.csv"
src.write_text("q1,42\n")
f = tmp_path / "main.py"
f.write_text("import helper\n")

stamp_file(
str(f),
agent="claude-code",
source="data.csv", # -> src_hash
evidence=["42/42 tests passed, coverage: 85%"], # -> metrics
replay="pytest -q", # -> replay + input_hash
)
meta = universal.extract(str(f)) # -> meta.deps
# sanity: the fields we're guarding are actually present
claim = meta["claims"][0]
assert claim.get("src_hash")
assert any(e.get("replay") for e in claim.get("evidence", []))
assert any(e.get("metrics") for e in claim.get("evidence", []))
assert meta.get("meta", {}).get("deps")

jsonschema.validate(meta, schema)


def test_bare_stamp_validates(schema, tmp_path):
from akf.stamp import stamp_file
from akf import universal

f = tmp_path / "doc.md"
f.write_text("# Doc\n")
stamp_file(str(f), agent="claude-code")
jsonschema.validate(universal.extract(str(f)), schema)
17 changes: 17 additions & 0 deletions spec/akf-v1.0-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ AKF (Agent Knowledge Format) is a lightweight, LLM-native file format for struct
| contra | string | no | — | Contradicting claim ID |
| fidelity | object | no | — | Multi-resolution {h, s, f} |
| kind | string | no | — | Claim kind (claim, code_change, decision, suggestion, review, test_result, diagnosis) |
| src_hash | string | no | — | Content hash of the cited source at stamp time (v1.6) — enables source-change staleness |
| evidence | array | no | — | Evidence objects supporting the claim |

## Evidence Fields
Expand All @@ -72,6 +73,22 @@ AKF (Agent Knowledge Format) is a lightweight, LLM-native file format for struct
| detail | string | yes | Description of the evidence |
| at | ISO-8601 | no | Timestamp |
| tool | string | no | Tool that produced this evidence |
| metrics | object | no | Parsed receipt strength (v1.6): coverage, tests_passed, tests_total |
| replay | object | no | Falsifiable probe recipe (v1.6) — see below |

### Replay Fields (v1.6)

A replay recipe makes evidence falsifiable: a signature proves who said it; a replay proves it could have been true.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| command | string | yes | Shell command that re-verifies the claim |
| cwd | string | no | Working directory, relative to the stamped file |
| expected_exit | int | no | Exit code meaning confirmed (default 0) |
| output_digest | string | no | Content hash of the expected output |
| input_hash | string | no | Fingerprint of the claim's input closure at issuance — distinguishes CONFIRMED from CONFIRMED_DRIFTED |

Envelope `meta.deps` (v1.6) maps first-degree local dependency paths to content hashes, enabling transitive-dependency staleness detection.

## Trust Grounding

Expand Down
52 changes: 50 additions & 2 deletions spec/akf-v1.1.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,15 @@
},
"meta": {
"type": "object",
"description": "Free-form extension metadata",
"additionalProperties": true
"description": "Free-form extension metadata. Reserved key 'deps' (v1.6) maps first-degree local dependency paths to content hashes for transitive staleness detection.",
"additionalProperties": true,
"properties": {
"deps": {
"type": "object",
"description": "Dependency path -> content hash, recorded at stamp time (v1.6)",
"additionalProperties": { "type": "string" }
}
}
},
"made_by": {
"type": "array",
Expand Down Expand Up @@ -171,6 +178,10 @@
"type": "string",
"description": "Source name"
},
"src_hash": {
"type": "string",
"description": "Content hash of the cited source at stamp time (v1.6). Enables STALE detection when the cited source changes."
},
"uri": {
"type": "string",
"description": "Source URL",
Expand Down Expand Up @@ -284,6 +295,43 @@
"tool": {
"type": "string",
"description": "Tool that produced this evidence"
},
"replay": {
"$ref": "#/$defs/Replay",
"description": "Falsifiable probe recipe (v1.6): how to re-verify this evidence"
},
"metrics": {
"type": "object",
"description": "Parsed receipt strength (v1.6), e.g. coverage, tests_passed, tests_total",
"additionalProperties": { "type": "number" }
}
}
},
"Replay": {
"type": "object",
"required": ["command"],
"additionalProperties": true,
"description": "A falsifiable probe recipe carried inside evidence (v1.6). A signature proves who said it; a replay proves it could have been true.",
"properties": {
"command": {
"type": "string",
"description": "Shell command that re-verifies the claim"
},
"cwd": {
"type": "string",
"description": "Working directory, relative to the stamped file"
},
"expected_exit": {
"type": "integer",
"description": "Exit code that means confirmed (default 0)"
},
"output_digest": {
"type": "string",
"description": "Optional content hash of the expected command output"
},
"input_hash": {
"type": "string",
"description": "Fingerprint of the claim's input closure (dependencies + pinned sources) at issuance. Distinguishes CONFIRMED from CONFIRMED_DRIFTED."
}
}
},
Expand Down
Loading