hypgraph 0.8.2__tar.gz → 0.8.3__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 (134) hide show
  1. {hypgraph-0.8.2 → hypgraph-0.8.3}/CHANGELOG.md +9 -0
  2. {hypgraph-0.8.2 → hypgraph-0.8.3}/PKG-INFO +1 -1
  3. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/PLAN.md +1 -1
  4. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/RELEASE-READINESS.md +5 -0
  5. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/__init__.py +1 -1
  6. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/plan.py +3 -2
  7. hypgraph-0.8.3/tests/test_next_order.py +45 -0
  8. {hypgraph-0.8.2 → hypgraph-0.8.3}/.gitignore +0 -0
  9. {hypgraph-0.8.2 → hypgraph-0.8.3}/AGENTS.md +0 -0
  10. {hypgraph-0.8.2 → hypgraph-0.8.3}/CITATION.cff +0 -0
  11. {hypgraph-0.8.2 → hypgraph-0.8.3}/DISCLAIMER.md +0 -0
  12. {hypgraph-0.8.2 → hypgraph-0.8.3}/LICENSE +0 -0
  13. {hypgraph-0.8.2 → hypgraph-0.8.3}/NOTICE +0 -0
  14. {hypgraph-0.8.2 → hypgraph-0.8.3}/README.md +0 -0
  15. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/decisions/ADR-001-token-bound-authors.md +0 -0
  16. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/decisions/ADR-002-governance-profiles.md +0 -0
  17. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/profile-workflows-plan.md +0 -0
  18. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/review-2026-10-24.md +0 -0
  19. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/site-plan.md +0 -0
  20. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/spec.md +0 -0
  21. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/ui-plan.md +0 -0
  22. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/verification.md +0 -0
  23. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/README.md +0 -0
  24. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/knowledge.md +0 -0
  25. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/optimization.md +0 -0
  26. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/scientific.md +0 -0
  27. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/software.md +0 -0
  28. {hypgraph-0.8.2 → hypgraph-0.8.3}/docs/workflows/trading.md +0 -0
  29. {hypgraph-0.8.2 → hypgraph-0.8.3}/examples/frameworks/README.md +0 -0
  30. {hypgraph-0.8.2 → hypgraph-0.8.3}/pyproject.toml +0 -0
  31. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/__main__.py +0 -0
  32. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/assertions.py +0 -0
  33. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/blind.py +0 -0
  34. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/bundle.py +0 -0
  35. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/checks.py +0 -0
  36. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/cli.py +0 -0
  37. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/coord.py +0 -0
  38. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/demos/__init__.py +0 -0
  39. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/demos/broad_street.py +0 -0
  40. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/demos/dispute.py +0 -0
  41. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/demos/linked.py +0 -0
  42. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/derive.py +0 -0
  43. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/graph.py +0 -0
  44. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/language.py +0 -0
  45. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/mcp.py +0 -0
  46. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/policy.py +0 -0
  47. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/profiles.py +0 -0
  48. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/references.py +0 -0
  49. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/refusals.py +0 -0
  50. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/report_check.py +0 -0
  51. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/schema.py +0 -0
  52. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/server.py +0 -0
  53. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/skill/SKILL.md +0 -0
  54. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/stats.py +0 -0
  55. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/store.py +0 -0
  56. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/__init__.py +0 -0
  57. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/atlas.css +0 -0
  58. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/atlas.js +0 -0
  59. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/hypgraph.css +0 -0
  60. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/hypgraph.i18n.js +0 -0
  61. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/hypgraph.js +0 -0
  62. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/hypgraph.svg +0 -0
  63. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/index.html +0 -0
  64. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/vendor/LICENSES.md +0 -0
  65. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/vendor/cose-base.js +0 -0
  66. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/vendor/cytoscape-fcose.js +0 -0
  67. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/vendor/cytoscape.min.js +0 -0
  68. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/ui/vendor/layout-base.js +0 -0
  69. {hypgraph-0.8.2 → hypgraph-0.8.3}/src/hypgraph/workflow.py +0 -0
  70. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_accept_work_kind.py +0 -0
  71. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_anchoring.py +0 -0
  72. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_assertions.py +0 -0
  73. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_blind.py +0 -0
  74. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_blind_oracles.py +0 -0
  75. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_borrowed_words.py +0 -0
  76. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_bound_support.py +0 -0
  77. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_bundle_telemetry.py +0 -0
  78. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_cancel_releases_lease.py +0 -0
  79. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_cited_and_failed_support.py +0 -0
  80. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_contradictions.py +0 -0
  81. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_coord.py +0 -0
  82. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_counts_that_bear.py +0 -0
  83. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_d10.py +0 -0
  84. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_demo_dispute.py +0 -0
  85. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_direction_and_units.py +0 -0
  86. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_engine.py +0 -0
  87. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_engine_fixes.py +0 -0
  88. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_figure_said_twice.py +0 -0
  89. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_framework_examples.py +0 -0
  90. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_i18n.py +0 -0
  91. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_incremental.py +0 -0
  92. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_link_translate.py +0 -0
  93. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_linked_records.py +0 -0
  94. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_log_and_check.py +0 -0
  95. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_measure_questions.py +0 -0
  96. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_opposed_answers.py +0 -0
  97. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_option_lead.py +0 -0
  98. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_order_detail.py +0 -0
  99. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_profiles.py +0 -0
  100. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_profiles_041.py +0 -0
  101. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_quantifiers_and_identity.py +0 -0
  102. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_questions_not_assertions.py +0 -0
  103. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_quoted_counterexample.py +0 -0
  104. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_references.py +0 -0
  105. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_refusal_friction.py +0 -0
  106. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_refusal_results.py +0 -0
  107. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_refusals.py +0 -0
  108. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_relation_words.py +0 -0
  109. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_report_answers.py +0 -0
  110. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_rerunnable.py +0 -0
  111. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_restates_scale.py +0 -0
  112. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_server_auth.py +0 -0
  113. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_server_hosts.py +0 -0
  114. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_shape_refusals.py +0 -0
  115. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_stats_not_backtests.py +0 -0
  116. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_stats_values.py +0 -0
  117. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_surfaces.py +0 -0
  118. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_telemetry_stream.py +0 -0
  119. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_trust_boundary.py +0 -0
  120. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_typed_audits.py +0 -0
  121. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_ui_app.py +0 -0
  122. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_ui_engine.py +0 -0
  123. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_uncorrected_effect.py +0 -0
  124. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_unnamed_inputs.py +0 -0
  125. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_complete.py +0 -0
  126. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_lifecycle.py +0 -0
  127. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_scope.py +0 -0
  128. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_scoped_views.py +0 -0
  129. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_trust.py +0 -0
  130. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_verify_views.py +0 -0
  131. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_versions_not_figures.py +0 -0
  132. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_vocabulary_friction.py +0 -0
  133. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_what_a_count_is_of.py +0 -0
  134. {hypgraph-0.8.2 → hypgraph-0.8.3}/tests/test_workflows.py +0 -0
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.8.3 — 2026-11-03: the next-experiments view in a stable order
4
+
5
+ - **`verify --standing` no longer fails on a sound bundle with two or more untested hypotheses.** `next_experiments`
6
+ listed `untested_hypotheses` by iterating a set of ids, so the order followed Python's per-process string hashing:
7
+ a bundle exported in one process carried one order and its re-derivation another, and `hypgraph verify --standing`
8
+ reported a standing mismatch (`<inv>/next`) on a record whose content was identical. The list now follows the order
9
+ the hypotheses were added. Found on a 785-node record; that record and three smaller ones now derive identically
10
+ under six hash seeds.
11
+
3
12
  ## 0.8.2 — 2026-11-01: an extreme that quotes its own counterexample; a disputed answer
4
13
 
5
14
  - **A quoted counterexample no longer excuses an extreme.** A stated count used to exempt an extreme whenever its
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: hypgraph
3
- Version: 0.8.2
3
+ Version: 0.8.3
4
4
  Summary: The evidence layer for AI research agents: a hash-chained research record that checks every claim as it is written and derives how well each is known.
5
5
  Project-URL: Homepage, https://hypgraph.com
6
6
  Project-URL: Documentation, https://hypgraph.com/engineers/
@@ -109,7 +109,7 @@ claim's derived standing.
109
109
  Multi-writer sync between graphs (bundles cover sharing), authentication (the host's job; the HTTP server binds to
110
110
  loopback and is read-only unless started with `--writable`), and a hosted service.
111
111
 
112
- ## Status at 0.8.2 (2026-11-01)
112
+ ## Status at 0.8.3 (2026-11-03)
113
113
 
114
114
  All seven phases are done: the library, bundles, the server and UI, the MCP server, the website, Pegasus running on
115
115
  the package, and releases to PyPI from tags with trusted publishing. What came after the plan, by release, is in
@@ -256,6 +256,11 @@ was taken from a changelog without being checked against the code.*
256
256
  > claim writes changes 5, all now refused (4 lies, 1 retraction worded as the claim). #106 is merged with green CI.
257
257
  > Released as 0.8.2, with the `dispute` demo (#107).
258
258
 
259
+ > **After 0.8.2 (2026-11-03).** One determinism fix in a derived view, no change to the checks: `next_experiments`
260
+ > listed untested hypotheses in a set's hash order, so `verify --standing` could report a mismatch on a sound bundle
261
+ > with two or more of them when the exporting and verifying processes hashed strings differently. The list now follows
262
+ > the order the hypotheses were added. #109 is merged with green CI. Released as 0.8.3.
263
+
259
264
  ## Recommendation: CONDITIONAL GO
260
265
 
261
266
  HypGraph is ready for a public developer preview once #59, #60 and #61 are merged with green CI and released as one
@@ -16,7 +16,7 @@ Standing is derived on every read, never stored; every write is an event in a SH
16
16
  their numbers; reviews pin versions; independence is counted, not assumed. See https://hypgraph.com.
17
17
  """
18
18
 
19
- __version__ = "0.8.2"
19
+ __version__ = "0.8.3"
20
20
 
21
21
  from .bundle import anchored, verify_bundle # noqa: E402
22
22
  from .graph import Author, Graph, GraphError, file_sha256 # noqa: E402
@@ -48,7 +48,8 @@ def next_experiments(g: "Graph", inv: str, limit: int = 10) -> dict:
48
48
  """Planned experiments ranked by how well they discriminate between live hypotheses, whether they can show their
49
49
  own power, and cost — duplicates and leased work flagged. Plus live hypotheses that no experiment tests yet."""
50
50
  s = g.snapshot()
51
- live = set(_live_hypotheses(s, inv))
51
+ order = _live_hypotheses(s, inv) # the record's order; the set is for membership only
52
+ live = set(order)
52
53
  dup = {x for grp in duplicates(s, inv) for x in grp[1:]}
53
54
  rows = []
54
55
  for i, n in s.nodes.items():
@@ -69,7 +70,7 @@ def next_experiments(g: "Graph", inv: str, limit: int = 10) -> dict:
69
70
  rows.sort(key=lambda r: (r["duplicate"], r["lease"] is not None, -r["score"]))
70
71
  tested = {e["dst"] for x, n in s.nodes.items() if n["type"] == "experiment" and n["inv"] == inv
71
72
  for e in s.out.get(x, []) if e["rel"] == "tests"}
72
- gaps = [g.brief(s, h) for h in live if h not in tested]
73
+ gaps = [g.brief(s, h) for h in order if h not in tested]
73
74
  return {"ranked": rows[:limit], "untested_hypotheses": gaps,
74
75
  "rule": "score = hypotheses it separates (distinct expected outcomes) × 1.5 if it can show its own power "
75
76
  "÷ log2(2 + cost in minutes); duplicates and leased work last"}
@@ -0,0 +1,45 @@
1
+ """The next-experiments view lists untested hypotheses in the record's order, not the hash order of a set.
2
+
3
+ ``next_experiments`` built ``untested_hypotheses`` by iterating a set of live hypothesis ids. String hashing is salted
4
+ per process, so the order changed from run to run, and ``hypgraph verify --standing`` failed on any bundle with two or
5
+ more untested hypotheses exported in another process: the bundle carried one order, the re-derivation another.
6
+ Invariants: the list follows the order the hypotheses were added; re-deriving a bundle's standing under any hash seed
7
+ agrees with what it carries."""
8
+ import json
9
+ import os
10
+ import subprocess
11
+ import sys
12
+
13
+ from hypgraph import Graph
14
+
15
+ TITLES = [f"Candidate {c} explains the readings." for c in "ABCDEFGH"]
16
+
17
+
18
+ def record():
19
+ g = Graph()
20
+ inv = g.author("curator").investigation("Readings", "Which candidate explains the readings?")["id"]
21
+ a = g.author("a")
22
+ hs = [a.add("hypothesis", inv, statement=t, predictions=["it fits the held-out readings"])["id"] for t in TITLES]
23
+ a.add("experiment", inv, aim="Compare candidates A and B on the held-out readings.",
24
+ protocol="Fit both candidates to the same held-out readings.", success_criteria="A fit for each.",
25
+ method="least squares",
26
+ links=[{"rel": "tests", "to": hs[0], "data": {"expected": "A fits"}},
27
+ {"rel": "tests", "to": hs[1], "data": {"expected": "B fits"}}])
28
+ return g, inv, hs
29
+
30
+
31
+ def test_untested_follow_the_record_order():
32
+ g, inv, hs = record()
33
+ got = [h["id"] for h in g.next_experiments(inv)["untested_hypotheses"]]
34
+ assert got == hs[2:]
35
+
36
+
37
+ def test_standing_verifies_under_any_hash_seed(tmp_path):
38
+ g, inv, _ = record()
39
+ f = tmp_path / "b.json"
40
+ f.write_text(json.dumps(g.export(inv)), encoding="utf-8")
41
+ for seed in ("0", "1", "2", "3", "4", "5"):
42
+ env = {**os.environ, "PYTHONHASHSEED": seed}
43
+ r = subprocess.run([sys.executable, "-m", "hypgraph", "verify", "--standing", str(f)], cwd=tmp_path, env=env,
44
+ capture_output=True, text=True, encoding="utf-8")
45
+ assert r.returncode == 0, (seed, r.stdout, r.stderr)
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