add constitution

This commit is contained in:
2026-08-20 16:48:44 -04:00
parent cfdcfcd873
commit db6ad1f3e8
+160 -35
View File
@@ -1,50 +1,175 @@
# [PROJECT_NAME] Constitution
<!-- Example: Spec Constitution, TaskFlow Constitution, etc. -->
<!--
Sync Impact Report
==================
Version change: (unversioned template) → 1.0.0
Bump rationale: Initial ratification. All placeholder tokens replaced with concrete,
project-specific governance derived from README.md and the approved
Phase 0 baseline (Persona-Engine-Developer-Handoff.txt).
Modified principles:
[PRINCIPLE_1_NAME] → I. Deterministic, Single-Persona Classification (NON-NEGOTIABLE)
[PRINCIPLE_2_NAME] → II. Configuration-Driven Rules
[PRINCIPLE_3_NAME] → III. Fail-Safe, Idempotent Persistence (NON-NEGOTIABLE)
[PRINCIPLE_4_NAME] → IV. Pure Rule Engine, Tested Offline First
[PRINCIPLE_5_NAME] → V. Explainable, Sanitized Observability
Added sections:
[SECTION_2_NAME] → Security and Least-Privilege Constraints
[SECTION_3_NAME] → Development Workflow and Quality Gates
Governance rules populated (amendment procedure, versioning policy, compliance review)
Removed sections: none
Follow-up TODOs: none — no placeholders deferred.
-->
# Persona Engine Constitution
## Core Principles
### [PRINCIPLE_1_NAME]
<!-- Example: I. Library-First -->
[PRINCIPLE_1_DESCRIPTION]
<!-- Example: Every feature starts as a standalone library; Libraries must be self-contained, independently testable, documented; Clear purpose required - no organizational-only libraries -->
### I. Deterministic, Single-Persona Classification (NON-NEGOTIABLE)
### [PRINCIPLE_2_NAME]
<!-- Example: II. CLI Interface -->
[PRINCIPLE_2_DESCRIPTION]
<!-- Example: Every library exposes functionality via CLI; Text in/out protocol: stdin/args → stdout, errors → stderr; Support JSON + human-readable formats -->
Identical input records and identical configuration MUST always produce an identical persona
decision. Every evaluated account MUST receive exactly one persona — never zero, never
several. Rules MUST be evaluated in ascending numeric priority order and evaluation MUST stop
at the first match. When all enabled rules evaluate successfully and none match, the result
MUST be `Unclassified`; when evaluation cannot complete reliably, the result MUST be
`EvaluationError`. Non-deterministic inputs — wall-clock time, random values, unordered
collection enumeration, or environment state — MUST NOT influence a decision.
### [PRINCIPLE_3_NAME]
<!-- Example: III. Test-First (NON-NEGOTIABLE) -->
[PRINCIPLE_3_DESCRIPTION]
<!-- Example: TDD mandatory: Tests written → User approved → Tests fail → Then implement; Red-Green-Refactor cycle strictly enforced -->
**Rationale**: Persona values drive access and Conditional Access decisions. A classification
that varies between runs is unreviewable and cannot be safely enforced.
### [PRINCIPLE_4_NAME]
<!-- Example: IV. Integration Testing -->
[PRINCIPLE_4_DESCRIPTION]
<!-- Example: Focus areas requiring integration tests: New library contract tests, Contract changes, Inter-service communication, Shared schemas -->
### II. Configuration-Driven Rules
### [PRINCIPLE_5_NAME]
<!-- Example: V. Observability, VI. Versioning & Breaking Changes, VII. Simplicity -->
[PRINCIPLE_5_DESCRIPTION]
<!-- Example: Text I/O ensures debuggability; Structured logging required; Or: MAJOR.MINOR.BUILD format; Or: Start simple, YAGNI principles -->
Business classification logic MUST live in JSON configuration, never in PowerShell source. The
engine implements condition operators and composition (`all` / `any` nesting within the
configured depth limit); it MUST NOT hard-code personas, priorities, group identifiers, role
identifiers, or tenant-specific attribute names. The candidate persona catalogue is business
data, not engine behaviour. JSON is the only supported configuration format for v1.
Configuration MUST be validated in four layers — JSON syntax, JSON Schema, semantic, then
safety — before it is used to evaluate any account.
## [SECTION_2_NAME]
<!-- Example: Additional Constraints, Security Requirements, Performance Standards, etc. -->
**Rationale**: Rule changes are business changes. Requiring a code change to reclassify accounts
couples routine policy updates to the release pipeline and invites unreviewed edits.
[SECTION_2_CONTENT]
<!-- Example: Technology stack requirements, compliance standards, deployment policies, etc. -->
### III. Fail-Safe, Idempotent Persistence (NON-NEGOTIABLE)
## [SECTION_3_NAME]
<!-- Example: Development Workflow, Review Process, Quality Gates, etc. -->
Re-running the engine MUST change nothing unless a calculated value actually differs from the
stored value. A missing or failed required data source MUST NOT be interpreted as a non-match:
the account MUST be recorded as `EvaluationError`, its existing persona MUST be preserved, no
write MUST be attempted for it, and the run MUST continue. Write-capable entry points MUST use
`CmdletBinding` with `SupportsShouldProcess`, and `-WhatIf` MUST produce zero directory writes.
`-Debug` and `-Verbose` MUST NOT be treated as read-only controls. A write payload MUST contain
only the single approved target attribute.
[SECTION_3_CONTENT]
<!-- Example: Code review requirements, testing gates, deployment approval process, etc. -->
**Rationale**: The engine writes to a live directory. Silent misclassification of a privileged
account is a security incident, so unavailable data must degrade to no change.
### IV. Pure Rule Engine, Tested Offline First
The rule engine MUST NOT depend on Microsoft Graph, authentication, Azure Automation, or console
rendering. Graph acquisition MUST be normalized into plain identity records before evaluation,
and persistence MUST sit behind an adapter the engine does not call directly. The rule engine
MUST be implemented and passing Pester tests against synthetic data before any Graph integration
is written, and the persistence adapter MUST be implemented last. Offline unit tests MUST run to
completion with no tenant connectivity and no credentials.
**Rationale**: Correctness of classification is provable only in isolation. A rule engine
reachable only through a live tenant cannot be exhaustively tested before it is trusted.
### V. Explainable, Sanitized Observability
Every persona result MUST identify the matched rule ID (or `Unclassified` / `EvaluationError`),
the run correlation ID, the UPN, and the Account Object ID. Each user result MUST be emitted
immediately as it is produced, with interim and final summaries, and reconciliation MUST confirm
that reported counts match accounts processed. Structured, audit-friendly logging is required
alongside console output. UPN and Account Object ID are approved for logs. Access tokens,
authorization headers, secrets, and full Graph responses MUST NEVER be logged. Detailed
condition-level values are diagnostic-only and MUST be gated behind `-Debug`.
**Rationale**: An unexplainable decision cannot be reviewed, appealed, or audited, and the
`-WhatIf` impact evidence required before enforcement depends on complete per-user output.
## Security and Least-Privilege Constraints
- **Authentication**: Azure Automation MUST use a managed identity. Local development MUST use an
approved interactive or read-only application identity. Client secrets MUST NEVER be committed
to source control.
- **Least privilege**: The execution identity MUST be granted only what the enabled rules require
— in-scope user properties, configured group membership, configured role data, and the existing
persona value.
- **Attribute-scoped writes**: Whether Entra can enforce write authorization at the individual
attribute level MUST be verified, never assumed (OTD-003). Until verified, the compensating
controls are mandatory: the persistence module accepts only the approved target attribute; that
attribute MUST appear in `approvedWritableAttributes`; validation rejects all others; a
dedicated function builds a request body containing only that attribute; tests inspect the
request body; and code owners gate persistence changes.
- **Sanitization**: Every artifact in this repository — docs, examples, tests, configuration
samples, specs — MUST be free of organization names, real domains, tenant or subscription IDs,
automation account names, real UPNs or Object IDs, real group or role identifiers,
environment-specific attribute names, log destination details, and any secret, token,
certificate, or credential. Only approved placeholders such as `<ORGANIZATION-NAME>`,
`<TENANT-ID>`, `<ACCOUNT-OBJECT-ID>`, `<GROUP-OBJECT-ID>`, and
`<APPROVED-PERSONA-ATTRIBUTE-NAME>` may be used. Test data MUST be obviously fictional and MUST
NEVER reproduce real employee records. Tenant-specific configuration belongs in a protected
repository or configuration store, not here.
- **Scope**: v1 covers Entra user objects only. Service principals, managed identities, workload
identities, and agentic identities are out of scope, and the architecture MUST NOT assume they
share user-object properties.
- **Kill switch and rollback**: A documented kill switch (disable the Automation schedule, run
with `-WhatIf`, revoke production write permission, or disable write deployment stages) and a
documented rollback procedure MUST exist before enforcement is enabled.
- **Runtime**: PowerShell 7 is the target runtime for both local execution and Azure Automation.
## Development Workflow and Quality Gates
- **Spec-driven delivery**: Nothing is implemented before it is specified, planned, and decomposed
into tasks (Specify → Plan → Tasks → Implement). Any unresolved question MUST be captured as an
explicit assumption, risk, or architecture decision — it MUST NEVER be silently implemented.
- **Open technical decisions**: OTD-001 through OTD-005 MUST be closed in `research.md` or an ADR
before any persistence implementation begins.
- **Build order**: Pure rule engine with offline Pester tests → configuration validation and
non-interactive pipeline mode → Graph read adapters → console and structured logging →
persistence adapter last, with tests proving zero writes under `-WhatIf`.
- **Traceability**: Requirements carry FR/NFR identifiers and MUST be traceable from spec through
tasks to tests.
- **Validation pipeline** (MUST pass before merge): repository hygiene and sanitization checks,
PowerShell static analysis, JSON Schema validation, semantic and safety configuration
validation, Pester unit tests, Pester safety tests, test result publication, and artifact
packaging.
- **Release pipeline**: validate the approved branch or tag, repeat validation and tests, package,
deploy to Azure Automation, import modules, publish the runbook with the schedule **disabled**,
execute `-WhatIf` validation, pass an approval gate, then enable enforcement.
- **Mandatory review**: Changes to the target attribute, `approvedWritableAttributes`, rule
priority, rule enablement, rule conditions, persona outputs, authentication permissions,
persistence functions, logging destination, or `WhatIf` / `ShouldProcess` behaviour MUST be
reviewed by a code owner. Delivery uses feature branches, pull requests, and a protected release
branch.
- **Definition of done**: A version is complete only when its `-WhatIf` impact evidence has been
reviewed and security review has confirmed permissions and compensating controls.
## Governance
<!-- Example: Constitution supersedes all other practices; Amendments require documentation, approval, migration plan -->
[GOVERNANCE_RULES]
<!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
This constitution supersedes all other development practices for this repository. Where a plan,
task list, or review comment conflicts with it, this document wins.
**Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
<!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
**Amendment procedure**: Amendments MUST be proposed as a change to this file in a pull request,
MUST state the rationale and the version bump type, and MUST be approved by a code owner. An
amendment that invalidates existing artifacts MUST include a migration note naming the specs,
plans, tasks, or code that require updating.
**Versioning policy**: This constitution uses semantic versioning.
- **MAJOR** — a principle or governance rule is removed or redefined in a backward-incompatible way.
- **MINOR** — a new principle or section is added, or existing guidance is materially expanded.
- **PATCH** — clarifications, wording, and typo fixes with no change in obligation.
**Compliance review**: Every pull request MUST verify compliance with these principles, and
reviewers MUST reject changes that violate a NON-NEGOTIABLE principle regardless of urgency.
Complexity that departs from these principles MUST be justified in writing in the plan's
complexity tracking, or the simpler compliant approach MUST be taken instead. `README.md` and the
feature's `spec.md`, `plan.md`, and `tasks.md` provide runtime development guidance and MUST be
kept consistent with this constitution.
**Version**: 1.0.0 | **Ratified**: 2026-08-20 | **Last Amended**: 2026-08-20