Privacy model¶
Privacy classes, filtering rules, redaction behavior, and role-permission mapping. Conductor must omit or redact context the active role is not permitted to access.
Privacy classes¶
| Class | Label | Meaning | Examples |
|---|---|---|---|
public |
Public | Safe for any surface, including generated packs, examples, and public repos | Product descriptions, published URLs, open-source code |
internal |
Internal | Safe within Conductor and permitted roles; not for public packs | Initiative outcomes, workstream status, asset descriptions, internal patterns |
restricted |
Restricted | Role-gated; only roles with explicit permission may see | Client identities, engagement terms, personal PII, scorecard evidence |
client-confidential |
Client-confidential | Only the engagement role and Client may see; never in packs or shared state | Contracts, invoices, client deliverables, personal contact data |
Filtering rules¶
Per-class behavior¶
| Class | Included in packs? | Included in state snapshots? | Included in estate index? | Included in generated docs? |
|---|---|---|---|---|
public |
Yes | Yes | Yes | Yes |
internal |
Yes (pack only) | Yes | Yes | No (generated corpus excluded) |
restricted |
No (redacted) | Role-filtered | No | No |
client-confidential |
Never | Never | Never | Never |
Per-role filtering¶
The compiler evaluates the active role against the privacy class of each data element before including it in context:
for element in candidate_context:
if element.privacy_class == 'public':
include(element)
elif element.privacy_class == 'internal':
include(element) # All Conductor roles may see internal
elif element.privacy_class == 'restricted':
if active_role.permissions.includes(element.privacy_class):
include(element)
else:
redact(element, marker='[restricted]')
elif element.privacy_class == 'client-confidential':
if active_role == element.owner_role:
include(element) # Only the owning role
else:
omit(element) # No marker — don't reveal existence
Redaction behavior¶
Two redaction modes:
| Mode | Behavior | When |
|---|---|---|
| Omit | The element is completely removed from context; its existence is not revealed | client-confidential for non-owning roles |
| Marker | The element is replaced with a class label (e.g. [restricted: engagement-terms]); existence is acknowledged but content is invisible |
restricted for roles without permission |
Role-to-privacy mapping¶
| Role group | May see public |
May see internal |
May see restricted |
May see client-confidential |
|---|---|---|---|---|
| President | Yes | Yes | Yes | Yes (all) |
| Portfolio roles | Yes | Yes | No | No |
| Product roles | Yes | Yes | Product evidence only | No |
| Software roles | Yes | Yes | Repository access only | No |
| Editorial roles | Yes | Yes | Publication data only | No |
| Services roles | Yes | Yes | Engagement data | Own engagements only |
| Operate roles | Yes | Yes | Runtime data only | No |
Services client boundary¶
Services engagements operate under a strict privacy boundary:
- Contracts, invoices, and personal contact data remain in private client folders
- GitHub issues for Services work must be sanitized — no PII, no contract terms
- Notion stores only privacy-safe links and summaries of Services work
- The
status.mdfile in client folders is detailed private state — never synchronized to public or shared surfaces - Conductor may read privacy-safe metadata (stage, status, SKU) but never client deliverables or contract content unless the active role is the Engagement Manager for that engagement
Rules from corpus/lines/services/units/privacy.yml:
- Contracts, invoices, personal contacts stay out of public GitHub
- Use sanitized issues when tracking deliverables
- status.md remains detailed private client state
Privacy in packs¶
Authorized packs must not contain:
- Client identities, contract terms, invoice amounts, or personal contact data
- Secret values (see
reference/security/secret-management.md) - Scorecard evidence for unrelated Initiatives
- Any
client-confidentialdata regardless of role
Packs may contain:
- Initiative outcomes and workstream status (
internal) - Stage contracts, standards, and policy units (
internal) - Asset descriptions and capability summaries (
internal) - Privacy-safe engagement metadata (stage, SKU, handoff status)
Privacy class assignment¶
Privacy classes are assigned at data creation time:
| Data type | Default class | Overridable by |
|---|---|---|
| Initiative fields (outcome, DoD, status) | internal |
Portfolio Manager |
| Workstream fields (stage, role, bindings) | internal |
Active role |
| Asset descriptions | internal |
Portfolio Manager |
| Product evidence (scores, research) | internal |
Product Manager |
| Software delivery evidence (commits, PRs) | internal |
Engineering Lead |
| Editorial drafts and source files | internal |
Editor-in-Chief |
| Published editorial content | public |
Publisher (at publish time) |
| Services client contracts | client-confidential |
Engagement Manager |
| Services invoices | client-confidential |
Engagement Manager |
| Operate runtime state | internal |
Platform Engineer |
Enforcement¶
Privacy filtering is applied at two points:
- Read path — Notion and GitHub read adapters filter results before returning to Conductor
- Pack compilation — The compiler applies privacy filtering before emitting the pack
A missing privacy class defaults to internal. Explicit classification is required for any data that should be restricted or client-confidential.
Related documents¶
- Secret management:
reference/security/secret-management.md - Integration contract (privacy section):
reference/authority/integration-contract.md - Read access contract:
evidence/read-access-contract.md - Source inventory (privacy classes):
evidence/source-inventory.md - Services privacy unit:
corpus/lines/services/units/privacy.yml - Organization profile:
about/organization-profile.md