strata-agent-memory 0.2.1__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {strata_agent_memory-0.2.1/strata_agent_memory.egg-info → strata_agent_memory-0.2.2}/PKG-INFO +8 -4
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/README.md +7 -3
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/__init__.py +1 -1
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/audit.py +7 -4
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/ledger.py +2 -2
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/trust.py +37 -18
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/pyproject.toml +1 -1
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2/strata_agent_memory.egg-info}/PKG-INFO +8 -4
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_audit.py +3 -1
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_ledger.py +10 -8
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_trust.py +41 -3
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/LICENSE +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/__main__.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/cli.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/compact.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/compiler.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/contracts.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/evidence.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/export.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/hooks.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/identity.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/mcp_server.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/memorizer.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/pathmap.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/recheck.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/records.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/relay/__init__.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/relay/adapters.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/relay/cli.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/relay/client.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/relay/core.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/reliability.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/remote.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/render.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/serve.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/signing.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/agent_memory/stats.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/setup.cfg +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/SOURCES.txt +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/dependency_links.txt +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/entry_points.txt +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/requires.txt +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/top_level.txt +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_cli.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_compact.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_compiler_render.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_contracts.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_deploy_relay.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_deploy_replica.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_deploy_tokens.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_evidence.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_hooks.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_identity.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_issue_bridge.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_ledger_index.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_memorizer.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_packaging.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_pathmap.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_phase2.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_recheck.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_records.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_redaction.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_relay_client.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_relay_codex.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_relay_core.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_reliability.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_remote.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_remote_signing.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_review2_fixes.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_review3_fixes.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_review_fixes.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_scale.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_serve.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_signing.py +0 -0
- {strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/tests/test_stats.py +0 -0
{strata_agent_memory-0.2.1/strata_agent_memory.egg-info → strata_agent_memory-0.2.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: strata-agent-memory
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Portable, auditable, cross-vendor memory for LLM agents: evidence-bound claims, trust tiers, and compiled context views.
|
|
5
5
|
Author: Strata Intelligence
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -45,9 +45,13 @@ service, no dependencies, Python 3.10+.
|
|
|
45
45
|
commit/file hash. The claim is rejected otherwise. A receipt is the
|
|
46
46
|
filer's record; the proof is the re-run, which `verify` and the nightly
|
|
47
47
|
lane perform, and the audit lists what nobody has re-run.
|
|
48
|
-
- **
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
- **Self-review is not verification.** A claim reaches `verified` when a
|
|
49
|
+
person, or an agent that is not its author, re-runs the proof; the author's
|
|
50
|
+
own re-run stays `self-verified`. A fleet on one vendor gets the same rigor
|
|
51
|
+
as a mixed one. A ledger that wants the stronger rule sets
|
|
52
|
+
`cross_vendor_required`, and then only a person or another vendor's agent
|
|
53
|
+
(Codex, Gemini, a local Qwen) promotes; either way the audit says which
|
|
54
|
+
lineage verified what.
|
|
51
55
|
- **Refuting a claim taints everything built on it.** Retractions walk the
|
|
52
56
|
provenance graph; nothing is deleted; the audit prints the chain.
|
|
53
57
|
- **Verifiers are isolated, workers fork.** A reviewer never sees the
|
|
@@ -21,9 +21,13 @@ service, no dependencies, Python 3.10+.
|
|
|
21
21
|
commit/file hash. The claim is rejected otherwise. A receipt is the
|
|
22
22
|
filer's record; the proof is the re-run, which `verify` and the nightly
|
|
23
23
|
lane perform, and the audit lists what nobody has re-run.
|
|
24
|
-
- **
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
- **Self-review is not verification.** A claim reaches `verified` when a
|
|
25
|
+
person, or an agent that is not its author, re-runs the proof; the author's
|
|
26
|
+
own re-run stays `self-verified`. A fleet on one vendor gets the same rigor
|
|
27
|
+
as a mixed one. A ledger that wants the stronger rule sets
|
|
28
|
+
`cross_vendor_required`, and then only a person or another vendor's agent
|
|
29
|
+
(Codex, Gemini, a local Qwen) promotes; either way the audit says which
|
|
30
|
+
lineage verified what.
|
|
27
31
|
- **Refuting a claim taints everything built on it.** Retractions walk the
|
|
28
32
|
provenance graph; nothing is deleted; the audit prints the chain.
|
|
29
33
|
- **Verifiers are isolated, workers fork.** A reviewer never sees the
|
|
@@ -195,8 +195,11 @@ def report(ledger, recheck: bool = False, cwd: Optional[str] = None, timeout: Op
|
|
|
195
195
|
if backed in ("static", "attested"):
|
|
196
196
|
# a clean static gate is not evidence that the thing runs
|
|
197
197
|
rep["static_only_outcomes"].append({**entry, "assurance": backed})
|
|
198
|
-
|
|
199
|
-
|
|
198
|
+
# a measure, not a tier: every claim whose only verifiers are agents of its own
|
|
199
|
+
# vendor, whether the ledger's policy lets that reach `verified` or not
|
|
200
|
+
if info["verified_by"] and not info.get("cross_vendor") and not info.get("self_verified_by_author") \
|
|
201
|
+
and info["tier"] in ("verified", "self-verified"):
|
|
202
|
+
rep["same_vendor_only"].append({**entry, "verified_by": info["verified_by"], "tier": info["tier"]})
|
|
200
203
|
if info.get("self_verified_by_author"):
|
|
201
204
|
rep["self_verified_by_author"].append({**entry, "verified_by": info["verified_by"]})
|
|
202
205
|
if info["tier"] == "refuted":
|
|
@@ -406,8 +409,8 @@ def format_report(rep: dict) -> str:
|
|
|
406
409
|
section("Receipts whose assurance was declared above the computed default", rep["assurance_overridden"],
|
|
407
410
|
lambda r: f"{r['id']} [{r['by']}] declared {r['declared']}, computed {r['computed']}: {r['what']}"
|
|
408
411
|
+ (f" (cited by {', '.join(r['claims'])})" if r["claims"] else " (cited by no claim)"))
|
|
409
|
-
section("Verified only by the same vendor (
|
|
410
|
-
lambda r: f"{r['id']} [{r['vendor']} verified by {', '.join(r['verified_by'])}] {r['statement']}")
|
|
412
|
+
section("Verified only by the same vendor (no person or other vendor has re-run it)", rep["same_vendor_only"],
|
|
413
|
+
lambda r: f"{r['id']} [{r['vendor']} verified by {', '.join(r['verified_by'])}; {r.get('tier','')}] {r['statement']}")
|
|
411
414
|
section("Verified only by the claim's own author", rep["self_verified_by_author"],
|
|
412
415
|
lambda r: f"{r['id']} [{r['by']}] {r['statement']}")
|
|
413
416
|
section("Verified from the claim's own session under another harness (collusion risk)",
|
|
@@ -43,7 +43,7 @@ DEFAULT_CONFIG = {
|
|
|
43
43
|
"project_aliases": [],
|
|
44
44
|
"org_path": None,
|
|
45
45
|
"user": None,
|
|
46
|
-
"cross_vendor_required":
|
|
46
|
+
"cross_vendor_required": False,
|
|
47
47
|
"org_include_other_projects": True,
|
|
48
48
|
"budget_tokens": 6000,
|
|
49
49
|
"vendor_map": {},
|
|
@@ -109,7 +109,7 @@ UNTRUSTED_POLICY = {
|
|
|
109
109
|
"redact": [], # an attacker-supplied regex can hang capture (catastrophic backtracking)
|
|
110
110
|
"path_map": [], # where a re-check runs
|
|
111
111
|
"org_path": None, # what it reads and writes outside the checkout
|
|
112
|
-
"cross_vendor_required":
|
|
112
|
+
"cross_vendor_required": False, # off: any agent other than the author verifies; on: another vendor or a person
|
|
113
113
|
"vendor_map": {}, # which lineage a harness belongs to, which is the same question
|
|
114
114
|
"signers": {}, # whose signature this machine believes
|
|
115
115
|
# A tier is a preference until it is a number: stale_after_days moves claims between
|
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Tiers (highest first):
|
|
4
4
|
constraint human-filed hard rule
|
|
5
|
-
verified
|
|
6
|
-
|
|
5
|
+
verified re-run by an independent verifier: a person, or an agent that is not the
|
|
6
|
+
claim's author (a different identity; of another vendor when the ledger
|
|
7
|
+
requires that)
|
|
8
|
+
self-verified re-run only by the claim's own author, or -- when the ledger requires a
|
|
9
|
+
verifier of another vendor -- only by agents of the author's vendor
|
|
7
10
|
evidenced carries receipts/bindings but nobody has re-run them
|
|
8
11
|
asserted no evidence (only allowed for non-outcome claim types)
|
|
9
12
|
stale TTL expired, or a re-check found the world moved (including a changed
|
|
@@ -11,11 +14,13 @@ Tiers (highest first):
|
|
|
11
14
|
refuted retracted, or a verification refuted it
|
|
12
15
|
tainted derived (transitively) from a refuted claim
|
|
13
16
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
Independence is a different identity, not a different vendor. A verification
|
|
18
|
+
filed by the claim's own author (same harness, user and session, or the same
|
|
19
|
+
person) never counts as independent, whatever the ledger's policy says. A ledger
|
|
20
|
+
that wants the stronger rule sets ``cross_vendor_required`` (off by default since
|
|
21
|
+
0.2.2): then a same-vendor verifier yields self-verified and only a person or
|
|
22
|
+
another vendor's agent reaches verified. Either way the audit reports which
|
|
23
|
+
lineage verified what, so a single-vendor fleet sees its own mix.
|
|
19
24
|
"""
|
|
20
25
|
from __future__ import annotations
|
|
21
26
|
|
|
@@ -56,6 +61,17 @@ def lineage_differs(a: dict, b: dict) -> bool:
|
|
|
56
61
|
return (a.get("vendor") or "unknown") != (b.get("vendor") or "unknown")
|
|
57
62
|
|
|
58
63
|
|
|
64
|
+
def same_identity(a: dict, b: dict) -> bool:
|
|
65
|
+
"""True when two author blocks are the same identity: same kind, harness and user.
|
|
66
|
+
|
|
67
|
+
The session is not part of it. A session is a label the client declares (a header on
|
|
68
|
+
the served path, a fresh id per initialize on the tool-server path), so an identity
|
|
69
|
+
that verified its own claim from a second session is still the claim's own author;
|
|
70
|
+
were the session counted, a coder could reach `verified` alone (review of PR #57).
|
|
71
|
+
"""
|
|
72
|
+
return (a.get("kind"), a.get("harness"), a.get("user")) == (b.get("kind"), b.get("harness"), b.get("user"))
|
|
73
|
+
|
|
74
|
+
|
|
59
75
|
def same_author(a: dict, b: dict) -> bool:
|
|
60
76
|
"""True when two author blocks are the same identity: same kind, harness and user,
|
|
61
77
|
and the same session whenever both sessions are known."""
|
|
@@ -227,7 +243,7 @@ def assess(ledger, config: Optional[dict] = None, now: Optional[str] = None,
|
|
|
227
243
|
Tiers are never changed by a statistic: the boundary moves, the rules do not.
|
|
228
244
|
"""
|
|
229
245
|
config = config or ledger.config
|
|
230
|
-
cross_required = bool(config.get("cross_vendor_required",
|
|
246
|
+
cross_required = bool(config.get("cross_vendor_required", False))
|
|
231
247
|
# a number config.json proposes and this code adds to a timestamp: read it through the
|
|
232
248
|
# one accessor that bounds it and names the file when it is malformed (review PE-11)
|
|
233
249
|
from .ledger import stale_after_days as _stale_after_days # local: ledger imports trust's callers
|
|
@@ -279,21 +295,24 @@ def assess(ledger, config: Optional[dict] = None, now: Optional[str] = None,
|
|
|
279
295
|
info["verdict"] = "verified"
|
|
280
296
|
verifiers = [v for v in verifications if _body(v).get("verdict") == "verified"]
|
|
281
297
|
info["verified_by"] = sorted({f"{v['author'].get('harness')}:{v['author'].get('vendor')}" for v in verifiers})
|
|
282
|
-
# a claim's own
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
298
|
+
# a claim's own identity never counts as an independent check of it, from any
|
|
299
|
+
# session and whatever the policy says; the policy decides whether another
|
|
300
|
+
# identity of the same vendor does
|
|
301
|
+
others = [v for v in verifiers if not same_identity(author, v["author"])]
|
|
302
|
+
cross_vendor = any(lineage_differs(author, v["author"]) for v in others)
|
|
303
|
+
own_author_only = bool(verifiers) and not others
|
|
304
|
+
independent = cross_vendor or (bool(others) and not cross_required)
|
|
305
|
+
info["cross_vendor"] = cross_vendor
|
|
287
306
|
info["self_verified_by_author"] = own_author_only
|
|
288
|
-
info["tier"] = "verified" if
|
|
307
|
+
info["tier"] = "verified" if independent else "self-verified"
|
|
289
308
|
if own_author_only:
|
|
290
309
|
info["reasons"].append("verified by the claim's own author")
|
|
310
|
+
elif cross_vendor:
|
|
311
|
+
info["reasons"].append("independently verified (another lineage)")
|
|
291
312
|
elif independent:
|
|
292
|
-
info["reasons"].append("independently verified")
|
|
293
|
-
elif not cross_required:
|
|
294
|
-
info["reasons"].append("verified (cross-vendor rule off)")
|
|
313
|
+
info["reasons"].append("independently verified (another agent of the same vendor)")
|
|
295
314
|
else:
|
|
296
|
-
info["reasons"].append("verified only by the same vendor lineage as the author")
|
|
315
|
+
info["reasons"].append("verified only by the same vendor lineage as the author; this ledger requires another vendor or a person")
|
|
297
316
|
elif body.get("type") == "constraint" and author.get("kind") == "human":
|
|
298
317
|
info["tier"] = "constraint"
|
|
299
318
|
info["reasons"].append("human-filed constraint")
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "strata-agent-memory"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2"
|
|
8
8
|
description = "Portable, auditable, cross-vendor memory for LLM agents: evidence-bound claims, trust tiers, and compiled context views."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
{strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2/strata_agent_memory.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: strata-agent-memory
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Portable, auditable, cross-vendor memory for LLM agents: evidence-bound claims, trust tiers, and compiled context views.
|
|
5
5
|
Author: Strata Intelligence
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -45,9 +45,13 @@ service, no dependencies, Python 3.10+.
|
|
|
45
45
|
commit/file hash. The claim is rejected otherwise. A receipt is the
|
|
46
46
|
filer's record; the proof is the re-run, which `verify` and the nightly
|
|
47
47
|
lane perform, and the audit lists what nobody has re-run.
|
|
48
|
-
- **
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
- **Self-review is not verification.** A claim reaches `verified` when a
|
|
49
|
+
person, or an agent that is not its author, re-runs the proof; the author's
|
|
50
|
+
own re-run stays `self-verified`. A fleet on one vendor gets the same rigor
|
|
51
|
+
as a mixed one. A ledger that wants the stronger rule sets
|
|
52
|
+
`cross_vendor_required`, and then only a person or another vendor's agent
|
|
53
|
+
(Codex, Gemini, a local Qwen) promotes; either way the audit says which
|
|
54
|
+
lineage verified what.
|
|
51
55
|
- **Refuting a claim taints everything built on it.** Retractions walk the
|
|
52
56
|
provenance graph; nothing is deleted; the audit prints the chain.
|
|
53
57
|
- **Verifiers are isolated, workers fork.** A reviewer never sees the
|
|
@@ -28,7 +28,8 @@ def test_report_unrechecked_outcomes(ledger, claude_agent, file_evidence):
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
def test_report_same_vendor_only(ledger, claude_agent, codex_agent):
|
|
31
|
-
"""report() lists
|
|
31
|
+
"""report() lists claims verified only by the author's own vendor, whatever tier the
|
|
32
|
+
ledger's policy gave them (a measure, not a tier: `verified` under the default)."""
|
|
32
33
|
scope = make_scope()
|
|
33
34
|
|
|
34
35
|
body = {"type": "fact", "statement": "test", "source": "test"}
|
|
@@ -50,6 +51,7 @@ def test_report_same_vendor_only(ledger, claude_agent, codex_agent):
|
|
|
50
51
|
|
|
51
52
|
assert len(rep["same_vendor_only"]) == 1
|
|
52
53
|
assert rep["same_vendor_only"][0]["id"] == claim["id"]
|
|
54
|
+
assert rep["same_vendor_only"][0]["tier"] == "verified"
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
def test_report_taint_chains(ledger, claude_agent):
|
|
@@ -782,11 +782,13 @@ def test_a_cloned_config_does_not_choose_what_this_machine_runs(tmp_path, claude
|
|
|
782
782
|
assert marker.exists() # trusted: the lane re-runs it
|
|
783
783
|
|
|
784
784
|
|
|
785
|
-
def
|
|
786
|
-
|
|
787
|
-
"""F-6: one line in a committed file
|
|
788
|
-
|
|
789
|
-
clone
|
|
785
|
+
def test_a_cloned_config_cannot_switch_the_cross_vendor_rule(tmp_path, claude_agent,
|
|
786
|
+
machine_home, capsys):
|
|
787
|
+
"""F-6: one line in a committed file changed what `verified` meant for everyone who
|
|
788
|
+
cloned. The policy key is a proposal until the repository is trusted: with the
|
|
789
|
+
stronger rule committed, an untrusted clone still applies the default (off) and a
|
|
790
|
+
same-vendor verifier reaches `verified`; trusting the clone makes it `self-verified`."""
|
|
791
|
+
clone = _cloned_repo(tmp_path, {"cross_vendor_required": True})
|
|
790
792
|
ledger = Ledger.open(clone)
|
|
791
793
|
claim = ledger.append(new_record("claim", claude_agent, make_scope(),
|
|
792
794
|
{"type": "fact", "statement": "the toolchain bootstrap succeeded",
|
|
@@ -797,8 +799,8 @@ def test_a_cloned_config_cannot_switch_off_the_cross_vendor_rule(tmp_path, claud
|
|
|
797
799
|
"results": [{"outcome": "match"}]}))
|
|
798
800
|
|
|
799
801
|
info = assess(ledger)[claim["id"]]
|
|
800
|
-
assert info["tier"] == "
|
|
801
|
-
assert "
|
|
802
|
+
assert info["tier"] == "verified" # the committed `true` is a proposal: default applies
|
|
803
|
+
assert "another agent of the same vendor" in " ".join(info["reasons"])
|
|
802
804
|
rep = audit_report(ledger)
|
|
803
805
|
assert rep["trusted"] is False
|
|
804
806
|
assert [r["id"] for r in rep["same_vendor_only"]] == [claim["id"]]
|
|
@@ -806,7 +808,7 @@ def test_a_cloned_config_cannot_switch_off_the_cross_vendor_rule(tmp_path, claud
|
|
|
806
808
|
|
|
807
809
|
ledger_mod.trust_repo(clone)
|
|
808
810
|
trusted = Ledger.open(clone)
|
|
809
|
-
assert assess(trusted)[claim["id"]]["tier"] == "verified"
|
|
811
|
+
assert assess(trusted)[claim["id"]]["tier"] == "self-verified" # now the stronger rule holds
|
|
810
812
|
assert audit_report(trusted)["trusted"] is True
|
|
811
813
|
|
|
812
814
|
|
|
@@ -37,8 +37,9 @@ def test_asserted_claim_tier_asserted(ledger, claude_agent):
|
|
|
37
37
|
assert assessment[rec["id"]]["tier"] == "asserted"
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def
|
|
41
|
-
"""
|
|
40
|
+
def test_verification_by_another_agent_of_the_same_vendor_is_verified_by_default(ledger, claude_agent, codex_agent):
|
|
41
|
+
"""Independence is a different identity, not a different vendor (the operator's
|
|
42
|
+
decision, 2026-09-24): by default another agent of the author's own vendor verifies."""
|
|
42
43
|
scope = make_scope()
|
|
43
44
|
|
|
44
45
|
# Create claim by Claude
|
|
@@ -59,7 +60,44 @@ def test_verification_by_same_vendor_self_verified(ledger, claude_agent, codex_a
|
|
|
59
60
|
ledger.append(ver_rec)
|
|
60
61
|
|
|
61
62
|
assessment = assess(ledger)
|
|
62
|
-
assert assessment[claim["id"]]["tier"] == "
|
|
63
|
+
assert assessment[claim["id"]]["tier"] == "verified"
|
|
64
|
+
assert assessment[claim["id"]]["cross_vendor"] is False
|
|
65
|
+
assert "another agent of the same vendor" in " ".join(assessment[claim["id"]]["reasons"])
|
|
66
|
+
# the stronger policy, per ledger: only a person or another vendor reaches verified
|
|
67
|
+
strict = assess(ledger, config={"cross_vendor_required": True})
|
|
68
|
+
assert strict[claim["id"]]["tier"] == "self-verified"
|
|
69
|
+
assert "requires another vendor or a person" in " ".join(strict[claim["id"]]["reasons"])
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def test_the_same_identity_from_another_session_is_still_the_own_author(ledger, claude_agent):
|
|
73
|
+
"""A session is client-declared; a coder re-launched, or a second header value, is the
|
|
74
|
+
same identity and never an independent verifier (review of PR #57, 2026-09-24)."""
|
|
75
|
+
scope = make_scope()
|
|
76
|
+
claim = ledger.append(new_record("claim", claude_agent, scope,
|
|
77
|
+
{"type": "fact", "statement": "test", "source": "test"}))
|
|
78
|
+
second_session = dict(claude_agent, session="a-second-visit")
|
|
79
|
+
ledger.append(new_record("verification", second_session, scope,
|
|
80
|
+
{"claim": claim["id"], "verdict": "verified", "method": "rerun",
|
|
81
|
+
"results": [{"outcome": "match"}]}))
|
|
82
|
+
for config in ({"cross_vendor_required": False}, {"cross_vendor_required": True}):
|
|
83
|
+
info = assess(ledger, config=config)[claim["id"]]
|
|
84
|
+
assert info["tier"] == "self-verified", config
|
|
85
|
+
assert info["self_verified_by_author"] is True
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_the_claims_own_author_never_verifies_it_whatever_the_policy(ledger, claude_agent):
|
|
89
|
+
"""With the rule off the own author's re-run used to reach `verified`; it never does."""
|
|
90
|
+
scope = make_scope()
|
|
91
|
+
claim = ledger.append(new_record("claim", claude_agent, scope,
|
|
92
|
+
{"type": "fact", "statement": "test", "source": "test"}))
|
|
93
|
+
ledger.append(new_record("verification", claude_agent, scope,
|
|
94
|
+
{"claim": claim["id"], "verdict": "verified", "method": "rerun",
|
|
95
|
+
"results": [{"outcome": "match"}]}))
|
|
96
|
+
for config in ({"cross_vendor_required": False}, {"cross_vendor_required": True}, None):
|
|
97
|
+
info = assess(ledger, config=config)[claim["id"]]
|
|
98
|
+
assert info["tier"] == "self-verified", config
|
|
99
|
+
assert info["self_verified_by_author"] is True
|
|
100
|
+
assert "own author" in " ".join(info["reasons"])
|
|
63
101
|
|
|
64
102
|
|
|
65
103
|
def test_verification_by_different_vendor_verified(ledger, claude_agent, codex_agent):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/requires.txt
RENAMED
|
File without changes
|
{strata_agent_memory-0.2.1 → strata_agent_memory-0.2.2}/strata_agent_memory.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|