State model¶
Physical Notion realization of Initiative, workstream, Product, Asset, and Decision/Event state for M1 (D-01 / G3). Ownership, operations, and conflict rules remain in the authority model. Component boundaries remain in system components.
Schema revision: state-model.v2 (proposed; Gate A pending)
Committed revision: c519ee3b5e19792222d1401f66df61ffbaca5dd5 (c519ee3 on origin/main; prior bind e0cf737 / 356c1e9)
Paired Asset contract: asset-registry.v2
Tracking: hector-sanchez-eu/conductor#3
Brief: M1 brief
Gate A approval must name this exact revision (state-model.v2). This document does not authorize database creation. Gate A approves the schema design. Gate D approves mutation/import.
Locked M0 constraints¶
- Conductor does not write routine Notion state. Executing agents persist IDs and writeback.
- Notion is authoritative for Initiative, workstream, Product, Asset, and Decision/Event state.
- The Conductor identity allocator mints IDs; executing agents persist them.
- Assets are enduring systems; Initiatives are work that creates or changes outcomes.
- Decision/Event ownership follows the authority model (line
active_rolevs Portfolio Manager).
Target workspace (Gate A input)¶
| Field | Proposed value | Status |
|---|---|---|
| Notion workspace | sdhector workspace (867ec393-2263-8154-bd17-000319357256) |
Confirmed via Notion MCP fetch self (2026-07-24) |
| Parent page | Conductor State — page ID 3a7ec393-2263-818b-bce3-daa9a46b9220 — open |
Created 2026-07-24 (workspace-level parent; nine DBs still Gate D only) |
| Schema revision property | Every database page carries schema_version = state-model.v2. Assets also carry asset_registry_version = asset-registry.v2. |
Proposed |
Until Gate D approval, do not create the nine databases under this parent. Schema design review may proceed; Gate A approval still requires a committed schema revision in git.
Multi-agent access (default: Notion CLI)¶
Default for every agent: official Notion CLI ntn + Bitwarden-backed token. See notion-access.md.
| Path | When |
|---|---|
ntn + NOTION_API_TOKEN / ntn login |
Preferred — Cursor, VPS, OpenClaw, CI |
| Notion REST API (same token) | Conductor read adapters after Gate C |
| Cursor Notion MCP | Optional interactive only — not the shared default |
Do not treat Cursor plugin OAuth as the shared secret store.
Database layout¶
Nine databases (Gate A / state-model.v2):
| Database | Title | Purpose |
|---|---|---|
initiatives |
Conductor Initiatives | Organizational work contracts |
workstreams |
Conductor Workstreams | One line contribution per Initiative |
products |
Conductor Products | Product evaluation state |
assets |
Conductor Assets | Enduring systems (see asset-registry.md) |
decisions_events |
Conductor Decisions/Events | Append-oriented history (may link Assets) |
asset_repositories |
Conductor Asset Repositories | Typed repo links for Assets |
asset_environments |
Conductor Asset Environments | Typed deploy/URL rows for Assets |
asset_evidence |
Conductor Asset Evidence | One-row-per-reference provenance, verification, and promotion evidence |
asset_relationships |
Conductor Asset Relationships | One-row-per-edge typed relationships with per-edge review |
Workstreams and Decisions/Events are not nested child pages of Initiative. Repositories, environments, provenance, and relationships are not free-text or parallel ordered fields on the Asset row.
Relations¶
text
Initiative 1──* Workstream
Initiative *──* Product
Initiative 1──* Decision/Event
Workstream *──* Decision/Event
Asset *──* Initiative
Asset 1──* AssetRepository
Asset 1──* AssetEnvironment
Asset 1──* AssetEvidence (provenance / verification / promotion refs)
Asset *──* AssetRelationship (as source or target; edge SoR)
Decision/Event *──* Asset (related_assets — verification/promotion/events)
AssetEvidence *──* Decision/Event (optional linked_event)
AssetRelationship *──* AssetEvidence
AssetRelationship *──* Decision/Event
Relationship kinds are not stored as Asset-wide checkboxes or unordered multi-relations without edge metadata. The asset_relationships database is authoritative for typed edges.
Identifier mint and persist¶
| Identifier | Format (convention) | Minted by | Persisted by | Store |
|---|---|---|---|---|
initiative_id |
init.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Initiatives DB |
workstream_id |
ws.<ulid> |
Identity allocator | Executing agent for current active_role |
Workstreams DB |
product_id |
prod.<ulid> |
Identity allocator | Executing agent for Product Manager | Products DB |
asset_id |
asset.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Assets DB |
event_id |
evt.<ulid> |
Identity allocator | Executing agent for owning role | Decisions/Events DB |
repo_id |
arep.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Asset Repositories DB |
env_id |
aenv.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Asset Environments DB |
evidence_id |
aev.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Asset Evidence DB |
relationship_id |
arel.<ulid> |
Identity allocator | Executing agent for Portfolio Manager | Asset Relationships DB |
Rules:
- Minting alone is not project-state writeback.
- Persist must be idempotent on the stable ID (create-if-absent or update-by-ID).
- Notion page ID is an adapter locator, not the Conductor stable ID.
- Authorization IDs remain control-plane artifacts; they are not Decision/Event IDs.
- Child Asset rows (
arep/aenv): uniqueness is(asset_id, url)for repositories and(asset_id, url, environment)for environments — re-persist updates the existing row by stable ID; never create a second row for the same uniqueness key.
Initiatives database¶
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | Human title |
initiative_id |
rich_text | yes | Stable ID |
schema_version |
select | yes | state-model.v2 |
outcome |
rich_text | yes | |
definition_of_done |
rich_text | yes | |
owner |
rich_text | yes | Role ID, e.g. role.portfolio-manager |
priority |
select | yes | p0 p1 p2 p3 |
portfolio_status |
select | yes | intake active parked done killed |
review_date |
date | when active/parked | |
archetype |
select | after classify | software-product content-product services-product |
related_initiatives |
relation → Initiatives | optional | Parent/child/enabling/derived; use relationship_kind on events for nuance |
products |
relation → Products | optional | |
assets |
relation → Assets | optional | |
privacy_class |
select | yes | See organization profile; default internal |
context_version |
rich_text | yes | Opaque version string bumped on material state change |
last_writeback_at |
date | optional | Last successful completion writeback |
notes_summary |
rich_text | optional | Short Portfolio summary only |
Removed vs superseded sketch (integrations/notion_schema.yml in the repo root):
- Do not use
active_lineorattending_lines. Concurrent participation is represented by Workstream rows. - Do not treat
github_issue_urlas required. Optional evidence may appear on workstreams. - Do not embed
software_stageon the Initiative; Software stage lives on the Software workstream.
Authoritative writer¶
Executing agent acting for Portfolio Manager (see authority model). Conductor: read / validate only.
Workstreams database¶
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | Display label, e.g. Software — Implement |
workstream_id |
rich_text | yes | |
schema_version |
select | yes | state-model.v2 |
initiative |
relation → Initiatives | yes | Exactly one |
line |
select | yes | portfolio product software editorial services operate |
stage |
rich_text | yes | Exact stage ID from org-map-model.md |
active_role |
rich_text | while active | One role ID |
status |
select | yes | planned active blocked waiting done cancelled |
next_action |
rich_text | while active/blocked | |
bindings |
rich_text | stage-dependent | JSON or structured text of inventory bindings |
evidence_links |
rich_text | stage-dependent | URLs and short labels |
privacy_class |
select | yes | |
context_version |
rich_text | yes | |
completion_records |
rich_text | optional | Latest completion JSON (see below) or pointer |
Portfolio workstream is persistent for every Initiative. Delivery-line workstreams are optional and concurrent.
Authoritative writer¶
Executing agent for the current active_role. Cross-workstream conflicts escalate to Portfolio Manager.
Products database¶
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | |
product_id |
rich_text | yes | |
schema_version |
select | yes | state-model.v2 |
initiatives |
relation → Initiatives | yes | One or more |
profile |
select | yes | venture bootstrap |
stage |
select | yes | Discover Explore Score Build-gate Ship-signal Archive (store exact IDs) |
status |
rich_text | yes | Free-form micro-status |
score_snapshot |
rich_text | at Score+ | |
evidence_links |
rich_text | optional | |
privacy_class |
select | yes | |
context_version |
rich_text | yes |
estate_urls from the old sketch move to the Assets database. Products do not store estate SoR.
Authoritative writer¶
Executing agent under Product Manager.
Assets database¶
Field-level Asset contract is defined in asset-registry.md. Physical properties for Gate A (state-model.v2 / asset-registry.v2):
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | Primary display name |
asset_id |
rich_text | yes | Stable ID |
schema_version |
select | yes | Always state-model.v2 (physical layout revision) |
asset_registry_version |
select | yes | Always asset-registry.v2 (Asset contract revision) |
review_status |
select | yes | candidate reviewed rejected superseded-record |
aliases |
multi_select | optional | Former names / slugs |
purpose |
rich_text | for reviewed | |
users_needs |
rich_text | for reviewed | |
capabilities |
rich_text | for reviewed | Comparable capability bullets |
lifecycle_status |
select | yes | proposed prototype active maintained superseded archived |
estate |
select | yes | prototype lab portfolio-org |
stack |
rich_text | when known | Descriptive; never sole equivalence evidence |
deploy_shape |
select | when known | static dynamic-socket dynamic-always-on saas unknown |
runtime_profile |
select | when known | Compatibility axis (e.g. browser node python systemd unknown) |
privacy_class |
select | yes | |
related_initiatives |
relation → Initiatives | optional | |
last_verified_at |
date | for reviewed | Must not be in the future |
extraction_notes |
rich_text | candidate only | Never authoritative |
portability_gap |
rich_text | when no portable canonical ref | Explicit gap |
Removed in v2 (lossy / non-edge-specific):
provenance_kinds+ orderedprovenance_refs— replaced byasset_evidencerows- Asset-wide
relationship_human_reviewedand Asset-siderel_*multi-relations as SoR — replaced byasset_relationshipsedges - Lone
verification_evidenceURL on Asset — moved intoasset_evidence(evidence_class=verification) plus optional Decision/Event viarelated_assets
Asset Repositories (asset_repositories)¶
| Property | Notion type | Required |
|---|---|---|
| Name | title | yes |
repo_id |
rich_text | yes |
schema_version |
select | yes |
asset |
relation → Assets | yes (exactly one) |
url |
url | yes |
role |
select | yes |
privacy_class |
select | yes |
Uniqueness / idempotency: one row per (asset_id, url). Upsert by repo_id or by uniqueness key.
Asset Environments (asset_environments)¶
| Property | Notion type | Required |
|---|---|---|
| Name | title | yes |
env_id |
rich_text | yes |
schema_version |
select | yes |
asset |
relation → Assets | yes |
url |
url | yes |
environment |
select | yes |
verified_at |
date | optional |
privacy_class |
select | yes |
Uniqueness / idempotency: one row per (asset_id, url, environment). Upsert by env_id or by uniqueness key.
Asset Evidence (asset_evidence) — lossless one-row-per-reference¶
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | Short label |
evidence_id |
rich_text | yes | Stable ID aev.<ulid> |
schema_version |
select | yes | state-model.v2 |
asset |
relation → Assets | yes | Exactly one Asset |
evidence_class |
select | yes | provenance verification promotion |
kind |
select | yes | github-repo notion-page deploy-url human decision-event other |
ref_url |
url | when URL-shaped | Preferred locator |
ref_text |
rich_text | when non-URL | Package id, note, etc. |
noted_by |
rich_text | yes | Role or human identity |
noted_at |
date | yes | Must not be in the future |
linked_event |
relation → Decisions/Events | optional | Ties verification/promotion to an event |
privacy_class |
select | yes |
Rules: each reference is one row. Repeated kinds are allowed (two github-repo rows). Do not encode lists by ordering across Asset properties.
Asset Relationships (asset_relationships) — edge SoR¶
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | e.g. alpha duplicate_of beta |
relationship_id |
rich_text | yes | arel.<ulid> |
schema_version |
select | yes | state-model.v2 |
source_asset |
relation → Assets | yes | Exactly one |
target_asset |
relation → Assets | yes | Exactly one |
kind |
select | yes | related depends_on fork_of duplicate_of replaces replaced_by extends |
review_status |
select | yes | candidate human-reviewed rejected |
reviewer |
rich_text | when human-reviewed | |
reviewed_at |
date | when human-reviewed | Must not be in the future |
asserted_need |
rich_text | when kind=extends and human-reviewed |
Exact need statement this edge supports for extend |
asserted_delta |
rich_text | when kind=extends and human-reviewed |
Exact delta justified for extend |
evidence_rows |
relation → Asset Evidence | optional | |
evidence_event |
relation → Decisions/Events | optional | Resolved to evt.* by the physical mapper |
evidence_url |
url | optional | |
notes |
rich_text | optional | |
privacy_class |
select | yes |
Human-required kinds (duplicate_of, replaces, replaced_by, fork_of, extends) must be review_status=human-reviewed with reviewer + reviewed_at before they may support reuse/extend evidence. For extends, asserted_need and asserted_delta are required on the physical edge and must match the evaluator request.
Config locator names:
CONDUCTOR_NOTION_ASSET_REPOS_DATABASE_IDCONDUCTOR_NOTION_ASSET_ENVS_DATABASE_IDCONDUCTOR_NOTION_ASSET_EVIDENCE_DATABASE_IDCONDUCTOR_NOTION_ASSET_RELATIONSHIPS_DATABASE_ID
Authoritative writer¶
Delegated humans or agents with Asset write permission under Portfolio Manager. Never the Conductor compiler.
Decisions/Events database¶
Append-oriented. Prefer create-new over mutate-in-place. Corrections supersede via supersedes relation, not silent rewrite of history meaning.
| Property | Notion type | Required | Notes |
|---|---|---|---|
| Name | title | yes | Short event label |
event_id |
rich_text | yes | |
schema_version |
select | yes | state-model.v2 |
initiative |
relation → Initiatives | yes | |
workstream |
relation → Workstreams | when line event / completion | |
related_assets |
relation → Assets | when Asset verification/promotion/estate event | Enables Asset-linked evidence |
event_class |
select | yes | line-workstream portfolio-disposition completion asset-verification asset-promotion estate-comparison exception other |
event_type |
rich_text | yes | e.g. stage-transition, decision, writeback, asset-verify, estate-comparison, kill |
actor_role |
rich_text | yes | |
agent_identity |
rich_text | for completion | Client/agent identity |
occurred_at |
date | yes | |
written_at |
date | for completion | Writeback timestamp |
authorization_id |
rich_text | when from authorized work | Control-plane ID reference only |
pack_version |
rich_text | when applicable | |
context_version |
rich_text | when applicable | |
summary |
rich_text | yes | |
actions |
rich_text | for completion | What was done |
decisions |
rich_text | for completion | Material decisions |
unresolved_items |
rich_text | for completion | Open gaps |
next_action |
rich_text | for completion | Concrete next action |
result |
select | for completion | success partial-failure failed |
idempotency_key |
rich_text | for completion | authorization_id + writeback class |
evidence_links |
rich_text | optional | One URL per line |
privacy_class |
select | yes | |
supersedes |
relation → Decisions/Events | optional | |
asserted_need |
rich_text | when event_class is estate-comparison or portfolio-disposition estate comparison |
Exact need statement for EstateComparison |
claim_ids |
multi_select or rich_text (one ID per line) | when estate comparison carries claims | Must match IDs inside comparison_payload |
disposition_ids |
multi_select or rich_text (one ID per line) | when estate comparison carries dispositions | Must match IDs inside comparison_payload |
comparison_payload |
rich_text (JSON) | when estate comparison | Immutable semantic payload: claims (polarity/text/citations), dispositions (status/negative_claim/evidence), optional no_material_gaps + evidence, optional extend {base_asset_id,delta} |
Completion/writeback conceptual fields from G3 map 1:1 onto these properties (plus initiative / workstream relations for stable ID resolution). Do not collapse writeback into summary alone.
Asset verification and promotion: create a Decision/Event with event_class asset-verification or asset-promotion, set related_assets, and create matching asset_evidence rows with linked_event pointing at that event.
EstateComparison (Gate B authority boundary)¶
Decisive reuse / extend / new outcomes require an immutable EstateComparison persisted as a Decisions/Events row:
event_classmust beestate-comparisonorportfolio-disposition(neverother/asset-verificationfor comparison authority)event_typeis typicallyestate-comparisonasserted_need,actor_role,occurred_at,privacy_class, andrelated_assetsbind the requestcomparison_payloadJSON holds the full semantic payload (claim polarity/text/citations, disposition status/negative_claim/evidence, optional no-gap + extend). Caller dictionaries cannot override this payload.claim_ids/disposition_idsmust match the payload when present
The evaluator consumes only validated typed EstateComparison records plus an opaque adapter-produced ExhaustiveSnapshot. Without both, the only legal outcome is insufficient-context.
See asset-registry.md and service/conductor/integrations/read_adapters/estate_comparison.py.
Ownership split (physical)¶
event_class |
Decision owner | Writer |
|---|---|---|
line-workstream |
Current active_role |
Executing agent for that role |
portfolio-disposition |
Portfolio Manager | Executing agent for Portfolio Manager |
completion |
Current active_role |
Executing agent for that role |
asset-verification / asset-promotion |
Portfolio Manager | Delegated Asset writers under Portfolio Manager |
Plan-authorization audit content is not stored here (authorization audit store).
Completion / writeback record (G3)¶
The authorized plan names exact Notion and production updates. The executing agent writes an idempotent completion record as a Decisions/Events row with the completion properties above.
Required fields (physical mapping)¶
| Field | Physical property |
|---|---|
initiative_id |
Resolved via initiative relation → Initiative.initiative_id |
workstream_id |
Resolved via workstream relation → Workstream.workstream_id |
agent_identity |
agent_identity |
authorization_id |
authorization_id |
pack_version |
pack_version |
context_version |
context_version |
actions |
actions |
evidence_links |
evidence_links |
decisions |
decisions |
unresolved_items |
unresolved_items |
next_action |
next_action |
result |
result |
idempotency_key |
idempotency_key |
written_at |
written_at |
Storage¶
- Primary: create a Decisions/Events row with
event_class=completionandevent_type=writeback. - Mirror summary: update Workstream
next_action,status,evidence_links,context_version, and Initiativelast_writeback_at/context_versionas named by the plan. - Success is not claimed until Notion writeback succeeds or
result=partial-failureis explicit. - Conductor may
read/ verify on next consultation. Conductor must not silently repair missing writeback.
Required views¶
| View | Database | Purpose |
|---|---|---|
| Portfolio Active | Initiatives | portfolio_status in active/intake; sorted by priority, review_date |
| Portfolio Review Due | Initiatives | review_date ≤ today |
| Concurrent Workstreams | Workstreams | Filter by Initiative; show line/stage/status/role |
| Product Pipeline | Products | By profile and stage |
| Asset Estate | Assets | By estate, lifecycle, review_status |
| Asset Candidates | Assets | review_status=candidate |
| Asset Evidence by Asset | Asset Evidence | Filter by asset; class provenance/verification/promotion |
| Asset Relationship Edges | Asset Relationships | By kind and review_status |
| Event Timeline | Decisions/Events | By Initiative, newest first |
| Writeback Gaps | Decisions/Events + Workstreams | Active workstreams with stale/missing completion |
Bootstrap and migration¶
Existing sketch¶
integrations/notion_schema.yml and the write orchestrator under service/conductor/integrations/ are superseded sketches for Initiatives/Products only. They use retired active_line / attending_lines fields and mutate Notion from Conductor, which violates M0.
M1 path:
- Gate A: approve this schema revision (
state-model.v2) and fill Target workspace. - Gate C: approve read credentials and scopes.
- Gate D: approve create/import plan.
- Create the nine databases under the confirmed parent.
- Optionally import any existing Initiative/Product pages as candidates mapped to
state-model.v2(strip superseded fields; create Workstream rows for concurrent lines). - Do not extend the write orchestrator as Conductor's steady-state write path. Legacy mutation MCP tools and schema bootstrap remain disabled by default (
CONDUCTOR_LEGACY_WRITES_ENABLED); unavailable in production. Executing agents own writeback; Conductor adapters are read-only (see read-access-contract.md).
Rollback¶
| Failure | Recovery |
|---|---|
| Partial DB create | Delete newly created empty DBs; leave prior sketch untouched |
| Bad import batch | Tag imported pages schema_version=rollback-pending; restore from Notion history or re-import from dry-run export |
| Wrong parent | Move databases only after Hector confirms; record new locators in org profile config names |
Rollback rehearsal is required evidence before Gate D import completes.
Conflict with indexes¶
Derived estate indexes and caches cannot override Notion. If index and Notion disagree, Notion wins; the index is rebuilt.
Gate A approval checklist¶
Hector approves Gate A when commenting Conductor-Gate-A: approve on issue #3, naming revision state-model.v2, and confirming:
- Nine-database layout (including
asset_evidenceandasset_relationships). - Workspace and parent page filled in the Target workspace table (owner action — blocked until provided).
- Identifier formats and mint/persist flow.
- Completion/writeback physical properties on Decisions/Events, including
related_assets. - Lossless evidence and per-edge relationship models (no parallel ordered provenance fields; no Asset-wide relationship review checkbox).
- Migration stance vs existing Initiatives/Products sketch.
- Legacy mutation surface remains disabled by default.
- Physical
schema_version=state-model.v2on all nine databases; Assets also setasset_registry_version=asset-registry.v2. - Approval names a committed schema revision (git SHA / PR), not only an in-doc label.