diff --git a/.auxiliary/configuration/AGENTS.md b/.auxiliary/configuration/AGENTS.md index ca991db..d37c2f3 100644 --- a/.auxiliary/configuration/AGENTS.md +++ b/.auxiliary/configuration/AGENTS.md @@ -1,7 +1,7 @@ # Context - Project overview and quick start: README.rst -- Product requirements and goals: documentation/prd.rst +- Product requirements and goals: documentation/architecture/openspec/specs - System architecture and design: @documentation/architecture/ - Development practices and style: @.auxiliary/instructions/ - Current session notes and TODOs: @.auxiliary/notes/ diff --git a/documentation/architecture/openspec/specs/classes/spec.md b/documentation/architecture/openspec/specs/classes/spec.md new file mode 100644 index 0000000..d4f3ec9 --- /dev/null +++ b/documentation/architecture/openspec/specs/classes/spec.md @@ -0,0 +1,43 @@ +# Accretive Classes + +## Purpose +To provide metaclasses that enforce accretive behavior on class instances, ensuring that instance attributes become immutable after their initial assignment. This supports creating robust objects where state accumulation is permitted but state mutation is forbidden. + +## Requirements + +### Requirement: Standard Metaclass +The system SHALL provide a metaclass for creating classes with accretive instances where instance attributes become immutable after first assignment. + +Priority: Critical + +#### Scenario: Defining an accretive class +- **WHEN** a class is defined with `metaclass=Class` (the accretive metaclass) +- **THEN** instances of that class exhibit accretive behavior + +#### Scenario: Assigning attributes +- **WHEN** an attribute is assigned for the first time on an instance +- **THEN** the assignment succeeds + +#### Scenario: Reassigning attributes +- **WHEN** an attribute is reassigned on an instance +- **THEN** an `AttributeImmutability` exception is raised + +### Requirement: Dataclass Metaclass +The system SHALL provide a metaclass for dataclasses with accretive instances, compatible with the `@dataclass` decorator. + +Priority: High + +#### Scenario: Defining an accretive dataclass +- **WHEN** a class is decorated with `@dataclass` and uses the accretive dataclass metaclass +- **THEN** the class behaves as a dataclass +- **AND** instances exhibit accretive behavior (fields are immutable after initialization) + +### Requirement: Mutable Dataclass Metaclass +The system SHALL provide a metaclass for dataclasses that supports selective mutability for specific attributes. + +Priority: Medium + +#### Scenario: Selective mutability +- **WHEN** a class is defined with specific attributes marked as mutable +- **THEN** those attributes can be reassigned +- **AND** other attributes remain immutable diff --git a/documentation/architecture/openspec/specs/dictionaries/spec.md b/documentation/architecture/openspec/specs/dictionaries/spec.md new file mode 100644 index 0000000..c9c7ed7 --- /dev/null +++ b/documentation/architecture/openspec/specs/dictionaries/spec.md @@ -0,0 +1,68 @@ +# Accretive Dictionaries + +## Purpose +To provide dictionary implementations that enforce grow-only semantics, where new entries can be added but existing entries cannot be modified or removed. This ensures data consistency for configuration registries, plugin systems, and other use cases requiring sticky state. + +## Requirements + +### Requirement: Basic Dictionary +The system SHALL provide a standard accretive dictionary implementation that allows adding new entries but prevents modifying or removing existing ones. + +Priority: Critical + +#### Scenario: Adding new entries +- **WHEN** a user adds a new key-value pair to the dictionary +- **THEN** the entry is successfully added +- **AND** the value can be retrieved using the key + +#### Scenario: Modifying existing entries +- **WHEN** a user attempts to update the value of an existing key +- **THEN** an `EntryImmutability` exception is raised +- **AND** the original value remains unchanged + +#### Scenario: Removing entries +- **WHEN** a user attempts to delete an existing key +- **THEN** an exception (likely `TypeError` or `EntryImmutability`) is raised +- **AND** the entry remains in the dictionary + +### Requirement: Producer Dictionary +The system SHALL provide a dictionary that auto-generates values for missing keys using a factory function, similar to `collections.defaultdict` but with accretive behavior. + +Priority: High + +#### Scenario: Accessing missing keys +- **WHEN** a user accesses a missing key +- **THEN** a new value is generated using the factory function +- **AND** the new value is stored in the dictionary associated with the key +- **AND** the value is returned to the user + +#### Scenario: Immutability of generated values +- **WHEN** a value has been generated for a key +- **THEN** subsequent attempts to modify that key raise `EntryImmutability` + +### Requirement: Validator Dictionary +The system SHALL provide a dictionary that validates entries before addition using a predicate function, ensuring only valid data can be added. + +Priority: Medium + +#### Scenario: Adding valid entries +- **WHEN** a user adds a key-value pair that passes the predicate function +- **THEN** the entry is successfully added + +#### Scenario: Adding invalid entries +- **WHEN** a user adds a key-value pair that fails the predicate function +- **THEN** an `EntryInvalidity` exception is raised +- **AND** the entry is not added to the dictionary + +### Requirement: Combined Producer-Validator +The system SHALL provide a dictionary combining auto-generation and validation behaviors. + +Priority: Medium + +#### Scenario: Generating valid values +- **WHEN** a missing key is accessed and the factory generates a value that passes validation +- **THEN** the value is stored and returned + +#### Scenario: Generating invalid values +- **WHEN** a missing key is accessed and the factory generates a value that fails validation +- **THEN** an `EntryInvalidity` exception is raised diff --git a/documentation/architecture/openspec/specs/exceptions/spec.md b/documentation/architecture/openspec/specs/exceptions/spec.md new file mode 100644 index 0000000..e656bb0 --- /dev/null +++ b/documentation/architecture/openspec/specs/exceptions/spec.md @@ -0,0 +1,23 @@ +# Accretive Exceptions + +## Purpose +To provide a clear and comprehensive exception hierarchy for handling violations of accretive constraints (immutability, validity). + +## Requirements + +### Requirement: Exception Hierarchy +The system SHALL provide a clear exception hierarchy for accretive violations, rooted in a common base class. + +Priority: Critical + +#### Scenario: Catching all errors +- **WHEN** a user catches `Omnierror` +- **THEN** all exceptions raised by the package are caught + +#### Scenario: Catching immutability errors +- **WHEN** a user catches `AttributeImmutability` or `EntryImmutability` +- **THEN** violations of attribute or dictionary entry immutability are caught + +#### Scenario: Catching validation errors +- **WHEN** a user catches `EntryInvalidity` +- **THEN** validation failures in Validator Dictionaries are caught diff --git a/documentation/architecture/openspec/specs/modules/spec.md b/documentation/architecture/openspec/specs/modules/spec.md new file mode 100644 index 0000000..d096396 --- /dev/null +++ b/documentation/architecture/openspec/specs/modules/spec.md @@ -0,0 +1,20 @@ +# Accretive Modules + +## Purpose +To provide utilities to reclassify existing modules as accretive, ensuring that module-level attributes become immutable after a finalization step. This is useful for preventing accidental modification of module constants or configuration. + +## Requirements + +### Requirement: Module Reclassification +The system SHALL provide utilities to reclassify existing modules as accretive, making module-level attributes immutable after finalization. + +Priority: High + +#### Scenario: Reclassifying a module +- **WHEN** a module is reclassified using the `finalize_module` utility +- **THEN** the module class is changed to an accretive module type + +#### Scenario: Modifying finalized module +- **WHEN** a user attempts to modify an attribute of a finalized module +- **THEN** an exception is raised +- **AND** the attribute remains unchanged diff --git a/documentation/architecture/openspec/specs/namespaces/spec.md b/documentation/architecture/openspec/specs/namespaces/spec.md new file mode 100644 index 0000000..c9d2c1a --- /dev/null +++ b/documentation/architecture/openspec/specs/namespaces/spec.md @@ -0,0 +1,26 @@ +# Accretive Namespaces + +## Purpose +To provide a namespace implementation similar to `types.SimpleNamespace` that allows adding attributes dynamically but prevents modification or deletion of existing attributes, suitable for configuration objects and structured data carriers. + +## Requirements + +### Requirement: Basic Namespace +The system SHALL provide an accretive namespace that allows adding attributes dynamically but prevents modification or deletion of existing attributes. + +Priority: Critical + +#### Scenario: Adding new attributes +- **WHEN** a user assigns a value to a new attribute +- **THEN** the attribute is added to the namespace +- **AND** the value can be accessed via dot notation + +#### Scenario: Modifying existing attributes +- **WHEN** a user attempts to reassign an existing attribute +- **THEN** an `AttributeImmutability` exception is raised +- **AND** the original value remains unchanged + +#### Scenario: Deleting attributes +- **WHEN** a user attempts to delete an existing attribute +- **THEN** an exception is raised +- **AND** the attribute remains in the namespace diff --git a/documentation/prd.rst b/documentation/prd.rst deleted file mode 100644 index c10568a..0000000 --- a/documentation/prd.rst +++ /dev/null @@ -1,424 +0,0 @@ -.. vim: set fileencoding=utf-8: -.. -*- coding: utf-8 -*- -.. +--------------------------------------------------------------------------+ - | | - | Licensed under the Apache License, Version 2.0 (the "License"); | - | you may not use this file except in compliance with the License. | - | You may obtain a copy of the License at | - | | - | http://www.apache.org/licenses/LICENSE-2.0 | - | | - | Unless required by applicable law or agreed to in writing, software | - | distributed under the License is distributed on an "AS IS" BASIS, | - | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | - | See the License for the specific language governing permissions and | - | limitations under the License. | - | | - +--------------------------------------------------------------------------+ - - -******************************************************************************* -Product Requirements Document -******************************************************************************* - -Executive Summary -=============================================================================== - -The package provides data structures that enforce a grow-only constraint: values -can be added but never modified or removed once set. It offers accretive -variants of familiar Python types (dictionaries, namespaces, classes, modules) -with consistent APIs and flexible configuration options for selective -mutability. - -The package addresses the need for collections that accumulate state with -immutability guarantees, particularly valuable for configuration registries, -plugin systems, and scenarios requiring sticky state. By providing a middle -ground between fully immutable and fully mutable collections, the package -enables developers to build safer, more predictable systems. - -Problem Statement -=============================================================================== - -Who Experiences the Problem -------------------------------------------------------------------------------- - -Python developers building systems that require: - -* Configuration registries where entries must persist once registered -* Plugin architectures where registered extensions must remain available -* Caching systems where entries should never be invalidated -* Event handlers or callback registries with guaranteed availability -* Any scenario requiring grow-only collections with immutability guarantees - -When and Where It Occurs -------------------------------------------------------------------------------- - -The problem manifests in production systems when: - -* Configuration values are accidentally overwritten, causing unpredictable behavior -* Plugin registrations are removed, breaking dependent functionality -* Cached entries are invalidated prematurely, causing performance issues -* State mutation creates race conditions in concurrent systems -* Debugging reveals unexpected state changes with unclear origins - -Impact and Consequences -------------------------------------------------------------------------------- - -Without accretive data structures: - -* **Correctness Issues**: Accidental state mutation leads to bugs that are - difficult to reproduce and diagnose -* **Concurrency Problems**: Mutable shared state creates race conditions and - synchronization complexity -* **Maintenance Burden**: Developers must manually enforce immutability through - documentation and code review -* **Runtime Failures**: State tampering can cause critical system failures in - production environments -* **Testing Complexity**: Mutable state makes unit tests fragile and dependent - on execution order - -Current Workarounds and Limitations -------------------------------------------------------------------------------- - -Existing approaches include: - -* **Frozen dataclasses**: Provide immutability but prevent any growth; cannot - add new attributes after initialization -* **Manual immutability enforcement**: Requires discipline, documentation, and - code review; error-prone and not enforceable at runtime -* **Copy-on-write patterns**: Add performance overhead and memory consumption; - complexity scales with collection size -* **Read-only wrappers**: Limited to specific collection types; do not support - selective mutability or initialization phases - -These solutions fail to provide the specific combination of: - -* Allowing growth (new entries/attributes) -* Preventing modification of existing entries/attributes -* Supporting flexible initialization patterns -* Maintaining familiar Python APIs -* Enabling selective mutability when needed - -Goals and Objectives -=============================================================================== - -Primary Objectives -------------------------------------------------------------------------------- - -**REQ-OBJ-001 [Critical]: Accretive Behavior** - -Provide data structures that enforce grow-only semantics: new values can be -added, but existing values cannot be modified or removed. - -Success Metrics: - -* 100% prevention of modification attempts on existing entries -* Clear, informative exceptions when immutability is violated -* Zero false positives (legitimate additions incorrectly rejected) - -**REQ-OBJ-002 [Critical]: Familiar APIs** - -Maintain APIs consistent with standard Python types (dict, SimpleNamespace, -type, ModuleType) to minimize learning curve. - -Success Metrics: - -* All standard collection operations supported except mutation -* Initialization patterns match standard library types -* Drop-in replacement possible in most use cases - -**REQ-OBJ-003 [High]: Flexible Mutability** - -Support selective mutability for specific attributes/entries when needed during -initialization or for specific use cases. - -Success Metrics: - -* Configuration options for mutable attribute patterns -* Support for unprotected initialization phases -* Compatibility with standard decorators (dataclasses, etc.) - -Secondary Objectives -------------------------------------------------------------------------------- - -**REQ-OBJ-004 [Medium]: Comprehensive Type Coverage** - -Provide accretive variants for common Python types beyond basic collections. - -Success Metrics: - -* Dictionary types with standard, producer, and validator variants -* Namespace types matching SimpleNamespace functionality -* Class metaclasses supporting dataclasses and standard classes -* Module reclassification utilities - -Functional Requirements -=============================================================================== - -Accretive Dictionary Types -------------------------------------------------------------------------------- - -**REQ-DICT-001 [Critical]: Basic Dictionary** - -Standard accretive dictionary implementation that allows adding new entries but -prevents modifying or removing existing ones. - -Acceptance Criteria: - -* Supports initialization from iterables and keyword arguments -* Implements collections.abc.Mapping protocol -* Allows ``__setitem__`` for new keys only -* Raises ``EntryImmutability`` exception on modification attempts -* Prevents ``__delitem__`` operations on existing keys -* Supports all read operations (get, keys, values, items, etc.) - -**REQ-DICT-002 [High]: Producer Dictionary** - -Dictionary that auto-generates values for missing keys using a factory function, -similar to collections.defaultdict but with accretive behavior. - -Acceptance Criteria: - -* Accepts factory function for generating default values -* Generates value on first access to missing key -* Generated values become immutable after creation -* Behaves identically to Dictionary for existing keys - -**REQ-DICT-003 [Medium]: Validator Dictionary** - -Dictionary that validates entries before addition using a predicate function, -ensuring only valid data can be added. - -Acceptance Criteria: - -* Accepts predicate function for validation -* Calls predicate with (key, value) on each addition attempt -* Raises ``EntryInvalidity`` exception on validation failure -* Allows only valid entries to be added and made immutable - -**REQ-DICT-004 [Medium]: Combined Producer-Validator** - -Dictionary combining auto-generation and validation behaviors. - -Acceptance Criteria: - -* Generated default values must pass validation -* Validation failures raise clear exceptions -* Behaves as expected from both parent classes - -Accretive Namespace Types -------------------------------------------------------------------------------- - -**REQ-NS-001 [Critical]: Basic Namespace** - -Accretive namespace similar to types.SimpleNamespace that allows adding -attributes dynamically but prevents modification or deletion of existing -attributes. - -Acceptance Criteria: - -* Allows dynamic attribute assignment with dot notation -* Prevents modification of existing attributes -* Prevents deletion of existing attributes -* Raises ``AttributeImmutability`` exception on violations -* Supports initialization from iterables and keyword arguments -* Provides readable ``__repr__`` listing all attributes - -Accretive Class Types -------------------------------------------------------------------------------- - -**REQ-CLASS-001 [Critical]: Standard Metaclass** - -Metaclass for creating classes with accretive instances where instance -attributes become immutable after first assignment. - -Acceptance Criteria: - -* Works as a metaclass (``metaclass=Class``) -* Instance attributes become immutable after first assignment -* Supports selective mutability via configuration -* Integrates with classcore class factory system -* Supports dynadoc documentation generation - -**REQ-CLASS-002 [High]: Dataclass Metaclass** - -Metaclass for dataclasses with accretive instances, compatible with the -@dataclass decorator. - -Acceptance Criteria: - -* Compatible with @dataclass decorator -* Frozen instances by default -* Supports kw_only parameters -* Field values immutable after initialization -* Proper dataclass_transform type checking support - -**REQ-CLASS-003 [Medium]: Mutable Dataclass Metaclass** - -Metaclass for dataclasses with selectively mutable instances. - -Acceptance Criteria: - -* Instance attributes can be declared mutable -* Class-level immutability maintained -* Supports standard dataclass features -* Clear documentation of mutability patterns - -Accretive Module Types -------------------------------------------------------------------------------- - -**REQ-MOD-001 [High]: Module Reclassification** - -Utilities to reclassify existing modules as accretive, making module-level -attributes immutable after finalization. - -Acceptance Criteria: - -* ``Module`` class extends types.ModuleType -* Module attributes become immutable after finalization -* ``finalize_module`` utility for reclassification -* Recursive reclassification for package hierarchies -* Integration with dynadoc for documentation - -Error Handling -------------------------------------------------------------------------------- - -**REQ-ERR-001 [Critical]: Exception Hierarchy** - -Clear exception hierarchy for accretive violations with informative error -messages. - -Acceptance Criteria: - -* ``Omnierror`` base class for all package errors -* ``AttributeImmutability`` for attribute violations -* ``EntryImmutability`` for dictionary entry violations -* ``EntryInvalidity`` for validation failures -* Exception messages include attribute/key names and context -* Exceptions inherit from appropriate standard types (TypeError, ValueError) - -Non-Functional Requirements -=============================================================================== - -Compatibility Requirements -------------------------------------------------------------------------------- - -**REQ-COMPAT-001**: Support Python 3.10 and above. - -**REQ-COMPAT-002**: Compatible with static type checkers (mypy, pyright). - -**REQ-COMPAT-003**: Compatible with standard decorators (@dataclass, @property, -etc.). - -**REQ-COMPAT-004**: Works correctly with pickling and unpickling. - -Usability Requirements -------------------------------------------------------------------------------- - -**REQ-USE-001**: API matches standard library conventions where possible. - -**REQ-USE-002**: Error messages clearly identify violation source and suggest -fixes. - -**REQ-USE-003**: Comprehensive documentation with practical examples. - -**REQ-USE-004**: Docstrings for all public APIs generated via dynadoc. - -Reliability Requirements -------------------------------------------------------------------------------- - -**REQ-REL-001**: 100% test coverage for core functionality. - -**REQ-REL-002**: Zero known bugs in immutability enforcement. - -**REQ-REL-003**: Comprehensive test suite covering edge cases. - -Maintainability Requirements -------------------------------------------------------------------------------- - -**REQ-MAINT-001**: Follows project-standard filesystem organization. - -**REQ-MAINT-002**: Uses cascading import hub pattern (``__`` subpackage). - -**REQ-MAINT-003**: Integrates with classcore for consistent behavior. - -**REQ-MAINT-004**: Clear separation between public API and internal implementation. - -Constraints and Assumptions -=============================================================================== - -Technical Constraints -------------------------------------------------------------------------------- - -* **Python Immutability Limitations**: True immutability is impossible in - Python; enforcement is best-effort and can be circumvented by determined users - with intermediate Python knowledge. The package encourages immutability rather - than guarantees it. - -* **Metaclass Limitations**: Classes can only have one metaclass; users cannot - combine accretive metaclasses with other custom metaclasses without multiple - inheritance or creative workarounds. - -* **Performance Overhead**: Attribute assignment interception adds overhead - compared to standard types; acceptable for most use cases but may be - prohibitive for performance-critical inner loops. - -Dependencies -------------------------------------------------------------------------------- - -* **classcore**: Core dependency providing class factory system and behavior - configuration mechanisms. - -* **dynadoc**: Documentation generation from type annotations and fragments. - -* **absence**: Sentinel values for distinguishing absent vs None parameters. - -* **frigid**: Immutable data structures for internal configuration storage. - -Assumptions -------------------------------------------------------------------------------- - -* Users have intermediate to advanced Python knowledge -* Users understand the limitations of Python immutability enforcement -* Users prioritize correctness and safety over maximum performance -* Users accept minimal performance overhead for immutability guarantees -* Standard library types (dict, object, module) will maintain backward - compatibility - -Out of Scope -=============================================================================== - -The following features are explicitly excluded from the current product scope: - -**Deep Immutability** - -The package does not enforce immutability of nested values. If a dictionary -entry is itself mutable (e.g., a list), that object can still be modified. Only -the binding between key and value is immutable. - -**Cryptographic Guarantees** - -The package does not provide cryptographic verification of immutability or -tamper detection. Immutability enforcement is best-effort in Python's dynamic -environment. - -**Multi-Process Synchronization** - -The package does not provide synchronization primitives for multi-process -scenarios. Thread-safety within a single process is supported, but distributed -consistency is out of scope. - -**Migration Tools** - -Automatic migration from standard types to accretive types is not provided. -Users must manually adopt accretive types in their codebases. - -**Performance Optimization Beyond Standard Types** - -While performance overhead should be minimal, optimizations to make accretive -types faster than standard types are not a goal. - -**Alternative Immutability Models** - -Other immutability patterns (copy-on-write, persistent data structures, etc.) -are not provided. The package focuses exclusively on accretive semantics. \ No newline at end of file