diff --git a/docs/COGITATE.md b/docs/COGITATE.md index 4adb6e16b..d65444c45 100644 --- a/docs/COGITATE.md +++ b/docs/COGITATE.md @@ -126,6 +126,7 @@ enforcement are layered on top of it. | `normal` | default cogitate talents | the `sol` tool (`sol` / `sol call`), the bounded raw-read tier, a finalization tool | | `system-read` | diagnostics boundary for scoped operational evidence | no cogitate talent claims it today (steward was demoted to a deterministic renderer + `lite` generate); the tier remains the declared diagnostics boundary and extension point, with scoped evidence arriving through a talent pre-hook rather than an extra model read tool | | `outbound` | comms-like talents that may submit something that leaves the machine (e.g. `support`) | the `sol` tool (`sol` / `sol call`) and a finalization tool, plus submit-capable support commands gated on per-send owner approval supplied only by a human-initiated chat launch; no raw-read tier — drafts and evidence go through `sol` domain commands | +| `synthesis` | pure sol-surface synthesis talents (e.g. `weekly_reflection`, `partner`) whose source of record is `sol call journal` / `sol call activities`, not the raw journal tree | the `sol` tool (`sol` / `sol call`) and a finalization tool; **no raw-read tier and no submit** — same as `outbound` minus the outbound submit capability. Removing the raw-read tools keeps a synthesis talent from spelunking `chronicle/` / `talents/` / `facets/` and burning its budget instead of reaching the journal through `sol` | Policy denies support send verbs (`create`, `reply`, `attach`, `feedback`) for `normal` / `system-read` runs. `outbound` runs may use those verbs only when the diff --git a/solstone/talent/partner.md b/solstone/talent/partner.md index 210fe2157..437660d70 100644 --- a/solstone/talent/partner.md +++ b/solstone/talent/partner.md @@ -1,5 +1,6 @@ { "type": "cogitate", + "access_tier": "synthesis", "title": "Partner Profile", "description": "Weekly observation of the journal owner's behavioral patterns — work style, communication, priorities, decision-making, expertise", @@ -19,7 +20,8 @@ This is not a conversation. Gather data, observe patterns, update the profile, t ## Step 1: Read current state -Read `identity/partner.md` with the `read_file` tool. +Read the current profile with `journal identity partner` — the settled +`sol`-surface read form for `identity/partner.md`. Note which sections have real observations vs `[observing]` placeholders. diff --git a/solstone/talent/weekly_reflection.md b/solstone/talent/weekly_reflection.md index 2faa39d0f..5f0cc7197 100644 --- a/solstone/talent/weekly_reflection.md +++ b/solstone/talent/weekly_reflection.md @@ -1,5 +1,6 @@ { "type": "cogitate", + "access_tier": "synthesis", "title": "Weekly Reflection", "description": "Sunday-start weekly reflection synthesized from the journal", "schedule": "weekly", diff --git a/solstone/think/cogitate_contract.py b/solstone/think/cogitate_contract.py index de2093239..385f72c51 100644 --- a/solstone/think/cogitate_contract.py +++ b/solstone/think/cogitate_contract.py @@ -27,7 +27,7 @@ You are a solstone cogitate talent running inside the live system. This runtime # Locked cogitate access-tier vocabulary (the C1 contract). Downstream milestones # key per-talent assignment, enforcement, redesign, and lint off these names. -COGITATE_ACCESS_TIERS = ("normal", "system-read", "outbound") +COGITATE_ACCESS_TIERS = ("normal", "system-read", "outbound", "synthesis") # `code-agent` is a documented FUTURE tier — NOT part of the current cogitate # runtime (it needs write access, broad tools, and a repo cwd, deliberately out of @@ -54,6 +54,11 @@ _ACCESS_TIER_CAPABILITIES: dict[str, AccessCapabilities] = { "normal": AccessCapabilities(sol=True, reads=True, submit=False), "system-read": AccessCapabilities(sol=True, reads=True, submit=False), "outbound": AccessCapabilities(sol=True, reads=False, submit=True), + # Pure sol-surface synthesis: the journal is reached only through `sol` + # domain commands, with no raw-filesystem read tier and no outbound submit. + # For synthesis talents (weekly_reflection, partner) whose source of record + # is `sol call journal` / `sol call activities`, not the raw journal tree. + "synthesis": AccessCapabilities(sol=True, reads=False, submit=False), } _missing_access_tiers = set(COGITATE_ACCESS_TIERS) - set(_ACCESS_TIER_CAPABILITIES) diff --git a/tests/test_cogitate_contract.py b/tests/test_cogitate_contract.py index 4bc4219bd..0cfbfe218 100644 --- a/tests/test_cogitate_contract.py +++ b/tests/test_cogitate_contract.py @@ -66,7 +66,7 @@ def test_prompt_body_unchanged_under_cogitate_injection(): def test_cogitate_vocabulary_lock(): - assert COGITATE_ACCESS_TIERS == ("normal", "system-read", "outbound") + assert COGITATE_ACCESS_TIERS == ("normal", "system-read", "outbound", "synthesis") assert COGITATE_READ_TOOL_NAMES == ( "read_file", "list_directory", @@ -107,6 +107,7 @@ def test_expects_emit_final(config, expected): ("normal", (True, True, False)), ("system-read", (True, True, False)), ("outbound", (True, False, True)), + ("synthesis", (True, False, False)), ], ) def test_capabilities_for_access_tier_real_tiers(tier, expected): diff --git a/tests/test_cogitate_contract_harness.py b/tests/test_cogitate_contract_harness.py index 3ad4319aa..fa0574956 100644 --- a/tests/test_cogitate_contract_harness.py +++ b/tests/test_cogitate_contract_harness.py @@ -63,7 +63,11 @@ def test_cogitate_finalization_class_assembles_on_contract( *(["sol"] if caps.sol else []), *(COGITATE_READ_TOOL_NAMES if caps.reads else ()), ] - assert tool_surface == ["sol", *COGITATE_READ_TOOL_NAMES] + # Every real cogitate tier exposes the `sol` surface; the bounded raw-read + # tools are present iff the talent's access tier grants reads. The + # `synthesis` tier (e.g. weekly_reflection) is sol-only by design. + expected_surface = ["sol", *COGITATE_READ_TOOL_NAMES] if caps.reads else ["sol"] + assert tool_surface == expected_surface body, system = assemble_prompt(config, sol_tool_name="sol") assert isinstance(body, str)