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
18 changes: 13 additions & 5 deletions SESSION_FOCUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

**See `docs/SPRINT.md` for full sprint plan and task details.** Do not duplicate sprint content here — SPRINT.md is the source of truth for task scope, status, and dependencies.

### Sprint 51 Summary: Minimum Viable Society Validation + Constraint Alignment (COMPLETE)

| Task | Status | Notes |
|------|--------|-------|
| T1: validate_minimum_viable() + Constraint alignment | DONE | Resolves Sprint 49 audit P5+P6. `validate_minimum_viable()` in `web4/role.py`: base-mandatory completeness, differentiation, witnessing. `Constraint` aligned with Rust: `threshold: float` + `hard: bool`. 1 new export (369 total), 12 new tests (2668 total), 0 new files. |

### Sprint 50 Summary: Add SocietyRole + RoleAssignment to Python SDK (COMPLETE)

| Task | Status | Notes |
Expand Down Expand Up @@ -196,7 +202,7 @@ See `docs/SPRINT.md` for full history. Highlights: JSON-LD serialization for all

- **Version**: 0.26.0
- **Modules**: 23 library modules + MCP server entry point (trust, lct, atp, federation, r6, mrh, acp, dictionary, entity, capability, errors, metabolic, binding, society, role, reputation, security, protocol, mcp, attestation, validation, deserialize, generate, mcp_server)
- **Tests**: 2656 passing
- **Tests**: 2668 passing
- **CLI**: `web4 info/validate/list-schemas/roundtrip/generate/selftest/trust` (7 subcommands)
- **Exports**: 368 symbols via `web4/__init__.py`
- **from_dict()**: 58 classmethods across 10 modules — all classes with to_dict()/as_dict() have matching from_dict()
Expand Down Expand Up @@ -272,7 +278,7 @@ Sprint 50 T1 PR pending.

## Completeness Summary

- All 50 sprints COMPLETE (Sprints 1-50, all merged or PR pending)
- All 51 sprints COMPLETE (Sprints 1-51, all merged or PR pending)
- All 9 JSON-LD schemas with cross-language validation vectors (278 total, in pytest)
- All `to_jsonld()` functions have `from_jsonld()` inverses (API symmetry complete)
- All `to_dict()`/`as_dict()` methods have `from_dict()` inverses (58 round-trip methods total)
Expand All @@ -283,7 +289,7 @@ Sprint 50 T1 PR pending.
- MCP server: 8 tools exposing SDK data operations + behavioral trust/reputation resolution to MCP clients
- TrustQuery: to_jsonld() for dispatcher + to_dict() for schema validation (trust-query.schema.json)
- `process_action_outcome()` — action consequence pipeline composing R7Action + ReputationEngine + TrustProfile + ATPAccount
- All 23 submodules have `__all__` declarations, 368 root exports
- All 23 submodules have `__all__` declarations, 369 root exports
- All public methods have docstrings and return type annotations
- `mypy --strict` passes with 0 errors across 26 source files
- Test coverage: 97.8% overall (4 modules at 100%, 16 at 95%+, __main__.py at 90.6%)
Expand All @@ -299,10 +305,12 @@ Sprint 50 T1 PR pending.
---

- **Society Roles added**: `SocietyRole` enum + `RoleAssignment` dataclass + `bootstrap_society_roles()` — resolves CRITICAL audit finding (P1), HIGH role-LCT binding (P2), and HIGH solo-founder genesis (P3)
- **web4-core Society/Role/ATP/R6 alignment**: Cross-language audit identified 14 items (1 CRITICAL: Python SDK missing SocietyRole, 3 HIGH, 3 MEDIUM, 4 LOW) — see `docs/audits/cross-language-society-role-atp-r6-alignment-2026-05-14.md`. P1-P3 resolved by Sprint 50. P4 (MetabolicState) and P7 (role integration) need operator decisions. P5 (validate_minimum_viable) now unblocked.
- **Minimum viable society validation**: `validate_minimum_viable()` added to Python SDK — resolves audit P5 (cross-language parity with Rust `Society::validate_minimum_viable()`)
- **Constraint alignment**: `Constraint` dataclass upgraded from `value: Any` to `threshold: float` + `hard: bool` — resolves audit P6 (cross-language parity with Rust `Constraint`)
- **web4-core Society/Role/ATP/R6 alignment**: Cross-language audit identified 14 items (1 CRITICAL: Python SDK missing SocietyRole, 3 HIGH, 3 MEDIUM, 4 LOW) — see `docs/audits/cross-language-society-role-atp-r6-alignment-2026-05-14.md`. P1-P3 resolved by Sprint 50. P5-P6 resolved by Sprint 51. P4 (MetabolicState) and P7 (role integration) need operator decisions.
- **web4-trust-core T3/V3 alignment**: Cross-language T3/V3 audit identified 8 divergences (1 CRITICAL, 4 HIGH) between Rust/WASM and spec/Python SDK — see `docs/audits/cross-language-t3v3-alignment-2026-05-13.md`
- **Parameter governance**: All trust/value/energy parameters classified into three tiers (protocol-invariant, society-configurable, simulation-only) — see `web4-standard/core-spec/t3-v3-tensors.md` §10

---

*Updated by autonomous session, 2026-05-14 (Sprint 50SocietyRole + RoleAssignment added to Python SDK)*
*Updated by autonomous session, 2026-05-14 (Sprint 51validate_minimum_viable + Constraint alignment)*
29 changes: 28 additions & 1 deletion docs/SPRINT.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
# Web4 Sprint Plan

**Created**: 2026-03-14
**Updated**: 2026-05-14 (Sprint 50)
**Updated**: 2026-05-14 (Sprint 51)
**Phase**: Development
**Track**: web4 (Legion)

---

## Sprint 51: Minimum Viable Society Validation + Constraint Alignment (2026-05-14)

Resolves two remaining autonomous-actionable items from the Sprint 49
cross-language audit fix queue: P5 (validate_minimum_viable) and P6
(Constraint threshold + hard flag alignment).

### T1: validate_minimum_viable() + Constraint alignment
**Status**: DONE
**Completed**: 2026-05-14
**Authorized by**: Sprint 49 audit fix queue P5+P6. Policy-reviewed and approved.
**Scope**:
1. **P5 — `validate_minimum_viable()`**: New function in `web4/role.py` per
`inter-society-protocol.md` §6.2 and Rust `Society::validate_minimum_viable()`.
Checks base-mandatory completeness, internal differentiation (≥2 fillers when
operational), witnessing capacity (Witness or Auditor when operational).
2. **P6 — Constraint alignment**: Updated `Constraint` dataclass in `web4/r6.py`
from `value: Any` to `threshold: float` + `hard: bool = True`. Updated
serialization, JSON schemas, and test vectors.

**Result**: 1 new export (369 total), 12 new tests (2668 total), 0 new files.
mypy --strict clean, ruff lint/format clean.

**Remaining from audit**: P4 (MetabolicState — needs operator decision),
P7 (role integration — needs operator decision).

---

## Sprint 50: Add SocietyRole + RoleAssignment to Python SDK (2026-05-14)

Implements the top 3 items from the Sprint 49 cross-language audit fix queue:
Expand Down
14 changes: 7 additions & 7 deletions web4-standard/implementation/sdk/tests/test_r6.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def test_prohibition_overrides_permission(self):
def test_constraint_minimum(self):
rules = Rules(
constraints=[
Constraint(constraint_type="atp_minimum", value=50),
Constraint(constraint_type="atp_minimum", threshold=50),
]
)
assert rules.check_constraint("atp_minimum", 100)
Expand All @@ -90,7 +90,7 @@ def test_constraint_minimum(self):
def test_constraint_maximum(self):
rules = Rules(
constraints=[
Constraint(constraint_type="rate_limit", value=100),
Constraint(constraint_type="rate_limit", threshold=100),
]
)
assert rules.check_constraint("rate_limit", 50)
Expand All @@ -100,7 +100,7 @@ def test_constraint_maximum(self):
def test_no_matching_constraint(self):
rules = Rules(
constraints=[
Constraint(constraint_type="atp_minimum", value=50),
Constraint(constraint_type="atp_minimum", threshold=50),
]
)
# No constraint for "rate_limit" → passes
Expand Down Expand Up @@ -856,8 +856,8 @@ def _make_full_action(self) -> R7Action:
law_hash="sha256:governance_v2",
society="lct:web4:society:genesis",
constraints=[
Constraint(constraint_type="atp_minimum", value=50),
Constraint(constraint_type="rate_limit", value=100),
Constraint(constraint_type="atp_minimum", threshold=50),
Constraint(constraint_type="rate_limit", threshold=100),
],
permissions=["read", "analyze"],
prohibitions=["delete"],
Expand Down Expand Up @@ -1296,7 +1296,7 @@ def test_full_action_validates(self):
rules=Rules(
law_hash="sha256:abc",
society="lct:society:genesis",
constraints=[Constraint(constraint_type="atp_minimum", value=50)],
constraints=[Constraint(constraint_type="atp_minimum", threshold=50)],
permissions=["read"],
),
role=Role(
Expand Down Expand Up @@ -1394,7 +1394,7 @@ def _make_full_action(self):
rules=Rules(
law_hash="lh1",
society="soc1",
constraints=[Constraint("trust_min", 0.5)],
constraints=[Constraint("trust_min", 0.5, True)],
permissions=["read"],
prohibitions=["delete"],
),
Expand Down
23 changes: 18 additions & 5 deletions web4-standard/implementation/sdk/tests/test_r6_roundtrip.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,30 @@

class TestConstraintRoundTrip:
def test_basic(self) -> None:
c = Constraint(constraint_type="rate_limit", value=100)
c = Constraint(constraint_type="rate_limit", threshold=100)
assert Constraint.from_dict(c.to_dict()) == c

def test_string_value(self) -> None:
c = Constraint(constraint_type="witness_required", value="true")
def test_hard_default(self) -> None:
c = Constraint(constraint_type="witness_quorum", threshold=3.0)
assert c.hard is True
assert Constraint.from_dict(c.to_dict()) == c

def test_soft_constraint(self) -> None:
c = Constraint(constraint_type="rate_limit", threshold=100, hard=False)
assert c.hard is False
assert Constraint.from_dict(c.to_dict()) == c

def test_float_value(self) -> None:
c = Constraint(constraint_type="atp_minimum", value=50.5)
c = Constraint(constraint_type="atp_minimum", threshold=50.5)
assert Constraint.from_dict(c.to_dict()) == c

def test_legacy_value_key(self) -> None:
"""from_dict accepts legacy 'value' key for backward compatibility."""
d = {"type": "atp_minimum", "value": 42}
c = Constraint.from_dict(d)
assert c.threshold == 42.0
assert c.hard is True


class TestRulesRoundTrip:
def test_empty(self) -> None:
Expand All @@ -48,7 +61,7 @@ def test_full(self) -> None:
law_hash="abc123",
society="test-society",
constraints=[
Constraint("rate_limit", 100),
Constraint("rate_limit", 100.0),
Constraint("atp_minimum", 10.0),
],
permissions=["read", "write"],
Expand Down
2 changes: 1 addition & 1 deletion web4-standard/implementation/sdk/web4/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
- Deserialization — generic JSON-LD dispatcher for all Web4 types
- Generation — produce minimal valid JSON-LD documents for any Web4 type

23 modules + MCP server, 368 exports, 2627 tests, 3 behavioral functions, 8 MCP tools, 7 CLI subcommands.
23 modules + MCP server, 369 exports, 2668 tests, 3 behavioral functions, 8 MCP tools, 7 CLI subcommands.
v0.26.0: CI quality gates (strict mypy, ruff lint, ruff format) enforced on every PR.
These modules define the canonical data types and algorithms specified in the web4-standard.
They work offline (no network services required) and are designed to be
Expand Down
49 changes: 37 additions & 12 deletions web4-standard/implementation/sdk/web4/r6.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,45 @@ class ReputationComputationError(R7Error):

@dataclass(frozen=True)
class Constraint:
"""A single constraint within Rules."""
"""A single constraint within Rules.

constraint_type: str # e.g. "rate_limit", "atp_minimum", "witness_required"
value: Any # threshold or limit
Cross-language parity with ``web4-core/src/r6.rs::Constraint``.

Attributes:
constraint_type: Constraint kind (e.g. "rate_limit", "min_atp",
"witness_quorum").
threshold: Numeric threshold value for the constraint.
hard: If True the constraint blocks execution; if False it warns
but allows the action to proceed. Defaults to True.
"""

constraint_type: str
threshold: float
hard: bool = True

def to_dict(self) -> Dict[str, Any]:
"""Serialize to dict with 'type' and 'value' keys."""
return {"type": self.constraint_type, "value": self.value}
"""Serialize to dict."""
return {
"type": self.constraint_type,
"threshold": self.threshold,
"hard": self.hard,
}

@classmethod
def from_dict(cls, d: Dict[str, Any]) -> "Constraint":
"""Deserialize from dict produced by to_dict()."""
return cls(constraint_type=d["type"], value=d["value"])
"""Deserialize from dict.

Accepts either ``threshold`` (current) or ``value`` (legacy) key
for the numeric threshold.
"""
raw = d.get("threshold", d.get("value"))
if raw is None:
raise KeyError("Constraint dict must contain 'threshold' or 'value'")
return cls(
constraint_type=d["type"],
threshold=float(raw),
hard=d.get("hard", True),
)


@dataclass
Expand Down Expand Up @@ -165,8 +191,9 @@ def check_constraint(self, constraint_type: str, actual_value: float) -> bool:
"""Check a specific constraint. Returns True if no constraint of that type exists."""
for c in self.constraints:
if c.constraint_type == constraint_type:
if isinstance(c.value, (int, float)):
return actual_value >= c.value if constraint_type.endswith("_minimum") else actual_value <= c.value
return (
actual_value >= c.threshold if constraint_type.endswith("_minimum") else actual_value <= c.threshold
)
return True

def to_dict(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -940,9 +967,7 @@ def from_jsonld(cls, doc: Dict[str, Any]) -> R7Action:
"""
# 1. Rules
rules_data = doc.get("rules", {})
constraints = [
Constraint(constraint_type=c["type"], value=c["value"]) for c in rules_data.get("constraints", [])
]
constraints = [Constraint.from_dict(c) for c in rules_data.get("constraints", [])]
rules = Rules(
law_hash=rules_data.get("lawHash", ""),
society=rules_data.get("society", ""),
Expand Down
9 changes: 7 additions & 2 deletions web4-standard/implementation/sdk/web4/schema_registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -2564,13 +2564,18 @@
"type": "object",
"required": [
"type",
"value"
"threshold"
],
"properties": {
"type": {
"type": "string"
},
"value": {}
"threshold": {
"type": "number"
},
"hard": {
"type": "boolean"
}
},
"additionalProperties": false
},
Expand Down
5 changes: 3 additions & 2 deletions web4-standard/schemas/r7-action-jsonld.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@
"type": "array",
"items": {
"type": "object",
"required": ["type", "value"],
"required": ["type", "threshold"],
"properties": {
"type": { "type": "string" },
"value": {}
"threshold": { "type": "number" },
"hard": { "type": "boolean" }
},
"additionalProperties": false
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
"lawHash": "sha256:law_hash_002",
"society": "lct:web4:society:research",
"constraints": [
{"type": "time_limit", "value": 3600},
{"type": "budget_cap", "value": 100}
{"type": "time_limit", "threshold": 3600, "hard": true},
{"type": "budget_cap", "threshold": 100, "hard": true}
],
"permissions": ["read", "analyze"],
"prohibitions": ["delete", "modify"]
Expand Down
Loading