Skip to content

Changelog

All notable changes to this project will be documented in this file.

The format follows Keep a Changelog and this project adheres to Semantic Versioning.

[0.4.0] - 2026-07-04

Added

  • Task.active_duration — time actively spent working on the task, distinct from actual_duration (which may include background or automated processing time). If only one of active_duration / actual_duration is provided at instantiation, the other defaults to the same value.
  • Risk — a project risk attached to Scope.risks (frozenset[Risk], keyed by integer id, merged like backlog/user_stories). Fields: id, description, rasci (frozenset[RasciAssignment], responsibility for managing the risk overall), potential_assessment and residual_assessment (RiskAssessment, before/after controls), risk_controls (frozenset[RiskControl], accumulated by union on merge).
  • RiskAssessment — scores impact, probability, and threat as [0.0, 1.0] indexes and categorizes each into a str label via a pluggable RiskAssessmentStrategy. Carries the strategy instance used plus a computed strategy_name field for provenance. RiskAssessment.assess(impact, probability, threat, strategy=...) is the convenience factory.
  • RiskAssessmentStrategy — abstract base (frozen pydantic.BaseModel + ABC) with categorize_impact/categorize_probability/categorize_threat methods. ThresholdRiskAssessmentStrategy is the default implementation, splitting [0.0, 1.0] into four quartile buckets.
  • RiskLevel, ImpactLevel, ProbabilityLevel — 4-level, semantically ordered enums used as the default strategy's category vocabulary for threat, impact, and probability respectively.
  • RiskControl — a control measure with a description and an optional embedded procedure: Procedure | None.
  • Risk, RiskAssessment, RiskAssessmentStrategy, ThresholdRiskAssessmentStrategy, DEFAULT_RISK_ASSESSMENT_STRATEGY, RiskControl, RiskLevel, ImpactLevel, and ProbabilityLevel are now part of the public API, importable directly from fushinryu_model.

[0.3.0] - 2026-07-03

Added

  • DescriptionMode — enum controlling how a child Role's description is composed with its parent's during a scope merge. Values: OVERRIDE (default), EXTEND, PREPEND. Now part of the public API.
  • Role.description_mode — new DescriptionMode field (defaults to OVERRIDE).
  • ChangeKind — enum of change event kinds: CREATED, UPDATED, DEACTIVATED, SUPERSEDED.
  • HistoryEntry — frozen value object recording a change event: kind (ChangeKind), timezone-aware timestamp, optional author.
  • UserStoryHistoryEntry — extends HistoryEntry with added_acs: frozenset[int] and deactivated_acs: frozenset[int] for AC-level change traceability.
  • Historized — frozen Pydantic mixin adding history: frozenset[HistoryEntry] with union merge semantics. UserStory overrides the field type to frozenset[UserStoryHistoryEntry].
  • Comment — frozen value object with id, body, timezone-aware timestamp, and optional author.
  • Commentable — frozen Pydantic mixin adding comments: frozenset[Comment] with union merge semantics.
  • UserStory and Task now carry both Historized and Commentable; Role carries Historized only.
  • ChangeKind, Comment, Commentable, HistoryEntry, Historized, and UserStoryHistoryEntry are now part of the public API, importable directly from fushinryu_model.

Changed

  • Role.description merge behaviour is now explicit: the child's description_mode field controls composition. BREAKING: the default is OVERRIDE (child replaces parent), replacing the prior implicit EXTEND behaviour (child appended to parent). Roles that relied on the old accumulation must set description_mode=EXTEND explicitly.

[0.2.0] - 2026-06-20

Added

  • examples/ interactive explorer (uv run python -m examples.tour) walking every feature area of the model through the fictional Windward Systems / BreezeBoard scenario. Repository-only: the wheel now explicitly packages fushinryu_model alone.
  • RASCILevel — semantically ordered enum (via the new fields-metadata dependency's SemanticallyOrderedEnum) for RASCI responsibility levels: ACCOUNTABLE ("A") > RESPONSIBLE ("R") > SUPPORTIVE ("S") > CONSULTED ("C") > INFORMED ("I"). Now part of the public API.
  • Procedure — non-mergeable flowchart entity attached to Scope.procedures. Fields: id (non-empty, the merge key), description (non-empty), nodes (frozenset[ProcedureNode]). Validates unique node ids and that every node's linkage target resolves to a node id present in the same procedure; multiple start terminators are allowed.
  • Node — discriminated union of 11 flowchart node kinds (StartTerminatorNode, EndTerminatorNode, ActivityNode, DecisionNode, InputNode, OutputNode, PredefinedProcedureNode, ManualOperationNode, ManualInputNode, ForkNode, SyncNode), each carrying id, description, and rasci (frozenset[RasciAssignment]). DecisionNode.cases pairs case labels with next-node ids (DecisionCase); ForkNode.branches lists parallel next-node ids; PredefinedProcedureNode.procedure_id references another Procedure.id.
  • RasciAssignment — binding pairing a role name with a RASCILevel, used by ProcedureNode.rasci.
  • Scope.proceduresfrozenset[Procedure] field, unique by id within a scope. On merge, a child scope's Procedure replaces a same-id parent Procedure wholesale (no field- or node-level merging), unlike the rest of Scope's collections.
  • Procedure, ProcedureNode, all 11 node classes, DecisionCase, and RasciAssignment are now part of the public API, importable directly from fushinryu_model.

Changed

  • pleroma and pydantic dependency constraints tightened from >= to ~=, matching the project's pinning convention for library dependencies.

[0.1.6] - 2026-06-12

Added

  • ScopeKindstr enum classifying the type of organisational unit a Scope represents. Values: organization, office, area, department, team, project, development.
  • Scope.kind — optional ScopeKind | None field (defaults to None). Inherits standard scalar merge semantics: a child's non-None kind overrides the parent's; a None child kind leaves the parent's value intact.
  • ScopeKind is now part of the public API, importable directly from fushinryu_model.
  • ProgramCompetence — binding that associates a Competence with the CompetenceLevel at which it is taught by a program.
  • TrainingProgram — standalone training course entity. Fields: id (int), title (non-empty), syllabus (non-empty), duration (positive timedelta), competences (frozenset[ProgramCompetence], defaults to empty). Each competence must appear at most once. Not attached to Scope.
  • Trainer — value object identifying who delivered a training. Fields: name (non-empty), organization (str | None, defaults to None).
  • ReceivedTraining — record that an employee completed a training program. Fields: program, employee, received_on (datetime.date), location (non-empty), trainer, evidences (frozenset[str], defaults to empty). Not attached to Scope.
  • ProgramCompetence, TrainingProgram, Trainer, and ReceivedTraining are now part of the public API, importable directly from fushinryu_model.

[0.1.5] - 2026-06-12

Added

  • Role — named actor entity. Fields: name (identifier-pattern validated), description (non-empty), parent (Role | None, defaults to None), competences (frozenset[RoleCompetence], defaults to empty). Exposes flatten() method that resolves and removes the parent chain. Competence names within a role must be unique.
  • CompetenceLevel — ordered int enum with values NONE=0, BASIC=1, MODERATE=2, PROFICIENT=3. Integer values enable direct comparison and max() in merge operations.
  • CompetenceRelevance — ordered int enum with values UNRELATED=0, RELEVANT=1, DESIRABLE=2, KEY=4. Integer values act as multipliers in weighted computations.
  • Competence — value object identified by (area, category, name) triple. All three fields must be non-empty strings.
  • RoleCompetence — binding that associates a Competence with a relevance and proficiency_threshold on a role. Merges using max-value semantics: the higher relevance and the higher proficiency threshold from parent/child are kept independently.
  • Scope.rolesfrozenset[Role] field. Role names must be unique within the set. Defaults to empty. Merges by matching Role.name: same-named roles from parent and child scopes are linked (child's parent is set to the parent scope's role). collapse() flattens all role parent chains.
  • EmployeeCompetence — binding that associates a Competence with a CompetenceLevel, representing an employee's actual proficiency.
  • Employee — person entity. Fields: id (non-empty string), username (non-empty string), competences (frozenset[EmployeeCompetence], defaults to empty). Each competence must appear at most once.
  • RoleAssignment — links an Employee to a Role. Exposes training_needs() -> TrainingNeeds and the idoneity property.
  • TrainingNeed — records the training distance for a single competence: competence, relevance, proficiency_threshold, employee_level. The partial_distance property computes max(0, threshold - level) × relevance.
  • TrainingNeeds — full gap analysis of an employee against a role: employee, role, needs (frozenset[TrainingNeed]). The total_distance property sums all partial_distance values.
  • idoneity property on RoleAssignment — computes Σ(level × relevance) / Σ(relevance) over all non-UNRELATED role competences. Absent competences default to NONE. Returns 0.0 when no relevant competences are defined.
  • Scope.role_assignmentsfrozenset[RoleAssignment] field. Defaults to empty. Merges with child-override semantics keyed by (employee.id, role.name).
  • Role, RoleCompetence, Competence, CompetenceLevel, CompetenceRelevance, Employee, EmployeeCompetence, RoleAssignment, TrainingNeed, and TrainingNeeds are now part of the public API, importable directly from fushinryu_model.

[0.1.4] - 2026-06-09

Added

  • Commandment — mandatory rule value object with a body string. Empty or whitespace-only body is rejected.
  • Suggestion — recommended rule value object with identical structure. May be waived under justified conditions.
  • Ruleset — groups commandments and suggestions as two separate frozenset fields (both default to empty).
  • Category — recursive rule-category entity. Fields: name (identifier-pattern validated), applicability (mandatory string), tags (frozenset[str]), additive (bool, default False), ruleset (Ruleset), subcategories (frozenset[Category]). Subcategory names must be unique. Exposes effective_commandments and effective_suggestions properties that union recursively down the subcategory tree.
  • Scope.rule_categoriesfrozenset[Category] field. Category names must be unique at the top level. Defaults to empty frozenset.
  • Rule-category merge semantics on Scope.merge() and collapse(): categories are matched by name at each tree level and merged recursively. Commandments union by body (deduplicated). Suggestions replace the parent's unless the child category has additive=True, in which case they are unioned. collapse() propagates this transitively across the full ancestry DAG.
  • Category, Commandment, Suggestion, and Ruleset are now part of the public API, importable directly from fushinryu_model.

[0.1.3] - 2026-06-06

Added

  • Task — new domain entity representing a concrete work item in a Scope's backlog. Fields: id, title, description, priority (TaskPriority), kind (TaskKind), lifecycle_status (TaskLifecycleStatus), on_hold, estimated_duration (timedelta | None), actual_duration (timedelta | None), related_acs (frozenset[str]).
  • TaskPriority enum — low, medium, high, critical.
  • TaskKind enum — enhancement, bug, research, investigation, documentation, release, deployment.
  • TaskLifecycleStatus enum — pending, doing, validation, done.
  • Scope.backlogfrozenset[Task] field holding the scope's work items. Task ids must be unique within the backlog. Backlog merges across the scope hierarchy the same way user_stories does.
  • estimated_duration is mandatory for kinds enhancement, bug, documentation, release, and deployment; optional for research and investigation.
  • related_acs merges as a union (same semantics as UserStory.tags).

[0.1.2] - 2026-06-06

Added

  • AcceptanceCriterion.requirement_specification — optional ISO 29148 document type (RequirementSpecification | None, defaults to None). Accepted values: SRS, SyRS, StRS.
  • AcceptanceCriterion.requirement_group — optional requirement category within the chosen specification (RequirementGroup | None, defaults to None). Must be set together with requirement_specification and must be a group that belongs to that specification.
  • RequirementSpecification and RequirementGroup enums — now part of the public API, importable directly from fushinryu_model.

[0.1.1] - 2026-06-06

Added

  • UserStory.dod — optional free-form prose field for the definition of done (str | None, defaults to None).
  • UserStory.tags — unordered set of short label strings (frozenset[str], defaults to empty). Tags merge as a union when parent and child stories are merged.
  • AcceptanceCriterion.tags — same type and merge semantics as UserStory.tags.

Changed

  • Scope.description is now optional (str | None, defaults to None). Previously it was a required field.
  • Project renamed from fushinryu_model to fushinryu-model to align with PyPI distribution naming conventions. The importable package name remains fushinryu_model.

[0.1.0] - 2026-06-06

Initial release. Provides the core domain entities:

  • Scope — organisational unit with DAG parent hierarchy and collapse().
  • UserStory — structured requirement with who / what / why and UserStoryType.
  • AcceptanceCriterionGiven / When / Then testable condition.
  • ManualValidation / AutomatedValidation — immutable validation evidence.
  • Merge semantics for all entities via pleroma.MergeableModel.