up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
This commit is contained in:
@@ -78,6 +78,33 @@ _Frozen v1 (add-only) — approved 2025-11-17 for CONCELIER-LNM-21-001/002/101._
|
||||
- **Deterministic keying:** `_id` derived from `hash(tenantId|source|advisoryId|provenance.sourceArtifactSha)` to keep inserts idempotent in replay.
|
||||
- **Normalization guardrails:** version ranges must be stored as raw-from-source; no inferred merges.
|
||||
|
||||
## Append-Only Contract (AOC) — LNM-21-004
|
||||
|
||||
The Aggregation-Only Contract (AOC) ensures observations are immutable after creation. This is enforced by `IAdvisoryObservationWriteGuard`.
|
||||
|
||||
### Write disposition rules
|
||||
| Existing Hash | New Hash | Disposition | Action |
|
||||
|--------------|----------|-------------|--------|
|
||||
| null/empty | any | `Proceed` | Insert new observation |
|
||||
| X | X (identical) | `SkipIdentical` | Idempotent re-insert, no write |
|
||||
| X | Y (different) | `RejectMutation` | Reject with `AppendOnlyViolationException` |
|
||||
|
||||
### Supersession model
|
||||
When an advisory source publishes a revised version of an advisory:
|
||||
1. A **new observation** is created with its own unique `observationId` and `contentHash`.
|
||||
2. The new observation MAY carry a `supersedesId` pointing to the previous observation.
|
||||
3. The **original observation remains immutable** — it is never updated or deleted.
|
||||
4. Linksets are rebuilt to include all non-superseded observations; superseded observations remain queryable for audit but excluded from active linkset aggregation.
|
||||
|
||||
### Implementation checklist (LNM-21-004)
|
||||
- [x] `IAdvisoryObservationWriteGuard` interface with `ValidateWrite(observation, existingContentHash)` method.
|
||||
- [x] `AdvisoryObservationWriteGuard` implementation enforcing append-only semantics.
|
||||
- [x] `AppendOnlyViolationException` for mutation rejections.
|
||||
- [x] DI registration via `AddConcelierAocGuards()` extension.
|
||||
- [x] Unit tests covering Proceed/SkipIdentical/RejectMutation scenarios.
|
||||
- [x] Legacy merge logic deprecated with `[Obsolete]` and gated by `NoMergeEnabled` feature flag (defaults to `true`).
|
||||
- [x] Roslyn analyzer `StellaOps.Concelier.Analyzers.NoMergeApiAnalyzer` emits warnings for merge API usage.
|
||||
|
||||
## Linkset document
|
||||
```json
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user