SACM 2.3 conformance matrix
Status values:
not-startedanalyzedtests-failingimplementedverifieddeferredout-of-scope
This matrix is a working control artifact and the canonical source of requirement IDs (test names embed them). Sources: normative specification text formal/23-05-08 (PDF) and machine-readable model ptc/22-03-13, pinned by scripts/fetch-sacm23-references.sh; the class/attribute/containment inventory derived from them is docs/sacm/sacm-2.3-metamodel-inventory.md.
The project goal is full SACM 2.3 compliance. Incremental rows may start with a subset, but subset status must not be represented as full compliance until verified.
| ID | Area | Source | Requirement | Type | Status | Library files | Tests | Notes |
|---|---|---|---|---|---|---|---|---|
| SACM23-LIB-001 | Library boundary | Architecture decision (ADR 0006) | The SACM library public API must not depend on Assurance Forge UI/app/core/parser/AI/review classes or names. | architecture | verified | libs/sacm/CMakeLists.txt, cmake/check_layer_gates.cmake | configure-time gate (cmake/check_layer_gates.cmake, FATAL_ERROR, runs on every build) | Reverse gate scans quoted+angle includes; pugixml banned from public headers; standalone build supported. |
| SACM23-CP-001 | Compliance point | formal/23-05-08 clause 2.4 | Assurance Case Model compliance point (mandatory): import and export XMI documents whose unit of interchange is SACM::AssuranceCasePackage. |
test | verified | libs/sacm/src/io/xmi_reader.cpp, libs/sacm/src/io/xmi_writer.cpp | Sacm23CompliancePoints.SACM23_CP_001_AssuranceCasePackageIsTheMandatoryInterchangeUnit | Claimed. The mandatory point. Decision table and limits: compliance points. |
| SACM23-CP-002 | Compliance point | formal/23-05-08 clause 2.2 | Argumentation Model compliance point: import and export XMI documents whose unit of interchange is Argumentation::ArgumentPackage. |
test | verified | libs/sacm/src/io/xmi_reader.cpp, libs/sacm/src/io/xmi_writer.cpp | Sacm23CompliancePoints.SACM23_CP_002_ArgumentPackageIsAnInterchangeUnit | Claimed. Clause 2.2 states conformance here does not entail Artifact or Terminology support, so the fixture carries neither. Before #295 the library accepted this root but no fixture used it. |
| SACM23-CP-003 | Compliance point | formal/23-05-08 clause 2.3 | Artifact Model compliance point: import and export XMI documents whose unit of interchange is Artifact::ArtifactPackage. |
test | verified | libs/sacm/src/io/xmi_reader.cpp, libs/sacm/src/io/xmi_writer.cpp | Sacm23CompliancePoints.SACM23_CP_003_ArtifactPackageIsAnInterchangeUnit | Claimed. Clause 2.3 states conformance here does not entail Argumentation or Terminology support. |
| SACM23-CP-004 | Compliance point | formal/23-05-08 clause 2.5 | Terminology Model compliance point: import and export XMI documents whose unit of interchange is Terminology::TerminologyPackage. |
test | verified | libs/sacm/src/io/xmi_reader.cpp, libs/sacm/src/io/xmi_writer.cpp | Sacm23CompliancePoints.SACM23_CP_004_TerminologyPackageIsAnInterchangeUnit | Claimed. |
| SACM23-CP-005 | Compliance point | formal/23-05-08 clause 2.6 | SACM UML Profile compliance point: import and export conformant XMI for all valid SACM UML models. | analysis | out-of-scope | (none) | (none) | Not claimed. A different input language -- UML models carrying SACM stereotypes, not SACM metamodel instances -- and no part of it is implemented in libs/sacm. Recorded rather than omitted, because an unmentioned compliance point reads as one that was met. See compliance points. |
| SACM23-LIB-002 | Source of truth | Architecture decision (ADR 0006) | Loaded SACM data must be owned by the SACM library; Assurance Forge projections must not become the serialization source of truth. | architecture | verified | src/core/app_state.cpp (load_file, save_file, sync_library_document), src/core/project_service.cpp (MinimalSacmXml), src/sacm_adapter/library_load.cpp (new_case_document_xmi, reload_document_keeping_compatibility_content), src/core/audit/event_replayer.cpp, libs/sacm/src/compat/preserve.cpp, src/core/commands/command_bus.cpp, src/core/audit/audit_recovery.cpp, src/core/audit/history_reconstruction.cpp, src/core/commands/undo_command.cpp, src/core/sacm_argument_sync.cpp, src/sacm_adapter/*, src/core/library_package_projection.cpp | AppStateTest.LoadFileUsesTheLibraryDocumentAsTheSourceOfTruth, SacmLibrarySave.SACM23_INT_001_XmiSaveRoundTripsTheProjection, SacmLibrarySave.SACM23_INT_001_LibraryPackageProjectionCapturesTerminology, SaveFromLibrary.SACM23_LIB_002_LegacyPackageSavePathDropsUnknownContent, SaveFromLibrary.SACM23_LIB_002_UnknownContentSurvivesLoadEditSaveReload, SaveFromLibrary.SACM23_LIB_002_AutosaveAndExplicitSaveProduceIdenticalBytes, SaveFromLibrary.SACM23_LIB_002_RepeatedSavesAreByteStable, SaveFromLibrary.SACM23_LIB_002_RepeatedSavesAreByteStableForRepositoryCases, SaveFromLibrary.SACM23_LIB_002_RestoreFromAuditPreservesUnknownContent, ProjectServiceTest.SACM23_LIB_002_NewProjectSeedIsStrictSacm23Xmi, SaveFromLibrary.SACM23_LIB_002_BridgedEditPreservesUnknownContent, SaveFromLibrary.SACM23_LIB_002_BridgedEditPreservesAcpTaggedValues, SaveFromLibrary.SACM23_LIB_002_BridgedEditSucceedsOnMultiArgumentPackageCase, SaveFromLibrary.SACM23_LIB_002_RestoreAfterBridgedEditPreservesAcpTaggedValues, SaveFromLibrary.SACM23_LIB_002_RestoreAfterBridgedEditPreservesUnknownContent, SaveFromLibrary.SACM23_LIB_002_RestoreAfterBridgedEditSucceedsOnMultiArgumentPackageCase, Sacm23RoundTrip.SACM23_LIB_002_AdoptPreservedContentRestoresWhatAProjectionDrops, UndoCommand.SACM23_LIB_002_UndoPreservesVendorTaggedValuesInTheSavedFile, UndoCommand.SACM23_LIB_002_LibraryPrimaryUndoPreservesUnknownVendorContent, HistoryReconstruction.SACM23_LIB_002_ReconstructionPreservesVendorTaggedValues, HistoryReconstruction.SACM23_LIB_002_ReconstructionCarriesBareStrategyPlacement, SaveFromLibrary.SACM23_LIB_002_BridgedEditPreservesCounterRelationships, SaveFromLibrary.SACM23_LIB_002_NodeOnlyRemovalRunsNativelyAndKeepsUnrepresentableElements, SaveFromLibrary.SACM23_LIB_002_FlippedMoveSubtreeRunsOnACaseTheBridgeRefuses, SaveFromLibrary.SACM23_LIB_002_FlippedReorderSiblingsRunsOnACaseTheBridgeRefuses, SaveFromLibrary.AuditProjectionOfAnArtifactBearingCaseReloadsThroughTheLibrary, SaveFromLibrary.SACM23_LIB_002_BridgedEditPreservesMetaClaimAndReasoningStructure, SaveFromLibrary.SACM23_LIB_002_ChildUnderReasoningFallbackFailsWithFileUntouched, SaveFromLibrary.SACM23_LIB_002_FlippedTerminologyCommandsRunOnACaseTheBridgeRefuses, SaveFromLibrary.SACM23_LIB_002_NativeTerminologyEditsPreserveUnknownContent, SaveFromLibrary.SACM23_LIB_002_NativeArgumentPackageRemovalPreservesUnknownContent, SaveFromLibrary.SACM23_LIB_002_ConsentedTermDeleteRemovesTheReferencesFromTheSavedFile, SaveFromLibrary.SACM23_LIB_002_FlippedPackageAndGidCommandsRunOnACaseTheBridgeRefuses, SaveFromLibrary.SACM23_LIB_002_FlippedGsnIdentifierRunsOnACaseTheBridgeRefuses, SaveFromLibrary.SACM23_LIB_002_FlippedAcpCommandsRunOnACaseTheBridgeRefuses, SaveFromLibrary.SACM23_LIB_002_FlippedMoveStrategyRunsOnACaseTheBridgeRefuses, ElementEditControllerTest.SACM23_LIB_002_NoBusEditKeepsUnrepresentableContent | Verified (round 5, after FAIL rounds 3 and 4 each closed a silent-loss path). Every bus command with a document present either applies through the library seams or routes its legacy fallback through the guarded bridge, whose DOCUMENT-inventory sweep refuses any edit on a document the projection cannot fully represent, tracked file byte-unchanged. Ten unrepresentable KINDS (listed in the preservation record) are swept by ProjectionCoverage.SACM23_LIB_002_BridgeRoundTripLosesOnlyTheKnownKinds and refused. Three ATTRIBUTES are lost and NOT refused (Claim@abstractForm, AssuranceCasePackage@gid, Expression@element, #347); Claim@isCitation+@citedElement are carried, because GSN Away elements rest on them (GSN3-MOD-003): the guard sweeps elements, so a document losing only attributes goes through silently. Gated both ways by SACM23_LIB_002_BridgeRoundTripKeepsEveryAttributeOfASurvivingElement, which fails outright on a changed value. The legacy bridge is DELETED (#350 phases 1-4): every command applies through the library seams, and a shape no seam expresses is refused with the document untouched rather than rebuilt from a projection. The kill switch, the replay bridge and the strategy-encoding migration went with it. Disclosed behaviour changes: a term delete now previews its references and removes them on recorded consent rather than leaving them dangling; an artifact-package removal scrubs the references it used to strand; gids are planned by the caller, not reconstructed by the seam; RemoveTerminologyPackage keeps its non-empty guard. Evidence, history and every verifier round: preservation record; phase status: migration plan. Library interchange conformance is a separate claim -- see compliance points. |
| SACM23-LIB-003 | Layout boundary | Architecture/layout policy | Layout, visual representation, canvas coordinates, tree positions, and GSN display state must not appear in the SACM library API or strict XMI output. | architecture | verified | libs/sacm/include/** | test_xmi_io.cpp (SACM23_LIB_003_*), test_roundtrip.cpp strict-output scan | Mechanical scan of public headers and strict XMI output for GSN/layout vocabulary. |
| SACM23-CMD-001 | Editing API | Editing policy | The library must expose SACM-native mutation operations with structured mutation results and no GSN/UI terminology. | model/edit | verified | libs/sacm/include/sacm/commands/, src/commands/ | SACM23_CMD_001_OperationsAreSacmNativeWithStructuredResults, test_delete_preview.cpp | Operation variant + Document::preview/apply; strict SACM terminology only. The test iterates the Operation variant, so new operations are covered automatically. SetMetaClaims (11.6) and SetRelationshipEnds (11.13) were added because AddMetaClaim and AddRelationshipSource were one-way -- attachable, never detachable -- so a client retracting either had no operation. Both replace the list the way SetExpressionCategories does. SetRelationshipEnds accepts an unresolved endpoint ONLY where the relationship already carried it, so a document with two broken endpoints stays repairable one at a time while a new dangling reference cannot be introduced. |
| SACM23-CMD-002 | Create document/package | Clause 9.2 + editing policy | The library must create a new SACM 2.3 document containing an AssuranceCasePackage with valid identity and strict-save behavior. |
model/edit/xmi | verified | libs/sacm/src/commands/commands.cpp, src/model/document.cpp | test_document_commands.cpp (SACM23_CMD_002_*) | Caller-provided and deterministic generated ids; strict-save proof lands with XMI slice. |
| SACM23-CMD-003 | Create argument/claim | Clauses 11.4, 11.11 + editing policy | The library must create an ArgumentPackage and Claim using SACM terminology and preserve them through save/load. |
model/edit/xmi | verified | libs/sacm/src/commands/commands.cpp | test_document_commands.cpp (SACM23_CMD_003_*) | Claim text stored as Description per clause 8.9; save/load proof lands with XMI slice. |
| SACM23-CMD-004 | Delete preview | Editing policy | Destructive delete operations must provide an operation preview with affected elements, relationships, diagnostics, and applicability before mutation. | edit/validation | verified | libs/sacm/src/commands/commands.cpp (check_delete) | test_delete_preview.cpp (SACM23_CMD_004_*) | Previews carry the document revision and expire on intervening mutation (SACM-CMD-003). |
| SACM23-CMD-005 | Delete apply | Editing policy | Delete operations must apply only with explicit policy choices and must leave the document valid or unchanged on failure. | edit/validation | verified | libs/sacm/src/commands/commands.cpp, include/sacm/commands/policies.h | test_delete_preview.cpp (SACM23_CMD_005_*), test_argumentation.cpp (SACM23_CMD_005_ScrubReferencesKeepsMultiSourceInference) | Policy defaults are the reject variants; cascades are explicit opt-in; no dangling references after any variant. ReferenceDeletePolicy now offers a third value, ScrubReferences: instead of cascading the whole referencing relationship, it removes the deleted element(s) from the relationship's source/target/reasoning (and membership) lists and drops the relationship only once scrubbing leaves it structurally invalid under the [1..*] multiplicities (clause 11.13; an AssertedInference also stays alive on a surviving reasoning). A relationship deleted this way is itself scrubbed from anything referencing it (fixpoint). This reproduces the GSN editor's scrub-then-drop exactly -- removing one sub-goal of a strategy whose single inference has several sources keeps the inference sourced by the rest -- and is the policy the Assurance Forge apply_delete_element seam uses so the library-primary delete matches the legacy core::RemoveElement. |
| SACM23-CMD-006 | Mutation audit data | Editing/audit policy | Mutation results must expose created/changed/deleted IDs and enough metadata to support future undo/redo and Assurance Forge audit alignment. | edit/audit | verified | libs/sacm/include/sacm/commands/mutation.h | test_document_commands.cpp (SACM23_CMD_006_*) | ChangeRecords carry kind/parent/property/before/after; exact undo mechanism remains open. |
| SACM23-XMI-001 | XMI/root | Clause 2 (Conformance) + ptc/22-03-13 | Strict SACM 2.3 import/export must recognize the standard document structure, namespaces, IDs, and top-level assurance case package behavior. | xmi | verified | libs/sacm/src/io/xmi_reader.cpp, xmi_writer.cpp, include/sacm/metadata/namespaces.h | test_xmi_io.cpp, test_roundtrip.cpp (golden), SACM23_XMI_001_LangStringIdIsNotPreservedButIsReported, SACM23_XMI_001_LegacyContentStatementIsThePrimaryDescription, SACM23_XMI_001_XmiTypeIsAcceptedAsATypeDiscriminator, SACM23_XMI_001_InstantiatingAnAbstractClassIsDiagnosed | Accepts bare package roots and xmi:XMI wrappers; xsi:type AND xmi:type -> role -> class-name dispatch (XMI 2.5.1 spells the discriminator xmi:type, and OMG-toolchain output uses it -- including the pinned normative metamodel file itself, #336); instantiating an abstract SACM class is diagnosed as such rather than as an unknown type; conventions pinned in the inventory doc. LangString identity is an explicit scope exclusion, not a claim: LangString generalizes Element (not SACMElement) and every metamodel appearance is containment, so no reference can target one. The reader reports the dropped id rather than losing it silently. A legacy content=/<content> statement is read as the element's primary Description (clause 8.9: the Description provides a Claim's content), so description() returns the statement and any <description> note is secondary. |
| SACM23-XMI-002 | XMI/namespaces | Clause 2 + XMI 2.5.1 rules | Import must be namespace-prefix independent and export must be deterministic. | xmi | verified | libs/sacm/src/io/xmi_reader.cpp, xmi_writer.cpp | SACM23_XMI_002_ImportIsPrefixIndependent, SACM23_XMI_002_ExportIsDeterministic | Byte-stable golden output; xmlns scope stack on import. |
| SACM23-XMI-003 | XMI/references | ptc/22-03-13 association ends + XMI rules | References must preserve target identity and produce diagnostics for broken or mistyped references. | xmi | verified | libs/sacm/src/io/xmi_reader.cpp, src/validation/validate.cpp | SACM23_XMI_003_ReportsBrokenReference, SACM23_XMI_003_ReportsDuplicateIds, SACM23_XMI_003_GeneratedIdDoesNotCollideWithPersistedExplicitId, SACM23_XMI_003_PersistedGeneratedIdRoundTripsCleanly | ref/href/xmi:idref/IDREFS forms accepted; external hrefs rejected with SACM-XMI-007. Generated ids are idempotent across round-trips: the reader pre-reserves every explicit xmi:id before minting any generated_N, so a generated id that was persisted (e.g. onto a TaggedValue) and reappears on re-load is not manufactured a second time for an id-less element — closing a real duplicate-id round-trip failure. Duplicate detection is unchanged (validation after load still reports genuinely duplicate explicit ids). |
| SACM23-XMI-004 | Strict save mode | Compliance policy | Strict save mode must emit SACM 2.3 XMI without Assurance Forge layout metadata or compatibility-only extensions. | xmi | verified | libs/sacm/src/io/xmi_writer.cpp, src/io/xmi_reader.cpp | SACM23_XMI_004_StrictSaveOmitsLayoutAndRefusesCompatOnlyContent, SACM23_COMPAT_001_VendorAttributesPreservedAndStrictSaveRefuses | Strict is the default save mode. Vendor-extension attributes are now preserved and refused symmetrically with vendor elements (SACM23_COMPAT_001_VendorAttributesPreservedAndStrictSaveRefuses), closing the defect that downgraded this row. Note the layout half remains structurally untestable until Phase 9: build_minimal_document() builds through an API with no layout concept, so that assertion cannot fail by construction. |
| SACM23-RT-001 | Round trip | Compliance policy | Import -> export -> import must preserve all SACM semantics covered by the implemented slice. | test | verified | libs/sacm/src/compare/semantic_compare.cpp, src/io/name_tables.cpp | SACM23_RT_001_* + CLI roundtrip on repo fixtures incl. data/oasc-ja.xml | Semantic comparison pairs by id, order-insensitive, defaults normalized. Round-trip is not by itself a losslessness proof: it compares two library models, so anything dropped at import is absent from both sides and invisible. Losslessness is covered separately by the import-side gate (SACM23_XMI_003_UnknownUnprefixedAttributeIsPreservedNotIgnored) which preserves and reports any element or attribute the serialization does not define. |
| SACM23-RT-002 | Created document round trip | Editing policy | A document created through the library edit API must save, reload, validate, and semantically match the pre-save model for the covered slice. | test/edit/xmi | verified | libs/sacm/src/io/, src/compare/ | SACM23_RT_002_CreatedDocumentSavesReloadsAndSemanticallyMatches | Strict reload validates clean. |
| SACM23-VAL-001 | Validation | Compliance policy | Parser and validator must report structured diagnostics with severity, requirement ID, location where practical, and message. | validation | verified | libs/sacm/include/sacm/validation/*, src/io/xmi_reader.cpp | SACM23_VAL_001_DiagnosticsAreMachineReadable, SACM23_VAL_001_MalformedXmlReportsWhereItFailed, SACM23_VAL_001_MalformedXmlNamesBothTagsOfAMismatch, SACM23_VAL_001_MalformedXmlNamesAnUndeclaredNamespacePrefix, SACM23_VAL_001_MalformedXmlNamesAStrayClosingTag | Source line/column attached to load diagnostics; codes catalogued in docs/sacm/sacm-diagnostics-catalog.md. A malformed document -- the case where the reporter usually did not write the file -- now carries the failure's line/column and names the tag pair that disagreed and any undeclared namespace prefix, rather than passing pugixml's wording through alone (#285). |
| SACM23-VAL-002 | Post-mutation validity | Editing policy | Public mutation operations must leave the document valid for the supported slice or fail unchanged. | validation/edit | verified | libs/sacm/src/model/document.cpp, src/validation/validate.cpp | test_document_commands.cpp (SACM23_VAL_002_*) | check/perform contract + debug-mode post-mutation validate_structure assertion. |
| SACM23-BASE-001 | Base model | Clause 8 (Base) | Common SACM element identity, naming, descriptions, notes, language strings, and metadata must be represented and round-tripped. | model/edit | verified | libs/sacm/include/sacm/model/element.h, lang_string.h, src/io/*, include/sacm/commands/operations.h, src/commands/commands.cpp | test_base_model.cpp (incl. SACM23_BASE_001_SetGidAssignsElementGid, SACM23_BASE_001_SetDescriptionAtAddressesDescriptionSlots, SACM23_BASE_001_SetTaggedValueMergesByKeyAndDropsAnEmptiedTag, SACM23_BASE_001_SetTaggedValueReportsTheEditedLanguageInItsChangeRecord), SACM23_BASE_001_ExpressionLangStringWithLiteralContentIsDiagnosed, test_repo_fixture_interop.cpp (incl. Japanese oasc-ja) | Multi-language legacy names map to reserved TaggedValue "sacm.import.name" (clause 8.6 allows one name LangString). SetGid sets/clears a SACMElement's clause-8.2 gid on any element (empty clears to absent); SetDescriptionAt addresses the Description list by ordinal slot (clause 8.6 declares description; 8.9 is the Description class itself) (slot 0 the statement, slot 1 a second note), appending at the count and rejecting gaps. Both round-trip through strict save; they are the operations the Assurance Forge terminology and claim seams use to mint the legacy gid-<id> at create time and to write a claim note into the second Description without disturbing the front statement. SetTaggedValue revises the TaggedValue carrying a key rather than appending another under it (clause 8.12), and removes one whose last language entry is cleared; AddTaggedValue always creates, which left two tags under one key and a reader keeping the first. |
| SACM23-BASE-002 | Base model | Clause 8.2 (SACMElement) | Abstract/citation/implementation-constraint behavior must be validated according to the standard. | validation | verified | libs/sacm/src/validation/validate.cpp | SACM23_BASE_002_* (citation, implementation-constraint, gid-uniqueness and abstractForm negatives) | SetCitation command maintains the invariant on edit. The clause-8.2 gaps the 2026-08-08 completeness audit found are now closed (#335): gid uniqueness is validated (SACM-ID-003), and the three abstractForm constraints are validated at the severity of the clause's own wording — the citing element's isAbstract being false is stated flatly and is an error; "the referred element's isAbstract should be true" and "should be of the same type" are warnings. Bound that remains: the clause's fourth sentence, that the citing element should satisfy the referred element's ImplementationConstraints, is not checked — the constraints are free MultiLangString prose with no machine-checkable form. |
| SACM23-PKG-001 | Assurance case package | Clause 9 (AssuranceCase) | AssuranceCasePackage must be represented as the full interchange package and support contained terminology, argumentation, artifact, and nested packages as required. |
model/xmi/edit | verified | libs/sacm/include/sacm/model/assurance_case.h, src/io/* | test_packages.cpp (SACM23_PKG_001_*) | Nested packages via command and XMI both round-trip. |
| SACM23-PKG-002 | Package interfaces/bindings | Clauses 9.3, 9.4 | Package interfaces and bindings must preserve participants, references, multiplicities, and validation behavior. | model/validation | verified | libs/sacm/include/sacm/model/*.h, src/validation/validate.cpp | test_packages.cpp (SACM23_PKG_002_*) | Interfaces/bindings serialize as package-role children with xsi:type; participant [2..*] validated. The content constraints the 2026-08-08 completeness audit recorded are now validated (#333): interface and binding content must be citations (clauses 11.5, 11.6, 12.4, 12.5), an AssuranceCasePackageInterface may hold only interface-typed sub-packages (9.3 OCL), an interface citation pointing outside the package it implements warns, and a binding named as another binding's participant warns. All four Terminology/Artifact interface and binding classes now have round-trip coverage. Deliberately NOT enforced, with the reason recorded in decisions: the exact participant type, because 9.4, 10.5/10.6 and 11.5 give three different rules for it; and the binding-citation locality rule, because a participant may be named as an interface residing inside the package the citation targets, so the containment test has two legitimate answers. |
| SACM23-PKG-003 | Package deletion | Editing policy + SACM containment rules | Package deletion must handle non-empty packages, recursive deletion, cross-package references, and preview/apply semantics explicitly. | edit/validation | verified | libs/sacm/src/commands/commands.cpp (check_delete) | test_packages.cpp (SACM23_PKG_003_*), test_delete_preview.cpp | Cross-package effects need explicit CrossPackageReferencePolicy (SACM-CMD-007). |
| SACM23-TERM-001 | Terminology | Clause 10 (Terminology) | Terminology packages, groups, terms, categories, expressions, and external references must be represented and round-tripped. | model/xmi | verified | libs/sacm/include/sacm/model/terminology.h, src/commands/commands.cpp | test_terminology.cpp (SACM23_TERM_001_*) | Incl. ExpressionLangString descriptions, sub-categories (2.3), groups, create/delete commands; ref-typing negative. In-place term/expression edits via SetExpressionValue, SetTermExternalReference, SetTermOrigin, and SetExpressionCategories (SACM23_TERM_001_UpdatesTermFieldsWithCommands, SACM23_TERM_001_TermUpdateCommandsValidateTargets) so a client's term-update routes through the library. Clause 10.10's OCL, which forbids a concrete Expression from referencing abstract ExpressionElements, is validated by SACM23_TERM_001_ConcreteExpressionCannotReferenceAbstractElements. |
| SACM23-ARG-001 | Argumentation | Clause 11 (Argumentation) | Argument packages, claims, reasoning, artifact references, assertion declarations, and asserted relationships must be represented and round-tripped. | model/xmi/edit | verified | libs/sacm/include/sacm/model/argumentation.h, src/commands/commands.cpp | test_argumentation.cpp (SACM23_ARG_001_*), test_artifact.cpp (SACM23_ARG_001_ArtifactReferenceCitationIsSetByCommand) | All five Asserted* families, isCounter, metaClaims, ArgumentGroup, reasoning structure, enum literals; create commands. ReorderPackageElements sets the document order of a named subset of a package's elements, through the positions those elements already occupy, refusing an id the package does not contain or one named twice (SACM23_ARG_001_ReordersNamedPackageElementsAndLeavesTheRestInPlace, SACM23_ARG_001_ReorderRefusesAnElementThePackageDoesNotContain); order carries no SACM meaning and the operation claims none -- it changes serialization order only. AddRelationshipSource extends an existing inference's sources (SACM23_ARG_001_AddsSourceToExistingRelationship), supporting GSN strategy materialization where the inference is built with its first sub-goal and grown as later sub-goals are added. A legacy non-standard assertionDeclaration="justification" is normalized on import to axiomatic with the original GSN role preserved in the reserved sacm.import.assertionDeclaration TaggedValue (SACM23_ARG_001_LegacyJustificationNormalizesToAxiomatic), so pre-gsn.role files migrate cleanly and strict save stays clean. SetArtifactReferenceElements replaces what an ArtifactReference cites (clause 11.9) wholesale, so a reference created without a citation -- every imported GSN Solution -- can be pointed at an artifact later; an unresolved id is refused and leaves the citation as it was, and citing another argument element is accepted because an ArgumentationElement is an ArtifactElement, which is how modules are cited (SACM23_ARG_001_ArtifactReferenceCitationIsSetByCommand, beside the Resource it cites in test_artifact.cpp). |
| SACM23-ARG-002 | Relationship typing | Clauses 11.13-11.18 | Asserted relationship source/target typing and multiplicities must be validated. | validation | verified | libs/sacm/src/validation/validate.cpp, src/commands/commands.cpp | test_argumentation.cpp (SACM23_ARG_002_*) | Typing enforced at load-validation and at command level; multiplicity [1..*] negatives. AddRelationshipSource enforces the same source typing (ArgumentAsset) and rejects a duplicate source (SACM23_ARG_002_AddSourceValidatesTargetAndDuplicate). The bounds the 2026-08-08 completeness audit recorded are now closed (#334): family-specific end typing is validated for 11.15 (AssertedEvidence source), 11.17 and 11.18 (both ends), the target[1] upper bound is validated, and clause 11.4's content-homogeneity constraint is validated. 11.14 and 11.16 keep the generic ArgumentAsset end typing deliberately — they state no family constraint, and the GSN mapping's Solution → ArtifactReference with SupportedBy → AssertedInference means an inference legitimately carries ArtifactReference ends. Enforcement is at load-validation only for the new family rules; the command layer still checks the generic ArgumentAsset typing. |
| SACM23-ARG-003 | Relationship edit consequences | Editing policy | Claim/package deletion must report and handle affected asserted relationships without leaving dangling references. | edit/validation | verified | libs/sacm/src/commands/commands.cpp (check_delete) | test_argumentation.cpp (SACM23_ARG_003_*), test_packages.cpp | Previews list RelationshipDeleted records; cascades run to fixpoint; post-delete validation clean. |
| SACM23-ART-001 | Artifact model | Clause 12 (Artifact) | Artifact packages, artifacts, artifact assets, properties, events, resources, activities, techniques, participants, and relationships must be represented and round-tripped. | model/xmi | verified | libs/sacm/include/sacm/model/artifact.h, src/commands/commands.cpp | test_artifact.cpp (SACM23_ART_001_*), test_metamodel_coverage.cpp | ptc/22-03-13 defects normalized per inventory (ArtifactAssetRelationship name+superclass, Event.date); alias spelling accepted on import. Resource.location (clause 12.10) is represented and round-trips (SACM23_ART_001_ResourceLocationRoundTrips): the normative text declares it and ptc/22-03-13 omits it, so this is the one inventory divergence resolved toward the TEXT -- it is the only payload a Resource carries, and without it a text-conformant <location> fell into preserved content and strict save refused the document (#337). SetResourceLocation sets, replaces (the same language, never a second entry) and clears it by command, and is refused on an Artifact, which has no location to set (SACM23_ART_001_ResourceLocationIsSetAndClearedByCommand). SetArtifactProvenance sets, replaces and clears an Artifact's version and date together by command, and is refused on a Resource (SACM23_ART_001_ArtifactProvenanceIsSetByCommand). |
| SACM23-COMPAT-001 | Compatibility | Interoperability policy | Legacy SACM versions, third-party XMI variations, and vendor extensions must be explicit compatibility modes, not default strict SACM 2.3 behavior. | compatibility | verified | libs/sacm/src/io/xmi_reader.cpp, xmi_writer.cpp, src/compare/semantic_compare.cpp, src/metadata/namespaces.cpp, include/sacm/model/document.h | SACM23_COMPAT_001_VendorContentPreservedAndStrictSaveRefuses, SACM23_COMPAT_001_EmfReferenceDialectImportsAndNormalizes, SACM23_COMPAT_001_PreservedForeignAttributeSurvivesTwoRoundTrips, SACM23_COMPAT_001_SavedOutputDeclaresPreservedForeignNamespaces, SACM23_COMPAT_001_StrictLoadRefusesVendorContent | Tolerant load preserves unknown vendor content; strict save refuses (SACM-XMI-006); compat save re-emits verbatim. The EMF reference dialect (one namespace per package, http://omg.sacm/2.2/*) now imports and normalizes. Foreign xmlns: declarations are recorded on Document::foreign_namespaces() (union over the whole source tree) and re-declared by a compatibility save, so re-emitted fragments are namespace-well-formed and a preserved vendor attribute survives repeated round-trips — previously it was re-emitted under an undeclared prefix and silently skipped by the next load. semantic_compare now covers preserved_attributes as well as preserved_content, so compatibility round-trip assertions no longer pass vacuously. Preserved child elements carry the sibling slot they occupied (model::PreservedFragment), so a compatibility save re-emits them in position rather than appended -- but only for fragments occupying a containment role the writer emits. An unknown vendor element whose tag is no containment role (this row's own case) is recorded with an empty role and is still appended, because there is no sibling sequence to hold a slot in. See SACM23-COMPAT-002 for why position is load-bearing rather than cosmetic. Mode separation is pinned in BOTH directions: tolerant load preserves and compatibility save re-emits, while strict load refuses AND keeps nothing -- no preserved content, no preserved attributes, no preserved-element identity (SACM23_COMPAT_001_StrictLoadRefusesVendorContent). Without that import-side assertion a warn-and-keep strict path would have satisfied every other test in this row. Third-party evidence is a separate requirement tracked under SACM23-COMPAT-002; this row covers strict/compatibility mode separation, which is why the two were split. Corpus and gap list: docs/sacm/sacm-interop-corpus.md. Verified by docs/sacm/verification/2026-07-25-compat-mode-separation.md. |
| SACM23-SEC-001 | XML safety | Security policy | XML parser must disable unsafe features such as external entity expansion and report malformed XML safely. | security | verified | libs/sacm/src/io/xmi_reader.cpp | SACM23_SEC_001_RejectsDoctype | DOCTYPE/ENTITY rejected before parsing; pugixml performs no entity expansion. |
| SACM23-INT-001 | Assurance Forge adapter | Integration plan | Assurance Forge must load, project, edit, and save through the library-owned document. | integration | verified | src/core/app_state.cpp, src/sacm_adapter/* (case_projection, document_edit), src/core/commands/library_bridge.cpp, src/core/audit/event_replayer.cpp (BridgeViaLegacy), src/core/commands/command_bus.cpp | SACM23_INT_001_ProjectionSynthesizesAcpsLikeLegacy, SACM23_INT_001_ProjectionMatchesLegacyWithinBaseline, SACM23_INT_001_SetNameReproducesLegacyNameEdit, SACM23_INT_001_ContentEditReproducesLegacyStatementEdit, SACM23_INT_001_ContentEditUnsupportedForRelationship, SACM23_INT_001_AddChildReproducesLegacyStructure, SACM23_INT_001_AddChildStrategyCreatesPendingReasoning, SACM23_INT_001_AttachChildWiresEachKindLikeAddChildDoes, SACM23_INT_001_JustificationRoundTripsViaGsnRoleTag, SACM23_INT_001_AddChildUsesCallerSuppliedIds, SACM23_INT_001_ChallengeUsesCallerSuppliedIds, SACM23_INT_001_ChallengeReproducesLegacyStructure, SACM23_INT_001_AddAcpReproducesLegacyRecord, SACM23_INT_001_AddAcpRefusesIneligibleTargets, SACM23_INT_001_DeleteLeafReproducesLegacyRemoval, SACM23_INT_001_SetNameOnMissingElementFailsUnchanged, SACM23_INT_001_UpdateElementTextIsLibraryPrimary, ProjectionCoverage.SACM23_INT_001_ProjectionEmitsEveryNonContainerElement, SACM23_INT_001_UncoveredCommandRederivesLibraryDocument, AppStateTest.LoadFileUsesTheLibraryDocumentAsTheSourceOfTruth, SaveFromLibrary.SACM23_INT_001_NoBusEditPreservesUnknownContentThroughSync, SaveFromLibrary.SACM23_INT_001_UnflippedBusCommandPreservesUnknownContentInTheDocument, SaveFromLibrary.SACM23_INT_001_LoadSurfacesNonConformanceWarningToTheUser, SACM23_INT_001_DeleteClearsATermOriginInAnotherPackage | Load, projection, edit and save all route through the library; AppState::load_file retains the LibraryDocument and projects loaded_case from it. The Stage-3 claim that the projection is "field-complete and lossless" holds over this repository's fixtures and not in general -- the same qualifier SACM23-LIB-002 carries. Full history: integration preservation record. A delete through the seam now cleans a citation from ANOTHER package the way it cleans one from the same package -- a glossary Term citing the deleted element as its origin loses the citation and stays; a relationship is still scrubbed and dropped only once empty -- rather than refusing with SACM-CMD-007. Refusing left a Context undeletable from the canvas because the TerminologyPackage cited it, for a reason nothing on the canvas showed. The legacy core::RemoveElement clears the same origins in both its models, so replay through either path agrees (SACM23_INT_001_DeleteClearsATermOriginInAnotherPackage). |
| SACM23-INT-002 | Delete confirmation integration | Integration plan | Assurance Forge delete UI should use library operation previews to show implications before applying deletes. | integration | verified | src/sacm_adapter/document_edit.cpp (preview_delete_elements), src/app/controllers/element_edit_controller.cpp (BuildRemovalPreview), src/app/areas/modal_host.cpp (RenderRemovalPreview) | SacmLibraryEdit.SACM23_INT_002_DeletePreviewReportsConsequencesWithoutMutating, SacmLibraryEdit.SACM23_INT_002_DeletePreviewUsesSetSemanticsNotPerElementUnion, SacmLibraryEdit.SACM23_INT_002_DeletePreviewMatchesWhatApplyDoes, ElementEditControllerTest.SACM23_INT_002_RemoveConfirmDisclosesLibraryConsequences, ElementEditControllerTest.SACM23_INT_002_RemoveWithoutConsequencesStillDeletesImmediately, ElementEditControllerTest.SACM23_INT_002_NodeOnlyOffersNoPreviewRatherThanAWrongOne, ElementEditControllerTest.SACM23_INT_002_ConfirmedRemovalMatchesThePreviewExactly, SacmLibraryEdit.SACM23_INT_002_DeletePreviewReportsATermCitingTheElementAsModified, ElementEditControllerTest.SACM23_INT_002_NodeOnlyOnALeafOffersThePreview, ElementEditControllerTest.SACM23_INT_002_RemovalCanBeAskedToAlwaysConfirm | The delete-confirmation UI is driven by the library's own preview, not a second implementation of the same rules. Full history, including the round-1 FAIL that found the preview and the apply disagreeing: integration preservation record. NodeOnly on a LEAF now offers the preview: a leaf has nothing to reparent, so the two modes coincide and a delete-modelled preview is exact; an interior node still offers none. The preview reports a glossary Term citing the element as modified (surviving), matching the delete. A caller can ask for confirmation regardless of consequences -- the evidence register does, since a table row is easier to hit by mistake than a selected node. |
| SACM23-COMPAT-002 | Third-party interop | Interoperability policy | Files produced by at least one independent SACM tool must import, validate, and semantically round-trip, so compliance claims rest on external evidence rather than on this project's own dialect. | compatibility | verified | libs/sacm/src/io/xmi_reader.cpp (normalize_emf_references, collect_embedded_packages, interchange_package_kind, normalize_role, read_xsi_type, preserve_extension_subtree, is_self_declared_namespace, record_extension_origin, extension_type_of), src/io/name_tables.cpp (resolve_extension_type, kImportExtensionTypeKey), libs/sacm/src/commands/commands.cpp (peek_generated_id), libs/sacm/tests/test_interop_corpus.cpp, libs/sacm/src/io/xmi_writer.cpp (write_preserved_content), libs/sacm/src/validation/validate.cpp, libs/sacm/include/sacm/model/element.h (PreservedFragment) | SACM23_COMPAT_002_EmfGsnFileWithoutIdsParsesIntoSacmElements, SACM23_COMPAT_002_CurrentGsnNamespaceAndAwayTypesAreRecognized, SACM23_COMPAT_002_GsnSupportedByEndpointsAreSwappedToSacmDirection, SACM23_COMPAT_002_ExtensionTypedElementIsPreservedNotDropped, SACM23_COMPAT_002_PreservedExtensionFragmentDeclaresItsNamespace, SACM23_COMPAT_002_PreservedExtensionContentSurvivesTwoRoundTrips, SACM23_COMPAT_002_ReferenceToPreservedElementIsNotDangling, SACM23_COMPAT_002_PreservedFragmentKeepsItsSiblingPosition, SACM23_COMPAT_002_OriginalGsnTypeIsRecordedOnImport, SACM23_COMPAT_002_GsnAssumptionAndJustificationAreNotPlainGoals, SACM23_COMPAT_002_RecordedGsnTypeSurvivesSaveAndReload, SACM23_COMPAT_002_ExplicitAssertionDeclarationBeatsTheGsnType, SACM23_COMPAT_002_PreservedTargetDowngradeDoesNotMaskRealDangling, SACM23_COMPAT_002_MintedIdDoesNotCollideWithPreservedContent, SACM23_COMPAT_002_ThirdPartyOdeContainerImportsWithNonConformanceWarning, SACM23_COMPAT_002_ThirdPartyEmfFileImportsAndReportsItsRealViolations, SACM23_COMPAT_002_ThirdPartyContainerLosesItsNonSacmSiblings, SACM23_COMPAT_002_ThirdPartyFilesParseIntoSacmElements, SACM23_COMPAT_002_ThirdPartyFilesSemanticallyRoundTrip | Files from an independent SACM producer (the EMF reference implementation) parse into elements and semantically round-trip. The corpus is small and its provenance is recorded in interop corpus; two corpus tests skip when the corpus is absent, which is why the non-vacuity guard matters. Full history, including the round-3 FAIL: integration preservation record. |
| SACM23-CLI-001 | CLI utility | API decision | The repository should include a small CLI test utility for version, validate, import/export, and round-trip smoke workflows. | tooling | verified | libs/sacm/tools/sacm_cli.cpp | SacmCliVersionSmoke, SacmCliRoundtripStrict, SacmCliValidateRejectsDuplicateIds | version/validate/roundtrip/export with --strict and --json. Positive round-trip and negative validate exit codes are both asserted by CTest. |