Skip to content
35 changes: 35 additions & 0 deletions docs/contract-assert-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Contract assert policy

**What this is:** a machine-checkable **lint** for mupot machine contracts
(JSON + TS module + vitest suite source text). It is **not** enforcement —
a motivated builder can step around it in one or two lines (omit a mirror
declaration with its assertion, comment out an assertion token, or alias a
lifecycle literal). Do not describe it as a production gate.

**Owner of `src/contracts/contract-assert-policy.ts`:** this branch
(`cursor/contract-assert-policy`). Consumer lanes (owner-experience,
brain-learning-ranker, …) must copy the blob verbatim and must not diverge.
Divergent edits land without merge conflicts and silently weaken other
consumers — pick this owner before a third adopter.

## Rules

1. **Lifecycle fields** (`status`, `mode`, `phase`): the policy spec must declare `allowedValues` and `whoMayFlip`. Contract JSON values must be members of `allowedValues`. Tests must **not** use `expect(contract.status).toBe('literal')` — assert membership in the declared set instead. `whoMayFlip` length-only checks are decorative unless the consumer also drift-locks the contents against a design doc / frozen TS constant.

2. **JSON↔TS mirrors**: mirrored JSON paths must match exported TS constants. Tests must assert `expect(contract.path).toEqual([...TS_CONSTANT])` or `.toBe(TS_CONSTANT)` — never retype literals (`['talk', 'know']`) in the test. Missing TS export is a finding. Finding code `json_ts_mirror_assertion_token_absent` means the suite **source text** lacks the assertion token — commented-out / `it.skip` / dead-branch text still counts. Rename honesty: this is token presence, not "assertion runs".

## Usage

```typescript
import { runContractAssertPolicy } from '../src/contracts/contract-assert-policy'

const findings = runContractAssertPolicy({
spec: { lifecycleFields, jsonTsMirrors },
contractJson,
tsExports,
testSource,
})
expect(findings).toEqual([])
```

Implementation: `src/contracts/contract-assert-policy.ts`. Self-test (all finding codes + mutation battery): `tests/contract-assert-policy.test.ts`.
162 changes: 162 additions & 0 deletions docs/owner-experience-v1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{
"id": "owner-experience/v1",
"status": "design",
"spec": "docs/superpowers/specs/2026-07-27-owner-experience-unified-surface-design.md",
"thesis": "Owner owns the goal and the gate; the mubot owns execution and adaptation; one relationship with Talk, Know, and Watch facets bound to a single project outcome.",
"artifactRef": "4cb8d84f-b5b9-4a55-a47c-3af193161b19",
"facets": ["talk", "know", "watch"],
"homeRequiredFacets": ["know", "watch"],
"talkOptionalUntil": "tier1-persistent-mubot-505-revived",
"loop": [
"goal",
"sense",
"rank",
"act",
"receipt",
"learn",
"adapt",
"gate"
],
"principles": [
"one-face",
"goals-not-tasks",
"honest-by-construction",
"earned-autonomy",
"visible-learning",
"owner-owns-goals-and-gates"
],
"invariants": [
"owner-owns-goal-mubot-cannot-redefine",
"owner-owns-gate-mubot-cannot-self-verdict",
"receipts-resolved-by-id-not-label",
"progress-never-fake-green",
"earned-autonomy-one-step-with-verified-wins",
"earned-autonomy-wins-consumed-after-widen",
"earned-autonomy-scope-bound-to-project-and-agent",
"lesson-requires-receipt-id",
"talk-v1-tier1-mubot-only-when-present",
"learn-adapt-instinct-requires-port4-prerequisite",
"brain-remains-rank-not-act",
"mechanism-lock-ne-trust-lock"
],
"talk": {
"v1Runtime": "tier1_persistent_mubot",
"tier1Status": "closed-unmerged-pr-505",
"tier2Status": "dyad-gate-blocked",
"tier2AllowedOnlyAfter": "tier2-user-chat/v1-pass",
"homePolicy": "optional-facet-until-tier1-revived"
},
"trustLevels": [
{ "level": 0, "autonomy": "suggest" },
{ "level": 1, "autonomy": "draft" },
{ "level": 2, "autonomy": "execute_with_approval" },
{ "level": 3, "autonomy": "execute" }
],
"earnedAutonomy": {
"maxStepsPerWiden": 1,
"defaultRequiredWins": 3,
"minRequiredWins": 3,
"winVerification": "branded-VerifiedWinRef-from-WinReceiptResolver-WeakSet-registry",
"winConstructor": "verifiedWinRefFromResolver",
"trustBoundary": "injected-WinReceiptResolver-plus-WeakSet-like-ranker-VerifiedReceiptRef",
"winConsumptionPolicy": "mark_consumed_after_successful_widen",
"dedupByReceiptId": true,
"scopeKeysRequired": ["projectId", "agentId"],
"decider": "owner_or_admin_human",
"mubotSelfWiden": false,
"note": "Same three receipts cannot climb the ladder — consumeReceiptIds must be persisted; top of ladder (execute) is NOT auto-gated per autonomyImpliesGate"
},
"progress": {
"allowedKinds": ["measured", "unmeasured", "unavailable"],
"forbidFakeGreen": true,
"v1Mode": "unmeasured_until_project_kpi",
"metricSourceIdType": "KpiSourceId",
"sourceWiredCallerBoolean": false,
"projectScopedKpiSourceIds": [],
"measuredUnreachableInV1": true
},
"unmetDependencies": [
{
"id": "tier1-persistent-mubot-505",
"status": "closed-unmerged",
"blocks": ["talk-facet"],
"decision": "talk-optional-on-owner-home-until-revived"
},
{
"id": "tier2-user-chat",
"status": "dyad-gate-blocked",
"blocks": ["talk-facet-every-member"]
},
{
"id": "brainport-default-adapter",
"status": "type-only-sealed",
"blocks": ["rank-via-BrainPort"],
"interim": "rankTasks"
},
{
"id": "project-scoped-kpi-source",
"status": "not-built",
"blocks": ["measured-progress"],
"v1": "unmeasured_until_project_kpi"
},
{
"id": "model-port-v2-tool-calling",
"status": "not-built",
"blocks": ["tier2-tool-loops"]
},
{
"id": "pot-monthly-model-ledger",
"status": "display-only",
"blocks": ["honest-talk-budget-story"]
},
{
"id": "per-project-docs-ui",
"status": "design-only",
"blocks": ["know-facet-full-editor"]
},
{
"id": "port-4-instinct-memory",
"status": "dormant-branch",
"blocks": ["learn-adapt-instinct"]
},
{
"id": "learning-ranker",
"status": "under-dyad-gate",
"blocks": ["learn-adapt-instinct"]
},
{
"id": "structured-project-outcome",
"status": "not-on-projects-table",
"blocks": ["outcome-strip"]
}
],
"nonGoals": [
"route-in-this-design-commit",
"migration-applied-in-this-design-commit",
"ui-in-this-design-commit",
"merge-port4-or-ranker-from-this-worktree",
"pretend-modelport-v2-exists",
"cite-dormant-surfaces-as-reuse",
"cite-BrainPort-as-reuse"
],
"buildSlices": [
"outcome-model",
"owner-home-shell",
"trust-strip-gate-queue",
"earned-autonomy",
"visible-learning",
"talk-facet-tier2-after-pass",
"know-facet-docs-507",
"learn-adapt-instinct-after-port4"
],
"suggestedBuildOrder": [
"trust-strip-gate-queue",
"visible-learning",
"outcome-model",
"earned-autonomy",
"owner-home-shell",
"know-facet-docs-507",
"talk-facet-tier2-after-pass",
"learn-adapt-instinct-after-port4"
]
}
Loading
Loading