Skip to content

Read-access contract

Read-only adapter contract for Notion, GitHub, and approved supplemental sources (D-04 / G14). Authority and non-mutation rules come from the authority model and organization profile. Source scopes live in source-inventory.md.

Contract version: read-access.v1 (Gate C approved) Tracking: hector-sanchez-eu/conductor#3
Brief: M1 brief

Do not unlock Bitwarden or call external APIs for M1 estate work until Gate C is approved.

Default Notion client for agents: official CLI ntn — see notion-access.md. Cursor Notion MCP is optional only.

Principles

  1. Adapters perform MCP read (and optional local validate of payload shape). They never perform plan authorize.
  2. Adapters must not mutate Notion, GitHub, or other authoritative state.
  3. Secret values resolve only from Bitwarden. Docs and config carry names and bindings only.
  4. Every response includes provenance, freshness, and completeness (complete | partial | unavailable | denied | stale | malformed).
  5. Permission filtering and privacy redaction apply before results leave the adapter boundary.
  6. Derived indexes are optional caches; they cannot override Notion/GitHub.

Secret names and provider bindings

Secret / config name Purpose Required for
CONDUCTOR_NOTION_READ_TOKEN Dedicated Notion read token Live Notion estate reads
CONDUCTOR_GITHUB_READ_TOKEN Dedicated GitHub read token Optional unattended/service enumeration mode (M3 production hardening)
CONDUCTOR_GITHUB_READ_ORGS Comma-separated approved GitHub organizations Live GitHub enumeration scope
CONDUCTOR_GITHUB_READ_USERS Comma-separated approved GitHub users Live GitHub enumeration scope
CONDUCTOR_GITHUB_READ_ALLOW_PRIVATE Explicit Gate C private-metadata policy switch Private repositories in approved scopes
CONDUCTOR_NOTION_INITIATIVES_DATABASE_ID Initiatives DB locator Initiative queries
CONDUCTOR_NOTION_WORKSTREAMS_DATABASE_ID Workstreams DB locator Workstream queries
CONDUCTOR_NOTION_PRODUCTS_DATABASE_ID Products DB locator Product queries
CONDUCTOR_NOTION_ASSETS_DATABASE_ID Assets DB locator Asset queries
CONDUCTOR_NOTION_DECISIONS_DATABASE_ID Decisions/Events DB locator History queries
CONDUCTOR_NOTION_ASSET_REPOS_DATABASE_ID Asset Repositories DB locator Repo link queries
CONDUCTOR_NOTION_ASSET_ENVS_DATABASE_ID Asset Environments DB locator Deploy URL queries
CONDUCTOR_NOTION_ASSET_EVIDENCE_DATABASE_ID Asset Evidence DB locator Provenance/verification/promotion refs
CONDUCTOR_NOTION_ASSET_RELATIONSHIPS_DATABASE_ID Asset Relationships DB locator Per-edge relationship SoR
CONDUCTOR_GATE_C_APPROVED Explicit Gate C enable flag Live reads
CONDUCTOR_READ_ALLOW_LIVE Operator live-read switch Live reads
CONDUCTOR_GITHUB_TOKEN Governance/proposal write path Proposals only — not estate reads
CONDUCTOR_NOTION_TOKEN Legacy write token Legacy writes only (disabled by default)
CONDUCTOR_LEGACY_WRITES_ENABLED Legacy mutation feature gate Defaults false; unavailable in production
CONDUCTOR_GITHUB_WEBHOOK_SECRET Webhook HMAC Required; webhook fail-closed if absent

Provider: Bitwarden Secrets Manager (organization binding). Missing secret → explicit failure; no host .env fallback as authoritative store.

Credential separation: estate read adapters must not fall back to CONDUCTOR_GITHUB_TOKEN, GH_TOKEN, GH_CLI_TOKEN, or CONDUCTOR_NOTION_TOKEN.

Database ID env vars are configuration locators (names/bindings), not secret values, but still organization-profile/adapter config—not packs.

Notion live reads require Gate C approval, CONDUCTOR_READ_ALLOW_LIVE, and the dedicated Notion read token. GitHub supports two explicit modes:

  1. Operator mode (current): authenticated gh CLI, constrained to approved owners and read-only commands.
  2. Unattended service mode (deferred to M3): a dedicated read credential supplied as CONDUCTOR_GITHUB_READ_TOKEN.

The selected mode must be reported in provenance. There is no implicit fallback between modes.

Gate C approval covers the bounded discovery envelope in source-inventory.md. It does not require application names before enumeration. Source completeness is established by approved locators, exclusions, pagination exhaustion, privacy filtering, and explicit degraded-source states. Discovered application identities remain candidates until human review.

Approved operator discovery with gh

Hector approved use of the authenticated GitHub CLI for current operator-driven discovery on 2026-07-26:

  • only read-only gh repo list and gh api GET operations may be used;
  • operations remain limited to the approved owners and metadata/content paths;
  • the service adapter must not silently consume GH_TOKEN, GH_CLI_TOKEN, or governance credentials;
  • evidence must disclose auth_mode=gh-operator and that the operator credential may be broader than a future service credential.

Operator discovery satisfies M1 source-enumeration evidence. Whether Conductor needs unattended GitHub access, and its least-privilege credential, is an M3 runtime/deployment decision.

Permission requirements

Notion

Capability Required Forbidden
Query approved databases Yes Create/update/delete pages
Retrieve page properties Yes Modify properties
List children for approved parents Optional Archive/move databases

Token must be least-privilege read against approved DB IDs only. Broader workspace admin is out of Gate C scope unless Hector explicitly expands.

GitHub

Capability Required Forbidden
List repos in approved orgs/users Yes Create repos, issues, PRs, releases
Read repository metadata Yes Push, merge, admin
Read README / selected metadata files Optional, privacy-filtered Write contents

Proposal/write tokens used by governance tooling are a separate binding and must not be reused to imply write permission in the estate read path.

Snapshot and provenance envelope

Every adapter result wraps records as:

yaml source: notion | github | supplemental source_locator: <db id, repo, url> fetched_at: <iso8601> snapshot_version: <opaque> completeness: complete | partial | unavailable | denied | stale | malformed provenance: - kind: notion-page | github-repo | human | deploy-url ref: <id or url> records: [] errors: [] retry: {recommended: true, after: "<seconds>"} # optional rate_limit: {status: 429, retry_after: "<seconds>"} # optional

Pagination: adapters must surface exhaustion. If has_more is true without a cursor, set completeness=partial and explain. Never report complete for truncated pages.

Rate limits: on HTTP 429, return unavailable (or partial if some pages succeeded) with retry / rate_limit metadata—never fabricate missing rows.

Transport errors, malformed JSON, and malformed records map to unavailable / malformed / partial as documented in adapter tests.

Freshness and stale behavior

Condition Behavior
Successful fetch completeness=complete (or partial); record fetched_at
Cached index older than policy TTL while SoR unreachable completeness=stale; cite cache age; do not present as live
Source denied (403) completeness=denied; empty records
Source down / timeout completeness=unavailable
Payload fails schema validation completeness=malformed; quarantine record

Callers must not treat stale, denied, unavailable, partial, or malformed as a complete estate.

Privacy filtering and redaction

  1. Reads receive authenticated identity, active_role, and an organization privacy policy.
  2. Each record must carry privacy_class. Unclassified records fail closed unless the source has an explicitly approved default in the Gate C inventory.
  3. Adapter redacts records the active role may not see.
  4. Private GitHub repository metadata is withheld unless Gate C policy explicitly allows private-repo indexing for that role.
  5. Services client artifacts: metadata only unless Gate C expands scope.
  6. Secret values never appear in adapter output.

Application wiring

The preparation tool prepare_estate_context uses build_read_adapters (permission-filtered, fail-closed). Fixture mode is for developer tests only and is not baseline evidence.

Legacy mutation surface

Pre-M1 Notion/GitHub/Calendar mutation MCP tools and schema bootstrap are disabled unless CONDUCTOR_LEGACY_WRITES_ENABLED=true. That gate must not be enabled in production. The GitHub webhook fails closed when CONDUCTOR_GITHUB_WEBHOOK_SECRET is absent, and refuses writes when legacy mode is off.

Non-mutation assurance

Control Requirement
HTTP methods GET/HEAD (and Notion search/query equivalents) only in read adapters
Code review Read adapter modules must not import write orchestrator mutation helpers
Tests Contract tests assert no create/update/delete calls
Config Read token separate from any write-capable token when possible

The existing write orchestrator under service/conductor/integrations/ is out of M1 steady-state scope (known M0 drift). M1 read adapters are separate modules.

Supplemental sources

Approved supplemental reads (deployed hosts, workspace pointers) follow the same envelope. They never become Asset SoR; they only feed candidate provenance.

Gate C approval checklist (access portion)

Hector approves Gate C access rules when commenting Conductor-Gate-C: approve after accepting this contract and source-inventory.md scopes.