jep-cli 0.6.1__tar.gz → 0.7.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.
@@ -1,6 +1,6 @@
1
1
  # Notice
2
2
 
3
- This repository contains an experimental CLI seed for the JEP v0.6 API.
3
+ This repository contains an experimental CLI seed for the JEP reference API. Supported protocol revisions are documented in README.md.
4
4
 
5
5
  Internet-Draft text and excerpts are governed by the IETF Trust Legal Provisions and BCP 78 / BCP 79.
6
6
 
jep_cli-0.7.2/PKG-INFO ADDED
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: jep-cli
3
+ Version: 0.7.2
4
+ Summary: Command-line client for JEP Core 0.7 with explicit legacy compatibility
5
+ Author-email: HJS Spec <signal@humanjudgment.org>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/hjs-spec/cli
8
+ Project-URL: Repository, https://github.com/hjs-spec/cli
9
+ Project-URL: Issues, https://github.com/hjs-spec/cli/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ License-File: NOTICE.md
18
+ Requires-Dist: rfc8785==0.1.4
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # JEP CLI — JEP Core 0.7
24
+
25
+ Command-line client for creating and verifying current JEP Core 0.7 events
26
+ through the JEP API.
27
+
28
+ Default endpoints:
29
+
30
+ ```text
31
+ POST /v0.7/events/create
32
+ POST /v0.7/events/verify
33
+ GET /health
34
+ ```
35
+
36
+ Historical pre-0.7 handling is explicit through `--legacy`; the CLI never
37
+ retries a failed 0.7 event with a legacy decoder.
38
+
39
+ ## Status
40
+
41
+ Experimental reference client. It does not define Core semantics or determine
42
+ truth, authorization validity, legal effect, causality, or policy outcome.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install jep-cli
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ ```bash
53
+ export JEP_API_URL=http://127.0.0.1:8000
54
+ export JEP_API_KEY=
55
+ ```
56
+
57
+ ## Create
58
+
59
+ Judgment:
60
+
61
+ ```bash
62
+ jep create \
63
+ --verb J \
64
+ --who did:example:agent-789 \
65
+ --what '{"claim":"approve","subject":"demo"}'
66
+ ```
67
+
68
+ Delegation:
69
+
70
+ ```bash
71
+ jep create \
72
+ --verb D \
73
+ --who did:example:principal \
74
+ --what '{"delegatee":"did:example:agent","scope":{"actions":["read"]}}'
75
+ ```
76
+
77
+ Termination and Verification require `--ref`. Pass a typed reference as
78
+ JSON when the target is another JEP event.
79
+
80
+ ## Verify
81
+
82
+ ```bash
83
+ jep verify event.json --mode archival
84
+ ```
85
+
86
+ 0.7 validation returns `status` plus independent `checks`, not a cumulative
87
+ Validation Level.
88
+
89
+ ## Explicit legacy verification
90
+
91
+ ```bash
92
+ jep verify old-event.json \
93
+ --legacy \
94
+ --legacy-format json-sorted-v1
95
+ ```
96
+
97
+ Legacy selection must come from known artifact context. Do not use a failed 0.7
98
+ validation as evidence that an event should be treated as 0.6.
99
+
100
+ ## JEP Core 0.7 model
101
+
102
+ - Event Identity is `(who,id)`.
103
+ - Event Hash identifies an exact signed artifact.
104
+ - Core does not require a top-level nonce.
105
+ - D requires `delegatee + scope`.
106
+ - T requires target `ref + termination_scope`.
107
+ - V requires target `ref + verification_scope + result`.
108
+ - chain and policy semantics remain outside Core.
109
+
110
+ ## Related repositories
111
+
112
+ - JEP Core: https://github.com/hjs-spec/jep-core
113
+ - JEP API: https://github.com/hjs-spec/jep-api
114
+ - Python SDK: https://github.com/hjs-spec/sdk-py
115
+ - JavaScript SDK: https://github.com/hjs-spec/sdk-js
116
+ - Go SDK: https://github.com/hjs-spec/sdk-go
117
+
118
+ ## Public draft
119
+
120
+ - https://datatracker.ietf.org/doc/draft-wang-jep-judgment-event-protocol/
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,102 @@
1
+ # JEP CLI — JEP Core 0.7
2
+
3
+ Command-line client for creating and verifying current JEP Core 0.7 events
4
+ through the JEP API.
5
+
6
+ Default endpoints:
7
+
8
+ ```text
9
+ POST /v0.7/events/create
10
+ POST /v0.7/events/verify
11
+ GET /health
12
+ ```
13
+
14
+ Historical pre-0.7 handling is explicit through `--legacy`; the CLI never
15
+ retries a failed 0.7 event with a legacy decoder.
16
+
17
+ ## Status
18
+
19
+ Experimental reference client. It does not define Core semantics or determine
20
+ truth, authorization validity, legal effect, causality, or policy outcome.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pip install jep-cli
26
+ ```
27
+
28
+ ## Configuration
29
+
30
+ ```bash
31
+ export JEP_API_URL=http://127.0.0.1:8000
32
+ export JEP_API_KEY=
33
+ ```
34
+
35
+ ## Create
36
+
37
+ Judgment:
38
+
39
+ ```bash
40
+ jep create \
41
+ --verb J \
42
+ --who did:example:agent-789 \
43
+ --what '{"claim":"approve","subject":"demo"}'
44
+ ```
45
+
46
+ Delegation:
47
+
48
+ ```bash
49
+ jep create \
50
+ --verb D \
51
+ --who did:example:principal \
52
+ --what '{"delegatee":"did:example:agent","scope":{"actions":["read"]}}'
53
+ ```
54
+
55
+ Termination and Verification require `--ref`. Pass a typed reference as
56
+ JSON when the target is another JEP event.
57
+
58
+ ## Verify
59
+
60
+ ```bash
61
+ jep verify event.json --mode archival
62
+ ```
63
+
64
+ 0.7 validation returns `status` plus independent `checks`, not a cumulative
65
+ Validation Level.
66
+
67
+ ## Explicit legacy verification
68
+
69
+ ```bash
70
+ jep verify old-event.json \
71
+ --legacy \
72
+ --legacy-format json-sorted-v1
73
+ ```
74
+
75
+ Legacy selection must come from known artifact context. Do not use a failed 0.7
76
+ validation as evidence that an event should be treated as 0.6.
77
+
78
+ ## JEP Core 0.7 model
79
+
80
+ - Event Identity is `(who,id)`.
81
+ - Event Hash identifies an exact signed artifact.
82
+ - Core does not require a top-level nonce.
83
+ - D requires `delegatee + scope`.
84
+ - T requires target `ref + termination_scope`.
85
+ - V requires target `ref + verification_scope + result`.
86
+ - chain and policy semantics remain outside Core.
87
+
88
+ ## Related repositories
89
+
90
+ - JEP Core: https://github.com/hjs-spec/jep-core
91
+ - JEP API: https://github.com/hjs-spec/jep-api
92
+ - Python SDK: https://github.com/hjs-spec/sdk-py
93
+ - JavaScript SDK: https://github.com/hjs-spec/sdk-js
94
+ - Go SDK: https://github.com/hjs-spec/sdk-go
95
+
96
+ ## Public draft
97
+
98
+ - https://datatracker.ietf.org/doc/draft-wang-jep-judgment-event-protocol/
99
+
100
+ ## License
101
+
102
+ MIT
@@ -0,0 +1,3 @@
1
+ """JEP Core 0.7 CLI."""
2
+
3
+ __version__ = "0.7.2"
@@ -1,4 +1,4 @@
1
- """Small HTTP client for JEP CLI v0.6."""
1
+ """Small HTTP client for the JEP Core 0.7 CLI."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -6,6 +6,8 @@ import json
6
6
  from typing import Any, Dict, Optional
7
7
  from urllib import request, error
8
8
 
9
+ from . import strict_json
10
+
9
11
 
10
12
  class JEPCLIError(Exception):
11
13
  pass
@@ -26,10 +28,16 @@ class JEPClient:
26
28
  self.timeout = timeout
27
29
 
28
30
  def create_event(self, payload: Dict[str, Any]) -> Dict[str, Any]:
29
- return self._json("POST", "/events/create", payload)
31
+ return self._json("POST", "/v0.7/events/create", payload)
30
32
 
31
33
  def verify_event(self, payload: Dict[str, Any]) -> Dict[str, Any]:
32
- return self._json("POST", "/events/verify", payload)
34
+ return self._json("POST", "/v0.7/events/verify", payload)
35
+
36
+ def create_event_legacy(self, payload: Dict[str, Any]) -> Dict[str, Any]:
37
+ return self._json("POST", "/events/create", payload)
38
+
39
+ def verify_event_legacy(self, payload: Dict[str, Any]) -> Dict[str, Any]:
40
+ return self._json("POST", "/events/verify-legacy", payload)
33
41
 
34
42
  def health(self) -> Dict[str, Any]:
35
43
  return self._json("GET", "/health", None)
@@ -38,24 +46,24 @@ class JEPClient:
38
46
  data = None
39
47
  headers = {
40
48
  "content-type": "application/json",
41
- "user-agent": "JEP-CLI/0.6.0",
49
+ "user-agent": "JEP-CLI/0.7.2",
42
50
  }
43
51
  if self.api_key:
44
52
  headers["authorization"] = f"Bearer {self.api_key}"
45
53
  headers["x-api-key"] = self.api_key
46
54
  if payload is not None:
47
- data = json.dumps(payload).encode("utf-8")
55
+ data = strict_json.dumps(payload).encode("utf-8")
48
56
 
49
57
  req = request.Request(self.base_url + path, data=data, headers=headers, method=method)
50
58
  try:
51
59
  with request.urlopen(req, timeout=self.timeout) as resp:
52
60
  body = resp.read().decode("utf-8")
53
- return json.loads(body) if body else {}
61
+ return strict_json.loads(body) if body else {}
54
62
  except error.HTTPError as exc:
55
63
  body = exc.read().decode("utf-8")
56
64
  try:
57
65
  parsed = json.loads(body)
58
66
  except Exception:
59
67
  parsed = {"message": body}
60
- msg = parsed.get("message") or parsed.get("error") or body
68
+ msg = parsed.get("message") or parsed.get("detail") or parsed.get("error") or body
61
69
  raise JEPAPIError(exc.code, msg, parsed) from exc
@@ -1,4 +1,4 @@
1
- """JEP CLI v0.6 command line interface."""
1
+ """JEP Core 0.7 command line interface with explicit legacy compatibility."""
2
2
 
3
3
  from __future__ import annotations
4
4
 
@@ -10,6 +10,7 @@ from pathlib import Path
10
10
  from typing import Any, Dict
11
11
 
12
12
  from .client import JEPClient, JEPCLIError
13
+ from . import strict_json
13
14
 
14
15
 
15
16
  VALID_VERBS = {"J", "D", "T", "V"}
@@ -17,16 +18,26 @@ VALID_VERBS = {"J", "D", "T", "V"}
17
18
 
18
19
  def parse_json_value(value: str) -> Any:
19
20
  if value == "-":
20
- return json.load(sys.stdin)
21
-
22
- path = Path(value)
23
- if path.exists() and path.is_file():
24
- return json.loads(path.read_text(encoding="utf-8"))
21
+ # Read bytes when available: a text stream may replace malformed UTF-8.
22
+ stream = getattr(sys.stdin, "buffer", sys.stdin)
23
+ return strict_json.loads(stream.read())
25
24
 
26
25
  try:
27
- return json.loads(value)
26
+ return strict_json.loads(value)
28
27
  except json.JSONDecodeError:
29
- return value
28
+ # JSON-looking input must not become a plain string after a parse error.
29
+ if value.lstrip().startswith(("{", "[", '"')):
30
+ raise
31
+ # Inline event JSON may be longer than the filesystem filename limit.
32
+ path = Path(value)
33
+ try:
34
+ is_file = path.is_file()
35
+ except OSError:
36
+ is_file = False
37
+ if is_file:
38
+ return strict_json.loads(path.read_bytes())
39
+ strict_json.validate(value)
40
+ return value
30
41
 
31
42
 
32
43
  def parse_ext_items(items: list[str]) -> Dict[str, Any]:
@@ -35,12 +46,15 @@ def parse_ext_items(items: list[str]) -> Dict[str, Any]:
35
46
  if "=" not in item:
36
47
  raise ValueError(f"extension must be key=json_or_string, got: {item}")
37
48
  key, raw = item.split("=", 1)
49
+ if key in ext:
50
+ raise ValueError(f"duplicate extension: {key!r}")
51
+ strict_json.validate(key)
38
52
  ext[key] = parse_json_value(raw)
39
53
  return ext
40
54
 
41
55
 
42
56
  def print_json(data: Any) -> None:
43
- print(json.dumps(data, indent=2, ensure_ascii=False))
57
+ print(strict_json.dumps(data))
44
58
 
45
59
 
46
60
  def build_client(args: argparse.Namespace) -> JEPClient:
@@ -72,7 +86,8 @@ def cmd_create(args: argparse.Namespace) -> int:
72
86
  if args.ext_crit:
73
87
  payload["ext_crit"] = args.ext_crit
74
88
 
75
- result = build_client(args).create_event(payload)
89
+ client = build_client(args)
90
+ result = client.create_event_legacy(payload) if args.legacy else client.create_event(payload)
76
91
  print_json(result)
77
92
  return 0
78
93
 
@@ -81,18 +96,21 @@ def cmd_verify(args: argparse.Namespace) -> int:
81
96
  event = parse_json_value(args.event)
82
97
  if not isinstance(event, dict):
83
98
  raise ValueError("event must be JSON object or path to JSON event file")
84
- payload = {
85
- "event": event,
86
- "mode": args.mode,
87
- "consume_nonce": args.consume_nonce,
88
- }
99
+ client = build_client(args)
100
+ if args.legacy:
101
+ payload = {"event": event, "format": args.legacy_format}
102
+ result = client.verify_event_legacy(payload)
103
+ print_json(result)
104
+ return 0 if result.get("valid") is True else 2
105
+
106
+ payload = {"event": event, "mode": args.mode}
89
107
  if args.expected_audience:
90
108
  payload["expected_audience"] = args.expected_audience
91
- if args.mode == "acceptance" and not args.expected_audience:
92
- raise ValueError("acceptance mode requires --expected-audience")
93
- result = build_client(args).verify_event(payload)
109
+ if args.max_age_seconds is not None:
110
+ payload["max_age_seconds"] = args.max_age_seconds
111
+ result = client.verify_event(payload)
94
112
  print_json(result)
95
- return 0 if result.get("valid") is True else 2
113
+ return 0 if result.get("status") == "valid" else 2
96
114
 
97
115
 
98
116
  def cmd_health(args: argparse.Namespace) -> int:
@@ -112,7 +130,7 @@ def cmd_extract_event(args: argparse.Namespace) -> int:
112
130
  def build_parser() -> argparse.ArgumentParser:
113
131
  parser = argparse.ArgumentParser(
114
132
  prog="jep",
115
- description="JEP CLI v0.6 for creating and verifying JEP-Core events through the JEP API.",
133
+ description="JEP CLI for JEP Core 0.7. Legacy pre-0.7 paths require explicit flags.",
116
134
  )
117
135
  parser.add_argument("--base-url", default="", help="JEP API base URL. Default: JEP_API_URL or http://127.0.0.1:8000")
118
136
  parser.add_argument("--api-key", default="", help="API key. Default: JEP_API_KEY")
@@ -125,18 +143,21 @@ def build_parser() -> argparse.ArgumentParser:
125
143
  create.add_argument("--who", default="", help="Actor identifier")
126
144
  create.add_argument("--what", required=True, help="JSON value, string, file path, or '-' for stdin")
127
145
  create.add_argument("--aud", default="", help="Audience / validation context")
128
- create.add_argument("--ref", default="", help="Reference event hash")
146
+ create.add_argument("--ref", default="", help="Reference JSON, string, or file path")
129
147
  create.add_argument("--ttl-minutes", type=int, default=None, help="Optional TTL extension in minutes")
130
148
  create.add_argument("--digest-only-who", action="store_true", help="Request digest-only privacy extension")
131
149
  create.add_argument("--ext", action="append", default=[], help="Extension key=json_or_string. May be repeated")
132
150
  create.add_argument("--ext-crit", action="append", default=[], help="Critical extension URI. May be repeated")
151
+ create.add_argument("--legacy", action="store_true", help="Use explicit pre-0.7 create endpoint")
133
152
  create.set_defaults(func=cmd_create)
134
153
 
135
154
  verify = sub.add_parser("verify", help="Verify a JEP event")
136
155
  verify.add_argument("event", help="Event JSON object, event JSON file path, or '-' for stdin")
137
156
  verify.add_argument("--mode", default="archival", choices=["archival", "acceptance"], help="Validation mode")
138
- verify.add_argument("--expected-audience", default="", help="Required receiving audience for acceptance")
139
- verify.add_argument("--consume-nonce", action="store_true", help="Ask verifier to consume nonce")
157
+ verify.add_argument("--expected-audience", default="", help="Optional audience required by the selected acceptance profile")
158
+ verify.add_argument("--max-age-seconds", type=int, default=None, help="Optional profile freshness window")
159
+ verify.add_argument("--legacy", action="store_true", help="Use explicit pre-0.7 legacy verifier")
160
+ verify.add_argument("--legacy-format", default="json-sorted-v1", choices=["json-sorted-v1", "hf-space-v06"], help="Historical decoder format; used only with --legacy")
140
161
  verify.set_defaults(func=cmd_verify)
141
162
 
142
163
  health = sub.add_parser("health", help="Check JEP API health")
@@ -0,0 +1,78 @@
1
+ """Strict JSON input boundary; signature/profile validation stays with the API."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import math
6
+ from typing import Any
7
+
8
+ import rfc8785
9
+
10
+
11
+ def _pairs(pairs):
12
+ result = {}
13
+ for key, value in pairs:
14
+ if key in result:
15
+ raise ValueError(f"duplicate JSON member: {key!r}")
16
+ result[key] = value
17
+ return result
18
+
19
+
20
+ def _constant(token):
21
+ raise ValueError(f"non-JSON numeric constant: {token}")
22
+
23
+
24
+ def validate(value: Any) -> None:
25
+ """Reject lossy/invalid input without rewriting values or signed members.
26
+
27
+ Large integer policy matches Core 0.7.4: exact binary64 integers and their
28
+ JCS shortest-decimal spellings are supported. This is not signature checking.
29
+ """
30
+ if value is None or isinstance(value, bool):
31
+ return
32
+ if isinstance(value, str):
33
+ value.encode("utf-8", errors="strict")
34
+ elif isinstance(value, int):
35
+ if abs(value) > 2**53 - 1:
36
+ try:
37
+ number = float(value)
38
+ if not math.isfinite(number):
39
+ raise ValueError("integer exceeds binary64 range")
40
+ if int(number) != value and rfc8785.dumps(number) != str(value).encode("ascii"):
41
+ raise ValueError("integer is neither exact binary64 nor its JCS spelling")
42
+ except OverflowError as exc:
43
+ raise ValueError("integer exceeds binary64 range") from exc
44
+ elif isinstance(value, float):
45
+ if not math.isfinite(value):
46
+ raise ValueError("non-finite number")
47
+ elif isinstance(value, list):
48
+ for item in value:
49
+ validate(item)
50
+ elif isinstance(value, dict):
51
+ for key, item in value.items():
52
+ if not isinstance(key, str):
53
+ raise ValueError("JSON member names must be strings")
54
+ validate(key)
55
+ validate(item)
56
+ else:
57
+ raise ValueError("unsupported JSON value")
58
+
59
+
60
+ def loads(text: str | bytes) -> Any:
61
+ if isinstance(text, bytes):
62
+ text = text.decode("utf-8", errors="strict")
63
+ # Reject raw surrogate code points even before JSON parsing.
64
+ text.encode("utf-8", errors="strict")
65
+ try:
66
+ value = json.loads(text, object_pairs_hook=_pairs, parse_constant=_constant)
67
+ validate(value)
68
+ return value
69
+ except RecursionError as exc:
70
+ raise ValueError("JSON nesting exceeds parser capacity") from exc
71
+
72
+
73
+ def dumps(value: Any) -> str:
74
+ try:
75
+ validate(value)
76
+ return json.dumps(value, ensure_ascii=False, allow_nan=False)
77
+ except RecursionError as exc:
78
+ raise ValueError("JSON nesting exceeds parser capacity") from exc
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: jep-cli
3
+ Version: 0.7.2
4
+ Summary: Command-line client for JEP Core 0.7 with explicit legacy compatibility
5
+ Author-email: HJS Spec <signal@humanjudgment.org>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/hjs-spec/cli
8
+ Project-URL: Repository, https://github.com/hjs-spec/cli
9
+ Project-URL: Issues, https://github.com/hjs-spec/cli/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Requires-Python: >=3.9
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ License-File: NOTICE.md
18
+ Requires-Dist: rfc8785==0.1.4
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # JEP CLI — JEP Core 0.7
24
+
25
+ Command-line client for creating and verifying current JEP Core 0.7 events
26
+ through the JEP API.
27
+
28
+ Default endpoints:
29
+
30
+ ```text
31
+ POST /v0.7/events/create
32
+ POST /v0.7/events/verify
33
+ GET /health
34
+ ```
35
+
36
+ Historical pre-0.7 handling is explicit through `--legacy`; the CLI never
37
+ retries a failed 0.7 event with a legacy decoder.
38
+
39
+ ## Status
40
+
41
+ Experimental reference client. It does not define Core semantics or determine
42
+ truth, authorization validity, legal effect, causality, or policy outcome.
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install jep-cli
48
+ ```
49
+
50
+ ## Configuration
51
+
52
+ ```bash
53
+ export JEP_API_URL=http://127.0.0.1:8000
54
+ export JEP_API_KEY=
55
+ ```
56
+
57
+ ## Create
58
+
59
+ Judgment:
60
+
61
+ ```bash
62
+ jep create \
63
+ --verb J \
64
+ --who did:example:agent-789 \
65
+ --what '{"claim":"approve","subject":"demo"}'
66
+ ```
67
+
68
+ Delegation:
69
+
70
+ ```bash
71
+ jep create \
72
+ --verb D \
73
+ --who did:example:principal \
74
+ --what '{"delegatee":"did:example:agent","scope":{"actions":["read"]}}'
75
+ ```
76
+
77
+ Termination and Verification require `--ref`. Pass a typed reference as
78
+ JSON when the target is another JEP event.
79
+
80
+ ## Verify
81
+
82
+ ```bash
83
+ jep verify event.json --mode archival
84
+ ```
85
+
86
+ 0.7 validation returns `status` plus independent `checks`, not a cumulative
87
+ Validation Level.
88
+
89
+ ## Explicit legacy verification
90
+
91
+ ```bash
92
+ jep verify old-event.json \
93
+ --legacy \
94
+ --legacy-format json-sorted-v1
95
+ ```
96
+
97
+ Legacy selection must come from known artifact context. Do not use a failed 0.7
98
+ validation as evidence that an event should be treated as 0.6.
99
+
100
+ ## JEP Core 0.7 model
101
+
102
+ - Event Identity is `(who,id)`.
103
+ - Event Hash identifies an exact signed artifact.
104
+ - Core does not require a top-level nonce.
105
+ - D requires `delegatee + scope`.
106
+ - T requires target `ref + termination_scope`.
107
+ - V requires target `ref + verification_scope + result`.
108
+ - chain and policy semantics remain outside Core.
109
+
110
+ ## Related repositories
111
+
112
+ - JEP Core: https://github.com/hjs-spec/jep-core
113
+ - JEP API: https://github.com/hjs-spec/jep-api
114
+ - Python SDK: https://github.com/hjs-spec/sdk-py
115
+ - JavaScript SDK: https://github.com/hjs-spec/sdk-js
116
+ - Go SDK: https://github.com/hjs-spec/sdk-go
117
+
118
+ ## Public draft
119
+
120
+ - https://datatracker.ietf.org/doc/draft-wang-jep-judgment-event-protocol/
121
+
122
+ ## License
123
+
124
+ MIT
@@ -5,6 +5,7 @@ pyproject.toml
5
5
  jep_cli/__init__.py
6
6
  jep_cli/client.py
7
7
  jep_cli/main.py
8
+ jep_cli/strict_json.py
8
9
  jep_cli.egg-info/PKG-INFO
9
10
  jep_cli.egg-info/SOURCES.txt
10
11
  jep_cli.egg-info/dependency_links.txt
@@ -12,4 +13,5 @@ jep_cli.egg-info/entry_points.txt
12
13
  jep_cli.egg-info/requires.txt
13
14
  jep_cli.egg-info/top_level.txt
14
15
  tests/test_acceptance.py
15
- tests/test_cli.py
16
+ tests/test_cli.py
17
+ tests/test_strict_json.py
@@ -1,3 +1,4 @@
1
+ rfc8785==0.1.4
1
2
 
2
3
  [dev]
3
4
  pytest>=7.0.0
@@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "jep-cli"
7
- version = "0.6.1"
8
- description = "Command-line tool for creating and verifying JEP v0.6 events through the JEP API"
7
+ version = "0.7.2"
8
+ description = "Command-line client for JEP Core 0.7 with explicit legacy compatibility"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
11
11
  authors = [
12
12
  { name = "HJS Spec", email = "signal@humanjudgment.org" }
13
13
  ]
14
14
  requires-python = ">=3.9"
15
- dependencies = []
15
+ dependencies = ["rfc8785==0.1.4"]
16
16
  classifiers = [
17
17
  "Development Status :: 3 - Alpha",
18
18
  "Intended Audience :: Developers",