repopact 2.1.0__tar.gz → 2.3.0__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.
Files changed (48) hide show
  1. {repopact-2.1.0 → repopact-2.3.0}/PKG-INFO +3 -3
  2. {repopact-2.1.0 → repopact-2.3.0}/README.md +2 -2
  3. repopact-2.3.0/VERSION +1 -0
  4. {repopact-2.1.0 → repopact-2.3.0}/pyproject.toml +1 -0
  5. repopact-2.3.0/schemas/adopter-fleet.schema.json +96 -0
  6. {repopact-2.1.0 → repopact-2.3.0}/schemas/conformance-manifest.schema.json +20 -1
  7. {repopact-2.1.0 → repopact-2.3.0}/scripts/adopt_repo.py +17 -10
  8. {repopact-2.1.0 → repopact-2.3.0}/scripts/doctor.py +17 -8
  9. repopact-2.3.0/scripts/fleet_verify.py +529 -0
  10. {repopact-2.1.0 → repopact-2.3.0}/scripts/generate_dashboard.py +30 -16
  11. {repopact-2.1.0 → repopact-2.3.0}/scripts/init_repo.py +3 -0
  12. {repopact-2.1.0 → repopact-2.3.0}/scripts/new.py +3 -0
  13. {repopact-2.1.0 → repopact-2.3.0}/scripts/plan_import.py +3 -0
  14. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/PKG-INFO +3 -3
  15. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/SOURCES.txt +3 -0
  16. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/top_level.txt +1 -0
  17. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact_cli.py +51 -13
  18. {repopact-2.1.0 → repopact-2.3.0}/scripts/run_conformance.py +60 -1
  19. {repopact-2.1.0 → repopact-2.3.0}/scripts/takeover.py +3 -0
  20. {repopact-2.1.0 → repopact-2.3.0}/scripts/validate_repo.py +129 -12
  21. {repopact-2.1.0 → repopact-2.3.0}/tests/test_conformance.py +43 -9
  22. repopact-2.3.0/tests/test_fleet_verify.py +233 -0
  23. {repopact-2.1.0 → repopact-2.3.0}/tests/test_validate_repo.py +33 -10
  24. repopact-2.1.0/VERSION +0 -1
  25. {repopact-2.1.0 → repopact-2.3.0}/LICENSE +0 -0
  26. {repopact-2.1.0 → repopact-2.3.0}/schemas/audit-finding.schema.json +0 -0
  27. {repopact-2.1.0 → repopact-2.3.0}/schemas/evidence-run.schema.json +0 -0
  28. {repopact-2.1.0 → repopact-2.3.0}/schemas/frozen-surface.schema.json +0 -0
  29. {repopact-2.1.0 → repopact-2.3.0}/schemas/invariants.schema.json +0 -0
  30. {repopact-2.1.0 → repopact-2.3.0}/schemas/record-frontmatter.schema.json +0 -0
  31. {repopact-2.1.0 → repopact-2.3.0}/schemas/work-item.schema.json +0 -0
  32. {repopact-2.1.0 → repopact-2.3.0}/scripts/check_frozen_surface.py +0 -0
  33. {repopact-2.1.0 → repopact-2.3.0}/scripts/frontmatter.py +0 -0
  34. {repopact-2.1.0 → repopact-2.3.0}/scripts/generate_spec.py +0 -0
  35. {repopact-2.1.0 → repopact-2.3.0}/scripts/repo_model.py +0 -0
  36. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/dependency_links.txt +0 -0
  37. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/entry_points.txt +0 -0
  38. {repopact-2.1.0 → repopact-2.3.0}/scripts/repopact.egg-info/requires.txt +0 -0
  39. {repopact-2.1.0 → repopact-2.3.0}/scripts/track_import.py +0 -0
  40. {repopact-2.1.0 → repopact-2.3.0}/setup.cfg +0 -0
  41. {repopact-2.1.0 → repopact-2.3.0}/templates/README.md +0 -0
  42. {repopact-2.1.0 → repopact-2.3.0}/templates/decision.md +0 -0
  43. {repopact-2.1.0 → repopact-2.3.0}/templates/evidence-run.json +0 -0
  44. {repopact-2.1.0 → repopact-2.3.0}/templates/policy.md +0 -0
  45. {repopact-2.1.0 → repopact-2.3.0}/templates/work-item.README.md +0 -0
  46. {repopact-2.1.0 → repopact-2.3.0}/templates/work-item.json +0 -0
  47. {repopact-2.1.0 → repopact-2.3.0}/tests/test_plan_import_links.py +0 -0
  48. {repopact-2.1.0 → repopact-2.3.0}/tests/test_takeover_refs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: repopact
3
- Version: 2.1.0
3
+ Version: 2.3.0
4
4
  Summary: A repository-native standard for durable agent work: binding invariants, evidence-gated work items, and drift audits.
5
5
  License: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/ForgeWireLabs/repopact
@@ -22,8 +22,8 @@ cannot be silently weakened.
22
22
  > The repository is the pact: authority, intent, evidence, and history that survive every
23
23
  > session.
24
24
 
25
- `pip install repopact` · Apache-2.0 · current release **2.1.0**
26
- ([changelog](decisions/0024-release-2.1.0-proposed-lifecycle.md)).
25
+ `pip install repopact` · Apache-2.0 · current release **2.2.0**
26
+ ([changelog](decisions/0025-release-2.2.0-dashboard-integrity.md)).
27
27
 
28
28
  ## How it relates to `AGENTS.md`
29
29
 
@@ -9,8 +9,8 @@ cannot be silently weakened.
9
9
  > The repository is the pact: authority, intent, evidence, and history that survive every
10
10
  > session.
11
11
 
12
- `pip install repopact` · Apache-2.0 · current release **2.1.0**
13
- ([changelog](decisions/0024-release-2.1.0-proposed-lifecycle.md)).
12
+ `pip install repopact` · Apache-2.0 · current release **2.2.0**
13
+ ([changelog](decisions/0025-release-2.2.0-dashboard-integrity.md)).
14
14
 
15
15
  ## How it relates to `AGENTS.md`
16
16
 
repopact-2.3.0/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.3.0
@@ -34,6 +34,7 @@ py-modules = [
34
34
  "new",
35
35
  "check_frozen_surface",
36
36
  "frontmatter",
37
+ "fleet_verify",
37
38
  "run_conformance",
38
39
  ]
39
40
 
@@ -0,0 +1,96 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "adopter-fleet.schema.json",
4
+ "type": "object",
5
+ "additionalProperties": false,
6
+ "required": ["version", "upstream", "adopters"],
7
+ "properties": {
8
+ "$schema": {"type": "string"},
9
+ "version": {"const": 1},
10
+ "upstream": {
11
+ "type": "object",
12
+ "additionalProperties": false,
13
+ "required": ["repository", "version_file"],
14
+ "properties": {
15
+ "repository": {"type": "string", "pattern": "^[^/]+/[^/]+$"},
16
+ "version_file": {"type": "string", "minLength": 1}
17
+ }
18
+ },
19
+ "adopters": {
20
+ "type": "array",
21
+ "minItems": 1,
22
+ "items": {"$ref": "#/$defs/adopter"}
23
+ }
24
+ },
25
+ "$defs": {
26
+ "sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"},
27
+ "adopter": {
28
+ "type": "object",
29
+ "additionalProperties": false,
30
+ "required": ["id", "repository", "default_branch", "consumption", "validation_commands"],
31
+ "properties": {
32
+ "id": {"type": "string", "pattern": "^[a-z0-9][a-z0-9-]*$"},
33
+ "repository": {"type": "string", "pattern": "^[^/]+/[^/]+$"},
34
+ "default_branch": {"type": "string", "minLength": 1},
35
+ "consumption": {
36
+ "oneOf": [
37
+ {"$ref": "#/$defs/pypiConsumption"},
38
+ {"$ref": "#/$defs/vendoredConsumption"}
39
+ ]
40
+ },
41
+ "validation_commands": {
42
+ "type": "array",
43
+ "minItems": 1,
44
+ "items": {"type": "string", "minLength": 1}
45
+ }
46
+ }
47
+ },
48
+ "pypiConsumption": {
49
+ "type": "object",
50
+ "additionalProperties": false,
51
+ "required": ["type", "package", "version_file"],
52
+ "properties": {
53
+ "type": {"const": "pypi"},
54
+ "package": {"const": "repopact"},
55
+ "version_file": {"type": "string", "minLength": 1}
56
+ }
57
+ },
58
+ "vendoredConsumption": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["type", "version_file", "upstream_version", "upstream_revision", "files"],
62
+ "properties": {
63
+ "type": {"const": "vendored"},
64
+ "version_file": {"type": "string", "minLength": 1},
65
+ "upstream_version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
66
+ "upstream_revision": {"type": "string", "pattern": "^[0-9a-f]{40}$"},
67
+ "files": {
68
+ "type": "array",
69
+ "minItems": 1,
70
+ "items": {"$ref": "#/$defs/vendoredFile"}
71
+ }
72
+ }
73
+ },
74
+ "vendoredFile": {
75
+ "type": "object",
76
+ "additionalProperties": false,
77
+ "required": ["upstream_path", "adopter_path", "mode", "upstream_sha256", "adopter_sha256"],
78
+ "properties": {
79
+ "upstream_path": {"type": "string", "minLength": 1},
80
+ "adopter_path": {"type": "string", "minLength": 1},
81
+ "mode": {"enum": ["exact", "overlay"]},
82
+ "upstream_sha256": {"$ref": "#/$defs/sha256"},
83
+ "adopter_sha256": {"$ref": "#/$defs/sha256"},
84
+ "overlay_path": {"type": "string", "minLength": 1},
85
+ "overlay_sha256": {"$ref": "#/$defs/sha256"}
86
+ },
87
+ "allOf": [
88
+ {
89
+ "if": {"properties": {"mode": {"const": "overlay"}}},
90
+ "then": {"required": ["overlay_path", "overlay_sha256"]},
91
+ "else": {"not": {"anyOf": [{"required": ["overlay_path"]}, {"required": ["overlay_sha256"]}]}}
92
+ }
93
+ ]
94
+ }
95
+ }
96
+ }
@@ -2,16 +2,34 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "conformance-manifest.schema.json",
4
4
  "type": "object",
5
- "required": ["suite_version", "fixtures_root", "cases"],
5
+ "additionalProperties": false,
6
+ "required": ["suite_version", "fixtures_root", "rules", "cases"],
6
7
  "properties": {
8
+ "$schema": {"type": "string"},
7
9
  "suite_version": {"type": "string", "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"},
8
10
  "spec_version_file": {"type": "string"},
9
11
  "fixtures_root": {"type": "string", "minLength": 1},
12
+ "rules": {
13
+ "type": "array",
14
+ "minItems": 1,
15
+ "items": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["id", "source", "enforced_by", "description"],
19
+ "properties": {
20
+ "id": {"type": "string", "minLength": 1},
21
+ "source": {"type": "string", "minLength": 1},
22
+ "enforced_by": {"type": "string", "minLength": 1},
23
+ "description": {"type": "string", "minLength": 1}
24
+ }
25
+ }
26
+ },
10
27
  "cases": {
11
28
  "type": "array",
12
29
  "minItems": 1,
13
30
  "items": {
14
31
  "type": "object",
32
+ "additionalProperties": false,
15
33
  "required": ["id", "path", "expect", "rules", "description"],
16
34
  "properties": {
17
35
  "id": {"type": "string", "minLength": 1},
@@ -19,6 +37,7 @@
19
37
  "overlay_on": {"type": "string", "minLength": 1},
20
38
  "expect": {"enum": ["accept", "reject"]},
21
39
  "expected_message": {"type": "string"},
40
+ "dashboard": {"enum": ["canonical", "preserve", "remove"]},
22
41
  "rules": {"type": "array", "items": {"type": "string"}, "minItems": 1},
23
42
  "description": {"type": "string", "minLength": 1}
24
43
  },
@@ -21,9 +21,10 @@ import re
21
21
  import subprocess
22
22
  import sys
23
23
  from datetime import date, datetime, timedelta
24
- from pathlib import Path
25
-
26
- import init_repo # reuse _seed_dir, _json/_write semantics, LIFECYCLE
24
+ from pathlib import Path
25
+
26
+ import generate_dashboard
27
+ import init_repo # reuse _seed_dir, _json/_write semantics, LIFECYCLE
27
28
 
28
29
 
29
30
  # --- non-destructive primitives --------------------------------------------
@@ -330,16 +331,22 @@ def adopt(target: Path, today: date | None = None, dry_run: bool = False) -> Rep
330
331
  "from the repository scan rather than proven by a run. Attach real verification evidence and\n"
331
332
  "run `repopact doctor` to ratchet it to concrete, then complete it. " + summary + "\n", target)
332
333
 
333
- rep.write(target / "decisions" / "0001-adopt-repopact.md",
334
+ rep.write(target / "decisions" / "0001-adopt-repopact.md",
334
335
  "---\nid: 0001\ntitle: Adopt RepoPact\nstatus: accepted\n"
335
336
  f"date: {today.isoformat()}\nsupersedes: []\n---\n\n# 0001: Adopt RepoPact\n\n## Context\n\n"
336
337
  "The project already had ad-hoc governance (CODEOWNERS, CI gates, AGENTS.md). RepoPact\n"
337
- "makes those bindings explicit and machine-checkable.\n\n## Decision\n\n"
338
- "Adopt RepoPact; existing workflows become binding gates (INV-2) and ownership becomes\n"
339
- "scopes/roles. Existing files were preserved; RepoPact records were added around them.\n", target)
340
-
341
- rep.gitignored = gitignored_records(target, rep.created)
342
- return rep
338
+ "makes those bindings explicit and machine-checkable.\n\n## Decision\n\n"
339
+ "Adopt RepoPact; existing workflows become binding gates (INV-2) and ownership becomes\n"
340
+ "scopes/roles. Existing files were preserved; RepoPact records were added around them.\n", target)
341
+
342
+ # The dashboard is derived, but adoption remains non-destructive: create the
343
+ # canonical projection only when the reserved path is absent. An existing file
344
+ # is preserved and validation will identify it if it is not canonical.
345
+ dashboard_text = "" if dry_run else generate_dashboard.generate(target, today=today)
346
+ rep.write(target / "audits" / "reports" / "dashboard.md", dashboard_text, target)
347
+
348
+ rep.gitignored = gitignored_records(target, rep.created)
349
+ return rep
343
350
 
344
351
 
345
352
  def _print_report(rep: Report) -> None:
@@ -20,10 +20,11 @@ import shutil
20
20
  import sys
21
21
  from dataclasses import dataclass
22
22
  from datetime import date, timedelta
23
- from pathlib import Path
24
-
25
- import adopt_repo
26
- import validate_repo
23
+ from pathlib import Path
24
+
25
+ import adopt_repo
26
+ import generate_dashboard
27
+ import validate_repo
27
28
 
28
29
 
29
30
  @dataclass
@@ -296,10 +297,18 @@ def fix(root: Path, today: date | None = None) -> list[str]:
296
297
  # 6. ratchet provisional records whose evidence is now concrete (decision 0021)
297
298
  actions.extend(_ratchet_provisional(root))
298
299
 
299
- # 7. migrate preflight on upgrade: grandfather pre-2.0 work items (decision 0021)
300
- actions.extend(_migrate_preflight(root, today))
301
-
302
- return actions
300
+ # 7. migrate preflight on upgrade: grandfather pre-2.0 work items (decision 0021)
301
+ actions.extend(_migrate_preflight(root, today))
302
+
303
+ # 8. derived output is safe to repair because it is fully reproducible.
304
+ dashboard = root / "audits" / "reports" / "dashboard.md"
305
+ expected = generate_dashboard.generate(root, today=today)
306
+ actual = dashboard.read_text(encoding="utf-8") if dashboard.is_file() else None
307
+ if actual != expected:
308
+ generate_dashboard.write_dashboard(root, today=today)
309
+ actions.append("regenerated audits/reports/dashboard.md")
310
+
311
+ return actions
303
312
 
304
313
 
305
314
  def main() -> int: